extension-develop 4.1.20 → 4.1.22

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 (47) hide show
  1. package/dist/672~0.mjs +24 -1
  2. package/dist/747~0.mjs +4 -2
  3. package/dist/832~0.mjs +8 -19
  4. package/dist/840~0.mjs +434 -36
  5. package/dist/852~0.mjs +5 -1
  6. package/dist/950~0.mjs +45 -28
  7. package/dist/command-preview.d.ts +8 -0
  8. package/dist/dev-server/control-bridge/consumer-client.d.ts +10 -0
  9. package/dist/dev-server/control-bridge/contracts.d.ts +42 -0
  10. package/dist/dev-server/control-bridge/logs-query.d.ts +16 -0
  11. package/dist/dev-server~0.mjs +2 -0
  12. package/dist/lib/addon-lint.d.ts +4 -1
  13. package/dist/lib/build-summary.d.ts +11 -0
  14. package/dist/lib/chunk-dependency-provenance.d.ts +14 -0
  15. package/dist/lib/constants.d.ts +1 -1
  16. package/dist/lib/manifest-utils.d.ts +2 -0
  17. package/dist/lib/messages.d.ts +3 -3
  18. package/dist/lib/messaging.d.ts +1 -0
  19. package/dist/lib/package-manager.d.ts +2 -0
  20. package/dist/lib/paths.d.ts +3 -0
  21. package/dist/plugin-browsers/index.d.ts +28 -0
  22. package/dist/plugin-compilation/env.d.ts +2 -0
  23. package/dist/plugin-js-frameworks/js-frameworks-lib/messages.d.ts +1 -0
  24. package/dist/plugin-js-frameworks/js-tools/solid.d.ts +3 -0
  25. package/dist/plugin-js-frameworks/js-tools/typescript.d.ts +16 -0
  26. package/dist/plugin-perf-budgets/categorize.d.ts +2 -1
  27. package/dist/plugin-perf-budgets/index.d.ts +1 -1
  28. package/dist/plugin-playwright/index.d.ts +1 -0
  29. package/dist/plugin-reload/classify-reload.d.ts +4 -0
  30. package/dist/plugin-reload/index.d.ts +18 -0
  31. package/dist/plugin-special-folders/folder-extensions/types.d.ts +13 -0
  32. package/dist/plugin-special-folders/messages.d.ts +2 -2
  33. package/dist/plugin-web-extension/feature-manifest/messages.d.ts +1 -0
  34. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/emitted-evidence.d.ts +22 -0
  35. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/patch-background.d.ts +9 -0
  36. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults-lib/patch-web-resources.d.ts +7 -16
  37. package/dist/plugin-web-extension/feature-manifest/steps/apply-dev-defaults.d.ts +6 -2
  38. package/dist/plugin-web-extension/feature-manifest/steps/warn-gecko-unsupported-apis.d.ts +2 -13
  39. package/dist/plugin-web-extension/feature-scripts/messages.d.ts +5 -0
  40. package/dist/plugin-web-extension/feature-scripts/steps/warn-page-context-worker.d.ts +5 -0
  41. package/dist/plugin-web-extension/feature-web-resources/collect-entry-imports.d.ts +1 -0
  42. package/dist/plugin-web-extension/feature-web-resources/web-resources-lib/messages.d.ts +1 -0
  43. package/dist/plugin-web-extension/feature-web-resources/web-resources-lib/unreachable-resources.d.ts +9 -0
  44. package/dist/rspack-config.d.ts +1 -1
  45. package/dist/rspack-config~0.mjs +432 -465
  46. package/dist/types.d.ts +190 -0
  47. package/package.json +1 -1
package/dist/950~0.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  import { createRequire as __extjsCreateRequire } from "node:module"; const require = __extjsCreateRequire(import.meta.url);
2
2
  import pintor from "pintor";
3
3
  import { spawnSync } from "node:child_process";
