diff --git a/README.md b/README.md index 3bb9456..ea7770d 100644 --- a/README.md +++ b/README.md @@ -24,5 +24,5 @@ Communication framework for browser extensions, with wings! ## Supports -* **Runtime contexts:** window (injected script), popup, devtools, content script, background, options, sidepanel (_planned_) +* **Runtime contexts:** window (injected script), popup, sidepanel, devtools, content script, background, options * **Browsers:** Chrome, Firefox, Safari, Opera, Edge + others supported by [webextension-polyfill](https://github.com/mozilla/webextension-polyfill) diff --git a/packages/rpc/src/types.ts b/packages/rpc/src/types.ts index 21e9030..4933b2d 100644 --- a/packages/rpc/src/types.ts +++ b/packages/rpc/src/types.ts @@ -4,6 +4,7 @@ export type RuntimeContext = | 'devtools' | 'background' | 'popup' + | 'sidepanel' | 'options' | 'content-script' | 'window'; diff --git a/packages/transport/README.md b/packages/transport/README.md index c6542a4..ddca66d 100644 --- a/packages/transport/README.md +++ b/packages/transport/README.md @@ -19,7 +19,7 @@ This library provides two communication patterns: ## Supports -* **Runtime contexts:** window (injected script), popup, devtools, content script, background, options, sidepanel (_planned_) +* **Runtime contexts:** window (injected script), popup, sidepanel, devtools, content script, background, options * **Browsers:** Chrome, Firefox, Safari, Opera, Edge + others supported by [webextension-polyfill](https://github.com/mozilla/webextension-polyfill) ## Comparison to other libraries @@ -88,6 +88,7 @@ eventBus.emitBroadcastEvent( - `@webext-pegasus/transport/devtools` - `@webext-pegasus/transport/options` - `@webext-pegasus/transport/popup` + - `@webext-pegasus/transport/sidepanel` - `@webext-pegasus/transport/window` (for injected scripts) @@ -125,7 +126,7 @@ initPegasusTransport(); ## Security risks while communicating with injected script -The following note only applies if and only if, you will be sending/receiving messages to/from `window` contexts. There's no security concern if you will be only working with `content-script`, `background`, `popup`, `options`, or `devtools` scope, which is the default setting. +The following note only applies if and only if, you will be sending/receiving messages to/from `window` contexts. There's no security concern if you will be only working with `content-script`, `background`, `popup`, `sidepanel`, `options`, or `devtools` scope, which is the default setting. `window` context(s) in tab `A` get unlocked the moment you call `initPegasusTransport({allowWindowMessagingForNamespace: 'TEST'})` in your extension's content script AND `initPegasusTransport({namespace: 'TEST'})` in your injected script. @@ -142,7 +143,7 @@ import { onMessage } from '@webext-pegasus/transport/background'; onMessage("getUserBrowsingHistory", (message) => { const { data, sender } = message; - // Respond only if request is from 'devtools', 'content-script', 'popup', 'options', or 'background' endpoint + // Respond only if request is from 'devtools', 'content-script', 'popup', 'sidepanel', 'options', or 'background' endpoint }); ``` diff --git a/packages/transport/package.json b/packages/transport/package.json index 0d4d30f..a415318 100644 --- a/packages/transport/package.json +++ b/packages/transport/package.json @@ -17,7 +17,7 @@ ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "tsup-build": "tsup index.ts background.ts content-script.ts devtools.ts popup.ts window.ts options.ts --format cjs,esm --dts", + "tsup-build": "tsup index.ts background.ts content-script.ts devtools.ts popup.ts sidepanel.ts window.ts options.ts --format cjs,esm --dts", "build": "npm run tsup-build --dts-resolve", "prepublishOnly": "npm run build" }, @@ -47,6 +47,10 @@ "import": "./dist/popup.js", "require": "./dist/popup.cjs" }, + "./sidepanel": { + "import": "./dist/sidepanel.js", + "require": "./dist/sidepanel.cjs" + }, "./window": { "import": "./dist/window.js", "require": "./dist/window.cjs" @@ -72,6 +76,9 @@ "popup": [ "dist/popup.d.ts" ], + "sidepanel": [ + "dist/sidepanel.d.ts" + ], "window": [ "dist/window.d.ts" ] diff --git a/packages/transport/sidepanel.ts b/packages/transport/sidepanel.ts new file mode 100644 index 0000000..1cc1ccd --- /dev/null +++ b/packages/transport/sidepanel.ts @@ -0,0 +1,33 @@ +import browser from 'webextension-polyfill'; + +import {createBroadcastEventRuntime} from './src/BroadcastEventRuntime'; +import {createMessageRuntime} from './src/MessageRuntime'; +import {createPersistentPort} from './src/PersistentPort'; +import {initTransportAPI} from './src/TransportAPI'; +import {internalPacketTypeRouter} from './src/utils/internalPacketTypeRouter'; + +export function initPegasusTransport(): void { + const port = createPersistentPort('sidepanel'); + const messageRuntime = createMessageRuntime('sidepanel', async (message) => + port.postMessage(message), + ); + + port.onMessage((packet) => + internalPacketTypeRouter(packet, {eventRuntime, messageRuntime}), + ); + + const eventRuntime = createBroadcastEventRuntime( + 'sidepanel', + async (event) => { + port.postMessage(event); + }, + ); + + initTransportAPI({ + browser: browser, + emitBroadcastEvent: eventRuntime.emitBroadcastEvent, + onBroadcastEvent: eventRuntime.onBroadcastEvent, + onMessage: messageRuntime.onMessage, + sendMessage: messageRuntime.sendMessage, + }); +} diff --git a/packages/transport/src/isInternalEndpoint.ts b/packages/transport/src/isInternalEndpoint.ts index ea09ecd..82ffea0 100644 --- a/packages/transport/src/isInternalEndpoint.ts +++ b/packages/transport/src/isInternalEndpoint.ts @@ -6,6 +6,7 @@ const internalEndpoints: RuntimeContext[] = [ 'content-script', 'options', 'popup', + 'sidepanel', ]; export const isInternalEndpoint = ({context: ctx}: Endpoint): boolean => diff --git a/packages/transport/src/types.ts b/packages/transport/src/types.ts index 3553b90..168bdc9 100644 --- a/packages/transport/src/types.ts +++ b/packages/transport/src/types.ts @@ -10,6 +10,7 @@ export type RuntimeContext = | 'devtools' | 'background' | 'popup' + | 'sidepanel' | 'options' | 'content-script' | 'window'; diff --git a/packages/transport/src/utils/endpoint-utils.ts b/packages/transport/src/utils/endpoint-utils.ts index add9bc8..2e32f7a 100644 --- a/packages/transport/src/utils/endpoint-utils.ts +++ b/packages/transport/src/utils/endpoint-utils.ts @@ -1,7 +1,7 @@ import type {Endpoint, RuntimeContext} from '../types'; const ENDPOINT_RE = - /^((?:background$)|devtools|popup|options|content-script|window)(?:@(\d+)(?:\.(\d+))?)?$/; + /^((?:background$)|devtools|popup|sidepanel|options|content-script|window)(?:@(\d+)(?:\.(\d+))?)?$/; export const deserializeEndpoint = (endpoint: string): Endpoint => { const [, context, tabId, frameId] = endpoint.match(ENDPOINT_RE) || []; @@ -18,7 +18,7 @@ export const serializeEndpoint = ({ tabId, frameId, }: Endpoint): string => { - if (['background', 'popup', 'options'].includes(context)) { + if (['background', 'popup', 'sidepanel', 'options'].includes(context)) { return context; }