extension-develop 3.10.3 → 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} +3118 -504
  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 +1999 -1690
  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
  }
@@ -2822,17 +3018,17 @@ exports.modules = {
2822
3018
  for (const r of fontAssets)if (!webAccessibleResourcesV2.includes(r)) webAccessibleResourcesV2.push(r);
2823
3019
  }
2824
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
+ }
2825
3031
  if (3 === canonicalManifest.manifest_version) {
2826
- const assetKeys = Object.keys(compilation.assets || {});
2827
- const cssUnderContentScripts = assetKeys.filter((k)=>k.startsWith("content_scripts/")).filter((k)=>k.endsWith('.css')).sort();
2828
- if (Array.isArray(canonicalManifest.content_scripts)) for (const contentScript of canonicalManifest.content_scripts){
2829
- const jsFiles = Array.isArray(contentScript.js) ? contentScript.js : [];
2830
- const canonicalCss = jsFiles.map(toCanonicalContentScriptCss).filter((resource)=>Boolean(resource && cssUnderContentScripts.includes(resource)));
2831
- if (canonicalCss.length > 0) contentScript.css = Array.from(new Set([
2832
- ...contentScript.css || [],
2833
- ...canonicalCss
2834
- ])).sort();
2835
- }
2836
3032
  if (cssUnderContentScripts.length > 0) {
2837
3033
  const allMatches = Array.from(new Set((canonicalManifest.content_scripts || []).flatMap((cs)=>cs.matches || [])));
2838
3034
  const normalizedMatches = cleanMatches(allMatches);
@@ -2860,6 +3056,8 @@ exports.modules = {
2860
3056
  });
2861
3057
  }
2862
3058
  }
3059
+ } else if (2 === canonicalManifest.manifest_version) {
3060
+ for (const resource of cssUnderContentScripts)if (!webAccessibleResourcesV2.includes(resource)) webAccessibleResourcesV2.push(resource);
2863
3061
  }
