extension-develop 4.1.20 → 4.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/672~0.mjs +24 -1
  2. package/dist/747~0.mjs +4 -2
  3. package/dist/832~0.mjs +1 -1
  4. package/dist/840~0.mjs +432 -20
  5. package/dist/950~0.mjs +15 -24
  6. package/dist/command-preview.d.ts +8 -0
  7. package/dist/dev-server/control-bridge/consumer-client.d.ts +10 -0
  8. package/dist/dev-server/control-bridge/contracts.d.ts +42 -0
  9. package/dist/dev-server/control-bridge/logs-query.d.ts +16 -0
  10. package/dist/dev-server~0.mjs +2 -0
  11. package/dist/lib/addon-lint.d.ts +4 -1
  12. package/dist/lib/build-summary.d.ts +11 -0
  13. package/dist/lib/chunk-dependency-provenance.d.ts +14 -0
  14. package/dist/lib/constants.d.ts +1 -1
  15. package/dist/lib/manifest-utils.d.ts +2 -0
  16. package/dist/lib/messages.d.ts +3 -3
  17. package/dist/lib/package-manager.d.ts +2 -0
  18. package/dist/plugin-browsers/index.d.ts +28 -0
  19. package/dist/plugin-compilation/env.d.ts +2 -0
  20. package/dist/plugin-js-frameworks/js-frameworks-lib/messages.d.ts +1 -0
  21. package/dist/plugin-js-frameworks/js-tools/solid.d.ts +3 -0
  22. package/dist/plugin-js-frameworks/js-tools/typescript.d.ts +16 -0
  23. package/dist/plugin-perf-budgets/categorize.d.ts +2 -1
  24. package/dist/plugin-perf-budgets/index.d.ts +1 -1
  25. package/dist/plugin-reload/classify-reload.d.ts +4 -0
  26. package/dist/plugin-reload/index.d.ts +18 -0
  27. package/dist/plugin-special-folders/folder-extensions/types.d.ts +13 -0
  28. package/dist/plugin-web-extension/feature-manifest/messages.d.ts +1 -0
  29. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/emitted-evidence.d.ts +22 -0
  30. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/patch-background.d.ts +9 -0
  31. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/patch-web-resources.d.ts +7 -16
  32. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults.d.ts +6 -2
  33. package/dist/plugin-web-extension/feature-manifest/steps/warn-gecko-unsupported-apis.d.ts +2 -13
  34. package/dist/plugin-web-extension/feature-scripts/messages.d.ts +5 -0
  35. package/dist/plugin-web-extension/feature-scripts/steps/warn-page-context-worker.d.ts +5 -0
  36. package/dist/plugin-web-extension/feature-web-resources/collect-entry-imports.d.ts +1 -0
  37. package/dist/plugin-web-extension/feature-web-resources/web-resources-lib/messages.d.ts +1 -0
  38. package/dist/plugin-web-extension/feature-web-resources/web-resources-lib/unreachable-resources.d.ts +9 -0
  39. package/dist/rspack-config.d.ts +1 -1
  40. package/dist/rspack-config~0.mjs +430 -463
  41. package/dist/types.d.ts +190 -0
  42. package/package.json +1 -1
package/dist/950~0.mjs CHANGED
@@ -102,10 +102,17 @@ function addonLintSummary(errorCount, warningCount, distDisplay) {
102
102
  if (warningCount > 0) parts.push(pluralize(warningCount, 'warning'));
103
103
  return `${getLoggingPrefix('warn')} Store check for addons.mozilla.org: addons-linter found ${parts.join(' and ')} in ${pintor.underline(distDisplay)}`;
104
104
  }
105
- function addonLintFinding(level, code, message, location) {
105
+ function addonLintFinding(level, code, message, location, attribution) {
106
106
  const glyph = getLoggingPrefix('error' === level ? 'warn' : 'info');
107
107
  const where = location ? ` ${pintor.gray(`(${location})`)}` : '';
108
- return `${glyph} AMO ${level} ${pintor.yellow(code)}: ${message}${where}`;
108
+ const from = attribution ? ` ${pintor.gray(attribution)}` : '';
109
+ return `${glyph} AMO ${level} ${pintor.yellow(code)}: ${message}${where}${from}`;
110
+ }
111
+ function addonLintDependencyAttribution(packages, onlyDependencies) {
112
+ if (0 === packages.length) return '';
113
+ const named = packages.slice(0, 3).join(', ');
114
+ const rest = packages.length > 3 ? `, +${packages.length - 3} more` : '';
115
+ return onlyDependencies ? `- this file is bundled dependency code (${named}${rest}), not yours` : `- this file also bundles ${named}${rest}, so the finding may be theirs`;
109
116
  }
110
117
  function addonLintMore(hiddenCount, distDisplay) {
111
118
  return `${getLoggingPrefix('info')} ${pluralize(hiddenCount, 'more finding')} not shown. Run ${pintor.blue(`npx addons-linter ${distDisplay}`)} for the full report.`;
@@ -198,17 +205,9 @@ function buildWarningsDetails(warnings) {
198
205
  });
199
206
  return blocks.join('\n\n');
200
207
  }
