Skip to content

refactor(extension): extract target-neutral recorder host and platform layer - #1998

Open
ManthanNimodiya wants to merge 4 commits into
CapSoftware:mainfrom
ManthanNimodiya:feat/extension-target-neutral-refactor
Open

refactor(extension): extract target-neutral recorder host and platform layer#1998
ManthanNimodiya wants to merge 4 commits into
CapSoftware:mainfrom
ManthanNimodiya:feat/extension-target-neutral-refactor

Conversation

@ManthanNimodiya

@ManthanNimodiya ManthanNimodiya commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Groundwork for a Firefox port, zero Chrome behavior change.

Renames offscreen.html→recorder.html and src/offscreen/→src/recorder/; extracts the offscreen lifecycle into src/background/recorder-host.ts; adds src/platform/ (compile-time TARGET, capability flags, EXTENSION_PROTOCOL).

Fixes three sender checks that hardcoded chrome-extension: (on Firefox they'd misclassify extension pages as web pages).

Pins the recorder to the streaming pipeline explicitly (selectRecordingPipelineFromSupport(..., { preferStreamingUpload: true })) since the UA heuristic in recorder-core returns false on Firefox; Chrome output unchanged.

Greptile Summary

This PR prepares the extension recorder for target-specific Chrome and Firefox behavior. The main changes are:

  • Renames the offscreen recorder page to recorder.html.
  • Moves recorder code from src/offscreen to src/recorder.
  • Extracts recorder host lifecycle logic into the background layer.
  • Adds platform target, protocol, and capability constants.
  • Updates sender protocol checks and recorder pipeline selection.

Confidence Score: 4/5

This is close, but the target define should be fixed before merging.

  • The recorder host and tab capture paths now have capability guards.
  • The shared Vite config still forces the Chrome target.
  • A Firefox build that uses this config can compile with the wrong capability set.

Files Needing Attention: apps/chrome-extension/vite.config.ts

Important Files Changed

Filename Overview
apps/chrome-extension/vite.config.ts Adds __TARGET__, but the shared config hardcodes it to "chrome".
apps/chrome-extension/src/platform/target.ts Adds the compile-time extension target with a Chrome fallback for tests.
apps/chrome-extension/src/platform/capabilities.ts Defines target-based recorder and capture capability flags.
apps/chrome-extension/src/background/recorder-host.ts Extracts recorder host creation and guards offscreen APIs by capability.
apps/chrome-extension/src/background/service-worker.ts Uses the recorder host abstraction, platform protocol checks, and a tab capture capability guard.
apps/chrome-extension/src/platform/extension-protocol.ts Computes the extension protocol from the runtime URL.
apps/chrome-extension/src/recorder/recorder.ts Selects the recording pipeline with explicit streaming upload preference.
apps/chrome-extension/recorder.html Loads the renamed recorder module entry point.
Prompt To Fix All With AI
### Issue 1
apps/chrome-extension/vite.config.ts:8
**Chrome Target Hardcoded**

This shared config now always compiles `__TARGET__` as `"chrome"`. A Firefox artifact built through this config will set `supportsOffscreen` and `supportsTabCapture` to true, so the worker can still enter the Chrome-only recorder host and tab capture paths instead of using the Firefox capability set. Please make the target value come from the build target, such as a Firefox-specific config or mode/env define.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (3): Last reviewed commit: "fix(extension): use string literal for C..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)

contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],
documentUrls: [recorderUrl],
},
(contexts) => resolve(contexts),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

chrome.runtime.getContexts can invoke the callback with contexts undefined (or fail in older runtimes), which would make hasRecorderHost() throw on .length. Small hardening tweak:

Suggested change
(contexts) => resolve(contexts),
(contexts) => resolve(contexts ?? []),