2864
3062
  if (3 === canonicalManifest.manifest_version) {
2865
3063
  if (webAccessibleResourcesV3.length > 0) canonicalManifest.web_accessible_resources = webAccessibleResourcesV3.map((entry)=>({
@@ -3136,6 +3334,7 @@ exports.modules = {
3136
3334
  permissions: [
3137
3335
  ...new Set([
3138
3336
  "scripting",
3337
+ 'tabs',
3139
3338
  'management',
3140
3339
  ...canonicalManifest.permissions || []
3141
3340
  ])
@@ -3143,6 +3342,7 @@ exports.modules = {
3143
3342
  } : {
3144
3343
  permissions: [
3145
3344
  "scripting",
3345
+ 'tabs',
3146
3346
  'management'
3147
3347
  ]
3148
3348
  } : {},
@@ -4240,6 +4440,51 @@ exports.modules = {
4240
4440
  this.browser = options.browser;
4241
4441
  }
4242
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");
4243
4488
  function add_scripts_and_styles_to_compilation_define_property(obj, key, value) {
4244
4489
  if (key in obj) Object.defineProperty(obj, key, {
4245
4490
  value: value,
@@ -4257,6 +4502,7 @@ exports.modules = {
4257
4502
  const projectRoot = compiler.options.context || manifestDir;
4258
4503
  const publicDir = external_path_.join(projectRoot, 'public');
4259
4504
  const hasPublicDir = external_fs_.existsSync(publicDir);
4505
+ const devServerHmrImports = 'development' === compiler.options.mode ? getDevServerHmrImports(compiler) : [];
4260
4506
  for (const field of Object.entries(htmlEntries)){
4261
4507
  const [feature, resource] = field;
4262
4508
  if (resource) {
@@ -4271,7 +4517,8 @@ exports.modules = {
4271
4517
  ...cssAssets
4272
4518
  ];
4273
4519
  if ('development' === compiler.options.mode) {
4274
- 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");
4275
4522
  fileAssets.push(hmrScript);
4276
4523
  }
4277
4524
  if (external_fs_.existsSync(resource)) compiler.options.entry = {
@@ -4688,24 +4935,40 @@ exports.modules = {
4688
4935
  includeList,
4689
4936
  browser: this.browser
4690
4937
  }).apply(compiler);
4691
- if ('production' !== (compiler.options.mode || 'development')) compiler.options.module.rules.push({
4692
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4693
- include: [
4694
- external_path_.dirname(this.manifestPath)
4695
- ],
4696
- exclude: [
4697
- /([\\/])node_modules\1/
4698
- ],
4699
- use: [
4700
- {
4701
- loader: external_path_.resolve(__dirname, "ensure-hmr-for-scripts"),
4702
- options: {
4703
- manifestPath: this.manifestPath,
4704
- includeList
4705
- }
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)));
4706
4947
  }
4707
- ]
4708
- });
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
+ }
4709
4972
  new AddToFileDependencies({
4710
4973
  manifestPath: this.manifestPath,
4711
4974
  includeList,
@@ -4769,6 +5032,29 @@ exports.modules = {
4769
5032
  });
4770
5033
  return fileAssets;
4771
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
+ }
4772
5058
  function findPackageRoot(startDir) {
4773
5059
  let current = startDir;
4774
5060
  for(let i = 0; i < 15; i++){
@@ -4812,12 +5098,11 @@ exports.modules = {
4812
5098
  const cs = contentScripts[i];
4813
5099
  if (cs?.world !== 'MAIN') continue;
4814
5100
  const bridgeIndex = originalCount + bridgeOrdinal++;
4815
- bridgeScripts[`content_scripts/content-${bridgeIndex}`] = bridgeSource;
5101
+ bridgeScripts[(0, contracts.Y0)(bridgeIndex)] = bridgeSource;
4816
5102
  }
4817
5103
  } catch {}
4818
5104
  return bridgeScripts;
4819
5105
  }
4820
- var package_json = __webpack_require__("./webpack/webpack-lib/package-json.ts");
4821
5106
  function add_content_script_wrapper_define_property(obj, key, value) {
4822
5107
  if (key in obj) Object.defineProperty(obj, key, {
4823
5108
  value: value,
@@ -4832,20 +5117,12 @@ exports.modules = {
4832
5117
  static getBridgeScripts(manifestPath) {
4833
5118
  return getMainWorldBridgeScripts(manifestPath);
4834
5119
  }
4835
- resolveLoader(name) {
4836
- const base = external_path_.resolve(__dirname, name);
4837
- const candidates = [
4838
- `${base}.cjs`,
4839
- `${base}.js`,
4840
- `${base}.mjs`,
4841
- base
4842
- ];
4843
- for (const candidate of candidates)if (external_fs_.existsSync(candidate)) return candidate;
4844
- return base;
5120
+ resolveLoader() {
5121
+ return (0, develop_context.G)("feature-scripts-content-script-wrapper");
4845
5122
  }
4846
5123
  apply(compiler) {
4847
5124
  const manifestDir = external_path_.dirname(this.manifestPath);
4848
- const packageJsonPath = (0, package_json.Pb)(this.manifestPath);
5125
+ const packageJsonPath = findNearestPackageJsonSync(this.manifestPath);
4849
5126
  const packageJsonDir = packageJsonPath ? external_path_.dirname(packageJsonPath) : manifestDir;
4850
5127
  const includeDirs = packageJsonDir === manifestDir ? [
4851
5128
  manifestDir
@@ -4861,7 +5138,7 @@ exports.modules = {
4861
5138
  ],
4862
5139
  use: [
4863
5140
  {
4864
- loader: this.resolveLoader("content-script-wrapper"),
5141
+ loader: this.resolveLoader(),
4865
5142
  options: {
4866
5143
  manifestPath: this.manifestPath,
4867
5144
  mode: compiler.options.mode
@@ -4869,41 +5146,6 @@ exports.modules = {
4869
5146
  }
4870
5147
  ]
4871
5148
  });
4872
- if ('production' !== compiler.options.mode) {
4873
- compiler.options.module.rules.push({
4874
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4875
- include: includeDirs,
4876
- exclude: [
4877
- /([\\/])node_modules\1/
4878
- ],
4879
- use: [
4880
- {
4881
- loader: this.resolveLoader('warn-no-default-export'),
4882
- options: {
4883
- manifestPath: this.manifestPath,
4884
- mode: compiler.options.mode
4885
- }
4886
- }
4887
- ],
4888
- enforce: 'pre'
4889
- });
4890
- compiler.options.module.rules.push({
4891
- test: /\.(js|cjs|mjs|jsx|mjsx|ts|mts|tsx|mtsx)$/,
4892
- include: includeDirs,
4893
- exclude: [
4894
- /([\\/])node_modules\1/
4895
- ],
4896
- use: [
4897
- {
4898
- loader: this.resolveLoader('add-hmr-accept-code'),
4899
- options: {
4900
- manifestPath: this.manifestPath,
4901
- mode: compiler.options.mode
4902
- }
4903
- }
4904
- ]
4905
- });
4906
- }
4907
5149
  }
4908
5150
  constructor(options){
4909
5151
  add_content_script_wrapper_define_property(this, "manifestPath", void 0);
@@ -4912,17 +5154,6 @@ exports.modules = {
4912
5154
  this.browser = options.browser || 'chrome';
4913
5155
  }
4914
5156
  }
4915
- function scriptsEntriesSummary(entriesAdded, publicTracked) {
4916
- return `Scripts entries — added=${external_pintor_default().gray(String(entriesAdded))}, publicTracked=${external_pintor_default().gray(String(publicTracked))}`;
4917
- }
4918
- function scriptsManifestChangeDetected(before, after) {
4919
- const parts = [
4920
- "Manifest scripts change detected",
4921
- before ? `${external_pintor_default().gray('before')} ${external_pintor_default().underline(before)}` : '',
4922
- after ? `${external_pintor_default().gray('after')} ${external_pintor_default().underline(after)}` : ''
4923
- ].filter(Boolean);
4924
- return parts.join(' — ');
4925
- }
4926
5157
  function add_scripts_define_property(obj, key, value) {
4927
5158
  if (key in obj) Object.defineProperty(obj, key, {
4928
5159
  value: value,
@@ -4934,14 +5165,22 @@ exports.modules = {
4934
5165
  return obj;
4935
5166
  }
4936
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
+ }
4937
5177
  class AddScripts {
4938
5178
  apply(compiler) {
4939
5179
  const bridgeScripts = AddContentScriptWrapper.getBridgeScripts(this.manifestPath);
4940
- const mergedIncludeList = {
5180
+ const scriptFields = {
4941
5181
  ...this.includeList,
4942
5182
  ...bridgeScripts
4943
5183
  };
4944
- const scriptFields = mergedIncludeList;
4945
5184
  if (compiler?.hooks?.thisCompilation?.tap) compiler.hooks.thisCompilation.tap("scripts:validate-include-list", (compilation)=>{
4946
5185
  try {
4947
5186
  const manifestDir = external_path_.dirname(this.manifestPath);
@@ -4952,20 +5191,19 @@ exports.modules = {
4952
5191
  raw
4953
5192
  ] : [];
4954
5193
  for (const entry of rawEntries){
4955
- if (!entry || 'string' != typeof entry) continue;
4956
- if (add_scripts_isRemoteUrl(entry)) continue;
5194
+ if (!entry || 'string' != typeof entry || add_scripts_isRemoteUrl(entry)) continue;
4957
5195
  let resolved = entry;
4958
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);
4959
5197
  if (external_fs_.existsSync(resolved)) continue;
4960
5198
  const isPublicRoot = entry.startsWith('/') && !external_path_.isAbsolute(entry);
4961
5199
  const displayPath = isPublicRoot ? outputRoot ? external_path_.join(outputRoot, entry.slice(1)) : entry : resolved;
4962
- const lines = [];
4963
- lines.push(`Check the ${feature.replace('/', '.')} field in your manifest.json file.`);
4964
- lines.push("The script path must point to an existing file that will be bundled.");
4965
- if (isPublicRoot) lines.push("Paths starting with '/' are resolved from the extension output root (served from public/), not your source directory.");
4966
- lines.push('');
4967
- lines.push(`NOT FOUND ${displayPath}`);
4968
- 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'));
4969
5207
  err.file = 'manifest.json';
4970
5208
  err.name = 'ScriptsMissingFile';
4971
5209
  (compilation.errors ||= []).push(err);
@@ -4976,15 +5214,18 @@ exports.modules = {
4976
5214
  const newEntries = {};
4977
5215
  const manifestDir = external_path_.dirname(this.manifestPath);
4978
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
+ }
4979
5223
  const resolveEntryPath = (entry)=>{
4980
- if (!entry) return entry;
4981
- if (add_scripts_isRemoteUrl(entry)) return entry;
5224
+ if (!entry || add_scripts_isRemoteUrl(entry)) return entry;
4982
5225
  if (entry.startsWith('/') && !external_path_.isAbsolute(entry)) return external_path_.join(projectPath, entry.slice(1));
4983
5226
  if (external_path_.isAbsolute(entry)) return entry;
4984
5227
  return external_path_.join(manifestDir, entry);
4985
5228
  };
4986
- let entriesAdded = 0;
4987
- let publicTracked = 0;
4988
5229
  for (const [feature, scriptPath] of Object.entries(scriptFields)){
4989
5230
  const rawEntries = Array.isArray(scriptPath) ? scriptPath || [] : scriptPath ? [
4990
5231
  scriptPath
@@ -4992,32 +5233,32 @@ exports.modules = {
4992
5233
  const resolvedEntries = rawEntries.map(resolveEntryPath);
4993
5234
  const scriptImports = getScriptEntries(resolvedEntries);
4994
5235
  const cssImports = getCssEntries(resolvedEntries);
4995
- const allImports = [
4996
- ...scriptImports,
4997
- ...cssImports
5236
+ const entryImports = [
5237
+ ...new Set([
5238
+ ...scriptImports,
5239
+ ...cssImports
5240
+ ])
4998
5241
  ];
4999
- const entryImports = allImports;
5000
- if (cssImports.length || scriptImports.length) {
5001
- if ('background/service_worker' === feature) {
5002
- const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf8'));
5003
- const isModuleServiceWorker = manifest.background?.type === 'module';
5004
- newEntries[feature] = {
5005
- import: entryImports,
5006
- ...isModuleServiceWorker ? {} : {
5007
- chunkLoading: "import-scripts"
5008
- }
5009
- };
5010
- } else newEntries[feature] = {
5011
- import: entryImports
5012
- };
5013
- entriesAdded++;
5014
- }
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
+ };
5015
5257
  }
5016
5258
  compiler.options.entry = {
5017
5259
  ...compiler.options.entry,
5018
5260
  ...newEntries
5019
5261
  };
5020
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(scriptsEntriesSummary(entriesAdded, publicTracked));
5021
5262
  }
5022
5263
  constructor(options){
5023
5264
  add_scripts_define_property(this, "manifestPath", void 0);
@@ -5026,45 +5267,6 @@ exports.modules = {
5026
5267
  this.includeList = options.includeList || {};
5027
5268
  }
5028
5269
  }
5029
- const basic = [
5030
- 'var isBrowser = !!(() => { try { return browser.runtime.getURL("/") } catch(e) {} })()',
5031
- 'var isChrome = !!(() => { try { return chrome.runtime.getURL("/") } catch(e) {} })()'
5032
- ];
5033
- const weakRuntimeCheck = [
5034
- ...basic,
5035
- "var runtime = isBrowser ? browser : isChrome ? chrome : { runtime: { getURL: x => x } }"
5036
- ];
5037
- class AddPublicPathRuntimeModule {
5038
- apply(compiler) {
5039
- const { RuntimeGlobals } = compiler.webpack;
5040
- compiler.hooks.compilation.tap('PublicPathRuntimeModule', (compilation)=>{
5041
- compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(AddPublicPathRuntimeModule.name, (chunk)=>{
5042
- const module = add_public_path_runtime_module_PublicPathRuntimeModule(compiler);
5043
- compilation.addRuntimeModule(chunk, module);
5044
- return true;
5045
- });
5046
- });
5047
- }
5048
- }
5049
- function add_public_path_runtime_module_PublicPathRuntimeModule(compiler) {
5050
- const { Template, RuntimeModule, RuntimeGlobals } = compiler.webpack;
5051
- class PublicPathRuntimeModule extends RuntimeModule {
5052
- generate() {
5053
- const publicPath = this.compilation?.outputOptions.publicPath;
5054
- return Template.asString([
5055
- ...weakRuntimeCheck,
5056
- `var path = ${JSON.stringify(this.compilation?.getPath(publicPath || '', {
5057
- hash: this.compilation.hash || 'XXXX'
5058
- }))}`,
5059
- `${RuntimeGlobals.publicPath} = typeof importScripts === 'function' || !(isBrowser || isChrome) ? path : runtime.runtime.getURL(path);`
5060
- ]);
5061
- }
5062
- constructor(){
5063
- super('publicPath', RuntimeModule.STAGE_BASIC);
5064
- }
5065
- }
5066
- return new PublicPathRuntimeModule();
5067
- }
5068
5270
  function TemplateFn(compilation, Template) {
5069
5271
  return {
5070
5272
  f: (args, body)=>{
@@ -5093,9 +5295,9 @@ exports.modules = {
5093
5295
  `${_let} isChrome, runtime;`,
5094
5296
  'try {',
5095
5297
  Template.indent([
5096
- `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"'}) {`,
5097
5299
  Template.indent([
5098
- 'runtime = browser;'
5300
+ 'runtime = globalThis.browser;'
5099
5301
  ]),
5100
5302
  '}'
5101
5303
  ]),
@@ -5104,10 +5306,10 @@ exports.modules = {
5104
5306
  Template.indent([
5105
5307
  'try {',
5106
5308
  Template.indent([
5107
- `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"'}) {`,
5108
5310
  Template.indent([
5109
5311
  'isChrome = true;',
5110
- 'runtime = chrome;'
5312
+ 'runtime = globalThis.chrome;'
5111
5313
  ]),
5112
5314
  '}'
5113
5315
  ]),
@@ -5158,7 +5360,7 @@ exports.modules = {
5158
5360
  const bundleId = chunkName ? `${chunkName}.js` : '';
5159
5361
  const world = bundleId && this.contentScriptsMeta[bundleId] ? this.contentScriptsMeta[bundleId].world : void 0;
5160
5362
  const isMainWorld = 'main' === world;
5161
- 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; } })();`;
5162
5364
  const DynamicImportLoader = `${_const} ${DYNAMIC_IMPORT_LOADER} = ` + f('url, done, key, chunkId', `import(url).then(${f('', [
5163
5365
  'if (isNotIframe) return done();',
5164
5366
  'try {',
@@ -5209,6 +5411,7 @@ exports.modules = {
5209
5411
  const ClassicLoader = `${_const} ${CLASSIC_LOADER} = ` + f('url, done', Template.asString([
5210
5412
  `${_const} msg = { type: "WTW_INJECT", file: url };`,
5211
5413
  `${_const} onError = ${f('e', 'done(Object.assign(e, { type: "missing" }))')};`,
5414
+ 'try {',
5212
5415
  `if (${RuntimeGlobalIsBrowser}) {`,
5213
5416
  Template.indent([
5214
5417
  `${RuntimeGlobal}.runtime.sendMessage(msg).then(done, onError);`
@@ -5221,7 +5424,8 @@ exports.modules = {
5221
5424
  'else done();'
5222
5425
  ])});`
5223
5426
  ]),
5224
- '}'
5427
+ '}',
5428
+ '} catch (e) { onError(e); }'
5225
5429
  ])) + ';';
5226
5430
  const ClassicLoaderDisabled = `${_const} ${CLASSIC_LOADER} = ` + f('', [
5227
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.\");"
@@ -5323,9 +5527,15 @@ exports.modules = {
5323
5527
  'try { __extjsBase = document.documentElement.getAttribute("data-extjs-extension-base") || ""; } catch(_) { __extjsBase = ""; }'
5324
5528
  ]),
5325
5529
  "}",
5530
+ 'var __extjsRuntimePath = "";',
5326
5531
  `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && typeof ${RuntimeGlobal}.runtime.getURL === "function") {`,
5327
5532
  Template.indent([
5328
- `${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;`
5329
5539
  ]),
5330
5540
  "} else if (__extjsBase) {",
5331
5541
  Template.indent([
@@ -5416,8 +5626,10 @@ exports.modules = {
5416
5626
  "}",
5417
5627
  "if (!scriptUrl) {",
5418
5628
  Template.indent([
5629
+ 'var __extjsRuntimeRoot = "";',
5419
5630
  `if (${RuntimeGlobal} && ${RuntimeGlobal}.runtime && typeof ${RuntimeGlobal}.runtime.getURL === "function") {`,
5420
- Template.indent(`scriptUrl = ${RuntimeGlobal}.runtime.getURL("/");`),
5631
+ Template.indent(`try { __extjsRuntimeRoot = ${RuntimeGlobal}.runtime.getURL("/"); } catch (_) { __extjsRuntimeRoot = ""; }`),
5632
+ Template.indent("scriptUrl = __extjsRuntimeRoot || scriptUrl;"),
5421
5633
  "} else {",
5422
5634
  Template.indent('scriptUrl = __extjsBase || "";'),
5423
5635
  "}"
@@ -5475,6 +5687,52 @@ exports.modules = {
5475
5687
  else if ('.' !== part) depth++;
5476
5688
  return depth > 0 ? `${'../'.repeat(depth)}${append}` : enforceRelative ? `./${append}` : append;
5477
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
+ }
5478
5736
  function ChunkLoaderFallbackRuntimeModule(webpack) {
5479
5737
  const { RuntimeModule, Template } = webpack;
5480
5738
  class ChunkLoaderFallbackRuntime extends RuntimeModule {
@@ -5485,7 +5743,7 @@ exports.modules = {
5485
5743
  const optionalChain = compilation.outputOptions.environment.optionalChaining;
5486
5744
  const _const = compilation.outputOptions.environment.const ? 'const' : 'var';
5487
5745
  const _let = compilation.outputOptions.environment.const ? 'let' : 'var';
5488
- 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', [
5489
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;',
5490
5748
  `${_let} file = message.file;`,
5491
5749
  'try {',
@@ -5514,7 +5772,7 @@ exports.modules = {
5514
5772
  ]),
5515
5773
  '}',
5516
5774
  'return true;'
5517
- ]) + ');';
5775
+ ]) + ");}";
5518
5776
  }
5519
5777
  constructor(){
5520
5778
  super('chunk loader fallback', RuntimeModule.STAGE_TRIGGER);
@@ -5553,8 +5811,13 @@ exports.modules = {
5553
5811
  compilation.addRuntimeModule(_chunk, LoadScriptRuntimeModule(compiler.webpack, false !== compilation.outputOptions.environment.dynamicImport, false !== options.classicLoader, this.contentScriptsMeta));
5554
5812
  return true;
5555
5813
  });
5556
- compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(WebExtensionChuckLoaderRuntimePlugin.name, (chunk, set)=>{
5557
- const { outputOptions } = compilation;
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
+ });
5819
+ compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.publicPath).tap(WebExtensionChuckLoaderRuntimePlugin.name, (chunk, set)=>{
5820
+ const { outputOptions } = compilation;
5558
5821
  const { publicPath, scriptType } = outputOptions;
5559
5822
  if ('auto' === publicPath || '' === publicPath && this.rspackAutoPublicPath) {
5560
5823
  const module = AutoPublicPathRuntimeModule(compiler.webpack);
@@ -5794,7 +6057,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
5794
6057
  } else code = [
5795
6058
  ';(() => {',
5796
6059
  Template.indent([
5797
- '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;',
5798
6061
  `${JSON.stringify(files)}.forEach(file => import(getURL(file)));`
5799
6062
  ]),
5800
6063
  '})();',
@@ -5982,12 +6245,23 @@ Set background.noDynamicEntryWarning to true to disable this warning.
5982
6245
  }
5983
6246
  }
5984
6247
  const webpack_target_webextension_fork = WebExtensionPlugin;
6248
+ function manifest_getManifestContent(compilation, manifestPath) {
6249
+ return getManifestContent(compilation, manifestPath);
6250
+ }
5985
6251
  function scripts_lib_manifest_filterKeysForThisBrowser(manifest, browser) {
5986
6252
  return manifest_filterKeysForThisBrowser(manifest, browser);
5987
6253
  }
5988
6254
  function backgroundIsRequiredMessageOnly(backgroundChunkName) {
5989
6255
  return `Check the ${external_pintor_default().yellow(backgroundChunkName.replace('/', '.'))} field in your ${external_pintor_default().yellow('manifest.json')} file.`;
5990
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
+ }
5991
6265
  function setup_background_entry_define_property(obj, key, value) {
5992
6266
  if (key in obj) Object.defineProperty(obj, key, {
5993
6267
  value: value,
@@ -6020,7 +6294,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6020
6294
  apply(compiler) {
6021
6295
  const manifest = JSON.parse(external_fs_.readFileSync(this.manifestPath, 'utf-8'));
6022
6296
  const browser = this.browser;
6023
- 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');
6024
6298
  const dirname = external_path_.dirname(this.manifestPath);
6025
6299
  let manifestBg = scripts_lib_manifest_filterKeysForThisBrowser(manifest, browser);
6026
6300
  manifestBg = manifestBg?.background ?? manifest.background;
@@ -6063,6 +6337,263 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6063
6337
  this.browser = options.browser || 'chrome';
6064
6338
  }
6065
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
+ }
6066
6597
  function setup_reload_strategy_define_property(obj, key, value) {
6067
6598
  if (key in obj) Object.defineProperty(obj, key, {
6068
6599
  value: value,
@@ -6108,17 +6639,17 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6108
6639
  let bridgeOrdinal = 0;
6109
6640
  for(let i = 0; i < csList.length; i++){
6110
6641
  const cs = csList[i];
6111
- const bundleId = `content_scripts/content-${i}.js`;
6642
+ const bundleId = (0, contracts.f6)(i);
6112
6643
  const isMain = cs?.world === 'MAIN';
6113
6644
  if (isMain) {
6114
6645
  const bridgeIndex = originalCount + bridgeOrdinal++;
6646
+ const bridgeBundleId = (0, contracts.f6)(bridgeIndex);
6115
6647
  contentScriptsMeta[bundleId] = {
6116
6648
  index: i,
6117
6649
  bundleId,
6118
6650
  world: 'main',
6119
- bridgeBundleId: `content_scripts/content-${bridgeIndex}.js`
6651
+ bridgeBundleId
6120
6652
  };
6121
- const bridgeBundleId = `content_scripts/content-${bridgeIndex}.js`;
6122
6653
  contentScriptsMeta[bridgeBundleId] = {
6123
6654
  index: bridgeIndex,
6124
6655
  bundleId: bridgeBundleId,
@@ -6133,12 +6664,17 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6133
6664
  };
6134
6665
  }
6135
6666
  } catch {}
6667
+ new ApplyManifestDevDefaults({
6668
+ manifestPath: this.manifestPath,
6669
+ browser: this.browser
6670
+ }).apply(compiler);
6136
6671
  new SetupBackgroundEntry({
6137
6672
  manifestPath: this.manifestPath,
6138
6673
  browser: this.browser
6139
6674
  }).apply(compiler);
6140
6675
  new webpack_target_webextension_fork({
6141
6676
  background: this.getEntryName(patchedManifest),
6677
+ hmrConfig: false,
6142
6678
  weakRuntimeCheck: true,
6143
6679
  contentScriptsMeta
6144
6680
  }).apply(compiler);
@@ -6150,6 +6686,135 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6150
6686
  this.browser = options.browser || 'chrome';
6151
6687
  }
6152
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
+ }
6153
6818
  function throw_if_manifest_scripts_change_define_property(obj, key, value) {
6154
6819
  if (key in obj) Object.defineProperty(obj, key, {
6155
6820
  value: value,
@@ -6272,6 +6937,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
6272
6937
  }).apply(compiler);
6273
6938
  if ('production' === compiler.options.mode) new AddPublicPathRuntimeModule().apply(compiler);
6274
6939
  if ('production' !== compiler.options.mode) {
6940
+ new StripContentScriptDevServerRuntime().apply(compiler);
6275
6941
  new SetupReloadStrategy({
6276
6942
  manifestPath: this.manifestPath,
6277
6943
  browser: this.browser
@@ -7661,6 +8327,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
7661
8327
  instanceId: options.instanceId
7662
8328
  };
7663
8329
  }
8330
+ var runtime_options = __webpack_require__("./webpack/plugin-browsers/browsers-lib/runtime-options.ts");
7664
8331
  var browsers_lib_messages = __webpack_require__("./webpack/plugin-browsers/browsers-lib/messages.ts");
7665
8332
  var chromium_context = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-context/index.ts");
7666
8333
  var chromium_launch = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-launch/index.ts");
@@ -8016,19 +8683,21 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8016
8683
  return hash.toString(16).padStart(8, '0');
8017
8684
  }
8018
8685
  function diffDomSnapshots(prev, next) {
8686
+ const prevNodes = Array.isArray(prev?.nodes) ? prev.nodes : [];
8687
+ const nextNodes = Array.isArray(next?.nodes) ? next.nodes : [];
8019
8688
  if (!prev) return {
8020
- added: next.nodes.length,
8689
+ added: nextNodes.length,
8021
8690
  removed: 0,
8022
8691
  changed: 0,
8023
- addedKeys: next.nodes.slice(0, 50).map((n)=>n.key),
8692
+ addedKeys: nextNodes.slice(0, 50).map((n)=>n.key),
8024
8693
  removedKeys: [],
8025
8694
  changedKeys: []
8026
8695
  };
8027
- const prevMap = new Map(prev.nodes.map((n)=>[
8696
+ const prevMap = new Map(prevNodes.map((n)=>[
8028
8697
  n.key,
8029
8698
  n
8030
8699
  ]));
8031
- const nextMap = new Map(next.nodes.map((n)=>[
8700
+ const nextMap = new Map(nextNodes.map((n)=>[
8032
8701
  n.key,
8033
8702
  n
8034
8703
  ]));
@@ -8135,6 +8804,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8135
8804
  return '<<<EXTJS_HTML_END>>>';
8136
8805
  }
8137
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");
8138
8808
  function chromium_hard_reload_define_property(obj, key, value) {
8139
8809
  if (key in obj) Object.defineProperty(obj, key, {
8140
8810
  value: value,
@@ -8164,6 +8834,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8164
8834
  };
8165
8835
  if (compiler.hooks?.watchRun?.tapAsync) compiler.hooks.watchRun.tapAsync('run-browsers:watch', (compilerWithModifiedFiles, done)=>{
8166
8836
  try {
8837
+ this.contentReloadGeneration += 1;
8167
8838
  const modifiedFiles = compilerWithModifiedFiles?.modifiedFiles || new Set();
8168
8839
  const normalizedModifiedFilePaths = Array.from(modifiedFiles).map((filePath)=>String(filePath).replace(/\\/g, '/'));
8169
8840
  const compilerContextRoot = String(compiler?.options?.context || '').replace(/\\/g, '/');
@@ -8196,9 +8867,34 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8196
8867
  });
8197
8868
  }
8198
8869
  }
8199
- if (hitManifest) this.ctx.setPendingReloadReason('manifest');
8200
- else if (localeChanged) this.ctx.setPendingReloadReason('locales');
8201
- 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
+ }
8202
8898
  } catch (error) {
8203
8899
  this.logger?.warn?.('[reload-debug] watchRun inspect failed:', String(error));
8204
8900
  }
@@ -8207,17 +8903,139 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8207
8903
  compiler.hooks.done.tapPromise('run-browsers:module', async (stats)=>{
8208
8904
  const hasErrors = 'function' == typeof stats?.hasErrors ? stats.hasErrors() : !!stats?.compilation?.errors?.length;
8209
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);
8210
8917
  this.refreshSWFromManifest(stats.compilation);
8211
- 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;
8212
8925
  if (!this.hasCompletedSuccessfulBuild) {
8213
8926
  this.hasCompletedSuccessfulBuild = true;
8214
8927
  this.firstSuccessfulBuildAtMs = Date.now();
8928
+ this.pendingContentReloadEntryNames = [];
8215
8929
  this.ctx.clearPendingReloadReason();
8216
8930
  return;
8217
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 || ''));
8218
8934
  const pendingReason = this.ctx.getPendingReloadReason();
8219
- const reason = pendingReason;
8220
- 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;
8221
9039
  this.ctx.clearPendingReloadReason();
8222
9040
  const now = Date.now();
8223
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})`);
@@ -8238,7 +9056,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8238
9056
  });
8239
9057
  const extensionRoot = this.ctx.getExtensionRoot();
8240
9058
  if (extensionRoot) {
8241
- const manifestReady = await (0, manifest_readiness.f)(extensionRoot, {
9059
+ const manifestReady = await (0, manifest_readiness.fR)(extensionRoot, {
8242
9060
  timeoutMs: 8000
8243
9061
  });
8244
9062
  if (!manifestReady) return void this.logger?.warn?.('[reload] manifest.json did not stabilize before hard reload');
@@ -8257,6 +9075,40 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8257
9075
  this.warnedHardReloadFailure = true;
8258
9076
  this.logger?.warn?.(browsers_lib_messages.WsE(this.options?.browser));
8259
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
+ }
8260
9112
  });
8261
9113
  }
8262
9114
  refreshSWFromManifest(compilation) {
@@ -8273,12 +9125,164 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8273
9125
  }
8274
9126
  } catch {}
8275
9127
  }
8276
- 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) {
8277
9260
  try {
8278
- const serviceWorkerEntrypointName = 'background/service_worker';
8279
- const discovered = this.collectEntrypointModuleResourcePaths(compilation, serviceWorkerEntrypointName);
8280
- this.serviceWorkerSourceDependencyPaths = discovered;
8281
- } 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;
8282
9286
  }
8283
9287
  collectEntrypointModuleResourcePaths(compilation, entrypointName) {
8284
9288
  const collectedResourcePaths = new Set();
@@ -8291,15 +9295,175 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8291
9295
  for (const chunk of entrypointChunks){
8292
9296
  const modulesIterable = chunkGraph.getChunkModulesIterable?.(chunk) || chunkGraph.getChunkModulesIterableBySourceType?.(chunk, "javascript") || chunkGraph.getChunkModules?.(chunk);
8293
9297
  if (modulesIterable) for (const module of modulesIterable){
8294
- const resourcePath = module?.resource || module?.rootModule?.resource || module?.originalSource?.()?.resource;
8295
- 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);
8296
9300
  }
8297
9301
  }
8298
9302
  return collectedResourcePaths;
8299
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
+ }
8300
9453
  shouldEmitReloadActionEvent() {
8301
9454
  return Boolean(this.options?.source || this.options?.watchSource);
8302
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
+ }
8303
9467
  constructor(options, ctx){
8304
9468
  chromium_hard_reload_define_property(this, "options", void 0);
8305
9469
  chromium_hard_reload_define_property(this, "ctx", void 0);
@@ -8308,17 +9472,89 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8308
9472
  chromium_hard_reload_define_property(this, "warnedHardReloadFailure", void 0);
8309
9473
  chromium_hard_reload_define_property(this, "hasCompletedSuccessfulBuild", void 0);
8310
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);
8311
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);
8312
9488
  this.options = options;
8313
9489
  this.ctx = ctx;
8314
9490
  this.hasCompletedSuccessfulBuild = false;
8315
9491
  this.firstSuccessfulBuildAtMs = null;
9492
+ this.contentReloadGeneration = 0;
9493
+ this.contentReloadQuietPeriodMs = 1200;
9494
+ this.contentReloadFollowupMs = 1200;
9495
+ this.lastWatchIncludedContentChanges = false;
9496
+ this.awaitingSettledContentBuild = false;
8316
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 = [];
8317
9505
  }
8318
9506
  }
8319
9507
  chromium_hard_reload_define_property(ChromiumHardReloadPlugin, "INITIAL_RELOAD_COOLDOWN_MS", 5000);
8320
9508
  var shared_utils = __webpack_require__("./webpack/plugin-browsers/browsers-lib/shared-utils.ts");
8321
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
+ }
8322
9558
  var instance_registry = __webpack_require__("./webpack/plugin-browsers/browsers-lib/instance-registry.ts");
8323
9559
  var discovery = __webpack_require__("./webpack/plugin-browsers/run-chromium/chromium-source-inspection/discovery.ts");
8324
9560
  async function waitForChromeRemoteDebugging(port, instanceId) {
@@ -8346,10 +9582,21 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8346
9582
  }
8347
9583
  throw new Error(browsers_lib_messages.olb(port));
8348
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
+ }
8349
9595
  async function ensureTargetAndSession(cdpClient, url, options) {
8350
9596
  const forceNavigate = Boolean(options?.forceNavigate);
9597
+ const normalizedUrl = normalizeInspectableUrl(url);
8351
9598
  const targets = await cdpClient.getTargets();
8352
- 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 || ''));
8353
9600
  let targetId = '';
8354
9601
  if (existingTarget && existingTarget.targetId) {
8355
9602
  targetId = String(existingTarget.targetId);
@@ -8376,70 +9623,23 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8376
9623
  try {
8377
9624
  await cdpClient.enableRuntimeAndLog(String(tempSession));
8378
9625
  } catch {}
8379
- await cdpClient.navigate(String(tempSession), url);
8380
- }
8381
- }
8382
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(browsers_lib_messages.MjP());
8383
- const sessionId = String(await cdpClient.attachToTarget(targetId) || '');
8384
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
8385
- console.log(browsers_lib_messages.v5i(sessionId));
8386
- console.log(browsers_lib_messages._JL());
8387
- }
8388
- await cdpClient.sendCommand('Page.enable', {}, sessionId);
8389
- try {
8390
- await cdpClient.enableRuntimeAndLog(sessionId);
8391
- } catch {}
8392
- return {
8393
- targetId: String(targetId),
8394
- sessionId: String(sessionId)
8395
- };
8396
- }
8397
- async function extractPageHtml(cdpClient, sessionId, logSamples = 'true' === process.env.EXTENSION_AUTHOR_MODE, includeShadow = 'open-only') {
8398
- let html = await cdpClient.getPageHTML(sessionId, includeShadow);
8399
- if (!html) try {
8400
- const targets = await cdpClient.getTargets();
8401
- const fallbackTarget = targets.find((target)=>'page' === target.type && /example\.com|http/.test(String(target.url || '')));
8402
- if (fallbackTarget && fallbackTarget.targetId) {
8403
- const newSessionId = await cdpClient.attachToTarget(fallbackTarget.targetId);
8404
- await cdpClient.waitForContentScriptInjection(newSessionId);
8405
- const retryHtml = await cdpClient.getPageHTML(newSessionId, includeShadow);
8406
- if (logSamples) {
8407
- const sample2 = (retryHtml || '').slice(0, 200).replace(/\n/g, ' ');
8408
- console.log(browsers_lib_messages.LcW(sample2));
8409
- }
8410
- if (retryHtml) return retryHtml;
9626
+ await cdpClient.navigate(String(tempSession), url);
8411
9627
  }
8412
- } catch {}
8413
- if (!html || !/(id=\"extension-root\"|content_script|content_title|js-probe)/.test(html)) for(let i = 0; i < 3; i++){
8414
- await new Promise((r)=>setTimeout(r, 500));
8415
- try {
8416
- const againHtml = await cdpClient.getPageHTML(sessionId, includeShadow);
8417
- if (logSamples) {
8418
- const sample3 = (againHtml || '').slice(0, 200).replace(/\n/g, ' ');
8419
- console.log(browsers_lib_messages.jUj(sample3));
8420
- }
8421
- if (againHtml && /(id=\"extension-root\"|content_script|content_title|js-probe)/.test(againHtml)) {
8422
- html = againHtml;
8423
- break;
8424
- }
8425
- } catch {}
8426
9628
  }
8427
- if (!html || 0 === html.trim().length) for(let i = 0; i < 6; i++){
8428
- try {
8429
- const evaluatedHtml = await cdpClient.evaluate(sessionId, '(() => { try { return String(document.documentElement.outerHTML||"") } catch(e) { return "" } })()');
8430
- if (logSamples) {
8431
- const sample4 = (evaluatedHtml || '').slice(0, 200).replace(/\n/g, ' ');
8432
- console.log(browsers_lib_messages.jUj(sample4));
8433
- }
8434
- if (evaluatedHtml && evaluatedHtml.trim().length > 0) {
8435
- html = evaluatedHtml;
8436
- break;
8437
- }
8438
- } catch {}
8439
- 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());
8440
9634
  }
8441
- if (logSamples) console.log(browsers_lib_messages.ehY());
8442
- 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
+ };
8443
9643
  }
8444
9644
  function chromium_source_inspection_define_property(obj, key, value) {
8445
9645
  if (key in obj) Object.defineProperty(obj, key, {
@@ -8504,7 +9704,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8504
9704
  const includeShadow = 'off' !== this.devOptions.sourceIncludeShadow;
8505
9705
  try {
8506
9706
  const payload = await this.cdpClient.evaluate(this.currentSessionId, `(() => {
8507
- 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"])');
8508
9708
  if (!rootEl) return null;
8509
9709
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
8510
9710
  const maxDepth = 6;
@@ -8568,6 +9768,28 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8568
9768
  if (payload && 'object' == typeof payload) return payload;
8569
9769
  } catch {}
8570
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
+ }
8571
9793
  async getPageMetaSnapshot() {
8572
9794
  if (!this.cdpClient || !this.currentSessionId) return {};
8573
9795
  try {
@@ -8629,7 +9851,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8629
9851
  const includeShadow = 'off' !== this.devOptions.sourceIncludeShadow;
8630
9852
  try {
8631
9853
  const payload = await this.cdpClient.evaluate(this.currentSessionId, `(() => {
8632
- 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"])');
8633
9855
  if (!rootEl) return null;
8634
9856
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
8635
9857
  const maxDepth = 4;
@@ -8849,6 +10071,10 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8849
10071
  if (this.devOptions.sourceMeta) {
8850
10072
  const metaSnapshot = await this.getPageMetaSnapshot();
8851
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);
8852
10078
  }
8853
10079
  if (Array.isArray(this.devOptions.sourceProbe)) {
8854
10080
  const probes = await this.getSelectorProbes(this.devOptions.sourceProbe);
@@ -8911,6 +10137,14 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8911
10137
  ...payload
8912
10138
  }));
8913
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
+ }
8914
10148
  async getCdpPort() {
8915
10149
  const instanceId = this.devOptions.instanceId;
8916
10150
  return (0, shared_utils.jl)(this.devOptions.port, instanceId);
@@ -8954,30 +10188,14 @@ Set background.noDynamicEntryWarning to true to disable this warning.
8954
10188
  await this.emitSourceOutput(String(initialHtml || ''), 'pre_injection');
8955
10189
  } catch {}
8956
10190
  if (this.isAuthorMode()) console.log(browsers_lib_messages.mOc());
8957
- await this.cdpClient.waitForContentScriptInjection(this.currentSessionId);
8958
- 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", {
8959
10194
  url
8960
10195
  });
10196
+ if (!injected) await this.cdpClient.pollForVisibleShadowHostContent(this.currentSessionId);
8961
10197
  try {
8962
- const deadline = Date.now() + 20000;
8963
- const started = Date.now();
8964
- while(Date.now() < deadline){
8965
- const hasRoot = await this.cdpClient.evaluate(this.currentSessionId, `(() => { try {
8966
- const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root="true"]'));
8967
- if (!hosts.length) return false;
8968
- for (const h of hosts) {
8969
- try {
8970
- const sr = h && h.shadowRoot;
8971
- if (sr && (String(sr.innerHTML||'').length > 0)) return true;
8972
- } catch { /* ignore */ }
8973
- }
8974
- return false;
8975
- } catch { return false } })()`);
8976
- if (hasRoot) break;
8977
- const elapsed = Date.now() - started;
8978
- const delay = elapsed < 2000 ? 150 : 500;
8979
- await new Promise((r)=>setTimeout(r, delay));
8980
- }
10198
+ await this.waitForContentScriptStyles(this.currentSessionId);
8981
10199
  } catch {}
8982
10200
  const outputConfig = this.getOutputConfig();
8983
10201
  const html = await extractPageHtml(this.cdpClient, this.currentSessionId, this.isAuthorMode(), outputConfig.includeShadow);
@@ -9011,14 +10229,104 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9011
10229
  ws.on('message', async (data)=>{
9012
10230
  try {
9013
10231
  const message = JSON.parse(data);
9014
- 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
+ }
9015
10243
  } catch (error) {}
9016
10244
  });
9017
10245
  }
9018
10246
  stopWatching() {
9019
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
+ }
9020
10254
  if (this.isAuthorMode()) console.log(browsers_lib_messages.Qx1());
9021
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
+ }
9022
10330
  async handleFileChange() {
9023
10331
  if (!this.cdpClient || !this.currentSessionId) return void console.warn(browsers_lib_messages.MfN());
9024
10332
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
@@ -9029,52 +10337,188 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9029
10337
  console.log(browsers_lib_messages.$xt());
9030
10338
  console.log(browsers_lib_messages.Tev());
9031
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) {
9032
10350
  const sourceUrl = 'string' == typeof this.devOptions.source && 'true' !== this.devOptions.source ? this.devOptions.source : '';
9033
- if (sourceUrl) {
10351
+ if (sourceUrl) try {
9034
10352
  emitActionEvent('watch_reinspect_source_url', {
9035
10353
  url: sourceUrl
9036
10354
  });
9037
10355
  const html = await this.inspectSource(sourceUrl, {
9038
- forceNavigate: true
10356
+ forceNavigate: false
9039
10357
  });
9040
10358
  await this.emitSourceOutput(html || '', 'updated');
9041
10359
  return;
9042
- }
9043
- await this.cdpClient.waitForContentScriptInjection(this.currentSessionId);
9044
- if (this.isAuthorMode()) console.log(browsers_lib_messages.Mcx());
9045
- let html = '';
9046
- const outputConfig = this.getOutputConfig();
9047
- try {
9048
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9049
- } catch (e) {
9050
- await new Promise((r)=>setTimeout(r, 250));
9051
- try {
9052
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9053
- } catch {}
9054
- }
9055
- if (!html) {
9056
- await new Promise((r)=>setTimeout(r, 300));
9057
- try {
9058
- html = await this.cdpClient.getPageHTML(this.currentSessionId, outputConfig.includeShadow);
9059
- } catch {}
9060
- }
9061
- await this.emitSourceOutput(html || '', 'updated');
9062
- } catch (error) {
10360
+ } catch {}
9063
10361
  console.error(browsers_lib_messages.acp(error.message));
9064
- 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')) {
9065
10364
  console.log(browsers_lib_messages.bGB());
9066
- await this.reconnectToTarget();
10365
+ await this.reconnectToTarget(sourceUrl || void 0);
9067
10366
  }
9068
10367
  }
9069
10368
  }, 300);
9070
10369
  }
9071
- 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) {
9072
10498
  if (!this.isAuthorMode()) return;
9073
10499
  try {
9074
- if (!this.cdpClient || !this.currentTargetId) return void console.warn(browsers_lib_messages.tVJ());
9075
10500
  console.log(browsers_lib_messages.kGe());
9076
- this.currentSessionId = await this.cdpClient.attachToTarget(this.currentTargetId) || null;
9077
- 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());
9078
10522
  } catch (error) {
9079
10523
  console.error(browsers_lib_messages.pcF(error.message));
9080
10524
  }
@@ -9105,19 +10549,32 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9105
10549
  if (this.devOptions.source && 'string' == typeof this.devOptions.source && 'true' !== this.devOptions.source) urlToInspect = this.devOptions.source;
9106
10550
  else if (this.devOptions.startingUrl) urlToInspect = this.devOptions.startingUrl;
9107
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
+ }
9108
10565
  const html = await this.inspectSource(urlToInspect, {
9109
10566
  forceNavigate: this.devOptions.watchSource && this.hasInspectedSourceOnce
9110
10567
  });
9111
10568
  this.hasInspectedSourceOnce = true;
9112
10569
  await this.printHTML(html);
9113
- const webSocketServer = compiler.options.webSocketServer;
9114
- if (this.devOptions.watchSource) if (webSocketServer) await this.startWatching(webSocketServer);
9115
- else try {
9116
- const updated = await this.inspectSource(urlToInspect, {
9117
- forceNavigate: true
9118
- });
9119
- await this.printUpdatedHTML(updated || '');
9120
- } 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
+ }
9121
10578
  } catch (error) {
9122
10579
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.error(browsers_lib_messages.b82(error.message));
9123
10580
  }
@@ -9131,7 +10588,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9131
10588
  chromium_source_inspection_define_property(this, "isInitialized", false);
9132
10589
  chromium_source_inspection_define_property(this, "isWatching", false);
9133
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);
9134
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);
9135
10596
  chromium_source_inspection_define_property(this, "runtimeMode", void 0);
9136
10597
  chromium_source_inspection_define_property(this, "lastOutputHash", void 0);
9137
10598
  chromium_source_inspection_define_property(this, "lastByteLength", void 0);
@@ -9204,38 +10665,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9204
10665
  run_chromium_define_property(this, "logTab", void 0);
9205
10666
  run_chromium_define_property(this, "logger", void 0);
9206
10667
  run_chromium_define_property(this, "chromiumCtx", void 0);
9207
- this.extension = options.extension;
9208
- this.browser = options.browser;
9209
- this.startingUrl = options.startingUrl;
9210
- this.preferences = options.preferences;
9211
- this.profile = options.profile;
9212
- this.browserFlags = options.browserFlags;
9213
- this.excludeBrowserFlags = options.excludeBrowserFlags;
9214
- this.noOpen = options.noOpen;
10668
+ Object.assign(this, (0, runtime_options.pA)(options));
9215
10669
  this.chromiumBinary = options.chromiumBinary;
9216
- this.instanceId = options.instanceId;
9217
- this.port = options.port;
9218
- this.source = options.source;
9219
- this.watchSource = options.watchSource;
9220
- this.sourceFormat = options.sourceFormat;
9221
- this.sourceSummary = options.sourceSummary;
9222
- this.sourceMeta = options.sourceMeta;
9223
- this.sourceProbe = options.sourceProbe;
9224
- this.sourceTree = options.sourceTree;
9225
- this.sourceConsole = options.sourceConsole;
9226
- this.sourceDom = options.sourceDom;
9227
- this.sourceMaxBytes = options.sourceMaxBytes;
9228
- this.sourceRedact = options.sourceRedact;
9229
- this.sourceIncludeShadow = options.sourceIncludeShadow;
9230
- this.sourceDiff = options.sourceDiff;
9231
- this.logLevel = options.logLevel;
9232
- this.logContexts = options.logContexts;
9233
- this.logFormat = options.logFormat;
9234
- this.logTimestamps = options.logTimestamps;
9235
- this.logColor = options.logColor;
9236
- this.logUrl = options.logUrl;
9237
- this.logTab = options.logTab;
9238
- this.dryRun = options.dryRun;
9239
10670
  }
9240
10671
  }
9241
10672
  var firefox_context = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-context/index.ts");
@@ -9288,17 +10719,65 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9288
10719
  return obj;
9289
10720
  }
9290
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
+ }
9291
10730
  apply(compiler) {
9292
10731
  if (compiler?.hooks?.watchRun?.tapAsync) compiler.hooks.watchRun.tapAsync('run-browsers:watch', (compilation, done)=>{
9293
10732
  try {
10733
+ this.contentReloadGeneration += 1;
9294
10734
  const files = compilation?.modifiedFiles || new Set();
9295
10735
  const normalized = Array.from(files).map((p)=>String(p).replace(/\\/g, '/'));
9296
- const hitManifest = normalized.some((p)=>/(^|\/)manifest\.json$/i.test(p));
9297
- const hitLocales = normalized.some((p)=>/(^|\/)__?locales\/.+\.json$/i.test(p));
9298
- const hitServiceWorker = normalized.some((p)=>/(^|\/)(service_worker|background)\.(m?js|cjs|ts)$/i.test(p));
9299
- if (hitManifest) this.ctx.setPendingReloadReason?.('manifest');
9300
- else if (hitLocales) this.ctx.setPendingReloadReason?.('locales');
9301
- 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
+ }
9302
10781
  } catch (error) {
9303
10782
  this.ctx.logger?.warn?.('[reload] watchRun inspect failed:', String(error));
9304
10783
  }
@@ -9309,43 +10788,600 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9309
10788
  if (hasErrors) return void done();
9310
10789
  try {
9311
10790
  const compilation = stats?.compilation;
9312
- const assetsArr = Array.isArray(compilation?.getAssets?.()) ? compilation.getAssets() : [];
9313
- 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);
9314
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
+ }
9315
10820
  if (controller && 'function' == typeof controller.hardReload) {
9316
- 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
+ }
9317
10881
  if (this.shouldEmitReloadActionEvent()) emitActionEvent('extension_reload', {
9318
10882
  reason: reason || 'unknown',
9319
10883
  browser: this.host.browser
9320
10884
  });
10885
+ this.pendingContentReloadEntryNames = [];
10886
+ globalThis.__EXTJS_PENDING_FIREFOX_CONTENT_RELOAD__ = false;
10887
+ this.ctx.clearPendingReloadReason?.();
9321
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;
9322
11105
  }
9323
- } catch {}
9324
- done();
9325
- });
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;
9326
11148
  }