201
- function fetchingProjectPath(owner, project) {
202
- return fmt.block('Fetching project', [
203
- [
204
- 'URL',
205
- fmt.val(`https://github.com/${owner}/${project}`)
206
- ]
207
- ]);
208
- }
209
- function downloadingProjectPath(projectName) {
208
+ function downloadingProjectPath(projectName, url) {
210
209
  const formatted = isPathLike(projectName) ? pintor.underline(projectName) : projectName;
211
- return `${getLoggingPrefix('info')} Downloading ${formatted}…`;
210
+ return `${getLoggingPrefix('info')} Downloading ${formatted}…\n${pintor.gray('URL')} ${fmt.val(url)}`;
212
211
  }
213
212
  function creatingProjectPath() {
214
213
  return `${getLoggingPrefix('info')} Creating a new browser extension…`;
@@ -241,12 +240,7 @@ function writingTypeDefinitionsError(error) {
241
240
  return `${getLoggingPrefix('error')} Couldn't write the extension type definitions.\n${pintor.gray('REASON')} ${pintor.red(String(error))}\nCheck the file permissions, then try again.`;
242
241
  }
243
242
  function downloadingText(url) {
244
- return fmt.block('Downloading extension', [
245
- [
246
- 'URL',
247
- fmt.val(url)
248
- ]
249
- ]);
243
+ return `${getLoggingPrefix('info')} Downloading the browser extension…\n${pintor.gray('URL')} ${fmt.val(url)}`;
250
244
  }
251
245
  function unpackagingExtension(zipFilePath) {
252
246
  return `${getLoggingPrefix('info')} Unpackaging the browser extension…\n${pintor.gray('PATH')} ${pintor.underline(zipFilePath)}`;
@@ -591,12 +585,9 @@ async function getProjectPath(pathOrRemoteUrl) {
591
585
  const urlSource = await importUrlSourceFromZip(pathOrRemoteUrl);
592
586
  return urlSource;
593
587
  }
594
- const urlData = url.pathname.split('/');
595
- const owner = urlData.slice(1, 3)[0];
596
- const project = urlData.slice(1, 3)[1];
597
- console.log(fetchingProjectPath(owner, project));
588
+ const [owner, project] = url.pathname.split('/').slice(1, 3);
598
589
  const projectName = __rspack_external_node_path_806ed179.basename(url.pathname);
599
- const urlSource = await importUrlSourceFromGithub(pathOrRemoteUrl, downloadingProjectPath(projectName));
590
+ const urlSource = await importUrlSourceFromGithub(pathOrRemoteUrl, downloadingProjectPath(projectName, `https://github.com/${owner}/${project}`));
600
591
  console.log(creatingProjectPath());
601
592
  return urlSource;
602
593
  }
@@ -979,4 +970,4 @@ function actionsPath(projectPath, browser) {
979
970
  function buildSummaryPath(projectPath, browser) {
980
971
  return __rspack_external_node_path_806ed179.join(browserArtifactsDir(projectPath, browser), 'build-summary.json');
981
972
  }
982
- export { actionsPath, addonLintFailed, addonLintFinding, addonLintMore, addonLintNotInstalled, addonLintSummary, anotherDevSessionActive, asAbsolute, authorInstallNotice, browserArtifactsDir, browserDistDir, browserLaunchFailed, browserProfileRootDir, buildAssetsTree, buildCommandFailed, buildComplete, buildFailed, buildShareHint, buildSummaryPath, buildWarningsDetails, computePreviewOutputPath, configBrowserOrThrow, configLoadingError, controlPortFilePath, controlTokenPath, debugBrowser, debugContextPath, debugDirs, debugExtensionsToLoad, debugOutputPath, debugPreviewOutput, debugSplitChunksNarrowed, devCommandFailed, devtoolsEngineFor, downloadingText, ensureSessionArtifactsIgnoreFile, ensureSessionStateInProjectGitignore, eventsPath, extensionLoadRecovered, extensionLoadStillRefused, failedToDownloadOrExtractZIPFileError, getDirs, getDistPath, getProjectStructure, invalidRemoteZip, isUsingExperimentalConfig, legacyControlPortFilePath, legacyControlTokenPath, localZipNotFound, logsPath, managedDependencyConflict, manifestInvalidJson, needsInstall, noCompanionExtensionsResolved, normalizeBrowser, notAZipArchive, packagingDistributionFiles, packagingSourceFiles, previewing, previewingCustomOutput, previewingSourceFallback, projectInstallFallbackToNpm, projectInstallInWorkspaceRoot, projectInstallScriptsDisabled, readyContractPath, resolveProjectStructureSync, sessionArtifactsRootDir, sessionStateDir, starting, toPosixPath, treeWithDistFilesBrowser, treeWithSourceAndDistFiles, treeWithSourceFiles, unpackagedSuccessfully, unpackagingExtension, writingTypeDefinitions, writingTypeDefinitionsError, zipArtifactReady };
973
+ export { actionsPath, addonLintDependencyAttribution, addonLintFailed, addonLintFinding, addonLintMore, addonLintNotInstalled, addonLintSummary, anotherDevSessionActive, asAbsolute, authorInstallNotice, browserArtifactsDir, browserDistDir, browserLaunchFailed, browserProfileRootDir, buildAssetsTree, buildCommandFailed, buildComplete, buildFailed, buildShareHint, buildSummaryPath, buildWarningsDetails, computePreviewOutputPath, configBrowserOrThrow, configLoadingError, controlPortFilePath, controlTokenPath, debugBrowser, debugContextPath, debugDirs, debugExtensionsToLoad, debugOutputPath, debugPreviewOutput, debugSplitChunksNarrowed, devCommandFailed, devtoolsEngineFor, downloadingText, ensureSessionArtifactsIgnoreFile, ensureSessionStateInProjectGitignore, eventsPath, extensionLoadRecovered, extensionLoadStillRefused, failedToDownloadOrExtractZIPFileError, getDirs, getDistPath, getProjectStructure, invalidRemoteZip, isUsingExperimentalConfig, legacyControlPortFilePath, legacyControlTokenPath, localZipNotFound, logsPath, managedDependencyConflict, manifestInvalidJson, needsInstall, noCompanionExtensionsResolved, normalizeBrowser, notAZipArchive, packagingDistributionFiles, packagingSourceFiles, previewing, previewingCustomOutput, previewingSourceFallback, projectInstallFallbackToNpm, projectInstallInWorkspaceRoot, projectInstallScriptsDisabled, readyContractPath, resolveProjectStructureSync, sessionArtifactsRootDir, sessionStateDir, starting, toPosixPath, treeWithDistFilesBrowser, treeWithSourceAndDistFiles, treeWithSourceFiles, unpackagedSuccessfully, unpackagingExtension, writingTypeDefinitions, writingTypeDefinitionsError, zipArtifactReady };
@@ -1,4 +1,8 @@
1
1
  import type { PreviewOptions } from './types.js';
2
+ /**
3
+ * Resolved browser launch options returned by extensionPreview.
4
+ * The caller is responsible for actually launching the browser.
5
+ */
2
6
  export interface ResolvedPreviewOptions {
3
7
  browser: string;
4
8
  outPath: string;
@@ -25,5 +29,9 @@ export interface ResolvedPreviewOptions {
25
29
  logUrl?: string;
26
30
  logTab?: number | string;
27
31
  }
32
+ /**
33
+ * Browser launcher callback. When provided, extensionPreview calls it
34
+ * instead of requiring plugin-browsers internally.
35
+ */
28
36
  export type PreviewLauncherFn = (opts: ResolvedPreviewOptions) => Promise<void>;
29
37
  export declare function extensionPreview(pathOrRemoteUrl: string | undefined, previewOptions: PreviewOptions, browserLauncher?: PreviewLauncherFn): Promise<void>;
@@ -4,17 +4,26 @@ export interface ReadyContractInfo {
4
4
  controlPort: number;
5
5
  instanceId: string;
6
6
  runId: string;
7
+ /** Ready-contract version, `ReadyMetadata['schemaVersion']` on current engines. */
7
8
  schemaVersion?: number;
9
+ /** Result-envelope capability advertisement, `1` on current engines. */
8
10
  schema?: number;
9
11
  logsPath?: string;
10
12
  status?: string;
13
+ /** Dev-server pid; absent in pre-4.1 contracts. */
11
14
  pid?: number;
15
+ /** Browser CDP port, stamped post-launch, may lag `status: 'ready'`. */
12
16
  cdpPort?: number;
17
+ /** Stamped when the launched browser exits while the server keeps running. */
13
18
  browserExitedAt?: string;
14
19
  browserExitCode?: number;
20
+ /** When the compile finished (ISO), the meaning of `status: 'ready'`. */
15
21
  compiledAt?: string;
22
+ /** When the extension's service worker attached to the control channel (ISO). */
16
23
  executorAttachedAt?: string;
24
+ /** `'attached'` once the SW has connected; absent while still launching. */
17
25
  runtime?: string;
26
+ /** Last contract write time (ISO). */
18
27
  ts?: string;
19
28
  binary?: string;
20
29
  binaryProvenance?: string;
@@ -46,6 +55,7 @@ export declare class BridgeConsumer {
46
55
  private timer;
47
56
  private lastCloseInfo;
48
57
  constructor(options: ConsumerOptions);
58
+ /** Why the last socket closed; null until a close has happened. */
49
59
  get lastClose(): ConsumerCloseInfo | null;
50
60
  start(): void;
51
61
  close(): void;
@@ -40,7 +40,21 @@ export interface BridgeTarget {
40
40
  tabId?: number;
41
41
  }
42
42
  export type CommandOp = 'eval' | 'storage.get' | 'storage.set' | 'reload' | 'open' | 'tabs.query' | 'inspect';
43
+ /**
44
+ * Granularity of a dev-loop reload. Mirrors `ReloadType` in
45
+ * plugin-reload/classify-reload.ts: the launched-browser path feeds this
46
+ * decision to the CDP controller; the `--no-browser` path feeds the same
47
+ * decision to the broker, which broadcasts a {@link ReloadFrame} to the SW
48
+ * producer.
49
+ */
43
50
  export type ReloadType = 'full' | 'service-worker' | 'content-scripts';
51
+ /**
52
+ * Everything a {@link ReloadFrame} can carry in `reloadType`: the extension
53
+ * reload granularities plus `'page'`, a notify-only signal for page-only
54
+ * edits (popup/options/sidebar/devtools/newtab). For `'page'` the producer
55
+ * performs NO reload (livereload owns the refresh); it only forwards the
56
+ * announcement so the devtools pill mirrors the dev loop.
57
+ */
44
58
  export type DevReloadKind = ReloadType | 'page';
45
59
  export type GapReason = 'ring_overflow' | 'rate_limit' | 'disk_slow' | 'slow_consumer';
46
60
  export interface HelloFrame {
@@ -101,12 +115,27 @@ export interface ResultFrame {
101
115
  code?: BridgeRefusalCode;
102
116
  };
103
117
  }
118
+ /**
119
+ * Dev-loop reload broadcast, server → producer. Sent by the broker on a compile
120
+ * that completed without a CDP controller (`--no-browser`, headless/CI, remote)
121
+ * so the service-worker producer can self-reload. Unlike a `reload` CommandFrame
122
+ * (a controller-issued, `--allow-control`-gated act verb that expects a result),
123
+ * this is a fire-and-forget dev-server signal, no cmdId, no result.
124
+ */
104
125
  export interface ReloadFrame {
105
126
  type: 'reload';
106
127
  reloadType: DevReloadKind;
107
128
  changedContentScriptEntries?: string[];
129
+ /**
130
+ * Server-built human context label, e.g. "content_script (content/scripts.tsx)".
131
+ * Shown VERBATIM by every announcement surface (CLI stdout, the page's
132
+ * devtools console line, the devtools-extension pill) so the three can
133
+ * never disagree about what is reloading.
134
+ */
108
135
  label?: string;
136
+ /** Project-relative source files that triggered this reload. */
109
137
  changedFiles?: string[];
138
+ /** Emitted scripts/ bundles the SW should replay its executeScript calls for. */
110
139
  changedScriptFiles?: string[];
111
140
  }
112
141
  export interface ReloadAckFrame {
@@ -114,6 +143,15 @@ export interface ReloadAckFrame {
114
143
  reloadType: DevReloadKind;
115
144
  label?: string;
116
145
  }
146
+ /**
147
+ * Server → producer keepalive. An MV3 service worker idles out after ~30s
148
+ * without events, and a stopped SW holds no control socket, reload
149
+ * broadcasts would reach zero producers and silently apply to nothing
150
+ * (quiet extensions lost SW/manifest reloads once >30s passed between
151
+ * edits). Receiving any WebSocket message resets the SW idle timer
152
+ * (Chrome 116+), so a periodic ping keeps the dev extension's SW
153
+ * responsive for the whole dev session. Producers ignore the frame.
154
+ */
117
155
  export interface PingFrame {
118
156
  type: 'ping';
119
157
  }
@@ -121,7 +159,11 @@ export type ClientFrame = HelloFrame | LogFrame | CommandFrame | ReloadAckFrame;
121
159
  export type ServerFrame = ReadyFrame | LogFrame | GapFrame | ResultFrame | ReloadFrame | PingFrame;
122
160
  export type AnyFrame = ClientFrame | ServerFrame;
123
161
  export declare const CONTROL_WS_PATH = "/extjs-control";
162
+ /** The hello named an instanceId from a previous dev session. */
124
163
  export declare const CLOSE_BAD_INSTANCE = 4001;
164
+ /** The hello was malformed: wrong envelope version, or an unknown role. */
125
165
  export declare const CLOSE_BAD_HELLO = 4002;
166
+ /** A controller dialed a session started without `--allow-control`. */
126
167
  export declare const CLOSE_CONTROL_UNAVAILABLE = 4003;
168
+ /** The socket fell far enough behind that it was dropped to protect the broker. */
127
169
  export declare const CLOSE_SLOW_CONSUMER = 4008;
@@ -1,13 +1,22 @@
1
+ /** Increasing verbosity; a level selects itself plus everything more severe. */
1
2
  export declare const LOG_LEVEL_ORDER: readonly ['error', 'warn', 'info', 'debug', 'trace'];
2
3
  export type LogLevelFilter = (typeof LOG_LEVEL_ORDER)[number] | 'all' | 'off' | (string & {});
3
4
  export interface LogQuery {
5
+ /** One context, a comma-separated list, an array, or 'all'. */
4
6
  context?: string | string[];
7
+ /** Minimum severity. 'all' and 'off' select every level. */
5
8
  level?: LogLevelFilter;
9
+ /** Only structured dx.signal diagnostics. */
6
10
  signalsOnly?: boolean;
11
+ /** Only events after this point: a sequence number, or an ISO timestamp
12
+ * compared against the event's own clock. */
7
13
  since?: number | string;
14
+ /** Glob (`*` = any run of chars) or plain substring over url then hostname. */
8
15
  url?: string;
16
+ /** Only events carrying this tab id. */
9
17
  tab?: number | string;
10
18
  }
19
+ /** A bridge log line as read off disk: dynamic, so the probed fields only. */
11
20
  export interface LogEventLike {
12
21
  type?: unknown;
13
22
  eventType?: unknown;
@@ -21,6 +30,7 @@ export interface LogEventLike {
21
30
  tabId?: unknown;
22
31
  }
23
32
  export declare function logLevelRank(level: string): number;
33
+ /** How a `since` value is read: a sequence number, or a point in time. */
24
34
  export type LogSince = {
25
35
  seq: number;
26
36
  } | {
@@ -28,5 +38,11 @@ export type LogSince = {
28
38
  };
29
39
  export declare function parseLogSince(value: unknown): LogSince | null | undefined;
30
40
  export declare function isAfterSince(event: LogEventLike, since: LogSince): boolean;
41
+ /** True when the event passes every clause of the query. */
31
42
  export declare function matchesLogQuery(event: LogEventLike, query: LogQuery): boolean;
43
+ /**
44
+ * One-shot read of a session's logs.ndjson. Returns an empty array when the
45
+ * session has never written one: an absent file is "nothing logged yet", and
46
+ * making that a throw would force every caller to guard it.
47
+ */
32
48
  export declare function readLogEvents(projectPath: string, browser?: string, query?: LogQuery): LogEventLike[];
@@ -262,6 +262,7 @@ const UNDELIVERED_RELOAD_WARN = {
262
262
  'never-connected': "SW not attached, your edit compiled but no page received it. The extension's service worker has not connected to the dev server this session (a heavy ad/bot-laden page, an auth wall, or a profile-cached worker can prevent it). Reloads resume automatically once it connects.",
263
263
  'recently-disconnected': "SW not attached, your edit compiled but no page received it. The extension's service worker disconnected (MV3 workers idle out, or the browser may have exited). Reloads resume automatically once it reconnects."
264
264
  };
265
+ const UNDELIVERED_RELOAD_WARN_WEBKIT_NEVER_CONNECTED = "Extension not connected, your edit compiled but no page received it. The extension has not connected to the dev server this session. Open Safari > Settings > Extensions and turn it on. Safari restarts the extension itself once it is enabled, and reloads resume automatically.";
265
266
  class BridgeBroker {
266
267
  instanceId;
267
268
  runId;
@@ -382,6 +383,7 @@ class BridgeBroker {
382
383
  if (options?.producerRestartExpected && 'recently-disconnected' === kind) return null;
383
384
  if (this.lastUndeliveredWarnKind === kind) return null;
384
385
  this.lastUndeliveredWarnKind = kind;
386
+ if ('never-connected' === kind && 'webkit' === this.engine) return UNDELIVERED_RELOAD_WARN_WEBKIT_NEVER_CONNECTED;
385
387
  return UNDELIVERED_RELOAD_WARN[kind];
386
388
  }
387
389
  pingProducers() {
@@ -1,3 +1,4 @@
1
+ import type { ChunkProvenance } from './chunk-dependency-provenance.js';
1
2
  export declare const ADDON_LINT_DEFAULT = true;
2
3
  export declare const ADDON_LINT_TIMEOUT_MS = 10000;
3
4
  export declare const ADDON_LINT_MAX_PRINTED = 20;
@@ -54,6 +55,7 @@ export interface RunAddonLintInput {
54
55
  enabled?: boolean;
55
56
  loadLinter?: LoadAddonLinter;
56
57
  timeoutMs?: number;
58
+ chunkProvenance?: () => Map<string, ChunkProvenance>;
57
59
  }
58
60
  export declare function shouldRunAddonLint(input: {
59
61
  browser: string;
@@ -63,7 +65,8 @@ export declare function shouldRunAddonLint(input: {
63
65
  status: 'skipped';
64
66
  }> | null;
65
67
  export declare function collectAddonLintLines(output: AddonLintOutput | null | undefined): AddonLintLine[];
66
- export declare function formatAddonLintFindings(output: AddonLintOutput | null | undefined, distDisplay: string, maxPrinted?: number): {
68
+ export declare function attributionFor(location: string, chunkProvenance?: Map<string, ChunkProvenance>): string;
69
+ export declare function formatAddonLintFindings(output: AddonLintOutput | null | undefined, distDisplay: string, maxPrinted?: number, chunkProvenance?: Map<string, ChunkProvenance>): {
67
70
  findings: number;
68
71
  lines: string[];
69
72
  };
@@ -1,3 +1,9 @@
1
+ /**
2
+ * What the injected Safari packager reports back about the app it produced.
3
+ * `bundleIdDerived` is the load-bearing one: a generated `dev.extensionjs.*`
4
+ * identifier comes from the app name, so every project built from the same
5
+ * source shares it and the first registration takes it.
6
+ */
1
7
  export interface SafariPackageSummary {
2
8
  appName?: string;
3
9
  bundleId?: string;
@@ -8,13 +14,18 @@ export interface SafariPackageSummary {
8
14
  }
9
15
  export type BuildSummary = {
10
16
  browser: string;
17
+ /** Absolute dist directory the build emitted into. Hosts that shell out
18
+ * would otherwise have to re-derive `<project>/dist/<browser>` themselves. */
11
19
  output_path?: string;
12
20
  total_assets: number;
13
21
  total_bytes: number;
14
22
  largest_asset_bytes: number;
15
23
  warnings_count: number;
16
24
  errors_count: number;
25
+ /** Plain-text warning messages (ANSI-stripped, capped) so programmatic
26
+ * consumers get a structured channel instead of scraping stdout. */
17
27
  warnings?: string[];
28
+ /** Present only for safari/webkit-based builds that ran the packager. */
18
29
  safari?: SafariPackageSummary;
19
30
  };
20
31
  export declare function getBuildSummary(browser: string, info: {
@@ -0,0 +1,14 @@
1
+ export interface ChunkProvenance {
2
+ packages: string[];
3
+ onlyDependencies: boolean;
4
+ }
5
+ interface ChunkGraphLike {
6
+ getChunkModulesIterable: (chunk: never) => Iterable<unknown>;
7
+ }
8
+ export interface CompilationLike {
9
+ chunks?: Iterable<unknown>;
10
+ chunkGraph?: ChunkGraphLike;
11
+ }
12
+ export declare function packageNameFromPath(candidate: string): string | null;
13
+ export declare function collectChunkDependencyProvenance(compilation: CompilationLike | null | undefined): Map<string, ChunkProvenance>;
14
+ export {};
@@ -6,7 +6,7 @@ export declare const CHROMIUM_FAMILY_ALIASES: string[];
6
6
  export declare const GECKO_FAMILY_ALIASES: string[];
7
7
  export declare const SUPPORTED_BROWSERS: string[];
8
8
  export declare const SUPPORTED_PACKAGE_MANAGERS: readonly ['npm', 'pnpm', 'yarn', 'bun', 'deno'];
9
- export declare const SUPPORTED_RUNTIMES: readonly ['node', 'deno'];
9
+ export declare const SUPPORTED_RUNTIMES: readonly ['node', 'deno', 'bun'];
10
10
  export declare const SUPPORTED_UI_FRAMEWORKS: readonly ['react', 'preact', 'vue', 'svelte'];
11
11
  export declare const SUPPORTED_CSS_TECH: readonly ['css', 'css-modules', 'sass', 'less', 'postcss', 'tailwind'];
12
12
  export declare function isChromiumBasedBrowser(browser: string): boolean;
@@ -8,5 +8,7 @@ export interface DroppedVendorKey {
8
8
  appliedBefore: boolean;
9
9
  }
10
10
  export declare function findDroppedVendorKeys(manifest: Manifest, browser: DevOptions['browser']): DroppedVendorKey[];
11
+ export declare function isValidManifestVersion(value: unknown): value is 2 | 3;
12
+ export declare function findPrefixedManifestVersionKeys(manifest: Manifest): string[];
11
13
  export declare function isStaticTheme(manifest: Manifest | undefined | null): boolean;
12
14
  export declare function isStaticThemeSource(manifestPath: string | undefined, browser: DevOptions['browser'] | string | undefined): boolean;
@@ -21,7 +21,8 @@ export declare function anotherDevSessionActive(browser: string, pid: number, ru
21
21
  export declare function buildAssetsTree(stats: Stats | undefined): string;
22
22
  export declare function buildComplete(browser: DevOptions['browser'], distDisplayPath: string, totalBytes?: number, mode?: 'development' | 'production' | 'none'): string;
23
23
  export declare function addonLintSummary(errorCount: number, warningCount: number, distDisplay: string): string;
24
- export declare function addonLintFinding(level: 'error' | 'warning', code: string, message: string, location: string): string;
24
+ export declare function addonLintFinding(level: 'error' | 'warning', code: string, message: string, location: string, attribution?: string): string;
25
+ export declare function addonLintDependencyAttribution(packages: string[], onlyDependencies: boolean): string;
25
26
  export declare function addonLintMore(hiddenCount: number, distDisplay: string): string;
26
27
  export declare function addonLintNotInstalled(installHint: string): string;
27
28
  export declare function addonLintFailed(reason: string): string;
@@ -41,8 +42,7 @@ type LooseBuildWarning = string | null | undefined | {
41
42
  chunkName?: unknown;
42
43
  };
43
44
  export declare function buildWarningsDetails(warnings: LooseBuildWarning[]): string;
44
- export declare function fetchingProjectPath(owner: string, project: string): string;
45
- export declare function downloadingProjectPath(projectName: string): string;
45
+ export declare function downloadingProjectPath(projectName: string, url: string): string;
46
46
  export declare function creatingProjectPath(): string;
47
47
  export declare function downloadedProjectFolderNotFound(cwd: string, candidates: string[]): string;
48
48
  export declare function packagingSourceFiles(zipPath: string): string;
@@ -1,3 +1,4 @@
1
+ import { type ChildProcess } from 'node:child_process';
1
2
  import { buildExecEnv } from 'prefers-yarn';
2
3
  export { buildExecEnv };
3
4
  import type { SUPPORTED_PACKAGE_MANAGERS } from './constants.js';
@@ -43,4 +44,5 @@ export declare function buildSpawnInvocation(command: string, args: string[]): {
43
44
  command: string;
44
45
  args: string[];
45
46
  };
47
+ export declare function spawnInstallCommand(command: string, args: string[], options?: ExecOptions): ChildProcess;
46
48
  export declare function execInstallCommand(command: string, args: string[], options?: ExecOptions): Promise<void>;
@@ -49,6 +49,7 @@ export interface BrowserLaunchOptions {
49
49
  logTab?: number | string;
50
50
  logSink?: BrowserLogSink;
51
51
  }
52
+ /** Browser-generated log entry normalized by the launcher's CDP controller. */
52
53
  export interface BrowserLogSinkEvent {
53
54
  level: 'log' | 'info' | 'warn' | 'error' | 'debug';
54
55
  text: string;
@@ -73,7 +74,9 @@ export interface BrowserController {
73
74
  urlFilter?: string;
74
75
  tabFilter?: number | string;
75
76
  }): Promise<void>;
77
+ /** The browser's refusal reason for this session, or null when it loaded. */
76
78
  getExtensionLoadRefusal?(): string | null;
79
+ /** Re-offer the current dist. Only ever called while the session is refused. */
77
80
  retryExtensionLoad?(): Promise<ExtensionLoadRetryResult>;
78
81
  }
79
82
  export type BrowserLauncherFn = (opts: BrowserLaunchOptions) => Promise<BrowserController>;
@@ -83,13 +86,33 @@ export interface RunnerPlugin {
83
86
  apply(compiler: Compiler): void;
84
87
  }
85
88
  export interface BrowsersPluginOptions {
89
+ /** Injected browser launcher, provided by the CLI from programs/extension/browsers/ */
86
90
  launcher: BrowserLauncherFn;
91
+ /** Browser-related options forwarded to the launcher (outputPath/contextDir/extensionsToLoad are filled at compile time) */
87
92
  browserOptions: Omit<BrowserLaunchOptions, 'outputPath' | 'contextDir' | 'extensionsToLoad'>;
88
93
  }
94
+ /**
95
+ * BrowsersPlugin
96
+ *
97
+ * An rspack plugin that manages the browser lifecycle for extension development.
98
+ * On first successful compilation it launches a browser via the injected launcher
99
+ * function; on subsequent compilations it classifies changed files and triggers
100
+ * the appropriate reload strategy (full / service-worker / content-scripts).
101
+ *
102
+ * A `BuildEmitter` is exposed as `plugin.emitter` so that external consumers
103
+ * (CLI telemetry, wait-mode, etc.) can subscribe to build events without
104
+ * coupling to rspack.
105
+ */
89
106
  export declare class BrowsersPlugin implements RunnerPlugin {
90
107
  private readonly options;
91
108
  static readonly name = "plugin-browsers";
109
+ /** EventEmitter for build lifecycle events (compiled, error, close). */
92
110
  readonly emitter: BuildEmitter;
111
+ /**
112
+ * Extension directories to load alongside the user extension.
113
+ * Set externally by webpack-config after computing companion extensions,
114
+ * before the first compilation.
115
+ */
93
116
  extensionsToLoad: string[];
94
117
  private isFirstCompile;
95
118
  private controller;
@@ -97,6 +120,11 @@ export declare class BrowsersPlugin implements RunnerPlugin {
97
120
  private logSink;
98
121
  private lastReportedRefusal;
99
122
  constructor(options: BrowsersPluginOptions);
123
+ /**
124
+ * The dev server injects the control-bridge broker so a launched
125
+ * Chromium reloads through the SW producer (the same path as `--no-browser`),
126
+ * not the CDP controller. Called once, before the first compile.
127
+ */
100
128
  setReloadBroker(broker: ReloadBroker): void;
101
129
  setLogSink(sink: BrowserLogSink): void;
102
130
  private retryRefusedExtensionLoad;
@@ -1,6 +1,8 @@
1
1
  import { type Compiler } from '@rspack/core';
2
2
  import type { DevOptions, PluginInterface } from '../types.js';
3
3
  export declare const IMPORT_META_URL_RUNTIME = "(function(){var h=typeof document!==\"undefined\"&&document.baseURI||self.location.href;try{var g=globalThis,r=(g.browser||g.chrome).runtime.getURL(\"/\");return h.indexOf(r)===0?h:r}catch(_){return h}})()";
4
+ export declare function importMetaUrlForEmitPath(emitPath: string): string;
5
+ export declare function toJsStringLiteral(value: string): string;
4
6
  export declare function getEnvFileCandidates(browser: DevOptions['browser'], mode: string): string[];
5
7
  export declare class EnvPlugin {
6
8
  readonly browser: DevOptions['browser'];
@@ -1,6 +1,7 @@
1
1
  export declare function installingRootDependencies(integration: string): string;
2
2
  export declare function integrationInstalledSuccessfully(integration: string): string;
3
3
  export declare function isUsingIntegration(name: string): string;
4
+ export declare function solidIsNotSupported(): string;
4
5
  export declare function youAreAllSet(name: string): string;
5
6
  export declare function creatingTSConfig(): string;
6
7
  export declare function failedToInstallIntegration(integration: string, error: unknown): string;
@@ -1,3 +1,6 @@
1
1
  import type { JsFramework } from '../../types.js';
2
2
  export declare function isUsingSolid(projectPath: string): boolean;
3
+ type ResolveFromProject = (id: string) => string | undefined;
4
+ export declare function resolveSolidHyperscript(resolveFromProject: ResolveFromProject): string | undefined;
3
5
  export declare function maybeUseSolid(projectPath: string): Promise<JsFramework | undefined>;
6
+ export {};
@@ -3,6 +3,22 @@ export declare function isUsingTypeScript(projectPath: string): boolean;
3
3
  export declare function ensureTypeScriptConfig(projectPath: string): void;
4
4
  export declare function defaultTypeScriptConfig(projectPath: string, _opts?: unknown): {
5
5
  compilerOptions: {
6
+ jsxImportSource: import("../js-frameworks-lib/jsx-transform.js").JsxImportSource;
7
+ allowJs: boolean;
8
+ allowSyntheticDefaultImports: boolean;
9
+ esModuleInterop: boolean;
10
+ forceConsistentCasingInFileNames: boolean;
11
+ jsx: string;
12
+ lib: string[];
13
+ moduleResolution: string;
14
+ module: string;
15
+ resolveJsonModule: boolean;
16
+ strict: boolean;
17
+ target: string;
18
+ isolatedModules: boolean;
19
+ skipLibCheck: boolean;
20
+ } | {
21
+ jsxImportSource?: undefined;
6
22
  allowJs: boolean;
7
23
  allowSyntheticDefaultImports: boolean;
8
24
  esModuleInterop: boolean;
@@ -1,3 +1,4 @@
1
- export type AssetCategory = 'content-script' | 'service-worker' | 'page' | 'runtime' | 'ignored';
1
+ export declare const ASSET_CATEGORIES: readonly ['content-script', 'service-worker', 'page', 'runtime', 'ignored'];
2
+ export type AssetCategory = (typeof ASSET_CATEGORIES)[number];
2
3
  export declare function categorizeAsset(rawName: string): AssetCategory;
3
4
  export declare const BUDGET_BYTES: Record<AssetCategory, number>;
@@ -11,4 +11,4 @@ export declare class PerfBudgetsPlugin {
11
11
  apply(compiler: Compiler): void;
12
12
  }
13
13
  export type { AssetCategory } from './categorize.js';
14
- export { BUDGET_BYTES, categorizeAsset } from './categorize.js';
14
+ export { ASSET_CATEGORIES, BUDGET_BYTES, categorizeAsset } from './categorize.js';
@@ -6,13 +6,17 @@ export interface ReloadInstruction {
6
6
  changedScriptFiles?: string[];
7
7
  label?: string;
8
8
  }
9
+ /** "context (fileA, fileB +2 more)", the one label every reload surface shows. */
9
10
  export declare function formatReloadContextLabel(context: string, files: string[]): string;
10
11
  export declare function pageContextFromSources(changedSources: string[]): string;
11
12
  export interface SourceFeatureIndex {
12
13
  swSources: Set<string>;
14
+ /** Source → canonical content_scripts entry names whose chunks contain it. */
13
15
  contentEntriesBySource: Map<string, Set<string>>;
14
16
  pageSources: Set<string>;
17
+ /** Source → emitted scripts/ bundle names whose chunks contain it. */
15
18
  scriptFilesBySource?: Map<string, Set<string>>;
19
+ /** Project-relative public/ roots the copier ships at the dist root. */
16
20
  publicRoots?: string[];
17
21
  }
18
22
  export declare function publicOutputPath(rel: string, publicRoots: string[] | undefined): string | undefined;
@@ -3,6 +3,24 @@ import type { DevOptions, PluginInterface } from '../types.js';
3
3
  export { buildSourceFeatureIndex, classifyReloadFromSources, formatReloadContextLabel, pageContextFromSources, publicOutputPath, type ReloadInstruction, type ReloadType, readContentScriptCount, type SourceFeatureIndex } from './classify-reload.js';
4
4
  export { type ChangedSourcesSnapshot, type ChangedSourcesTracker, createChangedSourcesTracker, dispatchReload, type ReloadBroker, type ReloadExecutor, type UndeliveredReloadContext } from './reload-dispatch.js';
5
5
  export { SetupChunkLoadingTarget } from './steps/setup-chunk-loading-target.js';
6
+ /**
7
+ * ReloadPlugin owns the dev-only reload/HMR strategy end to end:
8
+ *
9
+ * - build-time injection of the reload runtime (SetupReloadStrategy and the
10
+ * vendored webpack-target-webextension fork), the SW scripts-replay shim,
11
+ * and the control-bridge producer/relay instrumentation
12
+ * - the reload classifier and dispatch seam consumed by plugin-browsers'
13
+ * BrowsersPlugin and the dev server's `--no-browser` broadcast path
14
+ * (re-exported above from classify-reload.ts / reload-dispatch.ts)
15
+ *
16
+ * Registration order matters: this plugin must be applied AFTER
17
+ * plugin-web-extension, SetupReloadStrategy decorates the background and
18
+ * content-script entries that feature-scripts' AddScripts declares.
19
+ *
20
+ * The whole pipeline is dev-only; `EXTENSION_NO_RELOAD=true` opts out. The
21
+ * every-mode content-script wrapper (mount lifecycle) is NOT part of this
22
+ * plugin. It lives in feature-scripts/steps/add-content-script-wrapper.
23
+ */
6
24
  export declare class ReloadPlugin {
7
25
  static readonly name = "plugin-reload";
8
26
  readonly manifestPath: string;
@@ -1,4 +1,17 @@
1
+ /**
2
+ * Companion extensions are "load-only" unpacked extension directories that
3
+ * should be loaded alongside the user extension in dev/preview/start.
4
+ *
5
+ * Each directory MUST be an unpacked extension root containing a manifest.json.
6
+ */
1
7
  export type CompanionExtensionsConfig = string[] | {
8
+ /**
9
+ * Folder to scan for subfolders that contain a manifest.json.
10
+ * Example: "./extensions" -> loads "./extensions/*" (one level deep)
11
+ */
2
12
  dir?: string;
13
+ /**
14
+ * Explicit extension directories to load (absolute or relative to projectRoot).
15
+ */
3
16
  paths?: string[];
4
17
  };
@@ -13,6 +13,7 @@ export declare function manifestLegacyWarningsSummary(count: number): string;
13
13
  export declare function pageActionNotSupportedByBrowser(browser: string): string;
14
14
  export declare function pageActionDroppedForBrowserAction(browser: string): string;
15
15
  export declare function vendorPrefixedKeyDropped(key: string, familyKey: string, vendor: 'chrome' | 'edge', browser: string): string;
16
+ export declare function manifestVersionLostForBrowser(browser: string, prefixedKeys: string[], resolved: unknown): string;
16
17
  export declare function edgeStoreKeyDropped(browser: string): string;
17
18
  export declare function mv2SandboxPolicyDropped(browser: string): string;
18
19
  export declare function geckoSidePanelUnsupported(file: string): string;
@@ -0,0 +1,22 @@
1
+ export interface EmittedModule {
2
+ resource?: string;
3
+ modules?: Iterable<EmittedModule>;
4
+ }
5
+ export interface EmittedChunk {
6
+ files?: Iterable<string>;
7
+ }
8
+ export interface EmittedCompilation {
9
+ getAssets?: () => readonly {
10
+ name: string;
11
+ source: {
12
+ source(): string | Buffer;
13
+ };
14
+ }[];
15
+ chunkGraph?: {
16
+ getModuleChunksIterable(module: EmittedModule): Iterable<EmittedChunk>;
17
+ };
18
+ }
19
+ export declare function shippableText(text: string): string;
20
+ export declare function readEmittedScripts(compilation: EmittedCompilation): Map<string, string>;
21
+ export declare function readProjectSource(resource: string): string | undefined;
22
+ export declare function emittedFilesOf(compilation: EmittedCompilation, module: EmittedModule): string[] | undefined;
@@ -1,5 +1,14 @@
1
1
  import type { DevOptions, Manifest } from '../../../../types.js';
2
2
  export default function patchBackground(manifest: Manifest, browser: DevOptions['browser']): {
3
+ background: ({
4
+ scripts?: string[] | undefined;
5
+ page?: string | undefined;
6
+ persistent?: boolean | undefined;
7
+ } & {
8
+ service_worker: string;
9
+ type?: "module";
10
+ }) | undefined;
11
+ } | {
3
12
  background: {
4
13
  scripts?: string[] | undefined;
5
14
  page?: string | undefined;