wxt
Version:
⚡ Next-gen Web Extension Framework
144 lines (143 loc) • 5.37 kB
text/typescript
import { WxtLocationChangeEvent } from "./internal/custom-events.mjs";
import { ContentScriptDefinition } from "../types.mjs";
//#region src/utils/content-script-context.d.ts
/**
* Implements
* [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
* Used to detect and stop content script code when the script is invalidated.
*
* It also provides several utilities like `ctx.setTimeout` and
* `ctx.setInterval` that should be used in content scripts instead of
* `window.setTimeout` or `window.setInterval`.
*
* To create context for testing, you can use the class's constructor:
*
* ```ts
* import { ContentScriptContext } from 'wxt/utils/content-scripts-context';
*
* test('storage listener should be removed when context is invalidated', () => {
* const ctx = new ContentScriptContext('test');
* const item = storage.defineItem('local:count', { defaultValue: 0 });
* const watcher = vi.fn();
*
* const unwatch = item.watch(watcher);
* ctx.onInvalidated(unwatch); // Listen for invalidate here
*
* await item.setValue(1);
* expect(watcher).toBeCalledTimes(1);
* expect(watcher).toBeCalledWith(1, 0);
*
* ctx.notifyInvalidated(); // Use this function to invalidate the context
* await item.setValue(2);
* expect(watcher).toBeCalledTimes(1);
* });
* ```
*/
declare class ContentScriptContext implements AbortController {
private readonly contentScriptName;
readonly options?: Omit<ContentScriptDefinition, "main"> | undefined;
private static SCRIPT_STARTED_MESSAGE_TYPE;
private id;
private abortController;
private locationWatcher;
constructor(contentScriptName: string, options?: Omit<ContentScriptDefinition, "main"> | undefined);
get signal(): AbortSignal;
abort(reason?: any): void;
get isInvalid(): boolean;
get isValid(): boolean;
/**
* Add a listener that is called when the content script's context is
* invalidated.
*
* @example
* browser.runtime.onMessage.addListener(cb);
* const removeInvalidatedListener = ctx.onInvalidated(() => {
* browser.runtime.onMessage.removeListener(cb);
* });
* // ...
* removeInvalidatedListener();
*
* @returns A function to remove the listener.
*/
onInvalidated(cb: () => void): () => void;
/**
* Return a promise that never resolves. Useful if you have an async function
* that shouldn't run after the context is expired.
*
* @example
* const getValueFromStorage = async () => {
* if (ctx.isInvalid) return ctx.block();
*
* // ...
* };
*/
block<T>(): Promise<T>;
/**
* Wrapper around `window.setInterval` that automatically clears the interval
* when invalidated.
*
* Intervals can be cleared by calling the normal `clearInterval` function.
*/
setInterval(handler: () => void, timeout?: number): number;
/**
* Wrapper around `window.setTimeout` that automatically clears the interval
* when invalidated.
*
* Timeouts can be cleared by calling the normal `setTimeout` function.
*/
setTimeout(handler: () => void, timeout?: number): number;
/**
* Wrapper around `window.requestAnimationFrame` that automatically cancels
* the request when invalidated.
*
* Callbacks can be canceled by calling the normal `cancelAnimationFrame`
* function.
*/
requestAnimationFrame(callback: FrameRequestCallback): number;
/**
* Wrapper around `window.requestIdleCallback` that automatically cancels the
* request when invalidated.
*
* Callbacks can be canceled by calling the normal `cancelIdleCallback`
* function.
*/
requestIdleCallback(callback: IdleRequestCallback, options?: IdleRequestOptions): number;
/**
* Call `target.addEventListener` and remove the event listener when the
* context is invalidated.
*
* Listeners can be canceled by calling the normal `removeEventListener`
* function.
*
* Includes additional events useful for content scripts:
*
* - `"wxt:locationchange"` - Triggered when HTML5 history mode is used to
* change URL. Content scripts are not reloaded when navigating this way, so
* this can be used to reset the content script state on URL change, or run
* custom code.
*
* @example
* ctx.addEventListener(document, 'visibilitychange', () => {
* // ...
* });
* ctx.addEventListener(window, 'wxt:locationchange', () => {
* // ...
* });
*/
addEventListener<TType extends keyof WxtWindowEventMap>(target: Window, type: TType, handler: (event: WxtWindowEventMap[TType]) => void, options?: AddEventListenerOptions): void;
addEventListener<TType extends keyof DocumentEventMap>(target: Document, type: TType, handler: (event: DocumentEventMap[TType]) => void, options?: AddEventListenerOptions): void;
addEventListener<TTarget extends EventTarget>(target: TTarget, ...params: Parameters<TTarget['addEventListener']>): void;
/**
* @internal
* Abort the abort controller and execute all `onInvalidated` listeners.
*/
notifyInvalidated(): void;
stopOldScripts(): void;
verifyScriptStartedEvent(event: CustomEvent): boolean;
listenForNewerScripts(): void;
}
interface WxtWindowEventMap extends WindowEventMap {
'wxt:locationchange': WxtLocationChangeEvent;
}
//#endregion
export { ContentScriptContext, WxtWindowEventMap };