diff --git a/README.md b/README.md index b65bd49..99d6cc9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ > **`webext-bridge` just joined the Server Side Up family of open source projects.** [Read the announcement →](https://github.com/serversideup/webext-bridge/discussions/74) # Introduction -**Messaging in web extensions made easy. Batteries included.** Reduce headache and simplify the effort of keeping data in sync across different parts of your extension. `webext-bridge` is a tiny library that provides a simple and consistent API for sending and receiving messages between different parts of your web extension, such as `background`, `content-script`, `devtools`, `popup`, `options`, and `window` contexts. +**Messaging in web extensions made easy. Batteries included.** Reduce headache and simplify the effort of keeping data in sync across different parts of your extension. `webext-bridge` is a tiny library that provides a simple and consistent API for sending and receiving messages between different parts of your web extension, such as `background`, `content-script`, `devtools`, `popup`, `options`, `side-panel` and `window` contexts. ## Example @@ -310,7 +310,7 @@ Callback that should be called whenever `Stream` is opened from the other side. ## Serious security note -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`, `options`, `side-panel` or `devtools` scope, which is the default setting. `window` context(s) in tab `A` get unlocked the moment you call `allowWindowMessaging(namespace)` somewhere in your extension's content script(s) that's also loaded in tab `A`. @@ -329,7 +329,7 @@ import { onMessage, isInternalEndpoint } from "webext-bridge/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', 'options', 'side-panel', or 'background' endpoint if (isInternalEndpoint(sender)) { const { range } = data; return getHistory(range); diff --git a/package.json b/package.json index a1e8214..10cfe22 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ }, "author": "Neek Sandhu ", "scripts": { - "build": "tsup src/index.ts src/background.ts src/content-script.ts src/devtools.ts src/options.ts src/popup.ts src/window.ts --format esm,cjs --dts", + "build": "tsup src/index.ts src/background.ts src/content-script.ts src/devtools.ts src/options.ts src/popup.ts src/window.ts src/side-panel.ts --format esm,cjs --dts", "watch": "npm run build -- --watch", "release": "bumpp --commit --push --tag && npm run build && npm publish" }, @@ -52,6 +52,10 @@ "import": "./dist/popup.js", "require": "./dist/popup.cjs" }, + "./side-panel": { + "import": "./dist/side-panel.js", + "require": "./dist/side-panel.cjs" + }, "./window": { "import": "./dist/window.js", "require": "./dist/window.cjs" @@ -77,6 +81,9 @@ "popup": [ "dist/popup.d.ts" ], + "side-panel": [ + "dist/side-panel.d.ts" + ], "window": [ "dist/window.d.ts" ] diff --git a/src/content-script.ts b/src/content-script.ts index c5f63f6..416390b 100644 --- a/src/content-script.ts +++ b/src/content-script.ts @@ -12,12 +12,14 @@ const endpointRuntime = createEndpointRuntime('content-script', (message) => { }) win.onMessage((message: InternalMessage) => { - endpointRuntime.handleMessage(Object.assign({}, message, {origin: { + endpointRuntime.handleMessage(Object.assign({}, message, { + origin: { // a message event inside `content-script` means a script inside `window` dispatched it to be forwarded // so we're making sure that the origin is not tampered (i.e script is not masquerading it's true identity) - context: "window", - tabId: null - }})) + context: 'window', + tabId: null, + }, + })) }) port.onMessage(endpointRuntime.handleMessage) diff --git a/src/internal/endpoint.ts b/src/internal/endpoint.ts index 0c271f2..3d404f2 100644 --- a/src/internal/endpoint.ts +++ b/src/internal/endpoint.ts @@ -13,7 +13,7 @@ export const parseEndpoint = (endpoint: string): Endpoint => { } export const formatEndpoint = ({ context, tabId, frameId }: Endpoint): string => { - if (['background', 'popup', 'options'].includes(context)) + if (['background', 'popup', 'options', 'side-panel'].includes(context)) return context return `${context}@${tabId}${frameId ? `.${frameId}` : ''}` diff --git a/src/internal/is-internal-endpoint.ts b/src/internal/is-internal-endpoint.ts index 5e6ab4c..f8e3532 100644 --- a/src/internal/is-internal-endpoint.ts +++ b/src/internal/is-internal-endpoint.ts @@ -1,5 +1,5 @@ import type { Endpoint, RuntimeContext } from '../types' -const internalEndpoints: RuntimeContext[] = ['background', 'devtools', 'content-script', 'options', 'popup'] +const internalEndpoints: RuntimeContext[] = ['background', 'devtools', 'content-script', 'options', 'popup', 'side-panel'] export const isInternalEndpoint = ({ context: ctx }: Endpoint): boolean => internalEndpoints.includes(ctx) diff --git a/src/side-panel.ts b/src/side-panel.ts new file mode 100644 index 0000000..94bc95e --- /dev/null +++ b/src/side-panel.ts @@ -0,0 +1,14 @@ +import { createEndpointRuntime } from './internal/endpoint-runtime' +import { createStreamWirings } from './internal/stream' +import { createPersistentPort } from './internal/persistent-port' + +const port = createPersistentPort('side-panel') +const endpointRuntime = createEndpointRuntime( + 'side-panel', + message => port.postMessage(message), +) + +port.onMessage(endpointRuntime.handleMessage) + +export const { sendMessage, onMessage } = endpointRuntime +export const { openStream, onOpenStreamChannel } = createStreamWirings(endpointRuntime) diff --git a/src/types.ts b/src/types.ts index d184a5c..7ffa7be 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,6 +7,7 @@ export type RuntimeContext = | 'options' | 'content-script' | 'window' + | 'side-panel' export interface Endpoint { context: RuntimeContext @@ -85,16 +86,15 @@ export type GetDataType< : ProtocolMap[K] extends ProtocolWithReturn ? Data : ProtocolMap[K] - : Fallback; - + : Fallback export type GetReturnType< K extends DataTypeKey, - Fallback extends JsonValue = undefined + Fallback extends JsonValue = undefined, > = K extends keyof ProtocolMap ? ProtocolMap[K] extends (...args: any[]) => infer R ? R : ProtocolMap[K] extends ProtocolWithReturn ? Return : void - : Fallback; + : Fallback