extension-develop 4.0.26 → 4.0.28

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 (55) hide show
  1. package/README.md +5 -1
  2. package/dist/0~dev-server.mjs +81 -19
  3. package/dist/0~rspack-config.mjs +399 -184
  4. package/dist/101.mjs +1099 -972
  5. package/dist/494.mjs +12 -1
  6. package/dist/839.mjs +108 -27
  7. package/dist/bridge.mjs +1 -1
  8. package/dist/command-preview.d.ts +7 -0
  9. package/dist/dev-server/control-bridge/controller-client.d.ts +1 -0
  10. package/dist/dev-server/control-bridge/producer-runtime.d.ts +2 -1
  11. package/dist/dev-server/index.d.ts +2 -0
  12. package/dist/extension-js-devtools/chrome/background/service_worker.js +1 -1
  13. package/dist/extension-js-devtools/chrome/content_scripts/content-0.js +2 -2
  14. package/dist/extension-js-devtools/chrome/pages/centralized-logger.css +1 -1
  15. package/dist/extension-js-devtools/chrome/pages/centralized-logger.js +1 -1
  16. package/dist/extension-js-devtools/chrome/pages/welcome.css +1 -1
  17. package/dist/extension-js-devtools/chromium/background/service_worker.js +1 -1
  18. package/dist/extension-js-devtools/chromium/content_scripts/content-0.js +2 -2
  19. package/dist/extension-js-devtools/chromium/pages/centralized-logger.css +1 -1
  20. package/dist/extension-js-devtools/chromium/pages/centralized-logger.js +1 -1
  21. package/dist/extension-js-devtools/chromium/pages/welcome.css +1 -1
  22. package/dist/extension-js-devtools/edge/background/service_worker.js +1 -1
  23. package/dist/extension-js-devtools/edge/content_scripts/content-0.js +2 -2
  24. package/dist/extension-js-devtools/edge/pages/centralized-logger.css +1 -1
  25. package/dist/extension-js-devtools/edge/pages/centralized-logger.js +1 -1
  26. package/dist/extension-js-devtools/edge/pages/welcome.css +1 -1
  27. package/dist/extension-js-devtools/firefox/background/scripts.js +1 -1
  28. package/dist/extension-js-devtools/firefox/content_scripts/content-0.js +2 -2
  29. package/dist/extension-js-devtools/firefox/manifest.json +6 -1
  30. package/dist/extension-js-devtools/firefox/pages/centralized-logger.css +1 -1
  31. package/dist/extension-js-devtools/firefox/pages/centralized-logger.js +1 -1
  32. package/dist/extension-js-devtools/firefox/pages/welcome.css +1 -1
  33. package/dist/extension-js-theme/chrome/manifest.json +20 -5
  34. package/dist/extension-js-theme/chromium/manifest.json +20 -5
  35. package/dist/extension-js-theme/edge/manifest.json +20 -5
  36. package/dist/extension-js-theme/firefox/manifest.json +47 -12
  37. package/dist/feature-scripts-content-script-wrapper.js +2 -1
  38. package/dist/feature-scripts-content-script-wrapper.mjs +2 -1
  39. package/dist/lib/atomic-dist.d.ts +5 -0
  40. package/dist/lib/config-loader.d.ts +12 -12
  41. package/dist/lib/constants.d.ts +2 -0
  42. package/dist/lib/merge-options.d.ts +67 -0
  43. package/dist/lib/paths.d.ts +1 -1
  44. package/dist/lib/session-paths.d.ts +1 -0
  45. package/dist/plugin-compilation/boring.d.ts +1 -0
  46. package/dist/plugin-compilation/zip.d.ts +2 -0
  47. package/dist/plugin-playwright/index.d.ts +2 -0
  48. package/dist/plugin-web-extension/feature-html/html-lib/utils.d.ts +2 -1
  49. package/dist/plugin-web-extension/feature-json/messages.d.ts +2 -0
  50. package/dist/plugin-web-extension/feature-manifest/manifest-lib/theme-values.d.ts +1 -0
  51. package/dist/plugin-web-extension/feature-manifest/messages.d.ts +1 -0
  52. package/dist/plugin-web-extension/feature-manifest/steps/patch-chromium-theme-colors.d.ts +2 -0
  53. package/dist/plugin-web-extension/feature-web-resources/collect-entry-imports.d.ts +1 -0
  54. package/dist/types.d.ts +26 -5
  55. package/package.json +1 -1