4
- import { fmt, isDebug, artifactNoun, prefix as messaging_prefix } from "./852~0.mjs";
4
+ import { fmt, isDebug, artifactNoun, prefix as messaging_prefix, hasChannelPrefix } from "./852~0.mjs";
5
5
  import { findNearestDenoConfigSync, validateDenoConfig, PROJECT_MANIFEST_FILENAMES, parseJsonSafe, readProjectDependencies } from "./731~0.mjs";
6
6
  import * as __rspack_external_node_path_806ed179 from "node:path";
7
7
  import * as __rspack_external_node_fs_1b05aee1 from "node:fs";
8
+ import * as __rspack_external_node_os_4f3c9d58 from "node:os";
8
9
  function getLoggingPrefix(type) {
9
10
  return messaging_prefix(type);
10
11
  }
@@ -102,10 +103,17 @@ function addonLintSummary(errorCount, warningCount, distDisplay) {
102
103
  if (warningCount > 0) parts.push(pluralize(warningCount, 'warning'));
103
104
  return `${getLoggingPrefix('warn')} Store check for addons.mozilla.org: addons-linter found ${parts.join(' and ')} in ${pintor.underline(distDisplay)}`;
104
105
  }
105
- function addonLintFinding(level, code, message, location) {
106
+ function addonLintFinding(level, code, message, location, attribution) {
106
107
  const glyph = getLoggingPrefix('error' === level ? 'warn' : 'info');
107
108
  const where = location ? ` ${pintor.gray(`(${location})`)}` : '';
108
- return `${glyph} AMO ${level} ${pintor.yellow(code)}: ${message}${where}`;
109
+ const from = attribution ? ` ${pintor.gray(attribution)}` : '';
110
+ return `${glyph} AMO ${level} ${pintor.yellow(code)}: ${message}${where}${from}`;
111
+ }
112
+ function addonLintDependencyAttribution(packages, onlyDependencies) {
113
+ if (0 === packages.length) return '';
114
+ const named = packages.slice(0, 3).join(', ');
115
+ const rest = packages.length > 3 ? `, +${packages.length - 3} more` : '';
116
+ 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
117
  }
110
118
  function addonLintMore(hiddenCount, distDisplay) {
111
119
  return `${getLoggingPrefix('info')} ${pluralize(hiddenCount, 'more finding')} not shown. Run ${pintor.blue(`npx addons-linter ${distDisplay}`)} for the full report.`;
@@ -129,16 +137,22 @@ function buildFailed(errorCount) {
129
137
  function stripModuleWarningWrapper(message) {
130
138
  return message.replace(/^Module (?:Warning|Error) \(from [^)]*\):\s*/, '');
131
139
  }
140
+ function stripBundlerDecoration(message) {
141
+ return message.replace(/\r/g, '').split('\n').map((line, index)=>0 === index ? line.replace(/^\s*⚠ ?/, '') : line.replace(/^\s*│ ?/, '')).join('\n').trim();
142
+ }
143
+ function cleanWarningText(message) {
144
+ return stripModuleWarningWrapper(stripBundlerDecoration(message));
145
+ }
132
146
  function getWarningMessage(warning) {
133
147
  if (!warning) return '';
134
- if ('string' == typeof warning) return stripModuleWarningWrapper(warning.trim());
148
+ if ('string' == typeof warning) return cleanWarningText(warning);
135
149
  const candidates = [
136
150
  warning.message,
137
151
  warning.details,
138
152
  warning.reason,
139
153
  warning.description
140
154
  ];
141
- for (const candidate of candidates)if ('string' == typeof candidate && candidate.trim()) return stripModuleWarningWrapper(candidate.trim());
155
+ for (const candidate of candidates)if ('string' == typeof candidate && candidate.trim()) return cleanWarningText(candidate);
142
156
  return '';
143
157
  }
144
158
  function getWarningSource(warning) {
@@ -192,23 +206,17 @@ function buildWarningsDetails(warnings) {
192
206
  if (!message) return void blocks.push(`${getLoggingPrefix('warn')} Warning ${index + 1}: details were suppressed by tool output.\n${formatWarningLabelLine('Source', pintor.gray(source))}\n${formatWarningLabelLine('Hint', 'Re-run with EXTENSION_VERBOSE=1 to inspect full warning messages.')}`);
193
207
  const performanceWarning = parsePerformanceWarning(warning, source, artifact);
194
208
  if (performanceWarning) return void blocks.push(performanceWarning);
209
+ if (hasChannelPrefix(message)) return void blocks.push(message);
210
+ const explained = message.includes('\n');
195
211
  const oneLine = message.replace(/\s+/g, ' ').trim();
196
212
  const artifactSuffix = artifact ? ` ${pintor.gray(`(${artifact})`)}` : '';
197
- blocks.push(`${getLoggingPrefix('warn')} ${category}: ${oneLine}${artifactSuffix}\n${formatWarningLabelLine('Source', pintor.gray(source))}\n${formatWarningLabelLine('Hint', hint)}`);
213
+ blocks.push(`${getLoggingPrefix('warn')} ${category}: ${oneLine}${artifactSuffix}\n` + formatWarningLabelLine('Source', pintor.gray(source)) + (explained ? '' : `\n${formatWarningLabelLine('Hint', hint)}`));
198
214
  });
199
215
  return blocks.join('\n\n');
200
216
  }
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) {
217
+ function downloadingProjectPath(projectName, url) {
210
218
  const formatted = isPathLike(projectName) ? pintor.underline(projectName) : projectName;
211
- return `${getLoggingPrefix('info')} Downloading ${formatted}…`;
219
+ return `${getLoggingPrefix('info')} Downloading ${formatted}…\n${pintor.gray('URL')} ${fmt.val(url)}`;
212
220
  }
213
221
  function creatingProjectPath() {
214
222
  return `${getLoggingPrefix('info')} Creating a new browser extension…`;
@@ -241,12 +249,7 @@ function writingTypeDefinitionsError(error) {
241
249
  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
250
  }
243
251
  function downloadingText(url) {
244
- return fmt.block('Downloading extension', [
245
- [
246
- 'URL',
247
- fmt.val(url)
248
- ]
249
- ]);
252
+ return `${getLoggingPrefix('info')} Downloading the browser extension…\n${pintor.gray('URL')} ${fmt.val(url)}`;
250
253
  }
251
254
  function unpackagingExtension(zipFilePath) {
252
255
  return `${getLoggingPrefix('info')} Unpackaging the browser extension…\n${pintor.gray('PATH')} ${pintor.underline(zipFilePath)}`;
@@ -591,12 +594,9 @@ async function getProjectPath(pathOrRemoteUrl) {
591
594
  const urlSource = await importUrlSourceFromZip(pathOrRemoteUrl);
592
595
  return urlSource;
593
596
  }
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));
597
+ const [owner, project] = url.pathname.split('/').slice(1, 3);
598
598
  const projectName = __rspack_external_node_path_806ed179.basename(url.pathname);
599
- const urlSource = await importUrlSourceFromGithub(pathOrRemoteUrl, downloadingProjectPath(projectName));
599
+ const urlSource = await importUrlSourceFromGithub(pathOrRemoteUrl, downloadingProjectPath(projectName, `https://github.com/${owner}/${project}`));
600
600
  console.log(creatingProjectPath());
601
601
  return urlSource;
602
602
  }