return new Promise<Array<{ documentUrl?: string }>>((resolve) => {
chrome.runtime.getContexts(
{
contextTypes: [chrome.runtime.ContextType.OFFSCREEN_DOCUMENT],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Firefox Worker Imports Chrome APIs

recorder-host.ts is imported by the service worker at module load time, but this line reads chrome.runtime.ContextType.OFFSCREEN_DOCUMENT before any capability guard can run. In a Firefox build where that Chrome-only API is missing, the background worker can throw during startup instead of reaching the supportsOffscreen checks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/chrome-extension/src/background/recorder-host.ts
Line: 14

Comment:
**Firefox Worker Imports Chrome APIs**

`recorder-host.ts` is imported by the service worker at module load time, but this line reads `chrome.runtime.ContextType.OFFSCREEN_DOCUMENT` before any capability guard can run. In a Firefox build where that Chrome-only API is missing, the background worker can throw during startup instead of reaching the `supportsOffscreen` checks.

How can I resolve this? If you propose a fix, please make it concise.

export type ExtensionTarget = "chrome" | "firefox";

export const TARGET: ExtensionTarget =
typeof __TARGET__ === "undefined" ? "chrome" : __TARGET__;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Missing Target Becomes Chrome

TARGET defaults to "chrome" whenever __TARGET__ is absent, but the changed Vite config does not define __TARGET__. A Firefox build that uses this config without an injected define will enable Chrome-only capabilities like offscreen and tab capture, sending the Firefox worker into unsupported APIs.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/chrome-extension/src/platform/target.ts
Line: 8

Comment:
**Missing Target Becomes Chrome**

`TARGET` defaults to `"chrome"` whenever `__TARGET__` is absent, but the changed Vite config does not define `__TARGET__`. A Firefox build that uses this config without an injected define will enable Chrome-only capabilities like offscreen and tab capture, sending the Firefox worker into unsupported APIs.

How can I resolve this? If you propose a fix, please make it concise.

@ManthanNimodiya

Copy link
Copy Markdown
Contributor Author

@greptileai

// install, and getDisplayMedia requires transient user activation so capture
// cannot start without a click inside the recorder document.
export const capabilities = {
supportsTabCapture: TARGET === "chrome",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Tab Capture Unguarded

supportsTabCapture is defined as false for Firefox, but the service worker tab-recording path still calls chrome.tabCapture.getMediaStreamId without checking it. When a Firefox build starts a tab-mode recording, that path can still dereference an API Firefox does not provide, so the recording flow fails before capture can start. This needs a separate guard or tab-mode disablement at the call path that uses the capability.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/chrome-extension/src/platform/capabilities.ts
Line: 9

Comment:
**Tab Capture Unguarded**

`supportsTabCapture` is defined as false for Firefox, but the service worker tab-recording path still calls `chrome.tabCapture.getMediaStreamId` without checking it. When a Firefox build starts a tab-mode recording, that path can still dereference an API Firefox does not provide, so the recording flow fails before capture can start. This needs a separate guard or tab-mode disablement at the call path that uses the capability.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@ManthanNimodiya
ManthanNimodiya force-pushed the feat/extension-target-neutral-refactor branch from 8d0d262 to 4e327b7 Compare August 6, 2026 05:19
@ManthanNimodiya

Copy link
Copy Markdown
Contributor Author

@greptileai

Comment thread apps/chrome-extension/vite.config.ts Outdated
export default defineConfig({
plugins: [react()],
define: {
__TARGET__: JSON.stringify("chrome"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Chrome Target Hardcoded

This shared config now always compiles __TARGET__ as "chrome". A Firefox artifact built through this config will set supportsOffscreen and supportsTabCapture to true, so the worker can still enter the Chrome-only recorder host and tab capture paths instead of using the Firefox capability set. Please make the target value come from the build target, such as a Firefox-specific config or mode/env define.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/chrome-extension/vite.config.ts
Line: 8

Comment:
**Chrome Target Hardcoded**

This shared config now always compiles `__TARGET__` as `"chrome"`. A Firefox artifact built through this config will set `supportsOffscreen` and `supportsTabCapture` to true, so the worker can still enter the Chrome-only recorder host and tab capture paths instead of using the Firefox capability set. Please make the target value come from the build target, such as a Firefox-specific config or mode/env define.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant