extension-develop 3.10.2 → 3.10.4-canary.1

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 (99) hide show
  1. package/dist/215.cjs +350 -69
  2. package/dist/323.cjs +456 -26
  3. package/dist/324.cjs +15 -9
  4. package/dist/{270.cjs → 677.cjs} +3121 -494
  5. package/dist/ensure-hmr-for-scripts.cjs +50 -0
  6. package/dist/ensure-hmr-for-scripts.js +145 -0
  7. package/dist/feature-scripts-content-script-wrapper.cjs +237 -0
  8. package/dist/feature-scripts-content-script-wrapper.js +237 -0
  9. package/dist/main-world-bridge.js +127 -0
  10. package/dist/minimum-chromium-file.js +10 -0
  11. package/dist/minimum-firefox-file.js +10 -0
  12. package/dist/minimum-script-file.js +31 -0
  13. package/dist/module.cjs +2072 -1755
  14. package/dist/package.json +3 -0
  15. package/dist/resolve-paths-loader.js +1350 -0
  16. package/package.json +5 -5
  17. package/dist/add-hmr-accept-code.cjs +0 -91
  18. package/dist/content-script-wrapper.cjs +0 -319
  19. package/dist/extension-js-devtools/chrome/assets/developer-mode-off.f9a94937.jpeg +0 -0
  20. package/dist/extension-js-devtools/chrome/assets/developer-mode-on.ede80e5b.jpeg +0 -0
  21. package/dist/extension-js-devtools/chrome/assets/local-network-permission.4fae40a7.png +0 -0
  22. package/dist/extension-js-devtools/chrome/assets/logo.7dc70d61.png +0 -0
  23. package/dist/extension-js-devtools/chrome/background/service_worker.js +0 -26
  24. package/dist/extension-js-devtools/chrome/chrome_url_overrides/newtab.html +0 -23
  25. package/dist/extension-js-devtools/chrome/content_scripts/content-0.js +0 -5
  26. package/dist/extension-js-devtools/chrome/content_scripts/styles.24e59c3d.css +0 -2
  27. package/dist/extension-js-devtools/chrome/devtools/index.html +0 -12
  28. package/dist/extension-js-devtools/chrome/devtools/index.js +0 -1
  29. package/dist/extension-js-devtools/chrome/icons/logo.png +0 -0
  30. package/dist/extension-js-devtools/chrome/manifest.json +0 -57
  31. package/dist/extension-js-devtools/chrome/pages/centralized-logger.css +0 -2
  32. package/dist/extension-js-devtools/chrome/pages/centralized-logger.html +0 -12
  33. package/dist/extension-js-devtools/chrome/pages/centralized-logger.js +0 -15
  34. package/dist/extension-js-devtools/chrome/pages/welcome.css +0 -2
  35. package/dist/extension-js-devtools/chrome/pages/welcome.html +0 -11
  36. package/dist/extension-js-devtools/chrome/pages/welcome.js +0 -25
  37. package/dist/extension-js-devtools/chrome/scripts/logger-client.js +0 -1
  38. package/dist/extension-js-devtools/chromium/assets/developer-mode-off.f9a94937.jpeg +0 -0
  39. package/dist/extension-js-devtools/chromium/assets/developer-mode-on.ede80e5b.jpeg +0 -0
  40. package/dist/extension-js-devtools/chromium/assets/local-network-permission.4fae40a7.png +0 -0
  41. package/dist/extension-js-devtools/chromium/assets/logo.7dc70d61.png +0 -0
  42. package/dist/extension-js-devtools/chromium/background/service_worker.js +0 -26
  43. package/dist/extension-js-devtools/chromium/chrome_url_overrides/newtab.html +0 -23
  44. package/dist/extension-js-devtools/chromium/content_scripts/content-0.js +0 -5
  45. package/dist/extension-js-devtools/chromium/content_scripts/styles.24e59c3d.css +0 -2
  46. package/dist/extension-js-devtools/chromium/devtools/index.html +0 -12
  47. package/dist/extension-js-devtools/chromium/devtools/index.js +0 -1
  48. package/dist/extension-js-devtools/chromium/icons/logo.png +0 -0
  49. package/dist/extension-js-devtools/chromium/manifest.json +0 -57
  50. package/dist/extension-js-devtools/chromium/pages/centralized-logger.css +0 -2
  51. package/dist/extension-js-devtools/chromium/pages/centralized-logger.html +0 -12
  52. package/dist/extension-js-devtools/chromium/pages/centralized-logger.js +0 -15
  53. package/dist/extension-js-devtools/chromium/pages/welcome.css +0 -2
  54. package/dist/extension-js-devtools/chromium/pages/welcome.html +0 -11
  55. package/dist/extension-js-devtools/chromium/pages/welcome.js +0 -25
  56. package/dist/extension-js-devtools/chromium/scripts/logger-client.js +0 -1
  57. package/dist/extension-js-devtools/edge/assets/developer-mode-off.f9a94937.jpeg +0 -0
  58. package/dist/extension-js-devtools/edge/assets/developer-mode-on.ede80e5b.jpeg +0 -0
  59. package/dist/extension-js-devtools/edge/assets/local-network-permission.4fae40a7.png +0 -0
  60. package/dist/extension-js-devtools/edge/assets/logo.7dc70d61.png +0 -0
  61. package/dist/extension-js-devtools/edge/background/service_worker.js +0 -26
  62. package/dist/extension-js-devtools/edge/chrome_url_overrides/newtab.html +0 -23
  63. package/dist/extension-js-devtools/edge/content_scripts/content-0.js +0 -5
  64. package/dist/extension-js-devtools/edge/content_scripts/styles.24e59c3d.css +0 -2
  65. package/dist/extension-js-devtools/edge/devtools/index.html +0 -12
  66. package/dist/extension-js-devtools/edge/devtools/index.js +0 -1
  67. package/dist/extension-js-devtools/edge/icons/logo.png +0 -0
  68. package/dist/extension-js-devtools/edge/manifest.json +0 -57
  69. package/dist/extension-js-devtools/edge/pages/centralized-logger.css +0 -2
  70. package/dist/extension-js-devtools/edge/pages/centralized-logger.html +0 -12
  71. package/dist/extension-js-devtools/edge/pages/centralized-logger.js +0 -15
  72. package/dist/extension-js-devtools/edge/pages/welcome.css +0 -2
  73. package/dist/extension-js-devtools/edge/pages/welcome.html +0 -11
  74. package/dist/extension-js-devtools/edge/pages/welcome.js +0 -25
  75. package/dist/extension-js-devtools/edge/scripts/logger-client.js +0 -1
  76. package/dist/extension-js-devtools/firefox/assets/developer-mode-off.f9a94937.jpeg +0 -0
  77. package/dist/extension-js-devtools/firefox/assets/developer-mode-on.ede80e5b.jpeg +0 -0
  78. package/dist/extension-js-devtools/firefox/assets/local-network-permission.4fae40a7.png +0 -0
  79. package/dist/extension-js-devtools/firefox/assets/logo.7dc70d61.png +0 -0
  80. package/dist/extension-js-devtools/firefox/background/scripts.js +0 -26
  81. package/dist/extension-js-devtools/firefox/content_scripts/content-0.js +0 -5
  82. package/dist/extension-js-devtools/firefox/content_scripts/styles.24e59c3d.css +0 -2
  83. package/dist/extension-js-devtools/firefox/devtools/index.html +0 -12
  84. package/dist/extension-js-devtools/firefox/devtools/index.js +0 -1
  85. package/dist/extension-js-devtools/firefox/icons/logo.png +0 -0
  86. package/dist/extension-js-devtools/firefox/manifest.json +0 -42
  87. package/dist/extension-js-devtools/firefox/pages/centralized-logger.css +0 -2
  88. package/dist/extension-js-devtools/firefox/pages/centralized-logger.html +0 -12
  89. package/dist/extension-js-devtools/firefox/pages/centralized-logger.js +0 -15
  90. package/dist/extension-js-devtools/firefox/pages/welcome.css +0 -2
  91. package/dist/extension-js-devtools/firefox/pages/welcome.html +0 -11
  92. package/dist/extension-js-devtools/firefox/pages/welcome.js +0 -25
  93. package/dist/extension-js-devtools/firefox/scripts/logger-client.js +0 -1
  94. package/dist/extension-js-theme/chrome/manifest.json +0 -66
  95. package/dist/extension-js-theme/chromium/manifest.json +0 -66
  96. package/dist/extension-js-theme/edge/manifest.json +0 -66
  97. package/dist/extension-js-theme/firefox/manifest.json +0 -66
  98. package/dist/warn-no-default-export.cjs +0 -356
  99. package/webpack/webpack-lib/optional-dependencies.json +0 -20
@@ -3,7 +3,7 @@ const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
3
  return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
4
  }();
5
5
  exports.ids = [
6
- "270"
6
+ "677"
7
7
  ];
8
8
  exports.modules = {
9
9
  "./webpack/dev-server/compiler-hooks.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
@@ -794,9 +794,11 @@ exports.modules = {
794
794
  }
795
795
  };
796
796
  }
797
+ var contracts = __webpack_require__("./webpack/plugin-web-extension/feature-scripts/contracts.ts");
797
798
  function isBundledContentPath(filePath, ext) {
798
799
  const normalized = String(filePath || '').replace(/\\/g, '/');
799
- return new RegExp(`^content_scripts/content-\\d+\\.${ext}$`).test(normalized);
800
+ const bundledAsset = (0, contracts.es)(normalized);
801
+ return bundledAsset?.extension === ext;
800
802
  }
