feat(web-extension-bridge): adds @webex/web-extension-bridge - #5162
feat(web-extension-bridge): adds @webex/web-extension-bridge#5162rarajes2 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5c20beb11
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const value = await send({ | ||
| __webexBridgeClient: true, | ||
| channel, | ||
| command: ClientCommand.GET_BUFFERED, | ||
| ...(typeof opts.limit === 'number' ? {limit: opts.limit} : {}), |
There was a problem hiding this comment.
Filter buffered messages in the worker before limiting
When a popup calls getBufferedMessages({topic, limit}), this command sends only limit, so the worker returns the newest N messages across all topics; the client then filters that truncated list locally. If the matching topic has older entries behind newer other-topic pushes, the API returns too few or none even though createExtensionBridge().getBufferedMessages({topic, limit}) would return them. Please pass and handle topic in the worker before applying the limit.
Useful? React with 👍 / 👎.
| try { | ||
| serialised = JSON.stringify(payload) as string; |
There was a problem hiding this comment.
Reject nested non-JSON values before sending
For payloads like {a: () => {}}, {a: undefined}, or NaN, JSON.stringify either drops or converts the value and still returns a string, but the bridge continues sending the original object. On the page postMessage path nested functions throw a DataCloneError instead of the documented BridgeError, and values such as NaN/undefined can reach handlers despite the JsonValue contract. Please recursively validate JSON value types rather than treating any stringify result as acceptance.
Useful? React with 👍 / 👎.
| void Promise.resolve(tabsApi.sendMessage(tabId, relayRequest)).then( | ||
| (response) => settleFromRelay(id, topic, connection.session, response), | ||
| () => pending.reject(id, new BridgeError('NOT_CONNECTED', undefined, topic)) |
There was a problem hiding this comment.
Drop dead tab connections when sendMessage fails
When a tab still exists in session storage but the content script is gone, such as after an extension reload, discarded tab, or injection failure, chrome.tabs.sendMessage rejects and the request returns NOT_CONNECTED, but the connection record remains. listConnections() and default active-tab targeting then keep advertising the dead tab until a navigation/removal event happens. Please drop the connection on this rejection before or while rejecting the pending request.
Useful? React with 👍 / 👎.
| if (typeof node !== 'object' || node === null || depth > MAX_WALK_DEPTH) { | ||
| return undefined; |
There was a problem hiding this comment.
Reject over-deep payloads instead of skipping checks
For a payload nested more than 64 levels deep, this branch returns undefined, which is the same value used for “no reserved key found”. A malicious or malformed payload can put __proto__/constructor below that depth and bypass the reserved-key rejection even though the rest of the code treats those keys as never allowed anywhere in a payload. Please make depth overflow a rejection instead of a clean result.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 224c04f193
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| this.evictIfFull(); | ||
| this.buckets.set(key, {tokens: this.perSecond - 1, updatedAt: at}); |
There was a problem hiding this comment.
Add an aggregate cap before admitting new topic buckets
When an allow-listed page cycles through more than maxKeys unique topics, every push takes this new-key path, evicts an existing bucket, and receives a fresh full token budget. Because both the content relay and background worker key this limiter by topic, such a page can bypass rate limiting entirely and queue runtime messages and storage writes as fast as it can generate topic names; retain an aggregate per-tab/global bucket when bounding the per-topic map.
Useful? React with 👍 / 👎.
| case RelayKind.DISCONNECT: | ||
| logger.debug('tab detached', {channel, tabId, reason: relay.reason}); | ||
| dropConnection(tabId, relay.reason ?? 'bye'); |
There was a problem hiding this comment.
Match disconnects to the stored session
If a relay from session A sends a delayed DISCONNECT after the same tab has already connected with session B, this unconditional tab-level removal deletes B's connection and settles B's in-flight requests. Since the disconnect message carries its session token and connections are replaced solely by tabId, remove the record only when its stored session still matches the disconnecting relay.
Useful? React with 👍 / 👎.
COMPLETES #< CAI-8448 >
This pull request addresses
Adds
@webex/web-extension-bridge, a new TypeScript workspace package that lets a webapplication and a Chrome Manifest V3 extension exchange typed, validated messages over a
hardened
window.postMessage+chrome.runtimepath. Implements M1–M4 of the intake spec(added here as
WEB-EXTENSION-BRIDGE-INTAKE-SPEC.md).by making the following changes
What it provides
Four subpath exports, one per execution context, so a web build never pulls in extension code:
@webex/web-extension-bridge/webcreateWebBridge— publish, request handlers, connection events@webex/web-extension-bridge/extension/content@webex/web-extension-bridge/extension/backgroundcreateExtensionBridge— subscribe, request, connections, buffer@webex/web-extension-bridge/extension/clientcreateExtensionClient, proxies to the workerCore capabilities: fire-and-forget push from page to extension (buffered while the popup is
closed), on-demand pull from extension to page with timeouts and abort, connection lifecycle
events, per-topic rate limiting, and counters for observability.
Security posture
(
sender.id,sender.tab,sender.origin) rather than relying on manifestmatches.session binding; prototype-pollution-safe parsing.
and no log field can carry a payload or session token.
storageonly), noweb_accessible_resources, content scriptpre-bundled into a single classic script.
test/unit/spec/security/threats.ts.Samples
docs/samples/web-extension-bridge(web app) anddocs/samples/web-extension-bridge-extension(MV3 extension), built with esbuild into git-ignored
vendor/directories. The extensionmanifest is generated from a template so the allowed origin is configurable and carries a
"local testing only" banner. See the README for the click-path.
Tests
575 unit tests (mocha/sinon/chai via legacy-tools) covering core protocol, web and extension
adapters, an integration suite that wires both halves through fake browser seams, and the
security regression suite. Lint and typecheck are clean.
Not in this PR
Playwright end-to-end tests, the CI workflow, and release/SBOM tooling are deferred.
Test plan
yarn workspace @webex/web-extension-bridge test(lint + 575 unit tests)yarn workspace @webex/web-extension-bridge build:srcyarn workspace @webex/web-extension-bridge build:samples, load the unpacked extensionand walk the README click-path: handshake, push, pull,
HANDLER_ERROR,TIMEOUT,NO_HANDLERChange Type
The following scenarios were tested
Vidcast - https://app.vidcast.io/share/69f00dd6-68be-4d85-b0ff-dd476c171f83
The GAI Coding Policy And Copyright Annotation Best Practices
I certified that
Make sure to have followed the contributing guidelines before submitting.