Skip to content
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 support for side-panel #84

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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`.

Expand All @@ -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);
Expand Down
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"author": "Neek Sandhu <[email protected]>",
"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"
},
Expand Down Expand Up @@ -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"
Expand All @@ -77,6 +81,9 @@
"popup": [
"dist/popup.d.ts"
],
"side-panel": [
"dist/side-panel.d.ts"
],
"window": [
"dist/window.d.ts"
]
Expand Down
10 changes: 6 additions & 4 deletions src/content-script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/internal/endpoint.ts

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In messing, the side-panel page is same as popup page.

Most of your modifications are correct, but you forgot to add a side-panel in ENDPOINT_RE

Original file line number Diff line number Diff line change
Expand Up @@ -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}` : ''}`
Expand Down
2 changes: 1 addition & 1 deletion src/internal/is-internal-endpoint.ts
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 14 additions & 0 deletions src/side-panel.ts
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 4 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type RuntimeContext =
| 'options'
| 'content-script'
| 'window'
| 'side-panel'

export interface Endpoint {
context: RuntimeContext
Expand Down Expand Up @@ -85,16 +86,15 @@ export type GetDataType<
: ProtocolMap[K] extends ProtocolWithReturn<infer Data, any>
? 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<any, infer Return>
? Return
: void
: Fallback;
: Fallback