-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add proposal for runtime.onEnabled and runtime.onExtensionLoaded events #729
Open
sohailrajdev97
wants to merge
5
commits into
w3c:main
Choose a base branch
from
sohailrajdev97:runtime-events-proposal
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+182
−0
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
# Proposal: New runtime.onEnabled and runtime.onExtensionLoaded events | ||
|
||
**Summary** | ||
|
||
Creates two new extension state notification events that will help developers | ||
take action on the full “lifecycle” of their extensions. | ||
|
||
**Document Metadata** | ||
|
||
**Author:** [email protected] | ||
|
||
**Sponsoring Browser:** Google Chrome and Microsoft Edge | ||
|
||
**Contributors:** [email protected] | ||
|
||
**Created:** 2024-12-03 | ||
|
||
**Related Issues:** https://github.com/w3c/webextensions/issues/353 | ||
|
||
## Motivation | ||
|
||
### Objective | ||
|
||
Enable two new extension lifecycle events for the developer to add listeners for: | ||
|
||
#### chrome.runtime.onEnabled | ||
Enables a developer to listen to when an extension is re-enabled from a disabled | ||
state. There is currently no way for a developer to listen for the extension | ||
being disabled and then enabled. | ||
|
||
### chrome.runtime.onExtensionLoaded | ||
Enables a developer to listen to when an extension is added to the set of active | ||
extensions. This can occur from being installed, enabled, or when the browser / | ||
profile first starts. The listener will be given the cause so they can decide to | ||
take different actions based on the reason it was added to the set. There is | ||
currently no generic event that encapsulates all instances of extension install | ||
(and update), startup, and being enabled from a disabled state. | ||
|
||
#### Use Cases `chrome.runtime.onEnabled` | ||
A developer wants to run code once in an extension’s "lifecycle", without storing | ||
a flag to keep track of this. | ||
|
||
Before this API the developer would need to manually keep track of this state | ||
via a storage flag in persistent storage. | ||
|
||
With this new API a single listener can be registered and reduce the extension’s | ||
complexity. | ||
|
||
More use cases can be found [here](https://github.com/w3c/webextensions/issues/353#issuecomment-1490078217). | ||
|
||
#### Use Cases `chrome.runtime.onExtensionLoaded` | ||
An extension automatically does initial bootstrapping, such as creating an | ||
initial state used throughout the browser session, creating a WebSocket | ||
connection, checking for things you've missed while the browser was closed, and | ||
putting something in chrome.storage.session. | ||
|
||
Before this API the developer would have to create multiple listeners for | ||
`chrome.runtime.onInstalled()`, `onStartup()`, and (above) `onEnabled()`. | ||
|
||
With this new API method the developer could write one method that performs the | ||
same action for all three, potentially with small differences based on the | ||
loaded cause. | ||
|
||
More use cases can be found [here](https://github.com/w3c/webextensions/issues/353#issuecomment-1582536300). | ||
|
||
### Known Consumers | ||
|
||
This is a broadly applicable API method that will be helpful to any developer | ||
wanting to execute code as the extension changes running states. But there | ||
appears to be strong interest per the [WECG discussion](https://github.com/w3c/webextensions/issues/353). | ||
|
||
## Specification | ||
|
||
### Schema | ||
#### `chrome.runtime.onEnabled` | ||
```typescript | ||
namespace runtime { | ||
// Fired when an extension goes from being in a disabled state to an enabled | ||
// state. | ||
export interface onEnabled { | ||
addListener(callback: () => void): void; | ||
removeListener(callback: () => void): void; | ||
} | ||
} | ||
``` | ||
|
||
#### `chrome.runtime.onExtensionLoaded` | ||
```typescript | ||
namespace runtime { | ||
// The reason for which the event is being dispatched. | ||
// | ||
// 'enabled': The extension was re-enabled from a disabled state. | ||
// | ||
// 'installed': The extension was newly installed. | ||
// | ||
// 'updated': The extension was reloaded after an update. | ||
// | ||
// 'startup': The extension is being loaded during browser startup. | ||
// | ||
// 'reload': The extension was reloaded (e.g. via `chrome.runtime.reload() or` | ||
// the user manually reloaded the extension). | ||
export type OnLoadedReason = 'enabled' | | ||
'installed' | | ||
'updated' | | ||
'startup' | | ||
'reload'; | ||
|
||
export interface ExtensionLoadDetails { | ||
// The reason that this event is being dispatched. | ||
reason: OnLoadedReason; | ||
|
||
// Indicates the previous version of the extension, which has just been | ||
// updated. This is present only if 'reason' is 'updated' or ‘enabled’. | ||
previousVersion?: string; | ||
} | ||
|
||
// Fired when the extension is added to the set of active extensions. This can | ||
// occur in multiple scenarios: when an extension is first installed, updated | ||
// to a new version, and enabled after being disabled. | ||
export interface onExtensionLoaded { | ||
addListener(callback: (details: ExtensionLoadDetails) => void): void; | ||
hasListener(callback: (details: ExtensionLoadDetails) => void): boolean; | ||
removeListener(callback: (details: ExtensionLoadDetails) => void): void; | ||
} | ||
} | ||
``` | ||
|
||
### Behavior | ||
|
||
Described as code comments in schema description. | ||
|
||
### New Permissions | ||
|
||
No new permissions are needed as extensions can access the `browser.runtime` | ||
API without any permissions. | ||
|
||
### Manifest File Changes | ||
|
||
No new manifest changes are added. | ||
|
||
## Security and Privacy | ||
|
||
### Exposed Sensitive Data | ||
|
||
The new events expose some information that wasn’t present before. It does | ||
expose that an extension was (explicitly) disabled, which is something we don't | ||
expose today. Today, an extension cannot necessarily distinguish between being | ||
disabled and the user simply not opening the browser for <n> amount of | ||
time. | ||
|
||
### Abuse Mitigations | ||
|
||
These APIs would be difficult to use in an abusive way since they do not give | ||
information or access to other extensions, and don’t give control into the | ||
extensions lifecycle – only knowledge as it transitions to different states. | ||
|
||
### Additional Security Considerations | ||
|
||
N/A. | ||
|
||
## Alternatives | ||
|
||
### Existing Workarounds | ||
|
||
There is currently `chrome.runtime.onInstalled`, and `chrome.runtime.onStartup`. | ||
These API have gaps in listening that are addressed by these two events. In | ||
short, `chrome.runtime.onEnabled`, covers the remaining status that developers | ||
care to know, and `chrome.runtime.onExtensionLoaded` encapsulates them all | ||
together with a single listener. | ||
|
||
### Open Web API | ||
|
||
These API methods are specific to extension lifetime / lifecycle and would not | ||
be appropriate to be in the open web. | ||
|
||
## Implementation Notes | ||
|
||
N/A. | ||
|
||
## Future Work | ||
|
||
N/A. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the other events be soft deprecated now and slated for removal in the next manifest version bump? (I think so, as they are redundant now.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The impression I got from past discussions is that we see some value in having discrete events, for the cases where you do only want to listen to a particular part of the lifecycle. While I agree they are technically redundant, since we already have them I'm not sure if we should go out of our way to remove them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the old events are now technically redundant. If we want to soft-deprecate them, I think we can discuss that separately. What do you think?