extension-develop 3.10.3 → 3.11.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.
- package/dist/215.cjs +350 -69
- package/dist/323.cjs +456 -26
- package/dist/324.cjs +15 -9
- package/dist/{270.cjs → 677.cjs} +3118 -504
- package/dist/ensure-hmr-for-scripts.cjs +50 -0
- package/dist/ensure-hmr-for-scripts.js +145 -0
- package/dist/extension-js-devtools/chrome/content_scripts/content-0.js +2 -2
- package/dist/extension-js-devtools/{chromium/content_scripts/styles.24e59c3d.css → chrome/content_scripts/styles.5456c644.css} +1 -1
- package/dist/extension-js-devtools/chrome/manifest.json +1 -1
- package/dist/extension-js-devtools/chrome/pages/centralized-logger.css +1 -1
- package/dist/extension-js-devtools/chrome/pages/welcome.css +1 -1
- package/dist/extension-js-devtools/chrome/pages/welcome.js +2 -2
- package/dist/extension-js-devtools/chrome/scripts/logger-client.js +1 -1
- package/dist/extension-js-devtools/chromium/content_scripts/content-0.js +2 -2
- package/dist/extension-js-devtools/{edge/content_scripts/styles.24e59c3d.css → chromium/content_scripts/styles.5456c644.css} +1 -1
- package/dist/extension-js-devtools/chromium/manifest.json +1 -1
- package/dist/extension-js-devtools/chromium/pages/centralized-logger.css +1 -1
- package/dist/extension-js-devtools/chromium/pages/welcome.css +1 -1
- package/dist/extension-js-devtools/chromium/pages/welcome.js +2 -2
- package/dist/extension-js-devtools/chromium/scripts/logger-client.js +1 -1
- package/dist/extension-js-devtools/edge/content_scripts/content-0.js +2 -2
- package/dist/extension-js-devtools/{firefox/content_scripts/styles.24e59c3d.css → edge/content_scripts/styles.5456c644.css} +1 -1
- package/dist/extension-js-devtools/edge/manifest.json +1 -1
- package/dist/extension-js-devtools/edge/pages/centralized-logger.css +1 -1
- package/dist/extension-js-devtools/edge/pages/welcome.css +1 -1
- package/dist/extension-js-devtools/edge/pages/welcome.js +2 -2
- package/dist/extension-js-devtools/edge/scripts/logger-client.js +1 -1
- package/dist/extension-js-devtools/firefox/content_scripts/content-0.js +2 -2
- package/dist/extension-js-devtools/{chrome/content_scripts/styles.24e59c3d.css → firefox/content_scripts/styles.5456c644.css} +1 -1
- package/dist/extension-js-devtools/firefox/manifest.json +2 -1
- package/dist/extension-js-devtools/firefox/pages/centralized-logger.css +1 -1
- package/dist/extension-js-devtools/firefox/pages/welcome.css +1 -1
- package/dist/extension-js-devtools/firefox/pages/welcome.js +2 -2
- package/dist/extension-js-devtools/firefox/scripts/logger-client.js +1 -1
- package/dist/extension-js-theme/chrome/manifest.json +1 -1
- package/dist/extension-js-theme/chromium/manifest.json +1 -1
- package/dist/extension-js-theme/edge/manifest.json +1 -1
- package/dist/extension-js-theme/firefox/manifest.json +1 -1
- package/dist/feature-scripts-content-script-wrapper.cjs +237 -0
- package/dist/feature-scripts-content-script-wrapper.js +237 -0
- package/dist/main-world-bridge.js +127 -0
- package/dist/minimum-chromium-file.js +10 -0
- package/dist/minimum-firefox-file.js +10 -0
- package/dist/minimum-script-file.js +31 -0
- package/dist/module.cjs +2098 -1784
- package/dist/package.json +3 -0
- package/dist/resolve-paths-loader.js +1350 -0
- package/package.json +5 -5
- package/dist/add-hmr-accept-code.cjs +0 -91
- package/dist/content-script-wrapper.cjs +0 -319
- package/dist/warn-no-default-export.cjs +0 -356
- package/webpack/webpack-lib/optional-dependencies.json +0 -20
package/dist/323.cjs
CHANGED
|
@@ -12,6 +12,8 @@ exports.modules = {
|
|
|
12
12
|
var banner = __webpack_require__("./webpack/plugin-browsers/browsers-lib/banner.ts");
|
|
13
13
|
var external_path_ = __webpack_require__("path");
|
|
14
14
|
var external_fs_ = __webpack_require__("fs");
|
|
15
|
+
var content_script_targets = __webpack_require__("./webpack/plugin-browsers/browsers-lib/content-script-targets.ts");
|
|
16
|
+
var contracts = __webpack_require__("./webpack/plugin-web-extension/feature-scripts/contracts.ts");
|
|
15
17
|
async function deriveExtensionIdFromTargetsHelper(cdp, outPath, maxRetries = 6, backoffMs = 150, profilePath, extensionPaths) {
|
|
16
18
|
let expectedName;
|
|
17
19
|
let expectedVersion;
|
|
@@ -202,20 +204,6 @@ exports.modules = {
|
|
|
202
204
|
}
|
|
203
205
|
throw lastError instanceof Error ? lastError : new Error('Failed to bootstrap CDP connection');
|
|
204
206
|
}
|
|
205
|
-
async function loadUnpackedIfNeeded(cdp, outPath) {
|
|
206
|
-
try {
|
|
207
|
-
const response = await cdp.sendCommand('Extensions.loadUnpacked', {
|
|
208
|
-
extensionPath: outPath,
|
|
209
|
-
options: {
|
|
210
|
-
failOnError: false
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
const id = String(response?.extensionId || '');
|
|
214
|
-
return id || null;
|
|
215
|
-
} catch {
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
207
|
function readManifestInfo(outPath) {
|
|
220
208
|
try {
|
|
221
209
|
const manifestPath = external_path_.join(outPath, 'manifest.json');
|
|
@@ -302,11 +290,7 @@ exports.modules = {
|
|
|
302
290
|
};
|
|
303
291
|
} catch {}
|
|
304
292
|
try {
|
|
305
|
-
if (!this.extensionId
|
|
306
|
-
const id = await loadUnpackedIfNeeded(this.cdp, this.outPath);
|
|
307
|
-
if (id) this.extensionId = id;
|
|
308
|
-
}
|
|
309
|
-
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(10, 150);
|
|
293
|
+
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(20, 200);
|
|
310
294
|
if (!this.extensionId) throw new Error('Failed to determine extension ID via CDP');
|
|
311
295
|
await this.enableLogging();
|
|
312
296
|
let name;
|
|
@@ -337,12 +321,6 @@ exports.modules = {
|
|
|
337
321
|
if (!this.cdp) return null;
|
|
338
322
|
return await deriveExtensionIdFromTargetsHelper(this.cdp, this.outPath, maxRetries, backoffMs, this.profilePath, this.extensionPaths);
|
|
339
323
|
}
|
|
340
|
-
shouldAttemptLoadUnpacked() {
|
|
341
|
-
const normalizedOutPath = this.normalizePath(this.outPath);
|
|
342
|
-
const normalizedExtensionPaths = (this.extensionPaths || []).map((candidate)=>String(candidate || '').trim()).filter(Boolean).map((candidate)=>this.normalizePath(candidate));
|
|
343
|
-
if (0 === normalizedExtensionPaths.length) return true;
|
|
344
|
-
return !normalizedExtensionPaths.includes(normalizedOutPath);
|
|
345
|
-
}
|
|
346
324
|
normalizePath(input) {
|
|
347
325
|
try {
|
|
348
326
|
return external_fs_.realpathSync(external_path_.resolve(input));
|
|
@@ -400,6 +378,207 @@ exports.modules = {
|
|
|
400
378
|
} catch {}
|
|
401
379
|
return 'unknown';
|
|
402
380
|
}
|
|
381
|
+
getLastRuntimeReinjectionReport() {
|
|
382
|
+
return this.lastRuntimeReinjectionReport;
|
|
383
|
+
}
|
|
384
|
+
async reloadMatchingTabsForContentScripts(rules, options = {}) {
|
|
385
|
+
if (!this.cdp || 0 === rules.length) return 0;
|
|
386
|
+
let reinjectedTabs = 0;
|
|
387
|
+
const targets = await this.cdp.getTargets();
|
|
388
|
+
for (const target of targets || []){
|
|
389
|
+
const targetType = String(target?.type || '');
|
|
390
|
+
const targetId = String(target?.targetId || '');
|
|
391
|
+
const targetUrl = String(target?.url || '');
|
|
392
|
+
if ('page' !== targetType || !targetId || !targetUrl) continue;
|
|
393
|
+
const matchingRules = rules.filter((rule)=>(0, content_script_targets.lM)(targetUrl, [
|
|
394
|
+
rule
|
|
395
|
+
]));
|
|
396
|
+
if (0 !== matchingRules.length) try {
|
|
397
|
+
const sessionId = await this.cdp.attachToTarget(targetId);
|
|
398
|
+
let reinjected = false;
|
|
399
|
+
if (options.preferPageReload) reinjected = await this.reloadPageTarget(sessionId);
|
|
400
|
+
else {
|
|
401
|
+
for (const [index, rule] of matchingRules.entries()){
|
|
402
|
+
const didReinject = await this.reinjectContentScriptRule(sessionId, rule, options.allowCoarseCleanup ?? 0 === index, options.sourceOverridesByBundleId);
|
|
403
|
+
reinjected = reinjected || didReinject;
|
|
404
|
+
}
|
|
405
|
+
if (!reinjected) reinjected = await this.reloadPageTarget(sessionId);
|
|
406
|
+
}
|
|
407
|
+
if (reinjected) reinjectedTabs += 1;
|
|
408
|
+
} catch (error) {
|
|
409
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(`[CDP] Failed to reinject content scripts into ${targetUrl}: ${String(error?.message || error)}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return reinjectedTabs;
|
|
413
|
+
}
|
|
414
|
+
async reinjectMatchingTabsViaExtensionRuntime(rules) {
|
|
415
|
+
if (!this.cdp || 0 === rules.length) {
|
|
416
|
+
this.lastRuntimeReinjectionReport = {
|
|
417
|
+
phase: 'skipped',
|
|
418
|
+
reason: 'missing_cdp_or_rules',
|
|
419
|
+
hasCdp: !!this.cdp,
|
|
420
|
+
ruleCount: rules.length
|
|
421
|
+
};
|
|
422
|
+
return 0;
|
|
423
|
+
}
|
|
424
|
+
const targets = await this.cdp.getTargets();
|
|
425
|
+
const matchingUrlsByRule = new Map();
|
|
426
|
+
for (const target of targets || []){
|
|
427
|
+
const targetType = String(target?.type || '');
|
|
428
|
+
const targetUrl = String(target?.url || '');
|
|
429
|
+
if ('page' === targetType && targetUrl) for (const rule of rules){
|
|
430
|
+
if (!(0, content_script_targets.lM)(targetUrl, [
|
|
431
|
+
rule
|
|
432
|
+
])) continue;
|
|
433
|
+
const urls = matchingUrlsByRule.get(rule.index) || new Set();
|
|
434
|
+
urls.add(targetUrl);
|
|
435
|
+
matchingUrlsByRule.set(rule.index, urls);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const payload = rules.map((rule)=>{
|
|
439
|
+
const jsPath = (0, content_script_targets.nG)(this.outPath, rule.index, 'js');
|
|
440
|
+
const cssPath = (0, content_script_targets.nG)(this.outPath, rule.index, 'css');
|
|
441
|
+
if (!jsPath || !external_fs_.existsSync(jsPath)) return null;
|
|
442
|
+
const jsFile = external_path_.relative(this.outPath, jsPath).replace(/\\/g, '/');
|
|
443
|
+
const cssFile = cssPath && external_fs_.existsSync(cssPath) ? external_path_.relative(this.outPath, cssPath).replace(/\\/g, '/') : null;
|
|
444
|
+
const jsSource = external_fs_.readFileSync(jsPath, 'utf-8');
|
|
445
|
+
const buildTokenMatch = jsSource.match(/__EXTENSIONJS_REINJECT_BUILD_TOKEN\s*=\s*"([^"]+)"/);
|
|
446
|
+
const proofMatch = jsSource.match(/extjs-chromium-live-content-css-modules:script-primary-\d+/) || jsSource.match(/Live Update Proof [A-Za-z0-9_-]+/);
|
|
447
|
+
return {
|
|
448
|
+
index: rule.index,
|
|
449
|
+
world: rule.world,
|
|
450
|
+
matches: [
|
|
451
|
+
...rule.matches
|
|
452
|
+
],
|
|
453
|
+
urls: Array.from(matchingUrlsByRule.get(rule.index) || []).sort(),
|
|
454
|
+
jsFile,
|
|
455
|
+
cssFile,
|
|
456
|
+
buildToken: buildTokenMatch?.[1] || null,
|
|
457
|
+
proofMarker: proofMatch?.[0] || null
|
|
458
|
+
};
|
|
459
|
+
}).filter((entry)=>!!entry && entry.urls.length > 0);
|
|
460
|
+
if (0 === payload.length) {
|
|
461
|
+
this.lastRuntimeReinjectionReport = {
|
|
462
|
+
phase: 'skipped',
|
|
463
|
+
reason: 'no_payload',
|
|
464
|
+
ruleCount: rules.length
|
|
465
|
+
};
|
|
466
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log('[CDP] extension-runtime reinjection skipped: no payload');
|
|
467
|
+
return 0;
|
|
468
|
+
}
|
|
469
|
+
const runtimeTarget = await this.attachToExtensionRuntimeTarget();
|
|
470
|
+
if (!runtimeTarget) {
|
|
471
|
+
const targetSummary = (targets || []).map((target)=>({
|
|
472
|
+
type: String(target?.type || ''),
|
|
473
|
+
url: String(target?.url || '')
|
|
474
|
+
})).filter((entry)=>entry.type || entry.url);
|
|
475
|
+
this.lastRuntimeReinjectionReport = {
|
|
476
|
+
phase: 'unavailable',
|
|
477
|
+
reason: 'no_runtime_target',
|
|
478
|
+
extensionId: this.extensionId,
|
|
479
|
+
targets: targetSummary
|
|
480
|
+
};
|
|
481
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] extension-runtime reinjection unavailable: ${JSON.stringify({
|
|
482
|
+
extensionId: this.extensionId,
|
|
483
|
+
targets: targetSummary
|
|
484
|
+
})}`);
|
|
485
|
+
return 0;
|
|
486
|
+
}
|
|
487
|
+
const result = await this.cdp.evaluate(runtimeTarget.sessionId, `(() => (async () => {
|
|
488
|
+
const payload = ${JSON.stringify(payload)};
|
|
489
|
+
const chromeRuntime =
|
|
490
|
+
typeof globalThis === 'object' && globalThis && globalThis.chrome
|
|
491
|
+
? globalThis.chrome
|
|
492
|
+
: null;
|
|
493
|
+
const runtimeChrome =
|
|
494
|
+
chromeRuntime &&
|
|
495
|
+
chromeRuntime.scripting &&
|
|
496
|
+
chromeRuntime.tabs
|
|
497
|
+
? chromeRuntime
|
|
498
|
+
: null;
|
|
499
|
+
if (!runtimeChrome) {
|
|
500
|
+
return {
|
|
501
|
+
reinjectedTabs: 0,
|
|
502
|
+
hasRuntime: false,
|
|
503
|
+
hasChrome: !!chromeRuntime,
|
|
504
|
+
hasScripting: !!(chromeRuntime && chromeRuntime.scripting),
|
|
505
|
+
hasTabs: !!(chromeRuntime && chromeRuntime.tabs),
|
|
506
|
+
entries: payload.length,
|
|
507
|
+
matches: []
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
let reinjectedTabs = 0;
|
|
511
|
+
const matches = [];
|
|
512
|
+
for (const entry of payload) {
|
|
513
|
+
const queriedTabs = await runtimeChrome.tabs.query(
|
|
514
|
+
entry.matches.length > 0 ? { url: entry.matches } : {}
|
|
515
|
+
);
|
|
516
|
+
const matchingTabs = queriedTabs.filter((tab) => {
|
|
517
|
+
if (!tab || typeof tab.id !== 'number') return false;
|
|
518
|
+
if (typeof tab.url !== 'string' || !tab.url) return true;
|
|
519
|
+
return entry.urls.length === 0 || entry.urls.includes(tab.url);
|
|
520
|
+
});
|
|
521
|
+
matches.push({
|
|
522
|
+
index: entry.index,
|
|
523
|
+
queriedTabs: queriedTabs.length,
|
|
524
|
+
matchingTabs: matchingTabs.length
|
|
525
|
+
});
|
|
526
|
+
for (const tab of matchingTabs) {
|
|
527
|
+
const target = { tabId: tab.id, allFrames: false };
|
|
528
|
+
if (entry.cssFile) {
|
|
529
|
+
try {
|
|
530
|
+
await runtimeChrome.scripting.insertCSS({
|
|
531
|
+
target,
|
|
532
|
+
files: [entry.cssFile]
|
|
533
|
+
});
|
|
534
|
+
} catch (error) {}
|
|
535
|
+
}
|
|
536
|
+
await runtimeChrome.scripting.executeScript({
|
|
537
|
+
target,
|
|
538
|
+
files: [entry.jsFile],
|
|
539
|
+
world: entry.world === 'main' ? 'MAIN' : 'ISOLATED'
|
|
540
|
+
});
|
|
541
|
+
reinjectedTabs += 1;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
reinjectedTabs,
|
|
546
|
+
hasRuntime: true,
|
|
547
|
+
entries: payload.length,
|
|
548
|
+
matches
|
|
549
|
+
};
|
|
550
|
+
})())()`, {
|
|
551
|
+
awaitPromise: true
|
|
552
|
+
});
|
|
553
|
+
this.lastRuntimeReinjectionReport = {
|
|
554
|
+
phase: 'evaluated',
|
|
555
|
+
targetType: runtimeTarget.targetType,
|
|
556
|
+
targetUrl: runtimeTarget.targetUrl,
|
|
557
|
+
result: result && 'object' == typeof result ? JSON.parse(JSON.stringify(result)) : result
|
|
558
|
+
};
|
|
559
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] extension-runtime reinjection result: ${JSON.stringify({
|
|
560
|
+
targetType: runtimeTarget.targetType,
|
|
561
|
+
targetUrl: runtimeTarget.targetUrl,
|
|
562
|
+
result
|
|
563
|
+
})}`);
|
|
564
|
+
if ('number' == typeof result) return result;
|
|
565
|
+
if (result && 'object' == typeof result) {
|
|
566
|
+
const reinjectedTabs = Number(result.reinjectedTabs);
|
|
567
|
+
return Number.isFinite(reinjectedTabs) ? reinjectedTabs : 0;
|
|
568
|
+
}
|
|
569
|
+
return 0;
|
|
570
|
+
}
|
|
571
|
+
async reloadPageTarget(sessionId) {
|
|
572
|
+
if (!this.cdp) return false;
|
|
573
|
+
try {
|
|
574
|
+
await this.cdp.sendCommand('Page.reload', {
|
|
575
|
+
ignoreCache: true
|
|
576
|
+
}, sessionId);
|
|
577
|
+
return true;
|
|
578
|
+
} catch {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
403
582
|
async hardReload() {
|
|
404
583
|
if (!this.extensionId) return false;
|
|
405
584
|
try {
|
|
@@ -413,6 +592,32 @@ exports.modules = {
|
|
|
413
592
|
return false;
|
|
414
593
|
}
|
|
415
594
|
}
|
|
595
|
+
async attachToExtensionRuntimeTarget() {
|
|
596
|
+
if (!this.cdp) return;
|
|
597
|
+
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(10, 150);
|
|
598
|
+
if (!this.extensionId) return;
|
|
599
|
+
const extensionOrigin = `chrome-extension://${this.extensionId}/`;
|
|
600
|
+
for(let attempt = 0; attempt < 20; attempt++){
|
|
601
|
+
const targets = await this.cdp.getTargets();
|
|
602
|
+
const runtimeTargets = (targets || []).filter((target)=>{
|
|
603
|
+
const targetType = String(target?.type || '');
|
|
604
|
+
const targetId = String(target?.targetId || '');
|
|
605
|
+
return ('service_worker' === targetType || 'background_page' === targetType || 'worker' === targetType) && !!targetId;
|
|
606
|
+
});
|
|
607
|
+
const runtimeTarget = runtimeTargets.find((target)=>String(target?.url || '').startsWith(extensionOrigin)) || runtimeTargets.find((target)=>String(target?.url || '').startsWith('chrome-extension://'));
|
|
608
|
+
if (runtimeTarget) try {
|
|
609
|
+
const sessionId = await this.cdp.attachToTarget(String(runtimeTarget.targetId));
|
|
610
|
+
await this.cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
611
|
+
return {
|
|
612
|
+
sessionId,
|
|
613
|
+
targetType: String(runtimeTarget?.type || ''),
|
|
614
|
+
targetUrl: String(runtimeTarget?.url || '')
|
|
615
|
+
};
|
|
616
|
+
} catch {}
|
|
617
|
+
this.extensionId = await this.deriveExtensionIdFromTargets(4, 100) || this.extensionId;
|
|
618
|
+
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
619
|
+
}
|
|
620
|
+
}
|
|
416
621
|
async connectFreshClient() {
|
|
417
622
|
this.cdp = await connectToChromeCdp(this.cdpPort);
|
|
418
623
|
try {
|
|
@@ -449,7 +654,6 @@ exports.modules = {
|
|
|
449
654
|
}
|
|
450
655
|
clearProtocolEventHandler() {
|
|
451
656
|
if (!this.cdp) return;
|
|
452
|
-
this.cdp.onProtocolEvent(()=>{});
|
|
453
657
|
}
|
|
454
658
|
async enableUnifiedLogging() {
|
|
455
659
|
if (!this.cdp) return;
|
|
@@ -538,6 +742,231 @@ exports.modules = {
|
|
|
538
742
|
return null;
|
|
539
743
|
}
|
|
540
744
|
}
|
|
745
|
+
async reinjectContentScriptRule(sessionId, rule, allowCoarseCleanup, sourceOverridesByBundleId) {
|
|
746
|
+
if (!this.cdp) return false;
|
|
747
|
+
const bundleId = (0, contracts.Y0)(rule.index);
|
|
748
|
+
const bundlePath = (0, content_script_targets.nG)(this.outPath, rule.index, 'js');
|
|
749
|
+
if (!bundlePath || !external_fs_.existsSync(bundlePath)) return false;
|
|
750
|
+
const sourceOverride = sourceOverridesByBundleId && 'object' == typeof sourceOverridesByBundleId ? sourceOverridesByBundleId[bundleId] : void 0;
|
|
751
|
+
const source = this.patchReinjectSourceForInvalidatedRuntime('string' == typeof sourceOverride ? sourceOverride : external_fs_.readFileSync(bundlePath, 'utf-8'));
|
|
752
|
+
const buildTokenMatch = source.match(/__EXTENSIONJS_REINJECT_BUILD_TOKEN\s*=\s*"([^"]+)"/);
|
|
753
|
+
const proofMatch = source.match(/extjs-chromium-live-content-css-modules:script-primary-\d+/) || source.match(/Live Update Proof [A-Za-z0-9_-]+/);
|
|
754
|
+
if (!source.trim()) return false;
|
|
755
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] reinject bundle ${bundleId} from ${bundlePath}${proofMatch ? ` (${proofMatch[0]})` : ''} build=${buildTokenMatch?.[1] || '<none>'} sourceOverride=${'string' == typeof sourceOverride}`);
|
|
756
|
+
const contextId = await this.resolveExecutionContextId(sessionId, rule);
|
|
757
|
+
if (!contextId) {
|
|
758
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(`[CDP] No execution context found for ${bundleId} (${rule.world})`);
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
const result = await this.cdp.evaluateInContext(sessionId, this.buildReinjectExpression(bundleId, source, allowCoarseCleanup), contextId);
|
|
762
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] reinject result ${bundleId}: ${JSON.stringify(result)}`);
|
|
763
|
+
if (result && 'object' == typeof result && 'ok' in result) return false !== result.ok;
|
|
764
|
+
return true;
|
|
765
|
+
}
|
|
766
|
+
buildReinjectExpression(bundleId, source, allowCoarseCleanup) {
|
|
767
|
+
const annotatedSource = `${source}\n//# sourceURL=extension.js-reinject://${bundleId}.js`;
|
|
768
|
+
const extensionBase = this.extensionId ? `chrome-extension://${this.extensionId}/` : '';
|
|
769
|
+
return `(() => {
|
|
770
|
+
const bundleId = ${JSON.stringify(bundleId)};
|
|
771
|
+
const source = ${JSON.stringify(annotatedSource)};
|
|
772
|
+
const extensionBase = ${JSON.stringify(extensionBase)};
|
|
773
|
+
const rootSelector = '[data-extension-root], #extension-root';
|
|
774
|
+
const keyedSelector = '[data-extjs-reinject-key="${bundleId}"]';
|
|
775
|
+
const registry = (typeof globalThis === 'object' && globalThis)
|
|
776
|
+
? (globalThis.__EXTENSIONJS_DEV_REINJECT__ || (globalThis.__EXTENSIONJS_DEV_REINJECT__ = {}))
|
|
777
|
+
: {};
|
|
778
|
+
const existing = registry[bundleId];
|
|
779
|
+
const readGeneration = (entry) => {
|
|
780
|
+
try {
|
|
781
|
+
if (!entry) return 0;
|
|
782
|
+
if (typeof entry === 'function' && typeof entry.__extjsGeneration === 'number') {
|
|
783
|
+
return entry.__extjsGeneration;
|
|
784
|
+
}
|
|
785
|
+
if (typeof entry === 'object') {
|
|
786
|
+
if (typeof entry.__extjsGeneration === 'number') return entry.__extjsGeneration;
|
|
787
|
+
if (typeof entry.generation === 'number') return entry.generation;
|
|
788
|
+
if (typeof entry.cleanup === 'function' && typeof entry.cleanup.__extjsGeneration === 'number') {
|
|
789
|
+
return entry.cleanup.__extjsGeneration;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
} catch (error) {}
|
|
793
|
+
return 0;
|
|
794
|
+
};
|
|
795
|
+
const previousGeneration = readGeneration(existing);
|
|
796
|
+
try {
|
|
797
|
+
if (typeof existing === 'function') existing();
|
|
798
|
+
if (existing && typeof existing.cleanup === 'function') existing.cleanup();
|
|
799
|
+
} catch (error) {}
|
|
800
|
+
if (${allowCoarseCleanup ? 'true' : 'false'}) {
|
|
801
|
+
try {
|
|
802
|
+
const staleRoots = Array.from(document.querySelectorAll(rootSelector));
|
|
803
|
+
for (const root of staleRoots) {
|
|
804
|
+
if (root && typeof root.remove === 'function') root.remove();
|
|
805
|
+
}
|
|
806
|
+
} catch (error) {}
|
|
807
|
+
}
|
|
808
|
+
const trackedNodes = new Set();
|
|
809
|
+
const trackNode = (node) => {
|
|
810
|
+
try {
|
|
811
|
+
if (!node || typeof Element !== 'function' || !(node instanceof Element)) return;
|
|
812
|
+
const matchesRoot = typeof node.matches === 'function' && node.matches(rootSelector);
|
|
813
|
+
if (!matchesRoot) return;
|
|
814
|
+
trackedNodes.add(node);
|
|
815
|
+
if (typeof node.setAttribute === 'function') {
|
|
816
|
+
node.setAttribute('data-extjs-reinject-key', bundleId);
|
|
817
|
+
}
|
|
818
|
+
} catch (error) {}
|
|
819
|
+
};
|
|
820
|
+
const trackTree = (node) => {
|
|
821
|
+
trackNode(node);
|
|
822
|
+
try {
|
|
823
|
+
if (!node || typeof node.querySelectorAll !== 'function') return;
|
|
824
|
+
const nested = node.querySelectorAll(rootSelector);
|
|
825
|
+
for (const nestedNode of nested) trackNode(nestedNode);
|
|
826
|
+
} catch (error) {}
|
|
827
|
+
};
|
|
828
|
+
const observer = typeof MutationObserver === 'function'
|
|
829
|
+
? new MutationObserver((mutations) => {
|
|
830
|
+
for (const mutation of mutations) {
|
|
831
|
+
const addedNodes = Array.from(mutation.addedNodes || []);
|
|
832
|
+
for (const addedNode of addedNodes) {
|
|
833
|
+
trackTree(addedNode);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
})
|
|
837
|
+
: null;
|
|
838
|
+
try {
|
|
839
|
+
if (observer && document && document.documentElement) {
|
|
840
|
+
observer.observe(document.documentElement, {childList: true, subtree: true});
|
|
841
|
+
}
|
|
842
|
+
} catch (error) {}
|
|
843
|
+
const cleanupTrackedNodes = () => {
|
|
844
|
+
try {
|
|
845
|
+
if (observer) observer.disconnect();
|
|
846
|
+
} catch (error) {}
|
|
847
|
+
try {
|
|
848
|
+
const keyedNodes = Array.from(document.querySelectorAll(keyedSelector));
|
|
849
|
+
for (const keyedNode of keyedNodes) {
|
|
850
|
+
if (keyedNode && typeof keyedNode.remove === 'function') keyedNode.remove();
|
|
851
|
+
}
|
|
852
|
+
} catch (error) {}
|
|
853
|
+
try {
|
|
854
|
+
for (const trackedNode of trackedNodes) {
|
|
855
|
+
if (trackedNode && trackedNode.isConnected && typeof trackedNode.remove === 'function') {
|
|
856
|
+
trackedNode.remove();
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
} catch (error) {}
|
|
860
|
+
};
|
|
861
|
+
registry[bundleId] = {
|
|
862
|
+
cleanup: cleanupTrackedNodes,
|
|
863
|
+
generation: previousGeneration,
|
|
864
|
+
__extjsGeneration: previousGeneration
|
|
865
|
+
};
|
|
866
|
+
try {
|
|
867
|
+
if (typeof globalThis === 'object' && globalThis && extensionBase) {
|
|
868
|
+
globalThis.__EXTJS_EXTENSION_BASE__ = extensionBase;
|
|
869
|
+
}
|
|
870
|
+
if (typeof document === 'object' && document && document.documentElement && extensionBase) {
|
|
871
|
+
document.documentElement.setAttribute('data-extjs-extension-base', extensionBase);
|
|
872
|
+
}
|
|
873
|
+
(0, eval)(source);
|
|
874
|
+
} catch (error) {
|
|
875
|
+
return {
|
|
876
|
+
ok: false,
|
|
877
|
+
error: String((error && error.stack) || (error && error.message) || error || 'unknown'),
|
|
878
|
+
trackedRoots: trackedNodes.size,
|
|
879
|
+
existingRootCount: (() => {
|
|
880
|
+
try { return document.querySelectorAll(rootSelector).length; } catch (innerError) { return -1; }
|
|
881
|
+
})()
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
setTimeout(() => {
|
|
885
|
+
try {
|
|
886
|
+
const keyedNodes = Array.from(document.querySelectorAll(keyedSelector));
|
|
887
|
+
for (const keyedNode of keyedNodes) trackedNodes.add(keyedNode);
|
|
888
|
+
} catch (error) {}
|
|
889
|
+
}, 0);
|
|
890
|
+
setTimeout(() => {
|
|
891
|
+
try {
|
|
892
|
+
if (observer) observer.disconnect();
|
|
893
|
+
} catch (error) {}
|
|
894
|
+
}, 2000);
|
|
895
|
+
return {
|
|
896
|
+
ok: true,
|
|
897
|
+
trackedRoots: trackedNodes.size,
|
|
898
|
+
existingRootCount: (() => {
|
|
899
|
+
try { return document.querySelectorAll(rootSelector).length; } catch (innerError) { return -1; }
|
|
900
|
+
})(),
|
|
901
|
+
liveRoots: (() => {
|
|
902
|
+
try {
|
|
903
|
+
return Array.from(document.querySelectorAll(rootSelector)).map((node) => ({
|
|
904
|
+
key: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extjs-reinject-key') || null : null,
|
|
905
|
+
root: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extension-root') || null : null,
|
|
906
|
+
build: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extjs-reinject-build') || null : null,
|
|
907
|
+
text: String(node && node.textContent || '').slice(0, 120)
|
|
908
|
+
}));
|
|
909
|
+
} catch (error) {
|
|
910
|
+
return [];
|
|
911
|
+
}
|
|
912
|
+
})(),
|
|
913
|
+
hasChromeRuntime: (() => {
|
|
914
|
+
try { return !!(globalThis && globalThis.chrome && globalThis.chrome.runtime); } catch (error) { return false; }
|
|
915
|
+
})()
|
|
916
|
+
};
|
|
917
|
+
})()`;
|
|
918
|
+
}
|
|
919
|
+
patchReinjectSourceForInvalidatedRuntime(source) {
|
|
920
|
+
return source.replace('__webpack_require__.p = __webpack_require__.webExtRt.runtime.getURL("/");', 'try {\n __webpack_require__.p = __webpack_require__.webExtRt.runtime.getURL("/");\n} catch (_extjsRuntimeError) {\n if (__extjsBase) {\n __webpack_require__.p = __extjsBase.replace(/\\/+$/, "/") + String("/").replace(/^\\/+/, "");\n } else {\n __webpack_require__.p = "";\n }\n}');
|
|
921
|
+
}
|
|
922
|
+
async resolveExecutionContextId(sessionId, rule) {
|
|
923
|
+
if (!this.cdp) return;
|
|
924
|
+
const frameId = await this.getTopFrameId(sessionId);
|
|
925
|
+
const contexts = await this.collectExecutionContexts(sessionId);
|
|
926
|
+
if ('main' === rule.world) {
|
|
927
|
+
const defaultContext = contexts.find((context)=>{
|
|
928
|
+
const auxData = context?.auxData || {};
|
|
929
|
+
return 'default' === auxData.type && true === auxData.isDefault && (!frameId || !auxData.frameId || String(auxData.frameId) === frameId);
|
|
930
|
+
});
|
|
931
|
+
return 'number' == typeof defaultContext?.id ? defaultContext.id : void 0;
|
|
932
|
+
}
|
|
933
|
+
const extensionId = this.extensionId || await this.deriveExtensionIdFromTargets();
|
|
934
|
+
if (!extensionId) return;
|
|
935
|
+
const extensionOrigin = `chrome-extension://${extensionId}`;
|
|
936
|
+
const isolatedContext = contexts.find((context)=>{
|
|
937
|
+
const auxData = context?.auxData || {};
|
|
938
|
+
return 'isolated' === auxData.type && String(context?.origin || '') === extensionOrigin && (!frameId || !auxData.frameId || String(auxData.frameId) === frameId);
|
|
939
|
+
});
|
|
940
|
+
return 'number' == typeof isolatedContext?.id ? isolatedContext.id : void 0;
|
|
941
|
+
}
|
|
942
|
+
async getTopFrameId(sessionId) {
|
|
943
|
+
if (!this.cdp) return;
|
|
944
|
+
try {
|
|
945
|
+
const frameTree = await this.cdp.sendCommand('Page.getFrameTree', {}, sessionId);
|
|
946
|
+
const frameId = frameTree?.frameTree?.frame?.id;
|
|
947
|
+
return 'string' == typeof frameId && frameId ? frameId : void 0;
|
|
948
|
+
} catch {
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
async collectExecutionContexts(sessionId) {
|
|
953
|
+
if (!this.cdp) return [];
|
|
954
|
+
const contextsById = new Map();
|
|
955
|
+
const unsubscribe = this.cdp.onProtocolEvent((message)=>{
|
|
956
|
+
if (String(message.sessionId || '') !== sessionId) return;
|
|
957
|
+
if ('Runtime.executionContextCreated' !== String(message.method || '')) return;
|
|
958
|
+
const context = message.params?.context;
|
|
959
|
+
const contextId = context?.id;
|
|
960
|
+
if ('number' == typeof contextId) contextsById.set(contextId, context);
|
|
961
|
+
});
|
|
962
|
+
try {
|
|
963
|
+
await this.cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
964
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
965
|
+
} finally{
|
|
966
|
+
unsubscribe();
|
|
967
|
+
}
|
|
968
|
+
return Array.from(contextsById.values());
|
|
969
|
+
}
|
|
541
970
|
constructor(args){
|
|
542
971
|
_define_property(this, "outPath", void 0);
|
|
543
972
|
_define_property(this, "browser", void 0);
|
|
@@ -546,6 +975,7 @@ exports.modules = {
|
|
|
546
975
|
_define_property(this, "extensionPaths", void 0);
|
|
547
976
|
_define_property(this, "cdp", null);
|
|
548
977
|
_define_property(this, "extensionId", null);
|
|
978
|
+
_define_property(this, "lastRuntimeReinjectionReport", null);
|
|
549
979
|
this.outPath = args.outPath;
|
|
550
980
|
this.browser = args.browser;
|
|
551
981
|
this.cdpPort = args.cdpPort;
|
package/dist/324.cjs
CHANGED
|
@@ -28,6 +28,12 @@ exports.modules = {
|
|
|
28
28
|
else obj[key] = value;
|
|
29
29
|
return obj;
|
|
30
30
|
}
|
|
31
|
+
function resolveInstanceIdOverride() {
|
|
32
|
+
const raw = process.env.EXTENSION_INSTANCE_ID || process.env.EXTENSION_DEV_INSTANCE_ID || process.env.EXTJS_INSTANCE_ID || '';
|
|
33
|
+
const value = String(raw).trim();
|
|
34
|
+
if (!value) return;
|
|
35
|
+
return value.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 64) || void 0;
|
|
36
|
+
}
|
|
31
37
|
class PortManager {
|
|
32
38
|
async allocatePorts(_browser, _projectPath, requestedPort) {
|
|
33
39
|
try {
|
|
@@ -35,7 +41,7 @@ exports.modules = {
|
|
|
35
41
|
const base = isValidRequested ? requestedPort : this.basePort;
|
|
36
42
|
const port = await (0, shared_utils.aY)(base);
|
|
37
43
|
const webSocketPort = await (0, shared_utils.aY)(port + 1);
|
|
38
|
-
const instanceId = external_crypto_.randomBytes(8).toString('hex');
|
|
44
|
+
const instanceId = resolveInstanceIdOverride() || external_crypto_.randomBytes(8).toString('hex');
|
|
39
45
|
this.currentInstance = {
|
|
40
46
|
instanceId,
|
|
41
47
|
port,
|
|
@@ -367,6 +373,10 @@ exports.modules = {
|
|
|
367
373
|
hostname: devServerHost,
|
|
368
374
|
port
|
|
369
375
|
};
|
|
376
|
+
process.env.EXTENSION_DEV_SERVER_PROTOCOL = devServerWebSocketURL.protocol;
|
|
377
|
+
process.env.EXTENSION_DEV_SERVER_HOST = devServerHost;
|
|
378
|
+
process.env.EXTENSION_DEV_SERVER_PORT = String(port);
|
|
379
|
+
process.env.EXTENSION_DEV_SERVER_PATH = '/ws';
|
|
370
380
|
const safeBrowserConfig = (0, sanitize.a)(browserConfig);
|
|
371
381
|
const safeCommandConfig = (0, sanitize.a)(commandConfig);
|
|
372
382
|
const safeDevOptions = (0, sanitize.a)(devOptions);
|
|
@@ -406,6 +416,7 @@ exports.modules = {
|
|
|
406
416
|
}
|
|
407
417
|
}
|
|
408
418
|
};
|
|
419
|
+
delete compilerConfig.devServer;
|
|
409
420
|
const compiler = (0, core_.rspack)(compilerConfig);
|
|
410
421
|
const manifestOutputPath = external_path_.join(packageJsonDir, 'dist', devOptions.browser, 'manifest.json');
|
|
411
422
|
installManifestDiskWriteGuard(manifestOutputPath);
|
|
@@ -454,18 +465,13 @@ exports.modules = {
|
|
|
454
465
|
interval: 1000
|
|
455
466
|
}
|
|
456
467
|
},
|
|
457
|
-
client:
|
|
458
|
-
logging: 'none',
|
|
459
|
-
progress: false,
|
|
460
|
-
overlay: false,
|
|
461
|
-
webSocketURL: devServerWebSocketURL
|
|
462
|
-
},
|
|
468
|
+
client: false,
|
|
463
469
|
headers: {
|
|
464
470
|
'Access-Control-Allow-Origin': '*'
|
|
465
471
|
},
|
|
466
472
|
port,
|
|
467
|
-
hot:
|
|
468
|
-
liveReload:
|
|
473
|
+
hot: true,
|
|
474
|
+
liveReload: false
|
|
469
475
|
};
|
|
470
476
|
const devServer = new dev_server_.RspackDevServer(serverConfig, compiler);
|
|
471
477
|
const START_TIMEOUT_MS = parseInt(String(process.env.EXTENSION_START_TIMEOUT_MS || '30000'), 10);
|