extension 4.1.29 → 4.1.30

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.
package/dist/597.cjs CHANGED
@@ -193,6 +193,8 @@ exports.modules = {
193
193
  var external_node_path_ = __webpack_require__("node:path");
194
194
  var messaging = __webpack_require__("./helpers/messaging.ts");
195
195
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
196
+ var browser_family = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
197
+ var companion_session = __webpack_require__("./browsers/browsers-lib/companion-session.ts");
196
198
  var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
197
199
  var newtab_override = __webpack_require__("./browsers/browsers-lib/newtab-override.ts");
198
200
  var ready_stamp = __webpack_require__("./browsers/browsers-lib/ready-stamp.ts");
@@ -828,7 +830,12 @@ exports.modules = {
828
830
  else obj[key] = value;
829
831
  return obj;
830
832
  }
831
- const DEVTOOLS_COMPANION_ID_CHROMIUM = 'kgdaecdpfkikjncaalnmmnjjfpofkcbl';
833
+ function devtoolsCompanionWelcomeUrl(companionPath) {
834
+ return `chrome-extension://${(0, banner.vy)(companionPath)}/pages/welcome.html`;
835
+ }
836
+ const FORK_FIRST_RUN_PAGES = {
837
+ vivaldi: /^chrome-extension:\/\/mpognobbkildjkofajifpdfhcoklimli\/components\/welcome\//
838
+ };
832
839
  const __fileReadCache = new Map();
833
840
  function readTextFileCached(filePath) {
834
841
  try {
@@ -863,11 +870,32 @@ exports.modules = {
863
870
  url
864
871
  });
865
872
  }
873
+ async replaceForkFirstRunTabs(browser, replacementUrl) {
874
+ if (!this.cdp) return 0;
875
+ const pattern = FORK_FIRST_RUN_PAGES[String(browser || '').toLowerCase()];
876
+ if (!pattern) return 0;
877
+ const targets = await this.cdp.getTargets();
878
+ let replaced = 0;
879
+ for (const target of targets)if (target?.type === 'page') {
880
+ if (pattern.test(String(target?.url || ''))) try {
881
+ const attached = await this.cdp.sendCommand('Target.attachToTarget', {
882
+ targetId: target.targetId,
883
+ flatten: true
884
+ });
885
+ const sessionId = attached?.sessionId || '';
886
+ if (!sessionId) continue;
887
+ await this.cdp.sendCommand('Page.navigate', {
888
+ url: replacementUrl
889
+ }, sessionId);
890
+ replaced += 1;
891
+ } catch {}
892
+ }
893
+ return replaced;
894
+ }
866
895
  async closeSelfOpenedTabs() {
867
896
  if (!this.cdp) return 0;
868
- const selfIds = new Set([
869
- DEVTOOLS_COMPANION_ID_CHROMIUM
870
- ]);
897
+ const selfIds = new Set();
898
+ if (this.companionPath) selfIds.add((0, banner.vy)(this.companionPath));
871
899
  for (const extensionPath of this.extensionPaths || [])if (external_node_path_.resolve(extensionPath) !== external_node_path_.resolve(this.outPath)) selfIds.add((0, banner.vy)(extensionPath));
872
900
  const targets = await this.cdp.getTargets();
873
901
  let closed = 0;
@@ -892,7 +920,8 @@ exports.modules = {
892
920
  status: 'unknown'
893
921
  };
894
922
  const expectedId = (0, banner.vy)(this.outPath);
895
- if (expectedId && (0, ensure.tg)(this.outPath)) {
923
+ const loadedFromCommandLine = !(0, browser_family.v$)(this.browser);
924
+ if (expectedId && loadedFromCommandLine && (0, ensure.tg)(this.outPath)) {
896
925
  const present = await this.waitForExtensionTarget(expectedId, 12, 200);
897
926
  if (present) {
898
927
  if (!this.extensionId) this.extensionId = expectedId;
@@ -921,6 +950,25 @@ exports.modules = {
921
950
  getLoadRefusalReason() {
922
951
  return this.loadRefusalReason;
923
952
  }
953
+ async loadCompanions(extensionPaths) {
954
+ if (!this.cdp) return [];
955
+ const results = [];
956
+ for (const extensionPath of extensionPaths){
957
+ let outcome;
958
+ try {
959
+ outcome = await (0, ensure.iF)(this.cdp, extensionPath);
960
+ } catch {
961
+ outcome = {
962
+ status: 'unknown'
963
+ };
964
+ }
965
+ results.push({
966
+ path: extensionPath,
967
+ outcome
968
+ });
969
+ }
970
+ return results;
971
+ }
924
972
  async waitForExtensionTarget(extensionId, maxRetries, backoffMs) {
925
973
  const prefix = `chrome-extension://${extensionId}/`;
926
974
  for(let attempt = 0; attempt <= maxRetries; attempt++){
@@ -1136,9 +1184,11 @@ exports.modules = {
1136
1184
  }
1137
1185
  constructor(args){
1138
1186
  cdp_extension_controller_define_property(this, "outPath", void 0);
1187
+ cdp_extension_controller_define_property(this, "browser", void 0);
1139
1188
  cdp_extension_controller_define_property(this, "cdpPort", void 0);
1140
1189
  cdp_extension_controller_define_property(this, "profilePath", void 0);
1141
1190
  cdp_extension_controller_define_property(this, "extensionPaths", void 0);
1191
+ cdp_extension_controller_define_property(this, "companionPath", void 0);
1142
1192
  cdp_extension_controller_define_property(this, "pipeIn", void 0);
1143
1193
  cdp_extension_controller_define_property(this, "pipeOut", void 0);
1144
1194
  cdp_extension_controller_define_property(this, "logSink", void 0);
@@ -1146,9 +1196,11 @@ exports.modules = {
1146
1196
  cdp_extension_controller_define_property(this, "extensionId", null);
1147
1197
  cdp_extension_controller_define_property(this, "loadRefusalReason", null);
1148
1198
  this.outPath = args.outPath;
1199
+ this.browser = args.browser;
1149
1200
  this.cdpPort = args.cdpPort;
1150
1201
  this.profilePath = args.profilePath;
1151
1202
  this.extensionPaths = args.extensionPaths;
1203
+ this.companionPath = args.companionPath;
1152
1204
  this.pipeIn = args.pipeIn;
1153
1205
  this.pipeOut = args.pipeOut;
1154
1206
  this.logSink = args.logSink;
@@ -1162,6 +1214,7 @@ exports.modules = {
1162
1214
  const selectedExtensionPaths = extensionOutputPath && extensionOutputPath.length > 0 ? [
1163
1215
  extensionOutputPath
1164
1216
  ] : extensionPaths;
1217
+ const companionPath = extensionPaths.find(companion_session.Ck);
1165
1218
  const remoteDebugPortFlag = chromiumArgs.find((flag)=>flag.startsWith('--remote-debugging-port='));
1166
1219
  const chromeRemoteDebugPort = remoteDebugPortFlag ? parseInt(remoteDebugPortFlag.split('=')[1], 10) : (0, shared_utils.jl)(plugin.port, plugin.instanceId);
1167
1220
  const userDataDirFlag = chromiumArgs.find((flag)=>flag.startsWith('--user-data-dir='));
@@ -1173,10 +1226,11 @@ exports.modules = {
1173
1226
  }
1174
1227
  const cdpExtensionController = new CDPExtensionController({
1175
1228
  outPath: extensionOutputPath,
1176
- browser: 'chromium-based' === plugin.browser ? 'chrome' : plugin.browser,
1229
+ browser: plugin.browser,
1177
1230
  cdpPort: chromeRemoteDebugPort,
1178
1231
  profilePath: userDataDir || void 0,
1179
1232
  extensionPaths: selectedExtensionPaths,
1233
+ companionPath,
1180
1234
  pipeIn: pipeStreams?.input,
1181
1235
  pipeOut: pipeStreams?.output,
1182
1236
  logSink: plugin.logSink
@@ -1344,9 +1398,18 @@ exports.modules = {
1344
1398
  });
1345
1399
  } catch {}
1346
1400
  }
1401
+ try {
1402
+ if ((0, browser_family.v$)(plugin.browser)) {
1403
+ const results = await cdpExtensionController.loadCompanions((0, companion_session.xz)(extensionPaths, extensionOutputPath));
1404
+ if ((0, messaging._o)()) for (const { path: loadedPath, outcome } of results)(0, messaging._w)(`[CDP] companion ${loadedPath}: ${outcome.status}${'refused' === outcome.status ? ` (${outcome.reason})` : ''}`);
1405
+ }
1406
+ } catch {}
1347
1407
  try {
1348
1408
  if (extensionControllerInfo && !plugin.startingUrl && !plugin.noOpen && (0, newtab_override.c)(extensionOutputPath)) await cdpExtensionController.openTab('chrome://newtab/');
1349
1409
  } catch {}
1410
+ try {
1411
+ if (extensionControllerInfo) await cdpExtensionController.replaceForkFirstRunTabs(plugin.browser, plugin.noOpen || !companionPath ? 'about:blank' : devtoolsCompanionWelcomeUrl(companionPath));
1412
+ } catch {}
1350
1413
  try {
1351
1414
  if (plugin.noOpen) await cdpExtensionController.closeSelfOpenedTabs();
1352
1415
  } catch {}
package/dist/browsers.cjs CHANGED
@@ -289,6 +289,9 @@ var __webpack_modules__ = {
289
289
  'vivaldi',
290
290
  'yandex'
291
291
  ]);
292
+ const CDP_ONLY_EXTENSION_LOAD_BROWSERS = new Set([
293
+ 'yandex'
294
+ ]);
292
295
  const FIREFOX_BROWSERS = new Set([
293
296
  'firefox',
294
297
  'waterfox',
@@ -304,6 +307,9 @@ var __webpack_modules__ = {
304
307
  function isSystemLocatedChromiumFork(browser) {
305
308
  return SYSTEM_LOCATED_CHROMIUM_FORKS.has(String(browser));
306
309
  }
310
+ function loadsExtensionsOverCdpOnly(browser) {
311
+ return CDP_ONLY_EXTENSION_LOAD_BROWSERS.has(String(browser));
312
+ }
307
313
  function isFirefoxBrowser(browser) {
308
314
  return FIREFOX_BROWSERS.has(String(browser));
309
315
  }
@@ -317,24 +323,48 @@ var __webpack_modules__ = {
317
323
  M_: ()=>isFirefoxBrowser,
318
324
  cA: ()=>isSystemLocatedChromiumFork,
319
325
  eP: ()=>isEmulatorBrowser,
320
- rG: ()=>isChromiumBrowser
326
+ rG: ()=>isChromiumBrowser,
327
+ v$: ()=>loadsExtensionsOverCdpOnly
321
328
  });
322
329
  },
323
330
  "./browsers/browsers-lib/companion-session.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
324
331
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
325
332
  var node_path__rspack_import_1 = __webpack_require__("node:path");
326
333
  var _helpers_messaging__rspack_import_2 = __webpack_require__("./helpers/messaging.ts");
334
+ var _browser_family__rspack_import_3 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
327
335
  const COMPANION_SESSION_FLAGS_FILE = 'extension-js-session.json';
328
336
  const COMPANION_DIR_NAME = 'extension-js-devtools';
329
337
  function isDevtoolsCompanionPath(extensionPath) {
330
338
  return node_path__rspack_import_1.normalize(String(extensionPath || '')).split(/[\\/]+/).includes(COMPANION_DIR_NAME);
331
339
  }
340
+ function readManifest(extensionPath) {
341
+ try {
342
+ const parsed = JSON.parse(node_fs__rspack_import_0.readFileSync(node_path__rspack_import_1.join(extensionPath, 'manifest.json'), 'utf8'));
343
+ return parsed && 'object' == typeof parsed ? parsed : null;
344
+ } catch {
345
+ return null;
346
+ }
347
+ }
348
+ function companionPathsForCdpLoad(extensionPaths, outPath) {
349
+ return extensionPaths.filter((extensionPath)=>{
350
+ if (node_path__rspack_import_1.resolve(extensionPath) === node_path__rspack_import_1.resolve(outPath)) return false;
351
+ return !readManifest(extensionPath)?.theme;
352
+ });
353
+ }
354
+ function dropNewTabOverride(extensionPath) {
355
+ const manifestPath = node_path__rspack_import_1.join(extensionPath, 'manifest.json');
356
+ const manifest = readManifest(extensionPath);
357
+ if (!manifest || !('chrome_url_overrides' in manifest)) return;
358
+ delete manifest.chrome_url_overrides;
359
+ node_fs__rspack_import_0.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
360
+ }
332
361
  function stagedCompanionPath(stageRoot, companionPath) {
333
362
  return node_path__rspack_import_1.join(stageRoot, COMPANION_DIR_NAME, node_path__rspack_import_1.basename(companionPath));
334
363
  }
335
- function stageCompanionForNoOpen(input) {
364
+ function stageCompanionForSession(input) {
336
365
  const { extensionPaths } = input;
337
- if (!input.noOpen || !input.stageRoot) return extensionPaths;
366
+ const cdpOnly = (0, _browser_family__rspack_import_3.v$)(input.browser || '');
367
+ if (!input.noOpen && !cdpOnly || !input.stageRoot) return extensionPaths;
338
368
  const index = extensionPaths.findIndex((p)=>isDevtoolsCompanionPath(p));
339
369
  if (-1 === index) return extensionPaths;
340
370
  const source = extensionPaths[index];
@@ -349,11 +379,12 @@ var __webpack_modules__ = {
349
379
  recursive: true
350
380
  });
351
381
  const flags = {
352
- noOpen: true
382
+ noOpen: Boolean(input.noOpen)
353
383
  };
354
384
  node_fs__rspack_import_0.writeFileSync(node_path__rspack_import_1.join(staged, COMPANION_SESSION_FLAGS_FILE), `${JSON.stringify(flags)}\n`, 'utf8');
385
+ if (cdpOnly) dropNewTabOverride(staged);
355
386
  } catch (error) {
356
- if ((0, _helpers_messaging__rspack_import_2._o)()) (0, _helpers_messaging__rspack_import_2.mR)(`[browser] Could not stage the devtools companion for --no-open: ${error?.message || String(error)}`);
387
+ if ((0, _helpers_messaging__rspack_import_2._o)()) (0, _helpers_messaging__rspack_import_2.mR)(`[browser] Could not stage the devtools companion for this session: ${error?.message || String(error)}`);
357
388
  return extensionPaths;
358
389
  }
359
390
  const next = [
@@ -363,7 +394,9 @@ var __webpack_modules__ = {
363
394
  return next;
364
395
  }
365
396
  __webpack_require__.d(__webpack_exports__, {
366
- Br: ()=>stageCompanionForNoOpen
397
+ Ck: ()=>isDevtoolsCompanionPath,
398
+ mO: ()=>stageCompanionForSession,
399
+ xz: ()=>companionPathsForCdpLoad
367
400
  });
368
401
  },
369
402
  "./browsers/browsers-lib/constants.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1568,7 +1601,7 @@ var __webpack_modules__ = {
1568
1601
  (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1569
1602
  } catch {}
1570
1603
  }
1571
- function stampReadyBrowserExited(extensionOutputPath, code) {
1604
+ function stampReadyBrowserExited(extensionOutputPath, code, signal = null) {
1572
1605
  try {
1573
1606
  if (!extensionOutputPath) return;
1574
1607
  const readyPath = readyPathFor(extensionOutputPath);
@@ -1576,10 +1609,11 @@ var __webpack_modules__ = {
1576
1609
  const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
1577
1610
  ready.browserExitedAt = new Date().toISOString();
1578
1611
  ready.browserExitCode = code;
1612
+ ready.browserExitSignal = signal;
1579
1613
  if ('preview' === ready.command || 'start' === ready.command) {
1580
1614
  ready.status = 'error';
1581
1615
  ready.code = 'browser_exited';
1582
- ready.message = `the ${ready.browser || 'browser'} process exited (code ${code ?? 'unknown'}); nothing is running`;
1616
+ ready.message = `the ${ready.browser || 'browser'} process exited (${null == code && signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`}); nothing is running`;
1583
1617
  }
1584
1618
  (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1585
1619
  } catch {}
@@ -2857,6 +2891,18 @@ var __webpack_modules__ = {
2857
2891
  const edgeMasterPreferences = {
2858
2892
  ...masterPreferences
2859
2893
  };
2894
+ const forkPreferences = {
2895
+ vivaldi: {
2896
+ vivaldi: {
2897
+ startup: {
2898
+ has_seen_welcome_page: true
2899
+ }
2900
+ }
2901
+ }
2902
+ };
2903
+ function getForkPreferences(browser) {
2904
+ return forkPreferences[String(browser || '')] || {};
2905
+ }
2860
2906
  const DEFAULT_BROWSER_FLAGS = [
2861
2907
  '--no-first-run',
2862
2908
  '--disable-client-side-phishing-detection',
@@ -2902,7 +2948,8 @@ var __webpack_modules__ = {
2902
2948
  return merged;
2903
2949
  }
2904
2950
  function getChromiumMasterPreferences(browser) {
2905
- return 'edge' === browser ? edgeMasterPreferences : chromeMasterPreferences;
2951
+ const base = 'edge' === browser ? edgeMasterPreferences : chromeMasterPreferences;
2952
+ return deepMergePreferences(base, getForkPreferences(browser));
2906
2953
  }
2907
2954
  function seedChromiumPreferences(profilePath, browser, customPreferences) {
2908
2955
  const preferencesPath = external_node_path_.join(profilePath, 'Default', 'Preferences');
@@ -2975,9 +3022,10 @@ var __webpack_modules__ = {
2975
3022
  seedChromiumPreferences(userProfilePath, configOptions.browser, configOptions.preferences);
2976
3023
  } catch {}
2977
3024
  }
2978
- const extensionsForLaunch = (0, companion_session.Br)({
3025
+ const extensionsForLaunch = (0, companion_session.mO)({
2979
3026
  extensionPaths: extensionsToLoad,
2980
3027
  noOpen: configOptions.noOpen,
3028
+ browser: configOptions.browser,
2981
3029
  stageRoot: userProfilePath || void 0,
2982
3030
  provision
2983
3031
  });
@@ -3807,7 +3855,7 @@ var __webpack_modules__ = {
3807
3855
  const how = null == code ? `signal ${signal || 'unknown'}` : `code ${code}`;
3808
3856
  if (!(0, process_teardown.Op)(child)) {
3809
3857
  this.logger.error(this.closeHandlerContext?.isDevMode ? `[browser] ${this.options.browser} exited mid-session (${how}). The dev server is still running but reloads cannot be delivered, restart "extension dev" to relaunch the browser.` : `[browser] ${this.options.browser} exited (${how}); the preview session is over.`);
3810
- (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code);
3858
+ (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code, signal);
3811
3859
  }
3812
3860
  disposeSignalHandlers?.();
3813
3861
  const userDataDir = launchArgs.find((arg)=>arg.startsWith('--user-data-dir='))?.slice('--user-data-dir='.length).replace(/^"|"$/g, '');
@@ -4425,7 +4473,7 @@ var __webpack_modules__ = {
4425
4473
  const userJsContent = prefsToUserJs(prefs);
4426
4474
  external_node_fs_.writeFileSync(userJsPath, userJsContent);
4427
4475
  } catch {}
4428
- const extensionsToLoad = (0, companion_session.Br)({
4476
+ const extensionsToLoad = (0, companion_session.mO)({
4429
4477
  extensionPaths: configOptions.extension ? (0, runtime_options.fT)(configOptions.extension) : [],
4430
4478
  noOpen: configOptions.noOpen,
4431
4479
  stageRoot: profilePath || void 0,
@@ -6029,7 +6077,7 @@ var __webpack_modules__ = {
6029
6077
  if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
6030
6078
  if (!expected) {
6031
6079
  this.ctx.logger?.error?.(`[browser] ${this.host.browser} exited (${null == code ? `signal ${signal || 'unknown'}` : `code ${code}`}) without being asked to. The add-on may have been rejected or the browser crashed; the session cannot be driven.`);
6032
- (0, ready_stamp.Wi)(this.extensionOutputPath, code);
6080
+ (0, ready_stamp.Wi)(this.extensionOutputPath, code, signal ?? null);
6033
6081
  }
6034
6082
  this.cleanupInstance().catch((err)=>{
6035
6083
  if ((0, messaging._o)()) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
package/dist/cli.cjs CHANGED
@@ -290,6 +290,9 @@ var __webpack_modules__ = {
290
290
  'vivaldi',
291
291
  'yandex'
292
292
  ]);
293
+ const CDP_ONLY_EXTENSION_LOAD_BROWSERS = new Set([
294
+ 'yandex'
295
+ ]);
293
296
  const FIREFOX_BROWSERS = new Set([
294
297
  'firefox',
295
298
  'waterfox',
@@ -305,6 +308,9 @@ var __webpack_modules__ = {
305
308
  function isSystemLocatedChromiumFork(browser) {
306
309
  return SYSTEM_LOCATED_CHROMIUM_FORKS.has(String(browser));
307
310
  }
311
+ function loadsExtensionsOverCdpOnly(browser) {
312
+ return CDP_ONLY_EXTENSION_LOAD_BROWSERS.has(String(browser));
313
+ }
308
314
  function isFirefoxBrowser(browser) {
309
315
  return FIREFOX_BROWSERS.has(String(browser));
310
316
  }
@@ -318,24 +324,48 @@ var __webpack_modules__ = {
318
324
  M_: ()=>isFirefoxBrowser,
319
325
  cA: ()=>isSystemLocatedChromiumFork,
320
326
  eP: ()=>isEmulatorBrowser,
321
- rG: ()=>isChromiumBrowser
327
+ rG: ()=>isChromiumBrowser,
328
+ v$: ()=>loadsExtensionsOverCdpOnly
322
329
  });
323
330
  },
324
331
  "./browsers/browsers-lib/companion-session.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
325
332
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
326
333
  var node_path__rspack_import_1 = __webpack_require__("node:path");
327
334
  var _helpers_messaging__rspack_import_2 = __webpack_require__("./helpers/messaging.ts");
335
+ var _browser_family__rspack_import_3 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
328
336
  const COMPANION_SESSION_FLAGS_FILE = 'extension-js-session.json';
329
337
  const COMPANION_DIR_NAME = 'extension-js-devtools';
330
338
  function isDevtoolsCompanionPath(extensionPath) {
331
339
  return node_path__rspack_import_1.normalize(String(extensionPath || '')).split(/[\\/]+/).includes(COMPANION_DIR_NAME);
332
340
  }
341
+ function readManifest(extensionPath) {
342
+ try {
343
+ const parsed = JSON.parse(node_fs__rspack_import_0.readFileSync(node_path__rspack_import_1.join(extensionPath, 'manifest.json'), 'utf8'));
344
+ return parsed && 'object' == typeof parsed ? parsed : null;
345
+ } catch {
346
+ return null;
347
+ }
348
+ }
349
+ function companionPathsForCdpLoad(extensionPaths, outPath) {
350
+ return extensionPaths.filter((extensionPath)=>{
351
+ if (node_path__rspack_import_1.resolve(extensionPath) === node_path__rspack_import_1.resolve(outPath)) return false;
352
+ return !readManifest(extensionPath)?.theme;
353
+ });
354
+ }
355
+ function dropNewTabOverride(extensionPath) {
356
+ const manifestPath = node_path__rspack_import_1.join(extensionPath, 'manifest.json');
357
+ const manifest = readManifest(extensionPath);
358
+ if (!manifest || !('chrome_url_overrides' in manifest)) return;
359
+ delete manifest.chrome_url_overrides;
360
+ node_fs__rspack_import_0.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
361
+ }
333
362
  function stagedCompanionPath(stageRoot, companionPath) {
334
363
  return node_path__rspack_import_1.join(stageRoot, COMPANION_DIR_NAME, node_path__rspack_import_1.basename(companionPath));
335
364
  }
336
- function stageCompanionForNoOpen(input) {
365
+ function stageCompanionForSession(input) {
337
366
  const { extensionPaths } = input;
338
- if (!input.noOpen || !input.stageRoot) return extensionPaths;
367
+ const cdpOnly = (0, _browser_family__rspack_import_3.v$)(input.browser || '');
368
+ if (!input.noOpen && !cdpOnly || !input.stageRoot) return extensionPaths;
339
369
  const index = extensionPaths.findIndex((p)=>isDevtoolsCompanionPath(p));
340
370
  if (-1 === index) return extensionPaths;
341
371
  const source = extensionPaths[index];
@@ -350,11 +380,12 @@ var __webpack_modules__ = {
350
380
  recursive: true
351
381
  });
352
382
  const flags = {
353
- noOpen: true
383
+ noOpen: Boolean(input.noOpen)
354
384
  };
355
385
  node_fs__rspack_import_0.writeFileSync(node_path__rspack_import_1.join(staged, COMPANION_SESSION_FLAGS_FILE), `${JSON.stringify(flags)}\n`, 'utf8');
386
+ if (cdpOnly) dropNewTabOverride(staged);
356
387
  } catch (error) {
357
- if ((0, _helpers_messaging__rspack_import_2._o)()) (0, _helpers_messaging__rspack_import_2.mR)(`[browser] Could not stage the devtools companion for --no-open: ${error?.message || String(error)}`);
388
+ if ((0, _helpers_messaging__rspack_import_2._o)()) (0, _helpers_messaging__rspack_import_2.mR)(`[browser] Could not stage the devtools companion for this session: ${error?.message || String(error)}`);
358
389
  return extensionPaths;
359
390
  }
360
391
  const next = [
@@ -364,7 +395,9 @@ var __webpack_modules__ = {
364
395
  return next;
365
396
  }
366
397
  __webpack_require__.d(__webpack_exports__, {
367
- Br: ()=>stageCompanionForNoOpen
398
+ Ck: ()=>isDevtoolsCompanionPath,
399
+ mO: ()=>stageCompanionForSession,
400
+ xz: ()=>companionPathsForCdpLoad
368
401
  });
369
402
  },
370
403
  "./browsers/browsers-lib/constants.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -1569,7 +1602,7 @@ var __webpack_modules__ = {
1569
1602
  (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1570
1603
  } catch {}
1571
1604
  }
1572
- function stampReadyBrowserExited(extensionOutputPath, code) {
1605
+ function stampReadyBrowserExited(extensionOutputPath, code, signal = null) {
1573
1606
  try {
1574
1607
  if (!extensionOutputPath) return;
1575
1608
  const readyPath = readyPathFor(extensionOutputPath);
@@ -1577,10 +1610,11 @@ var __webpack_modules__ = {
1577
1610
  const ready = JSON.parse(node_fs__rspack_import_0.readFileSync(readyPath, 'utf-8'));
1578
1611
  ready.browserExitedAt = new Date().toISOString();
1579
1612
  ready.browserExitCode = code;
1613
+ ready.browserExitSignal = signal;
1580
1614
  if ('preview' === ready.command || 'start' === ready.command) {
1581
1615
  ready.status = 'error';
1582
1616
  ready.code = 'browser_exited';
1583
- ready.message = `the ${ready.browser || 'browser'} process exited (code ${code ?? 'unknown'}); nothing is running`;
1617
+ ready.message = `the ${ready.browser || 'browser'} process exited (${null == code && signal ? `signal ${signal}` : `code ${code ?? 'unknown'}`}); nothing is running`;
1584
1618
  }
1585
1619
  (0, _write_json_atomic__rspack_import_2.Z)(readyPath, ready);
1586
1620
  } catch {}
@@ -2848,6 +2882,18 @@ var __webpack_modules__ = {
2848
2882
  const edgeMasterPreferences = {
2849
2883
  ...masterPreferences
2850
2884
  };
2885
+ const forkPreferences = {
2886
+ vivaldi: {
2887
+ vivaldi: {
2888
+ startup: {
2889
+ has_seen_welcome_page: true
2890
+ }
2891
+ }
2892
+ }
2893
+ };
2894
+ function getForkPreferences(browser) {
2895
+ return forkPreferences[String(browser || '')] || {};
2896
+ }
2851
2897
  const DEFAULT_BROWSER_FLAGS = [
2852
2898
  '--no-first-run',
2853
2899
  '--disable-client-side-phishing-detection',
@@ -2893,7 +2939,8 @@ var __webpack_modules__ = {
2893
2939
  return merged;
2894
2940
  }
2895
2941
  function getChromiumMasterPreferences(browser) {
2896
- return 'edge' === browser ? edgeMasterPreferences : chromeMasterPreferences;
2942
+ const base = 'edge' === browser ? edgeMasterPreferences : chromeMasterPreferences;
2943
+ return deepMergePreferences(base, getForkPreferences(browser));
2897
2944
  }
2898
2945
  function seedChromiumPreferences(profilePath, browser, customPreferences) {
2899
2946
  const preferencesPath = external_node_path_.join(profilePath, 'Default', 'Preferences');
@@ -2966,9 +3013,10 @@ var __webpack_modules__ = {
2966
3013
  seedChromiumPreferences(userProfilePath, configOptions.browser, configOptions.preferences);
2967
3014
  } catch {}
2968
3015
  }
2969
- const extensionsForLaunch = (0, companion_session.Br)({
3016
+ const extensionsForLaunch = (0, companion_session.mO)({
2970
3017
  extensionPaths: extensionsToLoad,
2971
3018
  noOpen: configOptions.noOpen,
3019
+ browser: configOptions.browser,
2972
3020
  stageRoot: userProfilePath || void 0,
2973
3021
  provision
2974
3022
  });
@@ -3798,7 +3846,7 @@ var __webpack_modules__ = {
3798
3846
  const how = null == code ? `signal ${signal || 'unknown'}` : `code ${code}`;
3799
3847
  if (!(0, process_teardown.Op)(child)) {
3800
3848
  this.logger.error(this.closeHandlerContext?.isDevMode ? `[browser] ${this.options.browser} exited mid-session (${how}). The dev server is still running but reloads cannot be delivered, restart "extension dev" to relaunch the browser.` : `[browser] ${this.options.browser} exited (${how}); the preview session is over.`);
3801
- (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code);
3849
+ (0, ready_stamp.Wi)(this.closeHandlerContext?.extensionOutputPath, code, signal);
3802
3850
  }
3803
3851
  disposeSignalHandlers?.();
3804
3852
  const userDataDir = launchArgs.find((arg)=>arg.startsWith('--user-data-dir='))?.slice('--user-data-dir='.length).replace(/^"|"$/g, '');
@@ -4416,7 +4464,7 @@ var __webpack_modules__ = {
4416
4464
  const userJsContent = prefsToUserJs(prefs);
4417
4465
  external_node_fs_.writeFileSync(userJsPath, userJsContent);
4418
4466
  } catch {}
4419
- const extensionsToLoad = (0, companion_session.Br)({
4467
+ const extensionsToLoad = (0, companion_session.mO)({
4420
4468
  extensionPaths: configOptions.extension ? (0, runtime_options.fT)(configOptions.extension) : [],
4421
4469
  noOpen: configOptions.noOpen,
4422
4470
  stageRoot: profilePath || void 0,
@@ -6020,7 +6068,7 @@ var __webpack_modules__ = {
6020
6068
  if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.Th(this.host.browser));
6021
6069
  if (!expected) {
6022
6070
  this.ctx.logger?.error?.(`[browser] ${this.host.browser} exited (${null == code ? `signal ${signal || 'unknown'}` : `code ${code}`}) without being asked to. The add-on may have been rejected or the browser crashed; the session cannot be driven.`);
6023
- (0, ready_stamp.Wi)(this.extensionOutputPath, code);
6071
+ (0, ready_stamp.Wi)(this.extensionOutputPath, code, signal ?? null);
6024
6072
  }
6025
6073
  this.cleanupInstance().catch((err)=>{
6026
6074
  if ((0, messaging._o)()) this.ctx.logger?.error?.(`[browser] Cleanup error on child close: ${err?.message || err}`);
@@ -7931,7 +7979,7 @@ var __webpack_modules__ = {
7931
7979
  return Math.min(Math.max(n, min), max);
7932
7980
  }
7933
7981
  const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
7934
- const TEMPLATE_CORPUS_REF = '893a06ba86125ac721ca2df71e6eec7aba123e38';
7982
+ const TEMPLATE_CORPUS_REF = '639c381c2bcf09b15fb442e22c251567dfa68c6a';
7935
7983
  const TEMPLATE_CORPUS_SLUGS = [
7936
7984
  'action',
7937
7985
  'action-locales',
@@ -9684,8 +9732,20 @@ Cross-browser compatibility
9684
9732
  needs_headed_window: messaging.Lp.E_HEADED_WINDOW_REQUIRED,
9685
9733
  needs_user_gesture: messaging.Lp.E_USER_GESTURE_REQUIRED,
9686
9734
  surface_not_open: messaging.Lp.E_TARGET_NOT_FOUND,
9687
- api_unavailable: messaging.Lp.E_NOT_IMPLEMENTED
9735
+ surface_reply_failed: messaging.Lp.E_INTERNAL,
9736
+ api_unavailable: messaging.Lp.E_NOT_IMPLEMENTED,
9737
+ url_refused: messaging.Lp.E_ARGS,
9738
+ tab_not_found: messaging.Lp.E_TARGET_NOT_FOUND
9688
9739
  };
9740
+ const URL_REFUSED_HINT_GECKO = "Firefox refuses privileged pages (about:newtab, about:config, about:addons, and chrome:, file:, data: and javascript: urls) from an extension's tabs API. Only web urls and about:blank open this way. Open the extension's own pages by their moz-extension:// url instead.";
9741
+ const URL_REFUSED_HINT_CHROMIUM = "Chromium refuses javascript: urls from an extension's tabs API. To run code in a page, use extension eval --context content --tab <id> on a session started with --allow-eval.";
9742
+ const URL_REFUSED_HINT_GENERIC = "The browser refuses this url from an extension's tabs API. Web urls and about:blank open on every engine.";
9743
+ function urlRefusedHint(engine) {
9744
+ if ('firefox' === engine) return URL_REFUSED_HINT_GECKO;
9745
+ if ('chromium' === engine) return URL_REFUSED_HINT_CHROMIUM;
9746
+ return URL_REFUSED_HINT_GENERIC;
9747
+ }
9748
+ const TAB_NOT_FOUND_HINT = "List the open tabs and their ids with extension inspect --list-tabs, or drop --tab to target the active tab.";
9689
9749
  function codeForBridgeError(name, message, refusal) {
9690
9750
  if (refusal && refusal in REFUSAL_TO_CODE) return REFUSAL_TO_CODE[refusal];
9691
9751
  if ('Timeout' === name) return messaging.Lp.E_TIMEOUT;
@@ -9694,7 +9754,7 @@ Cross-browser compatibility
9694
9754
  if ('EvalDisabled' === name || 'EvalTokenMismatch' === name || 'Forbidden' === name) return messaging.Lp.E_EVAL_REFUSED;
9695
9755
  if ('TargetNotFound' === name) return messaging.Lp.E_TARGET_NOT_FOUND;
9696
9756
  if ('BadRequest' === name) return messaging.Lp.E_ARGS;
9697
- if ('Unsupported' === name) return /needs a --tab id|is not open/i.test(message) ? messaging.Lp.E_TARGET_NOT_FOUND : messaging.Lp.E_NOT_IMPLEMENTED;
9757
+ if ('Unsupported' === name) return /needs a --tab id|is not open|no open tab matches|no active tab/i.test(message) ? messaging.Lp.E_TARGET_NOT_FOUND : messaging.Lp.E_NOT_IMPLEMENTED;
9698
9758
  if ('EvalError' === name) return messaging.Lp.E_EVAL;
9699
9759
  if ('InspectError' === name) return messaging.Lp.E_INSPECT;
9700
9760
  if ('StorageError' === name) return messaging.Lp.E_STORAGE;
@@ -9721,7 +9781,7 @@ Cross-browser compatibility
9721
9781
  const message = 'string' == typeof raw.message ? raw.message : 'command failed';
9722
9782
  const refusal = 'string' == typeof raw.code ? raw.code : void 0;
9723
9783
  const code = codeForBridgeError(name, message, refusal);
9724
- const hint = 'string' == typeof raw.hint ? raw.hint : code === messaging.Lp.E_EVAL ? 'The expression threw inside the page. Check the expression itself.' : code === messaging.Lp.E_USER_GESTURE_REQUIRED ? "The browser opens this surface only in response to a click, and refuses to open it any other way. Click the extension in the browser toolbar to open it." : void 0;
9784
+ const hint = 'string' == typeof raw.hint ? raw.hint : 'url_refused' === refusal ? urlRefusedHint(raw.engine) : 'tab_not_found' === refusal ? TAB_NOT_FOUND_HINT : code === messaging.Lp.E_EVAL ? 'The expression threw inside the page. Check the expression itself.' : code === messaging.Lp.E_USER_GESTURE_REQUIRED ? "The browser opens this surface only in response to a click, and refuses to open it any other way. Click the extension in the browser toolbar to open it." : void 0;
9725
9785
  return {
9726
9786
  ...extras,
9727
9787
  ...messaging.Pr.fail(command, statusForCode(code), {
@@ -9993,7 +10053,17 @@ Cross-browser compatibility
9993
10053
  output: opts.output
9994
10054
  });
9995
10055
  });
9996
- commonOptions(program.command('reload').arguments('[project-path]').description(commandDescriptions.reload).option('--context <background|content|page>', 'target context (default background)').option('--tab <id>', 'for content/page: a specific tab')).action(async (projectPathArg, opts)=>{
10056
+ commonOptions(program.command('reload').arguments('[project-path]').description(commandDescriptions.reload).option('--context <background|content|page>', 'target context (default background)').option('--url <pattern>', 'for content/page: document to target (resolved to its tab)').option('--tab <id>', 'for content/page: a specific tab (default: the --url match, else the active tab)')).action(async (projectPathArg, opts)=>{
10057
+ const context = opts.context || 'background';
10058
+ if (![
10059
+ 'background',
10060
+ 'content',
10061
+ 'page'
10062
+ ].includes(context)) fail(`reload takes --context background, content or page (got ${context}). A ${context} page reloads with the extension: run extension reload without --context.`, {
10063
+ command: 'reload',
10064
+ code: messaging.Lp.E_ARGS,
10065
+ output: opts.output
10066
+ });
9997
10067
  await runCommand({
9998
10068
  projectPathArg,
9999
10069
  command: 'reload',
@@ -1,9 +1,11 @@
1
1
  import type { BrowserType } from '../browsers-types.js';
2
2
  export declare const CHROMIUM_BROWSERS: ReadonlySet<string>;
3
3
  export declare const SYSTEM_LOCATED_CHROMIUM_FORKS: ReadonlySet<string>;
4
+ export declare const CDP_ONLY_EXTENSION_LOAD_BROWSERS: ReadonlySet<string>;
4
5
  export declare const FIREFOX_BROWSERS: ReadonlySet<string>;
5
6
  export declare function isChromiumBrowser(browser: BrowserType | string): boolean;
6
7
  export declare function isSystemLocatedChromiumFork(browser: BrowserType | string): boolean;
8
+ export declare function loadsExtensionsOverCdpOnly(browser: BrowserType | string): boolean;
7
9
  export declare function isFirefoxBrowser(browser: BrowserType | string): boolean;
8
10
  export declare const EMULATOR_BROWSERS: ReadonlySet<string>;
9
11
  export declare function isEmulatorBrowser(browser: BrowserType | string): boolean;
@@ -3,10 +3,12 @@ export interface CompanionSessionFlags {
3
3
  noOpen: boolean;
4
4
  }
5
5
  export declare function isDevtoolsCompanionPath(extensionPath: string): boolean;
6
+ export declare function companionPathsForCdpLoad(extensionPaths: string[], outPath: string): string[];
6
7
  export declare function stagedCompanionPath(stageRoot: string, companionPath: string): string;
7
- export declare function stageCompanionForNoOpen(input: {
8
+ export declare function stageCompanionForSession(input: {
8
9
  extensionPaths: string[];
9
10
  noOpen?: boolean;
11
+ browser?: string;
10
12
  stageRoot?: string;
11
13
  provision?: boolean;
12
14
  }): string[];
@@ -16,4 +16,4 @@ export declare function stampReadyProfileLocked(extensionOutputPath: string | un
16
16
  pid: number;
17
17
  };
18
18
  }): void;
19
- export declare function stampReadyBrowserExited(extensionOutputPath: string | undefined, code: number | null): void;
19
+ export declare function stampReadyBrowserExited(extensionOutputPath: string | undefined, code: number | null, signal?: string | null): void;
@@ -8,11 +8,14 @@ interface ExtensionInfoResult {
8
8
  name?: string;
9
9
  version?: string;
10
10
  }
11
+ export declare function devtoolsCompanionWelcomeUrl(companionPath: string): string;
11
12
  export declare class CDPExtensionController {
12
13
  private readonly outPath;
14
+ private readonly browser;
13
15
  private readonly cdpPort;
14
16
  private readonly profilePath?;
15
17
  private readonly extensionPaths?;
18
+ private readonly companionPath?;
16
19
  private readonly pipeIn?;
17
20
  private readonly pipeOut?;
18
21
  private readonly logSink?;
@@ -21,10 +24,11 @@ export declare class CDPExtensionController {
21
24
  private loadRefusalReason;
22
25
  constructor(args: {
23
26
  outPath: string;
24
- browser: 'chrome' | 'edge' | 'chromium-based';
27
+ browser: string;
25
28
  cdpPort: number;
26
29
  profilePath?: string;
27
30
  extensionPaths?: string[];
31
+ companionPath?: string;
28
32
  pipeIn?: Readable;
29
33
  pipeOut?: Writable;
30
34
  logSink?: BrowserLogSink;
@@ -32,9 +36,14 @@ export declare class CDPExtensionController {
32
36
  connect(): Promise<void>;
33
37
  ensureDeveloperMode(): Promise<DeveloperModeOutcome>;
34
38
  openTab(url: string): Promise<void>;
39
+ replaceForkFirstRunTabs(browser: string, replacementUrl: string): Promise<number>;
35
40
  closeSelfOpenedTabs(): Promise<number>;
36
41
  verifyGuestLoaded(): Promise<LoadUnpackedOutcome>;
37
42
  getLoadRefusalReason(): string | null;
43
+ loadCompanions(extensionPaths: string[]): Promise<Array<{
44
+ path: string;
45
+ outcome: LoadUnpackedOutcome;
46
+ }>>;
38
47
  private waitForExtensionTarget;
39
48
  ensureLoaded(): Promise<ExtensionInfoResult>;
40
49
  private deriveExtensionIdFromTargets;
@@ -1,5 +1,6 @@
1
1
  import type { CompilationLike, DefaultBrowserFlags, PluginInterface } from '../../browsers-types.js';
2
2
  export declare const DEFAULT_BROWSER_FLAGS: DefaultBrowserFlags[];
3
+ export declare function getChromiumMasterPreferences(browser: PluginInterface['browser']): Record<string, unknown>;
3
4
  export interface BrowserConfigMode {
4
5
  provision?: boolean;
5
6
  }
@@ -160,4 +160,5 @@ declare const edgeMasterPreferences: {
160
160
  enabled: boolean;
161
161
  };
162
162
  };
163
+ export declare function getForkPreferences(browser?: string): Record<string, unknown>;
163
164
  export { chromeMasterPreferences, edgeMasterPreferences };
@@ -1,6 +1,6 @@
1
1
  export declare const DEFAULT_TEMPLATE = "typescript";
2
2
  export declare const BUNDLED_TEMPLATES: readonly string[];
3
- export declare const TEMPLATE_CATALOG_URL = "https://github.com/extension-js/examples/tree/893a06ba86125ac721ca2df71e6eec7aba123e38/examples";
3
+ export declare const TEMPLATE_CATALOG_URL = "https://github.com/extension-js/examples/tree/639c381c2bcf09b15fb442e22c251567dfa68c6a/examples";
4
4
  export interface TemplateGroup {
5
5
  title: string;
6
6
  summary: string;
@@ -1,3 +1,3 @@
1
1
  export declare const TEMPLATE_CORPUS_REPO = "extension-js/examples";
2
- export declare const TEMPLATE_CORPUS_REF = "893a06ba86125ac721ca2df71e6eec7aba123e38";
2
+ export declare const TEMPLATE_CORPUS_REF = "639c381c2bcf09b15fb442e22c251567dfa68c6a";
3
3
  export declare const TEMPLATE_CORPUS_SLUGS: readonly string[];
package/package.json CHANGED
@@ -38,7 +38,7 @@
38
38
  "extension": "./bin/extension.cjs"
39
39
  },
40
40
  "name": "extension",
41
- "version": "4.1.29",
41
+ "version": "4.1.30",
42
42
  "description": "The cross-browser extension framework. Build Chrome, Edge, Firefox, and Safari extensions with no build configuration.",
43
43
  "homepage": "https://extension.js.org/",
44
44
  "funding": "https://github.com/sponsors/cezaraugusto",
@@ -104,9 +104,9 @@
104
104
  "chromium-location": "2.1.2",
105
105
  "commander": "^15.0.0",
106
106
  "edge-location": "2.3.1",
107
- "extension-create": "4.1.29",
108
- "extension-develop": "4.1.29",
109
- "extension-install": "4.1.29",
107
+ "extension-create": "4.1.30",
108
+ "extension-develop": "4.1.30",
109
+ "extension-install": "4.1.30",
110
110
  "firefox-location2": "3.2.0",
111
111
  "floorp-location": "1.0.0",
112
112
  "librewolf-location": "1.2.1",