9327
- shouldEmitReloadActionEvent() {
9328
- 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 || []));
9329
11168
  }
9330
11169
  constructor(host, ctx){
9331
11170
  firefox_hard_reload_define_property(this, "host", void 0);
9332
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);
9333
11185
  this.host = host;
9334
11186
  this.ctx = ctx;
9335
11187
  }
9336
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");
9337
11191
  var messaging_client = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/messaging-client.ts");
9338
- var logging = __webpack_require__("./webpack/plugin-browsers/run-firefox/firefox-source-inspection/remote-firefox/logging.ts");
11192
+ var external_url_ = __webpack_require__("url");
9339
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
+ }
9340
11300
  async function selectActors(client, urlToInspect) {
9341
11301
  const deadline = Date.now() + 10000;
9342
11302
  let triedAddTab = false;
11303
+ const normalizedUrlToInspect = setup_firefox_inspection_actors_normalizeInspectableUrl(urlToInspect);
9343
11304
  while(Date.now() < deadline){
9344
11305
  const allTargets = await client.getTargets() || [];
9345
- for (const target of allTargets)if (target && 'string' == typeof target.url && target.url === urlToInspect && target.actor) return {
9346
- tabActor: target.actor,
9347
- consoleActor: target.consoleActor || target.actor
9348
- };
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
+ }
9349
11385
  if (!triedAddTab && urlToInspect) {
9350
11386
  triedAddTab = true;
9351
11387
  try {
@@ -9359,15 +11395,48 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9359
11395
  }
9360
11396
  }
9361
11397
  }