@@ -746,6 +746,23 @@ function asAbsolute(p) {
746
746
  function toPosixPath(p) {
747
747
  return p.split(__rspack_external_node_path_806ed179.sep).join('/');
748
748
  }
749
+ function collapseHomeDir(value) {
750
+ const raw = String(value || '');
751
+ const home = __rspack_external_node_os_4f3c9d58.homedir();
752
+ if (!home || !raw.startsWith(home)) return raw;
753
+ const rest = raw.slice(home.length);
754
+ if ('' === rest) return '~';
755
+ if (rest.startsWith(__rspack_external_node_path_806ed179.sep) || rest.startsWith('/')) return `~${rest}`;
756
+ return raw;
757
+ }
758
+ function relativeToDir(target, base) {
759
+ const relative = __rspack_external_node_path_806ed179.relative(base, target);
760
+ if (relative && !relative.startsWith('..') && !__rspack_external_node_path_806ed179.isAbsolute(relative)) return relative;
761
+ return null;
762
+ }
763
+ function displayPath(target, base = process.cwd()) {
764
+ return relativeToDir(target, base) || collapseHomeDir(target);
765
+ }
749
766
  function getDirs(struct) {
750
767
  const manifestDir = asAbsolute(__rspack_external_node_path_806ed179.dirname(struct.manifestPath));
751
768
  const projectManifestPath = struct.packageJsonPath || struct.denoJsonPath;
@@ -979,4 +996,4 @@ function actionsPath(projectPath, browser) {
979
996
  function buildSummaryPath(projectPath, browser) {
980
997
  return __rspack_external_node_path_806ed179.join(browserArtifactsDir(projectPath, browser), 'build-summary.json');
981
998
  }
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 };
999
+ export { actionsPath, addonLintDependencyAttribution, addonLintFailed, addonLintFinding, addonLintMore, addonLintNotInstalled, addonLintSummary, anotherDevSessionActive, asAbsolute, authorInstallNotice, browserArtifactsDir, browserDistDir, browserLaunchFailed, browserProfileRootDir, buildAssetsTree, buildCommandFailed, buildComplete, buildFailed, buildShareHint, buildSummaryPath, buildWarningsDetails, collapseHomeDir, computePreviewOutputPath, configBrowserOrThrow, configLoadingError, controlPortFilePath, controlTokenPath, debugBrowser, debugContextPath, debugDirs, debugExtensionsToLoad, debugOutputPath, debugPreviewOutput, debugSplitChunksNarrowed, devCommandFailed, devtoolsEngineFor, displayPath, 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, relativeToDir, 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,6 +1,7 @@
1
1
  export type Channel = 'info' | 'success' | 'warn' | 'error' | 'debug';
2
2
  export declare function isDebug(): boolean;
3
3
  export declare function prefix(type: Channel): string;
4
+ export declare function hasChannelPrefix(text: string): boolean;
4
5
  export declare function isMachineOutput(): boolean;
5
6
  export declare function humanLine(...parts: unknown[]): void;
6
7
  export declare function humanWarn(...parts: unknown[]): void;
@@ -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>;
@@ -6,6 +6,9 @@ export type BrowserInput = 'chrome' | 'edge' | 'chromium' | 'firefox' | 'brave'
6
6
  export type NormalizedBrowser = 'chrome' | 'edge' | 'chromium' | 'firefox' | 'brave' | 'opera' | 'vivaldi' | 'yandex' | 'waterfox' | 'librewolf' | 'chromium-based' | 'gecko-based' | 'safari' | 'webkit-based';
7
7
  export declare function asAbsolute(p: string): AbsolutePath;
8
8
  export declare function toPosixPath(p: string): string;
9
+ export declare function collapseHomeDir(value: string): string;
10
+ export declare function relativeToDir(target: string, base: string): string | null;
11
+ export declare function displayPath(target: string, base?: string): string;
9
12
  export declare function getDirs(struct: ProjectStructure): {
10
13
  manifestDir: AbsolutePath;
11
14
  packageJsonDir: AbsolutePath;
@@ -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';
@@ -30,6 +30,7 @@ export type ReadyMetadata = {
30
30
  rdpPort?: number;
31
31
  profilePath?: string;
32
32
  browserPid?: number;
33
+ launcherPid?: number;
33
34
  toolchainVersion: string;
34
35
  extensionName?: string;
35
36
  extensionVersion?: string;
@@ -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;