801
803
  function isAlreadyBundledContentScripts(contentScripts) {
802
804
  if (!Array.isArray(contentScripts) || 0 === contentScripts.length) return false;
@@ -829,7 +831,7 @@ exports.modules = {
829
831
  result.push({
830
832
  ...rest,
831
833
  js: [
832
- getFilename(`content_scripts/content-${bridgeIndex}.js`, 'main-world-bridge.js')
834
+ getFilename((0, contracts.f6)(bridgeIndex), 'main-world-bridge.js')
833
835
  ],
834
836
  css: []
835
837
  });
@@ -837,10 +839,10 @@ exports.modules = {
837
839
  result.push({
838
840
  ...original[index] || {},
839
841
  js: [
840
- ...new Set(contentJs.map((js)=>getFilename(`content_scripts/content-${index}.js`, js)))
842
+ ...new Set(contentJs.map((js)=>getFilename((0, contracts.f6)(index), js)))
841
843
  ],
842
844
  css: [
843
- ...new Set(contentCss.map((css)=>getFilename(`content_scripts/content-${index}.css`, css)))
845
+ ...new Set(contentCss.map((css)=>getFilename((0, contracts.J4)(index), css)))
844
846
  ]
845
847
  });
846
848
  }
@@ -1455,7 +1457,14 @@ exports.modules = {
1455
1457
  const manifestName = boring_readJsonFileSafe(this.manifestPath).name;
1456
1458
  const line = boring(manifestName, duration, stats);
1457
1459
  try {
1458
- const modifiedFiles = Array.from(stats?.compilation?.modifiedFiles || []).map((file)=>String(file).replace(/\\/g, '/'));
1460
+ const fromCompilation = Array.from(stats?.compilation?.modifiedFiles || []);
1461
+ const fromCompiler = Array.from(compiler.modifiedFiles ?? []);
1462
+ const modifiedFiles = [
1463
+ ...new Set([
1464
+ ...fromCompilation,
1465
+ ...fromCompiler
1466
+ ])
1467
+ ].map((file)=>String(file).replace(/\\/g, '/'));
1459
1468
  if (!this.sawUserInvalidation && modifiedFiles.length > 0) {
1460
1469
  const context = String(compiler?.options?.context || '').replace(/\\/g, '/');
1461
1470
  const hasUserFileChange = modifiedFiles.some((file)=>{
@@ -1576,7 +1585,7 @@ exports.modules = {
1576
1585
  }
1577
1586
  plugin_compilation_define_property(CompilationPlugin, "name", 'plugin-compilation');
1578
1587
  var css_lib_messages = __webpack_require__("./webpack/plugin-css/css-lib/messages.ts");
1579
- var optional_deps_lib = __webpack_require__("./webpack/optional-deps-lib/index.ts");
1588
+ var external_optional_deps_lib_ = __webpack_require__("optional-deps-lib");
1580
1589
  var sass = __webpack_require__("./webpack/plugin-css/css-tools/sass.ts");
1581
1590
  var less = __webpack_require__("./webpack/plugin-css/css-tools/less.ts");
1582
1591
  function getStylelintConfigFile(projectPath) {
@@ -1688,7 +1697,12 @@ exports.modules = {
1688
1697
  test,
1689
1698
  exclude,
1690
1699
  type,
1691
- issuer: isContentScript
1700
+ issuer: isContentScript,
1701
+ resourceQuery: {
1702
+ not: [
1703
+ /url/
1704
+ ]
1705
+ }
1692
1706
  };
1693
1707
  if ('asset' === type) baseConfig.generator = {
1694
1708
  filename: "content_scripts/[name].[contenthash:8].css"
@@ -1763,7 +1777,12 @@ exports.modules = {
1763
1777
  test,
1764
1778
  exclude,
1765
1779
  type,
1766
- issuer: isNotContentScript
1780
+ issuer: isNotContentScript,
1781
+ resourceQuery: {
1782
+ not: [
1783
+ /url/
1784
+ ]
1785
+ }
1767
1786
  };
1768
1787
  if (!loader) return {
1769
1788
  ...baseConfig,
@@ -1801,8 +1820,8 @@ exports.modules = {
1801
1820
  const projectPath = compiler.options.context || process.cwd();
1802
1821
  const plugins = [];
1803
1822
  const manifestPath = this.manifestPath;
1804
- const usingSass = (0, optional_deps_lib.ws)(projectPath, 'sass');
1805
- const usingLess = (0, optional_deps_lib.ws)(projectPath, 'less');
1823
+ const usingSass = (0, external_optional_deps_lib_.hasDependency)(projectPath, 'sass');
1824
+ const usingLess = (0, external_optional_deps_lib_.hasDependency)(projectPath, 'less');
1806
1825
  const maybeInstallStylelint = await maybeUseStylelint(projectPath);
1807
1826
  plugins.push(...maybeInstallStylelint);
1808
1827
  const maybeInstallSass = await (0, sass.IZ)(projectPath);
@@ -1845,8 +1864,8 @@ exports.modules = {
1845
1864
  ].filter(Boolean);
1846
1865
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
1847
1866
  const integrations = [];
1848
- const usingTailwind = (0, optional_deps_lib.ws)(projectPath, 'tailwindcss');
1849
- const usingPostcss = (0, optional_deps_lib.ws)(projectPath, 'postcss') || void 0 !== findPostCssConfig(projectPath) || usingSass || usingLess || usingTailwind;
1867
+ const usingTailwind = (0, external_optional_deps_lib_.hasDependency)(projectPath, 'tailwindcss');
1868
+ const usingPostcss = (0, external_optional_deps_lib_.hasDependency)(projectPath, 'postcss') || void 0 !== findPostCssConfig(projectPath) || usingSass || usingLess || usingTailwind;
1850
1869
  if (usingPostcss) integrations.push('PostCSS');
1851
1870
  if (usingSass) integrations.push('Sass');
1852
1871
  if (usingLess) integrations.push('Less');
@@ -2111,19 +2130,61 @@ exports.modules = {
2111
2130
  };
2112
2131
  return merged;
2113
2132
  }
2133
+ patchReactRefreshRules(rules) {
2134
+ for (const rule of rules){
2135
+ if (!rule || 'object' != typeof rule) continue;
2136
+ const uses = Array.isArray(rule.use) ? rule.use : rule.use ? [
2137
+ rule.use
2138
+ ] : rule.loader ? [
2139
+ {
2140
+ loader: rule.loader
2141
+ }
2142
+ ] : [];
2143
+ const hasReactRefreshLoader = uses.some((useEntry)=>String(useEntry?.loader || '').includes('react-refresh-loader'));
2144
+ if (hasReactRefreshLoader) rule.issuerLayer = {
2145
+ not: contracts.$t
2146
+ };
2147
+ if (Array.isArray(rule.oneOf)) this.patchReactRefreshRules(rule.oneOf);
2148
+ if (Array.isArray(rule.rules)) this.patchReactRefreshRules(rule.rules);
2149
+ }
2150
+ }
2114
2151
  async configureOptions(compiler) {
2115
2152
  const mode = compiler.options.mode || 'development';
2116
2153
  const projectPath = compiler.options.context;
2154
+ const manifestDir = external_path_.dirname(this.manifestPath);
2155
+ const swcIncludeDirs = Array.from(new Set([
2156
+ projectPath,
2157
+ manifestDir,
2158
+ ...resolveTranspilePackageDirs(projectPath, this.transpilePackages)
2159
+ ]));
2160
+ const contentScriptLikePaths = new Set();
2161
+ const scriptsDir = external_path_.resolve(projectPath, "scripts");
2162
+ const isfeatureScriptsContentLike = (resourcePath)=>{
2163
+ const normalized = external_path_.normalize(resourcePath);
2164
+ if (contentScriptLikePaths.has(normalized)) return true;
2165
+ const relToScripts = external_path_.relative(scriptsDir, normalized);
2166
+ return !!relToScripts && !relToScripts.startsWith('..') && !external_path_.isAbsolute(relToScripts);
2167
+ };
2117
2168
  const devtool = compiler.options.devtool;
2118
2169
  const wantsSourceMaps = false !== devtool && ('development' === mode || null != devtool);
2119
- const maybeInstallReact = await (0, react.b)(projectPath);
2170
+ try {
2171
+ const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf-8'));
2172
+ const contentScripts = Array.isArray(manifest?.content_scripts) ? manifest.content_scripts : [];
2173
+ for (const contentScript of contentScripts){
2174
+ const jsList = Array.isArray(contentScript?.js) ? contentScript.js : [];
2175
+ for (const jsFile of jsList)contentScriptLikePaths.add(external_path_.resolve(manifestDir, jsFile));
2176
+ }
2177
+ } catch {}
2178
+ const maybeInstallReact = await (0, react.b)(projectPath, {
2179
+ disableRefresh: true,
2180
+ refreshExclude: (resourcePath)=>isfeatureScriptsContentLike(resourcePath)
2181
+ });
2120
2182
  const maybeInstallPreact = await (0, preact.b)(projectPath);
2121
2183
  const maybeInstallVue = await (0, vue.K)(projectPath, mode);
2122
2184
  const maybeInstallSvelte = await (0, svelte.X)(projectPath, mode);
2123
2185
  const tsConfigPath = (0, typescript.hB)(projectPath);
2124
- const manifestDir = external_path_.dirname(this.manifestPath);
2125
2186
  const tsRoot = tsConfigPath ? external_path_.dirname(tsConfigPath) : manifestDir;
2126
- const transpilePackageDirs = resolveTranspilePackageDirs(projectPath, this.transpilePackages);
2187
+ const transpilePackageDirs = swcIncludeDirs.filter((dir)=>dir !== projectPath && dir !== manifestDir);
2127
2188
  const preferTypeScript = !!tsConfigPath || (0, typescript.eE)(projectPath);
2128
2189
  let targets = [
2129
2190
  'chrome >= 100'
@@ -2163,59 +2224,131 @@ exports.modules = {
2163
2224
  vueLoadersToAdd = [];
2164
2225
  }
2165
2226
  }
2166
- compiler.options.module.rules = [
2227
+ const swcRuleBase = {
2228
+ test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
2229
+ include: Array.from(new Set([
2230
+ tsRoot,
2231
+ ...swcIncludeDirs
2232
+ ])),
2233
+ exclude: [
2234
+ (resourcePath)=>{
2235
+ const isInNodeModules = /[\\/]node_modules[\\/]/.test(resourcePath);
2236
+ if (!isInNodeModules) return false;
2237
+ return !transpilePackageDirs.some((dir)=>isSubPath(resourcePath, dir));
2238
+ }
2239
+ ]
2240
+ };
2241
+ const swcLoaderBase = {
2242
+ loader: 'builtin:swc-loader',
2243
+ options: {
2244
+ sync: true,
2245
+ module: {
2246
+ type: 'es6'
2247
+ },
2248
+ minify: false,
2249
+ isModule: true,
2250
+ sourceMap: wantsSourceMaps,
2251
+ env: {
2252
+ targets
2253
+ },
2254
+ jsc: {
2255
+ parser: {
2256
+ syntax: preferTypeScript ? "typescript" : "ecmascript",
2257
+ tsx: preferTypeScript ? true : (0, typescript.eE)(projectPath) && ((0, react.S)(projectPath) || (0, preact.K)(projectPath)),
2258
+ jsx: !preferTypeScript && ((0, react.S)(projectPath) || (0, preact.K)(projectPath)),
2259
+ dynamicImport: true
2260
+ },
2261
+ transform: {
2262
+ react: {
2263
+ development: 'development' === mode,
2264
+ runtime: 'automatic',
2265
+ importSource: 'react',
2266
+ ...(0, preact.K)(projectPath) ? {
2267
+ pragma: 'h',
2268
+ pragmaFrag: 'Fragment',
2269
+ throwIfNamespace: true,
2270
+ useBuiltins: false
2271
+ } : {}
2272
+ }
2273
+ }
2274
+ }
2275
+ }
2276
+ };
2277
+ const swcRules = [
2167
2278
  {
2168
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
2169
- include: Array.from(new Set([
2170
- tsRoot,
2171
- manifestDir,
2172
- ...transpilePackageDirs
2173
- ])),
2174
- exclude: [
2175
- (resourcePath)=>{
2176
- const isInNodeModules = /[\\/]node_modules[\\/]/.test(resourcePath);
2177
- if (!isInNodeModules) return false;
2178
- return !transpilePackageDirs.some((dir)=>isSubPath(resourcePath, dir));
2279
+ ...swcRuleBase,
2280
+ layer: contracts.$t,
2281
+ include: (resourcePath)=>Array.from(new Set([
2282
+ tsRoot,
2283
+ ...swcIncludeDirs
2284
+ ])).some((dir)=>isSubPath(resourcePath, dir)) && isfeatureScriptsContentLike(resourcePath),
2285
+ use: {
2286
+ ...swcLoaderBase,
2287
+ options: {
2288
+ ...swcLoaderBase.options,
2289
+ jsc: {
2290
+ ...swcLoaderBase.options.jsc,
2291
+ transform: {
2292
+ ...swcLoaderBase.options.jsc.transform,
2293
+ react: {
2294
+ ...swcLoaderBase.options.jsc.transform.react,
2295
+ refresh: false
2296
+ }
2297
+ }
2298
+ }
2179
2299
  }
2180
- ],
2300
+ }
2301
+ },
2302
+ {
2303
+ ...swcRuleBase,
2304
+ issuerLayer: contracts.$t,
2305
+ layer: contracts.$t,
2181
2306
  use: {
2182
- loader: 'builtin:swc-loader',
2307
+ ...swcLoaderBase,
2183
2308
  options: {
2184
- sync: true,
2185
- module: {
2186
- type: 'es6'
2187
- },
2188
- minify: false,
2189
- isModule: true,
2190
- sourceMap: wantsSourceMaps,
2191
- env: {
2192
- targets
2193
- },
2309
+ ...swcLoaderBase.options,
2194
2310
  jsc: {
2195
- parser: {
2196
- syntax: preferTypeScript ? "typescript" : "ecmascript",
2197
- tsx: preferTypeScript ? true : (0, typescript.eE)(projectPath) && ((0, react.S)(projectPath) || (0, preact.K)(projectPath)),
2198
- jsx: !preferTypeScript && ((0, react.S)(projectPath) || (0, preact.K)(projectPath)),
2199
- dynamicImport: true
2200
- },
2311
+ ...swcLoaderBase.options.jsc,
2201
2312
  transform: {
2313
+ ...swcLoaderBase.options.jsc.transform,
2202
2314
  react: {
2203
- development: 'development' === mode,
2204
- refresh: 'development' === mode,
2205
- runtime: 'automatic',
2206
- importSource: 'react',
2207
- ...(0, preact.K)(projectPath) ? {
2208
- pragma: 'h',
2209
- pragmaFrag: 'Fragment',
2210
- throwIfNamespace: true,
2211
- useBuiltins: false
2212
- } : {}
2315
+ ...swcLoaderBase.options.jsc.transform.react,
2316
+ refresh: false
2213
2317
  }
2214
2318
  }
2215
2319
  }
2216
2320
  }
2217
2321
  }
2218
2322
  },
2323
+ {
2324
+ ...swcRuleBase,
2325
+ issuerLayer: {
2326
+ not: contracts.$t
2327
+ },
2328
+ exclude: [
2329
+ ...swcRuleBase.exclude,
2330
+ (resourcePath)=>isfeatureScriptsContentLike(resourcePath)
2331
+ ],
2332
+ use: {
2333
+ ...swcLoaderBase,
2334
+ options: {
2335
+ ...swcLoaderBase.options,
2336
+ jsc: {
2337
+ ...swcLoaderBase.options.jsc,
2338
+ transform: {
2339
+ ...swcLoaderBase.options.jsc.transform,
2340
+ react: {
2341
+ ...swcLoaderBase.options.jsc.transform.react,
2342
+ refresh: 'development' === mode
2343
+ }
2344
+ }
2345
+ }
2346
+ }
2347
+ }
2348
+ }
2349
+ ];
2350
+ compiler.options.module.rules = [
2351
+ ...swcRules,
2219
2352
  ...maybeInstallReact?.loaders || [],
2220
2353
  ...maybeInstallPreact?.loaders || [],
2221
2354
  ...vueLoadersToAdd,
@@ -2226,6 +2359,7 @@ exports.modules = {
2226
2359
  maybeInstallPreact?.plugins?.forEach((plugin)=>plugin.apply(compiler));
2227
2360
  maybeInstallVue?.plugins?.forEach((plugin)=>plugin.apply(compiler));
2228
2361
  maybeInstallSvelte?.plugins?.forEach((plugin)=>plugin.apply(compiler));
2362
+ this.patchReactRefreshRules(compiler.options.module.rules);
2229
2363
  if ((0, typescript.eE)(projectPath) || !!tsConfigPath) compiler.options.resolve.tsConfig = {
2230
2364
  configFile: tsConfigPath
2231
2365
  };
@@ -2347,6 +2481,67 @@ exports.modules = {
2347
2481
  this.manifestPath = options.manifestPath;
2348
2482
  }
2349
2483
  }
2484
+ function patchDevContentScriptManifestPaths(compilation, manifest) {
2485
+ if ('development' !== compilation.options.mode) return manifest;
2486
+ const cs = manifest.content_scripts;
2487
+ if (!Array.isArray(cs)) return manifest;
2488
+ const assetNames = new Set((compilation.getAssets?.() || []).map((a)=>a.name || '').filter(Boolean));
2489
+ const currentHashedNames = new Set();
2490
+ const next = cs.map((group, groupIndex)=>{
2491
+ const js = Array.isArray(group.js) ? [
2492
+ ...group.js
2493
+ ] : [];
2494
+ const css = Array.isArray(group.css) ? [
2495
+ ...group.css
2496
+ ] : [];
2497
+ const resolvedJs = js.map((p)=>resolveDevContentScriptDeclaredPath(p, groupIndex, 'js', assetNames));
2498
+ const resolvedCss = css.map((p)=>resolveDevContentScriptDeclaredPath(p, groupIndex, 'css', assetNames));
2499
+ for (const n of [
2500
+ ...resolvedJs,
2501
+ ...resolvedCss
2502
+ ])currentHashedNames.add(n);
2503
+ return {
2504
+ ...group,
2505
+ js: resolvedJs,
2506
+ css: resolvedCss
2507
+ };
2508
+ });
2509
+ purgeStaleHashedContentScripts(compilation, currentHashedNames);
2510
+ return {
2511
+ ...manifest,
2512
+ content_scripts: next
2513
+ };
2514
+ }
2515
+ function resolveDevContentScriptDeclaredPath(declaredPath, groupIndex, ext, assetNames) {
2516
+ const canonical = 'js' === ext ? (0, contracts.f6)(groupIndex) : (0, contracts.J4)(groupIndex);
2517
+ if (declaredPath !== canonical) return declaredPath;
2518
+ const hashed = findHashedContentScriptAsset(assetNames, groupIndex, ext);
2519
+ return hashed || declaredPath;
2520
+ }
2521
+ function findHashedContentScriptAsset(assetNames, groupIndex, ext) {
2522
+ const plain = `content_scripts/content-${groupIndex}.${ext}`;
2523
+ if (assetNames.has(plain)) return plain;
2524
+ const re = new RegExp(`^content_scripts/content-${groupIndex}\\.[a-f0-9]+\\.${ext}$`, 'i');
2525
+ for (const name of assetNames)if (re.test(name)) return name;
2526
+ }
2527
+ function purgeStaleHashedContentScripts(compilation, currentNames) {
2528
+ const outputPath = compilation.options.output?.path;
2529
+ if (!outputPath) return;
2530
+ const csDir = external_path_.join(outputPath, "content_scripts");
2531
+ if (!external_fs_.existsSync(csDir)) return;
2532
+ const hashedRe = /^content-\d+\.[a-f0-9]+\.(js|css)(\.map)?$/i;
2533
+ try {
2534
+ for (const name of external_fs_.readdirSync(csDir)){
2535
+ if (!hashedRe.test(name)) continue;
2536
+ const rel = `content_scripts/${name}`;
2537
+ if (!currentNames.has(rel)) {
2538
+ if (!currentNames.has(rel.replace(/\.map$/, ''))) try {
2539
+ external_fs_.unlinkSync(external_path_.join(csDir, name));
2540
+ } catch {}
2541
+ }
2542
+ }
2543
+ } catch {}
2544
+ }
2350
2545
  function update_manifest_define_property(obj, key, value) {
2351
2546
  if (key in obj) Object.defineProperty(obj, key, {
2352
2547
  value: value,
@@ -2375,8 +2570,9 @@ exports.modules = {
2375
2570
  }, ()=>{
2376
2571
  if (compilation.errors.length > 0) return;
2377
2572
  const manifest = getManifestContent(compilation, this.manifestPath);
2378
- const patchedManifest = buildCanonicalManifest(this.manifestPath, manifest, this.browser);
2573
+ let patchedManifest = buildCanonicalManifest(this.manifestPath, manifest, this.browser);
2379
2574
  const overrides = getManifestOverrides(this.manifestPath, manifest);
2575
+ if ('development' === compiler.options.mode) patchedManifest = patchDevContentScriptManifestPaths(compilation, patchedManifest);
2380
2576
  if ('development' === compiler.options.mode) {
2381
2577
  if (patchedManifest.content_scripts) patchedManifest.content_scripts = this.applyDevOverrides(patchedManifest);
2382
2578
  }
@@ -2665,6 +2861,11 @@ exports.modules = {
2665
2861
  function isCanonicalContentScriptCss(resource) {
2666
2862
  return /^content_scripts\/content-\d+\.css$/.test(resource);
2667
2863
  }
2864
+ function toCanonicalContentScriptCss(jsFile) {
2865
+ const normalized = String(jsFile || '');
2866
+ if (!/^content_scripts\/content-\d+\.js$/.test(normalized)) return;
2867
+ return normalized.replace(/\.js$/, '.css');
2868
+ }
2668
2869
  function generateManifestPatches(compilation, manifestPath, entryImports, browser) {
2669
2870
  const canonicalManifest = getManifestContent(compilation, manifestPath);
2670
2871
  const resolved = resolveUserDeclaredWAR(compilation, manifestPath, canonicalManifest, browser);
@@ -2817,9 +3018,17 @@ exports.modules = {
2817
3018
  for (const r of fontAssets)if (!webAccessibleResourcesV2.includes(r)) webAccessibleResourcesV2.push(r);
2818
3019
  }
2819
3020
  }
3021
+ const assetKeys = Object.keys(compilation.assets || {});
3022
+ const cssUnderContentScripts = assetKeys.filter((k)=>k.startsWith("content_scripts/")).filter((k)=>k.endsWith('.css')).sort();
3023
+ if (Array.isArray(canonicalManifest.content_scripts)) for (const contentScript of canonicalManifest.content_scripts){
3024
+ const jsFiles = Array.isArray(contentScript.js) ? contentScript.js : [];
3025
+ const canonicalCss = jsFiles.map(toCanonicalContentScriptCss).filter((resource)=>Boolean(resource && cssUnderContentScripts.includes(resource)));
3026
+ if (canonicalCss.length > 0) contentScript.css = Array.from(new Set([
3027
+ ...contentScript.css || [],
3028
+ ...canonicalCss
3029
+ ])).sort();
3030
+ }
2820
3031
  if (3 === canonicalManifest.manifest_version) {
2821
- const assetKeys = Object.keys(compilation.assets || {});
2822
- const cssUnderContentScripts = assetKeys.filter((k)=>k.startsWith("content_scripts/")).filter((k)=>k.endsWith('.css')).sort();
2823
3032
  if (cssUnderContentScripts.length > 0) {
2824
3033
  const allMatches = Array.from(new Set((canonicalManifest.content_scripts || []).flatMap((cs)=>cs.matches || [])));
2825
3034
  const normalizedMatches = cleanMatches(allMatches);
@@ -2847,6 +3056,8 @@ exports.modules = {
2847
3056
  });
2848
3057
  }
2849
3058
  }
3059
+ } else if (2 === canonicalManifest.manifest_version) {
3060
+ for (const resource of cssUnderContentScripts)if (!webAccessibleResourcesV2.includes(resource)) webAccessibleResourcesV2.push(resource);
2850
3061
  }
2851
3062
  if (3 === canonicalManifest.manifest_version) {
2852
3063
  if (webAccessibleResourcesV3.length > 0) canonicalManifest.web_accessible_resources = webAccessibleResourcesV3.map((entry)=>({
@@ -3123,6 +3334,7 @@ exports.modules = {
3123
3334
  permissions: [
3124
3335
  ...new Set([
3125
3336
  "scripting",
3337
+ 'tabs',
3126
3338
  'management',
3127
3339
  ...canonicalManifest.permissions || []
3128
3340
  ])
@@ -3130,6 +3342,7 @@ exports.modules = {
3130
3342
  } : {
3131
3343
  permissions: [
3132
3344
  "scripting",
3345
+ 'tabs',
3133
3346
  'management'
3134
3347
  ]
3135
3348
  } : {},
@@ -4227,6 +4440,51 @@ exports.modules = {
4227
4440
  this.browser = options.browser;
4228
4441
  }
4229
4442
  }
4443
+ function normalizeBoolean(value, fallback) {
4444
+ return String('boolean' == typeof value ? value : fallback);
4445
+ }
4446
+ function normalizeHotValue(value) {
4447
+ if ('only' === value) return 'only';
4448
+ if ('boolean' == typeof value) return String(value);
4449
+ return 'true';
4450
+ }
4451
+ function getDevServerHmrImports(compiler) {
4452
+ const devServer = compiler.options?.devServer;
4453
+ const envHost = process.env.EXTENSION_DEV_SERVER_HOST;
4454
+ const envPort = process.env.EXTENSION_DEV_SERVER_PORT;
4455
+ const envPath = process.env.EXTENSION_DEV_SERVER_PATH;
4456
+ const envProtocol = process.env.EXTENSION_DEV_SERVER_PROTOCOL;
4457
+ if (!devServer && !envHost && !envPort) return [];
4458
+ const clientConfig = devServer?.client && 'object' == typeof devServer.client ? devServer.client : {};
4459
+ const webSocketURL = clientConfig.webSocketURL && 'object' == typeof clientConfig.webSocketURL ? clientConfig.webSocketURL : {};
4460
+ const protocol = String(webSocketURL.protocol || envProtocol || 'ws');
4461
+ const hostname = String(webSocketURL.hostname || devServer?.host || envHost || '127.0.0.1');
4462
+ const port = webSocketURL.port ?? devServer?.port ?? envPort ?? process.env.EXTENSION_PUBLIC_PORT ?? 8080;
4463
+ const pathname = String(webSocketURL.pathname || envPath || '/ws');
4464
+ const logging = String(clientConfig.logging || 'none');
4465
+ const progress = normalizeBoolean(clientConfig.progress, false);
4466
+ const overlay = normalizeBoolean(clientConfig.overlay, false);
4467
+ const reconnect = String(clientConfig.reconnect ?? 10);
4468
+ const hot = normalizeHotValue(devServer?.hot ?? 'only');
4469
+ const liveReload = normalizeBoolean(devServer?.liveReload, true);
4470
+ const query = new URLSearchParams({
4471
+ protocol,
4472
+ hostname,
4473
+ port: String(port),
4474
+ pathname,
4475
+ logging,
4476
+ progress,
4477
+ overlay,
4478
+ reconnect,
4479
+ hot,
4480
+ 'live-reload': liveReload
4481
+ });
4482
+ return [
4483
+ `@rspack/dev-server/client/index.js?${query.toString()}`,
4484
+ 'webpack/hot/dev-server'
4485
+ ];
4486
+ }
4487
+ var develop_context = __webpack_require__("./webpack/webpack-lib/develop-context.ts");
4230
4488
  function add_scripts_and_styles_to_compilation_define_property(obj, key, value) {
4231
4489
  if (key in obj) Object.defineProperty(obj, key, {
4232
4490
  value: value,
@@ -4244,6 +4502,7 @@ exports.modules = {
4244
4502
  const projectRoot = compiler.options.context || manifestDir;
4245
4503
  const publicDir = external_path_.join(projectRoot, 'public');
4246
4504
  const hasPublicDir = external_fs_.existsSync(publicDir);
4505
+ const devServerHmrImports = 'development' === compiler.options.mode ? getDevServerHmrImports(compiler) : [];
4247
4506
  for (const field of Object.entries(htmlEntries)){
4248
4507
  const [feature, resource] = field;
4249
4508
  if (resource) {
@@ -4258,7 +4517,8 @@ exports.modules = {
4258
4517
  ...cssAssets
4259
4518
  ];
4260
4519
  if ('development' === compiler.options.mode) {
4261
- const hmrScript = external_path_.resolve(__dirname, "minimum-script-file");
4520
+ if (devServerHmrImports.length > 0) fileAssets.unshift(...devServerHmrImports);
4521
+ const hmrScript = (0, develop_context.G)("minimum-script-file");
4262
4522
  fileAssets.push(hmrScript);
4263
4523
  }
4264
4524
  if (external_fs_.existsSync(resource)) compiler.options.entry = {
@@ -4675,24 +4935,40 @@ exports.modules = {
4675
4935
  includeList,
4676
4936
  browser: this.browser
4677
4937
  }).apply(compiler);
4678
- if ('production' !== (compiler.options.mode || 'development')) compiler.options.module.rules.push({
4679
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4680
- include: [
4681
- external_path_.dirname(this.manifestPath)
4682
- ],
4683
- exclude: [
4684
- /([\\/])node_modules\1/
4685
- ],
4686
- use: [
4687
- {
4688
- loader: external_path_.resolve(__dirname, "ensure-hmr-for-scripts"),
4689
- options: {
4690
- manifestPath: this.manifestPath,
4691
- includeList
4692
- }
4938
+ if ('production' !== (compiler.options.mode || 'development')) {
4939
+ const contentScriptEntryPaths = new Set();
4940
+ try {
4941
+ const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf-8'));
4942
+ const manifestDir = external_path_.dirname(this.manifestPath);
4943
+ const contentScripts = Array.isArray(manifest?.content_scripts) ? manifest.content_scripts : [];
4944
+ for (const contentScript of contentScripts){
4945
+ const jsList = Array.isArray(contentScript?.js) ? contentScript.js : [];
4946
+ for (const jsFile of jsList)contentScriptEntryPaths.add(external_path_.normalize(external_path_.resolve(manifestDir, jsFile)));
4693
4947
  }
4694
- ]
4695
- });
4948
+ } catch {}
4949
+ compiler.options.module.rules.push({
4950
+ test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4951
+ include: [
4952
+ external_path_.dirname(this.manifestPath)
4953
+ ],
4954
+ issuerLayer: {
4955
+ not: contracts.$t
4956
+ },
4957
+ exclude: [
4958
+ /([\\/])node_modules\1/,
4959
+ (resourcePath)=>contentScriptEntryPaths.has(external_path_.normalize(resourcePath))
4960
+ ],
4961
+ use: [
4962
+ {
4963
+ loader: (0, develop_context.G)("ensure-hmr-for-scripts"),
4964
+ options: {
4965
+ manifestPath: this.manifestPath,
4966
+ includeList
4967
+ }
4968
+ }
4969
+ ]
4970
+ });
4971
+ }
4696
4972
  new AddToFileDependencies({
4697
4973
  manifestPath: this.manifestPath,
4698
4974
  includeList,
@@ -4756,6 +5032,29 @@ exports.modules = {
4756
5032
  });
4757
5033
  return fileAssets;
4758
5034
  }
5035
+ function findUpLocalSync(filename, options) {
5036
+ const root = external_path_.parse(options.cwd).root;
5037
+ let currentDir = options.cwd;
5038
+ while(true){
5039
+ const candidate = external_path_.join(currentDir, filename);
5040
+ try {
5041
+ const stat = external_fs_.statSync(candidate);
5042
+ if (stat.isFile()) return candidate;
5043
+ } catch {}
5044
+ if (currentDir === root) return;
5045
+ currentDir = external_path_.dirname(currentDir);
5046
+ }
5047
+ }
5048
+ function findNearestPackageJsonSync(manifestPath) {
5049
+ try {
5050
+ const manifestDir = external_path_.dirname(manifestPath);
5051
+ return findUpLocalSync('package.json', {
5052
+ cwd: manifestDir
5053
+ }) || null;
5054
+ } catch {
5055
+ return null;
5056
+ }
5057
+ }
4759
5058
  function findPackageRoot(startDir) {
4760
5059
  let current = startDir;
4761
5060
  for(let i = 0; i < 15; i++){
@@ -4799,12 +5098,11 @@ exports.modules = {
4799
5098
  const cs = contentScripts[i];
4800
5099
  if (cs?.world !== 'MAIN') continue;
4801
5100
  const bridgeIndex = originalCount + bridgeOrdinal++;
4802
- bridgeScripts[`content_scripts/content-${bridgeIndex}`] = bridgeSource;
5101
+ bridgeScripts[(0, contracts.Y0)(bridgeIndex)] = bridgeSource;
4803
5102
  }
4804
5103
  } catch {}
4805
5104
  return bridgeScripts;
4806
5105
  }
4807
- var package_json = __webpack_require__("./webpack/webpack-lib/package-json.ts");
4808
5106
  function add_content_script_wrapper_define_property(obj, key, value) {
4809
5107
  if (key in obj) Object.defineProperty(obj, key, {
4810
5108
  value: value,
@@ -4819,20 +5117,12 @@ exports.modules = {
4819
5117
  static getBridgeScripts(manifestPath) {
4820
5118
  return getMainWorldBridgeScripts(manifestPath);
4821
5119
  }
4822
- resolveLoader(name) {
4823
- const base = external_path_.resolve(__dirname, name);
4824
- const candidates = [
4825
- `${base}.cjs`,
4826
- `${base}.js`,
4827
- `${base}.mjs`,
4828
- base
4829
- ];
4830
- for (const candidate of candidates)if (external_fs_.existsSync(candidate)) return candidate;
4831
- return base;
5120
+ resolveLoader() {
5121
+ return (0, develop_context.G)("feature-scripts-content-script-wrapper");
4832
5122
  }
4833
5123
  apply(compiler) {
4834
5124
  const manifestDir = external_path_.dirname(this.manifestPath);
4835
- const packageJsonPath = (0, package_json.Pb)(this.manifestPath);
5125
+ const packageJsonPath = findNearestPackageJsonSync(this.manifestPath);
4836
5126
  const packageJsonDir = packageJsonPath ? external_path_.dirname(packageJsonPath) : manifestDir;
4837
5127
  const includeDirs = packageJsonDir === manifestDir ? [
4838
5128
  manifestDir
@@ -4848,7 +5138,7 @@ exports.modules = {
4848
5138
  ],
4849
5139
  use: [
4850
5140
  {
4851
- loader: this.resolveLoader("content-script-wrapper"),
5141
+ loader: this.resolveLoader(),
4852
5142
  options: {
4853
5143
  manifestPath: this.manifestPath,
4854
5144
  mode: compiler.options.mode
@@ -4856,41 +5146,6 @@ exports.modules = {
4856
5146
  }
4857
5147
  ]
4858
5148
  });
4859
- if ('production' !== compiler.options.mode) {
4860
- compiler.options.module.rules.push({
4861
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4862
- include: includeDirs,
4863
- exclude: [
4864
- /([\\/])node_modules\1/
4865
- ],
4866
- use: [
4867
- {
4868
- loader: this.resolveLoader('warn-no-default-export'),
4869
- options: {
4870
- manifestPath: this.manifestPath,
4871
- mode: compiler.options.mode
4872
- }
4873
- }
4874
- ],
4875
- enforce: 'pre'
4876
- });
4877
- compiler.options.module.rules.push({
4878
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4879
- include: includeDirs,
4880
- exclude: [
4881
- /([\\/])node_modules\1/
4882
- ],
4883
- use: [
4884
- {
4885
- loader: this.resolveLoader('add-hmr-accept-code'),
4886
- options: {
4887
- manifestPath: this.manifestPath,
4888
- mode: compiler.options.mode
4889
- }
4890
- }
4891
- ]
4892
- });
4893
- }
4894
5149
  }
4895
5150
  constructor(options){
4896
5151
  add_content_script_wrapper_define_property(this, "manifestPath", void 0);
@@ -4899,17 +5154,6 @@ exports.modules = {
4899
5154
  this.browser = options.browser || 'chrome';
4900
5155
  }
4901
5156
  }
4902
- function scriptsEntriesSummary(entriesAdded, publicTracked) {
4903
- return `Scripts entries — added=${external_pintor_default().gray(String(entriesAdded))}, publicTracked=${external_pintor_default().gray(String(publicTracked))}`;
4904
- }
4905
- function scriptsManifestChangeDetected(before, after) {
4906
- const parts = [
4907
- "Manifest scripts change detected",
4908
- before ? `${external_pintor_default().gray('before')} ${external_pintor_default().underline(before)}` : '',
4909
- after ? `${external_pintor_default().gray('after')} ${external_pintor_default().underline(after)}` : ''
4910
- ].filter(Boolean);
4911
- return parts.join(' — ');
4912
- }
4913
5157
  function add_scripts_define_property(obj, key, value) {
4914
5158
  if (key in obj) Object.defineProperty(obj, key, {
4915
5159
  value: value,
@@ -4921,14 +5165,22 @@ exports.modules = {
4921
5165
  return obj;
4922
5166
  }
4923
5167
  const add_scripts_isRemoteUrl = (entry)=>/^([a-z][a-z0-9+.-]*:)?\/\//i.test(entry);
5168
+ const isContentScriptFeature = (feature)=>feature.startsWith("content_scripts/");
5169
+ const isScriptsFolderFeature = (feature)=>feature.startsWith("scripts/");
5170
+ function createSequentialEntryModule(feature, entryImports) {
5171
+ const source = [
5172
+ `/* extension.js sequential entry: ${feature} */`,
5173
+ ...entryImports.map((entryImport)=>`import ${JSON.stringify(String(entryImport))};`)
5174
+ ].join('\n');
5175
+ return `data:text/javascript;charset=utf-8,${encodeURIComponent(source)}`;
5176
+ }
4924
5177
  class AddScripts {
4925
5178
  apply(compiler) {
4926
5179
  const bridgeScripts = AddContentScriptWrapper.getBridgeScripts(this.manifestPath);
4927
- const mergedIncludeList = {
5180
+ const scriptFields = {
4928
5181
  ...this.includeList,
4929
5182
  ...bridgeScripts
4930
5183
  };
4931
- const scriptFields = mergedIncludeList;
4932
5184
  if (compiler?.hooks?.thisCompilation?.tap) compiler.hooks.thisCompilation.tap("scripts:validate-include-list", (compilation)=>{
4933
5185
  try {
4934
5186
  const manifestDir = external_path_.dirname(this.manifestPath);
@@ -4939,20 +5191,19 @@ exports.modules = {
4939
5191
  raw
4940
5192
  ] : [];
4941
5193
  for (const entry of rawEntries){
4942
- if (!entry || 'string' != typeof entry) continue;
4943
- if (add_scripts_isRemoteUrl(entry)) continue;
5194
+ if (!entry || 'string' != typeof entry || add_scripts_isRemoteUrl(entry)) continue;
4944
5195
  let resolved = entry;
4945
5196
  if (!external_fs_.existsSync(resolved)) resolved = external_path_.isAbsolute(entry) ? entry : entry.startsWith('/') ? external_path_.join(manifestDir, entry.slice(1)) : external_path_.join(manifestDir, entry);
4946
5197
  if (external_fs_.existsSync(resolved)) continue;
4947
5198
  const isPublicRoot = entry.startsWith('/') && !external_path_.isAbsolute(entry);
4948
5199
  const displayPath = isPublicRoot ? outputRoot ? external_path_.join(outputRoot, entry.slice(1)) : entry : resolved;
4949
- const lines = [];
4950
- lines.push(`Check the ${feature.replace('/', '.')} field in your manifest.json file.`);
4951
- lines.push("The script path must point to an existing file that will be bundled.");
4952
- if (isPublicRoot) lines.push("Paths starting with '/' are resolved from the extension output root (served from public/), not your source directory.");
4953
- lines.push('');
4954
- lines.push(`NOT FOUND ${displayPath}`);
4955
- const err = new ErrorCtor(lines.join('\n'));
5200
+ const err = new ErrorCtor([
5201
+ `Check the ${feature.replace('/', '.')} field in your manifest.json file.`,
5202
+ "The script path must point to an existing file that will be bundled.",
5203
+ isPublicRoot ? "Paths starting with '/' are resolved from the extension output root (served from public/), not your source directory." : '',
5204
+ '',
5205
+ `NOT FOUND ${displayPath}`
5206
+ ].filter(Boolean).join('\n'));
4956
5207
  err.file = 'manifest.json';
4957
5208
  err.name = 'ScriptsMissingFile';
4958
5209
  (compilation.errors ||= []).push(err);
@@ -4963,15 +5214,18 @@ exports.modules = {
4963
5214
  const newEntries = {};
4964
5215
  const manifestDir = external_path_.dirname(this.manifestPath);
4965
5216
  const projectPath = compiler.options.context || manifestDir;
5217
+ let manifestJson = {};
5218
+ try {
5219
+ manifestJson = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf8'));
5220
+ } catch {
5221
+ manifestJson = {};
5222
+ }
4966
5223
  const resolveEntryPath = (entry)=>{
4967
- if (!entry) return entry;
4968
- if (add_scripts_isRemoteUrl(entry)) return entry;
5224
+ if (!entry || add_scripts_isRemoteUrl(entry)) return entry;
4969
5225
  if (entry.startsWith('/') && !external_path_.isAbsolute(entry)) return external_path_.join(projectPath, entry.slice(1));
4970
5226
  if (external_path_.isAbsolute(entry)) return entry;
4971
5227
  return external_path_.join(manifestDir, entry);
4972
5228
  };
4973
- let entriesAdded = 0;
4974
- let publicTracked = 0;
4975
5229
  for (const [feature, scriptPath] of Object.entries(scriptFields)){
4976
5230
  const rawEntries = Array.isArray(scriptPath) ? scriptPath || [] : scriptPath ? [
4977
5231
  scriptPath
@@ -4979,32 +5233,32 @@ exports.modules = {
4979
5233
  const resolvedEntries = rawEntries.map(resolveEntryPath);
4980
5234
  const scriptImports = getScriptEntries(resolvedEntries);
4981
5235
  const cssImports = getCssEntries(resolvedEntries);
4982
- const allImports = [
4983
- ...scriptImports,
4984
- ...cssImports
5236
+ const entryImports = [
5237
+ ...new Set([
5238
+ ...scriptImports,
5239
+ ...cssImports
5240
+ ])
4985
5241
  ];
4986
- const entryImports = allImports;
4987
- if (cssImports.length || scriptImports.length) {
4988
- if ('background/service_worker' === feature) {
4989
- const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf8'));
4990
- const isModuleServiceWorker = manifest.background?.type === 'module';
4991
- newEntries[feature] = {
4992
- import: entryImports,
4993
- ...isModuleServiceWorker ? {} : {
4994
- chunkLoading: "import-scripts"
4995
- }
4996
- };
4997
- } else newEntries[feature] = {
4998
- import: entryImports
4999
- };
5000
- entriesAdded++;
5001
- }
5242
+ const shouldUseSequentialEntryModule = isContentScriptFeature(feature) && scriptImports.length > 1;
5243
+ const finalEntryImports = shouldUseSequentialEntryModule ? [
5244
+ createSequentialEntryModule(feature, entryImports)
5245
+ ] : entryImports;
5246
+ if (finalEntryImports.length) newEntries[feature] = 'background/service_worker' === feature ? {
5247
+ import: finalEntryImports,
5248
+ ...manifestJson.background?.type === 'module' ? {} : {
5249
+ chunkLoading: "import-scripts"
5250
+ }
5251
+ } : {
5252
+ import: finalEntryImports,
5253
+ ...isContentScriptFeature(feature) || isScriptsFolderFeature(feature) ? {
5254
+ layer: contracts.$t
5255
+ } : {}
5256
+ };
5002
5257
  }
5003
5258
  compiler.options.entry = {
5004
5259
  ...compiler.options.entry,
5005
5260
  ...newEntries
5006
5261
  };
5007
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(scriptsEntriesSummary(entriesAdded, publicTracked));
5008
5262
  }
5009
5263
  constructor(options){
5010
5264
  add_scripts_define_property(this, "manifestPath", void 0);
@@ -5013,45 +5267,6 @@ exports.modules = {
5013
5267
  this.includeList = options.includeList || {};
5014
5268
  }
5015
5269
  }
5016
- const basic = [
5017
- 'var isBrowser = !!(() => { try { return browser.runtime.getURL("/") } catch(e) {} })()',
5018
- 'var isChrome = !!(() => { try { return chrome.runtime.getURL("/") } catch(e) {} })()'
5019
- ];
5020
- const weakRuntimeCheck = [
5021
- ...basic,
5022
- "var runtime = isBrowser ? browser : isChrome ? chrome : { runtime: { getURL: x => x } }"
5023
- ];
5024
- class AddPublicPathRuntimeModule {
5025
- apply(compiler) {
5026
- const { RuntimeGlobals } = compiler.webpack;
5027
- compiler.hooks.compilation.tap('PublicPathRuntimeModule', (compilation)=>{
5028
- compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(AddPublicPathRuntimeModule.name, (chunk)=>{
5029
- const module = add_public_path_runtime_module_PublicPathRuntimeModule(compiler);
5030
- compilation.addRuntimeModule(chunk, module);
5031
- return true;
5032
- });
5033
- });
5034
- }
5035
- }
5036
- function add_public_path_runtime_module_PublicPathRuntimeModule(compiler) {
5037
- const { Template, RuntimeModule, RuntimeGlobals } = compiler.webpack;
5038
- class PublicPathRuntimeModule extends RuntimeModule {
5039
- generate() {
5040
- const publicPath = this.compilation?.outputOptions.publicPath;
5041
- return Template.asString([
5042
- ...weakRuntimeCheck,
5043
- `var path = ${JSON.stringify(this.compilation?.getPath(publicPath || '', {
5044
- hash: this.compilation.hash || 'XXXX'
5045
- }))}`,
5046
- `${RuntimeGlobals.publicPath} = typeof importScripts === 'function' || !(isBrowser || isChrome) ? path : runtime.runtime.getURL(path);`
5047
- ]);
5048
- }
5049
- constructor(){
5050
- super('publicPath', RuntimeModule.STAGE_BASIC);
5051
- }
5052
- }
5053
- return new PublicPathRuntimeModule();
5054
- }
5055
5270
  function TemplateFn(compilation, Template) {
5056
5271
  return {
5057
5272
  f: (args, body)=>{
@@ -5080,9 +5295,9 @@ exports.modules = {
5080
5295
  `${_let} isChrome, runtime;`,
5081
5296
  'try {',
5082
5297
  Template.indent([
5083
- `if (typeof browser !== "undefined" && ${optionalChaining ? 'typeof browser.runtime?.getURL === "function"' : 'typeof browser.runtime === "object" && typeof browser.runtime.getURL === "function"'}) {`,
5298
+ `if (typeof globalThis === "object" && globalThis && typeof globalThis.browser !== "undefined" && ${optionalChaining ? 'typeof globalThis.browser.runtime?.getURL === "function"' : 'typeof globalThis.browser.runtime === "object" && typeof globalThis.browser.runtime.getURL === "function"'}) {`,
5084
5299
  Template.indent([
5085
- 'runtime = browser;'
5300
+ 'runtime = globalThis.browser;'
5086
5301
  ]),
5087
5302
  '}'
5088
5303
  ]),
@@ -5091,10 +5306,10 @@ exports.modules = {
5091
5306
  Template.indent([
5092
5307
  'try {',
5093
5308
  Template.indent([
5094
- `if (typeof chrome !== "undefined" && ${optionalChaining ? 'typeof chrome.runtime?.getURL === "function"' : 'typeof chrome.runtime === "object" && typeof chrome.runtime.getURL === "function"'}) {`,
5309
+ `if (typeof globalThis === "object" && globalThis && typeof globalThis.chrome !== "undefined" && ${optionalChaining ? 'typeof globalThis.chrome.runtime?.getURL === "function"' : 'typeof globalThis.chrome.runtime === "object" && typeof globalThis.chrome.runtime.getURL === "function"'}) {`,
5095
5310
  Template.indent([
5096
5311
  'isChrome = true;',
5097
- 'runtime = chrome;'
5312
+ 'runtime = globalThis.chrome;'
5098
5313
  ]),
5099
5314
  '}'
5100
5315
  ]),
@@ -5145,7 +5360,7 @@ exports.modules = {
5145
5360
  const bundleId = chunkName ? `${chunkName}.js` : '';
5146
5361
  const world = bundleId && this.contentScriptsMeta[bundleId] ? this.contentScriptsMeta[bundleId].world : void 0;
5147
5362
  const isMainWorld = 'main' === world;
5148
- const HasExtensionRuntime = `${_const} hasExtensionRuntime = (function(){ try {return ((typeof browser === "object" && browser && browser.runtime && typeof browser.runtime.sendMessage === "function") || (typeof chrome === "object" && chrome && chrome.runtime && typeof chrome.runtime.sendMessage === "function"));} catch (e) { return false; } })();`;
5363
+ const HasExtensionRuntime = `${_const} hasExtensionRuntime = (function(){ try {return ((typeof globalThis === "object" && globalThis && globalThis.browser && globalThis.browser.runtime && typeof globalThis.browser.runtime.sendMessage === "function") || (typeof globalThis === "object" && globalThis && globalThis.chrome && globalThis.chrome.runtime && typeof globalThis.chrome.runtime.sendMessage === "function"));} catch (e) { return false; } })();`;
5149
5364
  const DynamicImportLoader = `${_const} ${DYNAMIC_IMPORT_LOADER} = ` + f('url, done, key, chunkId', `import(url).then(${f('', [
5150
5365
  'if (isNotIframe) return done();',
5151
5366
  'try {',
@@ -5196,6 +5411,7 @@ exports.modules = {
5196
5411
  const ClassicLoader = `${_const} ${CLASSIC_LOADER} = ` + f('url, done', Template.asString([
5197
5412
  `${_const} msg = { type: "WTW_INJECT", file: url };`,
5198
5413
  `${_const} onError = ${f('e', 'done(Object.assign(e, { type: "missing" }))')};`,
5414
+ 'try {',
5199
5415
  `if (${RuntimeGlobalIsBrowser}) {`,
5200
5416
  Template.indent([
5201
5417
  `${RuntimeGlobal}.runtime.sendMessage(msg).then(done, onError);`
@@ -5208,7 +5424,8 @@ exports.modules = {
5208
5424
  'else done();'
5209
5425
  ])});`
5210
5426
  ]),
5211
- '}'
5427
+ '}',
5428
+ '} catch (e) { onError(e); }'
5212
5429
  ])) + ';';
5213
5430
  const ClassicLoaderDisabled = `${_const} ${CLASSIC_LOADER} = ` + f('', [
5214
5431
  "throw new Error(\"[webpack-target-webextension] Failed to load async chunk in the content script. No script loader is found. You can either\\n - Set output.environment.dynamicImport to true if your environment supports native ES Module\\n - Specify the background entry to enable the fallback loader\\n - Set module.parser.javascript.dynamicImportMode to 'eager' to inline all async chunks.\");"
@@ -5310,9 +5527,15 @@ exports.modules = {
5310
5527
  'try { __extjsBase = document.documentElement.getAttribute("data-extjs-extension-base") || ""; } catch(_) { __extjsBase = ""; }'
5311
5528
  ]),
5312
5529
  "}",
5530
+ 'var __extjsRuntimePath = "";',
5313
5531
  `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && typeof ${RuntimeGlobal}.runtime.getURL === "function") {`,
5314
5532
  Template.indent([
5315
- `${RuntimeGlobals.publicPath} = ${RuntimeGlobal}.runtime.getURL(${path});`
5533
+ `try { __extjsRuntimePath = ${RuntimeGlobal}.runtime.getURL(${path}); } catch (_) { __extjsRuntimePath = ""; }`
5534
+ ]),
5535
+ "}",
5536
+ "if (__extjsRuntimePath) {",
5537
+ Template.indent([
5538
+ `${RuntimeGlobals.publicPath} = __extjsRuntimePath;`
5316
5539
  ]),
5317
5540
  "} else if (__extjsBase) {",
5318
5541
  Template.indent([
@@ -5403,8 +5626,10 @@ exports.modules = {
5403
5626
  "}",
5404
5627
  "if (!scriptUrl) {",
5405
5628
  Template.indent([
5629
+ 'var __extjsRuntimeRoot = "";',
5406
5630
  `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && typeof ${RuntimeGlobal}.runtime.getURL === "function") {`,
5407
- Template.indent(`scriptUrl = ${RuntimeGlobal}.runtime.getURL("/");`),
5631
+ Template.indent(`try { __extjsRuntimeRoot = ${RuntimeGlobal}.runtime.getURL("/"); } catch (_) { __extjsRuntimeRoot = ""; }`),
5632
+ Template.indent("scriptUrl = __extjsRuntimeRoot || scriptUrl;"),
5408
5633
  "} else {",
5409
5634
  Template.indent('scriptUrl = __extjsBase || "";'),
5410
5635
  "}"
@@ -5462,6 +5687,52 @@ exports.modules = {
5462
5687
  else if ('.' !== part) depth++;
5463
5688
  return depth > 0 ? `${'../'.repeat(depth)}${append}` : enforceRelative ? `./${append}` : append;
5464
5689
  }
5690
+ function BaseUriRuntimeModule(webpack) {
5691
+ const { RuntimeGlobals, RuntimeModule, Template } = webpack;
5692
+ class BaseUriRuntime extends RuntimeModule {
5693
+ generate() {
5694
+ return Template.asString([
5695
+ 'var __extjsBase = "";',
5696
+ "try {",
5697
+ Template.indent([
5698
+ `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && typeof ${RuntimeGlobal}.runtime.getURL === "function") {`,
5699
+ Template.indent([
5700
+ `__extjsBase = String(${RuntimeGlobal}.runtime.getURL("/"));`
5701
+ ]),
5702
+ "}"
5703
+ ]),
5704
+ "} catch (_) {}",
5705
+ 'if (!__extjsBase && typeof globalThis === "object" && globalThis && globalThis.__EXTJS_EXTENSION_BASE__) {',
5706
+ Template.indent([
5707
+ '__extjsBase = String(globalThis.__EXTJS_EXTENSION_BASE__ || "");'
5708
+ ]),
5709
+ "}",
5710
+ 'if (!__extjsBase && typeof document === "object" && document && document.documentElement) {',
5711
+ Template.indent([
5712
+ 'try { __extjsBase = String(document.documentElement.getAttribute("data-extjs-extension-base") || ""); } catch (_) { __extjsBase = ""; }'
5713
+ ]),
5714
+ "}",
5715
+ "if (__extjsBase) {",
5716
+ Template.indent([
5717
+ `${RuntimeGlobals.baseURI} = __extjsBase;`
5718
+ ]),
5719
+ '} else if (typeof document !== "undefined" && document.baseURI) {',
5720
+ Template.indent([
5721
+ `${RuntimeGlobals.baseURI} = document.baseURI;`
5722
+ ]),
5723
+ "} else {",
5724
+ Template.indent([
5725
+ `${RuntimeGlobals.baseURI} = self.location.href;`
5726
+ ]),
5727
+ "}"
5728
+ ]);
5729
+ }
5730
+ constructor(){
5731
+ super('baseURI', RuntimeModule.STAGE_BASIC);
5732
+ }
5733
+ }
5734
+ return new BaseUriRuntime();
5735
+ }
5465
5736
  function ChunkLoaderFallbackRuntimeModule(webpack) {
5466
5737
  const { RuntimeModule, Template } = webpack;
5467
5738
  class ChunkLoaderFallbackRuntime extends RuntimeModule {
@@ -5472,7 +5743,7 @@ exports.modules = {
5472
5743
  const optionalChain = compilation.outputOptions.environment.optionalChaining;
5473
5744
  const _const = compilation.outputOptions.environment.const ? 'const' : 'var';
5474
5745
  const _let = compilation.outputOptions.environment.const ? 'let' : 'var';
5475
- return `${RuntimeGlobal}.runtime.onMessage.addListener(` + f('message, sender, sendResponse', [
5746
+ return `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && ${RuntimeGlobal}.runtime.onMessage) {${RuntimeGlobal}.runtime.onMessage.addListener(` + f('message, sender, sendResponse', [
5476
5747
  optionalChain ? 'if (message?.type != "WTW_INJECT" || typeof sender?.tab?.id != "number") return;' : 'if (!message || message.type != "WTW_INJECT" || !sender || !sender.tab || sender.tab.id == null) return;',
5477
5748
  `${_let} file = message.file;`,
5478
5749
  'try {',
@@ -5501,7 +5772,7 @@ exports.modules = {
5501
5772
  ]),
5502
5773
  '}',
5503
5774
  'return true;'
5504
- ]) + ');';
5775
+ ]) + ");}";
5505
5776
  }
5506
5777
  constructor(){
5507
5778
  super('chunk loader fallback', RuntimeModule.STAGE_TRIGGER);
@@ -5540,6 +5811,11 @@ exports.modules = {
5540
5811
  compilation.addRuntimeModule(_chunk, LoadScriptRuntimeModule(compiler.webpack, false !== compilation.outputOptions.environment.dynamicImport, false !== options.classicLoader, this.contentScriptsMeta));
5541
5812
  return true;
5542
5813
  });
5814
+ compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.baseURI).tap(WebExtensionChuckLoaderRuntimePlugin.name, (chunk, set)=>{
5815
+ set.add(RuntimeGlobal);
5816
+ compilation.addRuntimeModule(chunk, BaseUriRuntimeModule(compiler.webpack));
5817
+ return true;
5818
+ });
5543
5819
  compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(WebExtensionChuckLoaderRuntimePlugin.name, (chunk, set)=>{
5544
5820
  const { outputOptions } = compilation;
5545
5821
  const { publicPath, scriptType } = outputOptions;
@@ -5781,7 +6057,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
5781
6057
  } else code = [
5782
6058
  ';(() => {',
5783
6059
  Template.indent([
5784
- 'const getURL = typeof browser === "object" ? browser.runtime.getURL : chrome.runtime.getURL;',
6060
+ 'const getURL = typeof globalThis === "object" && globalThis && typeof globalThis.browser === "object" ? globalThis.browser.runtime.getURL : globalThis.chrome.runtime.getURL;',
5785
6061
  `${JSON.stringify(files)}.forEach(file => import(getURL(file)));`
5786
6062
  ]),
5787
6063
  '})();',
@@ -5969,12 +6245,23 @@ Set background.noDynamicEntryWarning to true to disable this warning.
5969
6245
  }
5970
6246
  }
5971
6247
  const webpack_target_webextension_fork = WebExtensionPlugin;
6248
+ function manifest_getManifestContent(compilation, manifestPath) {
6249
+ return getManifestContent(compilation, manifestPath);
6250
+ }
5972
6251
  function scripts_lib_manifest_filterKeysForThisBrowser(manifest, browser) {
5973
6252
  return manifest_filterKeysForThisBrowser(manifest, browser);
5974
6253
  }
5975
6254
  function backgroundIsRequiredMessageOnly(backgroundChunkName) {
5976
6255
  return `Check the ${external_pintor_default().yellow(backgroundChunkName.replace('/', '.'))} field in your ${external_pintor_default().yellow('manifest.json')} file.`;
5977
6256
  }
6257
+ function scriptsManifestChangeDetected(before, after) {
6258
+ const parts = [
6259
+ "Manifest scripts change detected",
6260
+ before ? `${external_pintor_default().gray('before')} ${external_pintor_default().underline(before)}` : '',
6261
+ after ? `${external_pintor_default().gray('after')} ${external_pintor_default().underline(after)}` : ''
6262
+ ].filter(Boolean);
6263
+ return parts.join(' — ');
6264
+ }
5978
6265
  function setup_background_entry_define_property(obj, key, value) {
5979
6266
  if (key in obj) Object.defineProperty(obj, key, {
5980
6267
  value: value,
@@ -6007,7 +6294,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6007
6294
  apply(compiler) {
6008
6295
  const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf-8'));
6009
6296
  const browser = this.browser;
6010
- const minimumBgScript = external_path_.resolve(__dirname, 'firefox' === browser || 'gecko-based' === browser ? 'minimum-firefox-file' : 'minimum-chromium-file');
6297
+ const minimumBgScript = (0, develop_context.G)('firefox' === browser || 'gecko-based' === browser ? 'minimum-firefox-file' : 'minimum-chromium-file');
6011
6298
  const dirname = external_path_.dirname(this.manifestPath);
6012
6299
  let manifestBg = scripts_lib_manifest_filterKeysForThisBrowser(manifest, browser);
6013
6300
  manifestBg = manifestBg?.background ?? manifest.background;
@@ -6050,6 +6337,263 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6050
6337
  this.browser = options.browser || 'chrome';
6051
6338
  }
6052
6339
  }
6340
+ function patch_csp_resolveV2Policy(policy) {
6341
+ if (!policy) return;
6342
+ if ('string' == typeof policy) return policy;
6343
+ if ('object' == typeof policy) {
6344
+ const extensionPages = policy.extension_pages;
6345
+ if ('string' == typeof extensionPages) return extensionPages;
6346
+ }
6347
+ }
6348
+ function patch_csp_buildCSP(cspObject) {
6349
+ const directives = Object.entries(cspObject).map(([directive, values])=>`${directive} ${values.join(' ')}`);
6350
+ return directives.join('; ') + '; ';
6351
+ }
6352
+ function patch_csp_patchV2CSP(manifest) {
6353
+ let policy = patch_csp_resolveV2Policy(manifest.content_security_policy);
6354
+ if (!policy) return patch_csp_buildCSP({
6355
+ "script-src": [
6356
+ "'self'",
6357
+ "'unsafe-eval'",
6358
+ 'blob:',
6359
+ 'filesystem:'
6360
+ ],
6361
+ 'object-src': [
6362
+ "'self'",
6363
+ 'blob:',
6364
+ 'filesystem:'
6365
+ ]
6366
+ });
6367
+ const csp = external_content_security_policy_parser_default()(policy);
6368
+ if (csp.get("script-src")) {
6369
+ const scriptSrc = csp.get("script-src") || [];
6370
+ if (!scriptSrc.includes("'unsafe-eval'")) scriptSrc.push("'unsafe-eval'");
6371
+ if (!scriptSrc.includes('blob:')) scriptSrc.push('blob:');
6372
+ if (!scriptSrc.includes('filesystem:')) scriptSrc.push('filesystem:');
6373
+ csp.set("script-src", scriptSrc);
6374
+ } else csp.set("script-src", [
6375
+ "'self'",
6376
+ "'unsafe-eval'",
6377
+ 'blob:',
6378
+ 'filesystem:'
6379
+ ]);
6380
+ if (csp.get('object-src')) {
6381
+ const objectSrc = csp.get('object-src') || [];
6382
+ if (!objectSrc.includes('blob:')) objectSrc.push('blob:');
6383
+ if (!objectSrc.includes('filesystem:')) objectSrc.push('filesystem:');
6384
+ csp.set('object-src', objectSrc);
6385
+ } else csp.set('object-src', [
6386
+ "'self'",
6387
+ 'blob:',
6388
+ 'filesystem:'
6389
+ ]);
6390
+ const cspObject = Object.fromEntries(csp.entries());
6391
+ return patch_csp_buildCSP(cspObject);
6392
+ }
6393
+ function patch_csp_patchV3CSP(manifest) {
6394
+ const policy = manifest.content_security_policy;
6395
+ if (!policy) return {
6396
+ extension_pages: patch_csp_buildCSP({
6397
+ "script-src": [
6398
+ "'self'"
6399
+ ],
6400
+ 'object-src': [
6401
+ "'self'"
6402
+ ]
6403
+ })
6404
+ };
6405
+ const csp = external_content_security_policy_parser_default()(policy.extension_pages || '');
6406
+ const defaultDirectives = {
6407
+ "script-src": [
6408
+ "'self'"
6409
+ ],
6410
+ 'object-src': [
6411
+ "'self'"
6412
+ ]
6413
+ };
6414
+ for(const directive in defaultDirectives)if (!csp.get(directive)) csp.set(directive, defaultDirectives[directive]);
6415
+ const cspObject = Object.fromEntries(csp.entries());
6416
+ const extensionPagesPolicy = patch_csp_buildCSP(cspObject);
6417
+ return {
6418
+ extension_pages: extensionPagesPolicy
6419
+ };
6420
+ }
6421
+ function patch_web_resources_patchWebResourcesV2(manifest) {
6422
+ const defaultResources = [
6423
+ '/*.json',
6424
+ '/*.js',
6425
+ '/*.css',
6426
+ '/*.scss',
6427
+ '/*.sass',
6428
+ '/*.less',
6429
+ '*.styl',
6430
+ "/scripts/*.js",
6431
+ "/scripts/*.css",
6432
+ '/hot/*',
6433
+ '/*.png',
6434
+ '/*.jpg',
6435
+ '/*.jpeg',
6436
+ '/*.svg',
6437
+ '/*.gif',
6438
+ '/*.webp',
6439
+ '/*.ico',
6440
+ '/*.avif'
6441
+ ];
6442
+ const resources = manifest.web_accessible_resources;
6443
+ if (!resources || 0 === resources.length) return defaultResources;
6444
+ const webResources = new Set(resources);
6445
+ for (const resource of defaultResources)if (!webResources.has(resource)) webResources.add(resource);
6446
+ return Array.from(webResources);
6447
+ }
6448
+ function patch_web_resources_patchWebResourcesV3(manifest) {
6449
+ const defaultResources = [
6450
+ '/*.json',
6451
+ '/*.js',
6452
+ '/*.css',
6453
+ '/*.scss',
6454
+ '/*.sass',
6455
+ '/*.less',
6456
+ '*.styl',
6457
+ "/scripts/*.js",
6458
+ "/scripts/*.css",
6459
+ '/hot/*',
6460
+ '/*.png',
6461
+ '/*.jpg',
6462
+ '/*.jpeg',
6463
+ '/*.svg',
6464
+ '/*.gif',
6465
+ '/*.webp',
6466
+ '/*.ico',
6467
+ '/*.avif'
6468
+ ];
6469
+ return [
6470
+ ...manifest.web_accessible_resources || [],
6471
+ {
6472
+ resources: defaultResources,
6473
+ matches: [
6474
+ '<all_urls>'
6475
+ ]
6476
+ }
6477
+ ];
6478
+ }
6479
+ function patch_background_patchBackground(manifest, browser) {
6480
+ if (!manifest.background) {
6481
+ if ('firefox' === browser || 'gecko-based' === browser) return {
6482
+ background: {
6483
+ ...manifest.background || {},
6484
+ scripts: [
6485
+ "background/script.js"
6486
+ ]
6487
+ }
6488
+ };
6489
+ if (2 === manifest.manifest_version) return {
6490
+ background: {
6491
+ ...manifest.background || {},
6492
+ scripts: [
6493
+ "background/script.js"
6494
+ ]
6495
+ }
6496
+ };
6497
+ return {
6498
+ background: {
6499
+ ...manifest.background || {},
6500
+ service_worker: 'background/service_worker.js'
6501
+ }
6502
+ };
6503
+ }
6504
+ return {
6505
+ background: {
6506
+ ...manifest.background
6507
+ }
6508
+ };
6509
+ }
6510
+ function patch_externally_connectable_patchExternallyConnectable(manifest) {
6511
+ if (manifest.externally_connectable && !manifest.externally_connectable.ids) return {
6512
+ externally_connectable: {
6513
+ ...manifest.externally_connectable,
6514
+ ids: [
6515
+ ...new Set(manifest.externally_connectable.ids || []),
6516
+ '*'
6517
+ ]
6518
+ }
6519
+ };
6520
+ if (manifest.externally_connectable && !manifest.externally_connectable.ids) return {
6521
+ externally_connectable: {
6522
+ ...manifest.externally_connectable,
6523
+ ids: [
6524
+ '*'
6525
+ ]
6526
+ }
6527
+ };
6528
+ return {};
6529
+ }
6530
+ function apply_manifest_dev_defaults_define_property(obj, key, value) {
6531
+ if (key in obj) Object.defineProperty(obj, key, {
6532
+ value: value,
6533
+ enumerable: true,
6534
+ configurable: true,
6535
+ writable: true
6536
+ });
6537
+ else obj[key] = value;
6538
+ return obj;
6539
+ }
6540
+ class ApplyManifestDevDefaults {
6541
+ generateManifestPatches(compilation) {
6542
+ const canonicalManifest = manifest_getManifestContent(compilation, this.manifestPath);
6543
+ const patchedManifest = {
6544
+ ...canonicalManifest,
6545
+ content_security_policy: 3 === canonicalManifest.manifest_version ? patch_csp_patchV3CSP(canonicalManifest) : patch_csp_patchV2CSP(canonicalManifest),
6546
+ ...3 === canonicalManifest.manifest_version ? canonicalManifest.permissions ? {
6547
+ permissions: [
6548
+ ...new Set([
6549
+ "scripting",
6550
+ 'tabs',
6551
+ 'management',
6552
+ ...canonicalManifest.permissions
6553
+ ])
6554
+ ]
6555
+ } : {
6556
+ permissions: [
6557
+ "scripting",
6558
+ 'tabs',
6559
+ 'management'
6560
+ ]
6561
+ } : {},
6562
+ ...patch_background_patchBackground(canonicalManifest, this.browser),
6563
+ ...patch_externally_connectable_patchExternallyConnectable(canonicalManifest),
6564
+ web_accessible_resources: 3 === canonicalManifest.manifest_version ? patch_web_resources_patchWebResourcesV3(canonicalManifest) : patch_web_resources_patchWebResourcesV2(canonicalManifest)
6565
+ };
6566
+ const source = JSON.stringify(patchedManifest, null, 2);
6567
+ const rawSource = new core_.sources.RawSource(source);
6568
+ if (compilation.getAsset('manifest.json')) compilation.updateAsset('manifest.json', rawSource);
6569
+ }
6570
+ apply(compiler) {
6571
+ if (!compiler?.hooks?.thisCompilation) return;
6572
+ compiler.hooks.thisCompilation.tap('run-chromium:apply-manifest-dev-defaults', (compilation)=>{
6573
+ if (!compilation?.hooks?.processAssets) return;
6574
+ compilation.hooks.processAssets.tap({
6575
+ name: 'run-chromium:apply-manifest-dev-defaults',
6576
+ stage: core_.Compilation.PROCESS_ASSETS_STAGE_REPORT + 100
6577
+ }, (_assets)=>{
6578
+ if (!this.manifestPath) {
6579
+ const errorMessage = 'No manifest.json found in your extension bundle. Unable to patch manifest.json.';
6580
+ try {
6581
+ const WebpackErrorCtor = compiler?.rspack?.WebpackError;
6582
+ compilation.errors.push(WebpackErrorCtor ? new WebpackErrorCtor(`run-chromium: ${errorMessage}`) : new Error(`run-chromium: ${errorMessage}`));
6583
+ } catch {}
6584
+ return;
6585
+ }
6586
+ this.generateManifestPatches(compilation);
6587
+ });
6588
+ });
6589
+ }
6590
+ constructor(options){
6591
+ apply_manifest_dev_defaults_define_property(this, "manifestPath", void 0);
6592
+ apply_manifest_dev_defaults_define_property(this, "browser", void 0);
6593
+ this.manifestPath = options.manifestPath;
6594
+ this.browser = options.browser || 'chrome';
6595
+ }
6596
+ }
6053
6597
  function setup_reload_strategy_define_property(obj, key, value) {
6054
6598
  if (key in obj) Object.defineProperty(obj, key, {
6055
6599
  value: value,
@@ -6095,17 +6639,17 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6095
6639
  let bridgeOrdinal = 0;
6096
6640
  for(let i = 0; i < csList.length; i++){
6097
6641
  const cs = csList[i];
6098
- const bundleId = `content_scripts/content-${i}.js`;
6642
+ const bundleId = (0, contracts.f6)(i);
6099
6643
  const isMain = cs?.world === 'MAIN';
6100
6644
  if (isMain) {
6101
6645
  const bridgeIndex = originalCount + bridgeOrdinal++;
6646
+ const bridgeBundleId = (0, contracts.f6)(bridgeIndex);
6102
6647
  contentScriptsMeta[bundleId] = {
6103
6648
  index: i,
6104
6649
  bundleId,
6105
6650
  world: 'main',
6106
- bridgeBundleId: `content_scripts/content-${bridgeIndex}.js`
6651
+ bridgeBundleId
6107
6652
  };
6108
- const bridgeBundleId = `content_scripts/content-${bridgeIndex}.js`;
6109
6653
  contentScriptsMeta[bridgeBundleId] = {
6110
6654
  index: bridgeIndex,
6111
6655
  bundleId: bridgeBundleId,
@@ -6120,12 +6664,17 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6120
6664
  };
6121
6665
  }
6122
6666
  } catch {}
6667
+ new ApplyManifestDevDefaults({
6668
+ manifestPath: this.manifestPath,
6669
+ browser: this.browser
6670
+ }).apply(compiler);
6123
6671
  new SetupBackgroundEntry({
6124
6672
  manifestPath: this.manifestPath,
6125
6673
  browser: this.browser
6126
6674
  }).apply(compiler);
6127
6675
  new webpack_target_webextension_fork({
6128
6676
  background: this.getEntryName(patchedManifest),
6677
+ hmrConfig: false,
6129
6678
  weakRuntimeCheck: true,
6130
6679
  contentScriptsMeta
6131
6680
  }).apply(compiler);
@@ -6137,6 +6686,135 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6137
6686
  this.browser = options.browser || 'chrome';
6138
6687
  }
6139
6688
  }
6689
+ const DEV_SERVER_CLIENT_MARKERS = [
6690
+ '@rspack/dev-server/client/index.js?',
6691
+ '@rspack/dev-server/client/utils/ansiHTML.js',
6692
+ 'webpack-dev-server',
6693
+ 'WebSocketClient'
6694
+ ];
6695
+ const DEV_SERVER_HOT_MARKERS = [
6696
+ '[HMR] Waiting for update signal from WDS...',
6697
+ '[HMR] Cannot find update. Need to do a full reload!',
6698
+ 'module.hot.check()'
6699
+ ];
6700
+ function stripDevServerStartupFromContentScript(source) {
6701
+ let nextSource = source;
6702
+ const startupModuleIds = getStartupModuleIds(source);
6703
+ for (const moduleId of startupModuleIds){
6704
+ const moduleBody = getModuleBody(source, moduleId);
6705
+ if (!moduleBody) continue;
6706
+ const shouldStrip = DEV_SERVER_CLIENT_MARKERS.some((marker)=>moduleBody.includes(marker)) || DEV_SERVER_HOT_MARKERS.some((marker)=>moduleBody.includes(marker));
6707
+ if (shouldStrip) nextSource = stripStartupRequire(nextSource, moduleId);
6708
+ }
6709
+ return stripExtraStartupRequires(nextSource);
6710
+ }
6711
+ function getStartupModuleIds(source) {
6712
+ const startupIndex = source.indexOf('// startup');
6713
+ if (-1 === startupIndex) return [];
6714
+ const startupSection = source.slice(startupIndex);
6715
+ const requirePattern = /__webpack_require__\((\d+)\);/g;
6716
+ const ids = [];
6717
+ let match = null;
6718
+ while(match = requirePattern.exec(startupSection))ids.push(match[1]);
6719
+ return ids;
6720
+ }
6721
+ function getModuleBody(source, moduleId) {
6722
+ const moduleHeaderPattern = new RegExp(`(?:^|\\n)${moduleId}\\([^)]*\\)\\s*\\{`, 'm');
6723
+ const headerMatch = moduleHeaderPattern.exec(source);
6724
+ if (!headerMatch) return null;
6725
+ const moduleStart = headerMatch.index;
6726
+ const nextHeaderPattern = /(?:^|\n)\d+\([^)]*\)\s*\{/g;
6727
+ nextHeaderPattern.lastIndex = moduleStart + headerMatch[0].length;
6728
+ const nextHeaderMatch = nextHeaderPattern.exec(source);
6729
+ return source.slice(moduleStart, nextHeaderMatch ? nextHeaderMatch.index : source.length);
6730
+ }
6731
+ function stripExtraStartupRequires(source) {
6732
+ const startupMarker = '// startup';
6733
+ const startupIndex = source.indexOf(startupMarker);
6734
+ if (-1 === startupIndex) return source;
6735
+ const startupSection = source.slice(startupIndex);
6736
+ const mainEntryMatch = startupSection.match(/var __webpack_exports__ = __webpack_require__\(\d+\);/);
6737
+ if (!mainEntryMatch) return source;
6738
+ const requireMatches = Array.from(startupSection.matchAll(/^\s*__webpack_require__\(\d+\);\s*$/gm));
6739
+ if (requireMatches.length <= 1) return source;
6740
+ const requiresToRemove = requireMatches.slice(1).map((match)=>match[0]);
6741
+ let nextSource = source;
6742
+ for (const requireLine of requiresToRemove)nextSource = nextSource.replace(requireLine, '');
6743
+ return nextSource;
6744
+ }
6745
+ function stripStartupRequire(source, moduleId) {
6746
+ const startupRequirePattern = new RegExp(`^\\s*__webpack_require__\\(${moduleId}\\);\\n?`, 'm');
6747
+ return source.replace(startupRequirePattern, '');
6748
+ }
6749
+ const strip_content_script_dev_server_runtime_CONTENT_SCRIPT_ASSET = /(^|\/)content_scripts\/content-\d+(?:\.[a-f0-9]+)?\.js$/i;
6750
+ class StripContentScriptDevServerRuntime {
6751
+ apply(compiler) {
6752
+ compiler.hooks.thisCompilation.tap(StripContentScriptDevServerRuntime.name, (compilation)=>{
6753
+ compilation.hooks.processAssets.tap({
6754
+ name: StripContentScriptDevServerRuntime.name,
6755
+ stage: core_.Compilation.PROCESS_ASSETS_STAGE_REPORT
6756
+ }, ()=>{
6757
+ for (const asset of compilation.getAssets()){
6758
+ if (!strip_content_script_dev_server_runtime_CONTENT_SCRIPT_ASSET.test(asset.name)) continue;
6759
+ const originalSource = asset.source.source().toString();
6760
+ const strippedSource = stripDevServerStartupFromContentScript(originalSource);
6761
+ if (strippedSource !== originalSource) compilation.updateAsset(asset.name, new core_.sources.RawSource(strippedSource));
6762
+ }
6763
+ });
6764
+ });
6765
+ }
6766
+ }
6767
+ const basic = [
6768
+ 'var isBrowser = !!(() => { try { return globalThis.browser.runtime.getURL("/") } catch(e) {} })()',
6769
+ 'var isChrome = !!(() => { try { return globalThis.chrome.runtime.getURL("/") } catch(e) {} })()'
6770
+ ];
6771
+ const weakRuntimeCheck = [
6772
+ ...basic,
6773
+ "var runtime = isBrowser ? globalThis.browser : isChrome ? globalThis.chrome : { runtime: { getURL: x => x } }"
6774
+ ];
6775
+ class AddPublicPathRuntimeModule {
6776
+ apply(compiler) {
6777
+ const { RuntimeGlobals } = compiler.webpack;
6778
+ compiler.hooks.compilation.tap('PublicPathRuntimeModule', (compilation)=>{
6779
+ compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(AddPublicPathRuntimeModule.name, (chunk)=>{
6780
+ const module = add_public_path_runtime_module_PublicPathRuntimeModule(compiler);
6781
+ compilation.addRuntimeModule(chunk, module);
6782
+ return true;
6783
+ });
6784
+ });
6785
+ }
6786
+ }
6787
+ function add_public_path_runtime_module_PublicPathRuntimeModule(compiler) {
6788
+ const { Template, RuntimeModule, RuntimeGlobals } = compiler.webpack;
6789
+ class PublicPathRuntimeModule extends RuntimeModule {
6790
+ generate() {
6791
+ const publicPath = this.compilation?.outputOptions.publicPath;
6792
+ return Template.asString([
6793
+ ...weakRuntimeCheck,
6794
+ 'var __extjsBase = (typeof globalThis === "object" && globalThis && globalThis.__EXTJS_EXTENSION_BASE__) ? String(globalThis.__EXTJS_EXTENSION_BASE__) : "";',
6795
+ 'if (!__extjsBase && typeof document === "object" && document && document.documentElement) {',
6796
+ Template.indent([
6797
+ 'try { __extjsBase = document.documentElement.getAttribute("data-extjs-extension-base") || ""; } catch(_) { __extjsBase = ""; }'
6798
+ ]),
6799
+ "}",
6800
+ `var path = ${JSON.stringify(this.compilation?.getPath(publicPath || '', {
6801
+ hash: this.compilation.hash || 'XXXX'
6802
+ }))}`,
6803
+ 'var __extjsRuntimePath = "";',
6804
+ "if (!(typeof importScripts === 'function') && (isBrowser || isChrome)) {",
6805
+ Template.indent([
6806
+ 'try { __extjsRuntimePath = runtime.runtime.getURL(path); } catch (_) { __extjsRuntimePath = ""; }'
6807
+ ]),
6808
+ "}",
6809
+ `${RuntimeGlobals.publicPath} = typeof importScripts === 'function' || !(isBrowser || isChrome) ? path : (__extjsRuntimePath || (__extjsBase ? __extjsBase.replace(/\\/+$/, "/") + String(path).replace(/^\\/+/, "") : ""));`
6810
+ ]);
6811
+ }
6812
+ constructor(){
6813
+ super('publicPath', RuntimeModule.STAGE_BASIC);
6814
+ }
6815
+ }
6816
+ return new PublicPathRuntimeModule();
6817
+ }
6140
6818
  function throw_if_manifest_scripts_change_define_property(obj, key, value) {
6141
6819
  if (key in obj) Object.defineProperty(obj, key, {
6142
6820
  value: value,
@@ -6259,6 +6937,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6259
6937
  }).apply(compiler);
6260
6938
  if ('production' === compiler.options.mode) new AddPublicPathRuntimeModule().apply(compiler);
6261
6939
  if ('production' !== compiler.options.mode) {
6940
+ new StripContentScriptDevServerRuntime().apply(compiler);
6262
6941
  new SetupReloadStrategy({
6263
6942
  manifestPath: this.manifestPath,
6264
6943
  browser: this.browser
@@ -7648,6 +8327,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7648
8327
  instanceId: options.instanceId
7649
8328
  };
7650
8329
  }
8330
+ var runtime_options = __webpack_require__("./webpack/plugin-browsers/browsers-lib/runtime-options.ts");
7651
8331
  var browsers_lib_messages = __webpack_require__("./webpack/plugin-browsers/browsers-lib/messages.ts");
7652
8332
  var chromium_context = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-context/index.ts");
7653
8333
  var chromium_launch = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-launch/index.ts");
@@ -8003,19 +8683,21 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8003
8683
  return hash.toString(16).padStart(8, '0');
8004
8684
  }
8005
8685
  function diffDomSnapshots(prev, next) {
8686
+ const prevNodes = Array.isArray(prev?.nodes) ? prev.nodes : [];
8687
+ const nextNodes = Array.isArray(next?.nodes) ? next.nodes : [];
8006
8688
  if (!prev) return {
8007
- added: next.nodes.length,
8689
+ added: nextNodes.length,
8008
8690
  removed: 0,
8009
8691
  changed: 0,
8010
- addedKeys: next.nodes.slice(0, 50).map((n)=>n.key),
8692
+ addedKeys: nextNodes.slice(0, 50).map((n)=>n.key),
8011
8693
  removedKeys: [],
8012
8694
  changedKeys: []
8013
8695
  };
8014
- const prevMap = new Map(prev.nodes.map((n)=>[
8696
+ const prevMap = new Map(prevNodes.map((n)=>[
8015
8697
  n.key,
8016
8698
  n
8017
8699
  ]));
8018
- const nextMap = new Map(next.nodes.map((n)=>[
8700
+ const nextMap = new Map(nextNodes.map((n)=>[
8019
8701
  n.key,
8020
8702
  n
8021
8703
  ]));
@@ -8122,6 +8804,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8122
8804
  return '<<<EXTJS_HTML_END>>>';
8123
8805
  }
8124
8806
  var manifest_readiness = __webpack_require__("./webpack/plugin-browsers/run-chromium/manifest-readiness.ts");
8807
+ var content_script_targets = __webpack_require__("./webpack/plugin-browsers/browsers-lib/content-script-targets.ts");
8125
8808
  function chromium_hard_reload_define_property(obj, key, value) {
8126
8809
  if (key in obj) Object.defineProperty(obj, key, {
8127
8810
  value: value,
@@ -8151,6 +8834,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8151
8834
  };
8152
8835
  if (compiler.hooks?.watchRun?.tapAsync) compiler.hooks.watchRun.tapAsync('run-browsers:watch', (compilerWithModifiedFiles, done)=>{
8153
8836
  try {
8837
+ this.contentReloadGeneration += 1;
8154
8838
  const modifiedFiles = compilerWithModifiedFiles?.modifiedFiles || new Set();
8155
8839
  const normalizedModifiedFilePaths = Array.from(modifiedFiles).map((filePath)=>String(filePath).replace(/\\/g, '/'));
8156
8840
  const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
@@ -8183,9 +8867,34 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8183
8867
  });
8184
8868
  }
8185
8869
  }
8186
- if (hitManifest) this.ctx.setPendingReloadReason('manifest');
8187
- else if (localeChanged) this.ctx.setPendingReloadReason('locales');
8188
- else if (serviceWorkerChanged) this.ctx.setPendingReloadReason('sw');
8870
+ if (hitManifest) {
8871
+ this.pendingContentReloadEntryNames = [];
8872
+ this.ctx.setPendingReloadReason('manifest');
8873
+ } else if (localeChanged) {
8874
+ this.pendingContentReloadEntryNames = [];
8875
+ this.ctx.setPendingReloadReason('locales');
8876
+ } else if (serviceWorkerChanged) {
8877
+ this.pendingContentReloadEntryNames = [];
8878
+ this.ctx.setPendingReloadReason('sw');
8879
+ } else {
8880
+ const changedContentEntries = (0, content_script_targets.JY)(sourceModifiedFilePaths, this.contentScriptSourceDependencyPathsByEntry);
8881
+ this.lastWatchIncludedContentChanges = changedContentEntries.length > 0;
8882
+ if (changedContentEntries.length > 0) {
8883
+ this.pendingContentReloadEntryNames = changedContentEntries;
8884
+ this.awaitingSettledContentBuild = true;
8885
+ globalThis.__EXTJS_PENDING_CHROMIUM_CONTENT_RELOAD__ = true;
8886
+ }
8887
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] changed content entries: ${this.pendingContentReloadEntryNames.join(', ') || '<none>'}`);
8888
+ if (this.shouldEmitReloadActionEvent()) emitActionEvent('reload_debug', {
8889
+ phase: 'watch',
8890
+ browser: this.options?.browser,
8891
+ sourceModifiedFilePaths,
8892
+ changedContentEntries,
8893
+ pendingContentReloadEntryNames: [
8894
+ ...this.pendingContentReloadEntryNames
8895
+ ]
8896
+ });
8897
+ }
8189
8898
  } catch (error) {
8190
8899
  this.logger?.warn?.('[reload-debug] watchRun inspect failed:', String(error));
8191
8900
  }
@@ -8194,17 +8903,139 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8194
8903
  compiler.hooks.done.tapPromise('run-browsers:module', async (stats)=>{
8195
8904
  const hasErrors = 'function' == typeof stats?.hasErrors ? stats.hasErrors() : !!stats?.compilation?.errors?.length;
8196
8905
  if (hasErrors) return;
8906
+ const inferredEntryNamesFromSourceSignatures = this.inferContentReloadEntryNamesFromSourceSignatures();
8907
+ const inferredHardReloadReason = this.inferHardReloadReasonFromSourceSignatures(compiler);
8908
+ const nextManifestSourceSignatures = this.collectManifestSourceSignatures(compiler);
8909
+ const nextLocaleSourceSignatures = this.collectLocaleSourceSignatures(compiler);
8910
+ const nextServiceWorkerSourceDependencyPaths = this.collectEntrypointModuleResourcePaths(stats.compilation, 'background/service_worker');
8911
+ const nextServiceWorkerSourceSignatures = this.collectSourceSignaturesFromPaths(nextServiceWorkerSourceDependencyPaths);
8912
+ const nextContentScriptSourceDependencyPaths = this.collectContentScriptSourceDependencyPaths(stats.compilation);
8913
+ const nextContentScriptSourceSignatures = this.collectContentScriptSourceSignatures(nextContentScriptSourceDependencyPaths);
8914
+ const contentScriptOutputRoot = this.ctx.getExtensionRoot() || String(stats?.compilation?.options?.output?.path || '');
8915
+ const nextContentScriptOutputSignatures = this.collectContentScriptOutputSignatures(stats.compilation, contentScriptOutputRoot || void 0);
8916
+ const inferredEntryNamesFromOutputSignatures = this.inferContentReloadEntryNamesFromOutputSignatures(nextContentScriptOutputSignatures);
8197
8917
  this.refreshSWFromManifest(stats.compilation);
8198
- this.refreshServiceWorkerSourceDependencyPaths(stats.compilation);
8918
+ this.serviceWorkerSourceDependencyPaths = nextServiceWorkerSourceDependencyPaths;
8919
+ this.serviceWorkerSourceSignatures = nextServiceWorkerSourceSignatures;
8920
+ this.manifestSourceSignatures = nextManifestSourceSignatures;
8921
+ this.localeSourceSignatures = nextLocaleSourceSignatures;
8922
+ this.contentScriptSourceDependencyPathsByEntry = nextContentScriptSourceDependencyPaths;
8923
+ this.contentScriptSourceSignaturesByEntry = nextContentScriptSourceSignatures;
8924
+ this.contentScriptOutputSignaturesByEntry = nextContentScriptOutputSignatures;
8199
8925
  if (!this.hasCompletedSuccessfulBuild) {
8200
8926
  this.hasCompletedSuccessfulBuild = true;
8201
8927
  this.firstSuccessfulBuildAtMs = Date.now();
8928
+ this.pendingContentReloadEntryNames = [];
8202
8929
  this.ctx.clearPendingReloadReason();
8203
8930
  return;
8204
8931
  }
8932
+ const assetsArr = Array.isArray(stats?.compilation?.getAssets?.()) ? stats.compilation.getAssets() : [];
8933
+ const changedAssets = assetsArr.filter((asset)=>asset?.emitted).map((asset)=>String(asset?.name || ''));
8205
8934
  const pendingReason = this.ctx.getPendingReloadReason();
8206
- const reason = pendingReason;
8207
- if (!reason) return;
8935
+ const inferredAssetReason = this.inferHardReloadReasonFromChangedAssets(this.pendingContentReloadEntryNames.length > 0 ? changedAssets.filter((a)=>'manifest.json' !== String(a || '').replace(/\\/g, '/')) : changedAssets);
8936
+ const reason = pendingReason || inferredHardReloadReason || inferredAssetReason;
8937
+ const inferredEntryNames = Array.from(new Set([
8938
+ ...this.inferContentReloadEntryNamesFromChangedAssets(changedAssets),
8939
+ ...inferredEntryNamesFromSourceSignatures,
8940
+ ...inferredEntryNamesFromOutputSignatures
8941
+ ]));
8942
+ const targetEntryNames = this.pendingContentReloadEntryNames.length > 0 ? [
8943
+ ...this.pendingContentReloadEntryNames
8944
+ ] : inferredEntryNames;
8945
+ if (this.shouldEmitReloadActionEvent()) emitActionEvent('reload_debug', {
8946
+ phase: 'done',
8947
+ browser: this.options?.browser,
8948
+ reason: reason || null,
8949
+ changedAssets,
8950
+ inferredEntryNamesFromSourceSignatures,
8951
+ inferredEntryNamesFromOutputSignatures,
8952
+ pendingContentReloadEntryNames: [
8953
+ ...this.pendingContentReloadEntryNames
8954
+ ],
8955
+ inferredEntryNames,
8956
+ targetEntryNames
8957
+ });
8958
+ if (!reason) {
8959
+ if (targetEntryNames.length > 0) {
8960
+ const ctrl = this.ctx.getController() ?? await new Promise((resolve)=>{
8961
+ const timeout = setTimeout(()=>resolve(void 0), 8000);
8962
+ this.ctx.onControllerReady((c)=>{
8963
+ clearTimeout(timeout);
8964
+ resolve(c);
8965
+ });
8966
+ });
8967
+ if (!ctrl) return;
8968
+ const selectedEntryNames = [
8969
+ ...targetEntryNames
8970
+ ];
8971
+ const selectedGeneration = this.contentReloadGeneration;
8972
+ const selectedRules = (0, content_script_targets.Il)((0, content_script_targets.iw)(stats.compilation, this.ctx.getExtensionRoot()), selectedEntryNames);
8973
+ const sourceOverridesByBundleId = this.collectContentScriptSourceOverrides(stats.compilation, selectedRules);
8974
+ if (0 === selectedRules.length) {
8975
+ this.pendingContentReloadEntryNames = [];
8976
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log('[reload] selected content rules: <none>');
8977
+ return;
8978
+ }
8979
+ if (this.lastWatchIncludedContentChanges && this.contentReloadQuietPeriodMs > 0) {
8980
+ await new Promise((resolve)=>setTimeout(resolve, this.contentReloadQuietPeriodMs));
8981
+ if (selectedGeneration !== this.contentReloadGeneration) {
8982
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log('[reload] skipping content reinjection during active watch churn');
8983
+ return;
8984
+ }
8985
+ }
8986
+ let reinjectionSourceOverridesByBundleId;
8987
+ const extensionRoot = this.ctx.getExtensionRoot();
8988
+ if (extensionRoot) {
8989
+ const selectedEntryFiles = this.collectEntrypointFiles(stats.compilation, selectedEntryNames, extensionRoot);
8990
+ const expectedAssetSignatures = this.collectAssetTextSignatures(stats.compilation, selectedEntryFiles);
8991
+ const filesReady = await this.waitForStableContentOutputs(extensionRoot, selectedEntryFiles, expectedAssetSignatures);
8992
+ const hasSourceOverrides = Object.keys(sourceOverridesByBundleId).length >= selectedRules.length;
8993
+ reinjectionSourceOverridesByBundleId = filesReady ? void 0 : hasSourceOverrides ? sourceOverridesByBundleId : void 0;
8994
+ if (!filesReady) {
8995
+ if (!hasSourceOverrides) return void this.logger?.warn?.("[reload] content script assets did not stabilize before targeted reload");
8996
+ }
8997
+ }
8998
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] selected content rules for ${selectedEntryNames.join(', ')}`);
8999
+ const reinjectedTabs = await ctrl.reloadMatchingTabsForContentScripts(selectedRules, {
9000
+ sourceOverridesByBundleId: reinjectionSourceOverridesByBundleId
9001
+ });
9002
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] reinjected tabs for ${selectedEntryNames.join(', ')}: ${reinjectedTabs}`);
9003
+ ctrl.hardReload().catch(()=>{});
9004
+ if (this.lastWatchIncludedContentChanges && this.contentReloadFollowupMs > 0) {
9005
+ await new Promise((resolve)=>setTimeout(resolve, this.contentReloadFollowupMs));
9006
+ if (selectedGeneration === this.contentReloadGeneration) {
9007
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] follow-up reinjection for ${selectedEntryNames.join(', ')}`);
9008
+ const followupReinjectedTabs = await ctrl.reloadMatchingTabsForContentScripts(selectedRules, {
9009
+ sourceOverridesByBundleId: reinjectionSourceOverridesByBundleId
9010
+ });
9011
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] follow-up reinjected tabs for ${selectedEntryNames.join(', ')}: ${followupReinjectedTabs}`);
9012
+ if (this.contentReloadQuietPeriodMs > 0) await new Promise((resolve)=>setTimeout(resolve, this.contentReloadQuietPeriodMs));
9013
+ }
9014
+ }
9015
+ if (this.awaitingSettledContentBuild && this.lastWatchIncludedContentChanges) {
9016
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log('[reload] preserving pending content reinjection until settled follow-up build');
9017
+ } else {
9018
+ this.pendingContentReloadEntryNames = [];
9019
+ this.awaitingSettledContentBuild = false;
9020
+ }
9021
+ if (this.awaitingSettledContentBuild && !this.lastWatchIncludedContentChanges) {
9022
+ this.pendingContentReloadEntryNames = [];
9023
+ this.awaitingSettledContentBuild = false;
9024
+ }
9025
+ this.broadcastSourceWatchMessage(compiler, {
9026
+ type: 'contentReloaded',
9027
+ browser: this.options?.browser,
9028
+ entries: selectedEntryNames
9029
+ });
9030
+ globalThis.__EXTJS_PENDING_CHROMIUM_CONTENT_RELOAD__ = false;
9031
+ try {
9032
+ await globalThis.__EXTJS_ON_CHROMIUM_CONTENT_RELOADED__?.();
9033
+ } catch {}
9034
+ }
9035
+ return;
9036
+ }
9037
+ this.pendingContentReloadEntryNames = [];
9038
+ globalThis.__EXTJS_PENDING_CHROMIUM_CONTENT_RELOAD__ = false;
8208
9039
  this.ctx.clearPendingReloadReason();
8209
9040
  const now = Date.now();
8210
9041
  if (this.firstSuccessfulBuildAtMs && now - this.firstSuccessfulBuildAtMs < ChromiumHardReloadPlugin.INITIAL_RELOAD_COOLDOWN_MS) return void this.logger?.info?.(`[reload] skipping early reload during startup cooldown (reason:${reason})`);
@@ -8225,7 +9056,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8225
9056
  });
8226
9057
  const extensionRoot = this.ctx.getExtensionRoot();
8227
9058
  if (extensionRoot) {
8228
- const manifestReady = await (0, manifest_readiness.f)(extensionRoot, {
9059
+ const manifestReady = await (0, manifest_readiness.fR)(extensionRoot, {
8229
9060
  timeoutMs: 8000
8230
9061
  });
8231
9062
  if (!manifestReady) return void this.logger?.warn?.('[reload] manifest.json did not stabilize before hard reload');
@@ -8244,6 +9075,40 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8244
9075
  this.warnedHardReloadFailure = true;
8245
9076
  this.logger?.warn?.(browsers_lib_messages.WsE(this.options?.browser));
8246
9077
  }
9078
+ if ('function' == typeof ctrl.reloadMatchingTabsForContentScripts) {
9079
+ const allContentRules = (0, content_script_targets.iw)(stats.compilation, extensionRoot);
9080
+ if (allContentRules.length > 0) {
9081
+ let reinjectedTabs = 0;
9082
+ if ('function' == typeof ctrl.reinjectMatchingTabsViaExtensionRuntime) for(let attempt = 0; attempt < 3 && 0 === reinjectedTabs; attempt++){
9083
+ await new Promise((resolve)=>setTimeout(resolve, 0 === attempt ? 1500 : 1000));
9084
+ const runtimeReinjectedTabs = await ctrl.reinjectMatchingTabsViaExtensionRuntime(allContentRules);
9085
+ reinjectedTabs = Math.max(reinjectedTabs, runtimeReinjectedTabs);
9086
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] extension-runtime reinjected tabs after hard reload: ${runtimeReinjectedTabs}`);
9087
+ }
9088
+ if (0 === reinjectedTabs && 'function' == typeof ctrl.getLastRuntimeReinjectionReport) {
9089
+ const runtimeReport = ctrl.getLastRuntimeReinjectionReport();
9090
+ if (runtimeReport) this.logger?.debug?.(`[reload] extension-runtime reinjection report: ${JSON.stringify(runtimeReport)}`);
9091
+ }
9092
+ if (0 === reinjectedTabs && 'function' == typeof ctrl.reloadMatchingTabsForContentScripts) {
9093
+ reinjectedTabs = await ctrl.reloadMatchingTabsForContentScripts(allContentRules, {
9094
+ allowCoarseCleanup: false
9095
+ });
9096
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] direct reinjected tabs after hard reload: ${reinjectedTabs}`);
9097
+ }
9098
+ if (reinjectedTabs > 0 && 'function' == typeof ctrl.reloadMatchingTabsForContentScripts) {
9099
+ const pageReloadedTabs = await ctrl.reloadMatchingTabsForContentScripts(allContentRules, {
9100
+ preferPageReload: true
9101
+ });
9102
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[reload] page reloaded tabs after direct reinjection: ${pageReloadedTabs}`);
9103
+ }
9104
+ if (0 === reinjectedTabs && 'function' == typeof ctrl.reloadMatchingTabsForContentScripts) for(let attempt = 0; attempt < 3; attempt++){
9105
+ await new Promise((resolve)=>setTimeout(resolve, 0 === attempt ? 1500 : 2000));
9106
+ await ctrl.reloadMatchingTabsForContentScripts(allContentRules, {
9107
+ preferPageReload: true
9108
+ });
9109
+ }
9110
+ }
9111
+ }
8247
9112
  });
8248
9113
  }
8249
9114
  refreshSWFromManifest(compilation) {
@@ -8260,12 +9125,164 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8260
9125
  }
8261
9126
  } catch {}
8262
9127
  }
8263
- refreshServiceWorkerSourceDependencyPaths(compilation) {
9128
+ collectServiceWorkerSourceSignatures() {
9129
+ return this.collectSourceSignaturesFromPaths(this.serviceWorkerSourceDependencyPaths);
9130
+ }
9131
+ collectManifestSourceSignatures(compiler) {
9132
+ return this.collectSourceSignaturesFromPaths(this.getWatchedManifestSourcePaths(compiler));
9133
+ }
9134
+ collectLocaleSourceSignatures(compiler) {
9135
+ const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
9136
+ if (!compilerContextRoot) return new Map();
9137
+ const localesRoot = external_path_.join(compilerContextRoot, 'src', '_locales');
9138
+ const discoveredLocaleFiles = [];
9139
+ const walk = (dirPath)=>{
9140
+ let entries;
9141
+ try {
9142
+ entries = external_fs_.readdirSync(dirPath, {
9143
+ withFileTypes: true
9144
+ });
9145
+ } catch {
9146
+ return;
9147
+ }
9148
+ for (const entry of entries){
9149
+ const absoluteEntryPath = external_path_.join(dirPath, entry.name);
9150
+ if (entry.isDirectory()) {
9151
+ walk(absoluteEntryPath);
9152
+ continue;
9153
+ }
9154
+ if (entry.isFile() && absoluteEntryPath.endsWith('.json')) discoveredLocaleFiles.push(absoluteEntryPath.replace(/\\/g, '/'));
9155
+ }
9156
+ };
9157
+ walk(localesRoot);
9158
+ return this.collectSourceSignaturesFromPaths(discoveredLocaleFiles);
9159
+ }
9160
+ collectSourceSignaturesFromPaths(dependencyPaths) {
9161
+ const signatures = new Map();
9162
+ for (const dependencyPath of dependencyPaths){
9163
+ const normalizedDependencyPath = String(dependencyPath).replace(/\\/g, '/');
9164
+ const signature = this.readSourceFileSignature(normalizedDependencyPath);
9165
+ if (signature) signatures.set(normalizedDependencyPath, signature);
9166
+ }
9167
+ return signatures;
9168
+ }
9169
+ collectContentScriptSourceDependencyPaths(compilation) {
9170
+ return (0, content_script_targets.im)(compilation);
9171
+ }
9172
+ collectContentScriptSourceSignatures(dependencyPathsByEntry) {
9173
+ const nextSignatures = new Map();
9174
+ for (const [entryName, dependencyPaths] of dependencyPathsByEntry.entries()){
9175
+ const signatures = new Map();
9176
+ for (const dependencyPath of dependencyPaths){
9177
+ const signature = this.readSourceFileSignature(dependencyPath);
9178
+ if (signature) signatures.set(dependencyPath, signature);
9179
+ }
9180
+ nextSignatures.set(entryName, signatures);
9181
+ }
9182
+ return nextSignatures;
9183
+ }
9184
+ inferContentReloadEntryNamesFromSourceSignatures() {
9185
+ const changedEntries = new Set();
9186
+ for (const [entryName, dependencySignatures] of this.contentScriptSourceSignaturesByEntry.entries())for (const [dependencyPath, previousSignature] of dependencySignatures){
9187
+ const nextSignature = this.readSourceFileSignature(dependencyPath);
9188
+ if (!nextSignature || nextSignature !== previousSignature) {
9189
+ changedEntries.add(entryName);
9190
+ break;
9191
+ }
9192
+ }
9193
+ return Array.from(changedEntries).sort();
9194
+ }
9195
+ inferContentReloadEntryNamesFromOutputSignatures(nextOutputSignaturesByEntry) {
9196
+ const changedEntries = new Set();
9197
+ for (const [entryName, nextOutputSignatures] of nextOutputSignaturesByEntry.entries()){
9198
+ const previousOutputSignatures = this.contentScriptOutputSignaturesByEntry.get(entryName);
9199
+ if (previousOutputSignatures && 0 !== previousOutputSignatures.size) {
9200
+ if (previousOutputSignatures.size !== nextOutputSignatures.size) {
9201
+ changedEntries.add(entryName);
9202
+ continue;
9203
+ }
9204
+ for (const [outputFile, previousSignature] of previousOutputSignatures){
9205
+ const nextSignature = nextOutputSignatures.get(outputFile);
9206
+ if (!nextSignature || nextSignature !== previousSignature) {
9207
+ changedEntries.add(entryName);
9208
+ break;
9209
+ }
9210
+ }
9211
+ }
9212
+ }
9213
+ return Array.from(changedEntries).sort();
9214
+ }
9215
+ inferHardReloadReasonFromSourceSignatures(compiler) {
9216
+ const nextManifestSourceSignatures = this.collectManifestSourceSignatures(compiler);
9217
+ if (this.haveSourceSignaturesChanged(this.manifestSourceSignatures, nextManifestSourceSignatures)) return 'manifest';
9218
+ const nextLocaleSourceSignatures = this.collectLocaleSourceSignatures(compiler);
9219
+ if (this.haveSourceSignaturesChanged(this.localeSourceSignatures, nextLocaleSourceSignatures)) return 'locales';
9220
+ const nextServiceWorkerSourceSignatures = this.collectServiceWorkerSourceSignatures();
9221
+ if (this.haveSourceSignaturesChanged(this.serviceWorkerSourceSignatures, nextServiceWorkerSourceSignatures)) return 'sw';
9222
+ }
9223
+ haveSourceSignaturesChanged(previousSignatures, nextSignatures) {
9224
+ if (0 === previousSignatures.size) return false;
9225
+ if (previousSignatures.size !== nextSignatures.size) return true;
9226
+ for (const [dependencyPath, previousSignature] of previousSignatures){
9227
+ const nextSignature = nextSignatures.get(dependencyPath);
9228
+ if (!nextSignature || nextSignature !== previousSignature) return true;
9229
+ }
9230
+ return false;
9231
+ }
9232
+ inferContentReloadEntryNamesFromChangedAssets(changedAssets) {
9233
+ const entries = new Set();
9234
+ for (const assetName of changedAssets){
9235
+ const normalizedAssetName = String(assetName || '').replace(/\\/g, '/');
9236
+ const canonicalAsset = (0, contracts.es)(normalizedAssetName);
9237
+ if (canonicalAsset) {
9238
+ entries.add((0, contracts.Y0)(canonicalAsset.index));
9239
+ continue;
9240
+ }
9241
+ const hotMatch = /^hot\/content_scripts\/content-(\d+)\.[^.]+\.json$/.exec(normalizedAssetName);
9242
+ if (!hotMatch) {
9243
+ if (!(0, content_script_targets.HE)(normalizedAssetName)) continue;
9244
+ }
9245
+ if (hotMatch) entries.add((0, contracts.Y0)(Number(hotMatch[1])));
9246
+ }
9247
+ return Array.from(entries);
9248
+ }
9249
+ inferHardReloadReasonFromChangedAssets(changedAssets) {
9250
+ for (const assetName of changedAssets){
9251
+ const normalizedAssetName = String(assetName || '').replace(/\\/g, '/');
9252
+ if (normalizedAssetName) {
9253
+ if ('manifest.json' === normalizedAssetName) return 'manifest';
9254
+ if (/(^|\/)_locales\/.+\.json$/i.test(normalizedAssetName)) return 'locales';
9255
+ if (/(^|\/)background\/(service_worker|script)\.(m?js|cjs)$/i.test(normalizedAssetName)) return 'sw';
9256
+ }
9257
+ }
9258
+ }
9259
+ readSourceFileSignature(absoluteFilePath) {
8264
9260
  try {
8265
- const serviceWorkerEntrypointName = 'background/service_worker';
8266
- const discovered = this.collectEntrypointModuleResourcePaths(compilation, serviceWorkerEntrypointName);
8267
- this.serviceWorkerSourceDependencyPaths = discovered;
8268
- } catch {}
9261
+ const stats = external_fs_.statSync(absoluteFilePath);
9262
+ if (!stats.isFile()) return;
9263
+ return `${stats.size}:${stats.mtimeMs}`;
9264
+ } catch {
9265
+ return;
9266
+ }
9267
+ }
9268
+ collectContentScriptOutputSignatures(compilation, extensionRoot) {
9269
+ const outputSignaturesByEntry = new Map();
9270
+ const entrypoints = compilation?.entrypoints;
9271
+ if (!entrypoints || !extensionRoot) return outputSignaturesByEntry;
9272
+ for (const [entryName] of entrypoints.entries()){
9273
+ if (!(0, content_script_targets.wH)(entryName)) continue;
9274
+ const entryFiles = this.collectEntrypointFiles(compilation, [
9275
+ entryName
9276
+ ], extensionRoot);
9277
+ const outputSignatures = new Map();
9278
+ for (const entryFile of entryFiles){
9279
+ const absoluteEntryFilePath = external_path_.join(extensionRoot, entryFile);
9280
+ const signature = this.readSourceFileSignature(absoluteEntryFilePath);
9281
+ if (signature) outputSignatures.set(entryFile, signature);
9282
+ }
9283
+ if (outputSignatures.size > 0) outputSignaturesByEntry.set(entryName, outputSignatures);
9284
+ }
9285
+ return outputSignaturesByEntry;
8269
9286
  }
8270
9287
  collectEntrypointModuleResourcePaths(compilation, entrypointName) {
8271
9288
  const collectedResourcePaths = new Set();
@@ -8278,15 +9295,175 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8278
9295
  for (const chunk of entrypointChunks){
8279
9296
  const modulesIterable = chunkGraph.getChunkModulesIterable?.(chunk) || chunkGraph.getChunkModulesIterableBySourceType?.(chunk, "javascript") || chunkGraph.getChunkModules?.(chunk);
8280
9297
  if (modulesIterable) for (const module of modulesIterable){
8281
- const resourcePath = module?.resource || module?.rootModule?.resource || module?.originalSource?.()?.resource;
8282
- if ('string' == typeof resourcePath && resourcePath.length > 0) collectedResourcePaths.add(resourcePath.replace(/\\/g, '/'));
9298
+ const resourcePath = (0, content_script_targets.Rt)(module?.resource || module?.rootModule?.resource || module?.originalSource?.()?.resource);
9299
+ if (resourcePath) collectedResourcePaths.add(resourcePath);
8283
9300
  }
8284
9301
  }
8285
9302
  return collectedResourcePaths;
8286
9303
  }
9304
+ collectEntrypointFiles(compilation, entrypointNames, extensionRoot) {
9305
+ const entrypoints = compilation?.entrypoints;
9306
+ if (!entrypoints) return this.deriveCanonicalContentEntryFiles(entrypointNames, extensionRoot);
9307
+ const collectedFiles = new Set();
9308
+ for (const entrypointName of entrypointNames){
9309
+ const entrypoint = entrypoints.get?.(entrypointName);
9310
+ const entryFiles = 'function' == typeof entrypoint?.getFiles ? entrypoint.getFiles() : [];
9311
+ for (const file of entryFiles){
9312
+ const normalizedFile = String(file || '').replace(/\\/g, '/');
9313
+ if (!(!normalizedFile || normalizedFile.endsWith('.map'))) {
9314
+ if (!normalizedFile.startsWith('hot/')) collectedFiles.add(normalizedFile);
9315
+ }
9316
+ }
9317
+ }
9318
+ if (0 === collectedFiles.size) return this.deriveCanonicalContentEntryFiles(entrypointNames, extensionRoot);
9319
+ return Array.from(collectedFiles);
9320
+ }
9321
+ deriveCanonicalContentEntryFiles(entrypointNames, extensionRoot) {
9322
+ const collectedFiles = new Set();
9323
+ for (const entrypointName of entrypointNames){
9324
+ const normalizedEntrypointName = String(entrypointName || '').replace(/\\/g, '/');
9325
+ if (normalizedEntrypointName) try {
9326
+ const jsRelativePath = `${normalizedEntrypointName}.js`;
9327
+ if (!extensionRoot || external_fs_.existsSync(external_path_.join(extensionRoot, jsRelativePath))) collectedFiles.add(jsRelativePath);
9328
+ if (!extensionRoot) continue;
9329
+ const cssRelativePath = `${normalizedEntrypointName}.css`;
9330
+ if (external_fs_.existsSync(external_path_.join(extensionRoot, cssRelativePath))) collectedFiles.add(cssRelativePath);
9331
+ } catch {}
9332
+ }
9333
+ return Array.from(collectedFiles);
9334
+ }
9335
+ async waitForStableContentOutputs(extensionRoot, entryFiles, expectedAssetSignatures = new Map(), timeoutMs = 8000, pollIntervalMs = 150, stableReadsRequired = 2) {
9336
+ const normalizedEntryFiles = entryFiles.map((file)=>String(file || '').replace(/\\/g, '/')).filter(Boolean);
9337
+ if (0 === normalizedEntryFiles.length) return true;
9338
+ const start = Date.now();
9339
+ let lastSignature = '';
9340
+ let stableReads = 0;
9341
+ while(Date.now() - start < timeoutMs){
9342
+ const referencedFiles = new Set(normalizedEntryFiles);
9343
+ const signatureParts = [];
9344
+ let allFilesReady = true;
9345
+ for (const entryFile of normalizedEntryFiles){
9346
+ const absoluteEntryFilePath = external_path_.join(extensionRoot, entryFile);
9347
+ const source = this.readFileTextSafe(absoluteEntryFilePath);
9348
+ const expectedAssetSignature = expectedAssetSignatures.get(entryFile);
9349
+ const signature = expectedAssetSignature ? this.readTextSignature(source) : this.readStableFileSignature(absoluteEntryFilePath);
9350
+ if (!signature) {
9351
+ allFilesReady = false;
9352
+ break;
9353
+ }
9354
+ if (expectedAssetSignature && signature !== expectedAssetSignature) {
9355
+ allFilesReady = false;
9356
+ break;
9357
+ }
9358
+ signatureParts.push(`${entryFile}:${signature}`);
9359
+ if (entryFile.endsWith('.js')) {
9360
+ if (!source) {
9361
+ allFilesReady = false;
9362
+ break;
9363
+ }
9364
+ for (const referencedFile of this.extractReferencedOutputFiles(source))referencedFiles.add(referencedFile);
9365
+ }
9366
+ }
9367
+ if (!allFilesReady) {
9368
+ lastSignature = '';
9369
+ stableReads = 0;
9370
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
9371
+ continue;
9372
+ }
9373
+ for (const referencedFile of referencedFiles){
9374
+ if (normalizedEntryFiles.includes(referencedFile)) continue;
9375
+ const absoluteReferencedFilePath = external_path_.join(extensionRoot, referencedFile);
9376
+ const signature = this.readStableFileSignature(absoluteReferencedFilePath);
9377
+ if (!signature) {
9378
+ allFilesReady = false;
9379
+ break;
9380
+ }
9381
+ signatureParts.push(`${referencedFile}:${signature}`);
9382
+ }
9383
+ if (!allFilesReady) {
9384
+ lastSignature = '';
9385
+ stableReads = 0;
9386
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
9387
+ continue;
9388
+ }
9389
+ const currentSignature = signatureParts.sort().join('|');
9390
+ if (currentSignature === lastSignature) stableReads += 1;
9391
+ else {
9392
+ lastSignature = currentSignature;
9393
+ stableReads = 1;
9394
+ }
9395
+ if (stableReads >= stableReadsRequired) return true;
9396
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
9397
+ }
9398
+ return false;
9399
+ }
9400
+ readStableFileSignature(absoluteFilePath) {
9401
+ try {
9402
+ const stats = external_fs_.statSync(absoluteFilePath);
9403
+ if (!stats.isFile()) return;
9404
+ return `${stats.size}:${stats.mtimeMs}`;
9405
+ } catch {
9406
+ return;
9407
+ }
9408
+ }
9409
+ readFileTextSafe(absoluteFilePath) {
9410
+ try {
9411
+ return external_fs_.readFileSync(absoluteFilePath, 'utf-8');
9412
+ } catch {
9413
+ return;
9414
+ }
9415
+ }
9416
+ collectAssetTextSignatures(compilation, assetNames) {
9417
+ const signatures = new Map();
9418
+ for (const assetName of assetNames){
9419
+ const normalizedAssetName = String(assetName || '').replace(/\\/g, '/');
9420
+ if (normalizedAssetName) try {
9421
+ const asset = compilation.getAsset?.(normalizedAssetName) || compilation?.assets?.[normalizedAssetName];
9422
+ const source = asset && 'function' == typeof asset.source?.source ? asset.source.source() : asset && 'function' == typeof asset.source ? asset.source() : void 0;
9423
+ const signature = this.readTextSignature('string' == typeof source || Buffer.isBuffer(source) ? source.toString() : void 0);
9424
+ if (signature) signatures.set(normalizedAssetName, signature);
9425
+ } catch {}
9426
+ }
9427
+ return signatures;
9428
+ }
9429
+ collectContentScriptSourceOverrides(compilation, rules) {
9430
+ const overrides = {};
9431
+ for (const rule of rules){
9432
+ const bundleId = (0, contracts.Y0)(rule.index);
9433
+ const assetName = `${bundleId}.js`;
9434
+ try {
9435
+ const asset = compilation.getAsset?.(assetName) || compilation?.assets?.[assetName];
9436
+ const source = asset && 'function' == typeof asset.source?.source ? asset.source.source() : asset && 'function' == typeof asset.source ? asset.source() : void 0;
9437
+ const text = 'string' == typeof source || Buffer.isBuffer(source) ? source.toString() : '';
9438
+ if (text) overrides[bundleId] = text;
9439
+ } catch {}
9440
+ }
9441
+ return overrides;
9442
+ }
9443
+ readTextSignature(source) {
9444
+ if ('string' != typeof source) return;
9445
+ let hash = 0;
9446
+ for(let index = 0; index < source.length; index++)hash = 31 * hash + source.charCodeAt(index) >>> 0;
9447
+ return `${source.length}:${hash.toString(16)}`;
9448
+ }
9449
+ extractReferencedOutputFiles(source) {
9450
+ const matches = source.match(/(?:content_scripts|assets)\/[^"'`\s)]+\.(?:css|js|json|png|jpg|jpeg|svg|gif|webp|ico|avif)/g);
9451
+ return Array.from(new Set(matches || []));
9452
+ }
8287
9453
  shouldEmitReloadActionEvent() {
8288
9454
  return Boolean(this.options?.source || this.options?.watchSource);
8289
9455
  }
9456
+ broadcastSourceWatchMessage(compiler, payload) {
9457
+ const webSocketServer = compiler?.options?.webSocketServer;
9458
+ const clients = webSocketServer?.clients;
9459
+ if (!clients || 'function' != typeof clients.forEach) return;
9460
+ const message = JSON.stringify(payload);
9461
+ clients.forEach((client)=>{
9462
+ try {
9463
+ if ('function' == typeof client?.send) client.send(message);
9464
+ } catch {}
9465
+ });
9466
+ }
8290
9467
  constructor(options, ctx){
8291
9468
  chromium_hard_reload_define_property(this, "options", void 0);
8292
9469
  chromium_hard_reload_define_property(this, "ctx", void 0);
@@ -8295,17 +9472,89 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8295
9472
  chromium_hard_reload_define_property(this, "warnedHardReloadFailure", void 0);
8296
9473
  chromium_hard_reload_define_property(this, "hasCompletedSuccessfulBuild", void 0);
8297
9474
  chromium_hard_reload_define_property(this, "firstSuccessfulBuildAtMs", void 0);
9475
+ chromium_hard_reload_define_property(this, "contentReloadGeneration", void 0);
9476
+ chromium_hard_reload_define_property(this, "contentReloadQuietPeriodMs", void 0);
9477
+ chromium_hard_reload_define_property(this, "contentReloadFollowupMs", void 0);
9478
+ chromium_hard_reload_define_property(this, "lastWatchIncludedContentChanges", void 0);
9479
+ chromium_hard_reload_define_property(this, "awaitingSettledContentBuild", void 0);
8298
9480
  chromium_hard_reload_define_property(this, "serviceWorkerSourceDependencyPaths", void 0);
9481
+ chromium_hard_reload_define_property(this, "serviceWorkerSourceSignatures", void 0);
9482
+ chromium_hard_reload_define_property(this, "manifestSourceSignatures", void 0);
9483
+ chromium_hard_reload_define_property(this, "localeSourceSignatures", void 0);
9484
+ chromium_hard_reload_define_property(this, "contentScriptSourceDependencyPathsByEntry", void 0);
9485
+ chromium_hard_reload_define_property(this, "contentScriptSourceSignaturesByEntry", void 0);
9486
+ chromium_hard_reload_define_property(this, "contentScriptOutputSignaturesByEntry", void 0);
9487
+ chromium_hard_reload_define_property(this, "pendingContentReloadEntryNames", void 0);
8299
9488
  this.options = options;
8300
9489
  this.ctx = ctx;
8301
9490
  this.hasCompletedSuccessfulBuild = false;
8302
9491
  this.firstSuccessfulBuildAtMs = null;
9492
+ this.contentReloadGeneration = 0;
9493
+ this.contentReloadQuietPeriodMs = 1200;
9494
+ this.contentReloadFollowupMs = 1200;
9495
+ this.lastWatchIncludedContentChanges = false;
9496
+ this.awaitingSettledContentBuild = false;
8303
9497
  this.serviceWorkerSourceDependencyPaths = new Set();
9498
+ this.serviceWorkerSourceSignatures = new Map();
9499
+ this.manifestSourceSignatures = new Map();
9500
+ this.localeSourceSignatures = new Map();
9501
+ this.contentScriptSourceDependencyPathsByEntry = new Map();
9502
+ this.contentScriptSourceSignaturesByEntry = new Map();
9503
+ this.contentScriptOutputSignaturesByEntry = new Map();
9504
+ this.pendingContentReloadEntryNames = [];
8304
9505
  }
8305
9506
  }
8306
9507
  chromium_hard_reload_define_property(ChromiumHardReloadPlugin, "INITIAL_RELOAD_COOLDOWN_MS", 5000);
8307
9508
  var shared_utils = __webpack_require__("./webpack/plugin-browsers/browsers-lib/shared-utils.ts");
8308
9509
  var cdp_client = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-source-inspection/cdp-client.ts");
9510
+ const CONTENT_HTML_HINT_RE = /(id=\"extension-root\"|data-extension-root=|content_script|content_title|js-probe|data-extjs-last-reinject-status=\"mounted\"|data-extjs-reinject-marker=)/i;
9511
+ async function extractPageHtml(cdpClient, sessionId, logSamples = 'true' === process.env.EXTENSION_AUTHOR_MODE, includeShadow = 'open-only') {
9512
+ let html = await cdpClient.getPageHTML(sessionId, includeShadow);
9513
+ if (!html) try {
9514
+ const targets = await cdpClient.getTargets();
9515
+ const fallbackTarget = targets.find((target)=>'page' === target.type && /example\.com|http/.test(String(target.url || '')));
9516
+ if (fallbackTarget && fallbackTarget.targetId) {
9517
+ const newSessionId = await cdpClient.attachToTarget(fallbackTarget.targetId);
9518
+ await cdpClient.waitForContentScriptInjection(newSessionId);
9519
+ const retryHtml = await cdpClient.getPageHTML(newSessionId, includeShadow);
9520
+ if (logSamples) {
9521
+ const sample2 = (retryHtml || '').slice(0, 200).replace(/\n/g, ' ');
9522
+ console.log(browsers_lib_messages.LcW(sample2));
9523
+ }
9524
+ if (retryHtml) return retryHtml;
9525
+ }
9526
+ } catch {}
9527
+ if (!html || !CONTENT_HTML_HINT_RE.test(html)) for(let i = 0; i < 1; i++){
9528
+ await new Promise((r)=>setTimeout(r, 250));
9529
+ try {
9530
+ const againHtml = await cdpClient.getPageHTML(sessionId, includeShadow);
9531
+ if (logSamples) {
9532
+ const sample3 = (againHtml || '').slice(0, 200).replace(/\n/g, ' ');
9533
+ console.log(browsers_lib_messages.jUj(sample3));
9534
+ }
9535
+ if (againHtml && CONTENT_HTML_HINT_RE.test(againHtml)) {
9536
+ html = againHtml;
9537
+ break;
9538
+ }
9539
+ } catch {}
9540
+ }
9541
+ if (!html || 0 === html.trim().length) for(let i = 0; i < 2; i++){
9542
+ try {
9543
+ const evaluatedHtml = await cdpClient.evaluate(sessionId, '(() => { try { return String(document.documentElement.outerHTML||"") } catch(e) { return "" } })()');
9544
+ if (logSamples) {
9545
+ const sample4 = (evaluatedHtml || '').slice(0, 200).replace(/\n/g, ' ');
9546
+ console.log(browsers_lib_messages.jUj(sample4));
9547
+ }
9548
+ if (evaluatedHtml && evaluatedHtml.trim().length > 0) {
9549
+ html = evaluatedHtml;
9550
+ break;
9551
+ }
9552
+ } catch {}
9553
+ await new Promise((r)=>setTimeout(r, 200));
9554
+ }
9555
+ if (logSamples) console.log(browsers_lib_messages.ehY());
9556
+ return html || '';
9557
+ }
8309
9558
  var instance_registry = __webpack_require__("./webpack/plugin-browsers/browsers-lib/instance-registry.ts");
8310
9559
  var discovery = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-source-inspection/discovery.ts");
8311
9560
  async function waitForChromeRemoteDebugging(port, instanceId) {
@@ -8333,10 +9582,21 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8333
9582
  }
8334
9583
  throw new Error(browsers_lib_messages.olb(port));
8335
9584
  }
9585
+ function normalizeInspectableUrl(rawUrl) {
9586
+ try {
9587
+ const parsed = new URL(String(rawUrl || ''));
9588
+ if (('http:' === parsed.protocol || 'https:' === parsed.protocol) && '/' === parsed.pathname) parsed.pathname = '';
9589
+ parsed.hash = '';
9590
+ return parsed.toString();
9591
+ } catch {
9592
+ return String(rawUrl || '').trim().replace(/\/$/, '');
9593
+ }
9594
+ }
8336
9595
  async function ensureTargetAndSession(cdpClient, url, options) {
8337
9596
  const forceNavigate = Boolean(options?.forceNavigate);
9597
+ const normalizedUrl = normalizeInspectableUrl(url);
8338
9598
  const targets = await cdpClient.getTargets();
8339
- const existingTarget = (targets || []).find((t)=>String(t?.url || '') === url && 'page' === String(t?.type || ''));
9599
+ const existingTarget = (targets || []).find((t)=>normalizeInspectableUrl(String(t?.url || '')) === normalizedUrl && 'page' === String(t?.type || ''));
8340
9600
  let targetId = '';
8341
9601
  if (existingTarget && existingTarget.targetId) {
8342
9602
  targetId = String(existingTarget.targetId);
@@ -8363,70 +9623,23 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8363
9623
  try {
8364
9624
  await cdpClient.enableRuntimeAndLog(String(tempSession));
8365
9625
  } catch {}
8366
- await cdpClient.navigate(String(tempSession), url);
8367
- }
8368
- }
8369
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(browsers_lib_messages.MjP());
8370
- const sessionId = String(await cdpClient.attachToTarget(targetId) || '');
8371
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
8372
- console.log(browsers_lib_messages.v5i(sessionId));
8373
- console.log(browsers_lib_messages._JL());
8374
- }
8375
- await cdpClient.sendCommand('Page.enable', {}, sessionId);
8376
- try {
8377
- await cdpClient.enableRuntimeAndLog(sessionId);
8378
- } catch {}
8379
- return {
8380
- targetId: String(targetId),
8381
- sessionId: String(sessionId)
8382
- };
8383
- }
8384
- async function extractPageHtml(cdpClient, sessionId, logSamples = 'true' === process.env.EXTENSION_AUTHOR_MODE, includeShadow = 'open-only') {
8385
- let html = await cdpClient.getPageHTML(sessionId, includeShadow);
8386
- if (!html) try {
8387
- const targets = await cdpClient.getTargets();
8388
- const fallbackTarget = targets.find((target)=>'page' === target.type && /example\.com|http/.test(String(target.url || '')));
8389
- if (fallbackTarget && fallbackTarget.targetId) {
8390
- const newSessionId = await cdpClient.attachToTarget(fallbackTarget.targetId);
8391
- await cdpClient.waitForContentScriptInjection(newSessionId);
8392
- const retryHtml = await cdpClient.getPageHTML(newSessionId, includeShadow);
8393
- if (logSamples) {
8394
- const sample2 = (retryHtml || '').slice(0, 200).replace(/\n/g, ' ');
8395
- console.log(browsers_lib_messages.LcW(sample2));
8396
- }
8397
- if (retryHtml) return retryHtml;
9626
+ await cdpClient.navigate(String(tempSession), url);
8398
9627
  }
8399
- } catch {}
8400
- if (!html || !/(id=\"extension-root\"|content_script|content_title|js-probe)/.test(html)) for(let i = 0; i < 3; i++){
8401
- await new Promise((r)=>setTimeout(r, 500));
8402
- try {
8403
- const againHtml = await cdpClient.getPageHTML(sessionId, includeShadow);
8404
- if (logSamples) {
8405
- const sample3 = (againHtml || '').slice(0, 200).replace(/\n/g, ' ');
8406
- console.log(browsers_lib_messages.jUj(sample3));
8407
- }
8408
- if (againHtml && /(id=\"extension-root\"|content_script|content_title|js-probe)/.test(againHtml)) {
8409
- html = againHtml;
8410
- break;
8411
- }
8412
- } catch {}
8413
9628
  }
8414
- if (!html || 0 === html.trim().length) for(let i = 0; i < 6; i++){
8415
- try {
8416
- const evaluatedHtml = await cdpClient.evaluate(sessionId, '(() => { try { return String(document.documentElement.outerHTML||"") } catch(e) { return "" } })()');
8417
- if (logSamples) {
8418
- const sample4 = (evaluatedHtml || '').slice(0, 200).replace(/\n/g, ' ');
8419
- console.log(browsers_lib_messages.jUj(sample4));
8420
- }
8421
- if (evaluatedHtml && evaluatedHtml.trim().length > 0) {
8422
- html = evaluatedHtml;
8423
- break;
8424
- }
8425
- } catch {}
8426
- await new Promise((r)=>setTimeout(r, 400));
9629
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(browsers_lib_messages.MjP());
9630
+ const sessionId = String(await cdpClient.attachToTarget(targetId) || '');
9631
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
9632
+ console.log(browsers_lib_messages.v5i(sessionId));
9633
+ console.log(browsers_lib_messages._JL());
8427
9634
  }
8428
- if (logSamples) console.log(browsers_lib_messages.ehY());
8429
- return html || '';
9635
+ await cdpClient.sendCommand('Page.enable', {}, sessionId);
9636
+ try {
9637
+ await cdpClient.enableRuntimeAndLog(sessionId);
9638
+ } catch {}
9639
+ return {
9640
+ targetId: String(targetId),
9641
+ sessionId: String(sessionId)
9642
+ };
8430
9643
  }
8431
9644
  function chromium_source_inspection_define_property(obj, key, value) {
8432
9645
  if (key in obj) Object.defineProperty(obj, key, {
@@ -8491,7 +9704,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8491
9704
  const includeShadow = 'off' !== this.devOptions.sourceIncludeShadow;
8492
9705
  try {
8493
9706
  const payload = await this.cdpClient.evaluate(this.currentSessionId, `(() => {
8494
- const rootEl = document.querySelector('#extension-root,[data-extension-root="true"]');
9707
+ const rootEl = document.querySelector('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])');
8495
9708
  if (!rootEl) return null;
8496
9709
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
8497
9710
  const maxDepth = 6;
@@ -8555,6 +9768,28 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8555
9768
  if (payload && 'object' == typeof payload) return payload;
8556
9769
  } catch {}
8557
9770
  }
9771
+ async getExtensionRootMeta() {
9772
+ if (!this.cdpClient || !this.currentSessionId) return;
9773
+ try {
9774
+ return await this.cdpClient.getExtensionRootMeta(this.currentSessionId);
9775
+ } catch {
9776
+ return;
9777
+ }
9778
+ }
9779
+ async shouldEmitContentScriptInjected(injectionWaitOk) {
9780
+ if (!injectionWaitOk || !this.cdpClient || !this.currentSessionId) return false;
9781
+ const sessionId = this.currentSessionId;
9782
+ const deadline = Date.now() + 2800;
9783
+ while(Date.now() < deadline){
9784
+ const rootMeta = await this.cdpClient.getExtensionRootMeta(sessionId);
9785
+ const shadow = await this.cdpClient.getShadowStyleSnapshot(sessionId);
9786
+ const hasUserRoot = Boolean(rootMeta && rootMeta.rootCount >= 1);
9787
+ const hasShadowStyles = shadow && 'number' == typeof shadow.count && Number(shadow.count) > 0;
9788
+ if (hasUserRoot || hasShadowStyles) return true;
9789
+ await new Promise((r)=>setTimeout(r, 200));
9790
+ }
9791
+ return this.cdpClient.hasVisibleShadowHostContent(sessionId);
9792
+ }
8558
9793
  async getPageMetaSnapshot() {
8559
9794
  if (!this.cdpClient || !this.currentSessionId) return {};
8560
9795
  try {
@@ -8616,7 +9851,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8616
9851
  const includeShadow = 'off' !== this.devOptions.sourceIncludeShadow;
8617
9852
  try {
8618
9853
  const payload = await this.cdpClient.evaluate(this.currentSessionId, `(() => {
8619
- const rootEl = document.querySelector('#extension-root,[data-extension-root="true"]');
9854
+ const rootEl = document.querySelector('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])');
8620
9855
  if (!rootEl) return null;
8621
9856
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
8622
9857
  const maxDepth = 4;
@@ -8836,6 +10071,10 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8836
10071
  if (this.devOptions.sourceMeta) {
8837
10072
  const metaSnapshot = await this.getPageMetaSnapshot();
8838
10073
  this.emitEventPayload('page_meta', stage, meta, metaSnapshot);
10074
+ const rootMeta = await this.getExtensionRootMeta();
10075
+ if (rootMeta) this.emitEventPayload('extension_root_meta', stage, meta, rootMeta);
10076
+ const styleSnapshot = await this.getShadowStyleSnapshot();
10077
+ if (styleSnapshot) this.emitEventPayload('shadow_style_output', stage, meta, styleSnapshot);
8839
10078
  }
8840
10079
  if (Array.isArray(this.devOptions.sourceProbe)) {
8841
10080
  const probes = await this.getSelectorProbes(this.devOptions.sourceProbe);
@@ -8898,6 +10137,14 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8898
10137
  ...payload
8899
10138
  }));
8900
10139
  }
10140
+ async getShadowStyleSnapshot() {
10141
+ if (!this.cdpClient || !this.currentSessionId) return;
10142
+ try {
10143
+ return await this.cdpClient.getShadowStyleSnapshot(this.currentSessionId);
10144
+ } catch {
10145
+ return;
10146
+ }
10147
+ }
8901
10148
  async getCdpPort() {
8902
10149
  const instanceId = this.devOptions.instanceId;
8903
10150
  return (0, shared_utils.jl)(this.devOptions.port, instanceId);
@@ -8941,30 +10188,14 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8941
10188
  await this.emitSourceOutput(String(initialHtml || ''), 'pre_injection');
8942
10189
  } catch {}
8943
10190
  if (this.isAuthorMode()) console.log(browsers_lib_messages.mOc());
8944
- await this.cdpClient.waitForContentScriptInjection(this.currentSessionId);
8945
- emitActionEvent("content_script_injected", {
10191
+ const injected = await this.cdpClient.waitForContentScriptInjection(this.currentSessionId);
10192
+ const emitInjection = await this.shouldEmitContentScriptInjected(injected);
10193
+ if (emitInjection) emitActionEvent("content_script_injected", {
8946
10194
  url
8947
10195
  });
10196
+ if (!injected) await this.cdpClient.pollForVisibleShadowHostContent(this.currentSessionId);
8948
10197
  try {
8949
- const deadline = Date.now() + 20000;
8950
- const started = Date.now();
8951
- while(Date.now() < deadline){
8952
- const hasRoot = await this.cdpClient.evaluate(this.currentSessionId, `(() => { try {
8953
- const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root="true"]'));
8954
- if (!hosts.length) return false;
8955
- for (const h of hosts) {
8956
- try {
8957
- const sr = h && h.shadowRoot;
8958
- if (sr && (String(sr.innerHTML||'').length > 0)) return true;
8959
- } catch { /* ignore */ }
8960
- }
8961
- return false;
8962
- } catch { return false } })()`);
8963
- if (hasRoot) break;
8964
- const elapsed = Date.now() - started;
8965
- const delay = elapsed < 2000 ? 150 : 500;
8966
- await new Promise((r)=>setTimeout(r, delay));
8967
- }
10198
+ await this.waitForContentScriptStyles(this.currentSessionId);
8968
10199
  } catch {}
8969
10200
  const outputConfig = this.getOutputConfig();
8970
10201
  const html = await extractPageHtml(this.cdpClient, this.currentSessionId, this.isAuthorMode(), outputConfig.includeShadow);
@@ -8998,14 +10229,104 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8998
10229
  ws.on('message', async (data)=>{
8999
10230
  try {
9000
10231
  const message = JSON.parse(data);
9001
- if ('changedFile' === message.type && this.isWatching) await this.handleFileChange();
10232
+ if ('changedFile' === message.type && this.isWatching) {
10233
+ if (!this.pendingWatchSourceUpdate) this.pendingWatchSourceRootMeta = await this.getExtensionRootMeta().catch(()=>void 0);
10234
+ this.pendingWatchSourceUpdate = true;
10235
+ } else if ('contentReloaded' === message.type && this.isWatching) {
10236
+ if (this.pendingWatchSourceUpdate) {
10237
+ const previousRootMeta = this.pendingWatchSourceRootMeta;
10238
+ this.pendingWatchSourceUpdate = false;
10239
+ this.pendingWatchSourceRootMeta = void 0;
10240
+ this.scheduleWatchSourceUpdate(previousRootMeta);
10241
+ }
10242
+ }
9002
10243
  } catch (error) {}
9003
10244
  });
9004
10245
  }
9005
10246
  stopWatching() {
9006
10247
  this.isWatching = false;
10248
+ this.pendingWatchSourceUpdate = false;
10249
+ this.pendingWatchSourceRootMeta = void 0;
10250
+ if (this.watchSourceFlushTimer) {
10251
+ clearTimeout(this.watchSourceFlushTimer);
10252
+ this.watchSourceFlushTimer = null;
10253
+ }
9007
10254
  if (this.isAuthorMode()) console.log(browsers_lib_messages.Qx1());
9008
10255
  }
10256
+ registerContentReloadSnapshotHook() {
10257
+ globalThis.__EXTJS_ON_CHROMIUM_CONTENT_RELOADED__ = async ()=>{
10258
+ if (!this.currentSessionId || !this.hasInspectedSourceOnce) return;
10259
+ if (this.isWatching) return;
10260
+ if (this.watchSourceFlushTimer) clearTimeout(this.watchSourceFlushTimer);
10261
+ this.watchSourceFlushTimer = setTimeout(async ()=>{
10262
+ this.watchSourceFlushTimer = null;
10263
+ if (this.isFlushingWatchSourceUpdate || !this.currentSessionId) return;
10264
+ this.isFlushingWatchSourceUpdate = true;
10265
+ try {
10266
+ await this.emitImmediateUpdatedSnapshotFromCurrentSession(this.currentSessionId);
10267
+ } finally{
10268
+ this.isFlushingWatchSourceUpdate = false;
10269
+ }
10270
+ }, 0);
10271
+ };
10272
+ }
10273
+ scheduleWatchSourceUpdate(previousRootMeta) {
10274
+ if (this.watchSourceFlushTimer) clearTimeout(this.watchSourceFlushTimer);
10275
+ this.watchSourceFlushTimer = setTimeout(async ()=>{
10276
+ if (this.isFlushingWatchSourceUpdate) return void this.scheduleWatchSourceUpdate(previousRootMeta);
10277
+ this.watchSourceFlushTimer = null;
10278
+ if (!this.currentSessionId) return;
10279
+ this.isFlushingWatchSourceUpdate = true;
10280
+ try {
10281
+ await this.emitUpdatedSnapshotFromCurrentSession(this.currentSessionId, previousRootMeta);
10282
+ } finally{
10283
+ this.isFlushingWatchSourceUpdate = false;
10284
+ }
10285
+ }, 0);
10286
+ }
10287
+ async emitImmediateUpdatedSnapshotFromCurrentSession(sessionId) {
10288
+ if (!this.cdpClient) return;
10289
+ const readBuildSignature = (rootMeta)=>{
10290
+ const builds = [
10291
+ rootMeta?.page?.build,
10292
+ ...(rootMeta?.roots || []).map((entry)=>entry?.build),
10293
+ ...(rootMeta?.markers || []).map((entry)=>entry?.build),
10294
+ ...(rootMeta?.registries || []).map((entry)=>entry?.build)
10295
+ ].filter((value)=>'string' == typeof value && value.length > 0).sort();
10296
+ return JSON.stringify(builds);
10297
+ };
10298
+ const previousOutputHash = this.lastOutputHash;
10299
+ const previousRootMeta = await this.getExtensionRootMeta().catch(()=>void 0);
10300
+ const previousBuildSignature = readBuildSignature(previousRootMeta);
10301
+ try {
10302
+ await this.waitForContentScriptStyles(sessionId);
10303
+ } catch {}
10304
+ try {
10305
+ await this.waitForMeaningfulContentScriptContent(sessionId);
10306
+ } catch {}
10307
+ let html = '';
10308
+ const outputConfig = this.getOutputConfig();
10309
+ const deadline = Date.now() + 5000;
10310
+ while(Date.now() < deadline){
10311
+ try {
10312
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10313
+ } catch {
10314
+ await new Promise((resolve)=>setTimeout(resolve, 250));
10315
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10316
+ }
10317
+ if (!html) {
10318
+ await new Promise((resolve)=>setTimeout(resolve, 300));
10319
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10320
+ }
10321
+ const currentRootMeta = await this.getExtensionRootMeta().catch(()=>void 0);
10322
+ const currentBuildSignature = readBuildSignature(currentRootMeta);
10323
+ const htmlChanged = !previousOutputHash || hashStringFNV1a(html || '') !== previousOutputHash;
10324
+ const buildsChanged = previousBuildSignature.length > 2 && currentBuildSignature.length > 2 && previousBuildSignature !== currentBuildSignature;
10325
+ if (htmlChanged || buildsChanged) break;
10326
+ await new Promise((resolve)=>setTimeout(resolve, 350));
10327
+ }
10328
+ await this.emitSourceOutput(html || '', 'updated');
10329
+ }
9009
10330
  async handleFileChange() {
9010
10331
  if (!this.cdpClient || !this.currentSessionId) return void console.warn(browsers_lib_messages.MfN());
9011
10332
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
@@ -9016,52 +10337,188 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9016
10337
  console.log(browsers_lib_messages.$xt());
9017
10338
  console.log(browsers_lib_messages.Tev());
9018
10339
  }
10340
+ 'string' == typeof this.devOptions.source && 'true' !== this.devOptions.source && this.devOptions.source;
10341
+ const previousRootMeta = await this.getExtensionRootMeta();
10342
+ await new Promise((resolve)=>setTimeout(resolve, 1000));
10343
+ await this.waitForContentScriptReinjection(this.currentSessionId, previousRootMeta);
10344
+ try {
10345
+ await this.waitForContentScriptStyles(this.currentSessionId);
10346
+ } catch {}
10347
+ if (this.isAuthorMode()) console.log(browsers_lib_messages.Mcx());
10348
+ await this.emitUpdatedSnapshotFromCurrentSession(this.currentSessionId, previousRootMeta);
10349
+ } catch (error) {
9019
10350
  const sourceUrl = 'string' == typeof this.devOptions.source && 'true' !== this.devOptions.source ? this.devOptions.source : '';
9020
- if (sourceUrl) {
10351
+ if (sourceUrl) try {
9021
10352
  emitActionEvent('watch_reinspect_source_url', {
9022
10353
  url: sourceUrl
9023
10354
  });
9024
10355
  const html = await this.inspectSource(sourceUrl, {
9025
- forceNavigate: true
10356
+ forceNavigate: false
9026
10357
  });
9027
10358
  await this.emitSourceOutput(html || '', 'updated');
9028
10359
  return;
9029
- }
9030
- await this.cdpClient.waitForContentScriptInjection(this.currentSessionId);
9031
- if (this.isAuthorMode()) console.log(browsers_lib_messages.Mcx());
9032
- let html = '';
9033
- const outputConfig = this.getOutputConfig();
9034
- try {
9035
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9036
- } catch (e) {
9037
- await new Promise((r)=>setTimeout(r, 250));
9038
- try {
9039
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9040
- } catch {}
9041
- }
9042
- if (!html) {
9043
- await new Promise((r)=>setTimeout(r, 300));
9044
- try {
9045
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9046
- } catch {}
9047
- }
9048
- await this.emitSourceOutput(html || '', 'updated');
9049
- } catch (error) {
10360
+ } catch {}
9050
10361
  console.error(browsers_lib_messages.acp(error.message));
9051
- if (error.message.includes('session') || error.message.includes('target')) {
10362
+ const errorMessage = String(error.message || error || '');
10363
+ if (errorMessage.includes('session') || errorMessage.includes('target') || errorMessage.includes('WebSocket is not open') || errorMessage.includes('connection is closed')) {
9052
10364
  console.log(browsers_lib_messages.bGB());
9053
- await this.reconnectToTarget();
10365
+ await this.reconnectToTarget(sourceUrl || void 0);
9054
10366
  }
9055
10367
  }
9056
10368
  }, 300);
9057
10369
  }
9058
- async reconnectToTarget() {
10370
+ async waitForContentScriptReinjection(sessionId, previousRootMeta) {
10371
+ if (!this.cdpClient) return;
10372
+ const readBuildSignature = (rootMeta)=>{
10373
+ const builds = [
10374
+ rootMeta?.page?.build,
10375
+ ...(rootMeta?.roots || []).map((entry)=>entry?.build),
10376
+ ...(rootMeta?.markers || []).map((entry)=>entry?.build),
10377
+ ...(rootMeta?.registries || []).map((entry)=>entry?.build)
10378
+ ].filter((value)=>'string' == typeof value && value.length > 0).sort();
10379
+ return JSON.stringify(builds);
10380
+ };
10381
+ const previousGeneration = Number(previousRootMeta?.latestGeneration || 0);
10382
+ const previousBuildSignature = readBuildSignature(previousRootMeta);
10383
+ const deadline = Date.now() + 20000;
10384
+ while(Date.now() < deadline){
10385
+ try {
10386
+ const rootMeta = await this.getExtensionRootMeta();
10387
+ if (rootMeta) {
10388
+ const nextBuildSignature = readBuildSignature(rootMeta);
10389
+ const generationAdvanced = Number(rootMeta.latestGeneration || 0) > previousGeneration;
10390
+ const buildAdvanced = previousBuildSignature.length > 2 && nextBuildSignature.length > 2 && previousBuildSignature !== nextBuildSignature;
10391
+ const pageMounted = rootMeta.page?.status === void 0 || rootMeta.page?.status === 'mounted';
10392
+ if ((generationAdvanced || buildAdvanced) && rootMeta.rootCount >= 1 && rootMeta.markerCount >= 1 && pageMounted) return;
10393
+ }
10394
+ } catch {}
10395
+ await new Promise((resolve)=>setTimeout(resolve, 200));
10396
+ }
10397
+ await this.cdpClient.waitForContentScriptInjection(sessionId);
10398
+ }
10399
+ async emitUpdatedSnapshotFromCurrentSession(sessionId, previousRootMeta) {
10400
+ const readBuildSignature = (rootMeta)=>{
10401
+ const builds = [
10402
+ rootMeta?.page?.build,
10403
+ ...(rootMeta?.roots || []).map((entry)=>entry?.build),
10404
+ ...(rootMeta?.markers || []).map((entry)=>entry?.build),
10405
+ ...(rootMeta?.registries || []).map((entry)=>entry?.build)
10406
+ ].filter((value)=>'string' == typeof value && value.length > 0).sort();
10407
+ return JSON.stringify(builds);
10408
+ };
10409
+ await this.waitForContentScriptReinjection(sessionId, previousRootMeta);
10410
+ try {
10411
+ await this.waitForContentScriptStyles(sessionId);
10412
+ } catch {}
10413
+ try {
10414
+ await this.waitForMeaningfulContentScriptContent(sessionId);
10415
+ } catch {}
10416
+ const previousOutputHash = this.lastOutputHash;
10417
+ const previousBuildSignature = readBuildSignature(previousRootMeta);
10418
+ let html = '';
10419
+ const outputConfig = this.getOutputConfig();
10420
+ const deadline = Date.now() + 5000;
10421
+ while(Date.now() < deadline){
10422
+ try {
10423
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10424
+ } catch {
10425
+ await new Promise((resolve)=>setTimeout(resolve, 250));
10426
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10427
+ }
10428
+ if (!html) {
10429
+ await new Promise((resolve)=>setTimeout(resolve, 300));
10430
+ html = await this.cdpClient.getPageHTML(sessionId, outputConfig.includeShadow);
10431
+ }
10432
+ const currentRootMeta = await this.getExtensionRootMeta().catch(()=>void 0);
10433
+ const currentBuildSignature = readBuildSignature(currentRootMeta);
10434
+ const htmlChanged = !previousOutputHash || hashStringFNV1a(html || '') !== previousOutputHash;
10435
+ const buildsChanged = previousBuildSignature.length > 2 && currentBuildSignature.length > 2 && previousBuildSignature !== currentBuildSignature;
10436
+ if (htmlChanged || buildsChanged) break;
10437
+ await new Promise((resolve)=>setTimeout(resolve, 350));
10438
+ }
10439
+ await this.emitSourceOutput(html || '', 'updated');
10440
+ }
10441
+ async waitForMeaningfulContentScriptContent(sessionId) {
10442
+ if (!this.cdpClient) return;
10443
+ const deadline = Date.now() + 10000;
10444
+ while(Date.now() < deadline){
10445
+ try {
10446
+ const hasMeaningfulContent = await this.cdpClient.evaluate(sessionId, `(() => { try {
10447
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
10448
+ if (!hosts.length) return false;
10449
+ for (const host of hosts) {
10450
+ const sr = host && host.shadowRoot;
10451
+ if (!sr) continue;
10452
+ const elements = Array.from(sr.querySelectorAll('*')).filter((element) => {
10453
+ const tagName = String(element?.nodeName || '').toLowerCase();
10454
+ return tagName !== 'style' && tagName !== 'script';
10455
+ });
10456
+ const hasMeaningfulText = elements.some((element) => {
10457
+ const text = String(element?.textContent || '').replace(/\\s+/g, ' ').trim();
10458
+ return text.length > 0;
10459
+ });
10460
+ if (hasMeaningfulText) return true;
10461
+ const hasMeaningfulVisualElement = elements.some((element) => {
10462
+ const tagName = String(element?.nodeName || '').toLowerCase();
10463
+ return ['img', 'svg', 'canvas', 'input', 'button', 'textarea', 'select'].includes(tagName);
10464
+ });
10465
+ if (hasMeaningfulVisualElement) return true;
10466
+ }
10467
+ return false;
10468
+ } catch { return false } })()`);
10469
+ if (hasMeaningfulContent) return;
10470
+ } catch {}
10471
+ await new Promise((resolve)=>setTimeout(resolve, 200));
10472
+ }
10473
+ }
10474
+ async waitForContentScriptStyles(sessionId) {
10475
+ if (!this.cdpClient) return;
10476
+ const deadline = Date.now() + 10000;
10477
+ while(Date.now() < deadline){
10478
+ try {
10479
+ const hasStyles = await this.cdpClient.evaluate(sessionId, `(() => { try {
10480
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
10481
+ if (!hosts.length) return false;
10482
+ for (const host of hosts) {
10483
+ const sr = host && host.shadowRoot;
10484
+ if (!sr) continue;
10485
+ const styles = Array.from(sr.querySelectorAll('style'));
10486
+ if (styles.some((styleEl) => String(styleEl.outerHTML || '').includes('<style') && String(styleEl.textContent || '').trim().length > 0)) {
10487
+ return true;
10488
+ }
10489
+ }
10490
+ return false;
10491
+ } catch { return false } })()`);
10492
+ if (hasStyles) return;
10493
+ } catch {}
10494
+ await new Promise((resolve)=>setTimeout(resolve, 200));
10495
+ }
10496
+ }
10497
+ async reconnectToTarget(sourceUrl) {
9059
10498
  if (!this.isAuthorMode()) return;
9060
10499
  try {
9061
- if (!this.cdpClient || !this.currentTargetId) return void console.warn(browsers_lib_messages.tVJ());
9062
10500
  console.log(browsers_lib_messages.kGe());
9063
- this.currentSessionId = await this.cdpClient.attachToTarget(this.currentTargetId) || null;
9064
- console.log(browsers_lib_messages.PQY(this.currentSessionId || ''));
10501
+ if (!this.cdpClient || !this.cdpClient.isConnected()) {
10502
+ try {
10503
+ this.cdpClient?.disconnect();
10504
+ } catch {}
10505
+ this.cdpClient = null;
10506
+ this.currentSessionId = null;
10507
+ await this.initialize();
10508
+ }
10509
+ if (this.cdpClient && this.currentTargetId) {
10510
+ this.currentSessionId = await this.cdpClient.attachToTarget(this.currentTargetId) || null;
10511
+ console.log(browsers_lib_messages.PQY(this.currentSessionId || ''));
10512
+ return;
10513
+ }
10514
+ if (sourceUrl) {
10515
+ await this.inspectSource(sourceUrl, {
10516
+ forceNavigate: false
10517
+ });
10518
+ console.log(browsers_lib_messages.PQY('source-url'));
10519
+ return;
10520
+ }
10521
+ console.warn(browsers_lib_messages.tVJ());
9065
10522
  } catch (error) {
9066
10523
  console.error(browsers_lib_messages.pcF(error.message));
9067
10524
  }
@@ -9092,19 +10549,32 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9092
10549
  if (this.devOptions.source && 'string' == typeof this.devOptions.source && 'true' !== this.devOptions.source) urlToInspect = this.devOptions.source;
9093
10550
  else if (this.devOptions.startingUrl) urlToInspect = this.devOptions.startingUrl;
9094
10551
  else throw new Error(browsers_lib_messages.Pu4());
10552
+ const webSocketServer = compiler.options.webSocketServer;
10553
+ if (this.devOptions.watchSource && this.hasInspectedSourceOnce) {
10554
+ if (webSocketServer) {
10555
+ if (!this.isWatching) await this.startWatching(webSocketServer);
10556
+ return;
10557
+ }
10558
+ if (this.currentSessionId) {
10559
+ if (globalThis.__EXTJS_PENDING_CHROMIUM_CONTENT_RELOAD__) return;
10560
+ const previousRootMeta = await this.getExtensionRootMeta();
10561
+ this.scheduleWatchSourceUpdate(previousRootMeta);
10562
+ return;
10563
+ }
10564
+ }
9095
10565
  const html = await this.inspectSource(urlToInspect, {
9096
10566
  forceNavigate: this.devOptions.watchSource && this.hasInspectedSourceOnce
9097
10567
  });
9098
10568
  this.hasInspectedSourceOnce = true;
9099
10569
  await this.printHTML(html);
9100
- const webSocketServer = compiler.options.webSocketServer;
9101
- if (this.devOptions.watchSource) if (webSocketServer) await this.startWatching(webSocketServer);
9102
- else try {
9103
- const updated = await this.inspectSource(urlToInspect, {
9104
- forceNavigate: true
9105
- });
9106
- await this.printUpdatedHTML(updated || '');
9107
- } catch {}
10570
+ if (this.devOptions.watchSource) {
10571
+ this.registerContentReloadSnapshotHook();
10572
+ if (webSocketServer) await this.startWatching(webSocketServer);
10573
+ else try {
10574
+ const previousRootMeta = await this.getExtensionRootMeta();
10575
+ if (this.currentSessionId) await this.emitUpdatedSnapshotFromCurrentSession(this.currentSessionId, previousRootMeta);
10576
+ } catch {}
10577
+ }
9108
10578
  } catch (error) {
9109
10579
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.error(browsers_lib_messages.b82(error.message));
9110
10580
  }
@@ -9118,7 +10588,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9118
10588
  chromium_source_inspection_define_property(this, "isInitialized", false);
9119
10589
  chromium_source_inspection_define_property(this, "isWatching", false);
9120
10590
  chromium_source_inspection_define_property(this, "hasInspectedSourceOnce", false);
10591
+ chromium_source_inspection_define_property(this, "pendingWatchSourceUpdate", false);
10592
+ chromium_source_inspection_define_property(this, "pendingWatchSourceRootMeta", void 0);
9121
10593
  chromium_source_inspection_define_property(this, "debounceTimer", null);
10594
+ chromium_source_inspection_define_property(this, "watchSourceFlushTimer", null);
10595
+ chromium_source_inspection_define_property(this, "isFlushingWatchSourceUpdate", false);
9122
10596
  chromium_source_inspection_define_property(this, "runtimeMode", void 0);
9123
10597
  chromium_source_inspection_define_property(this, "lastOutputHash", void 0);
9124
10598
  chromium_source_inspection_define_property(this, "lastByteLength", void 0);
@@ -9191,38 +10665,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9191
10665
  run_chromium_define_property(this, "logTab", void 0);
9192
10666
  run_chromium_define_property(this, "logger", void 0);
9193
10667
  run_chromium_define_property(this, "chromiumCtx", void 0);
9194
- this.extension = options.extension;
9195
- this.browser = options.browser;
9196
- this.startingUrl = options.startingUrl;
9197
- this.preferences = options.preferences;
9198
- this.profile = options.profile;
9199
- this.browserFlags = options.browserFlags;
9200
- this.excludeBrowserFlags = options.excludeBrowserFlags;
9201
- this.noOpen = options.noOpen;
10668
+ Object.assign(this, (0, runtime_options.pA)(options));
9202
10669
  this.chromiumBinary = options.chromiumBinary;
9203
- this.instanceId = options.instanceId;
9204
- this.port = options.port;
9205
- this.source = options.source;
9206
- this.watchSource = options.watchSource;
9207
- this.sourceFormat = options.sourceFormat;
9208
- this.sourceSummary = options.sourceSummary;
9209
- this.sourceMeta = options.sourceMeta;
9210
- this.sourceProbe = options.sourceProbe;
9211
- this.sourceTree = options.sourceTree;
9212
- this.sourceConsole = options.sourceConsole;
9213
- this.sourceDom = options.sourceDom;
9214
- this.sourceMaxBytes = options.sourceMaxBytes;
9215
- this.sourceRedact = options.sourceRedact;
9216
- this.sourceIncludeShadow = options.sourceIncludeShadow;
9217
- this.sourceDiff = options.sourceDiff;
9218
- this.logLevel = options.logLevel;
9219
- this.logContexts = options.logContexts;
9220
- this.logFormat = options.logFormat;
9221
- this.logTimestamps = options.logTimestamps;
9222
- this.logColor = options.logColor;
9223
- this.logUrl = options.logUrl;
9224
- this.logTab = options.logTab;
9225
- this.dryRun = options.dryRun;
9226
10670
  }
9227
10671
  }
9228
10672
  var firefox_context = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-context/index.ts");
@@ -9275,17 +10719,65 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9275
10719
  return obj;
9276
10720
  }
9277
10721
  class FirefoxHardReloadPlugin {
10722
+ getWatchedManifestSourcePaths(compiler) {
10723
+ const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
10724
+ if (!compilerContextRoot) return [];
10725
+ return [
10726
+ `${compilerContextRoot}/manifest.json`,
10727
+ `${compilerContextRoot}/src/manifest.json`
10728
+ ];
10729
+ }
9278
10730
  apply(compiler) {
9279
10731
  if (compiler?.hooks?.watchRun?.tapAsync) compiler.hooks.watchRun.tapAsync('run-browsers:watch', (compilation, done)=>{
9280
10732
  try {
10733
+ this.contentReloadGeneration += 1;
9281
10734
  const files = compilation?.modifiedFiles || new Set();
9282
10735
  const normalized = Array.from(files).map((p)=>String(p).replace(/\\/g, '/'));
9283
- const hitManifest = normalized.some((p)=>/(^|\/)manifest\.json$/i.test(p));
9284
- const hitLocales = normalized.some((p)=>/(^|\/)__?locales\/.+\.json$/i.test(p));
9285
- const hitServiceWorker = normalized.some((p)=>/(^|\/)(service_worker|background)\.(m?js|cjs|ts)$/i.test(p));
9286
- if (hitManifest) this.ctx.setPendingReloadReason?.('manifest');
9287
- else if (hitLocales) this.ctx.setPendingReloadReason?.('locales');
9288
- else if (hitServiceWorker) this.ctx.setPendingReloadReason?.('sw');
10736
+ const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
10737
+ const filesInCurrentCompilerContext = compilerContextRoot ? normalized.filter((filePath)=>filePath === compilerContextRoot || filePath.startsWith(`${compilerContextRoot}/`)) : normalized;
10738
+ const normalizedOutputPath = String(compiler?.options?.output?.path || '').replace(/\\/g, '/');
10739
+ const watchedModifiedFilePaths = compilerContextRoot ? filesInCurrentCompilerContext : normalized;
10740
+ const sourceModifiedFilePaths = watchedModifiedFilePaths.filter((filePath)=>!(normalizedOutputPath && (filePath === normalizedOutputPath || filePath.startsWith(`${normalizedOutputPath}/`))));
10741
+ const normalizedManifestSourcePaths = this.getWatchedManifestSourcePaths(compiler);
10742
+ const hitManifest = sourceModifiedFilePaths.some((filePath)=>{
10743
+ if (normalizedManifestSourcePaths.length > 0) return normalizedManifestSourcePaths.includes(filePath);
10744
+ return /(^|\/)manifest\.json$/i.test(filePath);
10745
+ });
10746
+ const hitLocales = sourceModifiedFilePaths.some((filePath)=>{
10747
+ if (compilerContextRoot) return filePath.startsWith(`${compilerContextRoot}/src/_locales/`);
10748
+ return /(^|\/)__?locales\/.+\.json$/i.test(filePath);
10749
+ });
10750
+ const hitServiceWorker = sourceModifiedFilePaths.some((p)=>/(^|\/)(service_worker|background)\.(m?js|cjs|ts)$/i.test(p));
10751
+ if (hitManifest) {
10752
+ this.pendingContentReloadEntryNames = [];
10753
+ this.ctx.setPendingReloadReason?.('manifest');
10754
+ } else if (hitLocales) {
10755
+ this.pendingContentReloadEntryNames = [];
10756
+ this.ctx.setPendingReloadReason?.('locales');
10757
+ } else if (hitServiceWorker) {
10758
+ this.pendingContentReloadEntryNames = [];
10759
+ this.ctx.setPendingReloadReason?.('sw');
10760
+ } else {
10761
+ const changedContentEntries = (0, content_script_targets.JY)(sourceModifiedFilePaths, this.contentScriptSourceDependencyPathsByEntry);
10762
+ this.lastWatchIncludedContentChanges = changedContentEntries.length > 0;
10763
+ if (changedContentEntries.length > 0) {
10764
+ this.pendingContentReloadEntryNames = changedContentEntries;
10765
+ this.awaitingSettledContentBuild = true;
10766
+ globalThis.__EXTJS_PENDING_FIREFOX_CONTENT_RELOAD__ = true;
10767
+ }
10768
+ if (this.shouldEmitReloadActionEvent()) emitActionEvent('reload_debug', {
10769
+ phase: 'watch',
10770
+ browser: this.host.browser,
10771
+ sourceModifiedFilePaths,
10772
+ hitManifest,
10773
+ hitLocales,
10774
+ hitServiceWorker,
10775
+ changedContentEntries,
10776
+ pendingContentReloadEntryNames: [
10777
+ ...this.pendingContentReloadEntryNames
10778
+ ]
10779
+ });
10780
+ }
9289
10781
  } catch (error) {
9290
10782
  this.ctx.logger?.warn?.('[reload] watchRun inspect failed:', String(error));
9291
10783
  }
@@ -9296,43 +10788,600 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9296
10788
  if (hasErrors) return void done();
9297
10789
  try {
9298
10790
  const compilation = stats?.compilation;
9299
- const assetsArr = Array.isArray(compilation?.getAssets?.()) ? compilation.getAssets() : [];
9300
- const changed = assetsArr.filter((a)=>a?.emitted).map((a)=>String(a?.name || ''));
10791
+ const inferredHardReloadReason = this.inferHardReloadReasonFromSourceSignatures(compiler);
10792
+ const nextManifestSourceSignatures = this.collectManifestSourceSignatures(compiler);
10793
+ const nextLocaleSourceSignatures = this.collectLocaleSourceSignatures(compiler);
10794
+ const nextServiceWorkerSourceDependencyPaths = this.collectEntrypointModuleResourcePaths(compilation, 'background/service_worker');
10795
+ const nextServiceWorkerSourceSignatures = this.collectSourceSignaturesFromPaths(nextServiceWorkerSourceDependencyPaths);
10796
+ this.refreshContentScriptSourceDependencyPaths(compilation);
10797
+ this.serviceWorkerSourceDependencyPaths = nextServiceWorkerSourceDependencyPaths;
10798
+ this.serviceWorkerSourceSignatures = nextServiceWorkerSourceSignatures;
10799
+ this.manifestSourceSignatures = nextManifestSourceSignatures;
10800
+ this.localeSourceSignatures = nextLocaleSourceSignatures;
10801
+ const changed = this.collectChangedAssetNames(compilation);
10802
+ const contentScriptOutputRoot = this.ctx.getExtensionRoot() || String(compilation?.options?.output?.path || '');
10803
+ const nextContentScriptOutputSignatures = this.collectContentScriptOutputSignatures(compilation, contentScriptOutputRoot || void 0);
10804
+ const inferredEntryNamesFromOutputSignatures = this.inferContentReloadEntryNamesFromOutputSignatures(nextContentScriptOutputSignatures);
9301
10805
  const controller = this.host?.rdpController;
10806
+ if (!this.hasSeenFirstSuccessfulDone) {
10807
+ this.hasSeenFirstSuccessfulDone = true;
10808
+ this.contentScriptOutputSignaturesByEntry = nextContentScriptOutputSignatures;
10809
+ this.pendingContentReloadEntryNames = [];
10810
+ this.awaitingSettledContentBuild = false;
10811
+ this.lastWatchIncludedContentChanges = false;
10812
+ this.ctx.clearPendingReloadReason?.();
10813
+ if (controller && 'function' == typeof controller.reloadMatchingTabsForContentScripts) {
10814
+ const allRules = (0, content_script_targets.iw)(compilation, this.ctx.getExtensionRoot());
10815
+ if (allRules.length > 0) controller.reloadMatchingTabsForContentScripts(allRules).catch(()=>{});
10816
+ }
10817
+ done();
10818
+ return;
10819
+ }
9302
10820
  if (controller && 'function' == typeof controller.hardReload) {
9303
- const reason = this.ctx.getPendingReloadReason?.();
10821
+ const inferredAssetReason = this.inferHardReloadReasonFromChangedAssets(this.pendingContentReloadEntryNames.length > 0 ? changed.filter((a)=>'manifest.json' !== String(a || '').replace(/\\/g, '/')) : changed);
10822
+ const reason = this.ctx.getPendingReloadReason?.() || inferredHardReloadReason || inferredAssetReason;
10823
+ const inferredEntryNames = Array.from(new Set([
10824
+ ...this.inferContentReloadEntryNamesFromChangedAssets(changed),
10825
+ ...inferredEntryNamesFromOutputSignatures
10826
+ ]));
10827
+ this.contentScriptOutputSignaturesByEntry = nextContentScriptOutputSignatures;
10828
+ const targetEntryNames = this.pendingContentReloadEntryNames.length > 0 ? [
10829
+ ...this.pendingContentReloadEntryNames
10830
+ ] : inferredEntryNames;
10831
+ if (this.shouldEmitReloadActionEvent()) emitActionEvent('reload_debug', {
10832
+ phase: 'done',
10833
+ browser: this.host.browser,
10834
+ reason: reason || null,
10835
+ pendingContentReloadEntryNames: [
10836
+ ...this.pendingContentReloadEntryNames
10837
+ ],
10838
+ inferredEntryNamesFromOutputSignatures,
10839
+ inferredEntryNames,
10840
+ targetEntryNames,
10841
+ changedAssets: changed
10842
+ });
10843
+ if (!reason && 0 === targetEntryNames.length) {
10844
+ this.pendingContentReloadEntryNames = [];
10845
+ this.awaitingSettledContentBuild = false;
10846
+ this.lastWatchIncludedContentChanges = false;
10847
+ done();
10848
+ return;
10849
+ }
10850
+ if (!reason && targetEntryNames.length > 0 && 'function' == typeof controller.reloadMatchingTabsForContentScripts) {
10851
+ const selectedEntryNames = targetEntryNames;
10852
+ const selectedGeneration = this.contentReloadGeneration;
10853
+ const selectedRules = (0, content_script_targets.Il)((0, content_script_targets.iw)(compilation, this.ctx.getExtensionRoot()), selectedEntryNames);
10854
+ if (selectedRules.length > 0) {
10855
+ if (this.lastWatchIncludedContentChanges && this.contentReloadQuietPeriodMs > 0) {
10856
+ await new Promise((resolve)=>setTimeout(resolve, this.contentReloadQuietPeriodMs));
10857
+ if (selectedGeneration !== this.contentReloadGeneration) return void done();
10858
+ }
10859
+ await controller.reloadMatchingTabsForContentScripts(selectedRules);
10860
+ if (this.lastWatchIncludedContentChanges && this.contentReloadFollowupMs > 0) {
10861
+ await new Promise((resolve)=>setTimeout(resolve, this.contentReloadFollowupMs));
10862
+ if (selectedGeneration === this.contentReloadGeneration) await controller.reloadMatchingTabsForContentScripts(selectedRules);
10863
+ }
10864
+ }
10865
+ globalThis.__EXTJS_PENDING_FIREFOX_CONTENT_RELOAD__ = false;
10866
+ try {
10867
+ await globalThis.__EXTJS_ON_FIREFOX_CONTENT_RELOADED__?.();
10868
+ } catch {}
10869
+ if (this.awaitingSettledContentBuild && this.lastWatchIncludedContentChanges) ;
10870
+ else {
10871
+ this.pendingContentReloadEntryNames = [];
10872
+ this.awaitingSettledContentBuild = false;
10873
+ }
10874
+ if (this.awaitingSettledContentBuild && !this.lastWatchIncludedContentChanges) {
10875
+ this.pendingContentReloadEntryNames = [];
10876
+ this.awaitingSettledContentBuild = false;
10877
+ }
10878
+ done();
10879
+ return;
10880
+ }
9304
10881
  if (this.shouldEmitReloadActionEvent()) emitActionEvent('extension_reload', {
9305
10882
  reason: reason || 'unknown',
9306
10883
  browser: this.host.browser
9307
10884
  });
10885
+ this.pendingContentReloadEntryNames = [];
10886
+ globalThis.__EXTJS_PENDING_FIREFOX_CONTENT_RELOAD__ = false;
10887
+ this.ctx.clearPendingReloadReason?.();
9308
10888
  await controller.hardReload(stats.compilation, changed);
10889
+ if ('function' == typeof controller.reloadMatchingTabsForContentScripts) {
10890
+ const allContentRules = (0, content_script_targets.iw)(compilation, this.ctx.getExtensionRoot());
10891
+ if (allContentRules.length > 0) await controller.reloadMatchingTabsForContentScripts(allContentRules);
10892
+ }
10893
+ if (this.host.watchSource || this.host.source) this.host.__extjsForceSourceReinspect = true;
10894
+ }
10895
+ } catch {}
10896
+ done();
10897
+ });
10898
+ }
10899
+ shouldEmitReloadActionEvent() {
10900
+ return Boolean(this.host.source || this.host.watchSource);
10901
+ }
10902
+ refreshContentScriptSourceDependencyPaths(compilation) {
10903
+ this.contentScriptSourceDependencyPathsByEntry = (0, content_script_targets.im)(compilation);
10904
+ if (this.shouldEmitReloadActionEvent()) {
10905
+ const summary = Array.from(this.contentScriptSourceDependencyPathsByEntry.entries()).map(([entryName, dependencyPaths])=>{
10906
+ const matches = [
10907
+ ...dependencyPaths
10908
+ ].filter((dependencyPath)=>/contentapp\.(t|j)sx?$/i.test(dependencyPath));
10909
+ return `${entryName}:${dependencyPaths.size}${matches.length ? `:has-ContentApp=${matches.join('|')}` : ''}`;
10910
+ }).join(', ');
10911
+ emitActionEvent('reload_debug', {
10912
+ phase: 'dependencies',
10913
+ browser: this.host.browser,
10914
+ summary: summary || '<none>'
10915
+ });
10916
+ }
10917
+ }
10918
+ collectManifestSourceSignatures(compiler) {
10919
+ return this.collectSourceSignaturesFromPaths(this.getWatchedManifestSourcePaths(compiler));
10920
+ }
10921
+ collectLocaleSourceSignatures(compiler) {
10922
+ const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
10923
+ if (!compilerContextRoot) return new Map();
10924
+ const localesRoot = external_path_.join(compilerContextRoot, 'src', '_locales');
10925
+ const discoveredLocaleFiles = [];
10926
+ const walk = (dirPath)=>{
10927
+ let entries;
10928
+ try {
10929
+ entries = external_fs_.readdirSync(dirPath, {
10930
+ withFileTypes: true
10931
+ });
10932
+ } catch {
10933
+ return;
10934
+ }
10935
+ for (const entry of entries){
10936
+ const absoluteEntryPath = external_path_.join(dirPath, entry.name);
10937
+ if (entry.isDirectory()) {
10938
+ walk(absoluteEntryPath);
10939
+ continue;
10940
+ }
10941
+ if (entry.isFile() && absoluteEntryPath.endsWith('.json')) discoveredLocaleFiles.push(absoluteEntryPath.replace(/\\/g, '/'));
10942
+ }
10943
+ };
10944
+ walk(localesRoot);
10945
+ return this.collectSourceSignaturesFromPaths(discoveredLocaleFiles);
10946
+ }
10947
+ collectSourceSignaturesFromPaths(dependencyPaths) {
10948
+ const signatures = new Map();
10949
+ for (const dependencyPath of dependencyPaths){
10950
+ const normalizedDependencyPath = String(dependencyPath).replace(/\\/g, '/');
10951
+ const signature = this.readSourceFileSignature(normalizedDependencyPath);
10952
+ if (signature) signatures.set(normalizedDependencyPath, signature);
10953
+ }
10954
+ return signatures;
10955
+ }
10956
+ inferHardReloadReasonFromSourceSignatures(compiler) {
10957
+ const nextManifestSourceSignatures = this.collectManifestSourceSignatures(compiler);
10958
+ if (this.haveSourceSignaturesChanged(this.manifestSourceSignatures, nextManifestSourceSignatures)) return 'manifest';
10959
+ const nextLocaleSourceSignatures = this.collectLocaleSourceSignatures(compiler);
10960
+ if (this.haveSourceSignaturesChanged(this.localeSourceSignatures, nextLocaleSourceSignatures)) return 'locales';
10961
+ const nextServiceWorkerSourceSignatures = this.collectSourceSignaturesFromPaths(this.serviceWorkerSourceDependencyPaths);
10962
+ if (this.haveSourceSignaturesChanged(this.serviceWorkerSourceSignatures, nextServiceWorkerSourceSignatures)) return 'sw';
10963
+ }
10964
+ haveSourceSignaturesChanged(previousSignatures, nextSignatures) {
10965
+ if (0 === previousSignatures.size) return false;
10966
+ if (previousSignatures.size !== nextSignatures.size) return true;
10967
+ for (const [dependencyPath, previousSignature] of previousSignatures){
10968
+ const nextSignature = nextSignatures.get(dependencyPath);
10969
+ if (!nextSignature || nextSignature !== previousSignature) return true;
10970
+ }
10971
+ return false;
10972
+ }
10973
+ collectChangedAssetNames(compilation) {
10974
+ const changed = new Set();
10975
+ const assetsArr = Array.isArray(compilation?.getAssets?.()) ? compilation.getAssets() : [];
10976
+ for (const asset of assetsArr){
10977
+ if (!asset?.emitted) continue;
10978
+ const assetName = String(asset?.name || '').replace(/\\/g, '/');
10979
+ if (assetName) changed.add(assetName);
10980
+ }
10981
+ const assetsInfo = compilation?.assetsInfo;
10982
+ if (assetsInfo instanceof Map) for (const key of assetsInfo.keys()){
10983
+ const assetName = String(key || '').replace(/\\/g, '/');
10984
+ if (assetName) changed.add(assetName);
10985
+ }
10986
+ return Array.from(changed);
10987
+ }
10988
+ inferHardReloadReasonFromChangedAssets(changedAssets) {
10989
+ for (const assetName of changedAssets){
10990
+ const normalizedAssetName = String(assetName || '').replace(/\\/g, '/');
10991
+ if (normalizedAssetName) {
10992
+ if ('manifest.json' === normalizedAssetName) return 'manifest';
10993
+ if (/(^|\/)_locales\/.+\.json$/i.test(normalizedAssetName)) return 'locales';
10994
+ if (/(^|\/)background\/(service_worker|script)\.(m?js|cjs)$/i.test(normalizedAssetName)) return 'sw';
10995
+ }
10996
+ }
10997
+ }
10998
+ inferContentReloadEntryNamesFromChangedAssets(changedAssets) {
10999
+ const entries = new Set();
11000
+ for (const assetName of changedAssets){
11001
+ const normalizedAssetName = String(assetName || '').replace(/\\/g, '/');
11002
+ if (!(0, content_script_targets.HE)(normalizedAssetName)) continue;
11003
+ const canonicalAsset = (0, contracts.es)(normalizedAssetName);
11004
+ if (canonicalAsset) entries.add((0, contracts.Y0)(canonicalAsset.index));
11005
+ }
11006
+ return Array.from(entries);
11007
+ }
11008
+ inferContentReloadEntryNamesFromOutputSignatures(nextOutputSignaturesByEntry) {
11009
+ const changedEntries = new Set();
11010
+ for (const [entryName, nextOutputSignatures] of nextOutputSignaturesByEntry.entries()){
11011
+ const previousOutputSignatures = this.contentScriptOutputSignaturesByEntry.get(entryName);
11012
+ if (previousOutputSignatures && 0 !== previousOutputSignatures.size) {
11013
+ if (previousOutputSignatures.size !== nextOutputSignatures.size) {
11014
+ changedEntries.add(entryName);
11015
+ continue;
11016
+ }
11017
+ for (const [outputFile, previousSignature] of previousOutputSignatures){
11018
+ const nextSignature = nextOutputSignatures.get(outputFile);
11019
+ if (!nextSignature || nextSignature !== previousSignature) {
11020
+ changedEntries.add(entryName);
11021
+ break;
11022
+ }
11023
+ }
11024
+ }
11025
+ }
11026
+ return Array.from(changedEntries).sort();
11027
+ }
11028
+ collectEntrypointModuleResourcePaths(compilation, entrypointName) {
11029
+ const collectedResourcePaths = new Set();
11030
+ const entrypoints = compilation?.entrypoints;
11031
+ const entrypoint = entrypoints?.get?.(entrypointName);
11032
+ if (!entrypoint) return collectedResourcePaths;
11033
+ const chunkGraph = compilation?.chunkGraph;
11034
+ if (!chunkGraph) return collectedResourcePaths;
11035
+ const entrypointChunks = Array.from(entrypoint?.chunks || []);
11036
+ for (const chunk of entrypointChunks){
11037
+ const modulesIterable = chunkGraph.getChunkModulesIterable?.(chunk) || chunkGraph.getChunkModulesIterableBySourceType?.(chunk, "javascript") || chunkGraph.getChunkModules?.(chunk);
11038
+ if (modulesIterable) for (const module of modulesIterable){
11039
+ const resourcePath = module?.resource || module?.rootModule?.resource || module?.originalSource?.()?.resource;
11040
+ if ('string' == typeof resourcePath && resourcePath.length > 0) collectedResourcePaths.add(resourcePath.replace(/\\/g, '/'));
11041
+ }
11042
+ }
11043
+ return collectedResourcePaths;
11044
+ }
11045
+ readSourceFileSignature(absoluteFilePath) {
11046
+ try {
11047
+ const stats = external_fs_.statSync(absoluteFilePath);
11048
+ if (!stats.isFile()) return;
11049
+ return `${stats.size}:${stats.mtimeMs}`;
11050
+ } catch {
11051
+ return;
11052
+ }
11053
+ }
11054
+ collectContentScriptOutputSignatures(compilation, extensionRoot) {
11055
+ const outputSignaturesByEntry = new Map();
11056
+ const entrypoints = compilation?.entrypoints;
11057
+ if (!entrypoints || !extensionRoot) return outputSignaturesByEntry;
11058
+ for (const [entryName] of entrypoints.entries()){
11059
+ if (!(0, content_script_targets.wH)(entryName)) continue;
11060
+ const entryFiles = this.collectEntrypointFiles(compilation, [
11061
+ entryName
11062
+ ]);
11063
+ const outputSignatures = new Map();
11064
+ for (const entryFile of entryFiles){
11065
+ const absoluteEntryFilePath = external_path_.join(extensionRoot, entryFile);
11066
+ const signature = this.readSourceFileSignature(absoluteEntryFilePath);
11067
+ if (signature) outputSignatures.set(entryFile, signature);
11068
+ }
11069
+ if (outputSignatures.size > 0) outputSignaturesByEntry.set(entryName, outputSignatures);
11070
+ }
11071
+ return outputSignaturesByEntry;
11072
+ }
11073
+ collectEntrypointFiles(compilation, entrypointNames) {
11074
+ const collectedFiles = new Set();
11075
+ const entrypoints = compilation?.entrypoints;
11076
+ if (!entrypoints) return [];
11077
+ for (const entrypointName of entrypointNames){
11078
+ const entrypoint = entrypoints.get?.(entrypointName);
11079
+ const entryFiles = 'function' == typeof entrypoint?.getFiles ? entrypoint.getFiles() : [];
11080
+ for (const file of entryFiles){
11081
+ const normalizedFile = String(file || '').replace(/\\/g, '/');
11082
+ if (!(!normalizedFile || normalizedFile.endsWith('.map'))) {
11083
+ if (!normalizedFile.startsWith('hot/')) collectedFiles.add(normalizedFile);
11084
+ }
11085
+ }
11086
+ }
11087
+ return Array.from(collectedFiles);
11088
+ }
11089
+ async waitForStableContentOutputs(extensionRoot, entryFiles, timeoutMs = 8000, pollIntervalMs = 150, stableReadsRequired = 2) {
11090
+ const normalizedEntryFiles = entryFiles.map((file)=>String(file || '').replace(/\\/g, '/')).filter(Boolean);
11091
+ if (0 === normalizedEntryFiles.length) return true;
11092
+ const start = Date.now();
11093
+ let lastSignature = '';
11094
+ let stableReads = 0;
11095
+ while(Date.now() - start < timeoutMs){
11096
+ const referencedFiles = new Set(normalizedEntryFiles);
11097
+ const signatureParts = [];
11098
+ let allFilesReady = true;
11099
+ for (const entryFile of normalizedEntryFiles){
11100
+ const absoluteEntryFilePath = external_path_.join(extensionRoot, entryFile);
11101
+ const signature = this.readStableFileSignature(absoluteEntryFilePath);
11102
+ if (!signature) {
11103
+ allFilesReady = false;
11104
+ break;
9309
11105
  }
9310
- } catch {}
9311
- done();
9312
- });
11106
+ signatureParts.push(`${entryFile}:${signature}`);
11107
+ if (entryFile.endsWith('.js')) {
11108
+ const source = this.readFileTextSafe(absoluteEntryFilePath);
11109
+ if (!source) {
11110
+ allFilesReady = false;
11111
+ break;
11112
+ }
11113
+ for (const referencedFile of this.extractReferencedOutputFiles(source))referencedFiles.add(referencedFile);
11114
+ }
11115
+ }
11116
+ if (!allFilesReady) {
11117
+ lastSignature = '';
11118
+ stableReads = 0;
11119
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
11120
+ continue;
11121
+ }
11122
+ for (const referencedFile of referencedFiles){
11123
+ if (normalizedEntryFiles.includes(referencedFile)) continue;
11124
+ const absoluteReferencedFilePath = external_path_.join(extensionRoot, referencedFile);
11125
+ const signature = this.readStableFileSignature(absoluteReferencedFilePath);
11126
+ if (!signature) {
11127
+ allFilesReady = false;
11128
+ break;
11129
+ }
11130
+ signatureParts.push(`${referencedFile}:${signature}`);
11131
+ }
11132
+ if (!allFilesReady) {
11133
+ lastSignature = '';
11134
+ stableReads = 0;
11135
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
11136
+ continue;
11137
+ }
11138
+ const currentSignature = signatureParts.sort().join('|');
11139
+ if (currentSignature === lastSignature) stableReads += 1;
11140
+ else {
11141
+ lastSignature = currentSignature;
11142
+ stableReads = 1;
11143
+ }
11144
+ if (stableReads >= stableReadsRequired) return true;
11145
+ await new Promise((resolve)=>setTimeout(resolve, pollIntervalMs));
11146
+ }
11147
+ return false;
9313
11148
  }
9314
- shouldEmitReloadActionEvent() {
9315
- return Boolean(this.host.source || this.host.watchSource);
11149
+ readStableFileSignature(absoluteFilePath) {
11150
+ try {
11151
+ const stats = external_fs_.statSync(absoluteFilePath);
11152
+ if (!stats.isFile()) return;
11153
+ return `${stats.size}:${stats.mtimeMs}`;
11154
+ } catch {
11155
+ return;
11156
+ }
11157
+ }
11158
+ readFileTextSafe(absoluteFilePath) {
11159
+ try {
11160
+ return external_fs_.readFileSync(absoluteFilePath, 'utf-8');
11161
+ } catch {
11162
+ return;
11163
+ }
11164
+ }
11165
+ extractReferencedOutputFiles(source) {
11166
+ const matches = source.match(/(?:content_scripts|assets)\/[^"'`\s)]+\.(?:css|js|json|png|jpg|jpeg|svg|gif|webp|ico|avif)/g);
11167
+ return Array.from(new Set(matches || []));
9316
11168
  }
9317
11169
  constructor(host, ctx){
9318
11170
  firefox_hard_reload_define_property(this, "host", void 0);
9319
11171
  firefox_hard_reload_define_property(this, "ctx", void 0);
11172
+ firefox_hard_reload_define_property(this, "hasSeenFirstSuccessfulDone", false);
11173
+ firefox_hard_reload_define_property(this, "serviceWorkerSourceDependencyPaths", new Set());
11174
+ firefox_hard_reload_define_property(this, "serviceWorkerSourceSignatures", new Map());
11175
+ firefox_hard_reload_define_property(this, "manifestSourceSignatures", new Map());
11176
+ firefox_hard_reload_define_property(this, "localeSourceSignatures", new Map());
11177
+ firefox_hard_reload_define_property(this, "contentScriptSourceDependencyPathsByEntry", new Map());
11178
+ firefox_hard_reload_define_property(this, "contentScriptOutputSignaturesByEntry", new Map());
11179
+ firefox_hard_reload_define_property(this, "pendingContentReloadEntryNames", []);
11180
+ firefox_hard_reload_define_property(this, "contentReloadGeneration", 0);
11181
+ firefox_hard_reload_define_property(this, "contentReloadQuietPeriodMs", 1200);
11182
+ firefox_hard_reload_define_property(this, "contentReloadFollowupMs", 1200);
11183
+ firefox_hard_reload_define_property(this, "lastWatchIncludedContentChanges", false);
11184
+ firefox_hard_reload_define_property(this, "awaitingSettledContentBuild", false);
9320
11185
  this.host = host;
9321
11186
  this.ctx = ctx;
9322
11187
  }
9323
11188
  }
11189
+ var evaluate = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/evaluate.ts");
11190
+ var remote_firefox_logging = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/logging.ts");
9324
11191
  var messaging_client = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/messaging-client.ts");
9325
- var logging = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/logging.ts");
11192
+ var external_url_ = __webpack_require__("url");
9326
11193
  const TARGET_SCAN_INTERVAL_MS = 250;
11194
+ function guessRepoRoot(startDir) {
11195
+ let dir = external_path_default().resolve(startDir);
11196
+ for(let depth = 0; depth < 24; depth++){
11197
+ if ((0, external_fs_.existsSync)(external_path_default().join(dir, 'programs', 'develop', 'package.json'))) return dir;
11198
+ const parent = external_path_default().dirname(dir);
11199
+ if (parent === dir) break;
11200
+ dir = parent;
11201
+ }
11202
+ dir = external_path_default().resolve(startDir);
11203
+ for(let depth = 0; depth < 16; depth++){
11204
+ if ((0, external_fs_.existsSync)(external_path_default().join(dir, 'pnpm-workspace.yaml')) || (0, external_fs_.existsSync)(external_path_default().join(dir, '.git'))) return dir;
11205
+ const parent = external_path_default().dirname(dir);
11206
+ if (parent === dir) break;
11207
+ dir = parent;
11208
+ }
11209
+ return null;
11210
+ }
11211
+ function guessRepoRootFromThisModule() {
11212
+ try {
11213
+ const here = external_path_default().dirname((0, external_url_.fileURLToPath)(__rslib_import_meta_url__));
11214
+ return guessRepoRoot(here);
11215
+ } catch {
11216
+ return null;
11217
+ }
11218
+ }
11219
+ function appendDebugLogLine(line) {
11220
+ const paths = [];
11221
+ const fromEnv = process.env.EXTENSION_DEBUG_SESSION_LOG;
11222
+ if ('string' == typeof fromEnv && fromEnv.length > 0) paths.push(fromEnv);
11223
+ const repoFromModule = guessRepoRootFromThisModule();
11224
+ if (repoFromModule) paths.push(external_path_default().join(repoFromModule, '.cursor', 'debug-a87efc.log'));
11225
+ const repoFromCwd = guessRepoRoot(process.cwd());
11226
+ if (repoFromCwd) paths.push(external_path_default().join(repoFromCwd, '.cursor', 'debug-a87efc.log'));
11227
+ for (const root of [
11228
+ process.env.INIT_CWD,
11229
+ process.env.PROJECT_ROOT,
11230
+ process.cwd()
11231
+ ])if ('string' == typeof root && root.length > 0) paths.push(external_path_default().join(root, '.cursor', 'debug-a87efc.log'));
11232
+ const seen = new Set();
11233
+ for (const filePath of paths)if (!seen.has(filePath)) {
11234
+ seen.add(filePath);
11235
+ try {
11236
+ (0, external_fs_.mkdirSync)(external_path_default().dirname(filePath), {
11237
+ recursive: true
11238
+ });
11239
+ (0, external_fs_.appendFileSync)(filePath, `${line}\n`);
11240
+ return;
11241
+ } catch {}
11242
+ }
11243
+ console.error('[extension-develop][debug-session a87efc] log file write failed', line);
11244
+ }
11245
+ function agentDebugLog(payload) {
11246
+ const line = JSON.stringify({
11247
+ sessionId: 'a87efc',
11248
+ timestamp: Date.now(),
11249
+ ...payload
11250
+ });
11251
+ fetch('http://127.0.0.1:7795/ingest/9eb8f923-a325-4455-a46c-a6e706558307', {
11252
+ method: 'POST',
11253
+ headers: {
11254
+ 'Content-Type': 'application/json',
11255
+ 'X-Debug-Session-Id': 'a87efc'
11256
+ },
11257
+ body: line
11258
+ }).catch(()=>{});
11259
+ appendDebugLogLine(line);
11260
+ }
11261
+ function shouldDeferFallbackUntilExactMatch(normalizedUrl) {
11262
+ try {
11263
+ const parsed = new URL(String(normalizedUrl || ''));
11264
+ return 'http:' === parsed.protocol || 'https:' === parsed.protocol || 'file:' === parsed.protocol || 'moz-extension:' === parsed.protocol || 'chrome-extension:' === parsed.protocol || 'edge:' === parsed.protocol;
11265
+ } catch {
11266
+ return false;
11267
+ }
11268
+ }
11269
+ async function findActorsMatchingLiveHref(client, allTargets, normalizedUrlToInspect) {
11270
+ const withActor = allTargets.filter((t)=>t && 'string' == typeof t.actor);
11271
+ for(let i = withActor.length - 1; i >= 0; i--){
11272
+ const target = withActor[i];
11273
+ const tabActor = String(target.actor);
11274
+ let consoleActor = 'string' == typeof target.consoleActor && target.consoleActor.length > 0 ? target.consoleActor : void 0;
11275
+ if (!consoleActor || consoleActor === tabActor) try {
11276
+ const detail = await client.getTargetFromDescriptor(tabActor);
11277
+ if ('string' == typeof detail.consoleActor && detail.consoleActor.length > 0) consoleActor = detail.consoleActor;
11278
+ } catch {}
11279
+ if (consoleActor) try {
11280
+ const hrefRaw = await client.evaluate(consoleActor, 'String(location.href || "")');
11281
+ const href = 'string' == typeof hrefRaw ? hrefRaw : String(hrefRaw ?? '');
11282
+ if (setup_firefox_inspection_actors_normalizeInspectableUrl(href) === normalizedUrlToInspect) return {
11283
+ tabActor,
11284
+ consoleActor
11285
+ };
11286
+ } catch {}
11287
+ }
11288
+ return null;
11289
+ }
11290
+ function setup_firefox_inspection_actors_normalizeInspectableUrl(rawUrl) {
11291
+ try {
11292
+ const parsed = new URL(String(rawUrl || ''));
11293
+ if (('http:' === parsed.protocol || 'https:' === parsed.protocol) && '/' === parsed.pathname) parsed.pathname = '';
11294
+ parsed.hash = '';
11295
+ return parsed.toString();
11296
+ } catch {
11297
+ return String(rawUrl || '').trim().replace(/\/$/, '');
11298
+ }
11299
+ }
9327
11300
  async function selectActors(client, urlToInspect) {
9328
11301
  const deadline = Date.now() + 10000;
9329
11302
  let triedAddTab = false;
11303
+ const normalizedUrlToInspect = setup_firefox_inspection_actors_normalizeInspectableUrl(urlToInspect);
9330
11304
  while(Date.now() < deadline){
9331
11305
  const allTargets = await client.getTargets() || [];
9332
- for (const target of allTargets)if (target && 'string' == typeof target.url && target.url === urlToInspect && target.actor) return {
9333
- tabActor: target.actor,
9334
- consoleActor: target.consoleActor || target.actor
9335
- };
11306
+ const exactMatches = allTargets.filter((target)=>target && 'string' == typeof target.url && setup_firefox_inspection_actors_normalizeInspectableUrl(target.url) === normalizedUrlToInspect && target.actor);
11307
+ const exactMatch = exactMatches.length > 0 ? exactMatches[exactMatches.length - 1] : void 0;
11308
+ if (exactMatch?.actor) {
11309
+ const matchDiagnostics = [];
11310
+ for (const target of exactMatches.slice(-5)){
11311
+ const actor = String(target.actor || '');
11312
+ const consoleActor = String(target.consoleActor || actor);
11313
+ let hostCount;
11314
+ let href;
11315
+ try {
11316
+ const probe = await client.evaluate(consoleActor, `(() => JSON.stringify({
11317
+ href: String(location.href || ''),
11318
+ readyState: String(document.readyState || ''),
11319
+ hostCount: document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])').length
11320
+ }))()`);
11321
+ if ('string' == typeof probe && probe) {
11322
+ const parsed = JSON.parse(probe);
11323
+ hostCount = 'number' == typeof parsed?.hostCount ? parsed.hostCount : void 0;
11324
+ href = 'string' == typeof parsed?.href ? parsed.href : void 0;
11325
+ }
11326
+ } catch {}
11327
+ matchDiagnostics.push({
11328
+ actor,
11329
+ consoleActor,
11330
+ url: target.url || '',
11331
+ href,
11332
+ hostCount
11333
+ });
11334
+ }
11335
+ agentDebugLog({
11336
+ runId: process.env.EXTENSION_INSTANCE_ID || 'firefox-select-actors',
11337
+ hypothesisId: 'H20',
11338
+ location: 'setup-firefox-inspection-actors.ts:exact-match-selection',
11339
+ message: 'Firefox exact URL match selection diagnostics',
11340
+ data: {
11341
+ urlToInspect,
11342
+ selectedActor: exactMatch.actor,
11343
+ selectedConsoleActor: exactMatch.consoleActor || exactMatch.actor,
11344
+ matchDiagnostics
11345
+ }
11346
+ });
11347
+ return {
11348
+ tabActor: exactMatch.actor,
11349
+ consoleActor: exactMatch.consoleActor || exactMatch.actor
11350
+ };
11351
+ }
11352
+ if (shouldDeferFallbackUntilExactMatch(normalizedUrlToInspect)) {
11353
+ const livePair = await findActorsMatchingLiveHref(client, allTargets, normalizedUrlToInspect);
11354
+ if (livePair) {
11355
+ let hostCount;
11356
+ let href;
11357
+ try {
11358
+ const probe = await client.evaluate(livePair.consoleActor, `(() => JSON.stringify({
11359
+ href: String(location.href || ''),
11360
+ readyState: String(document.readyState || ''),
11361
+ hostCount: document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])').length
11362
+ }))()`);
11363
+ if ('string' == typeof probe && probe) {
11364
+ const parsed = JSON.parse(probe);
11365
+ hostCount = 'number' == typeof parsed?.hostCount ? parsed.hostCount : void 0;
11366
+ href = 'string' == typeof parsed?.href ? parsed.href : void 0;
11367
+ }
11368
+ } catch {}
11369
+ agentDebugLog({
11370
+ runId: process.env.EXTENSION_INSTANCE_ID || 'firefox-select-actors',
11371
+ hypothesisId: 'H23',
11372
+ location: 'setup-firefox-inspection-actors.ts:live-href-match',
11373
+ message: 'Firefox actor matched by live location.href (listTabs URL was stale)',
11374
+ data: {
11375
+ urlToInspect,
11376
+ selectedActor: livePair.tabActor,
11377
+ selectedConsoleActor: livePair.consoleActor,
11378
+ href,
11379
+ hostCount
11380
+ }
11381
+ });
11382
+ return livePair;
11383
+ }
11384
+ }
9336
11385
  if (!triedAddTab && urlToInspect) {
9337
11386
  triedAddTab = true;
9338
11387
  try {
@@ -9346,15 +11395,48 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9346
11395
  }
9347
11396
  }
9348
11397
  }
9349
- for (const target of allTargets)if (target && ('string' == typeof target.actor || 'number' == typeof target.outerWindowID || 'number' == typeof target.outerWindowId)) return {
9350
- tabActor: String(target.actor || ''),
9351
- consoleActor: String(target.consoleActor || target.actor || '')
9352
- };
11398
+ if (!shouldDeferFallbackUntilExactMatch(normalizedUrlToInspect)) {
11399
+ for (const target of allTargets)if (target && ('string' == typeof target.actor || 'number' == typeof target.outerWindowID || 'number' == typeof target.outerWindowId)) {
11400
+ agentDebugLog({
11401
+ runId: process.env.EXTENSION_INSTANCE_ID || 'firefox-select-actors',
11402
+ hypothesisId: 'H21',
11403
+ location: 'setup-firefox-inspection-actors.ts:fallback-selection',
11404
+ message: 'Firefox actor selection fell back to first valid target',
11405
+ data: {
11406
+ urlToInspect,
11407
+ selectedActor: String(target.actor || ''),
11408
+ selectedConsoleActor: String(target.consoleActor || target.actor || ''),
11409
+ targets: allTargets.slice(0, 10).map((item, index)=>({
11410
+ index,
11411
+ actor: String(item?.actor || ''),
11412
+ consoleActor: String(item?.consoleActor || ''),
11413
+ url: String(item?.url || ''),
11414
+ outerWindowID: 'number' == typeof item?.outerWindowID ? item.outerWindowID : void 0,
11415
+ outerWindowId: 'number' == typeof item?.outerWindowId ? item.outerWindowId : void 0
11416
+ }))
11417
+ }
11418
+ });
11419
+ return {
11420
+ tabActor: String(target.actor || ''),
11421
+ consoleActor: String(target.consoleActor || target.actor || '')
11422
+ };
11423
+ }
11424
+ }
9353
11425
  await new Promise((r)=>setTimeout(r, TARGET_SCAN_INTERVAL_MS));
9354
11426
  }
9355
11427
  throw new Error(browsers_lib_messages.Itp());
9356
11428
  }
9357
11429
  const PAGE_READY_TIMEOUT_MS = 8000;
11430
+ function setup_firefox_inspection_navigation_normalizeInspectableUrl(rawUrl) {
11431
+ try {
11432
+ const parsed = new URL(String(rawUrl || ''));
11433
+ if (('http:' === parsed.protocol || 'https:' === parsed.protocol) && '/' === parsed.pathname) parsed.pathname = '';
11434
+ parsed.hash = '';
11435
+ return parsed.toString();
11436
+ } catch {
11437
+ return String(rawUrl || '').trim().replace(/\/$/, '');
11438
+ }
11439
+ }
9358
11440
  async function ensureNavigatedAndLoaded(client, urlToInspect, tabActor) {
9359
11441
  if (!tabActor) throw new Error(browsers_lib_messages.R4W());
9360
11442
  let consoleActor = tabActor;
@@ -9377,6 +11459,31 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9377
11459
  console.warn('[RDP] attach(frameActor) failed:', String(err.message || err));
9378
11460
  }
9379
11461
  }
11462
+ try {
11463
+ const currentUrl = await client.evaluate(consoleActor, 'String(location.href || "")');
11464
+ const sameDocumentTarget = 'string' == typeof currentUrl && setup_firefox_inspection_navigation_normalizeInspectableUrl(currentUrl) === setup_firefox_inspection_navigation_normalizeInspectableUrl(urlToInspect);
11465
+ if (sameDocumentTarget) {
11466
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE || '1' === process.env.EXTENSION_DEBUG_FIREFOX_INSPECTION) console.log(`[RDP] forcing native same-url reload for ${urlToInspect}`);
11467
+ const detail = await client.getTargetFromDescriptor(tabActor);
11468
+ const targetActor = detail.targetActor || frameActor || tabActor;
11469
+ try {
11470
+ await client.attach(targetActor);
11471
+ } catch (error) {
11472
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
11473
+ const err = error;
11474
+ console.warn('[RDP] attach(targetActor for same-url reload) failed:', String(err.message || err));
11475
+ }
11476
+ }
11477
+ await client.navigate(targetActor, urlToInspect);
11478
+ await client.waitForLoadEvent(targetActor);
11479
+ return;
11480
+ }
11481
+ } catch (error) {
11482
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
11483
+ const err = error;
11484
+ console.warn('[RDP] current URL check before navigate failed:', String(err.message || err));
11485
+ }
11486
+ }
9380
11487
  try {
9381
11488
  await client.navigateViaScript(consoleActor, urlToInspect);
9382
11489
  await client.waitForPageReady(consoleActor, urlToInspect, PAGE_READY_TIMEOUT_MS);
@@ -9645,6 +11752,10 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9645
11752
  }
9646
11753
  })()`);
9647
11754
  this.emitEventPayload('page_meta', stage, meta, metaSnapshot || {});
11755
+ const rootMeta = await this.getExtensionRootMeta();
11756
+ if (rootMeta) this.emitEventPayload('extension_root_meta', stage, meta, rootMeta);
11757
+ const styleSnapshot = await this.getShadowStyleSnapshot();
11758
+ if (styleSnapshot) this.emitEventPayload('shadow_style_output', stage, meta, styleSnapshot);
9648
11759
  }
9649
11760
  if (Array.isArray(this.devOptions?.sourceProbe)) {
9650
11761
  const probes = await this.evaluateJson(this.currentConsoleActor, `(() => {
@@ -9679,7 +11790,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9679
11790
  }
9680
11791
  if (this.devOptions?.sourceTree && 'off' !== this.devOptions.sourceTree) {
9681
11792
  const tree = await this.evaluateJson(this.currentConsoleActor, `(() => {
9682
- const rootEl = document.querySelector('#extension-root,[data-extension-root="true"]');
11793
+ const rootEl = document.querySelector('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])');
9683
11794
  if (!rootEl) return null;
9684
11795
  const root = (${'off' !== this.devOptions.sourceIncludeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
9685
11796
  const maxDepth = 4;
@@ -9760,11 +11871,238 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9760
11871
  if ('string' == typeof json && json.length > 0) return JSON.parse(json);
9761
11872
  } catch {}
9762
11873
  }
11874
+ async evaluateString(actor, expression) {
11875
+ if (!this.client) return;
11876
+ try {
11877
+ const response = await this.client.evaluateRaw(actor, expression);
11878
+ const value = await (0, evaluate.vA)(this.client, actor, response, {
11879
+ fallbackToFullDocument: false
11880
+ });
11881
+ return 'string' == typeof value ? value : String(value || '');
11882
+ } catch {
11883
+ return;
11884
+ }
11885
+ }
11886
+ async getShadowStyleSnapshot() {
11887
+ if (!this.client || !this.currentConsoleActor) return;
11888
+ try {
11889
+ const count = await this.client.evaluate(this.currentConsoleActor, `(() => {
11890
+ try {
11891
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
11892
+ for (const host of hosts) {
11893
+ const sr = host && host.shadowRoot;
11894
+ if (!sr) continue;
11895
+ const childStyleCount = Array.from(sr.childNodes || []).filter((node) => {
11896
+ try {
11897
+ return (
11898
+ node &&
11899
+ node.nodeType === 1 &&
11900
+ String(node.nodeName || '').toLowerCase() === 'style'
11901
+ )
11902
+ } catch {
11903
+ return false
11904
+ }
11905
+ }).length
11906
+ if (childStyleCount > 0) return childStyleCount
11907
+ return Array.from(sr.querySelectorAll('style')).length;
11908
+ }
11909
+ return 0;
11910
+ } catch {
11911
+ return 0;
11912
+ }
11913
+ })()`);
11914
+ const totalCount = Number(count || 0);
11915
+ const childNodeCss = await this.evaluateString(this.currentConsoleActor, `(() => {
11916
+ try {
11917
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
11918
+ for (const host of hosts) {
11919
+ const sr = host && host.shadowRoot;
11920
+ if (!sr) continue;
11921
+ const css = Array.from(sr.childNodes || [])
11922
+ .map((node) => {
11923
+ try {
11924
+ if (!node || node.nodeType !== 1) return '';
11925
+ if (String(node.nodeName || '').toLowerCase() !== 'style') return '';
11926
+ return String(node.textContent || '');
11927
+ } catch {
11928
+ return '';
11929
+ }
11930
+ })
11931
+ .filter(Boolean)
11932
+ .join('\\n');
11933
+ return css;
11934
+ }
11935
+ return '';
11936
+ } catch {
11937
+ return '';
11938
+ }
11939
+ })()`);
11940
+ const adoptedCss = await this.evaluateString(this.currentConsoleActor, `(() => {
11941
+ try {
11942
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
11943
+ for (const host of hosts) {
11944
+ const sr = host && host.shadowRoot;
11945
+ if (!sr) continue;
11946
+ const sheets = Array.from(sr.adoptedStyleSheets || []);
11947
+ const css = sheets
11948
+ .map((sheet) => {
11949
+ try {
11950
+ return Array.from(sheet.cssRules || [])
11951
+ .map((rule) => String(rule.cssText || ''))
11952
+ .join('\\n');
11953
+ } catch {
11954
+ return '';
11955
+ }
11956
+ })
11957
+ .filter(Boolean)
11958
+ .join('\\n');
11959
+ return css;
11960
+ }
11961
+ return '';
11962
+ } catch {
11963
+ return '';
11964
+ }
11965
+ })()`);
11966
+ const stylesheetCss = await this.evaluateString(this.currentConsoleActor, `(() => {
11967
+ try {
11968
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
11969
+ for (const host of hosts) {
11970
+ const sr = host && host.shadowRoot;
11971
+ if (!sr) continue;
11972
+ const sheets = Array.from(sr.styleSheets || []);
11973
+ const css = sheets
11974
+ .map((sheet) => {
11975
+ try {
11976
+ return Array.from(sheet.cssRules || [])
11977
+ .map((rule) => String(rule.cssText || ''))
11978
+ .join('\\n');
11979
+ } catch {
11980
+ return '';
11981
+ }
11982
+ })
11983
+ .filter(Boolean)
11984
+ .join('\\n');
11985
+ return css;
11986
+ }
11987
+ return '';
11988
+ } catch {
11989
+ return '';
11990
+ }
11991
+ })()`);
11992
+ if ((!Number.isFinite(totalCount) || totalCount <= 0) && !('string' == typeof childNodeCss && childNodeCss.trim().length > 0) && !('string' == typeof adoptedCss && adoptedCss.trim().length > 0) && !('string' == typeof stylesheetCss && stylesheetCss.trim().length > 0)) return;
11993
+ if ('string' == typeof childNodeCss && childNodeCss.trim().length > 0) return {
11994
+ rootMode: 'shadow',
11995
+ count: totalCount > 0 ? totalCount : 1,
11996
+ styles: [
11997
+ {
11998
+ html: `<style>${childNodeCss}</style>`,
11999
+ textLength: childNodeCss.length,
12000
+ textSnippet: childNodeCss.trim().slice(0, 200)
12001
+ }
12002
+ ]
12003
+ };
12004
+ if ('string' == typeof adoptedCss && adoptedCss.trim().length > 0) return {
12005
+ rootMode: 'shadow',
12006
+ count: totalCount > 0 ? totalCount : 1,
12007
+ styles: [
12008
+ {
12009
+ html: `<style>${adoptedCss}</style>`,
12010
+ textLength: adoptedCss.length,
12011
+ textSnippet: adoptedCss.trim().slice(0, 200)
12012
+ }
12013
+ ]
12014
+ };
12015
+ if ('string' == typeof stylesheetCss && stylesheetCss.trim().length > 0) return {
12016
+ rootMode: 'shadow',
12017
+ count: totalCount > 0 ? totalCount : 1,
12018
+ styles: [
12019
+ {
12020
+ html: `<style>${stylesheetCss}</style>`,
12021
+ textLength: stylesheetCss.length,
12022
+ textSnippet: stylesheetCss.trim().slice(0, 200)
12023
+ }
12024
+ ]
12025
+ };
12026
+ const shadowHtml = await this.evaluateString(this.currentConsoleActor, `(() => {
12027
+ try {
12028
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
12029
+ for (const host of hosts) {
12030
+ const sr = host && host.shadowRoot;
12031
+ if (!sr) continue;
12032
+ return String(sr.innerHTML || '');
12033
+ }
12034
+ return '';
12035
+ } catch {
12036
+ return '';
12037
+ }
12038
+ })()`);
12039
+ if ('string' == typeof shadowHtml && shadowHtml.includes('<style')) {
12040
+ const matches = Array.from(shadowHtml.matchAll(/<style[\s\S]*?<\/style>/g)).slice(0, 3);
12041
+ if (matches.length > 0) return {
12042
+ rootMode: 'shadow',
12043
+ count: totalCount,
12044
+ styles: matches.map((match)=>{
12045
+ const html = String(match[0] || '');
12046
+ const text = html.replace(/<style[^>]*>|<\/style>/g, '');
12047
+ return {
12048
+ html,
12049
+ textLength: text.length,
12050
+ textSnippet: text.trim().slice(0, 200)
12051
+ };
12052
+ })
12053
+ };
12054
+ }
12055
+ const styles = [];
12056
+ const sampleCount = Math.min(totalCount, 3);
12057
+ for(let index = 0; index < sampleCount; index++){
12058
+ const selectStyleExpression = `(() => {
12059
+ try {
12060
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
12061
+ for (const host of hosts) {
12062
+ const sr = host && host.shadowRoot;
12063
+ if (!sr) continue;
12064
+ const styleEl = Array.from(sr.querySelectorAll('style'))[${index}];
12065
+ if (!styleEl) return null;
12066
+ return styleEl;
12067
+ }
12068
+ return null;
12069
+ } catch {
12070
+ return null;
12071
+ }
12072
+ })()`;
12073
+ const html = await this.evaluateString(this.currentConsoleActor, `(() => {
12074
+ const styleEl = ${selectStyleExpression};
12075
+ return styleEl ? String(styleEl.outerHTML || '') : '';
12076
+ })()`);
12077
+ const textLength = await this.client.evaluate(this.currentConsoleActor, `(() => {
12078
+ const styleEl = ${selectStyleExpression};
12079
+ return styleEl ? String(styleEl.textContent || '').length : 0;
12080
+ })()`);
12081
+ const textSnippet = await this.evaluateString(this.currentConsoleActor, `(() => {
12082
+ const styleEl = ${selectStyleExpression};
12083
+ return styleEl ? String(styleEl.textContent || '').trim().slice(0, 200) : '';
12084
+ })()`);
12085
+ if ('string' == typeof html && html.length > 0) styles.push({
12086
+ html,
12087
+ textLength: Number(textLength || 0),
12088
+ textSnippet: 'string' == typeof textSnippet ? textSnippet : String(textSnippet || '')
12089
+ });
12090
+ }
12091
+ if (0 === styles.length) return;
12092
+ return {
12093
+ rootMode: 'shadow',
12094
+ count: totalCount,
12095
+ styles
12096
+ };
12097
+ } catch {
12098
+ return;
12099
+ }
12100
+ }
9763
12101
  async getDomSnapshot() {
9764
12102
  if (!this.client || !this.currentConsoleActor) return;
9765
12103
  const includeShadow = this.devOptions?.sourceIncludeShadow !== 'off';
9766
12104
  const payload = await this.evaluateJson(this.currentConsoleActor, `(() => {
9767
- const rootEl = document.querySelector('#extension-root,[data-extension-root="true"]');
12105
+ const rootEl = document.querySelector('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])');
9768
12106
  if (!rootEl) return null;
9769
12107
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
9770
12108
  const maxDepth = 6;
@@ -9824,6 +12162,173 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9824
12162
  truncated,
9825
12163
  nodes
9826
12164
  };
12165
+ })()`);
12166
+ if (payload && 'object' == typeof payload) return payload;
12167
+ }
12168
+ async getExtensionRootMeta() {
12169
+ if (!this.client || !this.currentConsoleActor) return;
12170
+ const payload = await this.evaluateJson(this.currentConsoleActor, `(() => {
12171
+ const readGeneration = (node) => {
12172
+ try {
12173
+ const raw = node && node.getAttribute
12174
+ ? node.getAttribute('data-extjs-reinject-generation')
12175
+ : '';
12176
+ if (typeof raw !== 'string' || raw.trim() === '') return undefined;
12177
+ const parsed = Number(raw);
12178
+ return Number.isFinite(parsed) ? parsed : undefined;
12179
+ } catch (error) {
12180
+ return undefined;
12181
+ }
12182
+ };
12183
+ const readRegistryGeneration = (entry) => {
12184
+ try {
12185
+ if (!entry) return undefined;
12186
+ if (typeof entry === 'function' && typeof entry.__extjsGeneration === 'number') {
12187
+ return entry.__extjsGeneration;
12188
+ }
12189
+ if (typeof entry === 'object') {
12190
+ if (typeof entry.__extjsGeneration === 'number') return entry.__extjsGeneration;
12191
+ if (typeof entry.generation === 'number') return entry.generation;
12192
+ if (typeof entry.cleanup === 'function' && typeof entry.cleanup.__extjsGeneration === 'number') {
12193
+ return entry.cleanup.__extjsGeneration;
12194
+ }
12195
+ }
12196
+ } catch (error) {
12197
+ return undefined;
12198
+ }
12199
+ return undefined;
12200
+ };
12201
+ const normalize = (node) => ({
12202
+ tag: node && node.tagName ? String(node.tagName).toLowerCase() : 'unknown',
12203
+ id: node && node.id ? String(node.id) : undefined,
12204
+ key: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-key') || undefined : undefined,
12205
+ generation: readGeneration(node),
12206
+ status: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-status') || undefined : undefined,
12207
+ build: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-build') || undefined : undefined
12208
+ });
12209
+ const roots = Array.from(
12210
+ document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])')
12211
+ )
12212
+ .slice(0, 10)
12213
+ .map(normalize);
12214
+ const page = (() => {
12215
+ try {
12216
+ const node = document.documentElement;
12217
+ if (!node || typeof node.getAttribute !== 'function') return undefined;
12218
+ const raw = node.getAttribute('data-extjs-last-reinject-generation');
12219
+ const generation =
12220
+ typeof raw === 'string' && raw.trim() !== '' && Number.isFinite(Number(raw))
12221
+ ? Number(raw)
12222
+ : undefined;
12223
+ return {
12224
+ key: node.getAttribute('data-extjs-last-reinject-key') || undefined,
12225
+ generation,
12226
+ status: node.getAttribute('data-extjs-last-reinject-status') || undefined,
12227
+ build: node.getAttribute('data-extjs-last-reinject-build') || undefined
12228
+ };
12229
+ } catch (error) {
12230
+ return undefined;
12231
+ }
12232
+ })();
12233
+ const debug = (() => {
12234
+ try {
12235
+ const node = document.documentElement;
12236
+ if (!node || typeof node.getAttribute !== 'function') return undefined;
12237
+ const parseMaybeNumber = (raw) =>
12238
+ typeof raw === 'string' && raw.trim() !== '' && Number.isFinite(Number(raw))
12239
+ ? Number(raw)
12240
+ : undefined;
12241
+ return {
12242
+ stage: node.getAttribute('data-extjs-debug-stage') || undefined,
12243
+ rootCount: parseMaybeNumber(node.getAttribute('data-extjs-debug-root-count')),
12244
+ ownedRootCount: parseMaybeNumber(
12245
+ node.getAttribute('data-extjs-debug-owned-root-count')
12246
+ ),
12247
+ markerCount: parseMaybeNumber(
12248
+ node.getAttribute('data-extjs-debug-marker-count')
12249
+ ),
12250
+ lastRemoval:
12251
+ node.getAttribute('data-extjs-debug-last-removal') || undefined,
12252
+ lastRemovalSource:
12253
+ node.getAttribute('data-extjs-debug-last-removal-source') ||
12254
+ undefined,
12255
+ lastRemovalKey:
12256
+ node.getAttribute('data-extjs-debug-last-removal-key') ||
12257
+ undefined,
12258
+ lastRemovedNodeTag:
12259
+ node.getAttribute('data-extjs-debug-last-removed-node-tag') ||
12260
+ undefined,
12261
+ lastRemovedNodeId:
12262
+ node.getAttribute('data-extjs-debug-last-removed-node-id') ||
12263
+ undefined,
12264
+ lastRemovedNodeClass:
12265
+ node.getAttribute('data-extjs-debug-last-removed-node-class') ||
12266
+ undefined,
12267
+ lastRemovedNodeDirect:
12268
+ node.getAttribute('data-extjs-debug-last-removed-node-direct') ||
12269
+ undefined,
12270
+ lastRemovalReadyState:
12271
+ node.getAttribute('data-extjs-debug-last-removal-ready-state') ||
12272
+ undefined,
12273
+ lastRemovalUrl:
12274
+ node.getAttribute('data-extjs-debug-last-removal-url') ||
12275
+ undefined,
12276
+ lastRemovalParentTag:
12277
+ node.getAttribute('data-extjs-debug-last-removal-parent-tag') ||
12278
+ undefined,
12279
+ executionCount: parseMaybeNumber(
12280
+ node.getAttribute('data-extjs-debug-execution-count')
12281
+ ),
12282
+ lastExecutionStage:
12283
+ node.getAttribute('data-extjs-debug-last-execution-stage') ||
12284
+ undefined,
12285
+ lastExecutionKey:
12286
+ node.getAttribute('data-extjs-debug-last-execution-key') ||
12287
+ undefined,
12288
+ existingRootCountBeforeCleanup: parseMaybeNumber(
12289
+ node.getAttribute(
12290
+ 'data-extjs-debug-existing-root-count-before-cleanup'
12291
+ )
12292
+ )
12293
+ };
12294
+ } catch (error) {
12295
+ return undefined;
12296
+ }
12297
+ })();
12298
+ const markers = Array.from(
12299
+ document.querySelectorAll('[data-extjs-reinject-marker="true"]')
12300
+ )
12301
+ .slice(0, 10)
12302
+ .map(normalize);
12303
+ const registry = (typeof globalThis === 'object' && globalThis && globalThis.__EXTENSIONJS_DEV_REINJECT__)
12304
+ ? globalThis.__EXTENSIONJS_DEV_REINJECT__
12305
+ : {};
12306
+ const registries = Object.entries(registry || {})
12307
+ .slice(0, 20)
12308
+ .map(([key, entry]) => ({
12309
+ key,
12310
+ generation: readRegistryGeneration(entry),
12311
+ hasCleanup:
12312
+ typeof entry === 'function' ||
12313
+ !!(entry && typeof entry === 'object' && typeof entry.cleanup === 'function')
12314
+ }));
12315
+ const generations = roots
12316
+ .concat(markers)
12317
+ .map((entry) => entry.generation)
12318
+ .concat(typeof page?.generation === 'number' ? [page.generation] : [])
12319
+ .concat(registries.map((entry) => entry.generation))
12320
+ .filter((value) => typeof value === 'number');
12321
+ return {
12322
+ rootCount: roots.length,
12323
+ markerCount: markers.length,
12324
+ registryCount: registries.length,
12325
+ latestGeneration: generations.length ? Math.max(...generations) : 0,
12326
+ debug,
12327
+ page,
12328
+ roots,
12329
+ markers,
12330
+ registries
12331
+ };
9827
12332
  })()`);
9828
12333
  if (payload && 'object' == typeof payload) return payload;
9829
12334
  }
@@ -9871,7 +12376,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9871
12376
  await client.connect(port);
9872
12377
  this.client = client;
9873
12378
  this.setupConsoleCapture();
9874
- if (this.devOptions?.sourceConsole) await (0, logging.c)(client);
12379
+ if (this.devOptions?.sourceConsole) await (0, remote_firefox_logging.c)(client);
9875
12380
  this.initialized = true;
9876
12381
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
9877
12382
  console.log(browsers_lib_messages.X6h());
@@ -9938,6 +12443,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9938
12443
  const currentTitle = await this.client.evaluate(actorToUse, 'String(document.title)');
9939
12444
  if ('string' == typeof currentTitle) meta.title = currentTitle;
9940
12445
  } catch {}
12446
+ try {
12447
+ await this.waitForContentScriptStyles(actorToUse);
12448
+ } catch {}
9941
12449
  const html = await (0, source_inspect.Lj)(this.client, descriptor, actorToUse) || '';
9942
12450
  this.emitSourceOutput(html, 'post_injection', meta);
9943
12451
  return;
@@ -9950,7 +12458,112 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9950
12458
  }
9951
12459
  async waitForContentScriptInjection(consoleActor) {
9952
12460
  if (!this.client) return;
9953
- await (0, source_inspect.NQ)(this.client, consoleActor);
12461
+ return await (0, source_inspect.NQ)(this.client, consoleActor);
12462
+ }
12463
+ async hasVisibleShadowHostContentFirefox() {
12464
+ if (!this.client || !this.currentConsoleActor) return false;
12465
+ try {
12466
+ const v = await this.client.evaluate(this.currentConsoleActor, `(() => { try {
12467
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
12468
+ for (const h of hosts) {
12469
+ const sr = h && h.shadowRoot;
12470
+ if (sr && String(sr.innerHTML || '').trim().length > 0) return true;
12471
+ }
12472
+ return false;
12473
+ } catch { return false } })()`);
12474
+ return Boolean(v);
12475
+ } catch {
12476
+ return false;
12477
+ }
12478
+ }
12479
+ async shouldEmitFirefoxContentScriptInjected(injectionWaitOk) {
12480
+ if (!injectionWaitOk || !this.client || !this.currentConsoleActor) return false;
12481
+ const deadline = Date.now() + 2800;
12482
+ while(Date.now() < deadline){
12483
+ const rootMeta = await this.getExtensionRootMeta();
12484
+ const shadow = await this.getShadowStyleSnapshot();
12485
+ if (rootMeta && rootMeta.rootCount >= 1) return true;
12486
+ if (shadow && 'number' == typeof shadow.count && Number(shadow.count) > 0) return true;
12487
+ await new Promise((r)=>setTimeout(r, 200));
12488
+ }
12489
+ return this.hasVisibleShadowHostContentFirefox();
12490
+ }
12491
+ async reopenTabAndResolveActors(urlToInspect) {
12492
+ if (!this.client) return null;
12493
+ try {
12494
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE || '1' === process.env.EXTENSION_DEBUG_FIREFOX_INSPECTION) console.log(`[RDP] source inspection reopening fresh tab for ${String(urlToInspect)}`);
12495
+ await this.client.addTab(urlToInspect);
12496
+ await wait(300);
12497
+ const { tabActor, consoleActor } = await this.selectActors(urlToInspect);
12498
+ this.currentTabActor = tabActor;
12499
+ const resolvedConsoleActor = await this.resolveConsoleActor(tabActor, urlToInspect);
12500
+ this.currentConsoleActor = resolvedConsoleActor || consoleActor;
12501
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE || '1' === process.env.EXTENSION_DEBUG_FIREFOX_INSPECTION) console.log(`[RDP] reopened tabActor=${String(tabActor)} consoleActor=${String(this.currentConsoleActor || '')}`);
12502
+ return {
12503
+ tabActor,
12504
+ consoleActor: this.currentConsoleActor
12505
+ };
12506
+ } catch {
12507
+ return null;
12508
+ }
12509
+ }
12510
+ async waitForContentScriptStyles(consoleActor) {
12511
+ if (!this.client) return;
12512
+ const deadline = Date.now() + 10000;
12513
+ while(Date.now() < deadline){
12514
+ try {
12515
+ const hasStyles = await this.client.evaluate(consoleActor, `(() => { try {
12516
+ const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
12517
+ if (!hosts.length) return false;
12518
+ for (const host of hosts) {
12519
+ const sr = host && host.shadowRoot;
12520
+ if (!sr) continue;
12521
+ const styles = Array.from(sr.querySelectorAll('style'));
12522
+ if (styles.some((styleEl) => String(styleEl.outerHTML || '').includes('<style') && String(styleEl.textContent || '').trim().length > 0)) {
12523
+ return true;
12524
+ }
12525
+ const childStyles = Array.from(sr.childNodes || []);
12526
+ if (childStyles.some((node) => {
12527
+ try {
12528
+ return (
12529
+ node &&
12530
+ node.nodeType === 1 &&
12531
+ String(node.nodeName || '').toLowerCase() === 'style' &&
12532
+ String(node.textContent || '').trim().length > 0
12533
+ );
12534
+ } catch {
12535
+ return false;
12536
+ }
12537
+ })) {
12538
+ return true;
12539
+ }
12540
+ const adoptedSheets = Array.from(sr.adoptedStyleSheets || []);
12541
+ if (adoptedSheets.some((sheet) => {
12542
+ try {
12543
+ return Array.from(sheet.cssRules || []).length > 0;
12544
+ } catch {
12545
+ return false;
12546
+ }
12547
+ })) {
12548
+ return true;
12549
+ }
12550
+ const styleSheets = Array.from(sr.styleSheets || []);
12551
+ if (styleSheets.some((sheet) => {
12552
+ try {
12553
+ return Array.from(sheet.cssRules || []).length > 0;
12554
+ } catch {
12555
+ return false;
12556
+ }
12557
+ })) {
12558
+ return true;
12559
+ }
12560
+ }
12561
+ return false;
12562
+ } catch { return false } })()`);
12563
+ if (hasStyles) return;
12564
+ } catch {}
12565
+ await wait(200);
12566
+ }
9954
12567
  }
9955
12568
  async handleFileChange() {
9956
12569
  if (!this.client || !this.currentConsoleActor) return;
@@ -9964,6 +12577,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9964
12577
  }
9965
12578
  if (this.lastUrlToInspect) await this.ensureUrlAndReady(this.currentConsoleActor, this.lastUrlToInspect);
9966
12579
  await this.waitForContentScriptInjection(this.currentConsoleActor);
12580
+ try {
12581
+ await this.waitForContentScriptStyles(this.currentConsoleActor);
12582
+ } catch {}
9967
12583
  let lastError = null;
9968
12584
  for(let attempt = 0; attempt < 3; attempt++){
9969
12585
  try {
@@ -9989,6 +12605,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9989
12605
  }
9990
12606
  }, CHANGE_DEBOUNCE_MS);
9991
12607
  }
12608
+ registerContentReloadSnapshotHook() {
12609
+ globalThis.__EXTJS_ON_FIREFOX_CONTENT_RELOADED__ = async ()=>{
12610
+ await this.handleFileChange();
12611
+ };
12612
+ }
9992
12613
  apply(compiler) {
9993
12614
  if (this.host.dryRun) return;
9994
12615
  if ('development' !== compiler.options.mode) return;
@@ -9999,6 +12620,18 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9999
12620
  if (!this.initialized) await this.initialize();
10000
12621
  const urlToInspect = this.resolveUrlToInspect();
10001
12622
  this.lastUrlToInspect = urlToInspect;
12623
+ const forceSourceReinspect = Boolean(this.host.__extjsForceSourceReinspect);
12624
+ if (forceSourceReinspect) {
12625
+ this.host.__extjsForceSourceReinspect = false;
12626
+ this.currentConsoleActor = null;
12627
+ this.currentTabActor = null;
12628
+ }
12629
+ if (this.devOptions?.watchSource && !forceSourceReinspect && this.isWatching && this.currentConsoleActor && this.currentTabActor) {
12630
+ if (globalThis.__EXTJS_PENDING_FIREFOX_CONTENT_RELOAD__) return void done();
12631
+ await this.handleFileChange();
12632
+ done();
12633
+ return;
12634
+ }
10002
12635
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(browsers_lib_messages.rCC(urlToInspect));
10003
12636
  const { tabActor, consoleActor } = await this.selectActors(urlToInspect);
10004
12637
  this.currentTabActor = tabActor;
@@ -10012,15 +12645,61 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10012
12645
  const resolvedConsoleActor = await this.resolveConsoleActor(tabActor, urlToInspect);
10013
12646
  this.currentConsoleActor = resolvedConsoleActor || consoleActor;
10014
12647
  if (this.currentConsoleActor) {
10015
- await this.waitForContentScriptInjection(this.currentConsoleActor);
10016
- emitActionEvent("content_script_injected", {
10017
- url: urlToInspect
10018
- });
12648
+ let injected = await this.waitForContentScriptInjection(this.currentConsoleActor);
12649
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE || '1' === process.env.EXTENSION_DEBUG_FIREFOX_INSPECTION) console.log(`[RDP] initial content-script wait result=${String(Boolean(injected))} actor=${String(this.currentConsoleActor)}`);
12650
+ if (!injected) {
12651
+ const reopened = await this.reopenTabAndResolveActors(urlToInspect);
12652
+ if (reopened?.consoleActor) {
12653
+ emitActionEvent('navigation_start', {
12654
+ url: urlToInspect
12655
+ });
12656
+ await this.ensureNavigatedAndLoaded(urlToInspect, reopened.tabActor);
12657
+ emitActionEvent('navigation_end', {
12658
+ url: urlToInspect
12659
+ });
12660
+ injected = await this.waitForContentScriptInjection(reopened.consoleActor);
12661
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE || '1' === process.env.EXTENSION_DEBUG_FIREFOX_INSPECTION) console.log(`[RDP] fresh-tab content-script wait result=${String(Boolean(injected))} actor=${String(reopened.consoleActor)}`);
12662
+ }
12663
+ }
12664
+ try {
12665
+ const actorHref = this.currentConsoleActor ? await this.client?.evaluate(this.currentConsoleActor, 'String(location.href || "")') : void 0;
12666
+ fetch('http://127.0.0.1:7795/ingest/9eb8f923-a325-4455-a46c-a6e706558307', {
12667
+ method: 'POST',
12668
+ headers: {
12669
+ 'Content-Type': 'application/json',
12670
+ 'X-Debug-Session-Id': 'a87efc'
12671
+ },
12672
+ body: JSON.stringify({
12673
+ sessionId: 'a87efc',
12674
+ runId: process.env.EXTENSION_INSTANCE_ID || 'firefox-source-inspection',
12675
+ hypothesisId: 'H4',
12676
+ location: "firefox-source-inspection/index.ts:before-content-script-event",
12677
+ message: "Firefox content-script event boundary",
12678
+ data: {
12679
+ urlToInspect,
12680
+ currentTabActor: this.currentTabActor,
12681
+ currentConsoleActor: this.currentConsoleActor,
12682
+ injected,
12683
+ actorHref
12684
+ },
12685
+ timestamp: Date.now()
12686
+ })
12687
+ }).catch(()=>{});
12688
+ } catch {}
12689
+ if (injected) {
12690
+ const emitOk = await this.shouldEmitFirefoxContentScriptInjected(injected);
12691
+ if (emitOk) emitActionEvent("content_script_injected", {
12692
+ url: urlToInspect
12693
+ });
12694
+ }
12695
+ try {
12696
+ await this.waitForContentScriptStyles(this.currentConsoleActor);
12697
+ } catch {}
10019
12698
  await this.printHTML(this.currentConsoleActor);
10020
12699
  }
10021
12700
  if (this.devOptions?.watchSource) {
12701
+ this.registerContentReloadSnapshotHook();
10022
12702
  this.isWatching = true;
10023
- await this.handleFileChange();
10024
12703
  }
10025
12704
  } catch (error) {
10026
12705
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.error(browsers_lib_messages.b82(error.message));
@@ -10089,8 +12768,6 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10089
12768
  run_firefox_define_property(this, "geckoBinary", void 0);
10090
12769
  run_firefox_define_property(this, "port", void 0);
10091
12770
  run_firefox_define_property(this, "instanceId", void 0);
10092
- run_firefox_define_property(this, "keepProfileChanges", void 0);
10093
- run_firefox_define_property(this, "copyFromProfile", void 0);
10094
12771
  run_firefox_define_property(this, "source", void 0);
10095
12772
  run_firefox_define_property(this, "watchSource", void 0);
10096
12773
  run_firefox_define_property(this, "sourceFormat", void 0);
@@ -10115,38 +12792,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10115
12792
  run_firefox_define_property(this, "logger", void 0);
10116
12793
  run_firefox_define_property(this, "firefoxCtx", void 0);
10117
12794
  run_firefox_define_property(this, "rdpController", void 0);
10118
- this.extension = options.extension;
10119
- this.browser = options.browser;
10120
- this.startingUrl = options.startingUrl;
10121
- this.preferences = options.preferences;
10122
- this.profile = options.profile;
10123
- this.browserFlags = options.browserFlags;
10124
- this.excludeBrowserFlags = options.excludeBrowserFlags;
10125
- this.noOpen = options.noOpen;
12795
+ Object.assign(this, (0, runtime_options.pA)(options));
10126
12796
  this.geckoBinary = options.geckoBinary;
10127
- this.instanceId = options.instanceId;
10128
- this.port = options.port;
10129
- this.source = options.source;
10130
- this.watchSource = options.watchSource;
10131
- this.sourceFormat = options.sourceFormat;
10132
- this.sourceSummary = options.sourceSummary;
10133
- this.sourceMeta = options.sourceMeta;
10134
- this.sourceProbe = options.sourceProbe;
10135
- this.sourceTree = options.sourceTree;
10136
- this.sourceConsole = options.sourceConsole;
10137
- this.sourceDom = options.sourceDom;
10138
- this.sourceMaxBytes = options.sourceMaxBytes;
10139
- this.sourceRedact = options.sourceRedact;
10140
- this.sourceIncludeShadow = options.sourceIncludeShadow;
10141
- this.sourceDiff = options.sourceDiff;
10142
- this.logLevel = options.logLevel;
10143
- this.logContexts = options.logContexts;
10144
- this.logFormat = options.logFormat;
10145
- this.logTimestamps = options.logTimestamps;
10146
- this.logColor = options.logColor;
10147
- this.logUrl = options.logUrl;
10148
- this.logTab = options.logTab;
10149
- this.dryRun = options.dryRun;
10150
12797
  }
10151
12798
  }
10152
12799
  function plugin_browsers_define_property(obj, key, value) {
@@ -10211,39 +12858,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10211
12858
  plugin_browsers_define_property(this, "logUrl", void 0);
10212
12859
  plugin_browsers_define_property(this, "logTab", void 0);
10213
12860
  const normalized = normalizePluginOptions(options);
10214
- this.extension = normalized.extension;
10215
- this.browser = normalized.browser;
10216
- this.startingUrl = normalized.startingUrl;
10217
- this.preferences = normalized.preferences;
10218
- this.profile = normalized.profile;
10219
- this.browserFlags = normalized.browserFlags;
10220
- this.excludeBrowserFlags = normalized.excludeBrowserFlags;
10221
- this.noOpen = normalized.noOpen;
12861
+ Object.assign(this, (0, runtime_options.pA)(normalized));
10222
12862
  this.chromiumBinary = normalized.chromiumBinary;
10223
12863
  this.geckoBinary = normalized.geckoBinary;
10224
- this.instanceId = normalized.instanceId;
10225
- this.port = normalized.port;
10226
- this.source = normalized.source;
10227
- this.watchSource = normalized.watchSource;
10228
- this.sourceFormat = normalized.sourceFormat;
10229
- this.sourceSummary = normalized.sourceSummary;
10230
- this.sourceMeta = normalized.sourceMeta;
10231
- this.sourceProbe = normalized.sourceProbe;
10232
- this.sourceTree = normalized.sourceTree;
10233
- this.sourceConsole = normalized.sourceConsole;
10234
- this.sourceDom = normalized.sourceDom;
10235
- this.sourceMaxBytes = normalized.sourceMaxBytes;
10236
- this.sourceRedact = normalized.sourceRedact;
10237
- this.sourceIncludeShadow = normalized.sourceIncludeShadow;
10238
- this.sourceDiff = normalized.sourceDiff;
10239
- this.logLevel = normalized.logLevel;
10240
- this.logContexts = normalized.logContexts;
10241
- this.logFormat = normalized.logFormat;
10242
- this.logTimestamps = normalized.logTimestamps;
10243
- this.logColor = normalized.logColor;
10244
- this.logUrl = normalized.logUrl;
10245
- this.logTab = normalized.logTab;
10246
- this.dryRun = normalized.dryRun;
10247
12864
  if ('chromium-based' === this.browser && !this.chromiumBinary) {
10248
12865
  console.error(browsers_lib_messages.nek());
10249
12866
  process.exit(1);
@@ -10413,6 +13030,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10413
13030
  watchSource: devOptions.watchSource,
10414
13031
  sourceFormat: devOptions.sourceFormat,
10415
13032
  sourceSummary: devOptions.sourceSummary,
13033
+ sourceMeta: devOptions.sourceMeta,
13034
+ sourceProbe: devOptions.sourceProbe,
13035
+ sourceTree: devOptions.sourceTree,
13036
+ sourceConsole: devOptions.sourceConsole,
13037
+ sourceDom: devOptions.sourceDom,
10416
13038
  sourceMaxBytes: devOptions.sourceMaxBytes,
10417
13039
  sourceRedact: devOptions.sourceRedact,
10418
13040
  sourceIncludeShadow: devOptions.sourceIncludeShadow,
@@ -10437,6 +13059,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10437
13059
  clean: devOptions.output.clean,
10438
13060
  path: primaryExtensionOutputDir,
10439
13061
  publicPath: '/',
13062
+ filename: 'development' === (devOptions.mode || 'development') ? (pathData)=>{
13063
+ const chunkName = pathData.chunk?.name;
13064
+ if ('string' == typeof chunkName && /^content_scripts\/content-\d+$/.test(chunkName)) return `${chunkName}.[fullhash:8].js`;
13065
+ return '[name].js';
13066
+ } : '[name].js',
10440
13067
  hotUpdateChunkFilename: 'hot/[id].[fullhash].hot-update.js',
10441
13068
  hotUpdateMainFilename: 'hot/[runtime].[fullhash].hot-update.json',
10442
13069
  environment: {