9362
- for (const target of allTargets)if (target && ('string' == typeof target.actor || 'number' == typeof target.outerWindowID || 'number' == typeof target.outerWindowId)) return {
9363
- tabActor: String(target.actor || ''),
9364
- consoleActor: String(target.consoleActor || target.actor || '')
9365
- };
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
+ }
9366
11425
  await new Promise((r)=>setTimeout(r, TARGET_SCAN_INTERVAL_MS));
9367
11426
  }
9368
11427
  throw new Error(browsers_lib_messages.Itp());
9369
11428
  }
9370
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
+ }
9371
11440
  async function ensureNavigatedAndLoaded(client, urlToInspect, tabActor) {
9372
11441
  if (!tabActor) throw new Error(browsers_lib_messages.R4W());
9373
11442
  let consoleActor = tabActor;
@@ -9390,6 +11459,31 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9390
11459
  console.warn('[RDP] attach(frameActor) failed:', String(err.message || err));
9391
11460
  }
9392
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
+ }
9393
11487
  try {
9394
11488
  await client.navigateViaScript(consoleActor, urlToInspect);
9395
11489
  await client.waitForPageReady(consoleActor, urlToInspect, PAGE_READY_TIMEOUT_MS);
@@ -9658,6 +11752,10 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9658
11752
  }
