extension 3.12.0 → 3.12.2
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/README.md +1 -1
- package/dist/728.cjs +1890 -0
- package/dist/browsers.cjs +4962 -0
- package/dist/cli.cjs +6621 -1684
- package/dist/extension/browsers/browsers-lib/banner.d.ts +37 -0
- package/dist/extension/browsers/browsers-lib/constants.d.ts +14 -0
- package/dist/extension/browsers/browsers-lib/content-script-contracts.d.ts +2 -0
- package/dist/extension/browsers/browsers-lib/content-script-targets.d.ts +33 -0
- package/dist/extension/browsers/browsers-lib/html-merge.d.ts +1 -0
- package/dist/extension/browsers/browsers-lib/instance-registry.d.ts +8 -0
- package/dist/extension/browsers/browsers-lib/messages.d.ts +208 -0
- package/dist/extension/browsers/browsers-lib/normalize-options.d.ts +12 -0
- package/dist/extension/browsers/browsers-lib/output-binaries-resolver.d.ts +5 -0
- package/dist/extension/browsers/browsers-lib/ready-message.d.ts +1 -0
- package/dist/extension/browsers/browsers-lib/runtime-options.d.ts +12 -0
- package/dist/extension/browsers/browsers-lib/shared-utils.d.ts +11 -0
- package/dist/extension/browsers/browsers-lib/source-output.d.ts +86 -0
- package/dist/extension/browsers/browsers-types.d.ts +270 -0
- package/dist/extension/browsers/index.d.ts +74 -0
- package/dist/extension/browsers/run-chromium/chromium-context/index.d.ts +20 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/browser-config.d.ts +4 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/dry-run.d.ts +1 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/extension-output-path.d.ts +8 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/index.d.ts +31 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/master-preferences.d.ts +163 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/process-handlers.d.ts +3 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/setup-cdp-after-launch.d.ts +3 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/wsl-support.d.ts +15 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-client.d.ts +60 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-extension-controller/connect.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-extension-controller/derive-id.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-extension-controller/ensure.d.ts +6 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-extension-controller/index.d.ts +58 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/cdp-extension-controller/logging.d.ts +7 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/deterministic-hmr-harness.d.ts +21 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/discovery.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/extensions.d.ts +9 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/extract.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/index.d.ts +79 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/page.d.ts +45 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/readiness.d.ts +1 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/sessions.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/targets.d.ts +7 -0
- package/dist/extension/browsers/run-chromium/chromium-source-inspection/ws.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/chromium-types.d.ts +65 -0
- package/dist/extension/browsers/run-chromium/chromium-unified-logger/index.d.ts +22 -0
- package/dist/extension/browsers/run-chromium/chromium-unified-logger/unified-logging.d.ts +2 -0
- package/dist/extension/browsers/run-chromium/manifest-readiness.d.ts +15 -0
- package/dist/extension/browsers/run-firefox/firefox-context/index.d.ts +24 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/binary-detector.d.ts +10 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/browser-config.d.ts +19 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/dry-run.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/index.d.ts +37 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/master-preferences.d.ts +137 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/process-handlers.d.ts +2 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/setup-rdp-after-launch.d.ts +6 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/wsl-support.d.ts +15 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/index.d.ts +52 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/rdp-extension-controller/index.d.ts +38 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/addons-install.d.ts +10 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/addons.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/evaluate.d.ts +18 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/firefox-utils.d.ts +17 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/index.d.ts +38 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/logging.d.ts +11 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/message-utils.d.ts +2 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/messaging-client.d.ts +42 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/moz-id.d.ts +2 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/rdp-api.d.ts +29 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/rdp-wire.d.ts +8 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/setup-firefox-inspection-actors.d.ts +5 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/setup-firefox-inspection-navigation.d.ts +2 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/source-inspect.d.ts +9 -0
- package/dist/extension/browsers/run-firefox/firefox-source-inspection/remote-firefox/transport.d.ts +20 -0
- package/dist/extension/browsers/run-firefox/firefox-types.d.ts +16 -0
- package/dist/extension/browsers/run-firefox/firefox-unified-logger/index.d.ts +14 -0
- package/dist/extension/browsers/run-only.d.ts +22 -0
- package/dist/extension/helpers/extension-develop-runtime.d.ts +9 -0
- package/dist/{utils.d.ts → extension/helpers/vendors.d.ts} +0 -1
- package/dist/extension/vitest.config.d.ts +2 -0
- package/package.json +19 -9
- package/dist/cli-lib/extension-develop-runtime.d.ts +0 -3
- /package/dist/{vitest.config.d.ts → extension/browsers/vitest.config.d.ts} +0 -0
- /package/dist/{commands → extension/commands}/build.d.ts +0 -0
- /package/dist/{commands → extension/commands}/create.d.ts +0 -0
- /package/dist/{commands → extension/commands}/dev-wait.d.ts +0 -0
- /package/dist/{commands → extension/commands}/dev.d.ts +0 -0
- /package/dist/{commands → extension/commands}/install.d.ts +0 -0
- /package/dist/{commands → extension/commands}/preview.d.ts +0 -0
- /package/dist/{commands → extension/commands}/start.d.ts +0 -0
- /package/dist/{check-updates.d.ts → extension/helpers/check-updates.d.ts} +0 -0
- /package/dist/{cli-package-json.d.ts → extension/helpers/cli-package-json.d.ts} +0 -0
- /package/dist/{cli-lib → extension/helpers}/manifest-summary.d.ts +0 -0
- /package/dist/{cli-lib → extension/helpers}/messages.d.ts +0 -0
- /package/dist/{utils → extension/helpers}/normalize-options.d.ts +0 -0
- /package/dist/{cli-lib → extension/helpers}/project-profile.d.ts +0 -0
- /package/dist/{cli-lib → extension/helpers}/telemetry-cli.d.ts +0 -0
- /package/dist/{cli-lib → extension/helpers}/telemetry.d.ts +0 -0
- /package/dist/{cli-lib → extension/helpers}/workflow-profile.d.ts +0 -0
- /package/dist/{index.d.ts → extension/index.d.ts} +0 -0
- /package/dist/{rslib.config.d.ts → extension/rslib.config.d.ts} +0 -0
package/dist/728.cjs
ADDED
|
@@ -0,0 +1,1890 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
exports.ids = [
|
|
3
|
+
"728"
|
|
4
|
+
];
|
|
5
|
+
exports.modules = {
|
|
6
|
+
"./browsers/run-chromium/chromium-launch/setup-cdp-after-launch.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
7
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
8
|
+
setupCdpAfterLaunch: ()=>setupCdpAfterLaunch
|
|
9
|
+
});
|
|
10
|
+
var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
|
|
11
|
+
var shared_utils = __webpack_require__("./browsers/browsers-lib/shared-utils.ts");
|
|
12
|
+
var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
|
|
13
|
+
var external_path_ = __webpack_require__("path");
|
|
14
|
+
var external_fs_ = __webpack_require__("fs");
|
|
15
|
+
var content_script_targets = __webpack_require__("./browsers/browsers-lib/content-script-targets.ts");
|
|
16
|
+
var content_script_contracts = __webpack_require__("./browsers/browsers-lib/content-script-contracts.ts");
|
|
17
|
+
async function deriveExtensionIdFromTargetsHelper(cdp, outPath, maxRetries = 6, backoffMs = 150, profilePath, extensionPaths) {
|
|
18
|
+
let expectedName;
|
|
19
|
+
let expectedVersion;
|
|
20
|
+
let expectedManifestVersion;
|
|
21
|
+
let expectedNameIsMsg = false;
|
|
22
|
+
try {
|
|
23
|
+
const manifest = JSON.parse(external_fs_.readFileSync(external_path_.join(outPath, 'manifest.json'), 'utf-8'));
|
|
24
|
+
expectedName = manifest?.name;
|
|
25
|
+
expectedVersion = manifest?.version;
|
|
26
|
+
expectedManifestVersion = manifest?.manifest_version;
|
|
27
|
+
expectedNameIsMsg = 'string' == typeof expectedName && /__MSG_/i.test(expectedName);
|
|
28
|
+
if (expectedNameIsMsg) {
|
|
29
|
+
const defaultLocale = String(manifest?.default_locale || '').trim();
|
|
30
|
+
const msgKeyMatch = String(expectedName || '').match(/__MSG_(.+)__/i);
|
|
31
|
+
const msgKey = msgKeyMatch ? msgKeyMatch[1] : '';
|
|
32
|
+
if (defaultLocale && msgKey) {
|
|
33
|
+
const messagesPath = external_path_.join(outPath, '_locales', defaultLocale, 'messages.json');
|
|
34
|
+
if (external_fs_.existsSync(messagesPath)) {
|
|
35
|
+
const messagesJson = JSON.parse(external_fs_.readFileSync(messagesPath, 'utf-8'));
|
|
36
|
+
const resolved = String(messagesJson?.[msgKey]?.message || '').trim();
|
|
37
|
+
if (resolved) {
|
|
38
|
+
expectedName = resolved;
|
|
39
|
+
expectedNameIsMsg = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch {}
|
|
45
|
+
const trimTrailingSep = (p)=>{
|
|
46
|
+
let end = p.length;
|
|
47
|
+
while(end > 0 && ('/' === p[end - 1] || '\\' === p[end - 1]))end--;
|
|
48
|
+
return p.slice(0, end);
|
|
49
|
+
};
|
|
50
|
+
const normalizePath = (p)=>{
|
|
51
|
+
try {
|
|
52
|
+
const resolved = external_path_.resolve(p);
|
|
53
|
+
if (external_fs_.existsSync(resolved)) return trimTrailingSep(external_fs_.realpathSync(resolved));
|
|
54
|
+
return trimTrailingSep(resolved);
|
|
55
|
+
} catch {
|
|
56
|
+
return trimTrailingSep(external_path_.resolve(p));
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const resolvedOutPath = normalizePath(outPath);
|
|
60
|
+
const normalizedCandidates = Array.isArray(extensionPaths) ? extensionPaths.map((p)=>p ? normalizePath(p) : '').filter(Boolean) : [];
|
|
61
|
+
const resolvedCandidates = normalizedCandidates.length ? normalizedCandidates : [
|
|
62
|
+
resolvedOutPath
|
|
63
|
+
];
|
|
64
|
+
const platformIsCaseInsensitive = 'win32' === process.platform || 'darwin' === process.platform;
|
|
65
|
+
const normalizeForCompare = (p)=>platformIsCaseInsensitive ? p.toLowerCase() : p;
|
|
66
|
+
const matchesAnyCandidate = (p)=>{
|
|
67
|
+
const n = normalizeForCompare(p);
|
|
68
|
+
return resolvedCandidates.some((candidate)=>n === normalizeForCompare(candidate));
|
|
69
|
+
};
|
|
70
|
+
const deriveFromProfile = ()=>{
|
|
71
|
+
if (!profilePath) return null;
|
|
72
|
+
const candidates = [];
|
|
73
|
+
const pushPrefIfExists = (dir)=>{
|
|
74
|
+
const prefPath = external_path_.join(dir, 'Preferences');
|
|
75
|
+
if (external_fs_.existsSync(prefPath)) candidates.push(prefPath);
|
|
76
|
+
};
|
|
77
|
+
try {
|
|
78
|
+
pushPrefIfExists(profilePath);
|
|
79
|
+
pushPrefIfExists(external_path_.join(profilePath, 'Default'));
|
|
80
|
+
const entries = external_fs_.readdirSync(profilePath);
|
|
81
|
+
for (const entry of entries)if (/^Profile\s+\d+$/i.test(entry)) pushPrefIfExists(external_path_.join(profilePath, entry));
|
|
82
|
+
} catch {}
|
|
83
|
+
for (const prefPath of candidates)try {
|
|
84
|
+
if (!external_fs_.existsSync(prefPath)) continue;
|
|
85
|
+
const prefs = JSON.parse(external_fs_.readFileSync(prefPath, 'utf-8'));
|
|
86
|
+
const settings = prefs?.extensions?.settings;
|
|
87
|
+
if (!settings || 'object' != typeof settings) continue;
|
|
88
|
+
const entries = Object.entries(settings);
|
|
89
|
+
let fallbackId = null;
|
|
90
|
+
for (const [id, info] of entries){
|
|
91
|
+
const storedPath = String(info?.path || '');
|
|
92
|
+
if (!storedPath) continue;
|
|
93
|
+
const normalized = normalizePath(storedPath);
|
|
94
|
+
if (!matchesAnyCandidate(normalized)) continue;
|
|
95
|
+
const manifestName = String(info?.manifest?.name || '');
|
|
96
|
+
const manifestVersion = String(info?.manifest?.version || '');
|
|
97
|
+
if (expectedName && manifestName === expectedName) return id;
|
|
98
|
+
if (expectedVersion && manifestVersion === expectedVersion) return id;
|
|
99
|
+
fallbackId = id;
|
|
100
|
+
}
|
|
101
|
+
if (fallbackId) return fallbackId;
|
|
102
|
+
} catch {}
|
|
103
|
+
return null;
|
|
104
|
+
};
|
|
105
|
+
let retries = 0;
|
|
106
|
+
let deferredFirstEvalId = null;
|
|
107
|
+
let deferredUrlDerivedId = null;
|
|
108
|
+
const hasExpectedManifestIdentity = Boolean(expectedName || expectedVersion || expectedManifestVersion);
|
|
109
|
+
while(retries <= maxRetries){
|
|
110
|
+
try {
|
|
111
|
+
const targets = await cdp.getTargets();
|
|
112
|
+
const profileCandidateId = deriveFromProfile();
|
|
113
|
+
let firstEvalId = null;
|
|
114
|
+
let evalIdCount = 0;
|
|
115
|
+
let urlDerivedId = null;
|
|
116
|
+
for (const t of targets || []){
|
|
117
|
+
const url = String(t?.url || '');
|
|
118
|
+
const type = String(t?.type || '');
|
|
119
|
+
const typeOk = [
|
|
120
|
+
'service_worker',
|
|
121
|
+
'background_page',
|
|
122
|
+
'worker'
|
|
123
|
+
].includes(type);
|
|
124
|
+
if (!typeOk) continue;
|
|
125
|
+
const urlMatch = url.match(/^chrome-extension:\/\/([^\/]+)/);
|
|
126
|
+
if (!urlDerivedId && urlMatch?.[1]) urlDerivedId = String(urlMatch[1]);
|
|
127
|
+
if (url && !url.startsWith('chrome-extension://')) continue;
|
|
128
|
+
const targetId = t?.targetId;
|
|
129
|
+
if (targetId) try {
|
|
130
|
+
const sessionId = await cdp.attachToTarget(targetId);
|
|
131
|
+
if (!sessionId) continue;
|
|
132
|
+
await cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
133
|
+
const info = await cdp.evaluate(sessionId, '(()=>{try{const m=chrome.runtime.getManifest?.();return {id:chrome.runtime?.id||"",name:m?.name||"",version:m?.version||"",manifestVersion:m?.manifest_version||0}}catch(_){return null}})()');
|
|
134
|
+
const id = String(info?.id || '').trim();
|
|
135
|
+
if (!id) continue;
|
|
136
|
+
evalIdCount += 1;
|
|
137
|
+
if (!firstEvalId) firstEvalId = id;
|
|
138
|
+
if (profileCandidateId && id === profileCandidateId) return id;
|
|
139
|
+
const gotName = String(info?.name || '');
|
|
140
|
+
const gotVersion = String(info?.version || '');
|
|
141
|
+
const gotManifestVersion = Number(info?.manifestVersion || 0);
|
|
142
|
+
const nameMatches = expectedName && !expectedNameIsMsg ? gotName === expectedName : false;
|
|
143
|
+
const versionMatches = expectedVersion ? gotVersion === expectedVersion : false;
|
|
144
|
+
const manifestVersionMatches = expectedManifestVersion ? gotManifestVersion === expectedManifestVersion : false;
|
|
145
|
+
if (nameMatches && (!profileCandidateId || id === profileCandidateId)) return id;
|
|
146
|
+
if (expectedVersion && versionMatches && (expectedManifestVersion ? manifestVersionMatches : true) && (!profileCandidateId || id === profileCandidateId)) return id;
|
|
147
|
+
} catch {}
|
|
148
|
+
}
|
|
149
|
+
if (1 === evalIdCount && firstEvalId) {
|
|
150
|
+
if (!hasExpectedManifestIdentity) return firstEvalId;
|
|
151
|
+
deferredFirstEvalId = deferredFirstEvalId || firstEvalId;
|
|
152
|
+
}
|
|
153
|
+
if (profileCandidateId) return profileCandidateId;
|
|
154
|
+
if (urlDerivedId) {
|
|
155
|
+
if (!hasExpectedManifestIdentity) return urlDerivedId;
|
|
156
|
+
deferredUrlDerivedId = deferredUrlDerivedId || urlDerivedId;
|
|
157
|
+
}
|
|
158
|
+
} catch {}
|
|
159
|
+
await new Promise((r)=>setTimeout(r, backoffMs));
|
|
160
|
+
retries++;
|
|
161
|
+
}
|
|
162
|
+
return deriveFromProfile() || deferredFirstEvalId || deferredUrlDerivedId;
|
|
163
|
+
}
|
|
164
|
+
var external_ws_ = __webpack_require__("ws");
|
|
165
|
+
var external_ws_default = /*#__PURE__*/ __webpack_require__.n(external_ws_);
|
|
166
|
+
var constants = __webpack_require__("./browsers/browsers-lib/constants.ts");
|
|
167
|
+
var discovery = __webpack_require__("./browsers/run-chromium/chromium-source-inspection/discovery.ts");
|
|
168
|
+
async function getExtensionInfo(cdp, extensionId) {
|
|
169
|
+
return await cdp.sendCommand('Extensions.getExtensionInfo', {
|
|
170
|
+
extensionId
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
async function loadUnpackedExtension(cdp, absPath) {
|
|
174
|
+
const response = await cdp.sendCommand('Extensions.loadUnpacked', {
|
|
175
|
+
extensionPath: absPath,
|
|
176
|
+
options: {
|
|
177
|
+
failOnError: false
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return String(response?.extensionId || '');
|
|
181
|
+
}
|
|
182
|
+
async function unloadExtension(cdp, extensionId) {
|
|
183
|
+
try {
|
|
184
|
+
await cdp.sendCommand('Extensions.unload', {
|
|
185
|
+
extensionId
|
|
186
|
+
});
|
|
187
|
+
return true;
|
|
188
|
+
} catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function mergeShadowIntoDocument(mainHTML, shadowContent) {
|
|
193
|
+
try {
|
|
194
|
+
if (!mainHTML) return '';
|
|
195
|
+
const hasRoot = /<div id=(["'])extension-root\1/i.test(mainHTML);
|
|
196
|
+
if (hasRoot) {
|
|
197
|
+
const emptyRoot = /<div id=(["'])extension-root\1[^>]*><\/div>/i;
|
|
198
|
+
const replacedEmpty = mainHTML.replace(emptyRoot, `<div id="extension-root">${shadowContent}</div>`);
|
|
199
|
+
if (replacedEmpty !== mainHTML) return replacedEmpty;
|
|
200
|
+
return mainHTML.replace(/<div id=(["'])extension-root\1[^>]*>[\s\S]*?<\/div>/i, `<div id="extension-root">${shadowContent}</div>`);
|
|
201
|
+
}
|
|
202
|
+
const hostOpen = /(<[^>]*data-extension-root=(["'])true\2[^>]*>)/i;
|
|
203
|
+
if (hostOpen.test(mainHTML)) return mainHTML.replace(hostOpen, `$1<div id="extension-root">${shadowContent}</div>`);
|
|
204
|
+
return mainHTML;
|
|
205
|
+
} catch {
|
|
206
|
+
return mainHTML;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const CONTENT_ROOT_SELECTOR = '#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])';
|
|
210
|
+
const NON_DEVTOOLS_CONTENT_ROOT_SELECTOR = '#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])';
|
|
211
|
+
const EXTENSION_ROOT_META_EXPRESSION = `(() => {
|
|
212
|
+
const readGeneration = (node) => {
|
|
213
|
+
try {
|
|
214
|
+
const raw = node && node.getAttribute
|
|
215
|
+
? node.getAttribute('data-extjs-reinject-generation')
|
|
216
|
+
: '';
|
|
217
|
+
const parsed = Number(raw);
|
|
218
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
219
|
+
} catch (error) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const normalize = (node) => ({
|
|
224
|
+
tag: node && node.tagName ? String(node.tagName).toLowerCase() : 'unknown',
|
|
225
|
+
id: node && node.id ? String(node.id) : undefined,
|
|
226
|
+
key: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-key') || undefined : undefined,
|
|
227
|
+
generation: readGeneration(node),
|
|
228
|
+
status: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-status') || undefined : undefined,
|
|
229
|
+
build: node && node.getAttribute ? node.getAttribute('data-extjs-reinject-build') || undefined : undefined,
|
|
230
|
+
hasShadowRoot: !!(node && node.shadowRoot),
|
|
231
|
+
hasShadowContent: !!(node && node.shadowRoot && String(node.shadowRoot.innerHTML || '').trim())
|
|
232
|
+
});
|
|
233
|
+
const registry = (typeof globalThis === 'object' && globalThis)
|
|
234
|
+
? (globalThis.__EXTENSIONJS_DEV_REINJECT__ || {})
|
|
235
|
+
: {};
|
|
236
|
+
const registries = Object.entries(registry)
|
|
237
|
+
.slice(0, 10)
|
|
238
|
+
.map(([key, entry]) => {
|
|
239
|
+
const candidate = entry && typeof entry === 'object' ? entry : {};
|
|
240
|
+
const cleanup = candidate && typeof candidate.cleanup === 'function'
|
|
241
|
+
? candidate.cleanup
|
|
242
|
+
: (typeof entry === 'function' ? entry : undefined);
|
|
243
|
+
return {
|
|
244
|
+
key,
|
|
245
|
+
generation: typeof candidate.generation === 'number'
|
|
246
|
+
? candidate.generation
|
|
247
|
+
: (cleanup && typeof cleanup.__extjsGeneration === 'number'
|
|
248
|
+
? cleanup.__extjsGeneration
|
|
249
|
+
: undefined),
|
|
250
|
+
hasCleanup: typeof cleanup === 'function',
|
|
251
|
+
build: typeof candidate.build === 'string'
|
|
252
|
+
? candidate.build
|
|
253
|
+
: (cleanup && typeof cleanup.__extjsBuild === 'string'
|
|
254
|
+
? cleanup.__extjsBuild
|
|
255
|
+
: undefined)
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
const pageCandidate = {
|
|
259
|
+
key: document.documentElement.getAttribute('data-extjs-last-reinject-key') || undefined,
|
|
260
|
+
generation: (() => {
|
|
261
|
+
const parsed = Number(document.documentElement.getAttribute('data-extjs-last-reinject-generation') || '');
|
|
262
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
263
|
+
})(),
|
|
264
|
+
status: document.documentElement.getAttribute('data-extjs-last-reinject-status') || undefined,
|
|
265
|
+
build: document.documentElement.getAttribute('data-extjs-last-reinject-build') || undefined
|
|
266
|
+
};
|
|
267
|
+
const roots = Array.from(
|
|
268
|
+
document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])')
|
|
269
|
+
)
|
|
270
|
+
.slice(0, 10)
|
|
271
|
+
.map(normalize)
|
|
272
|
+
.filter((entry) =>
|
|
273
|
+
entry.hasShadowRoot ||
|
|
274
|
+
entry.hasShadowContent ||
|
|
275
|
+
typeof entry.key === 'string' ||
|
|
276
|
+
typeof entry.generation === 'number' ||
|
|
277
|
+
typeof entry.status === 'string' ||
|
|
278
|
+
typeof entry.build === 'string'
|
|
279
|
+
)
|
|
280
|
+
.map(({hasShadowRoot, hasShadowContent, ...entry}) => entry);
|
|
281
|
+
const markers = Array.from(
|
|
282
|
+
document.querySelectorAll('[data-extjs-reinject-marker="true"]')
|
|
283
|
+
)
|
|
284
|
+
.slice(0, 10)
|
|
285
|
+
.map(normalize);
|
|
286
|
+
const pageHasBackingEvidence =
|
|
287
|
+
roots.length > 0 ||
|
|
288
|
+
markers.length > 0 ||
|
|
289
|
+
registries.some((entry) =>
|
|
290
|
+
entry.key === pageCandidate.key ||
|
|
291
|
+
typeof entry.generation === 'number' ||
|
|
292
|
+
!!entry.hasCleanup ||
|
|
293
|
+
typeof entry.build === 'string'
|
|
294
|
+
);
|
|
295
|
+
const page = pageHasBackingEvidence ? pageCandidate : undefined;
|
|
296
|
+
const generations = roots
|
|
297
|
+
.concat(markers)
|
|
298
|
+
.map((entry) => entry.generation)
|
|
299
|
+
.concat(typeof page.generation === 'number' ? [page.generation] : [])
|
|
300
|
+
.concat(
|
|
301
|
+
registries
|
|
302
|
+
.map((entry) => entry.generation)
|
|
303
|
+
.filter((value) => typeof value === 'number')
|
|
304
|
+
)
|
|
305
|
+
.filter((value) => typeof value === 'number');
|
|
306
|
+
return {
|
|
307
|
+
rootCount: roots.length,
|
|
308
|
+
markerCount: markers.length,
|
|
309
|
+
latestGeneration: generations.length ? Math.max(...generations) : 0,
|
|
310
|
+
roots,
|
|
311
|
+
markers,
|
|
312
|
+
registries,
|
|
313
|
+
page
|
|
314
|
+
};
|
|
315
|
+
})()`;
|
|
316
|
+
const SHADOW_STYLE_SNAPSHOT_EXPRESSION = `(() => {
|
|
317
|
+
try {
|
|
318
|
+
const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
|
|
319
|
+
if (!hosts.length) return null;
|
|
320
|
+
for (const host of hosts) {
|
|
321
|
+
const sr = host && host.shadowRoot;
|
|
322
|
+
if (!sr) continue;
|
|
323
|
+
const styles = Array.from(sr.querySelectorAll('style')).map((styleEl) => {
|
|
324
|
+
const html = String(styleEl.outerHTML || '');
|
|
325
|
+
const text = String(styleEl.textContent || '');
|
|
326
|
+
return {
|
|
327
|
+
html,
|
|
328
|
+
textLength: text.length,
|
|
329
|
+
textSnippet: text.trim().slice(0, 200)
|
|
330
|
+
};
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
rootMode: 'shadow',
|
|
334
|
+
count: styles.length,
|
|
335
|
+
styles
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
} catch {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
})()`;
|
|
343
|
+
const HAS_VISIBLE_SHADOW_HOST_EXPRESSION = `(() => { try {
|
|
344
|
+
const hosts = Array.from(document.querySelectorAll('#extension-root,[data-extension-root]:not([data-extension-root="extension-js-devtools"])'));
|
|
345
|
+
if (!hosts.length) return false;
|
|
346
|
+
for (const h of hosts) {
|
|
347
|
+
try {
|
|
348
|
+
const sr = h && h.shadowRoot;
|
|
349
|
+
if (sr && (String(sr.innerHTML||'').length > 0)) return true;
|
|
350
|
+
} catch { /* ignore */ }
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
} catch { return false } })()`;
|
|
354
|
+
async function collectExecutionContexts(cdp, sessionId) {
|
|
355
|
+
const rawCdp = cdp;
|
|
356
|
+
if ('function' != typeof rawCdp.sendCommand || 'function' != typeof rawCdp.onProtocolEvent) return [];
|
|
357
|
+
const contextsById = new Map();
|
|
358
|
+
const unsubscribe = rawCdp.onProtocolEvent((message)=>{
|
|
359
|
+
if (String(message.sessionId || '') !== sessionId) return;
|
|
360
|
+
if ('Runtime.executionContextCreated' !== String(message.method || '')) return;
|
|
361
|
+
const context = message.params?.context;
|
|
362
|
+
const contextId = context?.id;
|
|
363
|
+
if ('number' == typeof contextId) contextsById.set(contextId, context);
|
|
364
|
+
});
|
|
365
|
+
try {
|
|
366
|
+
await rawCdp.sendCommand('Runtime.enable', {}, sessionId, 3000);
|
|
367
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
368
|
+
} catch {
|
|
369
|
+
return [];
|
|
370
|
+
} finally{
|
|
371
|
+
unsubscribe();
|
|
372
|
+
}
|
|
373
|
+
return Array.from(contextsById.values());
|
|
374
|
+
}
|
|
375
|
+
async function getIsolatedContextId(cdp, sessionId) {
|
|
376
|
+
const contexts = await collectExecutionContexts(cdp, sessionId);
|
|
377
|
+
const preferredContext = contexts.find((context)=>{
|
|
378
|
+
const auxData = context?.auxData || {};
|
|
379
|
+
return 'isolated' === auxData.type && String(context?.origin || '').startsWith('chrome-extension://');
|
|
380
|
+
});
|
|
381
|
+
if ('number' == typeof preferredContext?.id) return preferredContext.id;
|
|
382
|
+
const fallbackContext = contexts.find((context)=>context?.auxData?.type === 'isolated');
|
|
383
|
+
return 'number' == typeof fallbackContext?.id ? fallbackContext.id : void 0;
|
|
384
|
+
}
|
|
385
|
+
async function evaluateWithContentContext(cdp, sessionId, expression, shouldAccept) {
|
|
386
|
+
let pageResult;
|
|
387
|
+
try {
|
|
388
|
+
pageResult = await cdp.evaluate(sessionId, expression);
|
|
389
|
+
if (shouldAccept(pageResult)) return pageResult;
|
|
390
|
+
} catch {}
|
|
391
|
+
try {
|
|
392
|
+
const isolatedContextId = await getIsolatedContextId(cdp, sessionId);
|
|
393
|
+
if ('number' == typeof isolatedContextId) {
|
|
394
|
+
const isolatedResult = await cdp.evaluateInContext(sessionId, expression, isolatedContextId);
|
|
395
|
+
if (shouldAccept(isolatedResult)) return isolatedResult;
|
|
396
|
+
if (void 0 !== pageResult) return pageResult;
|
|
397
|
+
return isolatedResult;
|
|
398
|
+
}
|
|
399
|
+
} catch {}
|
|
400
|
+
return pageResult;
|
|
401
|
+
}
|
|
402
|
+
function isExtensionRootMetaPayload(value) {
|
|
403
|
+
if (!value || 'object' != typeof value) return false;
|
|
404
|
+
const v = value;
|
|
405
|
+
return 'number' == typeof v.rootCount && 'number' == typeof v.markerCount && 'number' == typeof v.latestGeneration && Array.isArray(v.roots) && Array.isArray(v.markers) && Array.isArray(v.registries);
|
|
406
|
+
}
|
|
407
|
+
async function evaluateExtensionRootMeta(cdp, sessionId) {
|
|
408
|
+
try {
|
|
409
|
+
const payload = await evaluateWithContentContext(cdp, sessionId, EXTENSION_ROOT_META_EXPRESSION, isExtensionRootMetaPayload);
|
|
410
|
+
return payload;
|
|
411
|
+
} catch {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
async function evaluateShadowStyleSnapshot(cdp, sessionId) {
|
|
416
|
+
try {
|
|
417
|
+
const payload = await evaluateWithContentContext(cdp, sessionId, SHADOW_STYLE_SNAPSHOT_EXPRESSION, (value)=>null === value || 'object' == typeof value && null !== value);
|
|
418
|
+
if (null == payload) return;
|
|
419
|
+
return payload;
|
|
420
|
+
} catch {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
async function pollForVisibleShadowHostContent(cdp, sessionId, deadlineMs = 4000) {
|
|
425
|
+
const deadline = Date.now() + deadlineMs;
|
|
426
|
+
const started = Date.now();
|
|
427
|
+
while(Date.now() < deadline){
|
|
428
|
+
try {
|
|
429
|
+
const hasRoot = await hasVisibleShadowHostContent(cdp, sessionId);
|
|
430
|
+
if (hasRoot) return;
|
|
431
|
+
} catch {}
|
|
432
|
+
const elapsed = Date.now() - started;
|
|
433
|
+
const delay = elapsed < 1000 ? 150 : 350;
|
|
434
|
+
await new Promise((r)=>setTimeout(r, delay));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async function hasVisibleShadowHostContent(cdp, sessionId) {
|
|
438
|
+
try {
|
|
439
|
+
const v = await evaluateWithContentContext(cdp, sessionId, HAS_VISIBLE_SHADOW_HOST_EXPRESSION, (value)=>true === value || false === value);
|
|
440
|
+
return true === v;
|
|
441
|
+
} catch {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async function getPageHTML(cdp, sessionId, includeShadow = 'open-only') {
|
|
446
|
+
try {
|
|
447
|
+
await cdp.evaluate(sessionId, 'document.title');
|
|
448
|
+
} catch {}
|
|
449
|
+
const mainHTMLRaw = await cdp.evaluate(sessionId, `(() => {
|
|
450
|
+
try {
|
|
451
|
+
const serialize = () => {
|
|
452
|
+
const doctype = document.doctype
|
|
453
|
+
const dt = doctype
|
|
454
|
+
? '<!DOCTYPE '
|
|
455
|
+
+ doctype.name
|
|
456
|
+
+ (doctype.publicId ? ' PUBLIC "' + doctype.publicId + '"' : '')
|
|
457
|
+
+ (doctype.systemId ? ' "' + doctype.systemId + '"' : '')
|
|
458
|
+
+ '>'
|
|
459
|
+
: ''
|
|
460
|
+
return dt + '\n' + document.documentElement.outerHTML
|
|
461
|
+
}
|
|
462
|
+
return serialize()
|
|
463
|
+
} catch (e) {
|
|
464
|
+
return ''
|
|
465
|
+
}
|
|
466
|
+
})()`);
|
|
467
|
+
const mainHTML = 'string' == typeof mainHTMLRaw ? mainHTMLRaw : String(mainHTMLRaw || '');
|
|
468
|
+
if ('off' === includeShadow) return mainHTML;
|
|
469
|
+
const hasVisibleContentRoot = await evaluateWithContentContext(cdp, sessionId, `(() => {
|
|
470
|
+
try {
|
|
471
|
+
return !!document.querySelector(${JSON.stringify(NON_DEVTOOLS_CONTENT_ROOT_SELECTOR)})
|
|
472
|
+
} catch {
|
|
473
|
+
return false
|
|
474
|
+
}
|
|
475
|
+
})()`, (value)=>'boolean' == typeof value);
|
|
476
|
+
if (!hasVisibleContentRoot) return mainHTML;
|
|
477
|
+
try {
|
|
478
|
+
const mergedHtmlRaw = await evaluateWithContentContext(cdp, sessionId, `(() => { try {
|
|
479
|
+
var cloned = document.documentElement.cloneNode(true);
|
|
480
|
+
var selector = ${JSON.stringify(NON_DEVTOOLS_CONTENT_ROOT_SELECTOR)};
|
|
481
|
+
var s = new XMLSerializer();
|
|
482
|
+
try {
|
|
483
|
+
var liveHosts = Array.from(document.querySelectorAll(selector));
|
|
484
|
+
if (!liveHosts.length) return '';
|
|
485
|
+
var clonedHosts = Array.from(cloned.querySelectorAll(selector));
|
|
486
|
+
if (clonedHosts.length < liveHosts.length) {
|
|
487
|
+
var cloneDoc = cloned.ownerDocument || document;
|
|
488
|
+
var cloneBody = cloned.querySelector('body') || cloned;
|
|
489
|
+
for (var missingIndex = clonedHosts.length; missingIndex < liveHosts.length; missingIndex++) {
|
|
490
|
+
var missingLiveHost = liveHosts[missingIndex];
|
|
491
|
+
if (!missingLiveHost || !missingLiveHost.tagName || !cloneBody || typeof cloneBody.appendChild !== 'function') continue;
|
|
492
|
+
var shell = cloneDoc.createElement(String(missingLiveHost.tagName || 'div').toLowerCase());
|
|
493
|
+
try {
|
|
494
|
+
Array.from(missingLiveHost.attributes || []).forEach(function(attr){
|
|
495
|
+
try { shell.setAttribute(attr.name, attr.value); } catch(_) {}
|
|
496
|
+
});
|
|
497
|
+
} catch(_) {}
|
|
498
|
+
try { cloneBody.appendChild(shell); } catch(_) {}
|
|
499
|
+
clonedHosts.push(shell);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
for (var index = 0; index < liveHosts.length; index++) {
|
|
503
|
+
var host = clonedHosts[index];
|
|
504
|
+
var liveHost = liveHosts[index];
|
|
505
|
+
if (!host || !liveHost || !liveHost.shadowRoot) continue;
|
|
506
|
+
var shadow = Array.from(liveHost.shadowRoot.childNodes).map(function(n){
|
|
507
|
+
try { return s.serializeToString(n) } catch(e){ return '' }
|
|
508
|
+
}).join('');
|
|
509
|
+
if (!shadow) continue;
|
|
510
|
+
try { host.innerHTML = shadow; } catch(e) {}
|
|
511
|
+
}
|
|
512
|
+
} catch(e) {}
|
|
513
|
+
var doctype = document.doctype;
|
|
514
|
+
var dt = doctype ? '<!DOCTYPE ' + doctype.name + (doctype.publicId ? ' PUBLIC \"' + doctype.publicId + '\"' : '') + (doctype.systemId ? ' \"' + doctype.systemId + '\"' : '') + '>' : '';
|
|
515
|
+
return String(dt + '\\n' + (cloned.outerHTML || document.documentElement.outerHTML));
|
|
516
|
+
} catch(e) { try { return String(document.documentElement.outerHTML); } catch(_) { return '' } } })()`, (value)=>'string' == typeof value && /<html[\s>]/i.test(value));
|
|
517
|
+
const mergedHtml = 'string' == typeof mergedHtmlRaw ? mergedHtmlRaw : String(mergedHtmlRaw || '');
|
|
518
|
+
if (mergedHtml && /<html[\s>]/i.test(mergedHtml)) return mergedHtml;
|
|
519
|
+
} catch {}
|
|
520
|
+
let shadowContent = '';
|
|
521
|
+
try {
|
|
522
|
+
shadowContent = await evaluateWithContentContext(cdp, sessionId, `(() => {
|
|
523
|
+
try {
|
|
524
|
+
const hosts = Array.from(document.querySelectorAll(${JSON.stringify(CONTENT_ROOT_SELECTOR)}));
|
|
525
|
+
if (!hosts.length) return '';
|
|
526
|
+
const preferMarkers = ['iskilar_box','content_script','content_title','js-probe'];
|
|
527
|
+
let firstNonEmpty = '';
|
|
528
|
+
for (const host of hosts) {
|
|
529
|
+
try {
|
|
530
|
+
const sr = host && host.shadowRoot;
|
|
531
|
+
if (!sr) continue;
|
|
532
|
+
const html = String(sr.innerHTML || '');
|
|
533
|
+
if (html && html.length) {
|
|
534
|
+
if (preferMarkers.some((m) => html.includes(m))) return html;
|
|
535
|
+
if (!firstNonEmpty) firstNonEmpty = html;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
const parts = Array.from(sr.children)
|
|
540
|
+
.map((n) => (n && n.outerHTML) ? String(n.outerHTML) : '')
|
|
541
|
+
.join('');
|
|
542
|
+
if (parts && parts.length) {
|
|
543
|
+
if (preferMarkers.some((m) => parts.includes(m))) return parts;
|
|
544
|
+
if (!firstNonEmpty) firstNonEmpty = parts;
|
|
545
|
+
}
|
|
546
|
+
} catch { /* ignore */ }
|
|
547
|
+
} catch { /* ignore */ }
|
|
548
|
+
}
|
|
549
|
+
return firstNonEmpty || '';
|
|
550
|
+
} catch { return '' }
|
|
551
|
+
})()`, (value)=>'string' == typeof value && value.trim().length > 0);
|
|
552
|
+
} catch {}
|
|
553
|
+
if (shadowContent) try {
|
|
554
|
+
const sc = 'string' == typeof shadowContent ? shadowContent : String(shadowContent || '');
|
|
555
|
+
return mergeShadowIntoDocument(mainHTML, sc);
|
|
556
|
+
} catch {}
|
|
557
|
+
return mainHTML;
|
|
558
|
+
}
|
|
559
|
+
async function waitForLoadEvent(cdp, sessionId) {
|
|
560
|
+
return new Promise((resolve)=>{
|
|
561
|
+
let resolved = false;
|
|
562
|
+
const listener = (data)=>{
|
|
563
|
+
try {
|
|
564
|
+
const message = JSON.parse(data);
|
|
565
|
+
if ('Page.loadEventFired' === message.method && message.sessionId === sessionId && !resolved) {
|
|
566
|
+
resolved = true;
|
|
567
|
+
resolve();
|
|
568
|
+
}
|
|
569
|
+
} catch {}
|
|
570
|
+
};
|
|
571
|
+
const clientWithHandle = cdp;
|
|
572
|
+
const original = clientWithHandle.handleMessage.bind(cdp);
|
|
573
|
+
clientWithHandle.handleMessage = (data)=>{
|
|
574
|
+
original(data);
|
|
575
|
+
listener(data);
|
|
576
|
+
};
|
|
577
|
+
setTimeout(()=>{
|
|
578
|
+
if (!resolved) {
|
|
579
|
+
resolved = true;
|
|
580
|
+
console.log(messages.Qiq());
|
|
581
|
+
resolve();
|
|
582
|
+
}
|
|
583
|
+
clientWithHandle.handleMessage = original;
|
|
584
|
+
}, 2000);
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
async function waitForContentScriptInjection(cdp, sessionId) {
|
|
588
|
+
const deadline = Date.now() + 30000;
|
|
589
|
+
const started = Date.now();
|
|
590
|
+
while(Date.now() < deadline){
|
|
591
|
+
try {
|
|
592
|
+
const injected = await evaluateWithContentContext(cdp, sessionId, `(() => { try {
|
|
593
|
+
const hosts = Array.from(document.querySelectorAll(${JSON.stringify(CONTENT_ROOT_SELECTOR)}));
|
|
594
|
+
if (!hosts.length) return false;
|
|
595
|
+
const markers = ['iskilar_box','content_script','content_title','js-probe'];
|
|
596
|
+
for (const h of hosts) {
|
|
597
|
+
try {
|
|
598
|
+
const sr = h && h.shadowRoot;
|
|
599
|
+
if (!sr) continue;
|
|
600
|
+
const html = String(sr.innerHTML||'');
|
|
601
|
+
if (html.length > 0) return true;
|
|
602
|
+
if (markers.some((m) => html.includes(m))) return true;
|
|
603
|
+
try {
|
|
604
|
+
const parts = Array.from(sr.children).map((n) => (n && n.outerHTML) ? String(n.outerHTML) : '').join('');
|
|
605
|
+
if (parts && parts.length) return true;
|
|
606
|
+
if (markers.some((m) => parts.includes(m))) return true;
|
|
607
|
+
} catch { /* ignore */ }
|
|
608
|
+
} catch { /* ignore */ }
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
} catch { return false } })()`, (value)=>Boolean(value));
|
|
612
|
+
if (Boolean(injected)) return true;
|
|
613
|
+
} catch {}
|
|
614
|
+
const elapsed = Date.now() - started;
|
|
615
|
+
const delay = elapsed < 2000 ? 150 : 500;
|
|
616
|
+
await new Promise((r)=>setTimeout(r, delay));
|
|
617
|
+
}
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
function establishBrowserConnection(url, isDev, onMessage, onRejectPending) {
|
|
621
|
+
return new Promise((resolve, reject)=>{
|
|
622
|
+
const ws = new (external_ws_default())(url);
|
|
623
|
+
ws.on('open', ()=>{
|
|
624
|
+
if (isDev) console.log(messages.F1E());
|
|
625
|
+
resolve(ws);
|
|
626
|
+
});
|
|
627
|
+
ws.on('message', (data)=>{
|
|
628
|
+
onMessage(data.toString());
|
|
629
|
+
});
|
|
630
|
+
ws.on('error', (error)=>{
|
|
631
|
+
if (isDev) console.error(messages.fRy(error.message));
|
|
632
|
+
onRejectPending(error.message);
|
|
633
|
+
reject(error);
|
|
634
|
+
});
|
|
635
|
+
ws.on('close', ()=>{
|
|
636
|
+
if (isDev) console.log(messages.hE8());
|
|
637
|
+
onRejectPending('CDP connection closed');
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
function _define_property(obj, key, value) {
|
|
642
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
643
|
+
value: value,
|
|
644
|
+
enumerable: true,
|
|
645
|
+
configurable: true,
|
|
646
|
+
writable: true
|
|
647
|
+
});
|
|
648
|
+
else obj[key] = value;
|
|
649
|
+
return obj;
|
|
650
|
+
}
|
|
651
|
+
class CDPClient {
|
|
652
|
+
isDev() {
|
|
653
|
+
return 'true' === process.env.EXTENSION_AUTHOR_MODE;
|
|
654
|
+
}
|
|
655
|
+
async connect() {
|
|
656
|
+
return new Promise(async (resolve, reject)=>{
|
|
657
|
+
try {
|
|
658
|
+
this.targetWebSocketUrl = await (0, discovery.N)(this.host, this.port, this.isDev());
|
|
659
|
+
let pendingRejected = false;
|
|
660
|
+
this.ws = await establishBrowserConnection(this.targetWebSocketUrl, this.isDev(), (data)=>this.handleMessage(data), (reason)=>{
|
|
661
|
+
if (pendingRejected) return;
|
|
662
|
+
pendingRejected = true;
|
|
663
|
+
this.pendingRequests.forEach(({ reject, timeout }, id)=>{
|
|
664
|
+
try {
|
|
665
|
+
reject(new Error(reason));
|
|
666
|
+
} catch (error) {
|
|
667
|
+
if (this.isDev()) {
|
|
668
|
+
const err = error;
|
|
669
|
+
console.warn(messages.r0s(String(err.message || err)));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (timeout) clearTimeout(timeout);
|
|
673
|
+
this.pendingRequests.delete(id);
|
|
674
|
+
});
|
|
675
|
+
this.ws = null;
|
|
676
|
+
});
|
|
677
|
+
this.startHeartbeat();
|
|
678
|
+
if (this.isDev()) console.log(messages.M3V(this.host, this.port));
|
|
679
|
+
resolve();
|
|
680
|
+
} catch (error) {
|
|
681
|
+
const err = error;
|
|
682
|
+
reject(new Error(`Failed to connect to CDP: ${err.message || err}`));
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
disconnect() {
|
|
687
|
+
this.stopHeartbeat();
|
|
688
|
+
if (this.ws) {
|
|
689
|
+
try {
|
|
690
|
+
this.ws.close();
|
|
691
|
+
} catch {}
|
|
692
|
+
this.ws = null;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
startHeartbeat() {
|
|
696
|
+
this.stopHeartbeat();
|
|
697
|
+
this.heartbeatTimer = setInterval(async ()=>{
|
|
698
|
+
if (!this.isConnected()) return void this.stopHeartbeat();
|
|
699
|
+
try {
|
|
700
|
+
await this.getBrowserVersion();
|
|
701
|
+
} catch {
|
|
702
|
+
if (this.isDev()) console.warn('[CDP] Heartbeat failed, connection appears dead');
|
|
703
|
+
this.disconnect();
|
|
704
|
+
}
|
|
705
|
+
}, constants.Y$);
|
|
706
|
+
if ('function' == typeof this.heartbeatTimer.unref) this.heartbeatTimer.unref();
|
|
707
|
+
}
|
|
708
|
+
stopHeartbeat() {
|
|
709
|
+
if (this.heartbeatTimer) {
|
|
710
|
+
clearInterval(this.heartbeatTimer);
|
|
711
|
+
this.heartbeatTimer = null;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
isConnected() {
|
|
715
|
+
return !!this.ws && this.ws.readyState === external_ws_default().OPEN;
|
|
716
|
+
}
|
|
717
|
+
onProtocolEvent(handler) {
|
|
718
|
+
this.eventCallbacks.add(handler);
|
|
719
|
+
return ()=>{
|
|
720
|
+
this.eventCallbacks.delete(handler);
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
handleMessage(data) {
|
|
724
|
+
try {
|
|
725
|
+
const message = JSON.parse(data);
|
|
726
|
+
if (message.id) {
|
|
727
|
+
const pending = this.pendingRequests.get(message.id);
|
|
728
|
+
if (pending) {
|
|
729
|
+
if (pending.timeout) clearTimeout(pending.timeout);
|
|
730
|
+
this.pendingRequests.delete(message.id);
|
|
731
|
+
if (message.error) pending.reject(new Error(JSON.stringify(message.error)));
|
|
732
|
+
else pending.resolve(message.result);
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if ('Target.attachedToTarget' === message.method) {
|
|
737
|
+
const params = message.params || {};
|
|
738
|
+
if (this.isDev()) console.log(messages.p8m(String(params.sessionId || ''), String(params.targetInfo?.type || '')));
|
|
739
|
+
}
|
|
740
|
+
for (const eventCallback of this.eventCallbacks)eventCallback(message);
|
|
741
|
+
} catch (error) {
|
|
742
|
+
if (this.isDev()) {
|
|
743
|
+
const err = error;
|
|
744
|
+
console.warn(messages.xxG(String(err.message || err)));
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
async sendCommand(method, params = {}, sessionId, timeoutMs = constants.Ns) {
|
|
749
|
+
return new Promise((resolve, reject)=>{
|
|
750
|
+
if (!this.ws || this.ws.readyState !== external_ws_default().OPEN) return reject(new Error('WebSocket is not open'));
|
|
751
|
+
const id = ++this.messageId;
|
|
752
|
+
const message = {
|
|
753
|
+
id,
|
|
754
|
+
method,
|
|
755
|
+
params
|
|
756
|
+
};
|
|
757
|
+
if (sessionId) message.sessionId = sessionId;
|
|
758
|
+
try {
|
|
759
|
+
const timeout = setTimeout(()=>{
|
|
760
|
+
const pending = this.pendingRequests.get(id);
|
|
761
|
+
if (!pending) return;
|
|
762
|
+
this.pendingRequests.delete(id);
|
|
763
|
+
pending.reject(new Error(`CDP command timed out (${timeoutMs}ms): ${String(pending.method || method)}`));
|
|
764
|
+
}, timeoutMs);
|
|
765
|
+
this.pendingRequests.set(id, {
|
|
766
|
+
resolve,
|
|
767
|
+
reject,
|
|
768
|
+
timeout,
|
|
769
|
+
method
|
|
770
|
+
});
|
|
771
|
+
this.ws.send(JSON.stringify(message));
|
|
772
|
+
} catch (error) {
|
|
773
|
+
const pending = this.pendingRequests.get(id);
|
|
774
|
+
if (pending?.timeout) clearTimeout(pending.timeout);
|
|
775
|
+
this.pendingRequests.delete(id);
|
|
776
|
+
reject(error);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
async getTargets() {
|
|
781
|
+
const response = await this.sendCommand('Target.getTargets');
|
|
782
|
+
return response?.targetInfos || [];
|
|
783
|
+
}
|
|
784
|
+
async getBrowserVersion() {
|
|
785
|
+
const response = await this.sendCommand('Browser.getVersion');
|
|
786
|
+
return response || {};
|
|
787
|
+
}
|
|
788
|
+
async attachToTarget(targetId) {
|
|
789
|
+
const response = await this.sendCommand('Target.attachToTarget', {
|
|
790
|
+
targetId,
|
|
791
|
+
flatten: true
|
|
792
|
+
});
|
|
793
|
+
return response.sessionId || '';
|
|
794
|
+
}
|
|
795
|
+
async enableAutoAttach() {
|
|
796
|
+
await this.sendCommand('Target.setAutoAttach', {
|
|
797
|
+
autoAttach: true,
|
|
798
|
+
waitForDebuggerOnStart: false,
|
|
799
|
+
flatten: true
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
async enableRuntimeAndLog(sessionId) {
|
|
803
|
+
await this.sendCommand('Log.enable', {}, sessionId);
|
|
804
|
+
if (sessionId) await this.sendCommand('Runtime.enable', {}, sessionId);
|
|
805
|
+
}
|
|
806
|
+
async navigate(sessionId, url) {
|
|
807
|
+
await this.sendCommand('Page.navigate', {
|
|
808
|
+
url
|
|
809
|
+
}, sessionId);
|
|
810
|
+
}
|
|
811
|
+
async createTarget(url) {
|
|
812
|
+
const res = await this.sendCommand('Target.createTarget', {
|
|
813
|
+
url
|
|
814
|
+
});
|
|
815
|
+
return String(res?.targetId || '');
|
|
816
|
+
}
|
|
817
|
+
async activateTarget(targetId) {
|
|
818
|
+
await this.sendCommand('Target.activateTarget', {
|
|
819
|
+
targetId
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
async waitForLoadEvent(sessionId) {
|
|
823
|
+
return waitForLoadEvent(this, sessionId);
|
|
824
|
+
}
|
|
825
|
+
async waitForContentScriptInjection(sessionId) {
|
|
826
|
+
return waitForContentScriptInjection(this, sessionId);
|
|
827
|
+
}
|
|
828
|
+
async getExtensionRootMeta(sessionId) {
|
|
829
|
+
return evaluateExtensionRootMeta(this, sessionId);
|
|
830
|
+
}
|
|
831
|
+
async getShadowStyleSnapshot(sessionId) {
|
|
832
|
+
return evaluateShadowStyleSnapshot(this, sessionId);
|
|
833
|
+
}
|
|
834
|
+
async pollForVisibleShadowHostContent(sessionId, deadlineMs) {
|
|
835
|
+
return pollForVisibleShadowHostContent(this, sessionId, deadlineMs);
|
|
836
|
+
}
|
|
837
|
+
async hasVisibleShadowHostContent(sessionId) {
|
|
838
|
+
return hasVisibleShadowHostContent(this, sessionId);
|
|
839
|
+
}
|
|
840
|
+
async evaluate(sessionId, expression, options) {
|
|
841
|
+
const response = await this.sendCommand('Runtime.evaluate', {
|
|
842
|
+
expression,
|
|
843
|
+
returnByValue: true,
|
|
844
|
+
awaitPromise: options?.awaitPromise === true
|
|
845
|
+
}, sessionId);
|
|
846
|
+
return response.result?.value;
|
|
847
|
+
}
|
|
848
|
+
async evaluateInContext(sessionId, expression, contextId, options) {
|
|
849
|
+
const response = await this.sendCommand('Runtime.evaluate', {
|
|
850
|
+
expression,
|
|
851
|
+
contextId,
|
|
852
|
+
returnByValue: true,
|
|
853
|
+
awaitPromise: options?.awaitPromise === true
|
|
854
|
+
}, sessionId);
|
|
855
|
+
return response.result?.value;
|
|
856
|
+
}
|
|
857
|
+
async getPageHTML(sessionId, includeShadow = 'open-only') {
|
|
858
|
+
return getPageHTML(this, sessionId, includeShadow);
|
|
859
|
+
}
|
|
860
|
+
async closeTarget(targetId) {
|
|
861
|
+
await this.sendCommand('Target.closeTarget', {
|
|
862
|
+
targetId
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
async forceReloadExtension(extensionId) {
|
|
866
|
+
const attempts = 8;
|
|
867
|
+
let lastError = null;
|
|
868
|
+
for(let i = 0; i < attempts; i++){
|
|
869
|
+
try {
|
|
870
|
+
const ok = await this.reloadExtensionViaTargetEval(extensionId);
|
|
871
|
+
if (ok) return true;
|
|
872
|
+
} catch (error) {
|
|
873
|
+
lastError = error;
|
|
874
|
+
}
|
|
875
|
+
const backoffMs = Math.min(1200, 150 * (i + 1));
|
|
876
|
+
await new Promise((r)=>setTimeout(r, backoffMs));
|
|
877
|
+
}
|
|
878
|
+
console.warn(messages.ccn(extensionId, lastError?.message || String(lastError || 'runtime.reload failed')));
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
async getExtensionInfo(extensionId) {
|
|
882
|
+
try {
|
|
883
|
+
return await getExtensionInfo(this, extensionId);
|
|
884
|
+
} catch (error) {
|
|
885
|
+
throw new Error(messages.Z5i(extensionId, error.message));
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
async reloadExtensionViaTargetEval(extensionId) {
|
|
889
|
+
try {
|
|
890
|
+
const targets = await this.getTargets();
|
|
891
|
+
const preferredOrder = [
|
|
892
|
+
'service_worker',
|
|
893
|
+
'background_page',
|
|
894
|
+
'worker',
|
|
895
|
+
'page'
|
|
896
|
+
];
|
|
897
|
+
for (const type of preferredOrder){
|
|
898
|
+
const matchingTargets = (targets || []).filter((t)=>{
|
|
899
|
+
const url = String(t?.url || '');
|
|
900
|
+
const tt = String(t?.type || '');
|
|
901
|
+
const inExtensionScope = url.startsWith(`chrome-extension://${extensionId}/`);
|
|
902
|
+
return tt === type && inExtensionScope;
|
|
903
|
+
});
|
|
904
|
+
for (const target of matchingTargets){
|
|
905
|
+
const targetId = target?.targetId;
|
|
906
|
+
if (targetId) try {
|
|
907
|
+
const sessionId = await this.attachToTarget(targetId);
|
|
908
|
+
await this.sendCommand('Runtime.enable', {}, sessionId);
|
|
909
|
+
await this.sendCommand('Runtime.evaluate', {
|
|
910
|
+
expression: '(function(){ try { if (!chrome || !chrome.runtime || !chrome.runtime.reload) return false; chrome.runtime.reload(); return true; } catch (error) { return false; } })()',
|
|
911
|
+
returnByValue: true
|
|
912
|
+
}, sessionId);
|
|
913
|
+
return true;
|
|
914
|
+
} catch {}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
return false;
|
|
918
|
+
} catch {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async loadUnpackedExtension(path) {
|
|
923
|
+
try {
|
|
924
|
+
return await loadUnpackedExtension(this, path);
|
|
925
|
+
} catch (error) {
|
|
926
|
+
throw new Error(messages.xlM(path, error.message));
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
async unloadExtension(extensionId) {
|
|
930
|
+
try {
|
|
931
|
+
return await unloadExtension(this, extensionId);
|
|
932
|
+
} catch (error) {
|
|
933
|
+
console.error(messages.yEr(extensionId, error.message));
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
constructor(port = 9222, host = '127.0.0.1'){
|
|
938
|
+
_define_property(this, "port", void 0);
|
|
939
|
+
_define_property(this, "host", void 0);
|
|
940
|
+
_define_property(this, "ws", null);
|
|
941
|
+
_define_property(this, "targetWebSocketUrl", null);
|
|
942
|
+
_define_property(this, "eventCallbacks", new Set());
|
|
943
|
+
_define_property(this, "messageId", 0);
|
|
944
|
+
_define_property(this, "pendingRequests", new Map());
|
|
945
|
+
_define_property(this, "heartbeatTimer", null);
|
|
946
|
+
this.port = port;
|
|
947
|
+
this.host = host;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
function isRecoverableBootstrapError(error) {
|
|
951
|
+
const msg = String(error?.message || error || '').toLowerCase();
|
|
952
|
+
return msg.includes('econnreset') || msg.includes('websocket is not open') || msg.includes('cdp connection closed') || msg.includes('socket hang up') || msg.includes('timed out') || msg.includes('no cdp websocket url');
|
|
953
|
+
}
|
|
954
|
+
async function connectToChromeCdp(cdpPort) {
|
|
955
|
+
let retries = 0;
|
|
956
|
+
const maxRetries = 60;
|
|
957
|
+
const backoffMs = 250;
|
|
958
|
+
while(retries < maxRetries){
|
|
959
|
+
const ready = await (0, discovery.z)(cdpPort);
|
|
960
|
+
if (ready) break;
|
|
961
|
+
retries++;
|
|
962
|
+
await new Promise((r)=>setTimeout(r, backoffMs));
|
|
963
|
+
}
|
|
964
|
+
const maxBootstrapAttempts = 4;
|
|
965
|
+
let lastError = null;
|
|
966
|
+
for(let attempt = 1; attempt <= maxBootstrapAttempts; attempt++){
|
|
967
|
+
const cdp = new CDPClient(cdpPort, '127.0.0.1');
|
|
968
|
+
try {
|
|
969
|
+
await cdp.connect();
|
|
970
|
+
await cdp.sendCommand('Target.setDiscoverTargets', {
|
|
971
|
+
discover: true
|
|
972
|
+
});
|
|
973
|
+
await cdp.sendCommand('Target.setAutoAttach', {
|
|
974
|
+
autoAttach: true,
|
|
975
|
+
waitForDebuggerOnStart: false,
|
|
976
|
+
flatten: true
|
|
977
|
+
});
|
|
978
|
+
return cdp;
|
|
979
|
+
} catch (error) {
|
|
980
|
+
lastError = error;
|
|
981
|
+
cdp.disconnect();
|
|
982
|
+
const retryable = isRecoverableBootstrapError(error);
|
|
983
|
+
const hasMoreAttempts = attempt < maxBootstrapAttempts;
|
|
984
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
|
|
985
|
+
const base = String(error?.message || error);
|
|
986
|
+
console.warn(`[CDP] bootstrap attempt ${attempt}/${maxBootstrapAttempts} failed: ${base}`);
|
|
987
|
+
}
|
|
988
|
+
if (!retryable || !hasMoreAttempts) throw error;
|
|
989
|
+
const delayMs = 120 * attempt;
|
|
990
|
+
await new Promise((r)=>setTimeout(r, delayMs));
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
throw lastError instanceof Error ? lastError : new Error('Failed to bootstrap CDP connection');
|
|
994
|
+
}
|
|
995
|
+
function readManifestInfo(outPath) {
|
|
996
|
+
try {
|
|
997
|
+
const manifestPath = external_path_.join(outPath, 'manifest.json');
|
|
998
|
+
const manifest = JSON.parse(external_fs_.readFileSync(manifestPath, 'utf-8'));
|
|
999
|
+
return {
|
|
1000
|
+
name: manifest?.name,
|
|
1001
|
+
version: manifest?.version
|
|
1002
|
+
};
|
|
1003
|
+
} catch {
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function registerAutoEnableLogging(cdp, getExtensionId) {
|
|
1008
|
+
cdp.onProtocolEvent((message)=>{
|
|
1009
|
+
try {
|
|
1010
|
+
if (!message || !message.method) return;
|
|
1011
|
+
if ('Target.attachedToTarget' === message.method) {
|
|
1012
|
+
const params = message.params || {};
|
|
1013
|
+
const targetInfo = params.targetInfo || {};
|
|
1014
|
+
const sessionId = params.sessionId;
|
|
1015
|
+
const url = String(targetInfo.url || '');
|
|
1016
|
+
const type = String(targetInfo.type || '');
|
|
1017
|
+
const extId = getExtensionId();
|
|
1018
|
+
const matchesExtension = !!(extId && url.includes(`chrome-extension://${extId}/`) || 'service_worker' === type);
|
|
1019
|
+
if (sessionId && matchesExtension) {
|
|
1020
|
+
cdp.sendCommand('Runtime.enable', {}, sessionId).catch(()=>{});
|
|
1021
|
+
cdp.sendCommand('Log.enable', {}, sessionId).catch(()=>{});
|
|
1022
|
+
}
|
|
1023
|
+
} else if ('Runtime.consoleAPICalled' === message.method || 'Log.entryAdded' === message.method) {
|
|
1024
|
+
if ('1' === String(process.env.EXTENSION_VERBOSE || '').trim()) {
|
|
1025
|
+
const ts = new Date().toISOString();
|
|
1026
|
+
console.log(messages.bvI(ts, message.params));
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(messages.KK1(String(error?.message || error)));
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
function cdp_extension_controller_define_property(obj, key, value) {
|
|
1035
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
1036
|
+
value: value,
|
|
1037
|
+
enumerable: true,
|
|
1038
|
+
configurable: true,
|
|
1039
|
+
writable: true
|
|
1040
|
+
});
|
|
1041
|
+
else obj[key] = value;
|
|
1042
|
+
return obj;
|
|
1043
|
+
}
|
|
1044
|
+
class CDPExtensionController {
|
|
1045
|
+
async connect() {
|
|
1046
|
+
if (this.cdp) return;
|
|
1047
|
+
await this.connectFreshClient();
|
|
1048
|
+
}
|
|
1049
|
+
async ensureLoaded() {
|
|
1050
|
+
if (!this.cdp) throw new Error('CDP not connected');
|
|
1051
|
+
const exists = external_fs_.existsSync(this.outPath);
|
|
1052
|
+
if (!exists) throw new Error(`Output path not found: ${this.outPath}`);
|
|
1053
|
+
if (!this.extensionId) {
|
|
1054
|
+
const id = await this.deriveExtensionIdFromTargets();
|
|
1055
|
+
if (id) this.extensionId = id;
|
|
1056
|
+
}
|
|
1057
|
+
if (this.extensionId) {
|
|
1058
|
+
const belongsToOutPath = this.extensionIdBelongsToOutPath(this.extensionId);
|
|
1059
|
+
if (false === belongsToOutPath) this.extensionId = null;
|
|
1060
|
+
}
|
|
1061
|
+
if (this.extensionId) try {
|
|
1062
|
+
let info = null;
|
|
1063
|
+
try {
|
|
1064
|
+
info = await this.cdp.getExtensionInfo(this.extensionId);
|
|
1065
|
+
} catch {}
|
|
1066
|
+
if (!info) {
|
|
1067
|
+
const manifest = JSON.parse(external_fs_.readFileSync(external_path_.join(this.outPath, 'manifest.json'), 'utf-8'));
|
|
1068
|
+
return {
|
|
1069
|
+
extensionId: this.extensionId,
|
|
1070
|
+
name: manifest.name,
|
|
1071
|
+
version: manifest.version
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
return {
|
|
1075
|
+
extensionId: this.extensionId,
|
|
1076
|
+
name: info?.extensionInfo?.name,
|
|
1077
|
+
version: info?.extensionInfo?.version
|
|
1078
|
+
};
|
|
1079
|
+
} catch {}
|
|
1080
|
+
try {
|
|
1081
|
+
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(20, 200);
|
|
1082
|
+
if (!this.extensionId) throw new Error('Failed to determine extension ID via CDP');
|
|
1083
|
+
await this.enableLogging();
|
|
1084
|
+
let name;
|
|
1085
|
+
let version;
|
|
1086
|
+
try {
|
|
1087
|
+
const info = await this.cdp.getExtensionInfo(this.extensionId);
|
|
1088
|
+
name = info?.extensionInfo?.name;
|
|
1089
|
+
version = info?.extensionInfo?.version;
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
try {
|
|
1092
|
+
const manifest = readManifestInfo(this.outPath);
|
|
1093
|
+
name = String(manifest?.name || '') || void 0;
|
|
1094
|
+
version = String(manifest?.version || '') || void 0;
|
|
1095
|
+
} catch (e2) {
|
|
1096
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn('[CDP] Fallback manifest read failed:', String(e2?.message || e2));
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return {
|
|
1100
|
+
extensionId: this.extensionId,
|
|
1101
|
+
name,
|
|
1102
|
+
version
|
|
1103
|
+
};
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
throw new Error(`Failed to load extension from ${external_path_.resolve(this.outPath)}: ${String(error.message || error)}`);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
async deriveExtensionIdFromTargets(maxRetries = 20, backoffMs = 200) {
|
|
1109
|
+
if (!this.cdp) return null;
|
|
1110
|
+
return await deriveExtensionIdFromTargetsHelper(this.cdp, this.outPath, maxRetries, backoffMs, this.profilePath, this.extensionPaths);
|
|
1111
|
+
}
|
|
1112
|
+
normalizePath(input) {
|
|
1113
|
+
try {
|
|
1114
|
+
return external_fs_.realpathSync(external_path_.resolve(input));
|
|
1115
|
+
} catch {
|
|
1116
|
+
return external_path_.resolve(input);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
extensionIdBelongsToOutPath(extensionId) {
|
|
1120
|
+
if (!this.profilePath || !extensionId) return null;
|
|
1121
|
+
const prefCandidates = [];
|
|
1122
|
+
const addPrefCandidate = (dir)=>{
|
|
1123
|
+
const prefPath = external_path_.join(dir, 'Preferences');
|
|
1124
|
+
if (external_fs_.existsSync(prefPath)) prefCandidates.push(prefPath);
|
|
1125
|
+
};
|
|
1126
|
+
try {
|
|
1127
|
+
addPrefCandidate(this.profilePath);
|
|
1128
|
+
addPrefCandidate(external_path_.join(this.profilePath, 'Default'));
|
|
1129
|
+
for (const entry of external_fs_.readdirSync(this.profilePath))if (/^Profile\s+\d+$/i.test(entry)) addPrefCandidate(external_path_.join(this.profilePath, entry));
|
|
1130
|
+
} catch {}
|
|
1131
|
+
if (0 === prefCandidates.length) return null;
|
|
1132
|
+
const normalizedOutPath = this.normalizePath(this.outPath);
|
|
1133
|
+
for (const prefPath of prefCandidates)try {
|
|
1134
|
+
const prefs = JSON.parse(external_fs_.readFileSync(prefPath, 'utf-8'));
|
|
1135
|
+
const settings = prefs?.extensions?.settings;
|
|
1136
|
+
const info = settings?.[extensionId];
|
|
1137
|
+
const storedPath = String(info?.path || '');
|
|
1138
|
+
if (!storedPath) continue;
|
|
1139
|
+
return this.normalizePath(storedPath) === normalizedOutPath;
|
|
1140
|
+
} catch {}
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
1143
|
+
getDeveloperModeStatus() {
|
|
1144
|
+
if (!this.profilePath) return 'unknown';
|
|
1145
|
+
const prefCandidates = [];
|
|
1146
|
+
const seen = new Set();
|
|
1147
|
+
const addPrefCandidate = (dir)=>{
|
|
1148
|
+
const prefPath = external_path_.join(dir, 'Preferences');
|
|
1149
|
+
if (!external_fs_.existsSync(prefPath)) return;
|
|
1150
|
+
const dedupeKey = external_path_.resolve(prefPath);
|
|
1151
|
+
if (seen.has(dedupeKey)) return;
|
|
1152
|
+
seen.add(dedupeKey);
|
|
1153
|
+
prefCandidates.push(prefPath);
|
|
1154
|
+
};
|
|
1155
|
+
try {
|
|
1156
|
+
addPrefCandidate(this.profilePath);
|
|
1157
|
+
addPrefCandidate(external_path_.join(this.profilePath, 'Default'));
|
|
1158
|
+
for (const entry of external_fs_.readdirSync(this.profilePath))if (/^Profile\s+\d+$/i.test(entry)) addPrefCandidate(external_path_.join(this.profilePath, entry));
|
|
1159
|
+
} catch {}
|
|
1160
|
+
for (const prefPath of prefCandidates)try {
|
|
1161
|
+
const prefs = JSON.parse(external_fs_.readFileSync(prefPath, 'utf-8'));
|
|
1162
|
+
const uiFlag = prefs?.extensions?.ui?.developer_mode;
|
|
1163
|
+
if ('boolean' == typeof uiFlag) return uiFlag ? 'enabled' : 'disabled';
|
|
1164
|
+
const legacyFlag = prefs?.extensions?.developer_mode;
|
|
1165
|
+
if ('boolean' == typeof legacyFlag) return legacyFlag ? 'enabled' : 'disabled';
|
|
1166
|
+
} catch {}
|
|
1167
|
+
return 'unknown';
|
|
1168
|
+
}
|
|
1169
|
+
getLastRuntimeReinjectionReport() {
|
|
1170
|
+
return this.lastRuntimeReinjectionReport;
|
|
1171
|
+
}
|
|
1172
|
+
async reloadMatchingTabsForContentScripts(rules, options = {}) {
|
|
1173
|
+
if (!this.cdp || 0 === rules.length) return 0;
|
|
1174
|
+
let reinjectedTabs = 0;
|
|
1175
|
+
const targets = await this.cdp.getTargets();
|
|
1176
|
+
for (const target of targets || []){
|
|
1177
|
+
const targetType = String(target?.type || '');
|
|
1178
|
+
const targetId = String(target?.targetId || '');
|
|
1179
|
+
const targetUrl = String(target?.url || '');
|
|
1180
|
+
if ('page' !== targetType || !targetId || !targetUrl) continue;
|
|
1181
|
+
const matchingRules = rules.filter((rule)=>(0, content_script_targets.lM)(targetUrl, [
|
|
1182
|
+
rule
|
|
1183
|
+
]));
|
|
1184
|
+
if (0 !== matchingRules.length) try {
|
|
1185
|
+
const sessionId = await this.cdp.attachToTarget(targetId);
|
|
1186
|
+
let reinjected = false;
|
|
1187
|
+
if (options.preferPageReload) reinjected = await this.reloadPageTarget(sessionId);
|
|
1188
|
+
else {
|
|
1189
|
+
for (const [index, rule] of matchingRules.entries()){
|
|
1190
|
+
const didReinject = await this.reinjectContentScriptRule(sessionId, rule, options.allowCoarseCleanup ?? 0 === index, options.sourceOverridesByBundleId);
|
|
1191
|
+
reinjected = reinjected || didReinject;
|
|
1192
|
+
}
|
|
1193
|
+
if (!reinjected) reinjected = await this.reloadPageTarget(sessionId);
|
|
1194
|
+
}
|
|
1195
|
+
if (reinjected) reinjectedTabs += 1;
|
|
1196
|
+
} catch (error) {
|
|
1197
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(`[CDP] Failed to reinject content scripts into ${targetUrl}: ${String(error?.message || error)}`);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return reinjectedTabs;
|
|
1201
|
+
}
|
|
1202
|
+
async reinjectMatchingTabsViaExtensionRuntime(rules) {
|
|
1203
|
+
if (!this.cdp || 0 === rules.length) {
|
|
1204
|
+
this.lastRuntimeReinjectionReport = {
|
|
1205
|
+
phase: 'skipped',
|
|
1206
|
+
reason: 'missing_cdp_or_rules',
|
|
1207
|
+
hasCdp: !!this.cdp,
|
|
1208
|
+
ruleCount: rules.length
|
|
1209
|
+
};
|
|
1210
|
+
return 0;
|
|
1211
|
+
}
|
|
1212
|
+
const targets = await this.cdp.getTargets();
|
|
1213
|
+
const matchingUrlsByRule = new Map();
|
|
1214
|
+
for (const target of targets || []){
|
|
1215
|
+
const targetType = String(target?.type || '');
|
|
1216
|
+
const targetUrl = String(target?.url || '');
|
|
1217
|
+
if ('page' === targetType && targetUrl) for (const rule of rules){
|
|
1218
|
+
if (!(0, content_script_targets.lM)(targetUrl, [
|
|
1219
|
+
rule
|
|
1220
|
+
])) continue;
|
|
1221
|
+
const urls = matchingUrlsByRule.get(rule.index) || new Set();
|
|
1222
|
+
urls.add(targetUrl);
|
|
1223
|
+
matchingUrlsByRule.set(rule.index, urls);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
const payload = rules.map((rule)=>{
|
|
1227
|
+
const jsPath = (0, content_script_targets.nG)(this.outPath, rule.index, 'js');
|
|
1228
|
+
const cssPath = (0, content_script_targets.nG)(this.outPath, rule.index, 'css');
|
|
1229
|
+
if (!jsPath || !external_fs_.existsSync(jsPath)) return null;
|
|
1230
|
+
const jsFile = external_path_.relative(this.outPath, jsPath).replace(/\\/g, '/');
|
|
1231
|
+
const cssFile = cssPath && external_fs_.existsSync(cssPath) ? external_path_.relative(this.outPath, cssPath).replace(/\\/g, '/') : null;
|
|
1232
|
+
const jsSource = external_fs_.readFileSync(jsPath, 'utf-8');
|
|
1233
|
+
const buildTokenMatch = jsSource.match(/__EXTENSIONJS_REINJECT_BUILD_TOKEN\s*=\s*"([^"]+)"/);
|
|
1234
|
+
const proofMatch = jsSource.match(/extjs-chromium-live-content-css-modules:script-primary-\d+/) || jsSource.match(/Live Update Proof [A-Za-z0-9_-]+/);
|
|
1235
|
+
return {
|
|
1236
|
+
index: rule.index,
|
|
1237
|
+
world: rule.world,
|
|
1238
|
+
matches: [
|
|
1239
|
+
...rule.matches
|
|
1240
|
+
],
|
|
1241
|
+
urls: Array.from(matchingUrlsByRule.get(rule.index) || []).sort(),
|
|
1242
|
+
jsFile,
|
|
1243
|
+
cssFile,
|
|
1244
|
+
buildToken: buildTokenMatch?.[1] || null,
|
|
1245
|
+
proofMarker: proofMatch?.[0] || null
|
|
1246
|
+
};
|
|
1247
|
+
}).filter((entry)=>!!entry && entry.urls.length > 0);
|
|
1248
|
+
if (0 === payload.length) {
|
|
1249
|
+
this.lastRuntimeReinjectionReport = {
|
|
1250
|
+
phase: 'skipped',
|
|
1251
|
+
reason: 'no_payload',
|
|
1252
|
+
ruleCount: rules.length
|
|
1253
|
+
};
|
|
1254
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log('[CDP] extension-runtime reinjection skipped: no payload');
|
|
1255
|
+
return 0;
|
|
1256
|
+
}
|
|
1257
|
+
const runtimeTarget = await this.attachToExtensionRuntimeTarget();
|
|
1258
|
+
if (!runtimeTarget) {
|
|
1259
|
+
const targetSummary = (targets || []).map((target)=>({
|
|
1260
|
+
type: String(target?.type || ''),
|
|
1261
|
+
url: String(target?.url || '')
|
|
1262
|
+
})).filter((entry)=>entry.type || entry.url);
|
|
1263
|
+
this.lastRuntimeReinjectionReport = {
|
|
1264
|
+
phase: 'unavailable',
|
|
1265
|
+
reason: 'no_runtime_target',
|
|
1266
|
+
extensionId: this.extensionId,
|
|
1267
|
+
targets: targetSummary
|
|
1268
|
+
};
|
|
1269
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] extension-runtime reinjection unavailable: ${JSON.stringify({
|
|
1270
|
+
extensionId: this.extensionId,
|
|
1271
|
+
targets: targetSummary
|
|
1272
|
+
})}`);
|
|
1273
|
+
return 0;
|
|
1274
|
+
}
|
|
1275
|
+
const result = await this.cdp.evaluate(runtimeTarget.sessionId, `(() => (async () => {
|
|
1276
|
+
const payload = ${JSON.stringify(payload)};
|
|
1277
|
+
const chromeRuntime =
|
|
1278
|
+
typeof globalThis === 'object' && globalThis && globalThis.chrome
|
|
1279
|
+
? globalThis.chrome
|
|
1280
|
+
: null;
|
|
1281
|
+
const runtimeChrome =
|
|
1282
|
+
chromeRuntime &&
|
|
1283
|
+
chromeRuntime.scripting &&
|
|
1284
|
+
chromeRuntime.tabs
|
|
1285
|
+
? chromeRuntime
|
|
1286
|
+
: null;
|
|
1287
|
+
if (!runtimeChrome) {
|
|
1288
|
+
return {
|
|
1289
|
+
reinjectedTabs: 0,
|
|
1290
|
+
hasRuntime: false,
|
|
1291
|
+
hasChrome: !!chromeRuntime,
|
|
1292
|
+
hasScripting: !!(chromeRuntime && chromeRuntime.scripting),
|
|
1293
|
+
hasTabs: !!(chromeRuntime && chromeRuntime.tabs),
|
|
1294
|
+
entries: payload.length,
|
|
1295
|
+
matches: []
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
let reinjectedTabs = 0;
|
|
1299
|
+
const matches = [];
|
|
1300
|
+
for (const entry of payload) {
|
|
1301
|
+
const queriedTabs = await runtimeChrome.tabs.query(
|
|
1302
|
+
entry.matches.length > 0 ? { url: entry.matches } : {}
|
|
1303
|
+
);
|
|
1304
|
+
const matchingTabs = queriedTabs.filter((tab) => {
|
|
1305
|
+
if (!tab || typeof tab.id !== 'number') return false;
|
|
1306
|
+
if (typeof tab.url !== 'string' || !tab.url) return true;
|
|
1307
|
+
return entry.urls.length === 0 || entry.urls.includes(tab.url);
|
|
1308
|
+
});
|
|
1309
|
+
matches.push({
|
|
1310
|
+
index: entry.index,
|
|
1311
|
+
queriedTabs: queriedTabs.length,
|
|
1312
|
+
matchingTabs: matchingTabs.length
|
|
1313
|
+
});
|
|
1314
|
+
for (const tab of matchingTabs) {
|
|
1315
|
+
const target = { tabId: tab.id, allFrames: false };
|
|
1316
|
+
if (entry.cssFile) {
|
|
1317
|
+
try {
|
|
1318
|
+
await runtimeChrome.scripting.insertCSS({
|
|
1319
|
+
target,
|
|
1320
|
+
files: [entry.cssFile]
|
|
1321
|
+
});
|
|
1322
|
+
} catch (error) {}
|
|
1323
|
+
}
|
|
1324
|
+
await runtimeChrome.scripting.executeScript({
|
|
1325
|
+
target,
|
|
1326
|
+
files: [entry.jsFile],
|
|
1327
|
+
world: entry.world === 'main' ? 'MAIN' : 'ISOLATED'
|
|
1328
|
+
});
|
|
1329
|
+
reinjectedTabs += 1;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
return {
|
|
1333
|
+
reinjectedTabs,
|
|
1334
|
+
hasRuntime: true,
|
|
1335
|
+
entries: payload.length,
|
|
1336
|
+
matches
|
|
1337
|
+
};
|
|
1338
|
+
})())()`, {
|
|
1339
|
+
awaitPromise: true
|
|
1340
|
+
});
|
|
1341
|
+
this.lastRuntimeReinjectionReport = {
|
|
1342
|
+
phase: 'evaluated',
|
|
1343
|
+
targetType: runtimeTarget.targetType,
|
|
1344
|
+
targetUrl: runtimeTarget.targetUrl,
|
|
1345
|
+
result: result && 'object' == typeof result ? JSON.parse(JSON.stringify(result)) : result
|
|
1346
|
+
};
|
|
1347
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] extension-runtime reinjection result: ${JSON.stringify({
|
|
1348
|
+
targetType: runtimeTarget.targetType,
|
|
1349
|
+
targetUrl: runtimeTarget.targetUrl,
|
|
1350
|
+
result
|
|
1351
|
+
})}`);
|
|
1352
|
+
if ('number' == typeof result) return result;
|
|
1353
|
+
if (result && 'object' == typeof result) {
|
|
1354
|
+
const reinjectedTabs = Number(result.reinjectedTabs);
|
|
1355
|
+
return Number.isFinite(reinjectedTabs) ? reinjectedTabs : 0;
|
|
1356
|
+
}
|
|
1357
|
+
return 0;
|
|
1358
|
+
}
|
|
1359
|
+
async reloadPageTarget(sessionId) {
|
|
1360
|
+
if (!this.cdp) return false;
|
|
1361
|
+
try {
|
|
1362
|
+
await this.cdp.sendCommand('Page.reload', {
|
|
1363
|
+
ignoreCache: true
|
|
1364
|
+
}, sessionId);
|
|
1365
|
+
return true;
|
|
1366
|
+
} catch {
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async hardReload() {
|
|
1371
|
+
if (!this.extensionId) return false;
|
|
1372
|
+
try {
|
|
1373
|
+
if (!this.cdp) await this.connectFreshClient();
|
|
1374
|
+
if (this.cdp && await this.cdp.forceReloadExtension(this.extensionId)) return true;
|
|
1375
|
+
} catch {}
|
|
1376
|
+
try {
|
|
1377
|
+
await this.reconnectForReload();
|
|
1378
|
+
return Boolean(this.cdp && this.extensionId && await this.cdp.forceReloadExtension(this.extensionId));
|
|
1379
|
+
} catch {
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
async attachToExtensionRuntimeTarget() {
|
|
1384
|
+
if (!this.cdp) return;
|
|
1385
|
+
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(10, 150);
|
|
1386
|
+
if (!this.extensionId) return;
|
|
1387
|
+
const extensionOrigin = `chrome-extension://${this.extensionId}/`;
|
|
1388
|
+
for(let attempt = 0; attempt < 20; attempt++){
|
|
1389
|
+
const targets = await this.cdp.getTargets();
|
|
1390
|
+
const runtimeTargets = (targets || []).filter((target)=>{
|
|
1391
|
+
const targetType = String(target?.type || '');
|
|
1392
|
+
const targetId = String(target?.targetId || '');
|
|
1393
|
+
return ('service_worker' === targetType || 'background_page' === targetType || 'worker' === targetType) && !!targetId;
|
|
1394
|
+
});
|
|
1395
|
+
const runtimeTarget = runtimeTargets.find((target)=>String(target?.url || '').startsWith(extensionOrigin)) || runtimeTargets.find((target)=>String(target?.url || '').startsWith('chrome-extension://'));
|
|
1396
|
+
if (runtimeTarget) try {
|
|
1397
|
+
const sessionId = await this.cdp.attachToTarget(String(runtimeTarget.targetId));
|
|
1398
|
+
await this.cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
1399
|
+
return {
|
|
1400
|
+
sessionId,
|
|
1401
|
+
targetType: String(runtimeTarget?.type || ''),
|
|
1402
|
+
targetUrl: String(runtimeTarget?.url || '')
|
|
1403
|
+
};
|
|
1404
|
+
} catch {}
|
|
1405
|
+
this.extensionId = await this.deriveExtensionIdFromTargets(4, 100) || this.extensionId;
|
|
1406
|
+
await new Promise((resolve)=>setTimeout(resolve, 250));
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
async connectFreshClient() {
|
|
1410
|
+
this.cdp = await connectToChromeCdp(this.cdpPort);
|
|
1411
|
+
try {
|
|
1412
|
+
await this.cdp.sendCommand('Target.setDiscoverTargets', {
|
|
1413
|
+
discover: true
|
|
1414
|
+
});
|
|
1415
|
+
await this.cdp.sendCommand('Target.setAutoAttach', {
|
|
1416
|
+
autoAttach: true,
|
|
1417
|
+
waitForDebuggerOnStart: false,
|
|
1418
|
+
flatten: true
|
|
1419
|
+
});
|
|
1420
|
+
} catch (error) {
|
|
1421
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(messages.wXK(String(error?.message || error)));
|
|
1422
|
+
}
|
|
1423
|
+
registerAutoEnableLogging(this.cdp, ()=>this.extensionId);
|
|
1424
|
+
}
|
|
1425
|
+
async reconnectForReload() {
|
|
1426
|
+
try {
|
|
1427
|
+
this.cdp?.disconnect?.();
|
|
1428
|
+
} catch {}
|
|
1429
|
+
this.cdp = null;
|
|
1430
|
+
await this.connectFreshClient();
|
|
1431
|
+
try {
|
|
1432
|
+
const derivedExtensionId = await this.deriveExtensionIdFromTargets(10, 150);
|
|
1433
|
+
if (derivedExtensionId) this.extensionId = derivedExtensionId;
|
|
1434
|
+
} catch {}
|
|
1435
|
+
}
|
|
1436
|
+
onProtocolEvent(cb) {
|
|
1437
|
+
if (!this.cdp) throw new Error('CDP not connected');
|
|
1438
|
+
this.cdp.onProtocolEvent((raw)=>{
|
|
1439
|
+
const evt = raw;
|
|
1440
|
+
cb(evt);
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
clearProtocolEventHandler() {
|
|
1444
|
+
if (!this.cdp) return;
|
|
1445
|
+
}
|
|
1446
|
+
async enableUnifiedLogging() {
|
|
1447
|
+
if (!this.cdp) return;
|
|
1448
|
+
try {
|
|
1449
|
+
await this.cdp.enableAutoAttach();
|
|
1450
|
+
await this.cdp.enableRuntimeAndLog();
|
|
1451
|
+
try {
|
|
1452
|
+
const targets = await this.cdp.getTargets();
|
|
1453
|
+
for (const t of targets || []){
|
|
1454
|
+
const type = String(t?.type || '');
|
|
1455
|
+
if ('page' === type || 'service_worker' === type || 'background_page' === type || 'worker' === type) {
|
|
1456
|
+
const targetId = String(t?.targetId || '');
|
|
1457
|
+
if (!targetId) continue;
|
|
1458
|
+
const sessionId = await this.cdp.attachToTarget(targetId);
|
|
1459
|
+
await this.cdp.enableRuntimeAndLog(sessionId);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
} catch {}
|
|
1463
|
+
} catch {}
|
|
1464
|
+
}
|
|
1465
|
+
async enableRuntimeForSession(sessionId) {
|
|
1466
|
+
if (!this.cdp) return;
|
|
1467
|
+
try {
|
|
1468
|
+
await this.cdp.enableRuntimeAndLog(sessionId);
|
|
1469
|
+
} catch {}
|
|
1470
|
+
}
|
|
1471
|
+
async enableLogging() {
|
|
1472
|
+
if (!this.cdp) return;
|
|
1473
|
+
try {
|
|
1474
|
+
const extId = this.extensionId;
|
|
1475
|
+
this.onProtocolEvent(async (message)=>{
|
|
1476
|
+
try {
|
|
1477
|
+
if (!message || !message.method) return;
|
|
1478
|
+
if ('Target.attachedToTarget' === message.method) {
|
|
1479
|
+
const params = message.params || {};
|
|
1480
|
+
const targetInfo = params.targetInfo || {
|
|
1481
|
+
url: '',
|
|
1482
|
+
type: ''
|
|
1483
|
+
};
|
|
1484
|
+
const sessionId = params.sessionId;
|
|
1485
|
+
const url = String(targetInfo.url || '');
|
|
1486
|
+
const type = String(targetInfo.type || '');
|
|
1487
|
+
const matchesExtension = !!(this.extensionId && url.includes(`chrome-extension://${this.extensionId}/`) || extId && url.includes(`chrome-extension://${extId}/`) || 'service_worker' === type);
|
|
1488
|
+
if (sessionId && matchesExtension) {
|
|
1489
|
+
await this.cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
1490
|
+
await this.cdp.sendCommand('Log.enable', {}, sessionId);
|
|
1491
|
+
}
|
|
1492
|
+
} else if ('Runtime.consoleAPICalled' === message.method || 'Log.entryAdded' === message.method) {
|
|
1493
|
+
if ('1' === String(process.env.EXTENSION_VERBOSE || '').trim()) {
|
|
1494
|
+
const ts = new Date().toISOString();
|
|
1495
|
+
console.log(messages.bvI(ts, message.params));
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
} catch {}
|
|
1499
|
+
});
|
|
1500
|
+
} catch (e) {
|
|
1501
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn('[CDP] enableLogging failed:', String(e));
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
async getInfoBestEffort() {
|
|
1505
|
+
try {
|
|
1506
|
+
if (!this.cdp) return null;
|
|
1507
|
+
if (!this.extensionId) this.extensionId = await this.deriveExtensionIdFromTargets(6, 150);
|
|
1508
|
+
if (this.extensionId) {
|
|
1509
|
+
const belongsToOutPath = this.extensionIdBelongsToOutPath(this.extensionId);
|
|
1510
|
+
if (false === belongsToOutPath) this.extensionId = await this.deriveExtensionIdFromTargets(10, 150);
|
|
1511
|
+
}
|
|
1512
|
+
if (!this.extensionId) return null;
|
|
1513
|
+
let name;
|
|
1514
|
+
let version;
|
|
1515
|
+
try {
|
|
1516
|
+
const info = await this.cdp.getExtensionInfo(this.extensionId);
|
|
1517
|
+
name = info?.extensionInfo?.name;
|
|
1518
|
+
version = info?.extensionInfo?.version;
|
|
1519
|
+
} catch {
|
|
1520
|
+
try {
|
|
1521
|
+
const manifest = JSON.parse(external_fs_.readFileSync(external_path_.join(this.outPath, 'manifest.json'), 'utf-8'));
|
|
1522
|
+
name = manifest?.name;
|
|
1523
|
+
version = manifest?.version;
|
|
1524
|
+
} catch {}
|
|
1525
|
+
}
|
|
1526
|
+
return {
|
|
1527
|
+
extensionId: this.extensionId,
|
|
1528
|
+
name,
|
|
1529
|
+
version
|
|
1530
|
+
};
|
|
1531
|
+
} catch (error) {
|
|
1532
|
+
return null;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
async reinjectContentScriptRule(sessionId, rule, allowCoarseCleanup, sourceOverridesByBundleId) {
|
|
1536
|
+
if (!this.cdp) return false;
|
|
1537
|
+
const bundleId = (0, content_script_contracts.Y)(rule.index);
|
|
1538
|
+
const bundlePath = (0, content_script_targets.nG)(this.outPath, rule.index, 'js');
|
|
1539
|
+
if (!bundlePath || !external_fs_.existsSync(bundlePath)) return false;
|
|
1540
|
+
const sourceOverride = sourceOverridesByBundleId && 'object' == typeof sourceOverridesByBundleId ? sourceOverridesByBundleId[bundleId] : void 0;
|
|
1541
|
+
const source = this.patchReinjectSourceForInvalidatedRuntime('string' == typeof sourceOverride ? sourceOverride : external_fs_.readFileSync(bundlePath, 'utf-8'));
|
|
1542
|
+
const buildTokenMatch = source.match(/__EXTENSIONJS_REINJECT_BUILD_TOKEN\s*=\s*"([^"]+)"/);
|
|
1543
|
+
const proofMatch = source.match(/extjs-chromium-live-content-css-modules:script-primary-\d+/) || source.match(/Live Update Proof [A-Za-z0-9_-]+/);
|
|
1544
|
+
if (!source.trim()) return false;
|
|
1545
|
+
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}`);
|
|
1546
|
+
const contextId = await this.resolveExecutionContextId(sessionId, rule);
|
|
1547
|
+
if (!contextId) {
|
|
1548
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(`[CDP] No execution context found for ${bundleId} (${rule.world})`);
|
|
1549
|
+
return false;
|
|
1550
|
+
}
|
|
1551
|
+
const result = await this.cdp.evaluateInContext(sessionId, this.buildReinjectExpression(bundleId, source, allowCoarseCleanup), contextId);
|
|
1552
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(`[CDP] reinject result ${bundleId}: ${JSON.stringify(result)}`);
|
|
1553
|
+
if (result && 'object' == typeof result && 'ok' in result) return false !== result.ok;
|
|
1554
|
+
return true;
|
|
1555
|
+
}
|
|
1556
|
+
buildReinjectExpression(bundleId, source, allowCoarseCleanup) {
|
|
1557
|
+
const annotatedSource = `${source}\n//# sourceURL=extension.js-reinject://${bundleId}.js`;
|
|
1558
|
+
const extensionBase = this.extensionId ? `chrome-extension://${this.extensionId}/` : '';
|
|
1559
|
+
return `(() => {
|
|
1560
|
+
const bundleId = ${JSON.stringify(bundleId)};
|
|
1561
|
+
const source = ${JSON.stringify(annotatedSource)};
|
|
1562
|
+
const extensionBase = ${JSON.stringify(extensionBase)};
|
|
1563
|
+
const rootSelector = '[data-extension-root], #extension-root';
|
|
1564
|
+
const keyedSelector = '[data-extjs-reinject-key="${bundleId}"]';
|
|
1565
|
+
const registry = (typeof globalThis === 'object' && globalThis)
|
|
1566
|
+
? (globalThis.__EXTENSIONJS_DEV_REINJECT__ || (globalThis.__EXTENSIONJS_DEV_REINJECT__ = {}))
|
|
1567
|
+
: {};
|
|
1568
|
+
const existing = registry[bundleId];
|
|
1569
|
+
const readGeneration = (entry) => {
|
|
1570
|
+
try {
|
|
1571
|
+
if (!entry) return 0;
|
|
1572
|
+
if (typeof entry === 'function' && typeof entry.__extjsGeneration === 'number') {
|
|
1573
|
+
return entry.__extjsGeneration;
|
|
1574
|
+
}
|
|
1575
|
+
if (typeof entry === 'object') {
|
|
1576
|
+
if (typeof entry.__extjsGeneration === 'number') return entry.__extjsGeneration;
|
|
1577
|
+
if (typeof entry.generation === 'number') return entry.generation;
|
|
1578
|
+
if (typeof entry.cleanup === 'function' && typeof entry.cleanup.__extjsGeneration === 'number') {
|
|
1579
|
+
return entry.cleanup.__extjsGeneration;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
} catch (error) {}
|
|
1583
|
+
return 0;
|
|
1584
|
+
};
|
|
1585
|
+
const previousGeneration = readGeneration(existing);
|
|
1586
|
+
try {
|
|
1587
|
+
if (typeof existing === 'function') existing();
|
|
1588
|
+
if (existing && typeof existing.cleanup === 'function') existing.cleanup();
|
|
1589
|
+
} catch (error) {}
|
|
1590
|
+
if (${allowCoarseCleanup ? 'true' : 'false'}) {
|
|
1591
|
+
try {
|
|
1592
|
+
const staleRoots = Array.from(document.querySelectorAll(rootSelector));
|
|
1593
|
+
for (const root of staleRoots) {
|
|
1594
|
+
if (root && typeof root.remove === 'function') root.remove();
|
|
1595
|
+
}
|
|
1596
|
+
} catch (error) {}
|
|
1597
|
+
}
|
|
1598
|
+
const trackedNodes = new Set();
|
|
1599
|
+
const trackNode = (node) => {
|
|
1600
|
+
try {
|
|
1601
|
+
if (!node || typeof Element !== 'function' || !(node instanceof Element)) return;
|
|
1602
|
+
const matchesRoot = typeof node.matches === 'function' && node.matches(rootSelector);
|
|
1603
|
+
if (!matchesRoot) return;
|
|
1604
|
+
trackedNodes.add(node);
|
|
1605
|
+
if (typeof node.setAttribute === 'function') {
|
|
1606
|
+
node.setAttribute('data-extjs-reinject-key', bundleId);
|
|
1607
|
+
}
|
|
1608
|
+
} catch (error) {}
|
|
1609
|
+
};
|
|
1610
|
+
const trackTree = (node) => {
|
|
1611
|
+
trackNode(node);
|
|
1612
|
+
try {
|
|
1613
|
+
if (!node || typeof node.querySelectorAll !== 'function') return;
|
|
1614
|
+
const nested = node.querySelectorAll(rootSelector);
|
|
1615
|
+
for (const nestedNode of nested) trackNode(nestedNode);
|
|
1616
|
+
} catch (error) {}
|
|
1617
|
+
};
|
|
1618
|
+
const observer = typeof MutationObserver === 'function'
|
|
1619
|
+
? new MutationObserver((mutations) => {
|
|
1620
|
+
for (const mutation of mutations) {
|
|
1621
|
+
const addedNodes = Array.from(mutation.addedNodes || []);
|
|
1622
|
+
for (const addedNode of addedNodes) {
|
|
1623
|
+
trackTree(addedNode);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
})
|
|
1627
|
+
: null;
|
|
1628
|
+
try {
|
|
1629
|
+
if (observer && document && document.documentElement) {
|
|
1630
|
+
observer.observe(document.documentElement, {childList: true, subtree: true});
|
|
1631
|
+
}
|
|
1632
|
+
} catch (error) {}
|
|
1633
|
+
const cleanupTrackedNodes = () => {
|
|
1634
|
+
try {
|
|
1635
|
+
if (observer) observer.disconnect();
|
|
1636
|
+
} catch (error) {}
|
|
1637
|
+
try {
|
|
1638
|
+
const keyedNodes = Array.from(document.querySelectorAll(keyedSelector));
|
|
1639
|
+
for (const keyedNode of keyedNodes) {
|
|
1640
|
+
if (keyedNode && typeof keyedNode.remove === 'function') keyedNode.remove();
|
|
1641
|
+
}
|
|
1642
|
+
} catch (error) {}
|
|
1643
|
+
try {
|
|
1644
|
+
for (const trackedNode of trackedNodes) {
|
|
1645
|
+
if (trackedNode && trackedNode.isConnected && typeof trackedNode.remove === 'function') {
|
|
1646
|
+
trackedNode.remove();
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
} catch (error) {}
|
|
1650
|
+
};
|
|
1651
|
+
registry[bundleId] = {
|
|
1652
|
+
cleanup: cleanupTrackedNodes,
|
|
1653
|
+
generation: previousGeneration,
|
|
1654
|
+
__extjsGeneration: previousGeneration
|
|
1655
|
+
};
|
|
1656
|
+
try {
|
|
1657
|
+
if (typeof globalThis === 'object' && globalThis && extensionBase) {
|
|
1658
|
+
globalThis.__EXTJS_EXTENSION_BASE__ = extensionBase;
|
|
1659
|
+
}
|
|
1660
|
+
if (typeof document === 'object' && document && document.documentElement && extensionBase) {
|
|
1661
|
+
document.documentElement.setAttribute('data-extjs-extension-base', extensionBase);
|
|
1662
|
+
}
|
|
1663
|
+
(0, eval)(source);
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
return {
|
|
1666
|
+
ok: false,
|
|
1667
|
+
error: String((error && error.stack) || (error && error.message) || error || 'unknown'),
|
|
1668
|
+
trackedRoots: trackedNodes.size,
|
|
1669
|
+
existingRootCount: (() => {
|
|
1670
|
+
try { return document.querySelectorAll(rootSelector).length; } catch (innerError) { return -1; }
|
|
1671
|
+
})()
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
setTimeout(() => {
|
|
1675
|
+
try {
|
|
1676
|
+
const keyedNodes = Array.from(document.querySelectorAll(keyedSelector));
|
|
1677
|
+
for (const keyedNode of keyedNodes) trackedNodes.add(keyedNode);
|
|
1678
|
+
} catch (error) {}
|
|
1679
|
+
}, 0);
|
|
1680
|
+
setTimeout(() => {
|
|
1681
|
+
try {
|
|
1682
|
+
if (observer) observer.disconnect();
|
|
1683
|
+
} catch (error) {}
|
|
1684
|
+
}, 2000);
|
|
1685
|
+
return {
|
|
1686
|
+
ok: true,
|
|
1687
|
+
trackedRoots: trackedNodes.size,
|
|
1688
|
+
existingRootCount: (() => {
|
|
1689
|
+
try { return document.querySelectorAll(rootSelector).length; } catch (innerError) { return -1; }
|
|
1690
|
+
})(),
|
|
1691
|
+
liveRoots: (() => {
|
|
1692
|
+
try {
|
|
1693
|
+
return Array.from(document.querySelectorAll(rootSelector)).map((node) => ({
|
|
1694
|
+
key: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extjs-reinject-key') || null : null,
|
|
1695
|
+
root: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extension-root') || null : null,
|
|
1696
|
+
build: node && typeof node.getAttribute === 'function' ? node.getAttribute('data-extjs-reinject-build') || null : null,
|
|
1697
|
+
text: String(node && node.textContent || '').slice(0, 120)
|
|
1698
|
+
}));
|
|
1699
|
+
} catch (error) {
|
|
1700
|
+
return [];
|
|
1701
|
+
}
|
|
1702
|
+
})(),
|
|
1703
|
+
hasChromeRuntime: (() => {
|
|
1704
|
+
try { return !!(globalThis && globalThis.chrome && globalThis.chrome.runtime); } catch (error) { return false; }
|
|
1705
|
+
})()
|
|
1706
|
+
};
|
|
1707
|
+
})()`;
|
|
1708
|
+
}
|
|
1709
|
+
patchReinjectSourceForInvalidatedRuntime(source) {
|
|
1710
|
+
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}');
|
|
1711
|
+
}
|
|
1712
|
+
async resolveExecutionContextId(sessionId, rule) {
|
|
1713
|
+
if (!this.cdp) return;
|
|
1714
|
+
const frameId = await this.getTopFrameId(sessionId);
|
|
1715
|
+
const contexts = await this.collectExecutionContexts(sessionId);
|
|
1716
|
+
if ('main' === rule.world) {
|
|
1717
|
+
const defaultContext = contexts.find((context)=>{
|
|
1718
|
+
const auxData = context?.auxData || {};
|
|
1719
|
+
return 'default' === auxData.type && true === auxData.isDefault && (!frameId || !auxData.frameId || String(auxData.frameId) === frameId);
|
|
1720
|
+
});
|
|
1721
|
+
return 'number' == typeof defaultContext?.id ? defaultContext.id : void 0;
|
|
1722
|
+
}
|
|
1723
|
+
const extensionId = this.extensionId || await this.deriveExtensionIdFromTargets();
|
|
1724
|
+
if (!extensionId) return;
|
|
1725
|
+
const extensionOrigin = `chrome-extension://${extensionId}`;
|
|
1726
|
+
const isolatedContext = contexts.find((context)=>{
|
|
1727
|
+
const auxData = context?.auxData || {};
|
|
1728
|
+
return 'isolated' === auxData.type && String(context?.origin || '') === extensionOrigin && (!frameId || !auxData.frameId || String(auxData.frameId) === frameId);
|
|
1729
|
+
});
|
|
1730
|
+
return 'number' == typeof isolatedContext?.id ? isolatedContext.id : void 0;
|
|
1731
|
+
}
|
|
1732
|
+
async getTopFrameId(sessionId) {
|
|
1733
|
+
if (!this.cdp) return;
|
|
1734
|
+
try {
|
|
1735
|
+
const frameTree = await this.cdp.sendCommand('Page.getFrameTree', {}, sessionId);
|
|
1736
|
+
const frameId = frameTree?.frameTree?.frame?.id;
|
|
1737
|
+
return 'string' == typeof frameId && frameId ? frameId : void 0;
|
|
1738
|
+
} catch {
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
async collectExecutionContexts(sessionId) {
|
|
1743
|
+
if (!this.cdp) return [];
|
|
1744
|
+
const contextsById = new Map();
|
|
1745
|
+
const unsubscribe = this.cdp.onProtocolEvent((message)=>{
|
|
1746
|
+
if (String(message.sessionId || '') !== sessionId) return;
|
|
1747
|
+
if ('Runtime.executionContextCreated' !== String(message.method || '')) return;
|
|
1748
|
+
const context = message.params?.context;
|
|
1749
|
+
const contextId = context?.id;
|
|
1750
|
+
if ('number' == typeof contextId) contextsById.set(contextId, context);
|
|
1751
|
+
});
|
|
1752
|
+
try {
|
|
1753
|
+
await this.cdp.sendCommand('Runtime.enable', {}, sessionId);
|
|
1754
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
1755
|
+
} finally{
|
|
1756
|
+
unsubscribe();
|
|
1757
|
+
}
|
|
1758
|
+
return Array.from(contextsById.values());
|
|
1759
|
+
}
|
|
1760
|
+
constructor(args){
|
|
1761
|
+
cdp_extension_controller_define_property(this, "outPath", void 0);
|
|
1762
|
+
cdp_extension_controller_define_property(this, "browser", void 0);
|
|
1763
|
+
cdp_extension_controller_define_property(this, "cdpPort", void 0);
|
|
1764
|
+
cdp_extension_controller_define_property(this, "profilePath", void 0);
|
|
1765
|
+
cdp_extension_controller_define_property(this, "extensionPaths", void 0);
|
|
1766
|
+
cdp_extension_controller_define_property(this, "cdp", null);
|
|
1767
|
+
cdp_extension_controller_define_property(this, "extensionId", null);
|
|
1768
|
+
cdp_extension_controller_define_property(this, "lastRuntimeReinjectionReport", null);
|
|
1769
|
+
this.outPath = args.outPath;
|
|
1770
|
+
this.browser = args.browser;
|
|
1771
|
+
this.cdpPort = args.cdpPort;
|
|
1772
|
+
this.profilePath = args.profilePath;
|
|
1773
|
+
this.extensionPaths = args.extensionPaths;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
var extension_output_path = __webpack_require__("./browsers/run-chromium/chromium-launch/extension-output-path.ts");
|
|
1777
|
+
async function setupCdpAfterLaunch(compilation, plugin, chromiumArgs) {
|
|
1778
|
+
const loadExtensionFlag = chromiumArgs.find((flag)=>flag.startsWith('--load-extension='));
|
|
1779
|
+
const extensionOutputPath = (0, extension_output_path.W)(compilation, loadExtensionFlag);
|
|
1780
|
+
const extensionPaths = loadExtensionFlag ? loadExtensionFlag.replace('--load-extension=', '').split(',').map((s)=>s.trim()).filter(Boolean) : [];
|
|
1781
|
+
const selectedExtensionPaths = extensionOutputPath && extensionOutputPath.length > 0 ? [
|
|
1782
|
+
extensionOutputPath
|
|
1783
|
+
] : extensionPaths;
|
|
1784
|
+
const remoteDebugPortFlag = chromiumArgs.find((flag)=>flag.startsWith('--remote-debugging-port='));
|
|
1785
|
+
const chromeRemoteDebugPort = remoteDebugPortFlag ? parseInt(remoteDebugPortFlag.split('=')[1], 10) : (0, shared_utils.jl)(plugin.port, plugin.instanceId);
|
|
1786
|
+
const userDataDirFlag = chromiumArgs.find((flag)=>flag.startsWith('--user-data-dir='));
|
|
1787
|
+
const userDataDir = userDataDirFlag ? userDataDirFlag.replace('--user-data-dir=', '').replace(/^"|"$/g, '') : '';
|
|
1788
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) {
|
|
1789
|
+
if (userDataDir) console.log(messages.aIt(userDataDir));
|
|
1790
|
+
console.log(messages.CYH(chromeRemoteDebugPort, chromeRemoteDebugPort));
|
|
1791
|
+
}
|
|
1792
|
+
const cdpExtensionController = new CDPExtensionController({
|
|
1793
|
+
outPath: extensionOutputPath,
|
|
1794
|
+
browser: 'chromium-based' === plugin.browser ? 'chrome' : plugin.browser,
|
|
1795
|
+
cdpPort: chromeRemoteDebugPort,
|
|
1796
|
+
profilePath: userDataDir || void 0,
|
|
1797
|
+
extensionPaths: selectedExtensionPaths
|
|
1798
|
+
});
|
|
1799
|
+
await cdpExtensionController.connect();
|
|
1800
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.log(messages.M3V('127.0.0.1', chromeRemoteDebugPort));
|
|
1801
|
+
const mode = compilation?.options?.mode || 'development';
|
|
1802
|
+
let earlyBannerPrinted = false;
|
|
1803
|
+
if ('development' === mode) try {
|
|
1804
|
+
earlyBannerPrinted = await (0, banner.ai)({
|
|
1805
|
+
outPath: extensionOutputPath,
|
|
1806
|
+
browser: plugin.browser,
|
|
1807
|
+
hostPort: {
|
|
1808
|
+
host: '127.0.0.1',
|
|
1809
|
+
port: chromeRemoteDebugPort
|
|
1810
|
+
},
|
|
1811
|
+
getInfo: async ()=>null,
|
|
1812
|
+
browserVersionLine: plugin.browserVersionLine
|
|
1813
|
+
});
|
|
1814
|
+
} catch {}
|
|
1815
|
+
if ('development' === mode) try {
|
|
1816
|
+
earlyBannerPrinted = await (0, banner.ai)({
|
|
1817
|
+
outPath: extensionOutputPath,
|
|
1818
|
+
browser: plugin.browser,
|
|
1819
|
+
hostPort: {
|
|
1820
|
+
host: '127.0.0.1',
|
|
1821
|
+
port: chromeRemoteDebugPort
|
|
1822
|
+
},
|
|
1823
|
+
getInfo: async ()=>cdpExtensionController.getInfoBestEffort(),
|
|
1824
|
+
browserVersionLine: plugin.browserVersionLine
|
|
1825
|
+
});
|
|
1826
|
+
} catch {}
|
|
1827
|
+
let extensionControllerInfo = null;
|
|
1828
|
+
try {
|
|
1829
|
+
const ensureLoadedTimeoutMs = 10000;
|
|
1830
|
+
extensionControllerInfo = await Promise.race([
|
|
1831
|
+
cdpExtensionController.ensureLoaded(),
|
|
1832
|
+
new Promise((_, reject)=>{
|
|
1833
|
+
setTimeout(()=>reject(new Error(`ensureLoaded timeout (${ensureLoadedTimeoutMs}ms)`)), ensureLoadedTimeoutMs);
|
|
1834
|
+
})
|
|
1835
|
+
]);
|
|
1836
|
+
} catch (error) {
|
|
1837
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(`[CDP] ensureLoaded failed: ${String(error?.message || error)}`);
|
|
1838
|
+
}
|
|
1839
|
+
try {
|
|
1840
|
+
if ('development' === mode) {
|
|
1841
|
+
if (!earlyBannerPrinted) {
|
|
1842
|
+
const bannerPrinted = await (0, banner.ai)({
|
|
1843
|
+
outPath: extensionOutputPath,
|
|
1844
|
+
browser: plugin.browser,
|
|
1845
|
+
hostPort: {
|
|
1846
|
+
host: '127.0.0.1',
|
|
1847
|
+
port: chromeRemoteDebugPort
|
|
1848
|
+
},
|
|
1849
|
+
getInfo: async ()=>extensionControllerInfo,
|
|
1850
|
+
browserVersionLine: plugin.browserVersionLine
|
|
1851
|
+
});
|
|
1852
|
+
if (!bannerPrinted) await (0, banner.ai)({
|
|
1853
|
+
outPath: extensionOutputPath,
|
|
1854
|
+
browser: plugin.browser,
|
|
1855
|
+
hostPort: {
|
|
1856
|
+
host: '127.0.0.1',
|
|
1857
|
+
port: chromeRemoteDebugPort
|
|
1858
|
+
},
|
|
1859
|
+
getInfo: async ()=>cdpExtensionController.getInfoBestEffort(),
|
|
1860
|
+
browserVersionLine: plugin.browserVersionLine
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
} else if ('production' === mode) {
|
|
1864
|
+
const runtime = extensionControllerInfo ? {
|
|
1865
|
+
extensionId: extensionControllerInfo.extensionId,
|
|
1866
|
+
name: extensionControllerInfo.name,
|
|
1867
|
+
version: extensionControllerInfo.version
|
|
1868
|
+
} : void 0;
|
|
1869
|
+
await (0, banner.MK)({
|
|
1870
|
+
browser: plugin.browser,
|
|
1871
|
+
outPath: extensionOutputPath,
|
|
1872
|
+
browserVersionLine: plugin.browserVersionLine,
|
|
1873
|
+
runtime
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
} catch (bannerErr) {
|
|
1877
|
+
if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.warn(messages.$wD(String(bannerErr)));
|
|
1878
|
+
try {
|
|
1879
|
+
const mode = compilation?.options?.mode || 'development';
|
|
1880
|
+
if ('production' === mode) await (0, banner.MK)({
|
|
1881
|
+
browser: plugin.browser,
|
|
1882
|
+
outPath: extensionOutputPath,
|
|
1883
|
+
browserVersionLine: plugin.browserVersionLine
|
|
1884
|
+
});
|
|
1885
|
+
} catch {}
|
|
1886
|
+
}
|
|
1887
|
+
plugin.cdpController = cdpExtensionController;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
};
|