@@ -12,7 +12,7 @@ import { filterKeysForThisBrowser as external_browser_extension_manifest_fields_
12
12
  import content_security_policy_parser from "content-security-policy-parser";
13
13
  import node_fs from "node:fs";
14
14
  import node_path from "node:path";
15
- import { debugExtensionsToLoad, package_namespaceObject, getDirs, asAbsolute, browserRunnerDisabled, treeWithDistFilesBrowser, packagingDistributionFiles, toPosixPath, resolveCompanionExtensionDirs, debugContextPath, PlaywrightPlugin, isGeckoBasedBrowser, spacerLine, messages_ready, CHROMIUM_FAMILY_ALIASES, treeWithSourceAndDistFiles, computeExtensionsToLoad, noCompanionExtensionsResolved, treeWithSourceFiles, bundlerFatalError, bundlerRecompiling, noEntrypointsDetected, GECKO_FAMILY_ALIASES, packagingSourceFiles, debugBrowser, debugOutputPath, manifestInvalidJson, isChromiumBasedBrowser, getSpecialFoldersDataForCompiler } from "./101.mjs";
15
+ import { debugExtensionsToLoad, package_namespaceObject, getDirs, asAbsolute, browserRunnerDisabled, treeWithDistFilesBrowser, packagingDistributionFiles, toPosixPath, resolveCompanionExtensionDirs, debugContextPath, PlaywrightPlugin, isWebkitBasedBrowser, spacerLine, isGeckoBasedBrowser, messages_ready, CHROMIUM_FAMILY_ALIASES, treeWithSourceAndDistFiles, computeExtensionsToLoad, noCompanionExtensionsResolved, treeWithSourceFiles, bundlerFatalError, bundlerRecompiling, noEntrypointsDetected, GECKO_FAMILY_ALIASES, packagingSourceFiles, debugBrowser, debugOutputPath, manifestInvalidJson, isChromiumBasedBrowser, getSpecialFoldersDataForCompiler } from "./101.mjs";
16
16
  import { stripBom, parseJsonSafe } from "./23.mjs";
17
17
  import { isResourceUnderDirs, canonicalizeDir, toResourceKey } from "./93.mjs";
18
18
  import { prefix as messaging_prefix, isDebug } from "./349.mjs";
@@ -377,6 +377,7 @@ class BoringPlugin {
377
377
  browser;
378
378
  sawUserInvalidation = false;
379
379
  printedStartupSuccess = false;
380
+ printedStartupWarning = false;
380
381
  lastKnownManifestName;
381
382
  constructor(options){
382
383
  this.manifestPath = options.manifestPath;
@@ -386,6 +387,7 @@ class BoringPlugin {
386
387
  compiler.hooks.watchClose.tap('develop:brand:watch-close', ()=>{
387
388
  this.sawUserInvalidation = false;
388
389
  this.printedStartupSuccess = false;
390
+ this.printedStartupWarning = false;
389
391
  });
390
392
  compiler.hooks.done.tap('develop:brand', (stats)=>{
391
393
  const hasErrors = Boolean(stats?.hasErrors?.());
@@ -396,8 +398,10 @@ class BoringPlugin {
396
398
  let manifestName;
397
399
  try {
398
400
  const parsedName = parseJsonSafe(__rspack_external_node_fs_5ea92f0c.readFileSync(this.manifestPath, 'utf-8')).name;
399
- if ('string' == typeof parsedName && parsedName) this.lastKnownManifestName = parsedName;
400
- manifestName = parsedName;
401
+ if ('string' == typeof parsedName && parsedName) {
402
+ this.lastKnownManifestName = parsedName;
403
+ manifestName = parsedName;
404
+ } else manifestName = this.lastKnownManifestName;
401
405
  } catch {
402
406
  manifestName = this.lastKnownManifestName;
403
407
  }
@@ -413,16 +417,22 @@ class BoringPlugin {
413
417
  ].map((file)=>String(file).replace(/\\/g, '/'));
414
418
  if (!this.sawUserInvalidation && modifiedFiles.length > 0) {
415
419
  const context = String(compiler?.options?.context || '').replace(/\\/g, '/');
420
+ const outputPath = String(compiler?.options?.output?.path || '').replace(/\\/g, '/');
421
+ const distRoot = context ? `${context}/dist` : '';
422
+ const isUnderRoot = (file, root)=>'' !== root && (file === root || file.startsWith(`${root}/`));
416
423
  const hasUserFileChange = modifiedFiles.some((file)=>{
417
424
  const inProject = !context || file.startsWith(`${context}/`);
418
- const isGenerated = file.includes('/dist/') || file.includes('/extension-js/profiles/');
425
+ const isGenerated = isUnderRoot(file, outputPath) || isUnderRoot(file, distRoot) || file.includes('/extension-js/profiles/');
419
426
  return inProject && !isGenerated;
420
427
  });
421
428
  if (hasUserFileChange) this.sawUserInvalidation = true;
422
429
  }
423
- if (browserLaunchEnabled && !hasErrors && !hasWarnings) {
424
- if (!this.sawUserInvalidation) if (this.printedStartupSuccess) return;
425
- else this.printedStartupSuccess = true;
430
+ if (browserLaunchEnabled && !hasErrors && !this.sawUserInvalidation) if (hasWarnings) {
431
+ if (this.printedStartupWarning) return;
432
+ this.printedStartupWarning = true;
433
+ } else {
434
+ if (this.printedStartupSuccess) return;
435
+ this.printedStartupSuccess = true;
426
436
  }
427
437
  humanLine(line);
428
438
  } catch {}
@@ -436,7 +446,8 @@ class CleanDistFolderPlugin {
436
446
  }
437
447
  apply(compiler) {
438
448
  const logger = compiler.getInfrastructureLogger('plugin-compilation:clean');
439
- const distPath = __rspack_external_node_path_c5b9b54f.join(compiler.options.context, 'dist', this.options.browser);
449
+ const configuredOutputPath = compiler.options.output?.path;
450
+ const distPath = 'string' == typeof configuredOutputPath && configuredOutputPath ? configuredOutputPath : __rspack_external_node_path_c5b9b54f.join(compiler.options.context, 'dist', this.options.browser);
440
451
  if (__rspack_external_node_fs_5ea92f0c.existsSync(distPath)) {
441
452
  const removedCount = countFilesRecursively(distPath);
442
453
  if (isDebug()) console.log(cleanDistStarting(distPath));
@@ -1054,8 +1065,15 @@ function getManifestOverrides(manifestPath, manifest) {
1054
1065
  return JSON.stringify(merged, null, 2);
1055
1066
  }
1056
1067
  const manifest_cjsRequire = createRequire(import.meta.url);
1057
- const INTERNAL_MANIFEST_SOURCE = '__extensionjs_manifest_source__';
1058
- const INTERNAL_MANIFEST_CURRENT_SOURCE = '__extensionjs_manifest_current_source__';
1068
+ const manifestSourceStore = new WeakMap();
1069
+ function manifestSourceEntry(compilation) {
1070
+ let entry = manifestSourceStore.get(compilation);
1071
+ if (!entry) {
1072
+ entry = {};
1073
+ manifestSourceStore.set(compilation, entry);
1074
+ }
1075
+ return entry;
1076
+ }
1059
1077
  function readAssetSource(asset) {
1060
1078
  if (!asset) return '';
1061
1079
  const source = asset.source;
@@ -1071,16 +1089,16 @@ function readAssetSource(asset) {
1071
1089
  return '';
1072
1090
  }
1073
1091
  function setOriginalManifestContent(compilation, source) {
1074
- compilation[INTERNAL_MANIFEST_SOURCE] = source;
1092
+ manifestSourceEntry(compilation).original = source;
1075
1093
  }
1076
1094
  function getOriginalManifestContent(compilation) {
1077
- return compilation[INTERNAL_MANIFEST_SOURCE];
1095
+ return manifestSourceStore.get(compilation)?.original;
1078
1096
  }
1079
1097
  function setCurrentManifestContent(compilation, source) {
1080
- compilation[INTERNAL_MANIFEST_CURRENT_SOURCE] = source;
1098
+ manifestSourceEntry(compilation).current = source;
1081
1099
  }
1082
1100
  function getCurrentManifestContent(compilation) {
1083
- return compilation[INTERNAL_MANIFEST_CURRENT_SOURCE];
1101
+ return manifestSourceStore.get(compilation)?.current;
1084
1102
  }
1085
1103
  function getManifestContent(compilation, manifestPath) {
1086
1104
  const currentManifest = getCurrentManifestContent(compilation);
@@ -1305,6 +1323,23 @@ function isCompanionExtension(file) {
1305
1323
  const [first] = toPosix(file).split('/');
1306
1324
  return first === COMPANION_DIR;
1307
1325
  }
1326
+ const DENIED_SEGMENTS = new Set([
1327
+ '.git',
1328
+ '.extension-js',
1329
+ 'node_modules'
1330
+ ]);
1331
+ const SESSION_ARTIFACTS_PREFIX = 'dist/extension-js';
1332
+ function isDeniedEnvFile(basename) {
1333
+ if (!basename.startsWith('.env')) return false;
1334
+ return !basename.endsWith('.example');
1335
+ }
1336
+ function isDeniedFromSourceZip(file) {
1337
+ const posix = toPosix(file);
1338
+ const segments = posix.split('/');
1339
+ if (segments.some((segment)=>DENIED_SEGMENTS.has(segment))) return true;
1340
+ if (isDeniedEnvFile(segments[segments.length - 1])) return true;
1341
+ return posix === SESSION_ARTIFACTS_PREFIX || posix.startsWith(`${SESSION_ARTIFACTS_PREFIX}/`);
1342
+ }
1308
1343
  async function getFilesToZip(projectDir) {
1309
1344
  const gitignorePath = __rspack_external_node_path_c5b9b54f.join(projectDir, '.gitignore');
1310
1345
  const ig = ignore();
@@ -1314,9 +1349,11 @@ async function getFilesToZip(projectDir) {
1314
1349
  } catch {}
1315
1350
  const files = await tiny_glob('**/*', {
1316
1351
  cwd: projectDir,
1317
- dot: true
1352
+ dot: true,
1353
+ filesOnly: true,
1354
+ flush: true
1318
1355
  });
1319
- return files.filter((file)=>!ig.ignores(file) && !isCompanionExtension(file));
1356
+ return files.filter((file)=>!isDeniedFromSourceZip(file) && !ig.ignores(file) && !isCompanionExtension(file));
1320
1357
  }
1321
1358
  class ZipPlugin {
1322
1359
  options;
@@ -2928,7 +2965,7 @@ const cloneParsedHtmlAsset = (assets)=>({
2928
2965
  ]
2929
2966
  });
2930
2967
  const assetsFromHtmlCache = new Map();
2931
- function getAssetsFromHtml(htmlFilePath, htmlContent, publicPath = 'public') {
2968
+ function getAssetsFromHtml(htmlFilePath, htmlContent) {
2932
2969
  const assets = {
2933
2970
  css: [],
2934
2971
  js: [],
@@ -2939,7 +2976,7 @@ function getAssetsFromHtml(htmlFilePath, htmlContent, publicPath = 'public') {
2939
2976
  let cacheKey;
2940
2977
  if (void 0 === htmlContent) try {
2941
2978
  const stat = __rspack_external_node_fs_5ea92f0c.statSync(htmlFilePath);
2942
- cacheKey = `${stat.mtimeMs}:${stat.size}:${publicPath}`;
2979
+ cacheKey = `${stat.mtimeMs}:${stat.size}`;
2943
2980
  const cached = assetsFromHtmlCache.get(htmlFilePath);
2944
2981
  if (cached && cached.key === cacheKey) return cloneParsedHtmlAsset(cached.assets);
2945
2982
  } catch {
@@ -2983,6 +3020,11 @@ function getAssetsFromHtml(htmlFilePath, htmlContent, publicPath = 'public') {
2983
3020
  }
2984
3021
  });
2985
3022
  } catch (error) {
3023
+ const code = error?.code;
3024
+ if (void 0 === htmlContent && 'ENOENT' === code) {
3025
+ assetsFromHtmlCache.delete(htmlFilePath);
3026
+ throw error;
3027
+ }
2986
3028
  return assets;
2987
3029
  }
2988
3030
  if (cacheKey) assetsFromHtmlCache.set(htmlFilePath, {
@@ -2995,6 +3037,7 @@ function getHtmlPageDeclaredAssetPath(filepathList, filePath, extension) {
2995
3037
  const entryname = Object.keys(filepathList).find((key)=>{
2996
3038
  const includePath = filepathList[key];
2997
3039
  if (includePath === filePath) return true;
3040
+ if (!includePath || !__rspack_external_node_fs_5ea92f0c.existsSync(includePath)) return false;
2998
3041
  const assets = getAssetsFromHtml(includePath);
2999
3042
  return Boolean(assets?.js?.includes(filePath) || assets?.css?.includes(filePath));
3000
3043
  }) || '';
@@ -3872,6 +3915,7 @@ class PerfBudgetsPlugin {
3872
3915
  });
3873
3916
  }
3874
3917
  }
3918
+ const CONTROL_PORT_ASSET_NAME = 'extension-js-control.json';
3875
3919
  const BRIDGE_PRODUCER_SOURCE = `;(function () {
3876
3920
  try {
3877
3921
  var g = (typeof globalThis === "object" && globalThis) ? globalThis : this;
@@ -3913,12 +3957,24 @@ const BRIDGE_PRODUCER_SOURCE = `;(function () {
3913
3957
  } catch (e) { /* non-fatal: trigger falls back to its no-listener reply */ }
3914
3958
  }
3915
3959
 
3916
- // Use g.chrome (not the hoisted chrome var below). This runs first.
3960
+ // Use the raw globals (not the hoisted chrome var below). This runs first.
3961
+ // On Gecko browser.* is a DISTINCT wrapper object: hook BOTH namespaces.
3917
3962
  var actionClickedListeners = [];
3918
3963
  var commandListeners = [];
3919
- if (g.chrome) {
3920
- captureEvent(g.chrome.action && g.chrome.action.onClicked, actionClickedListeners);
3921
- captureEvent(g.chrome.commands && g.chrome.commands.onCommand, commandListeners);
3964
+ var capturedEvents = [];
3965
+ function captureEventOnce(event, sink) {
3966
+ // Polyfilled extensions expose ONE event object on both namespaces:
3967
+ // wrap it once, and the sink dedupes callbacks shared across wrappers.
3968
+ if (!event || capturedEvents.indexOf(event) !== -1) return;
3969
+ capturedEvents.push(event);
3970
+ captureEvent(event, sink);
3971
+ }
3972
+ var captureNamespaces = [g.chrome, g.browser];
3973
+ for (var cn = 0; cn < captureNamespaces.length; cn++) {
3974
+ var capNS = captureNamespaces[cn];
3975
+ if (!capNS) continue;
3976
+ captureEventOnce(capNS.action && capNS.action.onClicked, actionClickedListeners);
3977
+ captureEventOnce(capNS.commands && capNS.commands.onCommand, commandListeners);
3922
3978
  }
3923
3979
 
3924
3980
  var LEVELS = ["log", "info", "warn", "error", "debug", "trace"];
@@ -3927,6 +3983,7 @@ const BRIDGE_PRODUCER_SOURCE = `;(function () {
3927
3983
  var queue = [];
3928
3984
  var backoff = 250;
3929
3985
  var MAX_BACKOFF = 5000;
3986
+ var connectFailures = 0;
3930
3987
  var MAX_QUEUE = 1000;
3931
3988
  var MAX_RESULT_BYTES = 256 * 1024;
3932
3989
 
@@ -4695,10 +4752,36 @@ const BRIDGE_PRODUCER_SOURCE = `;(function () {
4695
4752
  if (queue.length < MAX_QUEUE) queue.push(frame);
4696
4753
  }
4697
4754
 
4755
+ // The baked PORT is a snapshot of an ephemeral port. After a dev-server
4756
+ // restart, the port file shipped in the unpacked extension names the
4757
+ // live one, and unpacked resources are read from disk on every fetch.
4758
+ function refreshControlPort(done) {
4759
+ try {
4760
+ var runtime = (g.chrome && g.chrome.runtime) || (g.browser && g.browser.runtime);
4761
+ if (!runtime || typeof runtime.getURL !== "function" || typeof g.fetch !== "function") { done(); return; }
4762
+ g.fetch(runtime.getURL("extension-js-control.json"), {cache: "no-store"})
4763
+ .then(function (res) { return res.json(); })
4764
+ .then(function (data) {
4765
+ var next = data && parseInt(data.port, 10);
4766
+ if (next && next > 0 && next < 65536 && next !== PORT) PORT = next;
4767
+ done();
4768
+ })
4769
+ .catch(function () { done(); });
4770
+ } catch (e) { done(); }
4771
+ }
4772
+
4698
4773
  function schedule() {
4699
4774
  var delay = backoff;
4700
4775
  backoff = Math.min(backoff * 2, MAX_BACKOFF);
4701
- try { setTimeout(connect, delay); } catch (e) {
4776
+ connectFailures++;
4777
+ try {
4778
+ setTimeout(function () {
4779
+ // Two straight failures make the baked port suspect (a restarted
4780
+ // server dials out on a new port): re-resolve before re-dialing.
4781
+ if (connectFailures >= 2) refreshControlPort(connect);
4782
+ else connect();
4783
+ }, delay);
4784
+ } catch (e) {
4702
4785
  // Ignore
4703
4786
  }
4704
4787
  }
@@ -4713,6 +4796,7 @@ const BRIDGE_PRODUCER_SOURCE = `;(function () {
4713
4796
  socket.onopen = function () {
4714
4797
  open = true;
4715
4798
  backoff = 250;
4799
+ connectFailures = 0;
4716
4800
  try {
4717
4801
  socket.send(JSON.stringify({type: "hello", v: 1, role: "producer", instanceId: INSTANCE_ID}));
4718
4802
  } catch (e) {
@@ -5171,6 +5255,10 @@ class InjectBridgeProducer {
5171
5255
  name: InjectBridgeProducer.name,
5172
5256
  stage: core_Compilation.PROCESS_ASSETS_STAGE_REPORT + 101
5173
5257
  }, ()=>{
5258
+ if (!compilation.getAsset(CONTROL_PORT_ASSET_NAME)) compilation.emitAsset(CONTROL_PORT_ASSET_NAME, new core_sources.RawSource(JSON.stringify({
5259
+ port: controlPort,
5260
+ instanceId
5261
+ })));
5174
5262
  for (const asset of compilation.getAssets()){
5175
5263
  if (!BACKGROUND_ASSET.test(asset.name)) continue;
5176
5264
  const original = asset.source.source().toString();
@@ -7485,31 +7573,29 @@ class StaticAssetsPlugin {
7485
7573
  }
7486
7574
  }
7487
7575
  };
7488
- const hasCustomSvgRule = compiler.options.module.rules.some((thisRule)=>{
7576
+ const isFullCustomRuleFor = (thisRule, sample)=>{
7489
7577
  const rule = thisRule;
7490
- return Boolean(rule && rule.test instanceof RegExp && rule.test.test('.svg') && void 0 !== rule.use);
7491
- });
7578
+ return Boolean(rule && rule.test instanceof RegExp && rule.test.test(sample) && (void 0 !== rule.type || void 0 !== rule.use) && void 0 === rule.resourceQuery);
7579
+ };
7580
+ const scopedQueriesFor = (sample)=>compiler.options.module.rules.map((thisRule)=>thisRule).filter((rule)=>Boolean(rule && rule.test instanceof RegExp && rule.test.test(sample) && (void 0 !== rule.type || void 0 !== rule.use) && rule.resourceQuery instanceof RegExp)).map((rule)=>rule?.resourceQuery);
7581
+ const hasCustomSvgRule = compiler.options.module.rules.some((thisRule)=>isFullCustomRuleFor(thisRule, '.svg'));
7492
7582
  const hasUrlResourceQueryRule = compiler.options.module.rules.some((thisRule)=>{
7493
7583
  const rule = thisRule;
7494
7584
  const resourceQuery = rule?.resourceQuery;
7495
7585
  if (!(resourceQuery instanceof RegExp)) return false;
7496
7586
  return resourceQuery.test('?url');
7497
7587
  });
7498
- const hasCustomFontsRule = compiler.options.module.rules.some((thisRule)=>{
7499
- const rule = thisRule;
7500
- if (!rule || !(rule.test instanceof RegExp)) return false;
7501
- if (!rule.test.test('.woff')) return false;
7502
- return void 0 !== rule.type || void 0 !== rule.use;
7503
- });
7588
+ const hasCustomFontsRule = compiler.options.module.rules.some((thisRule)=>isFullCustomRuleFor(thisRule, '.woff'));
7589
+ const svgScopedQueries = scopedQueriesFor('.svg');
7590
+ const fontsScopedQueries = scopedQueriesFor('.woff');
7504
7591
  const loaders = [
7505
- ...hasUrlResourceQueryRule ? [] : [
7506
- {
7507
- resourceQuery: /(?:^\?|&)url(?:&|=|$)/,
7508
- type: 'asset/resource'
7509
- }
7510
- ],
7511
7592
  ...hasCustomSvgRule ? [] : [
7512
- defaultSvgRule
7593
+ svgScopedQueries.length ? {
7594
+ ...defaultSvgRule,
7595
+ resourceQuery: {
7596
+ not: svgScopedQueries
7597
+ }
7598
+ } : defaultSvgRule
7513
7599
  ],
7514
7600
  {
7515
7601
  test: /\.(png|jpg|jpeg|gif|webp|avif|ico|bmp)$/i,
@@ -7529,7 +7615,12 @@ class StaticAssetsPlugin {
7529
7615
  type: 'asset',
7530
7616
  generator: {
7531
7617
  filename: filenamePattern
7532
- }
7618
+ },
7619
+ ...fontsScopedQueries.length ? {
7620
+ resourceQuery: {
7621
+ not: fontsScopedQueries
7622
+ }
7623
+ } : {}
7533
7624
  }
7534
7625
  ],
7535
7626
  {
@@ -7543,7 +7634,16 @@ class StaticAssetsPlugin {
7543
7634
  maxSize: 2048
7544
7635
  }
7545
7636
  }
7546
- }
7637
+ },
7638
+ ...hasUrlResourceQueryRule ? [] : [
7639
+ {
7640
+ resourceQuery: /(?:^\?|&)url(?:&|=|$)/,
7641
+ type: 'asset/resource',
7642
+ generator: {
7643
+ filename: filenamePattern
7644
+ }
7645
+ }
7646
+ ]
7547
7647
  ];
7548
7648
  compiler.options.module.rules = [
7549
7649
  ...compiler.options.module.rules,
@@ -8347,9 +8447,9 @@ class AddToFileDependencies {
8347
8447
  for (const field of Object.entries(allEntries)){
8348
8448
  const [, resource] = field;
8349
8449
  if (resource) {
8350
- const resourceData = getAssetsFromHtml(resource);
8351
8450
  const fileDependencies = new Set(compilation.fileDependencies);
8352
8451
  if (__rspack_external_node_fs_5ea92f0c.existsSync(resource)) {
8452
+ const resourceData = getAssetsFromHtml(resource);
8353
8453
  const fileResources = [
8354
8454
  resource,
8355
8455
  ...resourceData?.static || []
@@ -8576,8 +8676,9 @@ class ThrowIfRecompileIsNeeded {
8576
8676
  if (changedFile && this.initialHtmlAssets[changedFile]) {
8577
8677
  const isRemoteUrl = (p)=>/^(https?:)?\/\//i.test(p);
8578
8678
  const looksLikePublicRootUrl = (p)=>p.startsWith('/') && !__rspack_external_node_fs_5ea92f0c.existsSync(p);
8579
- const updatedJsEntries = (getAssetsFromHtml(changedFile)?.js || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8580
- const updatedCssEntries = (getAssetsFromHtml(changedFile)?.css || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8679
+ const updatedAssets = __rspack_external_node_fs_5ea92f0c.existsSync(changedFile) ? getAssetsFromHtml(changedFile) : void 0;
8680
+ const updatedJsEntries = (updatedAssets?.js || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8681
+ const updatedCssEntries = (updatedAssets?.css || []).filter((p)=>!looksLikePublicRootUrl(p) && !isRemoteUrl(p));
8581
8682
  const { js, css } = this.initialHtmlAssets[changedFile];
8582
8683
  if (this.hasEntriesChanged(updatedCssEntries, css) || this.hasEntriesChanged(updatedJsEntries, js)) {
8583
8684
  const projectRoot = __rspack_external_node_path_c5b9b54f.dirname(this.manifestPath);
@@ -8985,6 +9086,24 @@ function invalidRulesetStructure(manifestField, file) {
8985
9086
  "Update the file to contain an array of rules."
8986
9087
  ].join('\n');
8987
9088
  }
9089
+ function invalidRulesetRule(manifestField, file, ruleIndex, reason) {
9090
+ return [
9091
+ `The Declarative Net Request ruleset listed in ${pintor.blue(manifestField)} has a rule Chrome rejects at load.`,
9092
+ `${pintor.gray('PATH')} ${pintor.underline(file)}`,
9093
+ `${pintor.gray('RULE')} ${pintor.underline(`index ${ruleIndex}`)}`,
9094
+ `${pintor.gray('REASON')} ${pintor.underline(reason)}`,
9095
+ "Give every rule an integer id of 1 or more, an action with a type, and a condition object."
9096
+ ].join('\n');
9097
+ }
9098
+ function rulesetRuleShapeIssue(manifestField, file, ruleIndex, reason) {
9099
+ return [
9100
+ `A rule in the Declarative Net Request ruleset listed in ${pintor.blue(manifestField)} may not behave as intended.`,
9101
+ `${pintor.gray('PATH')} ${pintor.underline(file)}`,
9102
+ `${pintor.gray('RULE')} ${pintor.underline(`index ${ruleIndex}`)}`,
9103
+ `${pintor.gray('REASON')} ${pintor.underline(reason)}`,
9104
+ `Check the rule against the Declarative Net Request rule schema.\nThe build continues.`
9105
+ ].join('\n');
9106
+ }
8988
9107
  function invalidManagedSchemaStructure(manifestField, file) {
8989
9108
  return [
8990
9109
  `The managed storage schema listed in ${pintor.blue(manifestField)} isn't a schema object.`,
@@ -9005,6 +9124,22 @@ function jsonIncludeSummary(totalFeatures, criticalCount) {
9005
9124
  function isCriticalJsonFeature(feature) {
9006
9125
  return feature.startsWith('declarative_net_request') || 'storage.managed_schema' === feature;
9007
9126
  }
9127
+ function isPlainObject(value) {
9128
+ return 'object' == typeof value && null !== value && !Array.isArray(value);
9129
+ }
9130
+ function getDnrRuleRejection(rule) {
9131
+ if (!isPlainObject(rule)) return 'the rule is not an object';
9132
+ const id = rule.id;
9133
+ if ('number' != typeof id || !Number.isInteger(id) || id < 1) return 'the rule id is not a positive integer';
9134
+ const action = rule.action;
9135
+ if (!isPlainObject(action)) return 'the rule has no action object';
9136
+ if ('string' != typeof action.type || 0 === action.type.length) return 'the rule action has no type';
9137
+ if (!isPlainObject(rule.condition)) return 'the rule has no condition object';
9138
+ }
9139
+ function getDnrRuleSoftIssue(rule) {
9140
+ const priority = rule.priority;
9141
+ if (void 0 !== priority && ('number' != typeof priority || !Number.isInteger(priority) || priority < 1)) return 'the rule priority is not a positive integer';
9142
+ }
9008
9143
  function validateJsonAsset(compilation, feature, filePath, buf) {
9009
9144
  let parsed;
9010
9145
  try {
@@ -9024,6 +9159,23 @@ function validateJsonAsset(compilation, feature, filePath, buf) {
9024
9159
  compilation.errors.push(err);
9025
9160
  return false;
9026
9161
  }
9162
+ for(let index = 0; index < parsed.length; index++){
9163
+ const rejection = getDnrRuleRejection(parsed[index]);
9164
+ if (rejection) {
9165
+ const err = new core_WebpackError(invalidRulesetRule(feature, filePath, index, rejection));
9166
+ err.file = filePath;
9167
+ err.name = 'DNRInvalidRule';
9168
+ compilation.errors.push(err);
9169
+ return false;
9170
+ }
9171
+ const softIssue = getDnrRuleSoftIssue(parsed[index]);
9172
+ if (softIssue) {
9173
+ const warn = new core_WebpackError(rulesetRuleShapeIssue(feature, filePath, index, softIssue));
9174
+ warn.file = filePath;
9175
+ warn.name = 'DNRRuleShapeIssue';
9176
+ compilation.warnings.push(warn);
9177
+ }
9178
+ }
9027
9179
  } else if ('storage.managed_schema' === feature) {
9028
9180
  if (null === parsed || Array.isArray(parsed) || 'object' != typeof parsed) {
9029
9181
  const err = new core_WebpackError(invalidManagedSchemaStructure(feature, filePath));
@@ -9462,6 +9614,12 @@ function invalidThemeValue(field, detail, value) {
9462
9614
  lines.push(`${pintor.red('INVALID VALUE')} ${value}`);
9463
9615
  return lines.join('\n');
9464
9616
  }
9617
+ function themeNotSupportedByBrowser(browser) {
9618
+ const lines = [];
9619
+ lines.push(`${messaging_prefix('warn')} ${pintor.blue(browser)} does not support the ${pintor.yellow('theme')} field.`);
9620
+ lines.push("The field ships unchanged in the manifest and Safari ignores it.");
9621
+ return lines.join('\n');
9622
+ }
9465
9623
  function missingGeckoDataCollectionPermissions() {
9466
9624
  const lines = [];
9467
9625
  lines.push(`${messaging_prefix('warn')} addons.mozilla.org requires ${pintor.blue('browser_specific_settings.gecko.data_collection_permissions')} for new add-ons.`);
@@ -9933,6 +10091,99 @@ class ManifestLegacyWarnings {
9933
10091
  });
9934
10092
  }
9935
10093
  }
10094
+ const EMITTED_ASSET_REF_PATTERN = /assets\/[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*/g;
10095
+ function forEachStringKey(objectOrMap, callback) {
10096
+ if (!objectOrMap) return;
10097
+ if (objectOrMap instanceof Map) {
10098
+ const keys = objectOrMap.keys();
10099
+ for (const key of keys)callback(String(key));
10100
+ } else if ('object' == typeof objectOrMap) {
10101
+ const objectKeys = Object.keys(objectOrMap);
10102
+ for (const key of objectKeys)callback(key);
10103
+ }
10104
+ }
10105
+ function getAssetSource(compilation, filename) {
10106
+ let assetGetFunction;
10107
+ if ('function' == typeof compilation.getAsset) assetGetFunction = compilation.getAsset(filename);
10108
+ let assetViaAssets;
10109
+ if (!assetGetFunction && compilation.assets) assetViaAssets = compilation.assets[filename];
10110
+ const asset = assetGetFunction || assetViaAssets;
10111
+ if (!asset) return '';
10112
+ let src;
10113
+ src = 'function' == typeof asset.source ? asset.source() : asset.source?.source ? asset.source.source() : asset.source;
10114
+ if ('string' == typeof src) return src;
10115
+ return '';
10116
+ }
10117
+ function collectContentScriptEntryImports(compilation, includeList) {
10118
+ const entryImports = {};
10119
+ const contentEntryNames = new Set(Object.keys(includeList || {}).filter((k)=>k.startsWith("content_scripts")));
10120
+ const chunkGraph = compilation.chunkGraph;
10121
+ compilation.entrypoints.forEach((_entry, entryName)=>{
10122
+ if (String(entryName).startsWith("content_scripts/")) contentEntryNames.add(entryName);
10123
+ });
10124
+ compilation.entrypoints.forEach((entry, entryName)=>{
10125
+ if (!contentEntryNames.has(entryName)) return;
10126
+ const collectedFilesSet = new Set();
10127
+ function addFileIfRelevant(file) {
10128
+ if (null == file) return;
10129
+ const fileNameStr = String(file);
10130
+ const isJavaScript = fileNameStr.endsWith('.js');
10131
+ const isSourceMap = fileNameStr.endsWith('.map');
10132
+ if (isJavaScript || isSourceMap) return;
10133
+ collectedFilesSet.add(fileNameStr);
10134
+ }
10135
+ entry.chunks.forEach((chunk)=>{
10136
+ const currentChunk = chunk;
10137
+ const chunkFilesArray = Array.isArray(currentChunk.files) ? currentChunk.files : [];
10138
+ for(let i = 0; i < chunkFilesArray.length; i++)addFileIfRelevant(chunkFilesArray[i]);
10139
+ let chunkAuxFilesArray = [];
10140
+ if (Array.isArray(currentChunk.auxiliaryFiles)) chunkAuxFilesArray = currentChunk.auxiliaryFiles;
10141
+ for(let i = 0; i < chunkAuxFilesArray.length; i++)addFileIfRelevant(chunkAuxFilesArray[i]);
10142
+ const modulesArray = Array.from(chunkGraph.getChunkModulesIterable(chunk));
10143
+ for(let j = 0; j < modulesArray.length; j++){
10144
+ const moduleObj = modulesArray[j];
10145
+ const moduleChunksArray = Array.from(chunkGraph.getModuleChunks(moduleObj));
10146
+ for(let k = 0; k < moduleChunksArray.length; k++){
10147
+ const mk = moduleChunksArray[k];
10148
+ const mkAuxFilesArr = Array.isArray(mk.auxiliaryFiles) ? mk.auxiliaryFiles : [];
10149
+ for(let l = 0; l < mkAuxFilesArr.length; l++)addFileIfRelevant(mkAuxFilesArr[l]);
10150
+ }
10151
+ const moduleWithBuildInfo = moduleObj;
10152
+ const buildInfo = moduleWithBuildInfo.buildInfo;
10153
+ forEachStringKey(buildInfo?.assets, (key)=>{
10154
+ addFileIfRelevant(key);
10155
+ });
10156
+ forEachStringKey(buildInfo?.assetsInfo, (key)=>{
10157
+ addFileIfRelevant(key);
10158
+ });
10159
+ }
10160
+ for(let i = 0; i < chunkFilesArray.length; i++){
10161
+ const chunkFileName = chunkFilesArray[i];
10162
+ if (!String(chunkFileName).endsWith('.js')) continue;
10163
+ const jsSource = getAssetSource(compilation, chunkFileName);
10164
+ if (!jsSource) continue;
10165
+ const matchedStrings = jsSource.match(EMITTED_ASSET_REF_PATTERN) || [];
10166
+ for(let m = 0; m < matchedStrings.length; m++)addFileIfRelevant(matchedStrings[m]);
10167
+ }
10168
+ });
10169
+ const logicalJsAssetName = `${entryName}.js`;
10170
+ const logicalJsAssetSource = getAssetSource(compilation, logicalJsAssetName);
10171
+ if (logicalJsAssetSource) {
10172
+ const matchedStrings = logicalJsAssetSource.match(EMITTED_ASSET_REF_PATTERN) || [];
10173
+ for(let n = 0; n < matchedStrings.length; n++)addFileIfRelevant(matchedStrings[n]);
10174
+ }
10175
+ entryImports[entryName] = Array.from(collectedFilesSet);
10176
+ });
10177
+ const entryImportsEntries = Object.entries(entryImports);
10178
+ for(let i = 0; i < entryImportsEntries.length; i++){
10179
+ const name = entryImportsEntries[i][0];
10180
+ const files = entryImportsEntries[i][1];
10181
+ const normalizedFiles = [];
10182
+ for(let j = 0; j < files.length; j++)normalizedFiles.push(unixify(files[j]));
10183
+ entryImports[name] = normalizedFiles;
10184
+ }
10185
+ return entryImports;
10186
+ }
9936
10187
  function cleanMatches(matches) {
9937
10188
  return matches.map((match)=>{
9938
10189
  try {
@@ -10072,6 +10323,9 @@ function resolve_war_findSourceSibling(absOutputPath) {
10072
10323
  function isFirefox(browser) {
10073
10324
  return !!browser && isGeckoBasedBrowser(browser.toLowerCase());
10074
10325
  }
10326
+ function isWebkit(browser) {
10327
+ return !!browser && isWebkitBasedBrowser(browser.toLowerCase());
10328
+ }
10075
10329
  function isValidChromeMatchPattern(pattern) {
10076
10330
  if ('<all_urls>' === pattern) return true;
10077
10331
  if (/[?#]/.test(pattern)) return false;
@@ -10085,7 +10339,7 @@ function isValidChromeMatchPattern(pattern) {
10085
10339
  }
10086
10340
  }
10087
10341
  function validateMatchesOrReport(compilation, matches, browser) {
10088
- if (!matches || isFirefox(browser)) return;
10342
+ if (!matches || isFirefox(browser) || isWebkit(browser)) return;
10089
10343
  compilation.errors ||= [];
10090
10344
  for (const m of matches)if (!isValidChromeMatchPattern(m)) {
10091
10345
  const msg = warInvalidMatchPattern(m);
@@ -10227,7 +10481,7 @@ function resolveUserDeclaredWAR(compilation, manifestPath, manifest, browser) {
10227
10481
  v3
10228
10482
  };
10229
10483
  }
10230
- function getAssetSource(compilation, filename) {
10484
+ function generate_manifest_getAssetSource(compilation, filename) {
10231
10485
  const byGet = 'function' == typeof compilation.getAsset ? compilation.getAsset(filename) : void 0;
10232
10486
  const byAssets = !byGet && compilation.assets ? compilation.assets[filename] : void 0;
10233
10487
  const asset = byGet || byAssets;
@@ -10318,10 +10572,9 @@ function generateManifestPatches(compilation, manifestPath, entryImports, browse
10318
10572
  const cacheKey = assetForCache && 'object' == typeof assetForCache.source ? assetForCache.source : void 0;
10319
10573
  let filtered = cacheKey ? assetScanCache.get(cacheKey) : void 0;
10320
10574
  if (!filtered) {
10321
- const source = getAssetSource(compilation, jsFile);
10575
+ const source = generate_manifest_getAssetSource(compilation, jsFile);
10322
10576
  if (!source) continue;
10323
- const re = /assets\/[A-Za-z0-9._-]+/g;
10324
- const found = source.match(re) || [];
10577
+ const found = source.match(EMITTED_ASSET_REF_PATTERN) || [];
10325
10578
  filtered = Array.from(new Set(found.filter((r)=>!r.endsWith('.js') && !r.endsWith('.map')))).sort();
10326
10579
  if (cacheKey) assetScanCache.set(cacheKey, filtered);
10327
10580
  }
@@ -10484,6 +10737,15 @@ function collectRequiredManifestFiles(manifest) {
10484
10737
  const backgroundScripts = background?.scripts;
10485
10738
  if (Array.isArray(backgroundScripts)) for (const script of backgroundScripts)addFile(script);
10486
10739
  addFile(manifestObj?.side_panel?.default_path);
10740
+ addFile(manifestObj?.action?.default_popup);
10741
+ addFile(manifestObj?.browser_action?.default_popup);
10742
+ addFile(manifestObj?.page_action?.default_popup);
10743
+ addFile(manifestObj?.options_ui?.page);
10744
+ addFile(manifestObj?.options_page);
10745
+ addFile(manifestObj?.devtools_page);
10746
+ addFile(manifestObj?.chrome_url_overrides?.newtab);
10747
+ addFile(manifestObj?.chrome_url_overrides?.history);
10748
+ addFile(manifestObj?.chrome_url_overrides?.bookmarks);
10487
10749
  const contentScripts = manifestObj?.content_scripts;
10488
10750
  if (Array.isArray(contentScripts)) for (const contentScript of contentScripts){
10489
10751
  const js = contentScript?.js;
@@ -10763,6 +11025,78 @@ function patchChromiumBackground(manifest, browser) {
10763
11025
  }
10764
11026
  };
10765
11027
  }
11028
+ const isChannel = (entry)=>'number' == typeof entry && Number.isInteger(entry) && entry >= 0 && entry <= 255;
11029
+ const isFiniteNumber = (entry)=>'number' == typeof entry && Number.isFinite(entry);
11030
+ function parseHexThemeColor(value) {
11031
+ if ('string' != typeof value) return;
11032
+ const match = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.exec(value.trim());
11033
+ if (!match) return;
11034
+ const hex = match[1];
11035
+ const digits = hex.length >= 6 ? hex.match(/../g) : hex.split('').map((digit)=>digit + digit);
11036
+ const bytes = digits.map((pair)=>parseInt(pair, 16));
11037
+ if (3 === bytes.length) return bytes;
11038
+ return [
11039
+ ...bytes.slice(0, 3),
11040
+ Math.round(bytes[3] / 255 * 1000) / 1000
11041
+ ];
11042
+ }
11043
+ function colorValueDetail(value) {
11044
+ if (parseHexThemeColor(value)) return;
11045
+ if (!Array.isArray(value) || 3 !== value.length && 4 !== value.length) return 'Chrome only accepts an [R, G, B] or [R, G, B, A] array here.';
11046
+ for (const entry of value.slice(0, 3))if (!isChannel(entry)) return 'Chrome only accepts integer color channels from 0 to 255 here.';
11047
+ if (4 === value.length && !isFiniteNumber(value[3])) return 'Chrome only accepts a numeric alpha channel here.';
11048
+ }
11049
+ function tintValueDetail(value) {
11050
+ if (!Array.isArray(value) || 3 !== value.length || !value.every(isFiniteNumber)) return 'Chrome only accepts a [hue, saturation, lightness] array of 3 numbers here.';
11051
+ }
11052
+ function collectThemeValueIssues(manifest) {
11053
+ const issues = [];
11054
+ const theme = manifest?.theme;
11055
+ if (!theme || 'object' != typeof theme) return issues;
11056
+ const groups = [
11057
+ [
11058
+ 'colors',
11059
+ theme.colors,
11060
+ colorValueDetail
11061
+ ],
11062
+ [
11063
+ 'tints',
11064
+ theme.tints,
11065
+ tintValueDetail
11066
+ ]
11067
+ ];
11068
+ for (const [group, container, detailFor] of groups)if (!(!container || 'object' != typeof container || Array.isArray(container))) for (const [key, value] of Object.entries(container)){
11069
+ const detail = detailFor(value);
11070
+ if (detail) issues.push({
11071
+ field: `theme.${group}.${key}`,
11072
+ detail,
11073
+ value: JSON.stringify(value)
11074
+ });
11075
+ }
11076
+ return issues;
11077
+ }
11078
+ function patchChromiumThemeColors(manifest, browser) {
11079
+ if (!isChromiumBasedBrowser(String(browser))) return manifest;
11080
+ const theme = manifest.theme;
11081
+ if (!theme || 'object' != typeof theme || Array.isArray(theme)) return manifest;
11082
+ const colors = theme.colors;
11083
+ if (!colors || 'object' != typeof colors || Array.isArray(colors)) return manifest;
11084
+ let converted = false;
11085
+ const patchedColors = {};
11086
+ for (const [key, value] of Object.entries(colors)){
11087
+ const rgb = parseHexThemeColor(value);
11088
+ patchedColors[key] = rgb ?? value;
11089
+ if (rgb) converted = true;
11090
+ }
11091
+ if (!converted) return manifest;
11092
+ return {
11093
+ ...manifest,
11094
+ theme: {
11095
+ ...theme,
11096
+ colors: patchedColors
11097
+ }
11098
+ };
11099
+ }
10766
11100
  function patchDevContentScriptManifestPaths(compilation, manifest) {
10767
11101
  if ('development' !== compilation.options.mode) return manifest;
10768
11102
  const cs = manifest.content_scripts;
@@ -10881,6 +11215,7 @@ class UpdateManifest {
10881
11215
  let patchedManifest = buildCanonicalManifest(this.manifestPath, manifest, this.browser);
10882
11216
  patchedManifest = patchGeckoBackground(patchedManifest, this.browser);
10883
11217
  patchedManifest = patchChromiumBackground(patchedManifest, this.browser);
11218
+ patchedManifest = patchChromiumThemeColors(patchedManifest, this.browser);
10884
11219
  const overrides = getManifestOverrides(this.manifestPath, manifest);
10885
11220
  if ('development' === compiler.options.mode) {
10886
11221
  if (patchedManifest.content_scripts) patchedManifest.content_scripts = this.applyDevOverrides(patchedManifest);
@@ -10922,42 +11257,6 @@ class UpdateManifest {
10922
11257
  });
10923
11258
  }
10924
11259
  }
10925
- const isChannel = (entry)=>'number' == typeof entry && Number.isInteger(entry) && entry >= 0 && entry <= 255;
10926
- const isFiniteNumber = (entry)=>'number' == typeof entry && Number.isFinite(entry);
10927
- function colorValueDetail(value) {
10928
- if (!Array.isArray(value) || 3 !== value.length && 4 !== value.length) return 'Chrome only accepts an [R, G, B] or [R, G, B, A] array here.';
10929
- for (const entry of value.slice(0, 3))if (!isChannel(entry)) return 'Chrome only accepts integer color channels from 0 to 255 here.';
10930
- if (4 === value.length && !isFiniteNumber(value[3])) return 'Chrome only accepts a numeric alpha channel here.';
10931
- }
10932
- function tintValueDetail(value) {
10933
- if (!Array.isArray(value) || 3 !== value.length || !value.every(isFiniteNumber)) return 'Chrome only accepts a [hue, saturation, lightness] array of 3 numbers here.';
10934
- }
10935
- function collectThemeValueIssues(manifest) {
10936
- const issues = [];
10937
- const theme = manifest?.theme;
10938
- if (!theme || 'object' != typeof theme) return issues;
10939
- const groups = [
10940
- [
10941
- 'colors',
10942
- theme.colors,
10943
- colorValueDetail
10944
- ],
10945
- [
10946
- 'tints',
10947
- theme.tints,
10948
- tintValueDetail
10949
- ]
10950
- ];
10951
- for (const [group, container, detailFor] of groups)if (!(!container || 'object' != typeof container || Array.isArray(container))) for (const [key, value] of Object.entries(container)){
10952
- const detail = detailFor(value);
10953
- if (detail) issues.push({
10954
- field: `theme.${group}.${key}`,
10955
- detail,
10956
- value: JSON.stringify(value)
10957
- });
10958
- }
10959
- return issues;
10960
- }
10961
11260
  class ValidateThemeValues {
10962
11261
  static name = 'manifest:validate-theme-values';
10963
11262
  manifestPath;
@@ -10967,7 +11266,9 @@ class ValidateThemeValues {
10967
11266
  this.browser = options.browser || 'chrome';
10968
11267
  }
10969
11268
  apply(compiler) {
10970
- if (!isChromiumBasedBrowser(String(this.browser))) return;
11269
+ const browserName = String(this.browser);
11270
+ const webkitTarget = isWebkitBasedBrowser(browserName);
11271
+ if (!isChromiumBasedBrowser(browserName) && !webkitTarget) return;
10971
11272
  compiler.hooks.thisCompilation.tap(ValidateThemeValues.name, (compilation)=>{
10972
11273
  compilation.hooks.processAssets.tap({
10973
11274
  name: ValidateThemeValues.name,
@@ -10979,6 +11280,10 @@ class ValidateThemeValues {
10979
11280
  } catch {
10980
11281
  return;
10981
11282
  }
11283
+ if (webkitTarget) {
11284
+ if (manifest.theme) reportToCompilation(compilation, compiler, themeNotSupportedByBrowser(browserName), 'warning', 'manifest.json');
11285
+ return;
11286
+ }
10982
11287
  for (const issue of collectThemeValueIssues(manifest))reportToCompilation(compilation, compiler, invalidThemeValue(issue.field, issue.detail, issue.value), 'error', 'manifest.json');
10983
11288
  });
10984
11289
  });
@@ -11436,100 +11741,6 @@ class ScriptsPlugin {
11436
11741
  new ValidateContentScriptSyntax().apply(compiler);
11437
11742
  }
11438
11743
  }
11439
- function forEachStringKey(objectOrMap, callback) {
11440
- if (!objectOrMap) return;
11441
- if (objectOrMap instanceof Map) {
11442
- const keys = objectOrMap.keys();
11443
- for (const key of keys)callback(String(key));
11444
- } else if ('object' == typeof objectOrMap) {
11445
- const objectKeys = Object.keys(objectOrMap);
11446
- for (const key of objectKeys)callback(key);
11447
- }
11448
- }
11449
- function collect_entry_imports_getAssetSource(compilation, filename) {
11450
- let assetGetFunction;
11451
- if ('function' == typeof compilation.getAsset) assetGetFunction = compilation.getAsset(filename);
11452
- let assetViaAssets;
11453
- if (!assetGetFunction && compilation.assets) assetViaAssets = compilation.assets[filename];
11454
- const asset = assetGetFunction || assetViaAssets;
11455
- if (!asset) return '';
11456
- let src;
11457
- src = 'function' == typeof asset.source ? asset.source() : asset.source?.source ? asset.source.source() : asset.source;
11458
- if ('string' == typeof src) return src;
11459
- return '';
11460
- }
11461
- function collectContentScriptEntryImports(compilation, includeList) {
11462
- const entryImports = {};
11463
- const contentEntryNames = new Set(Object.keys(includeList || {}).filter((k)=>k.startsWith("content_scripts")));
11464
- const chunkGraph = compilation.chunkGraph;
11465
- compilation.entrypoints.forEach((_entry, entryName)=>{
11466
- if (String(entryName).startsWith("content_scripts/")) contentEntryNames.add(entryName);
11467
- });
11468
- compilation.entrypoints.forEach((entry, entryName)=>{
11469
- if (!contentEntryNames.has(entryName)) return;
11470
- const collectedFilesSet = new Set();
11471
- function addFileIfRelevant(file) {
11472
- if (null == file) return;
11473
- const fileNameStr = String(file);
11474
- const isJavaScript = fileNameStr.endsWith('.js');
11475
- const isSourceMap = fileNameStr.endsWith('.map');
11476
- if (isJavaScript || isSourceMap) return;
11477
- collectedFilesSet.add(fileNameStr);
11478
- }
11479
- entry.chunks.forEach((chunk)=>{
11480
- const currentChunk = chunk;
11481
- const chunkFilesArray = Array.isArray(currentChunk.files) ? currentChunk.files : [];
11482
- for(let i = 0; i < chunkFilesArray.length; i++)addFileIfRelevant(chunkFilesArray[i]);
11483
- let chunkAuxFilesArray = [];
11484
- if (Array.isArray(currentChunk.auxiliaryFiles)) chunkAuxFilesArray = currentChunk.auxiliaryFiles;
11485
- for(let i = 0; i < chunkAuxFilesArray.length; i++)addFileIfRelevant(chunkAuxFilesArray[i]);
11486
- const modulesArray = Array.from(chunkGraph.getChunkModulesIterable(chunk));
11487
- for(let j = 0; j < modulesArray.length; j++){
11488
- const moduleObj = modulesArray[j];
11489
- const moduleChunksArray = Array.from(chunkGraph.getModuleChunks(moduleObj));
11490
- for(let k = 0; k < moduleChunksArray.length; k++){
11491
- const mk = moduleChunksArray[k];
11492
- const mkAuxFilesArr = Array.isArray(mk.auxiliaryFiles) ? mk.auxiliaryFiles : [];
11493
- for(let l = 0; l < mkAuxFilesArr.length; l++)addFileIfRelevant(mkAuxFilesArr[l]);
11494
- }
11495
- const moduleWithBuildInfo = moduleObj;
11496
- const buildInfo = moduleWithBuildInfo.buildInfo;
11497
- forEachStringKey(buildInfo?.assets, (key)=>{
11498
- addFileIfRelevant(key);
11499
- });
11500
- forEachStringKey(buildInfo?.assetsInfo, (key)=>{
11501
- addFileIfRelevant(key);
11502
- });
11503
- }
11504
- for(let i = 0; i < chunkFilesArray.length; i++){
11505
- const chunkFileName = chunkFilesArray[i];
11506
- if (!String(chunkFileName).endsWith('.js')) continue;
11507
- const jsSource = collect_entry_imports_getAssetSource(compilation, chunkFileName);
11508
- if (!jsSource) continue;
11509
- const assetPattern = /assets\/[A-Za-z0-9._-]+/g;
11510
- const matchedStrings = jsSource.match(assetPattern) || [];
11511
- for(let m = 0; m < matchedStrings.length; m++)addFileIfRelevant(matchedStrings[m]);
11512
- }
11513
- });
11514
- const logicalJsAssetName = `${entryName}.js`;
11515
- const logicalJsAssetSource = collect_entry_imports_getAssetSource(compilation, logicalJsAssetName);
11516
- if (logicalJsAssetSource) {
11517
- const assetPattern = /assets\/[A-Za-z0-9._-]+/g;
11518
- const matchedStrings = logicalJsAssetSource.match(assetPattern) || [];
11519
- for(let n = 0; n < matchedStrings.length; n++)addFileIfRelevant(matchedStrings[n]);
11520
- }
11521
- entryImports[entryName] = Array.from(collectedFilesSet);
11522
- });
11523
- const entryImportsEntries = Object.entries(entryImports);
11524
- for(let i = 0; i < entryImportsEntries.length; i++){
11525
- const name = entryImportsEntries[i][0];
11526
- const files = entryImportsEntries[i][1];
11527
- const normalizedFiles = [];
11528
- for(let j = 0; j < files.length; j++)normalizedFiles.push(unixify(files[j]));
11529
- entryImports[name] = normalizedFiles;
11530
- }
11531
- return entryImports;
11532
- }
11533
11744
  class CollectContentEntryImports {
11534
11745
  includeList;
11535
11746
  constructor(options){
@@ -11572,10 +11783,13 @@ class WebResourcesPlugin {
11572
11783
  function isCriticalJsonFeatureKey(key) {
11573
11784
  return key.startsWith('declarative_net_request') || 'storage.managed_schema' === key;
11574
11785
  }
11786
+ function toComparablePath(value) {
11787
+ return 'string' == typeof value ? value : JSON.stringify(value);
11788
+ }
11575
11789
  function flattenValues(map) {
11576
11790
  const paths = [];
11577
- for (const val of Object.values(map || {}))if (Array.isArray(val)) paths.push(...val.filter(Boolean));
11578
- else if (val) paths.push(val);
11791
+ for (const val of Object.values(map || {}))if (Array.isArray(val)) paths.push(...val.filter(Boolean).map(toComparablePath));
11792
+ else if (val) paths.push(toComparablePath(val));
11579
11793
  return paths;
11580
11794
  }
11581
11795
  function diffArray(prev, next) {
@@ -11628,7 +11842,7 @@ class ManifestFieldsChangeDetector {
11628
11842
  else if (val) scripts.push(val);
11629
11843
  const html = fields.html || {};
11630
11844
  const iconsRaw = fields.icons;
11631
- const icons = iconsRaw ? Array.isArray(iconsRaw) ? iconsRaw : flattenValues(iconsRaw) : [];
11845
+ const icons = iconsRaw ? Array.isArray(iconsRaw) ? iconsRaw.filter(Boolean).map(toComparablePath) : flattenValues(iconsRaw) : [];
11632
11846
  const jsonMap = fields.json || {};
11633
11847
  const json = [];
11634
11848
  for (const [key, val] of Object.entries(jsonMap))if (isCriticalJsonFeatureKey(key)) {
@@ -11800,6 +12014,7 @@ function webpackConfig(projectStructure, devOptions) {
11800
12014
  }
11801
12015
  const manifest = filterKeysForThisBrowser(rawManifest, devOptions.browser);
11802
12016
  const primaryExtensionOutputDir = asAbsolute(__rspack_external_node_path_c5b9b54f.isAbsolute(devOptions.output.path) ? devOptions.output.path : __rspack_external_node_path_c5b9b54f.resolve(packageJsonDir, devOptions.output.path));
12017
+ const publishedExtensionOutputDir = devOptions.output.finalPath ? asAbsolute(__rspack_external_node_path_c5b9b54f.isAbsolute(devOptions.output.finalPath) ? devOptions.output.finalPath : __rspack_external_node_path_c5b9b54f.resolve(packageJsonDir, devOptions.output.finalPath)) : primaryExtensionOutputDir;
11803
12018
  const companionUnpackedExtensionDirs = resolveCompanionExtensionDirs({
11804
12019
  projectRoot: packageJsonDir,
11805
12020
  config: devOptions.extensions
@@ -11926,7 +12141,7 @@ function webpackConfig(projectStructure, devOptions) {
11926
12141
  browser: devOptions.browser,
11927
12142
  mode: devOptions.mode,
11928
12143
  command: devOptions.metadataCommand,
11929
- outputPath: primaryExtensionOutputDir,
12144
+ outputPath: publishedExtensionOutputDir,
11930
12145
  manifestPath,
11931
12146
  port: devOptions.port,
11932
12147
  host: process.env.EXTENSION_DEV_SERVER_CONNECTABLE_HOST || devOptions.host,