9659
11753
  })()`);
9660
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);
9661
11759
  }
9662
11760
  if (Array.isArray(this.devOptions?.sourceProbe)) {
9663
11761
  const probes = await this.evaluateJson(this.currentConsoleActor, `(() => {
@@ -9692,7 +11790,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9692
11790
  }
9693
11791
  if (this.devOptions?.sourceTree && 'off' !== this.devOptions.sourceTree) {
9694
11792
  const tree = await this.evaluateJson(this.currentConsoleActor, `(() => {
9695
- 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"])');
9696
11794
  if (!rootEl) return null;
9697
11795
  const root = (${'off' !== this.devOptions.sourceIncludeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
9698
11796
  const maxDepth = 4;
@@ -9773,11 +11871,238 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9773
11871
  if ('string' == typeof json && json.length > 0) return JSON.parse(json);
9774
11872
  } catch {}
9775
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
+ }
9776
12101
  async getDomSnapshot() {
9777
12102
  if (!this.client || !this.currentConsoleActor) return;
9778
12103
  const includeShadow = this.devOptions?.sourceIncludeShadow !== 'off';
9779
12104
  const payload = await this.evaluateJson(this.currentConsoleActor, `(() => {
9780
- 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"])');
9781
12106
  if (!rootEl) return null;
9782
12107
  const root = (${includeShadow ? 'rootEl.shadowRoot || rootEl' : 'rootEl'});
9783
12108
  const maxDepth = 6;
@@ -9837,6 +12162,173 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9837
12162
  truncated,
9838
12163
  nodes
9839
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
+ };
9840
12332
  })()`);
9841
12333
  if (payload && 'object' == typeof payload) return payload;
9842
12334
  }
@@ -9884,7 +12376,7 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9884
12376
  await client.connect(port);
9885
12377
  this.client = client;
9886
12378
  this.setupConsoleCapture();
9887
- if (this.devOptions?.sourceConsole) await (0, logging.c)(client);
12379
+ if (this.devOptions?.sourceConsole) await (0, remote_firefox_logging.c)(client);
9888
12380
  this.initialized = true;
9889
12381
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
9890
12382
  console.log(browsers_lib_messages.X6h());
@@ -9951,6 +12443,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9951
12443
  const currentTitle = await this.client.evaluate(actorToUse, 'String(document.title)');
9952
12444
  if ('string' == typeof currentTitle) meta.title = currentTitle;
9953
12445
  } catch {}
12446
+ try {
12447
+ await this.waitForContentScriptStyles(actorToUse);
12448
+ } catch {}
9954
12449
  const html = await (0, source_inspect.Lj)(this.client, descriptor, actorToUse) || '';
9955
12450
  this.emitSourceOutput(html, 'post_injection', meta);
9956
12451
  return;
@@ -9963,7 +12458,112 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9963
12458
  }
9964
12459
  async waitForContentScriptInjection(consoleActor) {
9965
12460
  if (!this.client) return;
9966
- 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
+ }
9967
12567
  }
9968
12568
  async handleFileChange() {
9969
12569
  if (!this.client || !this.currentConsoleActor) return;
@@ -9977,6 +12577,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
9977
12577
  }
9978
12578
  if (this.lastUrlToInspect) await this.ensureUrlAndReady(this.currentConsoleActor, this.lastUrlToInspect);
9979
12579
  await this.waitForContentScriptInjection(this.currentConsoleActor);
12580
+ try {
12581
+ await this.waitForContentScriptStyles(this.currentConsoleActor);
12582
+ } catch {}
9980
12583
  let lastError = null;
9981
12584
  for(let attempt = 0; attempt < 3; attempt++){
9982
12585
  try {
@@ -10002,6 +12605,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10002
12605
  }
10003
12606
  }, CHANGE_DEBOUNCE_MS);
10004
12607
  }
12608
+ registerContentReloadSnapshotHook() {
12609
+ globalThis.__EXTJS_ON_FIREFOX_CONTENT_RELOADED__ = async ()=>{
12610
+ await this.handleFileChange();
12611
+ };
12612
+ }
10005
12613
  apply(compiler) {
10006
12614
  if (this.host.dryRun) return;
10007
12615
  if ('development' !== compiler.options.mode) return;
@@ -10012,6 +12620,18 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10012
12620
  if (!this.initialized) await this.initialize();
10013
12621
  const urlToInspect = this.resolveUrlToInspect();
10014
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
+ }
10015
12635
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(browsers_lib_messages.rCC(urlToInspect));
10016
12636
  const { tabActor, consoleActor } = await this.selectActors(urlToInspect);
10017
12637
  this.currentTabActor = tabActor;
@@ -10025,15 +12645,61 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10025
12645
  const resolvedConsoleActor = await this.resolveConsoleActor(tabActor, urlToInspect);
10026
12646
  this.currentConsoleActor = resolvedConsoleActor || consoleActor;
10027
12647
  if (this.currentConsoleActor) {
10028
- await this.waitForContentScriptInjection(this.currentConsoleActor);
10029
- emitActionEvent("content_script_injected", {
10030
- url: urlToInspect
10031
- });
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 {}
10032
12698
  await this.printHTML(this.currentConsoleActor);
10033
12699
  }
10034
12700
  if (this.devOptions?.watchSource) {
12701
+ this.registerContentReloadSnapshotHook();
10035
12702
  this.isWatching = true;
10036
- await this.handleFileChange();
10037
12703
  }
10038
12704
  } catch (error) {
10039
12705
  if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.error(browsers_lib_messages.b82(error.message));
@@ -10102,8 +12768,6 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10102
12768
  run_firefox_define_property(this, "geckoBinary", void 0);
10103
12769
  run_firefox_define_property(this, "port", void 0);
10104
12770
  run_firefox_define_property(this, "instanceId", void 0);
10105
- run_firefox_define_property(this, "keepProfileChanges", void 0);
10106
- run_firefox_define_property(this, "copyFromProfile", void 0);
10107
12771
  run_firefox_define_property(this, "source", void 0);
10108
12772
  run_firefox_define_property(this, "watchSource", void 0);
10109
12773
  run_firefox_define_property(this, "sourceFormat", void 0);
@@ -10128,38 +12792,8 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10128
12792
  run_firefox_define_property(this, "logger", void 0);
10129
12793
  run_firefox_define_property(this, "firefoxCtx", void 0);
10130
12794
  run_firefox_define_property(this, "rdpController", void 0);
10131
- this.extension = options.extension;
10132
- this.browser = options.browser;
10133
- this.startingUrl = options.startingUrl;
10134
- this.preferences = options.preferences;
10135
- this.profile = options.profile;
10136
- this.browserFlags = options.browserFlags;
10137
- this.excludeBrowserFlags = options.excludeBrowserFlags;
10138
- this.noOpen = options.noOpen;
12795
+ Object.assign(this, (0, runtime_options.pA)(options));
10139
12796
  this.geckoBinary = options.geckoBinary;
10140
- this.instanceId = options.instanceId;
10141
- this.port = options.port;
10142
- this.source = options.source;
10143
- this.watchSource = options.watchSource;
10144
- this.sourceFormat = options.sourceFormat;
10145
- this.sourceSummary = options.sourceSummary;
10146
- this.sourceMeta = options.sourceMeta;
10147
- this.sourceProbe = options.sourceProbe;
10148
- this.sourceTree = options.sourceTree;
10149
- this.sourceConsole = options.sourceConsole;
10150
- this.sourceDom = options.sourceDom;
10151
- this.sourceMaxBytes = options.sourceMaxBytes;
10152
- this.sourceRedact = options.sourceRedact;
10153
- this.sourceIncludeShadow = options.sourceIncludeShadow;
10154
- this.sourceDiff = options.sourceDiff;
10155
- this.logLevel = options.logLevel;
10156
- this.logContexts = options.logContexts;
10157
- this.logFormat = options.logFormat;
10158
- this.logTimestamps = options.logTimestamps;
10159
- this.logColor = options.logColor;
10160
- this.logUrl = options.logUrl;
10161
- this.logTab = options.logTab;
10162
- this.dryRun = options.dryRun;
10163
12797
  }
10164
12798
  }
10165
12799
  function plugin_browsers_define_property(obj, key, value) {
@@ -10224,39 +12858,9 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10224
12858
  plugin_browsers_define_property(this, "logUrl", void 0);
10225
12859
  plugin_browsers_define_property(this, "logTab", void 0);
10226
12860
  const normalized = normalizePluginOptions(options);
10227
- this.extension = normalized.extension;
10228
- this.browser = normalized.browser;
10229
- this.startingUrl = normalized.startingUrl;
10230
- this.preferences = normalized.preferences;
10231
- this.profile = normalized.profile;
10232
- this.browserFlags = normalized.browserFlags;
10233
- this.excludeBrowserFlags = normalized.excludeBrowserFlags;
10234
- this.noOpen = normalized.noOpen;
12861
+ Object.assign(this, (0, runtime_options.pA)(normalized));
10235
12862
  this.chromiumBinary = normalized.chromiumBinary;
10236
12863
  this.geckoBinary = normalized.geckoBinary;
10237
- this.instanceId = normalized.instanceId;
10238
- this.port = normalized.port;
10239
- this.source = normalized.source;
10240
- this.watchSource = normalized.watchSource;
10241
- this.sourceFormat = normalized.sourceFormat;
10242
- this.sourceSummary = normalized.sourceSummary;
10243
- this.sourceMeta = normalized.sourceMeta;
10244
- this.sourceProbe = normalized.sourceProbe;
10245
- this.sourceTree = normalized.sourceTree;
10246
- this.sourceConsole = normalized.sourceConsole;
10247
- this.sourceDom = normalized.sourceDom;
10248
- this.sourceMaxBytes = normalized.sourceMaxBytes;
10249
- this.sourceRedact = normalized.sourceRedact;
10250
- this.sourceIncludeShadow = normalized.sourceIncludeShadow;
10251
- this.sourceDiff = normalized.sourceDiff;
10252
- this.logLevel = normalized.logLevel;
10253
- this.logContexts = normalized.logContexts;
10254
- this.logFormat = normalized.logFormat;
10255
- this.logTimestamps = normalized.logTimestamps;
10256
- this.logColor = normalized.logColor;
10257
- this.logUrl = normalized.logUrl;
10258
- this.logTab = normalized.logTab;
10259
- this.dryRun = normalized.dryRun;
10260
12864
  if ('chromium-based' === this.browser && !this.chromiumBinary) {
10261
12865
  console.error(browsers_lib_messages.nek());
10262
12866
  process.exit(1);
@@ -10426,6 +13030,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10426
13030
  watchSource: devOptions.watchSource,
10427
13031
  sourceFormat: devOptions.sourceFormat,
10428
13032
  sourceSummary: devOptions.sourceSummary,
13033
+ sourceMeta: devOptions.sourceMeta,
13034
+ sourceProbe: devOptions.sourceProbe,
13035
+ sourceTree: devOptions.sourceTree,
13036
+ sourceConsole: devOptions.sourceConsole,
13037
+ sourceDom: devOptions.sourceDom,
10429
13038
  sourceMaxBytes: devOptions.sourceMaxBytes,
10430
13039
  sourceRedact: devOptions.sourceRedact,
10431
13040
  sourceIncludeShadow: devOptions.sourceIncludeShadow,
@@ -10450,6 +13059,11 @@ Set background.noDynamicEntryWarning to true to disable this warning.
10450
13059
  clean: devOptions.output.clean,
10451
13060
  path: primaryExtensionOutputDir,
10452
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',
10453
13067
  hotUpdateChunkFilename: 'hot/[id].[fullhash].hot-update.js',
10454
13068
  hotUpdateMainFilename: 'hot/[runtime].[fullhash].hot-update.json',
10455
13069
  environment: {