extension 4.1.12 → 4.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/49.cjs +2 -10
- package/dist/browsers.cjs +355 -111
- package/dist/cli.cjs +1012 -518
- package/dist/extension/browsers/browsers-lib/messages.d.ts +1 -1
- package/dist/extension/browsers/browsers-lib/newtab-override.d.ts +1 -0
- package/dist/extension/browsers/browsers-lib/resolve-profile.d.ts +1 -0
- package/dist/extension/browsers/run-chromium/chromium-launch/browser-config.d.ts +8 -1
- package/dist/extension/browsers/run-chromium/chromium-launch/index.d.ts +1 -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 +9 -0
- package/dist/extension/browsers/run-firefox/firefox-launch/dry-run.d.ts +1 -1
- package/dist/extension/browsers/run-firefox/firefox-launch/index.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/firefox-types.d.ts +1 -1
- package/dist/extension/browsers/run-firefox/rdp/rdp-extension-controller/index.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/index.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/manager-tab.d.ts +10 -0
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/messaging-client.d.ts +1 -0
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/transport.d.ts +3 -1
- package/dist/extension/commands/doctor.d.ts +1 -1
- package/dist/extension/helpers/cli-argv.d.ts +8 -0
- package/dist/extension/helpers/cli-options.d.ts +7 -0
- package/dist/extension/helpers/messages.d.ts +5 -0
- package/dist/extension/helpers/msg-placeholders.d.ts +2 -0
- package/dist/extension/helpers/output-flag.d.ts +6 -0
- package/dist/extension/helpers/session-project-path.d.ts +4 -0
- package/dist/extension/helpers/telemetry-cli.d.ts +1 -0
- package/dist/extension/helpers/template-catalog.d.ts +1 -1
- package/package.json +4 -4
- package/types/assets.d.ts +65 -0
- package/types/index.d.ts +1 -60
package/dist/cli.cjs
CHANGED
|
@@ -642,12 +642,6 @@ var __webpack_modules__ = {
|
|
|
642
642
|
function firefoxLaunchCalled() {
|
|
643
643
|
return `${getLoggingPrefix('debug')} browser launch browser=firefox`;
|
|
644
644
|
}
|
|
645
|
-
function firefoxBinaryArgsExtracted(args) {
|
|
646
|
-
return `${getLoggingPrefix('debug')} browser args="${args}"`;
|
|
647
|
-
}
|
|
648
|
-
function firefoxNoBinaryArgsFound() {
|
|
649
|
-
return `${getLoggingPrefix('debug')} browser args=none`;
|
|
650
|
-
}
|
|
651
645
|
function firefoxFailedToStart(error) {
|
|
652
646
|
return `${getLoggingPrefix('error')} Firefox failed to start.\n${pintor__rspack_import_8_default().red(errorDetail(error))}`;
|
|
653
647
|
}
|
|
@@ -657,8 +651,8 @@ var __webpack_modules__ = {
|
|
|
657
651
|
function firefoxDryRunBinary(path) {
|
|
658
652
|
return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('PATH')} ${pintor__rspack_import_8_default().underline(path)}`;
|
|
659
653
|
}
|
|
660
|
-
function
|
|
661
|
-
return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('
|
|
654
|
+
function firefoxDryRunArgs(args) {
|
|
655
|
+
return `${getLoggingPrefix('info')} ${pintor__rspack_import_8_default().gray('ARGS')} ${pintor__rspack_import_8_default().gray(args)}`;
|
|
662
656
|
}
|
|
663
657
|
function safariBuildCalled() {
|
|
664
658
|
return `${getLoggingPrefix('debug')} browser build browser=safari`;
|
|
@@ -958,7 +952,6 @@ var __webpack_modules__ = {
|
|
|
958
952
|
bv: ()=>cdpUnifiedExtensionLog,
|
|
959
953
|
cD: ()=>targetActorHasActiveRequestError,
|
|
960
954
|
cF: ()=>safariRebuilt,
|
|
961
|
-
dN: ()=>firefoxNoBinaryArgsFound,
|
|
962
955
|
dk: ()=>generalBrowserError,
|
|
963
956
|
dw: ()=>devFirefoxProfilePath,
|
|
964
957
|
e_: ()=>runningInDevelopment,
|
|
@@ -969,14 +962,13 @@ var __webpack_modules__ = {
|
|
|
969
962
|
fw: ()=>safariOpening,
|
|
970
963
|
hE: ()=>cdpClientConnectionClosed,
|
|
971
964
|
io: ()=>emptyLine,
|
|
972
|
-
iv: ()=>firefoxBinaryArgsExtracted,
|
|
973
965
|
jP: ()=>rdpInvalidRequestPayload,
|
|
974
966
|
jR: ()=>safariBuilding,
|
|
975
967
|
jc: ()=>safariProjectStale,
|
|
976
968
|
jk: ()=>requireGeckoBinaryForGeckoBased,
|
|
977
|
-
k6: ()=>firefoxDryRunConfig,
|
|
978
969
|
kK: ()=>preferringSystemBrowserOverSnapshot,
|
|
979
970
|
l9: ()=>parsingPacketError,
|
|
971
|
+
lO: ()=>firefoxDryRunArgs,
|
|
980
972
|
l_: ()=>safariConverted,
|
|
981
973
|
ne: ()=>requireChromiumBinaryForChromiumBased,
|
|
982
974
|
nn: ()=>chromeProcessExited,
|
|
@@ -999,6 +991,22 @@ var __webpack_modules__ = {
|
|
|
999
991
|
yc: ()=>safariDryRunNotBuilding
|
|
1000
992
|
});
|
|
1001
993
|
},
|
|
994
|
+
"./browsers/browsers-lib/newtab-override.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
995
|
+
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
996
|
+
var node_path__rspack_import_1 = __webpack_require__("node:path");
|
|
997
|
+
function manifestDeclaresNewtabOverride(outPath) {
|
|
998
|
+
try {
|
|
999
|
+
const manifest = JSON.parse(node_fs__rspack_import_0.readFileSync(node_path__rspack_import_1.join(outPath, 'manifest.json'), 'utf-8'));
|
|
1000
|
+
const overrides = manifest?.chrome_url_overrides || manifest?.['chromium:chrome_url_overrides'] || manifest?.['chrome:chrome_url_overrides'] || manifest?.['gecko:chrome_url_overrides'] || manifest?.['firefox:chrome_url_overrides'];
|
|
1001
|
+
return Boolean(overrides && 'string' == typeof overrides.newtab && overrides.newtab.trim().length > 0);
|
|
1002
|
+
} catch {
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
1007
|
+
c: ()=>manifestDeclaresNewtabOverride
|
|
1008
|
+
});
|
|
1009
|
+
},
|
|
1002
1010
|
"./browsers/browsers-lib/output-binaries-resolver.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1003
1011
|
var node_fs__rspack_import_0 = __webpack_require__("node:fs");
|
|
1004
1012
|
var node_path__rspack_import_1 = __webpack_require__("node:path");
|
|
@@ -1474,6 +1482,7 @@ var __webpack_modules__ = {
|
|
|
1474
1482
|
}
|
|
1475
1483
|
function resolveProfileConfig(input) {
|
|
1476
1484
|
const { managedBaseDir, useSystemProfile, persistProfile, keepProfileChanges, copyFromProfile, resolveExplicit } = input;
|
|
1485
|
+
const provision = false !== input.provision;
|
|
1477
1486
|
const rawProfile = normalizeProfileOption(input.rawProfile);
|
|
1478
1487
|
if (false === rawProfile || useSystemProfile) return {
|
|
1479
1488
|
kind: 'system',
|
|
@@ -1504,6 +1513,14 @@ var __webpack_modules__ = {
|
|
|
1504
1513
|
profilePath = external_node_path_.join(managedBaseDir, human);
|
|
1505
1514
|
}
|
|
1506
1515
|
const isFreshTarget = !external_node_fs_.existsSync(profilePath) || 0 === external_node_fs_.readdirSync(profilePath).length;
|
|
1516
|
+
if (!provision) return {
|
|
1517
|
+
kind: 'managed',
|
|
1518
|
+
profilePath,
|
|
1519
|
+
persisted,
|
|
1520
|
+
...hasCopyFrom(copyFromProfile) && isFreshTarget ? {
|
|
1521
|
+
seededFrom: copyFromProfile.trim()
|
|
1522
|
+
} : {}
|
|
1523
|
+
};
|
|
1507
1524
|
external_node_fs_.mkdirSync(profilePath, {
|
|
1508
1525
|
recursive: true
|
|
1509
1526
|
});
|
|
@@ -1976,6 +1993,7 @@ var __webpack_modules__ = {
|
|
|
1976
1993
|
preferences: opts.preferences,
|
|
1977
1994
|
browserFlags: opts.browserFlags,
|
|
1978
1995
|
startingUrl: opts.startingUrl,
|
|
1996
|
+
noOpen: opts.noOpen,
|
|
1979
1997
|
geckoBinary: opts.geckoBinary,
|
|
1980
1998
|
instanceId: opts.instanceId,
|
|
1981
1999
|
port: opts.port,
|
|
@@ -2170,6 +2188,38 @@ var __webpack_modules__ = {
|
|
|
2170
2188
|
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
2171
2189
|
var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
|
|
2172
2190
|
var instance_registry = __webpack_require__("./browsers/browsers-lib/instance-registry.ts");
|
|
2191
|
+
const MSG_REFERENCE = /__MSG_([A-Za-z0-9_@]+?)__/g;
|
|
2192
|
+
function collectMsgReferences(value) {
|
|
2193
|
+
const found = [];
|
|
2194
|
+
const seen = new Set();
|
|
2195
|
+
const visit = (node)=>{
|
|
2196
|
+
if ('string' == typeof node) {
|
|
2197
|
+
MSG_REFERENCE.lastIndex = 0;
|
|
2198
|
+
let match = MSG_REFERENCE.exec(node);
|
|
2199
|
+
while(null !== match){
|
|
2200
|
+
const name = match[1];
|
|
2201
|
+
if (name && !name.startsWith('@@') && !seen.has(name)) {
|
|
2202
|
+
seen.add(name);
|
|
2203
|
+
found.push(name);
|
|
2204
|
+
}
|
|
2205
|
+
match = MSG_REFERENCE.exec(node);
|
|
2206
|
+
}
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
if (Array.isArray(node)) {
|
|
2210
|
+
for (const item of node)visit(item);
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
if (node && 'object' == typeof node) for (const item of Object.values(node))visit(item);
|
|
2214
|
+
};
|
|
2215
|
+
visit(value);
|
|
2216
|
+
return found;
|
|
2217
|
+
}
|
|
2218
|
+
function findUndefinedMsgReferences(value, catalogKeys) {
|
|
2219
|
+
const lower = new Set();
|
|
2220
|
+
for (const key of catalogKeys)lower.add(String(key).toLowerCase());
|
|
2221
|
+
return collectMsgReferences(value).filter((name)=>!lower.has(name.toLowerCase()));
|
|
2222
|
+
}
|
|
2173
2223
|
function diagnoseChromiumManifestRefusal(manifest) {
|
|
2174
2224
|
const m = manifest;
|
|
2175
2225
|
if (2 === Number(m?.manifest_version)) return 'mv2';
|
|
@@ -2304,7 +2354,7 @@ var __webpack_modules__ = {
|
|
|
2304
2354
|
if (external_node_fs_.existsSync(catalogPath)) try {
|
|
2305
2355
|
const raw = external_node_fs_.readFileSync(catalogPath, 'utf8').replace(/^\uFEFF/, '');
|
|
2306
2356
|
const catalog = JSON.parse(raw);
|
|
2307
|
-
catalogKeys = new Set(Object.keys(catalog || {})
|
|
2357
|
+
catalogKeys = new Set(Object.keys(catalog || {}));
|
|
2308
2358
|
} catch {
|
|
2309
2359
|
blockers.push(`default_locale: _locales/${defaultLocale}/messages.json is not valid JSON, Chrome refuses the whole extension.`);
|
|
2310
2360
|
}
|
|
@@ -2312,11 +2362,7 @@ var __webpack_modules__ = {
|
|
|
2312
2362
|
} catch {
|
|
2313
2363
|
return blockers;
|
|
2314
2364
|
}
|
|
2315
|
-
if (catalogKeys) {
|
|
2316
|
-
const refs = new Set();
|
|
2317
|
-
collectMsgRefs(m, refs);
|
|
2318
|
-
for (const ref of refs)if (!catalogKeys.has(ref.toLowerCase())) blockers.push(`__MSG_${ref}__: used in the manifest but not defined in _locales/${defaultLocale}/messages.json, Chrome refuses the whole extension.`);
|
|
2319
|
-
}
|
|
2365
|
+
if (catalogKeys) for (const ref of findUndefinedMsgReferences(m, catalogKeys))blockers.push(`__MSG_${ref}__: used in the manifest but not defined in _locales/${defaultLocale}/messages.json, Chrome refuses the whole extension.`);
|
|
2320
2366
|
} else try {
|
|
2321
2367
|
if (external_node_fs_.existsSync(localesDir)) {
|
|
2322
2368
|
const hasCatalog = external_node_fs_.readdirSync(localesDir).some((entry)=>external_node_fs_.existsSync(external_node_path_.join(localesDir, entry, 'messages.json')));
|
|
@@ -2337,13 +2383,6 @@ var __webpack_modules__ = {
|
|
|
2337
2383
|
} catch {}
|
|
2338
2384
|
return [];
|
|
2339
2385
|
}
|
|
2340
|
-
function collectMsgRefs(value, out) {
|
|
2341
|
-
if ('string' == typeof value) {
|
|
2342
|
-
const match = /^__MSG_(.+)__$/.exec(value.trim());
|
|
2343
|
-
if (match && !match[1].startsWith('@@')) out.add(match[1]);
|
|
2344
|
-
} else if (Array.isArray(value)) for (const item of value)collectMsgRefs(item, out);
|
|
2345
|
-
else if (value && 'object' == typeof value) for (const item of Object.values(value))collectMsgRefs(item, out);
|
|
2346
|
-
}
|
|
2347
2386
|
function isValidDottedVersion(version) {
|
|
2348
2387
|
if (!version) return false;
|
|
2349
2388
|
const parts = version.split('.');
|
|
@@ -2524,7 +2563,19 @@ var __webpack_modules__ = {
|
|
|
2524
2563
|
});
|
|
2525
2564
|
external_node_fs_.writeFileSync(preferencesPath, JSON.stringify(mergedPreferences), 'utf8');
|
|
2526
2565
|
}
|
|
2527
|
-
function
|
|
2566
|
+
function chromiumLaunchPlan(binary, chromiumConfig, startingUrl) {
|
|
2567
|
+
return {
|
|
2568
|
+
binary,
|
|
2569
|
+
args: startingUrl ? [
|
|
2570
|
+
...chromiumConfig,
|
|
2571
|
+
startingUrl
|
|
2572
|
+
] : [
|
|
2573
|
+
...chromiumConfig
|
|
2574
|
+
]
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
function browserConfig(compilation, configOptions, mode = {}) {
|
|
2578
|
+
const provision = false !== mode.provision;
|
|
2528
2579
|
const extensionsToLoad = (0, runtime_options.fT)(configOptions.extension);
|
|
2529
2580
|
const devWantsCDP = compilation?.options?.mode === 'development';
|
|
2530
2581
|
const rawProfile = configOptions.profile;
|
|
@@ -2548,17 +2599,18 @@ var __webpack_modules__ = {
|
|
|
2548
2599
|
persistProfile: configOptions.persistProfile,
|
|
2549
2600
|
keepProfileChanges: configOptions.keepProfileChanges,
|
|
2550
2601
|
copyFromProfile: configOptions.copyFromProfile,
|
|
2551
|
-
resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile)
|
|
2602
|
+
resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile),
|
|
2603
|
+
provision
|
|
2552
2604
|
});
|
|
2553
2605
|
const userProfilePath = resolved.profilePath;
|
|
2554
|
-
if ('managed' === resolved.kind) {
|
|
2606
|
+
if ('managed' === resolved.kind && provision) {
|
|
2555
2607
|
if ((0, messaging._o)()) (0, messaging._w)(messages.sY(shownPath(userProfilePath)));
|
|
2556
2608
|
if (!resolved.persisted) try {
|
|
2557
2609
|
const maxAgeHours = parseInt(String(process.env.EXTENSION_TMP_PROFILE_MAX_AGE_HOURS || ''), 10);
|
|
2558
2610
|
(0, shared_utils.CW)(managedBaseDir, external_node_path_.basename(userProfilePath), Number.isFinite(maxAgeHours) ? maxAgeHours : 12);
|
|
2559
2611
|
} catch {}
|
|
2560
2612
|
}
|
|
2561
|
-
if (userProfilePath) {
|
|
2613
|
+
if (userProfilePath && provision) {
|
|
2562
2614
|
external_node_fs_.mkdirSync(userProfilePath, {
|
|
2563
2615
|
recursive: true
|
|
2564
2616
|
});
|
|
@@ -2879,7 +2931,10 @@ var __webpack_modules__ = {
|
|
|
2879
2931
|
process.exit(1);
|
|
2880
2932
|
}
|
|
2881
2933
|
}
|
|
2882
|
-
|
|
2934
|
+
const inTestRunner = Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
|
|
2935
|
+
const dryRun = Boolean(this.options?.dryRun);
|
|
2936
|
+
if (inTestRunner && !dryRun) return void logChromiumDryRun(this.options?.chromiumBinary ? (0, wsl_support.f7)(String(this.options.chromiumBinary)) : 'chromium-mock-binary', []);
|
|
2937
|
+
if (inTestRunner && dryRun && !this.options?.chromiumBinary) return void this.printDryRunPlan(compilation, 'chromium-mock-binary');
|
|
2883
2938
|
const browser = this.options?.browser;
|
|
2884
2939
|
let browserBinaryLocation = null;
|
|
2885
2940
|
let printedGuidance = false;
|
|
@@ -3188,6 +3243,8 @@ var __webpack_modules__ = {
|
|
|
3188
3243
|
instanceId: this.options.instanceId,
|
|
3189
3244
|
extension: extensionsToLoad,
|
|
3190
3245
|
logLevel: this.options.logLevel
|
|
3246
|
+
}, {
|
|
3247
|
+
provision: !dryRun
|
|
3191
3248
|
});
|
|
3192
3249
|
} catch (error) {
|
|
3193
3250
|
if (shared_utils.ci(error)) (0, ready_stamp.iD)((0, extension_output_path.W)(compilation, void 0), {
|
|
@@ -3220,7 +3277,7 @@ var __webpack_modules__ = {
|
|
|
3220
3277
|
enableCdp
|
|
3221
3278
|
});
|
|
3222
3279
|
} catch {}
|
|
3223
|
-
if (
|
|
3280
|
+
if (dryRun) return void this.printDryRunPlan(compilation, browserBinaryLocation, chromiumConfig);
|
|
3224
3281
|
const usePipe = chromiumConfig.includes('--remote-debugging-pipe');
|
|
3225
3282
|
this.closeHandlerContext = {
|
|
3226
3283
|
isDevMode: 'development' === compilation.options.mode,
|
|
@@ -3290,14 +3347,18 @@ var __webpack_modules__ = {
|
|
|
3290
3347
|
reportReady();
|
|
3291
3348
|
}
|
|
3292
3349
|
}
|
|
3350
|
+
printDryRunPlan(compilation, binary, chromiumConfig) {
|
|
3351
|
+
const flags = chromiumConfig ?? browserConfig(compilation, {
|
|
3352
|
+
...this.options
|
|
3353
|
+
}, {
|
|
3354
|
+
provision: false
|
|
3355
|
+
});
|
|
3356
|
+
const plan = chromiumLaunchPlan(binary, flags, this.options?.startingUrl);
|
|
3357
|
+
logChromiumDryRun(plan.binary, plan.args);
|
|
3358
|
+
}
|
|
3293
3359
|
async launchWithDirectSpawn(binary, chromeFlags, usePipe = false) {
|
|
3294
3360
|
if ((0, messaging._o)()) this.logger.info(messages.xy());
|
|
3295
|
-
const launchArgs = this.options?.startingUrl
|
|
3296
|
-
...chromeFlags,
|
|
3297
|
-
this.options.startingUrl
|
|
3298
|
-
] : [
|
|
3299
|
-
...chromeFlags
|
|
3300
|
-
];
|
|
3361
|
+
const { args: launchArgs } = chromiumLaunchPlan(binary, chromeFlags, this.options?.startingUrl);
|
|
3301
3362
|
const stdio = usePipe ? [
|
|
3302
3363
|
'ignore',
|
|
3303
3364
|
'ignore',
|
|
@@ -3570,6 +3631,29 @@ var __webpack_modules__ = {
|
|
|
3570
3631
|
return /^(1|true)$/i.test(String(env.MOZ_HEADLESS || '').trim()) || (0, shared_utils.ZO)(env);
|
|
3571
3632
|
}
|
|
3572
3633
|
class FirefoxBinaryDetector {
|
|
3634
|
+
static launchPlan(input) {
|
|
3635
|
+
if (input.profilePath) return FirefoxBinaryDetector.generateFirefoxArgs(input.binaryPath, input.profilePath, input.debugPort, input.binaryArgs, input.headless);
|
|
3636
|
+
const args = [
|
|
3637
|
+
...input.headless ? [
|
|
3638
|
+
'-headless'
|
|
3639
|
+
] : [],
|
|
3640
|
+
...input.debugPort > 0 ? [
|
|
3641
|
+
'-start-debugger-server',
|
|
3642
|
+
String(input.debugPort)
|
|
3643
|
+
] : [],
|
|
3644
|
+
...'win32' === process.platform ? [
|
|
3645
|
+
'-wait-for-browser'
|
|
3646
|
+
] : [],
|
|
3647
|
+
...input.headless ? [] : [
|
|
3648
|
+
'--foreground'
|
|
3649
|
+
],
|
|
3650
|
+
...input.binaryArgs
|
|
3651
|
+
];
|
|
3652
|
+
return {
|
|
3653
|
+
binary: input.binaryPath,
|
|
3654
|
+
args
|
|
3655
|
+
};
|
|
3656
|
+
}
|
|
3573
3657
|
static generateFirefoxArgs(binaryPath, profilePath, debugPort, additionalArgs = [], headless = false) {
|
|
3574
3658
|
const headlessArgs = headless ? [
|
|
3575
3659
|
'-headless'
|
|
@@ -3699,7 +3783,8 @@ var __webpack_modules__ = {
|
|
|
3699
3783
|
...customPrefs
|
|
3700
3784
|
};
|
|
3701
3785
|
}
|
|
3702
|
-
async function
|
|
3786
|
+
async function resolveFirefoxLaunchConfig(compilation, configOptions, mode = {}) {
|
|
3787
|
+
const provision = false !== mode.provision;
|
|
3703
3788
|
const { browser, profile, browserFlags = [] } = configOptions;
|
|
3704
3789
|
const binaryArgs = [];
|
|
3705
3790
|
const excludeFlags = configOptions.excludeBrowserFlags || [];
|
|
@@ -3727,17 +3812,18 @@ var __webpack_modules__ = {
|
|
|
3727
3812
|
persistProfile: configOptions.persistProfile,
|
|
3728
3813
|
keepProfileChanges: configOptions.keepProfileChanges,
|
|
3729
3814
|
copyFromProfile: configOptions.copyFromProfile,
|
|
3730
|
-
resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile)
|
|
3815
|
+
resolveExplicit: (trimmedProfile)=>external_node_path_.isAbsolute(trimmedProfile) ? trimmedProfile : external_node_path_.resolve(contextDir, trimmedProfile),
|
|
3816
|
+
provision
|
|
3731
3817
|
});
|
|
3732
3818
|
const profilePath = resolved.profilePath;
|
|
3733
|
-
if ('managed' === resolved.kind) {
|
|
3819
|
+
if ('managed' === resolved.kind && provision) {
|
|
3734
3820
|
if ((0, messaging._o)()) (0, messaging._w)(messages.sY(shownPath(profilePath)));
|
|
3735
3821
|
if (!resolved.persisted) try {
|
|
3736
3822
|
const maxAgeHours = parseInt(String(process.env.EXTENSION_TMP_PROFILE_MAX_AGE_HOURS || ''), 10);
|
|
3737
3823
|
(0, shared_utils.CW)(managedBaseDir, external_node_path_.basename(profilePath), Number.isFinite(maxAgeHours) ? maxAgeHours : 12);
|
|
3738
3824
|
} catch {}
|
|
3739
3825
|
}
|
|
3740
|
-
if (profilePath) {
|
|
3826
|
+
if (profilePath && provision) {
|
|
3741
3827
|
try {
|
|
3742
3828
|
external_node_fs_.mkdirSync(profilePath, {
|
|
3743
3829
|
recursive: true
|
|
@@ -3750,7 +3836,7 @@ var __webpack_modules__ = {
|
|
|
3750
3836
|
});
|
|
3751
3837
|
} catch {}
|
|
3752
3838
|
}
|
|
3753
|
-
if (profilePath) try {
|
|
3839
|
+
if (profilePath && provision) try {
|
|
3754
3840
|
const prefs = getPreferences(configOptions?.preferences || {});
|
|
3755
3841
|
function serializeValue(value) {
|
|
3756
3842
|
if ('string' == typeof value) return JSON.stringify(value);
|
|
@@ -3770,13 +3856,17 @@ var __webpack_modules__ = {
|
|
|
3770
3856
|
];
|
|
3771
3857
|
if (binaryArgs.length > 0) parts.unshift(`--binary-args="${binaryArgs.join(' ')}"`);
|
|
3772
3858
|
if (profilePath) parts.splice(1, 0, `--profile="${profilePath}"`);
|
|
3773
|
-
return
|
|
3859
|
+
return {
|
|
3860
|
+
profilePath,
|
|
3861
|
+
binaryArgs,
|
|
3862
|
+
config: parts.join(' ')
|
|
3863
|
+
};
|
|
3774
3864
|
}
|
|
3775
|
-
function logFirefoxDryRun(browserBinaryLocation,
|
|
3865
|
+
function logFirefoxDryRun(browserBinaryLocation, launchArgs) {
|
|
3776
3866
|
if ((0, messaging._o)()) (0, messaging._w)(messages.A9());
|
|
3777
3867
|
(0, messaging._w)(messages.qn());
|
|
3778
3868
|
(0, messaging._w)(messages.LD(browserBinaryLocation));
|
|
3779
|
-
(0, messaging._w)(messages.
|
|
3869
|
+
(0, messaging._w)(messages.lO(launchArgs.join(' ')));
|
|
3780
3870
|
}
|
|
3781
3871
|
const activeInstances = new Set();
|
|
3782
3872
|
let globalHandlersInstalled = false;
|
|
@@ -3841,6 +3931,7 @@ var __webpack_modules__ = {
|
|
|
3841
3931
|
activeInstances.delete(instance);
|
|
3842
3932
|
};
|
|
3843
3933
|
}
|
|
3934
|
+
var newtab_override = __webpack_require__("./browsers/browsers-lib/newtab-override.ts");
|
|
3844
3935
|
var constants = __webpack_require__("./browsers/browsers-lib/constants.ts");
|
|
3845
3936
|
var manifest_readiness = __webpack_require__("./browsers/run-chromium/manifest-readiness.ts");
|
|
3846
3937
|
function resolveAddonDirectory(baseDir, inputPath) {
|
|
@@ -4094,6 +4185,110 @@ var __webpack_modules__ = {
|
|
|
4094
4185
|
} catch {}
|
|
4095
4186
|
});
|
|
4096
4187
|
}
|
|
4188
|
+
const MANAGER_ADDON_ID = 'devtools@extension.js';
|
|
4189
|
+
const OPEN_NEW_TAB_EXPRESSION = "(function () { var api = globalThis.browser || globalThis.chrome; api.tabs.create({active: true}); return true;})()";
|
|
4190
|
+
const TARGET_WAIT_MS = 2000;
|
|
4191
|
+
function reportStep(step, detail) {
|
|
4192
|
+
if (!(0, messaging._o)()) return;
|
|
4193
|
+
const reason = detail instanceof Error ? detail.message : void 0 === detail ? '' : ` ${JSON.stringify(detail).slice(0, 300)}`;
|
|
4194
|
+
(0, messaging.mR)(`[browser] Firefox new-tab courtesy: ${step}${reason}`);
|
|
4195
|
+
}
|
|
4196
|
+
async function findManagerAddon(client) {
|
|
4197
|
+
const reply = await client.request({
|
|
4198
|
+
to: 'root',
|
|
4199
|
+
type: 'listAddons'
|
|
4200
|
+
});
|
|
4201
|
+
return (reply?.addons || []).find((addon)=>addon?.id === MANAGER_ADDON_ID);
|
|
4202
|
+
}
|
|
4203
|
+
function manager_tab_unsubscribe(client, listener) {
|
|
4204
|
+
if ('function' == typeof client.off) client.off('message', listener);
|
|
4205
|
+
else client.removeListener?.('message', listener);
|
|
4206
|
+
}
|
|
4207
|
+
function isBackgroundPage(target) {
|
|
4208
|
+
return /_generated_background_page\.html|\/background/.test(String(target?.url || ''));
|
|
4209
|
+
}
|
|
4210
|
+
async function resolveConsoleActorViaWatcher(client, descriptorActor) {
|
|
4211
|
+
const watcher = await client.request({
|
|
4212
|
+
to: descriptorActor,
|
|
4213
|
+
type: 'getWatcher',
|
|
4214
|
+
isServerTargetSwitchingEnabled: true
|
|
4215
|
+
});
|
|
4216
|
+
const noop = ()=>{};
|
|
4217
|
+
if (!watcher?.actor) return {
|
|
4218
|
+
release: noop
|
|
4219
|
+
};
|
|
4220
|
+
const watcherActor = watcher.actor;
|
|
4221
|
+
const release = ()=>{
|
|
4222
|
+
client.request({
|
|
4223
|
+
to: watcherActor,
|
|
4224
|
+
type: 'unwatchTargets',
|
|
4225
|
+
targetType: 'frame'
|
|
4226
|
+
}).catch(()=>{});
|
|
4227
|
+
};
|
|
4228
|
+
const targets = [];
|
|
4229
|
+
const collect = (message)=>{
|
|
4230
|
+
const event = message;
|
|
4231
|
+
if (event?.type === 'target-available-form' && event.target) targets.push(event.target);
|
|
4232
|
+
};
|
|
4233
|
+
client.on('message', collect);
|
|
4234
|
+
try {
|
|
4235
|
+
collect(await client.request({
|
|
4236
|
+
to: watcherActor,
|
|
4237
|
+
type: 'watchTargets',
|
|
4238
|
+
targetType: 'frame'
|
|
4239
|
+
}));
|
|
4240
|
+
const deadline = Date.now() + TARGET_WAIT_MS;
|
|
4241
|
+
while(Date.now() < deadline){
|
|
4242
|
+
const background = targets.find((target)=>target.consoleActor && isBackgroundPage(target));
|
|
4243
|
+
if (background) return {
|
|
4244
|
+
consoleActor: background.consoleActor,
|
|
4245
|
+
release
|
|
4246
|
+
};
|
|
4247
|
+
await new Promise((resolve)=>setTimeout(resolve, 50));
|
|
4248
|
+
}
|
|
4249
|
+
return {
|
|
4250
|
+
consoleActor: targets.find((target)=>target.consoleActor)?.consoleActor,
|
|
4251
|
+
release
|
|
4252
|
+
};
|
|
4253
|
+
} finally{
|
|
4254
|
+
manager_tab_unsubscribe(client, collect);
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
async function resolveConsoleActor(client, addon) {
|
|
4258
|
+
if (addon.consoleActor) return {
|
|
4259
|
+
consoleActor: addon.consoleActor,
|
|
4260
|
+
release: ()=>{}
|
|
4261
|
+
};
|
|
4262
|
+
if (!addon.actor) return {
|
|
4263
|
+
release: ()=>{}
|
|
4264
|
+
};
|
|
4265
|
+
return await resolveConsoleActorViaWatcher(client, addon.actor);
|
|
4266
|
+
}
|
|
4267
|
+
async function openManagerNewTab(client) {
|
|
4268
|
+
try {
|
|
4269
|
+
const addon = await findManagerAddon(client);
|
|
4270
|
+
if (!addon) {
|
|
4271
|
+
reportStep('manager add-on not listed');
|
|
4272
|
+
return false;
|
|
4273
|
+
}
|
|
4274
|
+
const { consoleActor, release } = await resolveConsoleActor(client, addon);
|
|
4275
|
+
if (!consoleActor) {
|
|
4276
|
+
release();
|
|
4277
|
+
reportStep('no console actor for the manager background page');
|
|
4278
|
+
return false;
|
|
4279
|
+
}
|
|
4280
|
+
try {
|
|
4281
|
+
const result = await client.evaluate(consoleActor, OPEN_NEW_TAB_EXPRESSION);
|
|
4282
|
+
reportStep('tabs.create evaluated', result);
|
|
4283
|
+
} finally{
|
|
4284
|
+
release();
|
|
4285
|
+
}
|
|
4286
|
+
return true;
|
|
4287
|
+
} catch (error) {
|
|
4288
|
+
reportStep('failed', error);
|
|
4289
|
+
return false;
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4097
4292
|
function requestErrorToMessage(error) {
|
|
4098
4293
|
if (error instanceof Error) return String(error);
|
|
4099
4294
|
try {
|
|
@@ -4282,21 +4477,33 @@ var __webpack_modules__ = {
|
|
|
4282
4477
|
const raw = parseInt(String(process.env.EXTENSION_RDP_REQUEST_TIMEOUT_MS || ''), 10);
|
|
4283
4478
|
return Number.isFinite(raw) && raw > 0 ? raw : 30000;
|
|
4284
4479
|
}
|
|
4480
|
+
function surfaceTransportError(emitter, error) {
|
|
4481
|
+
if (emitter.listenerCount('error') > 0) return void emitter.emit('error', error);
|
|
4482
|
+
(0, messaging.Gg)(error instanceof Error ? error.message : String(error));
|
|
4483
|
+
}
|
|
4285
4484
|
class RdpTransport extends external_node_events_default() {
|
|
4286
4485
|
async connect(port, host = '127.0.0.1') {
|
|
4287
4486
|
await new Promise((resolve, reject)=>{
|
|
4487
|
+
let connected = false;
|
|
4288
4488
|
try {
|
|
4289
4489
|
const c = external_node_net_default().createConnection({
|
|
4290
4490
|
host,
|
|
4291
4491
|
port
|
|
4292
4492
|
}, ()=>{
|
|
4493
|
+
connected = true;
|
|
4293
4494
|
if ((0, messaging._o)()) (0, messaging._w)(messages.EI(host, port));
|
|
4294
4495
|
resolve();
|
|
4295
4496
|
});
|
|
4296
4497
|
this.conn = c;
|
|
4498
|
+
this.lost = false;
|
|
4297
4499
|
c.on('data', this.onData.bind(this));
|
|
4298
|
-
c.on('error',
|
|
4299
|
-
|
|
4500
|
+
c.on('error', (err)=>{
|
|
4501
|
+
if (connected) return;
|
|
4502
|
+
this.conn = void 0;
|
|
4503
|
+
reject(err);
|
|
4504
|
+
});
|
|
4505
|
+
c.on('end', this.onConnectionLost.bind(this));
|
|
4506
|
+
c.on('close', this.onConnectionLost.bind(this));
|
|
4300
4507
|
c.on('timeout', this.onTimeout.bind(this));
|
|
4301
4508
|
} catch (err) {
|
|
4302
4509
|
reject(err);
|
|
@@ -4304,11 +4511,15 @@ var __webpack_modules__ = {
|
|
|
4304
4511
|
});
|
|
4305
4512
|
}
|
|
4306
4513
|
disconnect() {
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
this.conn
|
|
4310
|
-
|
|
4311
|
-
this.
|
|
4514
|
+
const c = this.conn;
|
|
4515
|
+
if (!c) return;
|
|
4516
|
+
this.conn = void 0;
|
|
4517
|
+
this.lost = true;
|
|
4518
|
+
this.incoming = Buffer.alloc(0);
|
|
4519
|
+
c.removeAllListeners();
|
|
4520
|
+
c.on('error', ()=>{});
|
|
4521
|
+
c.end();
|
|
4522
|
+
this.rejectAll(new Error(messages.qN('firefox')));
|
|
4312
4523
|
}
|
|
4313
4524
|
rejectAll(error) {
|
|
4314
4525
|
for (const entry of this.active.values()){
|
|
@@ -4380,8 +4591,8 @@ var __webpack_modules__ = {
|
|
|
4380
4591
|
const { remainingData, parsedMessage, error, fatal } = parseRdpFrame(this.incoming);
|
|
4381
4592
|
this.incoming = remainingData;
|
|
4382
4593
|
if (error) {
|
|
4383
|
-
this
|
|
4384
|
-
if (fatal) this.
|
|
4594
|
+
surfaceTransportError(this, new Error(messages.l9('firefox', error)));
|
|
4595
|
+
if (fatal) this.onConnectionLost();
|
|
4385
4596
|
return !fatal;
|
|
4386
4597
|
}
|
|
4387
4598
|
if (!parsedMessage) return false;
|
|
@@ -4389,10 +4600,11 @@ var __webpack_modules__ = {
|
|
|
4389
4600
|
return true;
|
|
4390
4601
|
}
|
|
4391
4602
|
handleMessage(message) {
|
|
4392
|
-
|
|
4393
|
-
|
|
4603
|
+
const from = message.from;
|
|
4604
|
+
if (!from) return void surfaceTransportError(this, new Error(messages.HH('firefox', message)));
|
|
4605
|
+
const entry = this.active.get(from);
|
|
4394
4606
|
if (entry) {
|
|
4395
|
-
this.active.delete(
|
|
4607
|
+
this.active.delete(from);
|
|
4396
4608
|
if (entry.timer) clearTimeout(entry.timer);
|
|
4397
4609
|
if (message.error) entry.deferred.reject(message);
|
|
4398
4610
|
else entry.deferred.resolve(message);
|
|
@@ -4401,7 +4613,17 @@ var __webpack_modules__ = {
|
|
|
4401
4613
|
}
|
|
4402
4614
|
this.emit('message', message);
|
|
4403
4615
|
}
|
|
4404
|
-
|
|
4616
|
+
onConnectionLost() {
|
|
4617
|
+
if (this.lost) return;
|
|
4618
|
+
this.lost = true;
|
|
4619
|
+
const c = this.conn;
|
|
4620
|
+
this.conn = void 0;
|
|
4621
|
+
this.incoming = Buffer.alloc(0);
|
|
4622
|
+
if (c) {
|
|
4623
|
+
c.removeAllListeners();
|
|
4624
|
+
c.on('error', ()=>{});
|
|
4625
|
+
c.destroy();
|
|
4626
|
+
}
|
|
4405
4627
|
this.rejectAll(new Error(messages.qN('firefox')));
|
|
4406
4628
|
this.emit('end');
|
|
4407
4629
|
}
|
|
@@ -4409,7 +4631,7 @@ var __webpack_modules__ = {
|
|
|
4409
4631
|
this.emit('timeout');
|
|
4410
4632
|
}
|
|
4411
4633
|
constructor(...args){
|
|
4412
|
-
super(...args), _define_property(this, "conn", void 0), _define_property(this, "incoming", Buffer.alloc(0)), _define_property(this, "active", new Map()), _define_property(this, "pending", []);
|
|
4634
|
+
super(...args), _define_property(this, "conn", void 0), _define_property(this, "incoming", Buffer.alloc(0)), _define_property(this, "active", new Map()), _define_property(this, "pending", []), _define_property(this, "lost", false);
|
|
4413
4635
|
}
|
|
4414
4636
|
}
|
|
4415
4637
|
function messaging_client_define_property(obj, key, value) {
|
|
@@ -4422,15 +4644,20 @@ var __webpack_modules__ = {
|
|
|
4422
4644
|
else obj[key] = value;
|
|
4423
4645
|
return obj;
|
|
4424
4646
|
}
|
|
4647
|
+
const RECONNECT_MAX_ATTEMPTS = 5;
|
|
4648
|
+
const RECONNECT_RETRY_DELAY_MS = 1000;
|
|
4425
4649
|
class MessagingClient extends external_node_events_default() {
|
|
4426
4650
|
async connect(port) {
|
|
4427
|
-
this.lastPort = port;
|
|
4428
4651
|
this.disconnectedByUser = false;
|
|
4652
|
+
await this.openTransport(port);
|
|
4653
|
+
}
|
|
4654
|
+
async openTransport(port) {
|
|
4655
|
+
this.lastPort = port;
|
|
4429
4656
|
await this.transport.connect(port);
|
|
4430
4657
|
if (!this.forwardingSetup) {
|
|
4431
4658
|
this.forwardingSetup = true;
|
|
4432
4659
|
this.transport.on('message', (message)=>this.emit('message', message));
|
|
4433
|
-
this.transport.on('error', (error)=>this
|
|
4660
|
+
this.transport.on('error', (error)=>surfaceTransportError(this, error));
|
|
4434
4661
|
this.transport.on('end', ()=>{
|
|
4435
4662
|
this.emit('end');
|
|
4436
4663
|
this.attemptReconnect();
|
|
@@ -4445,20 +4672,21 @@ var __webpack_modules__ = {
|
|
|
4445
4672
|
async attemptReconnect() {
|
|
4446
4673
|
if (this.disconnectedByUser || this.reconnecting || !this.lastPort) return;
|
|
4447
4674
|
this.reconnecting = true;
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
}
|
|
4675
|
+
try {
|
|
4676
|
+
for(let i = 0; i < RECONNECT_MAX_ATTEMPTS; i++){
|
|
4677
|
+
await new Promise((r)=>setTimeout(r, RECONNECT_RETRY_DELAY_MS));
|
|
4678
|
+
if (this.disconnectedByUser) return;
|
|
4679
|
+
try {
|
|
4680
|
+
this.transport = new RdpTransport();
|
|
4681
|
+
this.forwardingSetup = false;
|
|
4682
|
+
await this.openTransport(this.lastPort);
|
|
4683
|
+
this.emit('reconnected');
|
|
4684
|
+
return;
|
|
4685
|
+
} catch {}
|
|
4686
|
+
}
|
|
4687
|
+
} finally{
|
|
4688
|
+
this.reconnecting = false;
|
|
4460
4689
|
}
|
|
4461
|
-
this.reconnecting = false;
|
|
4462
4690
|
}
|
|
4463
4691
|
async request(requestProps) {
|
|
4464
4692
|
if ('string' == typeof requestProps) return await this.transport.request({
|
|
@@ -4647,6 +4875,10 @@ var __webpack_modules__ = {
|
|
|
4647
4875
|
});
|
|
4648
4876
|
if (!bannerPrinted) throw new Error(messages.WV(this.options.browser, 'Failed to print runningInDevelopment banner; add-on may not be installed.'));
|
|
4649
4877
|
}
|
|
4878
|
+
async openNewTab() {
|
|
4879
|
+
if (!this.client) return false;
|
|
4880
|
+
return await openManagerNewTab(this.client);
|
|
4881
|
+
}
|
|
4650
4882
|
async enableUnifiedLogging(opts) {
|
|
4651
4883
|
try {
|
|
4652
4884
|
if (this.loggingAttached) return;
|
|
@@ -4700,6 +4932,9 @@ var __webpack_modules__ = {
|
|
|
4700
4932
|
getAddonInstallRefusalReason() {
|
|
4701
4933
|
return this.remote.getAddonInstallRefusalReason();
|
|
4702
4934
|
}
|
|
4935
|
+
async openNewTab() {
|
|
4936
|
+
return await this.remote.openNewTab();
|
|
4937
|
+
}
|
|
4703
4938
|
getExtensionId() {
|
|
4704
4939
|
return this.remote.getDerivedExtensionId();
|
|
4705
4940
|
}
|
|
@@ -4762,6 +4997,14 @@ var __webpack_modules__ = {
|
|
|
4762
4997
|
} catch (error) {
|
|
4763
4998
|
throw withRefusalReason(error);
|
|
4764
4999
|
}
|
|
5000
|
+
try {
|
|
5001
|
+
const outPath = String(compilation?.options?.output?.path || '');
|
|
5002
|
+
if (!plugin.startingUrl && !plugin.noOpen && (0, newtab_override.c)(outPath)) {
|
|
5003
|
+
const live = plugin.rdpController || controller;
|
|
5004
|
+
const opened = await live.openNewTab?.();
|
|
5005
|
+
if (!opened && (0, messaging._o)()) (0, messaging.mR)('[browser] Firefox: could not open the new-tab override page.');
|
|
5006
|
+
}
|
|
5007
|
+
} catch {}
|
|
4765
5008
|
return controller;
|
|
4766
5009
|
}
|
|
4767
5010
|
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
@@ -4844,7 +5087,7 @@ var __webpack_modules__ = {
|
|
|
4844
5087
|
debug: (...a)=>console?.debug?.(...a)
|
|
4845
5088
|
};
|
|
4846
5089
|
await this.launch(compilation, options);
|
|
4847
|
-
if ('development'
|
|
5090
|
+
if (options?.mode === 'development' && !this.host.extensionLoadRefused) this.ctx.logger?.info?.((0, ready_message.G)(options.mode, this.host.browser));
|
|
4848
5091
|
this.ctx.didLaunch = true;
|
|
4849
5092
|
}
|
|
4850
5093
|
apply(compiler) {
|
|
@@ -4909,12 +5152,10 @@ var __webpack_modules__ = {
|
|
|
4909
5152
|
if (process.env.VITEST || process.env.VITEST_WORKER_ID) throw new Error('Firefox not installed or binary path not found');
|
|
4910
5153
|
process.exit(1);
|
|
4911
5154
|
};
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
return;
|
|
4917
|
-
}
|
|
5155
|
+
const inTestRunner = Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
|
|
5156
|
+
const dryRun = Boolean(this.host.dryRun);
|
|
5157
|
+
if (inTestRunner && !dryRun) return void logFirefoxDryRun('firefox-mock-binary', []);
|
|
5158
|
+
if (inTestRunner && dryRun && !this.host.geckoBinary) return void await this.printDryRunPlan(compilation, options, 'firefox-mock-binary');
|
|
4918
5159
|
let browserBinaryLocation = resolveManagedBinary();
|
|
4919
5160
|
let skipDetection = Boolean(browserBinaryLocation);
|
|
4920
5161
|
const engineBased = 'gecko-based' === this.host.browser || 'firefox-based' === this.host.browser;
|
|
@@ -5008,25 +5249,25 @@ var __webpack_modules__ = {
|
|
|
5008
5249
|
rdpPort: debugPort
|
|
5009
5250
|
});
|
|
5010
5251
|
const effectiveInstanceId = this.host.instanceId;
|
|
5011
|
-
|
|
5012
|
-
firefoxCfg = await browserConfig(compilation, {
|
|
5252
|
+
const launchConfig = await resolveFirefoxLaunchConfig(compilation, {
|
|
5013
5253
|
...options,
|
|
5014
5254
|
profile: this.host.profile,
|
|
5015
5255
|
preferences: this.host.preferences || {},
|
|
5016
5256
|
instanceId: effectiveInstanceId
|
|
5257
|
+
}, {
|
|
5258
|
+
provision: !dryRun
|
|
5259
|
+
});
|
|
5260
|
+
const { profilePath, binaryArgs: firefoxArgs } = launchConfig;
|
|
5261
|
+
const plan = FirefoxBinaryDetector.launchPlan({
|
|
5262
|
+
binaryPath,
|
|
5263
|
+
profilePath,
|
|
5264
|
+
debugPort,
|
|
5265
|
+
binaryArgs: firefoxArgs,
|
|
5266
|
+
headless: isFirefoxHeadlessRequested()
|
|
5017
5267
|
});
|
|
5018
|
-
if (
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
if (binaryArgsMatch) {
|
|
5022
|
-
const rawArgs = String(binaryArgsMatch[1] || '').trim();
|
|
5023
|
-
if (rawArgs) firefoxArgs.push(...rawArgs.split(' ').filter((arg)=>arg.trim().length > 0));
|
|
5024
|
-
if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.iv(binaryArgsMatch[1]));
|
|
5025
|
-
} else if ((0, messaging._o)()) this.ctx.logger?.info?.(messages.dN());
|
|
5026
|
-
const profileMatch = firefoxCfg.match(/--profile="([^"]*)"/);
|
|
5027
|
-
if (profileMatch) {
|
|
5028
|
-
const profilePath = profileMatch[1];
|
|
5029
|
-
const { binary, args } = FirefoxBinaryDetector.generateFirefoxArgs(binaryPath, profilePath, debugPort, firefoxArgs, isFirefoxHeadlessRequested());
|
|
5268
|
+
if (dryRun) return void logFirefoxDryRun(plan.binary, plan.args);
|
|
5269
|
+
if (profilePath) {
|
|
5270
|
+
const { binary, args } = plan;
|
|
5030
5271
|
this.host.launchProfilePath = profilePath;
|
|
5031
5272
|
this.child = await this.spawnFirefoxChild(binary, args, wslFallbackBinary);
|
|
5032
5273
|
(0, ready_stamp.M)(this.extensionOutputPath, {
|
|
@@ -5066,23 +5307,7 @@ var __webpack_modules__ = {
|
|
|
5066
5307
|
} catch {}
|
|
5067
5308
|
} else {
|
|
5068
5309
|
if ((0, messaging._o)()) this.ctx.logger?.warn?.('[browser] Firefox profile not set; skipping RDP add-on install.');
|
|
5069
|
-
|
|
5070
|
-
...isFirefoxHeadlessRequested() ? [
|
|
5071
|
-
'-headless'
|
|
5072
|
-
] : [],
|
|
5073
|
-
...debugPort > 0 ? [
|
|
5074
|
-
'-start-debugger-server',
|
|
5075
|
-
String(debugPort)
|
|
5076
|
-
] : [],
|
|
5077
|
-
...'win32' === process.platform ? [
|
|
5078
|
-
'-wait-for-browser'
|
|
5079
|
-
] : [],
|
|
5080
|
-
...isFirefoxHeadlessRequested() ? [] : [
|
|
5081
|
-
'--foreground'
|
|
5082
|
-
],
|
|
5083
|
-
...firefoxArgs
|
|
5084
|
-
];
|
|
5085
|
-
this.child = await this.spawnFirefoxChild(binaryPath, args, wslFallbackBinary);
|
|
5310
|
+
this.child = await this.spawnFirefoxChild(plan.binary, plan.args, wslFallbackBinary);
|
|
5086
5311
|
(0, ready_stamp.M)(this.extensionOutputPath, {
|
|
5087
5312
|
browserPid: this.child?.pid,
|
|
5088
5313
|
extensionId: this.extensionOutputPath ? (0, banner.MT)(this.extensionOutputPath) : void 0
|
|
@@ -5092,6 +5317,24 @@ var __webpack_modules__ = {
|
|
|
5092
5317
|
this.scheduleWatchTimeout();
|
|
5093
5318
|
}
|
|
5094
5319
|
}
|
|
5320
|
+
async printDryRunPlan(compilation, options, binaryPath) {
|
|
5321
|
+
const launchConfig = await resolveFirefoxLaunchConfig(compilation, {
|
|
5322
|
+
...options,
|
|
5323
|
+
profile: this.host.profile,
|
|
5324
|
+
preferences: this.host.preferences || {},
|
|
5325
|
+
instanceId: this.host.instanceId
|
|
5326
|
+
}, {
|
|
5327
|
+
provision: false
|
|
5328
|
+
});
|
|
5329
|
+
const plan = FirefoxBinaryDetector.launchPlan({
|
|
5330
|
+
binaryPath,
|
|
5331
|
+
profilePath: launchConfig.profilePath,
|
|
5332
|
+
debugPort: (0, shared_utils.jl)(this.host.port, this.host.instanceId),
|
|
5333
|
+
binaryArgs: launchConfig.binaryArgs,
|
|
5334
|
+
headless: isFirefoxHeadlessRequested()
|
|
5335
|
+
});
|
|
5336
|
+
logFirefoxDryRun(plan.binary, plan.args);
|
|
5337
|
+
}
|
|
5095
5338
|
resolveSpawnStdio() {
|
|
5096
5339
|
if ('win32' !== process.platform) return [
|
|
5097
5340
|
'pipe',
|
|
@@ -5305,6 +5548,7 @@ var __webpack_modules__ = {
|
|
|
5305
5548
|
preferences: pluginOptions.preferences,
|
|
5306
5549
|
browserFlags: pluginOptions.browserFlags,
|
|
5307
5550
|
startingUrl: pluginOptions.startingUrl,
|
|
5551
|
+
noOpen: pluginOptions.noOpen,
|
|
5308
5552
|
geckoBinary: pluginOptions.geckoBinary,
|
|
5309
5553
|
instanceId: pluginOptions.instanceId,
|
|
5310
5554
|
port: pluginOptions.port,
|
|
@@ -6617,257 +6861,6 @@ var __webpack_modules__ = {
|
|
|
6617
6861
|
if (!Number.isFinite(n)) return min;
|
|
6618
6862
|
return Math.min(Math.max(n, min), max);
|
|
6619
6863
|
}
|
|
6620
|
-
const KNOWN_COMMANDS = new Set([
|
|
6621
|
-
'create',
|
|
6622
|
-
'dev',
|
|
6623
|
-
'start',
|
|
6624
|
-
'preview',
|
|
6625
|
-
'build',
|
|
6626
|
-
'install',
|
|
6627
|
-
'uninstall',
|
|
6628
|
-
'telemetry',
|
|
6629
|
-
'unknown'
|
|
6630
|
-
]);
|
|
6631
|
-
function detectInvokedCommand(argv) {
|
|
6632
|
-
for(let i = 2; i < argv.length; i += 1){
|
|
6633
|
-
const arg = argv[i];
|
|
6634
|
-
if (!(!arg || arg.startsWith('-'))) {
|
|
6635
|
-
if (KNOWN_COMMANDS.has(arg)) return arg;
|
|
6636
|
-
break;
|
|
6637
|
-
}
|
|
6638
|
-
}
|
|
6639
|
-
return 'unknown';
|
|
6640
|
-
}
|
|
6641
|
-
function readArgValue(argv, names) {
|
|
6642
|
-
for(let i = 2; i < argv.length; i += 1){
|
|
6643
|
-
const arg = argv[i];
|
|
6644
|
-
if (arg) for (const name of names){
|
|
6645
|
-
if (arg === name) {
|
|
6646
|
-
const next = argv[i + 1];
|
|
6647
|
-
return next && !next.startsWith('-') ? next : void 0;
|
|
6648
|
-
}
|
|
6649
|
-
if (arg.startsWith(`${name}=`)) return arg.slice(name.length + 1);
|
|
6650
|
-
}
|
|
6651
|
-
}
|
|
6652
|
-
}
|
|
6653
|
-
function telemetryCommandContext(command, argv = process.argv) {
|
|
6654
|
-
if ('create' !== command) return {};
|
|
6655
|
-
return {
|
|
6656
|
-
template: readArgValue(argv, [
|
|
6657
|
-
'--template',
|
|
6658
|
-
'-t'
|
|
6659
|
-
]),
|
|
6660
|
-
source: readArgValue(argv, [
|
|
6661
|
-
'--source'
|
|
6662
|
-
]) || 'cli'
|
|
6663
|
-
};
|
|
6664
|
-
}
|
|
6665
|
-
const consent = resolveTelemetryConsent(process.argv);
|
|
6666
|
-
const invoked = detectInvokedCommand(process.argv);
|
|
6667
|
-
const telemetry_cli_version = String(getCliPackageJson().version || '0.0.0');
|
|
6668
|
-
const telemetry = new Telemetry({
|
|
6669
|
-
app: 'extension',
|
|
6670
|
-
version: telemetry_cli_version,
|
|
6671
|
-
disabled: !consent.enabled
|
|
6672
|
-
});
|
|
6673
|
-
function getTelemetryConsent() {
|
|
6674
|
-
return consent;
|
|
6675
|
-
}
|
|
6676
|
-
function setTelemetryConsent(value) {
|
|
6677
|
-
const ok = writeConsent(value);
|
|
6678
|
-
const storage = resolveTelemetryStorage();
|
|
6679
|
-
return {
|
|
6680
|
-
ok,
|
|
6681
|
-
path: storage?.consentFile ?? null
|
|
6682
|
-
};
|
|
6683
|
-
}
|
|
6684
|
-
let tracked = false;
|
|
6685
|
-
function markTracked() {
|
|
6686
|
-
if (tracked) return false;
|
|
6687
|
-
tracked = true;
|
|
6688
|
-
return true;
|
|
6689
|
-
}
|
|
6690
|
-
function markCommandSuccess(command = invoked) {
|
|
6691
|
-
if (!markTracked()) return;
|
|
6692
|
-
telemetry.track('command_executed', {
|
|
6693
|
-
command,
|
|
6694
|
-
success: true,
|
|
6695
|
-
version: telemetry_cli_version,
|
|
6696
|
-
...telemetryCommandContext(command)
|
|
6697
|
-
});
|
|
6698
|
-
}
|
|
6699
|
-
function markCommandFailure(command = invoked) {
|
|
6700
|
-
if (!markTracked()) return;
|
|
6701
|
-
telemetry.track('command_failed', {
|
|
6702
|
-
command,
|
|
6703
|
-
success: false,
|
|
6704
|
-
version: telemetry_cli_version,
|
|
6705
|
-
...telemetryCommandContext(command)
|
|
6706
|
-
});
|
|
6707
|
-
}
|
|
6708
|
-
function printOptOutNoticeIfFirstRun() {
|
|
6709
|
-
if (!consent.enabled || 'default' !== consent.source) return;
|
|
6710
|
-
const storage = resolveTelemetryStorage();
|
|
6711
|
-
if (!storage) return;
|
|
6712
|
-
const written = writeConsent('enabled');
|
|
6713
|
-
if (!written) return;
|
|
6714
|
-
console.error(`${external_pintor_default().gray('⏵⏵⏵')} Extension.js collects anonymous, opt-out telemetry (two events: ${external_pintor_default().cyan('command_executed')} + ${external_pintor_default().cyan('command_failed')}). Disable with ${external_pintor_default().cyan('extension telemetry disable')}, ${external_pintor_default().cyan('EXTENSION_TELEMETRY=0')}, or ${external_pintor_default().cyan('--no-telemetry')}. See docs/TELEMETRY.md.`);
|
|
6715
|
-
}
|
|
6716
|
-
if (consent.enabled) {
|
|
6717
|
-
printOptOutNoticeIfFirstRun();
|
|
6718
|
-
process.on('beforeExit', async ()=>{
|
|
6719
|
-
if (!tracked) if ((process.exitCode ?? 0) === 0) markCommandSuccess();
|
|
6720
|
-
else markCommandFailure();
|
|
6721
|
-
await telemetry.flush();
|
|
6722
|
-
});
|
|
6723
|
-
process.on('uncaughtException', ()=>{
|
|
6724
|
-
markCommandFailure();
|
|
6725
|
-
});
|
|
6726
|
-
process.on('unhandledRejection', ()=>{
|
|
6727
|
-
markCommandFailure();
|
|
6728
|
-
});
|
|
6729
|
-
}
|
|
6730
|
-
const TELEMETRY_FLUSH_TIMEOUT_MS = 500;
|
|
6731
|
-
async function exitAfterDrain(code) {
|
|
6732
|
-
try {
|
|
6733
|
-
await Promise.race([
|
|
6734
|
-
telemetry.flush(),
|
|
6735
|
-
new Promise((resolve)=>setTimeout(resolve, TELEMETRY_FLUSH_TIMEOUT_MS).unref?.())
|
|
6736
|
-
]);
|
|
6737
|
-
} catch {}
|
|
6738
|
-
await Promise.all([
|
|
6739
|
-
process.stdout,
|
|
6740
|
-
process.stderr
|
|
6741
|
-
].map((stream)=>new Promise((resolve)=>{
|
|
6742
|
-
if (0 === stream.writableLength) return resolve();
|
|
6743
|
-
stream.write('', ()=>resolve());
|
|
6744
|
-
})));
|
|
6745
|
-
process.exit(code);
|
|
6746
|
-
}
|
|
6747
|
-
var external_node_module_ = __webpack_require__("node:module");
|
|
6748
|
-
const external_node_url_namespaceObject = require("node:url");
|
|
6749
|
-
const extension_develop_runtime_require = (0, external_node_module_.createRequire)(__rslib_import_meta_url__);
|
|
6750
|
-
function parseJsonSafe(filePath) {
|
|
6751
|
-
return JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf8'));
|
|
6752
|
-
}
|
|
6753
|
-
function resolveDevelopRootFromDir(dir) {
|
|
6754
|
-
try {
|
|
6755
|
-
const packageJsonPath = external_node_path_default().join(dir, 'package.json');
|
|
6756
|
-
if (!external_node_fs_default().existsSync(packageJsonPath)) return;
|
|
6757
|
-
const pkg = parseJsonSafe(packageJsonPath);
|
|
6758
|
-
return pkg?.name === 'extension-develop' ? dir : void 0;
|
|
6759
|
-
} catch {
|
|
6760
|
-
return;
|
|
6761
|
-
}
|
|
6762
|
-
}
|
|
6763
|
-
function resolveWorkspaceDevelopRoot(startDir) {
|
|
6764
|
-
let currentDir = external_node_path_default().resolve(startDir);
|
|
6765
|
-
if (currentDir.split(external_node_path_default().sep).includes('node_modules')) return;
|
|
6766
|
-
for(let depth = 0; depth < 8; depth += 1){
|
|
6767
|
-
const candidate = external_node_path_default().join(currentDir, 'programs', 'develop');
|
|
6768
|
-
const resolved = resolveDevelopRootFromDir(candidate);
|
|
6769
|
-
if (resolved) return resolved;
|
|
6770
|
-
const parent = external_node_path_default().dirname(currentDir);
|
|
6771
|
-
if (parent === currentDir) break;
|
|
6772
|
-
currentDir = parent;
|
|
6773
|
-
}
|
|
6774
|
-
}
|
|
6775
|
-
function resolveInstalledDevelopRoot() {
|
|
6776
|
-
try {
|
|
6777
|
-
const packageJsonPath = extension_develop_runtime_require.resolve('extension-develop/package.json');
|
|
6778
|
-
return resolveDevelopRootFromDir(external_node_path_default().dirname(packageJsonPath));
|
|
6779
|
-
} catch {
|
|
6780
|
-
try {
|
|
6781
|
-
const entryPath = extension_develop_runtime_require.resolve('extension-develop');
|
|
6782
|
-
return resolveDevelopRootFromDir(external_node_path_default().dirname(external_node_path_default().dirname(entryPath)));
|
|
6783
|
-
} catch {
|
|
6784
|
-
return;
|
|
6785
|
-
}
|
|
6786
|
-
}
|
|
6787
|
-
}
|
|
6788
|
-
function resolvePreferredDevelopRoot(startDir) {
|
|
6789
|
-
const workspaceRoot = resolveWorkspaceDevelopRoot(startDir);
|
|
6790
|
-
if (workspaceRoot) return {
|
|
6791
|
-
root: workspaceRoot,
|
|
6792
|
-
source: 'workspace'
|
|
6793
|
-
};
|
|
6794
|
-
const envRoot = process.env.EXTENSION_DEVELOP_ROOT ? resolveDevelopRootFromDir(external_node_path_default().resolve(process.env.EXTENSION_DEVELOP_ROOT)) : void 0;
|
|
6795
|
-
if (envRoot) return {
|
|
6796
|
-
root: envRoot,
|
|
6797
|
-
source: 'env'
|
|
6798
|
-
};
|
|
6799
|
-
const installedRoot = resolveInstalledDevelopRoot();
|
|
6800
|
-
if (installedRoot) return {
|
|
6801
|
-
root: installedRoot,
|
|
6802
|
-
source: 'installed'
|
|
6803
|
-
};
|
|
6804
|
-
return {
|
|
6805
|
-
root: void 0,
|
|
6806
|
-
source: 'missing'
|
|
6807
|
-
};
|
|
6808
|
-
}
|
|
6809
|
-
function resolveDevelopDistEntry(root, name = 'module') {
|
|
6810
|
-
const base = external_node_path_default().join(root, 'dist', name);
|
|
6811
|
-
const candidates = [
|
|
6812
|
-
`${base}.mjs`,
|
|
6813
|
-
`${base}.cjs`,
|
|
6814
|
-
`${base}.js`,
|
|
6815
|
-
base
|
|
6816
|
-
];
|
|
6817
|
-
for (const candidate of candidates)if (external_node_fs_default().existsSync(candidate)) return candidate;
|
|
6818
|
-
}
|
|
6819
|
-
function resolveExtensionDevelopRoot(startDir = __dirname) {
|
|
6820
|
-
const { root, source } = resolvePreferredDevelopRoot(startDir);
|
|
6821
|
-
if (!root) throw new Error('Unable to locate the extension-develop runtime.');
|
|
6822
|
-
process.env.EXTENSION_DEVELOP_ROOT = root;
|
|
6823
|
-
if ('workspace' === source) process.env.EXTENSION_CREATE_DEVELOP_ROOT = root;
|
|
6824
|
-
return root;
|
|
6825
|
-
}
|
|
6826
|
-
function resolveExtensionDevelopVersion(startDir = __dirname, fallbackVersion) {
|
|
6827
|
-
try {
|
|
6828
|
-
const root = resolveExtensionDevelopRoot(startDir);
|
|
6829
|
-
const packageJsonPath = external_node_path_default().join(root, 'package.json');
|
|
6830
|
-
const pkg = parseJsonSafe(packageJsonPath);
|
|
6831
|
-
return pkg?.version || fallbackVersion || '0.0.0';
|
|
6832
|
-
} catch {
|
|
6833
|
-
return fallbackVersion || '0.0.0';
|
|
6834
|
-
}
|
|
6835
|
-
}
|
|
6836
|
-
async function importModule(filePath) {
|
|
6837
|
-
const mod = await import((0, external_node_url_namespaceObject.pathToFileURL)(filePath).href);
|
|
6838
|
-
return mod?.default && 'object' == typeof mod.default ? {
|
|
6839
|
-
...mod.default,
|
|
6840
|
-
...mod
|
|
6841
|
-
} : mod;
|
|
6842
|
-
}
|
|
6843
|
-
async function loadExtensionDevelopModule(startDir = __dirname) {
|
|
6844
|
-
const root = resolveExtensionDevelopRoot(startDir);
|
|
6845
|
-
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
6846
|
-
const distEntry = resolveDevelopDistEntry(root);
|
|
6847
|
-
if (distEntry) return importModule(distEntry);
|
|
6848
|
-
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
6849
|
-
return await import("extension-develop");
|
|
6850
|
-
}
|
|
6851
|
-
async function loadExtensionDevelopPreviewModule(startDir = __dirname) {
|
|
6852
|
-
const root = resolveExtensionDevelopRoot(startDir);
|
|
6853
|
-
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
6854
|
-
const previewEntry = resolveDevelopDistEntry(root, 'preview');
|
|
6855
|
-
if (previewEntry) return importModule(previewEntry);
|
|
6856
|
-
const fullEntry = resolveDevelopDistEntry(root);
|
|
6857
|
-
if (fullEntry) return importModule(fullEntry);
|
|
6858
|
-
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
6859
|
-
return await import("extension-develop/preview");
|
|
6860
|
-
}
|
|
6861
|
-
async function loadExtensionDevelopBridgeModule(startDir = __dirname) {
|
|
6862
|
-
const root = resolveExtensionDevelopRoot(startDir);
|
|
6863
|
-
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
6864
|
-
const bridgeEntry = resolveDevelopDistEntry(root, 'bridge');
|
|
6865
|
-
if (bridgeEntry) return importModule(bridgeEntry);
|
|
6866
|
-
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
6867
|
-
const bridgeSpecifier = 'extension-develop/bridge';
|
|
6868
|
-
return await import(bridgeSpecifier);
|
|
6869
|
-
}
|
|
6870
|
-
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
6871
6864
|
const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
|
|
6872
6865
|
const TEMPLATE_CORPUS_REF = 'cb6a25377bd9516a1e55447a2010537019851ab2';
|
|
6873
6866
|
const TEMPLATE_CORPUS_SLUGS = [
|
|
@@ -6931,7 +6924,7 @@ var __webpack_modules__ = {
|
|
|
6931
6924
|
"typescript",
|
|
6932
6925
|
'vue'
|
|
6933
6926
|
];
|
|
6934
|
-
const DEFAULT_TEMPLATE = "
|
|
6927
|
+
const DEFAULT_TEMPLATE = "typescript";
|
|
6935
6928
|
const BUNDLED_TEMPLATES = [
|
|
6936
6929
|
"javascript"
|
|
6937
6930
|
];
|
|
@@ -7093,6 +7086,9 @@ var __webpack_modules__ = {
|
|
|
7093
7086
|
function listTemplates() {
|
|
7094
7087
|
return TEMPLATE_GROUPS.flatMap((group)=>group.templates);
|
|
7095
7088
|
}
|
|
7089
|
+
function templateAliasFor(name) {
|
|
7090
|
+
return TEMPLATE_ALIASES.find((alias)=>alias.name === name);
|
|
7091
|
+
}
|
|
7096
7092
|
function wrapSlugs(slugs, indent, width) {
|
|
7097
7093
|
const lines = [];
|
|
7098
7094
|
let current = '';
|
|
@@ -7124,32 +7120,290 @@ var __webpack_modules__ = {
|
|
|
7124
7120
|
lines.push(` ${title('Aliases')}`);
|
|
7125
7121
|
for (const alias of TEMPLATE_ALIASES)lines.push(` ${slug(alias.name)} ${dim(`still works, ${alias.note}`)}`);
|
|
7126
7122
|
}
|
|
7127
|
-
return lines.join('\n');
|
|
7123
|
+
return lines.join('\n');
|
|
7124
|
+
}
|
|
7125
|
+
function renderCreateTemplateHelp() {
|
|
7126
|
+
const total = listTemplates().length;
|
|
7127
|
+
const dim = (text)=>external_pintor_default().gray(text);
|
|
7128
|
+
const defaultIsBundled = BUNDLED_TEMPLATES.includes(DEFAULT_TEMPLATE);
|
|
7129
|
+
return [
|
|
7130
|
+
'',
|
|
7131
|
+
external_pintor_default().underline(external_pintor_default().blue(`Templates (${total})`)),
|
|
7132
|
+
renderTemplateList(),
|
|
7133
|
+
'',
|
|
7134
|
+
` ${external_pintor_default().green('Default')}`,
|
|
7135
|
+
` ${external_pintor_default().blue(DEFAULT_TEMPLATE)} ${dim('is used when --template is omitted.')}`,
|
|
7136
|
+
...defaultIsBundled ? [
|
|
7137
|
+
dim(' It ships inside the CLI, so it scaffolds with no network.')
|
|
7138
|
+
] : [
|
|
7139
|
+
dim(' It downloads the catalog archive like every other name.')
|
|
7140
|
+
],
|
|
7141
|
+
'',
|
|
7142
|
+
` ${external_pintor_default().green('Everything else')}`,
|
|
7143
|
+
dim(' downloads the catalog archive at create time, so it needs the'),
|
|
7144
|
+
dim(' network and takes longer. A GitHub URL or a ZIP URL also works.'),
|
|
7145
|
+
` ${external_pintor_default().blue(TEMPLATE_CATALOG_URL)}`,
|
|
7146
|
+
''
|
|
7147
|
+
].join('\n');
|
|
7148
|
+
}
|
|
7149
|
+
const KNOWN_COMMANDS = new Set([
|
|
7150
|
+
'create',
|
|
7151
|
+
'dev',
|
|
7152
|
+
'start',
|
|
7153
|
+
'preview',
|
|
7154
|
+
'build',
|
|
7155
|
+
'install',
|
|
7156
|
+
'uninstall',
|
|
7157
|
+
'telemetry',
|
|
7158
|
+
'unknown'
|
|
7159
|
+
]);
|
|
7160
|
+
function detectInvokedCommand(argv) {
|
|
7161
|
+
for(let i = 2; i < argv.length; i += 1){
|
|
7162
|
+
const arg = argv[i];
|
|
7163
|
+
if (!(!arg || arg.startsWith('-'))) {
|
|
7164
|
+
if (KNOWN_COMMANDS.has(arg)) return arg;
|
|
7165
|
+
break;
|
|
7166
|
+
}
|
|
7167
|
+
}
|
|
7168
|
+
return 'unknown';
|
|
7169
|
+
}
|
|
7170
|
+
function readArgValue(argv, names) {
|
|
7171
|
+
for(let i = 2; i < argv.length; i += 1){
|
|
7172
|
+
const arg = argv[i];
|
|
7173
|
+
if (arg) for (const name of names){
|
|
7174
|
+
if (arg === name) {
|
|
7175
|
+
const next = argv[i + 1];
|
|
7176
|
+
return next && !next.startsWith('-') ? next : void 0;
|
|
7177
|
+
}
|
|
7178
|
+
if (arg.startsWith(`${name}=`)) return arg.slice(name.length + 1);
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
function advertisedTemplateName(value) {
|
|
7183
|
+
if (!value) return;
|
|
7184
|
+
const name = value.trim();
|
|
7185
|
+
if (!name) return;
|
|
7186
|
+
if (listTemplates().includes(name)) return name;
|
|
7187
|
+
if (templateAliasFor(name)) return name;
|
|
7188
|
+
}
|
|
7189
|
+
function telemetryCommandContext(command, argv = process.argv) {
|
|
7190
|
+
if ('create' !== command) return {};
|
|
7191
|
+
return {
|
|
7192
|
+
template: advertisedTemplateName(readArgValue(argv, [
|
|
7193
|
+
'--template',
|
|
7194
|
+
'-t'
|
|
7195
|
+
])),
|
|
7196
|
+
source: readArgValue(argv, [
|
|
7197
|
+
'--source'
|
|
7198
|
+
]) || 'cli'
|
|
7199
|
+
};
|
|
7200
|
+
}
|
|
7201
|
+
const consent = resolveTelemetryConsent(process.argv);
|
|
7202
|
+
const invoked = detectInvokedCommand(process.argv);
|
|
7203
|
+
const telemetry_cli_version = String(getCliPackageJson().version || '0.0.0');
|
|
7204
|
+
const telemetry = new Telemetry({
|
|
7205
|
+
app: 'extension',
|
|
7206
|
+
version: telemetry_cli_version,
|
|
7207
|
+
disabled: !consent.enabled
|
|
7208
|
+
});
|
|
7209
|
+
function getTelemetryConsent() {
|
|
7210
|
+
return consent;
|
|
7211
|
+
}
|
|
7212
|
+
function setTelemetryConsent(value) {
|
|
7213
|
+
const ok = writeConsent(value);
|
|
7214
|
+
const storage = resolveTelemetryStorage();
|
|
7215
|
+
return {
|
|
7216
|
+
ok,
|
|
7217
|
+
path: storage?.consentFile ?? null
|
|
7218
|
+
};
|
|
7219
|
+
}
|
|
7220
|
+
let tracked = false;
|
|
7221
|
+
function markTracked() {
|
|
7222
|
+
if (tracked) return false;
|
|
7223
|
+
tracked = true;
|
|
7224
|
+
return true;
|
|
7225
|
+
}
|
|
7226
|
+
function markCommandSuccess(command = invoked) {
|
|
7227
|
+
if (!markTracked()) return;
|
|
7228
|
+
telemetry.track('command_executed', {
|
|
7229
|
+
command,
|
|
7230
|
+
success: true,
|
|
7231
|
+
version: telemetry_cli_version,
|
|
7232
|
+
...telemetryCommandContext(command)
|
|
7233
|
+
});
|
|
7234
|
+
}
|
|
7235
|
+
function markCommandFailure(command = invoked) {
|
|
7236
|
+
if (!markTracked()) return;
|
|
7237
|
+
telemetry.track('command_failed', {
|
|
7238
|
+
command,
|
|
7239
|
+
success: false,
|
|
7240
|
+
version: telemetry_cli_version,
|
|
7241
|
+
...telemetryCommandContext(command)
|
|
7242
|
+
});
|
|
7243
|
+
}
|
|
7244
|
+
function printOptOutNoticeIfFirstRun() {
|
|
7245
|
+
if (!consent.enabled || 'default' !== consent.source) return;
|
|
7246
|
+
const storage = resolveTelemetryStorage();
|
|
7247
|
+
if (!storage) return;
|
|
7248
|
+
const written = writeConsent('enabled');
|
|
7249
|
+
if (!written) return;
|
|
7250
|
+
console.error(`${external_pintor_default().gray('⏵⏵⏵')} Extension.js collects anonymous, opt-out telemetry (two events: ${external_pintor_default().cyan('command_executed')} + ${external_pintor_default().cyan('command_failed')}). Disable with ${external_pintor_default().cyan('extension telemetry disable')}, ${external_pintor_default().cyan('EXTENSION_TELEMETRY=0')}, or ${external_pintor_default().cyan('--no-telemetry')}. See docs/TELEMETRY.md.`);
|
|
7251
|
+
}
|
|
7252
|
+
if (consent.enabled) {
|
|
7253
|
+
printOptOutNoticeIfFirstRun();
|
|
7254
|
+
process.on('beforeExit', async ()=>{
|
|
7255
|
+
if (!tracked) if ((process.exitCode ?? 0) === 0) markCommandSuccess();
|
|
7256
|
+
else markCommandFailure();
|
|
7257
|
+
await telemetry.flush();
|
|
7258
|
+
});
|
|
7259
|
+
process.on('uncaughtException', ()=>{
|
|
7260
|
+
markCommandFailure();
|
|
7261
|
+
});
|
|
7262
|
+
process.on('unhandledRejection', ()=>{
|
|
7263
|
+
markCommandFailure();
|
|
7264
|
+
});
|
|
7265
|
+
}
|
|
7266
|
+
const TELEMETRY_FLUSH_TIMEOUT_MS = 500;
|
|
7267
|
+
async function exitAfterDrain(code) {
|
|
7268
|
+
try {
|
|
7269
|
+
await Promise.race([
|
|
7270
|
+
telemetry.flush(),
|
|
7271
|
+
new Promise((resolve)=>setTimeout(resolve, TELEMETRY_FLUSH_TIMEOUT_MS).unref?.())
|
|
7272
|
+
]);
|
|
7273
|
+
} catch {}
|
|
7274
|
+
await Promise.all([
|
|
7275
|
+
process.stdout,
|
|
7276
|
+
process.stderr
|
|
7277
|
+
].map((stream)=>new Promise((resolve)=>{
|
|
7278
|
+
if (0 === stream.writableLength) return resolve();
|
|
7279
|
+
stream.write('', ()=>resolve());
|
|
7280
|
+
})));
|
|
7281
|
+
process.exit(code);
|
|
7282
|
+
}
|
|
7283
|
+
var external_node_module_ = __webpack_require__("node:module");
|
|
7284
|
+
const external_node_url_namespaceObject = require("node:url");
|
|
7285
|
+
const extension_develop_runtime_require = (0, external_node_module_.createRequire)(__rslib_import_meta_url__);
|
|
7286
|
+
function parseJsonSafe(filePath) {
|
|
7287
|
+
return JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf8'));
|
|
7288
|
+
}
|
|
7289
|
+
function resolveDevelopRootFromDir(dir) {
|
|
7290
|
+
try {
|
|
7291
|
+
const packageJsonPath = external_node_path_default().join(dir, 'package.json');
|
|
7292
|
+
if (!external_node_fs_default().existsSync(packageJsonPath)) return;
|
|
7293
|
+
const pkg = parseJsonSafe(packageJsonPath);
|
|
7294
|
+
return pkg?.name === 'extension-develop' ? dir : void 0;
|
|
7295
|
+
} catch {
|
|
7296
|
+
return;
|
|
7297
|
+
}
|
|
7298
|
+
}
|
|
7299
|
+
function resolveWorkspaceDevelopRoot(startDir) {
|
|
7300
|
+
let currentDir = external_node_path_default().resolve(startDir);
|
|
7301
|
+
if (currentDir.split(external_node_path_default().sep).includes('node_modules')) return;
|
|
7302
|
+
for(let depth = 0; depth < 8; depth += 1){
|
|
7303
|
+
const candidate = external_node_path_default().join(currentDir, 'programs', 'develop');
|
|
7304
|
+
const resolved = resolveDevelopRootFromDir(candidate);
|
|
7305
|
+
if (resolved) return resolved;
|
|
7306
|
+
const parent = external_node_path_default().dirname(currentDir);
|
|
7307
|
+
if (parent === currentDir) break;
|
|
7308
|
+
currentDir = parent;
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
function resolveInstalledDevelopRoot() {
|
|
7312
|
+
try {
|
|
7313
|
+
const packageJsonPath = extension_develop_runtime_require.resolve('extension-develop/package.json');
|
|
7314
|
+
return resolveDevelopRootFromDir(external_node_path_default().dirname(packageJsonPath));
|
|
7315
|
+
} catch {
|
|
7316
|
+
try {
|
|
7317
|
+
const entryPath = extension_develop_runtime_require.resolve('extension-develop');
|
|
7318
|
+
return resolveDevelopRootFromDir(external_node_path_default().dirname(external_node_path_default().dirname(entryPath)));
|
|
7319
|
+
} catch {
|
|
7320
|
+
return;
|
|
7321
|
+
}
|
|
7322
|
+
}
|
|
7323
|
+
}
|
|
7324
|
+
function resolvePreferredDevelopRoot(startDir) {
|
|
7325
|
+
const workspaceRoot = resolveWorkspaceDevelopRoot(startDir);
|
|
7326
|
+
if (workspaceRoot) return {
|
|
7327
|
+
root: workspaceRoot,
|
|
7328
|
+
source: 'workspace'
|
|
7329
|
+
};
|
|
7330
|
+
const envRoot = process.env.EXTENSION_DEVELOP_ROOT ? resolveDevelopRootFromDir(external_node_path_default().resolve(process.env.EXTENSION_DEVELOP_ROOT)) : void 0;
|
|
7331
|
+
if (envRoot) return {
|
|
7332
|
+
root: envRoot,
|
|
7333
|
+
source: 'env'
|
|
7334
|
+
};
|
|
7335
|
+
const installedRoot = resolveInstalledDevelopRoot();
|
|
7336
|
+
if (installedRoot) return {
|
|
7337
|
+
root: installedRoot,
|
|
7338
|
+
source: 'installed'
|
|
7339
|
+
};
|
|
7340
|
+
return {
|
|
7341
|
+
root: void 0,
|
|
7342
|
+
source: 'missing'
|
|
7343
|
+
};
|
|
7344
|
+
}
|
|
7345
|
+
function resolveDevelopDistEntry(root, name = 'module') {
|
|
7346
|
+
const base = external_node_path_default().join(root, 'dist', name);
|
|
7347
|
+
const candidates = [
|
|
7348
|
+
`${base}.mjs`,
|
|
7349
|
+
`${base}.cjs`,
|
|
7350
|
+
`${base}.js`,
|
|
7351
|
+
base
|
|
7352
|
+
];
|
|
7353
|
+
for (const candidate of candidates)if (external_node_fs_default().existsSync(candidate)) return candidate;
|
|
7354
|
+
}
|
|
7355
|
+
function resolveExtensionDevelopRoot(startDir = __dirname) {
|
|
7356
|
+
const { root, source } = resolvePreferredDevelopRoot(startDir);
|
|
7357
|
+
if (!root) throw new Error('Unable to locate the extension-develop runtime.');
|
|
7358
|
+
process.env.EXTENSION_DEVELOP_ROOT = root;
|
|
7359
|
+
if ('workspace' === source) process.env.EXTENSION_CREATE_DEVELOP_ROOT = root;
|
|
7360
|
+
return root;
|
|
7361
|
+
}
|
|
7362
|
+
function resolveExtensionDevelopVersion(startDir = __dirname, fallbackVersion) {
|
|
7363
|
+
try {
|
|
7364
|
+
const root = resolveExtensionDevelopRoot(startDir);
|
|
7365
|
+
const packageJsonPath = external_node_path_default().join(root, 'package.json');
|
|
7366
|
+
const pkg = parseJsonSafe(packageJsonPath);
|
|
7367
|
+
return pkg?.version || fallbackVersion || '0.0.0';
|
|
7368
|
+
} catch {
|
|
7369
|
+
return fallbackVersion || '0.0.0';
|
|
7370
|
+
}
|
|
7128
7371
|
}
|
|
7129
|
-
function
|
|
7130
|
-
const
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7372
|
+
async function importModule(filePath) {
|
|
7373
|
+
const mod = await import((0, external_node_url_namespaceObject.pathToFileURL)(filePath).href);
|
|
7374
|
+
return mod?.default && 'object' == typeof mod.default ? {
|
|
7375
|
+
...mod.default,
|
|
7376
|
+
...mod
|
|
7377
|
+
} : mod;
|
|
7378
|
+
}
|
|
7379
|
+
async function loadExtensionDevelopModule(startDir = __dirname) {
|
|
7380
|
+
const root = resolveExtensionDevelopRoot(startDir);
|
|
7381
|
+
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
7382
|
+
const distEntry = resolveDevelopDistEntry(root);
|
|
7383
|
+
if (distEntry) return importModule(distEntry);
|
|
7384
|
+
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
7385
|
+
return await import("extension-develop");
|
|
7386
|
+
}
|
|
7387
|
+
async function loadExtensionDevelopPreviewModule(startDir = __dirname) {
|
|
7388
|
+
const root = resolveExtensionDevelopRoot(startDir);
|
|
7389
|
+
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
7390
|
+
const previewEntry = resolveDevelopDistEntry(root, 'preview');
|
|
7391
|
+
if (previewEntry) return importModule(previewEntry);
|
|
7392
|
+
const fullEntry = resolveDevelopDistEntry(root);
|
|
7393
|
+
if (fullEntry) return importModule(fullEntry);
|
|
7394
|
+
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
7395
|
+
return await import("extension-develop/preview");
|
|
7396
|
+
}
|
|
7397
|
+
async function loadExtensionDevelopBridgeModule(startDir = __dirname) {
|
|
7398
|
+
const root = resolveExtensionDevelopRoot(startDir);
|
|
7399
|
+
const { source } = resolvePreferredDevelopRoot(startDir);
|
|
7400
|
+
const bridgeEntry = resolveDevelopDistEntry(root, 'bridge');
|
|
7401
|
+
if (bridgeEntry) return importModule(bridgeEntry);
|
|
7402
|
+
if ('workspace' === source) throw new Error(`Local extension-develop runtime is not built at ${external_node_path_default().join(root, 'dist')}. Run \`pnpm --filter extension-develop compile\` before invoking the local CLI.`);
|
|
7403
|
+
const bridgeSpecifier = 'extension-develop/bridge';
|
|
7404
|
+
return await import(bridgeSpecifier);
|
|
7152
7405
|
}
|
|
7406
|
+
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
7153
7407
|
function getLoggingPrefix(type) {
|
|
7154
7408
|
return (0, messaging.Pl)(type);
|
|
7155
7409
|
}
|
|
@@ -7856,9 +8110,135 @@ Cross-browser compatibility
|
|
|
7856
8110
|
function deprecatedOutputAlias(flag) {
|
|
7857
8111
|
return `${getLoggingPrefix('warn')} ${messages_code(flag)} is deprecated and maps to ${messages_code('--output')}.\nPass ${messages_code('--output')} ${messages_arg('<pretty|json>')} instead.`;
|
|
7858
8112
|
}
|
|
8113
|
+
const OPEN_SURFACE_NOUN = {
|
|
8114
|
+
popup: 'popup',
|
|
8115
|
+
sidebar: 'side panel',
|
|
8116
|
+
action: 'action popup'
|
|
8117
|
+
};
|
|
8118
|
+
function openSurfaceNoun(surface) {
|
|
8119
|
+
return OPEN_SURFACE_NOUN[surface] || surface;
|
|
8120
|
+
}
|
|
8121
|
+
function openSurfaceGestureStep(surface) {
|
|
8122
|
+
return `Click the extension's toolbar entry, or its row in the extensions menu, to open the ${openSurfaceNoun(surface)}.`;
|
|
8123
|
+
}
|
|
8124
|
+
function openSurfaceNeedsGesturePlain(surface) {
|
|
8125
|
+
return `Chromium opens the ${openSurfaceNoun(surface)} only in response to a user gesture, so extension open ${surface} can't open it from the command line.`;
|
|
8126
|
+
}
|
|
8127
|
+
function openSurfaceNeedsGesture(surface) {
|
|
8128
|
+
return `${getLoggingPrefix('error')} Chromium opens the ${openSurfaceNoun(surface)} only in response to a user gesture, so ${messages_code(`extension open ${surface}`)} can't open it from the command line.\n` + openSurfaceGestureStep(surface);
|
|
8129
|
+
}
|
|
8130
|
+
function sessionOnPort(browser, port) {
|
|
8131
|
+
return port ? `for ${browser} on port ${port}` : `for ${browser}`;
|
|
8132
|
+
}
|
|
8133
|
+
function controlDisabledInSessionPlain(browser, port, flag) {
|
|
8134
|
+
return `The dev session ${sessionOnPort(browser, port)} refused the controller because control is off in that session. Restart the dev session with ${flag} to turn it on, or run extension doctor when a session started with ${flag} still answers this way.`;
|
|
8135
|
+
}
|
|
8136
|
+
function controlDisabledInSession(browser, port, flag) {
|
|
8137
|
+
return `${getLoggingPrefix('error')} The dev session ${sessionOnPort(browser, port)} refused the controller because control is off in that session.\nRestart the dev session with ${messages_code(flag)} to turn it on, or run ${messages_code('extension doctor')} when a session started with ${messages_code(flag)} still answers this way.`;
|
|
8138
|
+
}
|
|
7859
8139
|
function noBrowserNotSupportedForCommand(command) {
|
|
7860
8140
|
return `${getLoggingPrefix('error')} ${messages_code('--no-browser')} is only supported for ${messages_code('dev')}, ${messages_code('start')}, and ${messages_code('preview')}.\n${messaging.Sc.label('GOT')} ${messages_code(command || '(none)')}`;
|
|
7861
8141
|
}
|
|
8142
|
+
let warnedDeprecatedAlias = false;
|
|
8143
|
+
function warnDeprecatedOutputAlias(flag) {
|
|
8144
|
+
if (warnedDeprecatedAlias) return;
|
|
8145
|
+
warnedDeprecatedAlias = true;
|
|
8146
|
+
console.error(deprecatedOutputAlias(flag));
|
|
8147
|
+
}
|
|
8148
|
+
function normalizeOutputFormat(value) {
|
|
8149
|
+
const v = String(value ?? '').trim().toLowerCase();
|
|
8150
|
+
return 'pretty' === v || 'json' === v ? v : void 0;
|
|
8151
|
+
}
|
|
8152
|
+
const normalize = normalizeOutputFormat;
|
|
8153
|
+
function isJsonOutput(opts) {
|
|
8154
|
+
return 'json' === resolveOutputFormat(opts);
|
|
8155
|
+
}
|
|
8156
|
+
function resolveOutputFormat(opts) {
|
|
8157
|
+
const direct = normalize(opts.output);
|
|
8158
|
+
if (direct) return direct;
|
|
8159
|
+
const aliases = [
|
|
8160
|
+
[
|
|
8161
|
+
'--format',
|
|
8162
|
+
opts.format
|
|
8163
|
+
],
|
|
8164
|
+
[
|
|
8165
|
+
'--wait-format',
|
|
8166
|
+
opts.waitFormat
|
|
8167
|
+
]
|
|
8168
|
+
];
|
|
8169
|
+
for (const [flag, value] of aliases){
|
|
8170
|
+
const resolved = normalize(value);
|
|
8171
|
+
if (resolved) {
|
|
8172
|
+
warnDeprecatedOutputAlias(flag);
|
|
8173
|
+
return resolved;
|
|
8174
|
+
}
|
|
8175
|
+
}
|
|
8176
|
+
return 'pretty';
|
|
8177
|
+
}
|
|
8178
|
+
function resolveSessionProjectPath(bridge, pathArg) {
|
|
8179
|
+
const inputPath = external_node_path_default().resolve(pathArg || process.cwd());
|
|
8180
|
+
const resolve = bridge?.resolveSessionProjectRoot;
|
|
8181
|
+
if ('function' != typeof resolve) return inputPath;
|
|
8182
|
+
try {
|
|
8183
|
+
const resolved = resolve(inputPath);
|
|
8184
|
+
return 'string' == typeof resolved && resolved ? resolved : inputPath;
|
|
8185
|
+
} catch {
|
|
8186
|
+
return inputPath;
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
function sessionFilePath(bridge, exportName, projectPath, browser, fileName) {
|
|
8190
|
+
const fn = bridge?.[exportName];
|
|
8191
|
+
if ('function' == typeof fn) try {
|
|
8192
|
+
const resolved = fn(projectPath, browser);
|
|
8193
|
+
if ('string' == typeof resolved && resolved) return resolved;
|
|
8194
|
+
} catch {}
|
|
8195
|
+
return external_node_path_default().join(projectPath, 'dist', 'extension-js', browser, fileName);
|
|
8196
|
+
}
|
|
8197
|
+
function sessionReadyPath(bridge, projectPath, browser) {
|
|
8198
|
+
return sessionFilePath(bridge, 'readyContractPath', projectPath, browser, 'ready.json');
|
|
8199
|
+
}
|
|
8200
|
+
function sessionLogsPath(bridge, projectPath, browser) {
|
|
8201
|
+
return sessionFilePath(bridge, 'logsPath', projectPath, browser, 'logs.ndjson');
|
|
8202
|
+
}
|
|
8203
|
+
function parseLogSinceLocal(value) {
|
|
8204
|
+
if (null == value || '' === value) return null;
|
|
8205
|
+
if ('number' == typeof value) return Number.isFinite(value) ? {
|
|
8206
|
+
seq: value
|
|
8207
|
+
} : void 0;
|
|
8208
|
+
const text = String(value).trim();
|
|
8209
|
+
if (/^\d+(?:\.\d+)?$/.test(text)) return {
|
|
8210
|
+
seq: Number(text)
|
|
8211
|
+
};
|
|
8212
|
+
const time = Date.parse(text);
|
|
8213
|
+
return Number.isFinite(time) ? {
|
|
8214
|
+
time
|
|
8215
|
+
} : void 0;
|
|
8216
|
+
}
|
|
8217
|
+
function isAfterSinceLocal(event, since) {
|
|
8218
|
+
if ('seq' in since) return !('number' == typeof event.seq && event.seq <= since.seq);
|
|
8219
|
+
const raw = event.timestamp;
|
|
8220
|
+
const time = 'number' == typeof raw ? raw : 'string' == typeof event.ts ? Date.parse(String(event.ts)) : NaN;
|
|
8221
|
+
return !Number.isFinite(time) || time > since.time;
|
|
8222
|
+
}
|
|
8223
|
+
function sinceHelpersFrom(bridge) {
|
|
8224
|
+
const candidate = bridge;
|
|
8225
|
+
return {
|
|
8226
|
+
parseLogSince: 'function' == typeof candidate?.parseLogSince ? candidate.parseLogSince : parseLogSinceLocal,
|
|
8227
|
+
isAfterSince: 'function' == typeof candidate?.isAfterSince ? candidate.isAfterSince : isAfterSinceLocal
|
|
8228
|
+
};
|
|
8229
|
+
}
|
|
8230
|
+
function parseLogLine(line) {
|
|
8231
|
+
let parsed;
|
|
8232
|
+
try {
|
|
8233
|
+
parsed = JSON.parse(line);
|
|
8234
|
+
} catch {
|
|
8235
|
+
return null;
|
|
8236
|
+
}
|
|
8237
|
+
return isLogEventLike(parsed) ? parsed : null;
|
|
8238
|
+
}
|
|
8239
|
+
function isLogEventLike(value) {
|
|
8240
|
+
return Boolean(value) && 'object' == typeof value && !Array.isArray(value);
|
|
8241
|
+
}
|
|
7862
8242
|
const LEVEL_ORDER = [
|
|
7863
8243
|
'error',
|
|
7864
8244
|
'warn',
|
|
@@ -7887,10 +8267,9 @@ Cross-browser compatibility
|
|
|
7887
8267
|
return candidates.some((c)=>re ? re.test(c) : c.includes(pattern));
|
|
7888
8268
|
};
|
|
7889
8269
|
}
|
|
7890
|
-
function makeFilter(opts) {
|
|
8270
|
+
function makeFilter(opts, since, helpers) {
|
|
7891
8271
|
const minLevel = String(opts.level || 'all').toLowerCase();
|
|
7892
8272
|
const contexts = opts.context && 'all' !== opts.context.toLowerCase() ? new Set(opts.context.split(',').map((c)=>c.trim())) : null;
|
|
7893
|
-
const sinceSeq = null != opts.since ? Number(opts.since) : null;
|
|
7894
8273
|
const urlMatches = opts.url ? makeUrlMatcher(opts.url) : null;
|
|
7895
8274
|
const tabId = null != opts.tab && '' !== opts.tab ? Number(opts.tab) : null;
|
|
7896
8275
|
return (event)=>{
|
|
@@ -7901,14 +8280,15 @@ Cross-browser compatibility
|
|
|
7901
8280
|
if ('all' !== minLevel && 'off' !== minLevel) {
|
|
7902
8281
|
if (levelRank(String(event.level || '')) > levelRank(minLevel)) return false;
|
|
7903
8282
|
}
|
|
7904
|
-
if (
|
|
8283
|
+
if (since && !helpers.isAfterSince(event, since)) return false;
|
|
7905
8284
|
if (urlMatches && !urlMatches(event)) return false;
|
|
7906
8285
|
if (null != tabId && Number.isFinite(tabId) && event.tabId !== tabId) return false;
|
|
7907
8286
|
return true;
|
|
7908
8287
|
};
|
|
7909
8288
|
}
|
|
7910
8289
|
function resolveFormat(opts) {
|
|
7911
|
-
|
|
8290
|
+
const requested = String(opts.output ?? '').trim().toLowerCase();
|
|
8291
|
+
if ('pretty' === requested || 'json' === requested || 'ndjson' === requested) return requested;
|
|
7912
8292
|
return process.stdout.isTTY ? 'pretty' : 'ndjson';
|
|
7913
8293
|
}
|
|
7914
8294
|
function printEvent(event, format) {
|
|
@@ -7929,18 +8309,28 @@ Cross-browser compatibility
|
|
|
7929
8309
|
console.log(JSON.stringify(frame));
|
|
7930
8310
|
}
|
|
7931
8311
|
}
|
|
7932
|
-
function logsFilePath(projectPath, browser) {
|
|
7933
|
-
return external_node_path_default().resolve(projectPath, 'dist', 'extension-js', browser, 'logs.ndjson');
|
|
7934
|
-
}
|
|
7935
8312
|
function registerLogsCommand(program) {
|
|
7936
|
-
program.command('logs').arguments('[project-path]').usage('[project-path] [options]').description(commandDescriptions.logs).option('--browser <chrome | chromium | edge | firefox>', 'which dist/extension-js/<browser> to read. Defaults to `chromium`').option('--follow', 'stream live via the control channel instead of printing and exiting').option('--context <list>', 'comma-separated contexts (background, content, popup, options, sidebar, devtools, page)').option('--level <off|error|warn|info|debug|trace|all>', 'minimum severity to show. Defaults to `all`').option('--signals-only', '[experimental] show only structured dx.signal diagnostics. No emitter ships yet, so this currently prints nothing').option('--since <seq|iso>', 'only show events after this sequence number').option('--url <glob|substring>', 'only events whose url/hostname matches (glob with * or plain substring)').option('--tab <id>', 'only events from this tab id').option('--output <pretty|json|ndjson>', 'output format. Defaults to pretty on a TTY, ndjson when piped').action(async (projectPathArg, options)=>{
|
|
7937
|
-
const
|
|
8313
|
+
program.command('logs').arguments('[project-path]').usage('[project-path] [options]').description(commandDescriptions.logs).option('--browser <chrome | chromium | edge | firefox>', 'which dist/extension-js/<browser> to read. Defaults to `chromium`').option('--follow', 'stream live via the control channel instead of printing and exiting').option('--context <list>', 'comma-separated contexts (background, content, popup, options, sidebar, devtools, page)').option('--level <off|error|warn|info|debug|trace|all>', 'minimum severity to show. Defaults to `all`').option('--signals-only', '[experimental] show only structured dx.signal diagnostics. No emitter ships yet, so this currently prints nothing').option('--since <seq|iso>', 'only show events after this sequence number or ISO timestamp').option('--url <glob|substring>', 'only events whose url/hostname matches (glob with * or plain substring)').option('--tab <id>', 'only events from this tab id').option('--output <pretty|json|ndjson>', 'output format. Defaults to pretty on a TTY, ndjson when piped').action(async (projectPathArg, options)=>{
|
|
8314
|
+
const bridge = await loadExtensionDevelopBridgeModule();
|
|
8315
|
+
const projectPath = resolveSessionProjectPath(bridge, projectPathArg);
|
|
7938
8316
|
const browser = options.browser || 'chromium';
|
|
7939
8317
|
const format = resolveFormat(options);
|
|
7940
|
-
const
|
|
8318
|
+
const helpers = sinceHelpersFrom(bridge);
|
|
8319
|
+
const since = helpers.parseLogSince(options.since);
|
|
8320
|
+
if (null != options.since && '' !== options.since && void 0 === since) {
|
|
8321
|
+
const message = `extension logs --since expects a sequence number or an ISO timestamp, got: ${options.since}`;
|
|
8322
|
+
console.error(message);
|
|
8323
|
+
if ('pretty' !== format) writeFrame(messaging.Pr.fail('logs', 'usage', {
|
|
8324
|
+
code: messaging.Lp.E_INVALID_OPTION,
|
|
8325
|
+
message,
|
|
8326
|
+
name: 'CliError'
|
|
8327
|
+
}));
|
|
8328
|
+
process.exit(1);
|
|
8329
|
+
}
|
|
8330
|
+
const matches = makeFilter(options, since ?? null, helpers);
|
|
7941
8331
|
if (options.signalsOnly) console.error("extension logs --signals-only: no signals emitter ships in this build, so dev sessions record no dx.signal events and this filter will print nothing.");
|
|
7942
8332
|
if (options.follow) return void await followLogs(projectPath, browser, format, matches);
|
|
7943
|
-
const file =
|
|
8333
|
+
const file = sessionLogsPath(bridge, projectPath, browser);
|
|
7944
8334
|
if (!external_node_fs_default().existsSync(file)) {
|
|
7945
8335
|
const message = `No logs found at ${file}. Start a dev session (extension dev) first, or pass --browser to match it.`;
|
|
7946
8336
|
console.error(message);
|
|
@@ -7953,21 +8343,17 @@ Cross-browser compatibility
|
|
|
7953
8343
|
}
|
|
7954
8344
|
const lines = external_node_fs_default().readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
7955
8345
|
for (const line of lines){
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
event = JSON.parse(line);
|
|
7959
|
-
} catch {
|
|
7960
|
-
continue;
|
|
7961
|
-
}
|
|
7962
|
-
if (matches(event)) printEvent(event, format);
|
|
8346
|
+
const event = parseLogLine(line);
|
|
8347
|
+
if (event && matches(event)) printEvent(event, format);
|
|
7963
8348
|
}
|
|
7964
8349
|
});
|
|
7965
8350
|
}
|
|
7966
8351
|
async function followLogs(projectPath, browser, format, matches) {
|
|
7967
|
-
const
|
|
8352
|
+
const bridge = await loadExtensionDevelopBridgeModule();
|
|
8353
|
+
const { BridgeConsumer, readReadyContract } = bridge;
|
|
7968
8354
|
const ready = readReadyContract(projectPath, browser);
|
|
7969
8355
|
if (!ready) {
|
|
7970
|
-
const message = `No active dev session control channel found for ${browser}. Run \`extension dev --browser=${browser}\` first.`;
|
|
8356
|
+
const message = `No active dev session control channel found for ${browser}. Looked at ${sessionReadyPath(bridge, projectPath, browser)}. Run \`extension dev --browser=${browser}\` first.`;
|
|
7971
8357
|
console.error(message);
|
|
7972
8358
|
if ('pretty' !== format) writeFrame(messaging.Pr.fail('logs', 'not-found', {
|
|
7973
8359
|
code: messaging.Lp.E_SESSION_NOT_FOUND,
|
|
@@ -7976,6 +8362,19 @@ Cross-browser compatibility
|
|
|
7976
8362
|
}));
|
|
7977
8363
|
process.exit(1);
|
|
7978
8364
|
}
|
|
8365
|
+
let settle = ()=>{};
|
|
8366
|
+
const settled = new Promise((resolve)=>{
|
|
8367
|
+
settle = resolve;
|
|
8368
|
+
});
|
|
8369
|
+
const refusals = new Set([
|
|
8370
|
+
bridge.CLOSE_BAD_INSTANCE,
|
|
8371
|
+
bridge.CLOSE_BAD_HELLO,
|
|
8372
|
+
bridge.CLOSE_CONTROL_UNAVAILABLE
|
|
8373
|
+
].filter((code)=>'number' == typeof code));
|
|
8374
|
+
const sessionStillNamed = ()=>{
|
|
8375
|
+
const current = readReadyContract(projectPath, browser);
|
|
8376
|
+
return Boolean(current) && 'stopped' !== current.status && current.instanceId === ready.instanceId && current.controlPort === ready.controlPort;
|
|
8377
|
+
};
|
|
7979
8378
|
const consumer = new BridgeConsumer({
|
|
7980
8379
|
controlPort: ready.controlPort,
|
|
7981
8380
|
instanceId: ready.instanceId,
|
|
@@ -7985,6 +8384,18 @@ Cross-browser compatibility
|
|
|
7985
8384
|
},
|
|
7986
8385
|
onGap: (gap)=>{
|
|
7987
8386
|
console.error(`… ${gap.dropped} event(s) dropped (${gap.reason}), stream is behind`);
|
|
8387
|
+
},
|
|
8388
|
+
onClose: (close)=>{
|
|
8389
|
+
if (!refusals.has(close.code) && sessionStillNamed()) return;
|
|
8390
|
+
consumer.close();
|
|
8391
|
+
const why = close.reason ? `${close.code}, ${close.reason}` : close.code;
|
|
8392
|
+
console.error(`extension logs --follow: the control channel closed (${why}) and the dev session is over.`);
|
|
8393
|
+
if ('pretty' !== format) console.log(JSON.stringify(messaging.Pr.ok('logs', 'closed', {
|
|
8394
|
+
closeCode: close.code,
|
|
8395
|
+
reason: close.reason,
|
|
8396
|
+
follow: true
|
|
8397
|
+
})));
|
|
8398
|
+
settle();
|
|
7988
8399
|
}
|
|
7989
8400
|
});
|
|
7990
8401
|
const shutdown = (signal)=>{
|
|
@@ -7998,7 +8409,7 @@ Cross-browser compatibility
|
|
|
7998
8409
|
process.on('SIGINT', ()=>shutdown('SIGINT'));
|
|
7999
8410
|
process.on('SIGTERM', ()=>shutdown('SIGTERM'));
|
|
8000
8411
|
consumer.start();
|
|
8001
|
-
await
|
|
8412
|
+
await settled;
|
|
8002
8413
|
}
|
|
8003
8414
|
function readRecentConsole(projectPath, browser, target, limit) {
|
|
8004
8415
|
const file = external_node_path_default().resolve(projectPath, 'dist', 'extension-js', browser, 'logs.ndjson');
|
|
@@ -8098,15 +8509,54 @@ Cross-browser compatibility
|
|
|
8098
8509
|
}
|
|
8099
8510
|
function fail(message, frame) {
|
|
8100
8511
|
console.error(message);
|
|
8101
|
-
if (frame && 'json' === frame.output) act_writeFrame(messaging.Pr.fail(frame.command, statusForCode(frame.code), {
|
|
8512
|
+
if (frame && 'json' === normalizeOutputFormat(frame.output)) act_writeFrame(messaging.Pr.fail(frame.command, statusForCode(frame.code), {
|
|
8102
8513
|
code: frame.code,
|
|
8103
|
-
message,
|
|
8104
|
-
name: 'CliError'
|
|
8514
|
+
message: frame.plain ?? message,
|
|
8515
|
+
name: 'CliError',
|
|
8516
|
+
...frame.hint ? {
|
|
8517
|
+
hint: frame.hint
|
|
8518
|
+
} : {}
|
|
8105
8519
|
}));
|
|
8106
8520
|
process.exit(1);
|
|
8107
8521
|
}
|
|
8522
|
+
function isChromiumFamily(browser) {
|
|
8523
|
+
return !/firefox|gecko|safari|webkit/i.test(browser);
|
|
8524
|
+
}
|
|
8525
|
+
function readSessionManifest(bridge, projectPath, browser) {
|
|
8526
|
+
const candidates = [];
|
|
8527
|
+
const readDocument = bridge?.readReadyContractDocument;
|
|
8528
|
+
if ('function' == typeof readDocument) try {
|
|
8529
|
+
const doc = readDocument(projectPath, browser);
|
|
8530
|
+
if (doc && 'string' == typeof doc.distPath) candidates.push(external_node_path_default().join(doc.distPath, 'manifest.json'));
|
|
8531
|
+
if (doc && 'string' == typeof doc.manifestPath) candidates.push(doc.manifestPath);
|
|
8532
|
+
} catch {}
|
|
8533
|
+
candidates.push(external_node_path_default().join(projectPath, 'manifest.json'));
|
|
8534
|
+
for (const file of candidates)try {
|
|
8535
|
+
const parsed = JSON.parse(external_node_fs_default().readFileSync(file, 'utf-8'));
|
|
8536
|
+
if (parsed && 'object' == typeof parsed && !Array.isArray(parsed)) return parsed;
|
|
8537
|
+
} catch {}
|
|
8538
|
+
}
|
|
8539
|
+
function manifestDeclaresPopup(manifest) {
|
|
8540
|
+
for (const [key, value] of Object.entries(manifest)){
|
|
8541
|
+
if (!/(?:^|:)(?:action|browser_action)$/.test(key)) continue;
|
|
8542
|
+
const popup = value?.default_popup;
|
|
8543
|
+
if ('string' == typeof popup && popup.trim()) return true;
|
|
8544
|
+
}
|
|
8545
|
+
return false;
|
|
8546
|
+
}
|
|
8547
|
+
function gestureRefusal(surface, bridge, projectPath, browser) {
|
|
8548
|
+
if (!isChromiumFamily(browser)) return;
|
|
8549
|
+
const gated = 'popup' === surface || 'sidebar' === surface || 'action' === surface && manifestDeclaresPopup(readSessionManifest(bridge, projectPath, browser) ?? {});
|
|
8550
|
+
if (!gated) return;
|
|
8551
|
+
return {
|
|
8552
|
+
message: openSurfaceNeedsGesture(surface),
|
|
8553
|
+
plain: openSurfaceNeedsGesturePlain(surface),
|
|
8554
|
+
code: messaging.Lp.E_USER_GESTURE_REQUIRED,
|
|
8555
|
+
hint: openSurfaceGestureStep(surface)
|
|
8556
|
+
};
|
|
8557
|
+
}
|
|
8108
8558
|
function printResult(result, output, command) {
|
|
8109
|
-
if ('json' === output) return void console.log(JSON.stringify(buildActEnvelope(command, result)));
|
|
8559
|
+
if ('json' === normalizeOutputFormat(output)) return void console.log(JSON.stringify(buildActEnvelope(command, result)));
|
|
8110
8560
|
if (result.ok) {
|
|
8111
8561
|
const value = result.value;
|
|
8112
8562
|
console.log('string' == typeof value ? value : JSON.stringify(value, null, 2));
|
|
@@ -8125,16 +8575,24 @@ Cross-browser compatibility
|
|
|
8125
8575
|
console.error(`${err.name}: ${err.message}${err.engine ? ` (engine: ${err.engine})` : ''}`);
|
|
8126
8576
|
}
|
|
8127
8577
|
async function runCommand(input) {
|
|
8128
|
-
const
|
|
8578
|
+
const bridge = await loadExtensionDevelopBridgeModule();
|
|
8579
|
+
const projectPath = resolveSessionProjectPath(bridge, input.projectPathArg);
|
|
8129
8580
|
const browser = input.opts.browser || 'chromium';
|
|
8130
|
-
const { BridgeController, readReadyContract, readControlToken } =
|
|
8581
|
+
const { BridgeController, readReadyContract, readControlToken } = bridge;
|
|
8131
8582
|
const outputFrame = {
|
|
8132
8583
|
command: input.command,
|
|
8133
8584
|
output: input.opts.output
|
|
8134
8585
|
};
|
|
8135
8586
|
const unlockFlag = 'eval' === input.op ? '--allow-eval' : '--allow-control';
|
|
8587
|
+
const refusal = input.preflight?.(bridge, projectPath, browser);
|
|
8588
|
+
if (refusal) fail(refusal.message, {
|
|
8589
|
+
...outputFrame,
|
|
8590
|
+
code: refusal.code,
|
|
8591
|
+
plain: refusal.plain,
|
|
8592
|
+
hint: refusal.hint
|
|
8593
|
+
});
|
|
8136
8594
|
const ready = readReadyContract(projectPath, browser);
|
|
8137
|
-
if (!ready) fail(`No active control channel found for ${browser}. Run \`extension dev --browser=${browser} ${unlockFlag}\` first.`, {
|
|
8595
|
+
if (!ready) fail(`No active control channel found for ${browser}. Looked at ${sessionReadyPath(bridge, projectPath, browser)}. Run \`extension dev --browser=${browser} ${unlockFlag}\` first.`, {
|
|
8138
8596
|
...outputFrame,
|
|
8139
8597
|
code: messaging.Lp.E_SESSION_NOT_FOUND
|
|
8140
8598
|
});
|
|
@@ -8150,6 +8608,12 @@ Cross-browser compatibility
|
|
|
8150
8608
|
} catch (err) {
|
|
8151
8609
|
controller.close();
|
|
8152
8610
|
const message = err?.message || 'could not connect to the control channel';
|
|
8611
|
+
const closeCode = err?.closeCode;
|
|
8612
|
+
if (4003 === closeCode || /code 4003\b/.test(message)) fail(controlDisabledInSession(browser, ready.controlPort, unlockFlag), {
|
|
8613
|
+
...outputFrame,
|
|
8614
|
+
code: messaging.Lp.E_CONTROL_DENIED,
|
|
8615
|
+
plain: controlDisabledInSessionPlain(browser, ready.controlPort, unlockFlag)
|
|
8616
|
+
});
|
|
8153
8617
|
fail(message, {
|
|
8154
8618
|
...outputFrame,
|
|
8155
8619
|
code: /code 40\d\d/.test(message) ? messaging.Lp.E_CONTROL_DENIED : messaging.Lp.E_CONTROL_UNAVAILABLE
|
|
@@ -8321,13 +8785,25 @@ Cross-browser compatibility
|
|
|
8321
8785
|
context
|
|
8322
8786
|
},
|
|
8323
8787
|
args,
|
|
8324
|
-
opts
|
|
8788
|
+
opts,
|
|
8789
|
+
preflight: (bridge, projectPath, browser)=>gestureRefusal(surface, bridge, projectPath, browser)
|
|
8325
8790
|
});
|
|
8326
8791
|
});
|
|
8327
8792
|
}
|
|
8328
8793
|
var safari_launch = __webpack_require__("./browsers/run-safari/safari-launch/index.ts");
|
|
8329
8794
|
var safari_config = __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
|
|
8330
8795
|
var safari_packager = __webpack_require__("./browsers/run-safari/safari-packager.ts");
|
|
8796
|
+
async function resolveConfigBrowser(projectPath, command) {
|
|
8797
|
+
try {
|
|
8798
|
+
const develop = await loadExtensionDevelopModule();
|
|
8799
|
+
if ('function' != typeof develop.loadCommandConfig) return;
|
|
8800
|
+
const config = await develop.loadCommandConfig(projectPath, command);
|
|
8801
|
+
const browser = config?.browser;
|
|
8802
|
+
return 'string' == typeof browser && browser.length > 0 ? browser : void 0;
|
|
8803
|
+
} catch {
|
|
8804
|
+
return;
|
|
8805
|
+
}
|
|
8806
|
+
}
|
|
8331
8807
|
function parseLogContexts(raw) {
|
|
8332
8808
|
if (!raw || 0 === String(raw).trim().length) return;
|
|
8333
8809
|
if ('all' === String(raw).trim().toLowerCase()) return;
|
|
@@ -8438,7 +8914,8 @@ Cross-browser compatibility
|
|
|
8438
8914
|
return null;
|
|
8439
8915
|
}
|
|
8440
8916
|
function registerBuildCommand(program) {
|
|
8441
|
-
program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari treats as unsigned: the extension then needs Develop \u25b8 Allow Unsigned Extensions re-ticked on every launch. A signed build is listed and stays enabled across restarts').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser
|
|
8917
|
+
program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', parseOptionalBoolean).option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', parseOptionalBoolean).option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', parseOptionalBoolean).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari treats as unsigned: the extension then needs Develop \u25b8 Allow Unsigned Extensions re-ticked on every launch. A signed build is listed and stays enabled across restarts').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser: cliBrowser, ...buildOptions })=>{
|
|
8918
|
+
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'build') ?? 'chromium';
|
|
8442
8919
|
if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
|
|
8443
8920
|
process.env.EXTENSION_DEBUG = '1';
|
|
8444
8921
|
process.env.EXTENSION_AUTHOR_MODE = 'true';
|
|
@@ -8502,7 +8979,7 @@ Cross-browser compatibility
|
|
|
8502
8979
|
}
|
|
8503
8980
|
}
|
|
8504
8981
|
const { extensionBuild } = await loadExtensionDevelopModule();
|
|
8505
|
-
const asJson =
|
|
8982
|
+
const asJson = isJsonOutput(buildOptions);
|
|
8506
8983
|
if (asJson) process.env.EXTENSION_OUTPUT = 'json';
|
|
8507
8984
|
const built = [];
|
|
8508
8985
|
const summaries = [];
|
|
@@ -8601,7 +9078,9 @@ Cross-browser compatibility
|
|
|
8601
9078
|
}
|
|
8602
9079
|
function registerCreateCommand(program) {
|
|
8603
9080
|
program.command('create').arguments('<project-name|project-path>').usage('<project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', `catalog name, GitHub URL, or ZIP URL to scaffold from; every catalog name is listed below (default: ${DEFAULT_TEMPLATE})`).option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default, pass --install to opt in)', parseOptionalBoolean, false).option('--source <source>', 'attribution tag for where this create was initiated (e.g. cli, templates); recorded in anonymous telemetry only').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addHelpText('after', renderCreateTemplateHelp()).action(async (pathOrRemoteUrl, { template, install, output })=>{
|
|
8604
|
-
const asJson =
|
|
9081
|
+
const asJson = isJsonOutput({
|
|
9082
|
+
output
|
|
9083
|
+
});
|
|
8605
9084
|
if (!process.env.EXTENSION_CREATE_DEVELOP_ROOT) try {
|
|
8606
9085
|
process.env.EXTENSION_CREATE_DEVELOP_ROOT = resolveExtensionDevelopRoot();
|
|
8607
9086
|
} catch {
|
|
@@ -8672,6 +9151,59 @@ Cross-browser compatibility
|
|
|
8672
9151
|
].includes(normalized)) return true;
|
|
8673
9152
|
}
|
|
8674
9153
|
}
|
|
9154
|
+
function scanArgvValue(argv, flag) {
|
|
9155
|
+
const equalArg = argv.find((arg)=>arg.startsWith(`${flag}=`));
|
|
9156
|
+
if (equalArg) return equalArg.slice(flag.length + 1);
|
|
9157
|
+
const flagIndex = argv.indexOf(flag);
|
|
9158
|
+
if (flagIndex >= 0) return argv[flagIndex + 1] || '';
|
|
9159
|
+
}
|
|
9160
|
+
function collectValuedLongFlags(program) {
|
|
9161
|
+
const flags = new Set();
|
|
9162
|
+
const visit = (command)=>{
|
|
9163
|
+
for (const option of command.options)if (option.long && (option.required || option.optional)) flags.add(option.long);
|
|
9164
|
+
for (const sub of command.commands)visit(sub);
|
|
9165
|
+
};
|
|
9166
|
+
visit(program);
|
|
9167
|
+
return flags;
|
|
9168
|
+
}
|
|
9169
|
+
function resolveCommandFromArgv(argv, valuedFlags = new Set()) {
|
|
9170
|
+
for(let i = 2; i < argv.length; i += 1){
|
|
9171
|
+
const arg = argv[i];
|
|
9172
|
+
if (arg.startsWith('-')) {
|
|
9173
|
+
if (valuedFlags.has(arg)) i += 1;
|
|
9174
|
+
continue;
|
|
9175
|
+
}
|
|
9176
|
+
return arg;
|
|
9177
|
+
}
|
|
9178
|
+
}
|
|
9179
|
+
function rewriteOutputAliasArgv(argv, valuedFlags = new Set()) {
|
|
9180
|
+
const index = argv.findIndex((arg)=>'--format' === arg || arg.startsWith('--format='));
|
|
9181
|
+
if (index < 0) return {
|
|
9182
|
+
argv,
|
|
9183
|
+
rewritten: false
|
|
9184
|
+
};
|
|
9185
|
+
const next = [
|
|
9186
|
+
...argv
|
|
9187
|
+
];
|
|
9188
|
+
const tokens = [];
|
|
9189
|
+
if (next[index].startsWith('--format=')) {
|
|
9190
|
+
tokens.push(`--output=${next[index].slice(9)}`);
|
|
9191
|
+
next.splice(index, 1);
|
|
9192
|
+
} else {
|
|
9193
|
+
tokens.push('--output');
|
|
9194
|
+
const value = next[index + 1];
|
|
9195
|
+
next.splice(index, void 0 === value || value.startsWith('-') ? 1 : 2);
|
|
9196
|
+
if (void 0 !== value && !value.startsWith('-')) tokens.push(value);
|
|
9197
|
+
}
|
|
9198
|
+
const command = resolveCommandFromArgv(next, valuedFlags);
|
|
9199
|
+
const commandIndex = command ? next.indexOf(command, 2) : -1;
|
|
9200
|
+
if (commandIndex >= index) next.splice(commandIndex + 1, 0, ...tokens);
|
|
9201
|
+
else next.splice(index, 0, ...tokens);
|
|
9202
|
+
return {
|
|
9203
|
+
argv: next,
|
|
9204
|
+
rewritten: true
|
|
9205
|
+
};
|
|
9206
|
+
}
|
|
8675
9207
|
const FRAMED_FLAG = 'extensionEnvelopePrinted';
|
|
8676
9208
|
function markErrorFramed(err) {
|
|
8677
9209
|
if (err && 'object' == typeof err) try {
|
|
@@ -8682,11 +9214,7 @@ Cross-browser compatibility
|
|
|
8682
9214
|
return Boolean(err && 'object' == typeof err && true === err[FRAMED_FLAG]);
|
|
8683
9215
|
}
|
|
8684
9216
|
function wantsJsonOutput(argv) {
|
|
8685
|
-
|
|
8686
|
-
if (equalArg) return 'json' === equalArg.slice(9).trim().toLowerCase();
|
|
8687
|
-
const flagIndex = argv.indexOf('--output');
|
|
8688
|
-
if (flagIndex >= 0) return 'json' === String(argv[flagIndex + 1] || '').trim().toLowerCase();
|
|
8689
|
-
return false;
|
|
9217
|
+
return 'json' === normalizeOutputFormat(scanArgvValue(argv, '--output'));
|
|
8690
9218
|
}
|
|
8691
9219
|
function isCommanderError(err) {
|
|
8692
9220
|
return Boolean(err && 'object' == typeof err && 'string' == typeof err.code && String(err.code).startsWith('commander.'));
|
|
@@ -8784,16 +9312,14 @@ Cross-browser compatibility
|
|
|
8784
9312
|
console.log(JSON.stringify(frame));
|
|
8785
9313
|
}
|
|
8786
9314
|
}
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
return;
|
|
8796
|
-
}
|
|
9315
|
+
function geckoBinaryOption() {
|
|
9316
|
+
return new external_commander_namespaceObject.Option('--gecko-binary <path-to-binary>', 'specify a path to the Gecko binary (alias: --firefox-binary). This option overrides the --browser setting. Defaults to the system default');
|
|
9317
|
+
}
|
|
9318
|
+
function firefoxBinaryAliasOption() {
|
|
9319
|
+
return new external_commander_namespaceObject.Option('--firefox-binary <path-to-binary>').hideHelp();
|
|
9320
|
+
}
|
|
9321
|
+
function cliGeckoBinary(opts) {
|
|
9322
|
+
return opts.geckoBinary ?? opts.firefoxBinary;
|
|
8797
9323
|
}
|
|
8798
9324
|
async function resolveNoBrowser(projectPath, command) {
|
|
8799
9325
|
if ('1' === process.env.EXTENSION_CLI_NO_BROWSER) return true;
|
|
@@ -8806,38 +9332,6 @@ Cross-browser compatibility
|
|
|
8806
9332
|
return false;
|
|
8807
9333
|
}
|
|
8808
9334
|
}
|
|
8809
|
-
let warnedDeprecatedAlias = false;
|
|
8810
|
-
function warnDeprecatedOutputAlias(flag) {
|
|
8811
|
-
if (warnedDeprecatedAlias) return;
|
|
8812
|
-
warnedDeprecatedAlias = true;
|
|
8813
|
-
console.error(deprecatedOutputAlias(flag));
|
|
8814
|
-
}
|
|
8815
|
-
function normalize(value) {
|
|
8816
|
-
const v = String(value ?? '').trim().toLowerCase();
|
|
8817
|
-
return 'pretty' === v || 'json' === v ? v : void 0;
|
|
8818
|
-
}
|
|
8819
|
-
function resolveOutputFormat(opts) {
|
|
8820
|
-
const direct = normalize(opts.output);
|
|
8821
|
-
if (direct) return direct;
|
|
8822
|
-
const aliases = [
|
|
8823
|
-
[
|
|
8824
|
-
'--format',
|
|
8825
|
-
opts.format
|
|
8826
|
-
],
|
|
8827
|
-
[
|
|
8828
|
-
'--wait-format',
|
|
8829
|
-
opts.waitFormat
|
|
8830
|
-
]
|
|
8831
|
-
];
|
|
8832
|
-
for (const [flag, value] of aliases){
|
|
8833
|
-
const resolved = normalize(value);
|
|
8834
|
-
if (resolved) {
|
|
8835
|
-
warnDeprecatedOutputAlias(flag);
|
|
8836
|
-
return resolved;
|
|
8837
|
-
}
|
|
8838
|
-
}
|
|
8839
|
-
return 'pretty';
|
|
8840
|
-
}
|
|
8841
9335
|
const POLL_INTERVAL_MS = 2000;
|
|
8842
9336
|
const HARD_EXIT_GRACE_MS = 5000;
|
|
8843
9337
|
function isProcessAlive(pid) {
|
|
@@ -8897,9 +9391,17 @@ Cross-browser compatibility
|
|
|
8897
9391
|
if (!value) return false;
|
|
8898
9392
|
return /^https?:\/\//i.test(value);
|
|
8899
9393
|
}
|
|
8900
|
-
function resolveProjectPath(pathOrRemoteUrl) {
|
|
8901
|
-
|
|
8902
|
-
|
|
9394
|
+
async function resolveProjectPath(pathOrRemoteUrl) {
|
|
9395
|
+
let bridge;
|
|
9396
|
+
try {
|
|
9397
|
+
bridge = await loadExtensionDevelopBridgeModule();
|
|
9398
|
+
} catch {
|
|
9399
|
+
bridge = void 0;
|
|
9400
|
+
}
|
|
9401
|
+
return {
|
|
9402
|
+
projectPath: resolveSessionProjectPath(bridge, pathOrRemoteUrl),
|
|
9403
|
+
bridge
|
|
9404
|
+
};
|
|
8903
9405
|
}
|
|
8904
9406
|
function parseWaitTimeoutMs(value) {
|
|
8905
9407
|
const fallback = 60000;
|
|
@@ -8911,7 +9413,7 @@ Cross-browser compatibility
|
|
|
8911
9413
|
return fallback;
|
|
8912
9414
|
}
|
|
8913
9415
|
function parseWaitFormat(value) {
|
|
8914
|
-
return
|
|
9416
|
+
return normalizeOutputFormat(value) ?? 'pretty';
|
|
8915
9417
|
}
|
|
8916
9418
|
class WaitModeError extends Error {
|
|
8917
9419
|
constructor(message, code){
|
|
@@ -8966,7 +9468,7 @@ Cross-browser compatibility
|
|
|
8966
9468
|
return false;
|
|
8967
9469
|
}
|
|
8968
9470
|
async function waitForReadyContract(options) {
|
|
8969
|
-
const readyPath =
|
|
9471
|
+
const readyPath = sessionReadyPath(options.bridge, options.projectPath, options.browser);
|
|
8970
9472
|
const start = Date.now();
|
|
8971
9473
|
while(Date.now() - start < options.timeoutMs){
|
|
8972
9474
|
if (external_node_fs_.existsSync(readyPath)) try {
|
|
@@ -9002,7 +9504,7 @@ Cross-browser compatibility
|
|
|
9002
9504
|
}
|
|
9003
9505
|
async function runWaitMode(options) {
|
|
9004
9506
|
if (isHttpUrl(options.pathOrRemoteUrl)) throw new WaitModeError('--wait requires a local project path (remote URLs are not supported)', messaging.Lp.E_ARGS);
|
|
9005
|
-
const projectPath = resolveProjectPath(options.pathOrRemoteUrl);
|
|
9507
|
+
const { projectPath, bridge } = await resolveProjectPath(options.pathOrRemoteUrl);
|
|
9006
9508
|
const timeoutMs = parseWaitTimeoutMs(options.waitTimeout);
|
|
9007
9509
|
const format = parseWaitFormat(options.waitFormat);
|
|
9008
9510
|
const results = [];
|
|
@@ -9010,6 +9512,7 @@ Cross-browser compatibility
|
|
|
9010
9512
|
const payload = await waitForReadyContract({
|
|
9011
9513
|
command: options.command,
|
|
9012
9514
|
projectPath,
|
|
9515
|
+
bridge,
|
|
9013
9516
|
browser,
|
|
9014
9517
|
timeoutMs
|
|
9015
9518
|
});
|
|
@@ -9041,7 +9544,7 @@ Cross-browser compatibility
|
|
|
9041
9544
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
9042
9545
|
}
|
|
9043
9546
|
function registerDevCommand(program) {
|
|
9044
|
-
program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser do not launch the browser (dev server still starts)\n --no-reload emit a dev-mode dist without the content-script reload runtime; tabs need manual reload to see changes\n --wait wait for ready contract and exit; pair with --output json for machine output\n").option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only; no live reload)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').
|
|
9547
|
+
program.command('dev').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.dev).addHelpText('after', "\nAdditional options:\n --no-browser do not launch the browser (dev server still starts)\n --no-reload emit a dev-mode dist without the content-script reload runtime; tabs need manual reload to see changes\n --wait wait for ready contract and exit; pair with --output json for machine output\n").option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`-b, --browser <${BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds and opens a Safari app via Xcode (macOS only; no live reload)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--safari-binary <path-to-binary>', 'specify the Safari binary to open after packaging (safari targets only)').option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari treats as unsigned: the extension then needs Develop \u25b8 Allow Unsigned Extensions re-ticked on every launch. A signed build is listed and stays enabled across restarts').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', parseOptionalBoolean).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', 'do not open the browser automatically (default: open)').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).option('--allow-control', 'enable the agent-bridge control channel for bounded act (storage/reload/open): see `extension reload|storage|open`').option('--allow-eval', 'additionally enable `extension eval` (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--parent-pid <pid>', 'exit when the given process dies. For wrappers that spawn `extension dev`, so a leaked dev server can never outlive its owner').action(async (pathOrRemoteUrl, options, command)=>{
|
|
9045
9548
|
const { browser: cliBrowser, ...devOptions } = options;
|
|
9046
9549
|
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'dev') ?? 'chromium';
|
|
9047
9550
|
if (devOptions.debug || devOptions.author || devOptions.authorMode) {
|
|
@@ -9175,7 +9678,7 @@ Cross-browser compatibility
|
|
|
9175
9678
|
profile: (0, resolve_profile.Md)(devOptions.profile),
|
|
9176
9679
|
browser: vendor,
|
|
9177
9680
|
chromiumBinary: devOptions.chromiumBinary,
|
|
9178
|
-
geckoBinary: devOptions
|
|
9681
|
+
geckoBinary: cliGeckoBinary(devOptions),
|
|
9179
9682
|
polyfill: explicitCliValue(command, 'polyfill', explicitOptionalBoolean(devOptions.polyfill)),
|
|
9180
9683
|
noOpen: explicitNoOpen,
|
|
9181
9684
|
macOsOnly: opts.macosOnly,
|
|
@@ -9244,13 +9747,12 @@ Cross-browser compatibility
|
|
|
9244
9747
|
return [];
|
|
9245
9748
|
}
|
|
9246
9749
|
}
|
|
9247
|
-
function resolveDoctorBrowser(
|
|
9750
|
+
function resolveDoctorBrowser(projectPath, optsBrowser) {
|
|
9248
9751
|
if (optsBrowser) return {
|
|
9249
9752
|
browser: optsBrowser,
|
|
9250
9753
|
sessionBrowsers: []
|
|
9251
9754
|
};
|
|
9252
|
-
const
|
|
9253
|
-
const sessionBrowsers = listSessionBrowsers(projectPath);
|
|
9755
|
+
const sessionBrowsers = listSessionBrowsers(external_node_path_default().resolve(projectPath || process.cwd()));
|
|
9254
9756
|
if (1 === sessionBrowsers.length) return {
|
|
9255
9757
|
browser: sessionBrowsers[0],
|
|
9256
9758
|
sessionBrowsers
|
|
@@ -9269,8 +9771,9 @@ Cross-browser compatibility
|
|
|
9269
9771
|
};
|
|
9270
9772
|
}
|
|
9271
9773
|
async function runDoctor(projectPathArg, opts) {
|
|
9272
|
-
const
|
|
9273
|
-
const
|
|
9774
|
+
const bridge = await loadExtensionDevelopBridgeModule();
|
|
9775
|
+
const projectPath = resolveSessionProjectPath(bridge, projectPathArg);
|
|
9776
|
+
const { browser, sessionBrowsers } = resolveDoctorBrowser(projectPath, opts.browser);
|
|
9274
9777
|
const results = [];
|
|
9275
9778
|
if (sessionBrowsers.length > 1) results.push({
|
|
9276
9779
|
check: 'session-resolution',
|
|
@@ -9285,13 +9788,13 @@ Cross-browser compatibility
|
|
|
9285
9788
|
detail: `skipped: blocked by ${blockedBy}`
|
|
9286
9789
|
});
|
|
9287
9790
|
};
|
|
9288
|
-
const { BridgeController, readReadyContract, readControlToken, readPersistedControlPort, controlPortFilePath } =
|
|
9791
|
+
const { BridgeController, readReadyContract, readControlToken, readPersistedControlPort, controlPortFilePath } = bridge;
|
|
9289
9792
|
const ready = readReadyContract(projectPath, browser);
|
|
9290
9793
|
if (!ready) {
|
|
9291
9794
|
results.push({
|
|
9292
9795
|
check: 'ready-contract',
|
|
9293
9796
|
status: 'fail',
|
|
9294
|
-
detail: `no ready contract at
|
|
9797
|
+
detail: `no ready contract at ${sessionReadyPath(bridge, projectPath, browser)}`,
|
|
9295
9798
|
remediation: `Start a dev session first: extension dev --browser=${browser} --allow-control (add --allow-eval for the eval verb)`
|
|
9296
9799
|
});
|
|
9297
9800
|
for (const check of [
|
|
@@ -9392,7 +9895,7 @@ Cross-browser compatibility
|
|
|
9392
9895
|
detail = 'refused: ready.json instanceId no longer matches the live server';
|
|
9393
9896
|
remediation = "A newer session overwrote the contract, or this dist belongs to another session, re-read ready.json or restart the dev session";
|
|
9394
9897
|
} else if ('4003' === code) {
|
|
9395
|
-
detail = 'refused:
|
|
9898
|
+
detail = 'refused: control is off in the session that answered';
|
|
9396
9899
|
remediation = `Restart with control enabled: extension dev --browser=${browser} --allow-control`;
|
|
9397
9900
|
}
|
|
9398
9901
|
results.push({
|
|
@@ -9513,8 +10016,8 @@ Cross-browser compatibility
|
|
|
9513
10016
|
browser: messaging.Lp.E_BROWSER_LAUNCH
|
|
9514
10017
|
};
|
|
9515
10018
|
function registerDoctorCommand(program) {
|
|
9516
|
-
program.command('doctor').argument('[project-path]', 'path to the extension project root').option('--browser <chrome | chromium | edge | firefox>', 'which session to diagnose (defaults to the single live session, else chromium)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').description(commandDescriptions.doctor).action(async (projectPathArg, opts)=>{
|
|
9517
|
-
const asJson =
|
|
10019
|
+
program.command('doctor').argument('[project-path]', 'path to the extension project root or the folder holding its manifest').option('--browser <chrome | chromium | edge | firefox>', 'which session to diagnose (defaults to the single live session, else chromium)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').description(commandDescriptions.doctor).action(async (projectPathArg, opts)=>{
|
|
10020
|
+
const asJson = isJsonOutput(opts);
|
|
9518
10021
|
let results;
|
|
9519
10022
|
try {
|
|
9520
10023
|
results = await runDoctor(projectPathArg, opts);
|
|
@@ -9596,7 +10099,7 @@ Cross-browser compatibility
|
|
|
9596
10099
|
}
|
|
9597
10100
|
function registerInstallCommand(program) {
|
|
9598
10101
|
program.command('install').arguments('[browser-name]').usage('[browser-name] [options]').description(commandDescriptions.install).option(`--browser <${MANAGED_INSTALL_TARGETS_HELP}>`, 'override the positional browser name. Supports comma-separated values and `all`.').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').action(async (browserArg, options)=>{
|
|
9599
|
-
const asJson =
|
|
10102
|
+
const asJson = isJsonOutput(options);
|
|
9600
10103
|
const named = Boolean(options.browser || browserArg);
|
|
9601
10104
|
const selectedBrowser = options.browser || browserArg || 'chromium';
|
|
9602
10105
|
const browserList = installTargets(selectedBrowser);
|
|
@@ -9636,7 +10139,9 @@ Cross-browser compatibility
|
|
|
9636
10139
|
}));
|
|
9637
10140
|
});
|
|
9638
10141
|
program.command('uninstall').usage('<browser-name> | --all | --where').description(commandDescriptions.uninstall).option(`--browser <${MANAGED_INSTALL_TARGETS_HELP}>`, 'browser(s) to uninstall. Supports comma-separated values and `all`.').option('--all', 'remove all managed browser binaries').option('--where', 'print the resolved managed browser cache root').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').argument('[browser-name]').action(async (browserArg, { browser, all, where, output })=>{
|
|
9639
|
-
const asJson =
|
|
10142
|
+
const asJson = isJsonOutput({
|
|
10143
|
+
output
|
|
10144
|
+
});
|
|
9640
10145
|
const named = Boolean(browserArg || browser);
|
|
9641
10146
|
const selected = all || 'all' === browserArg || 'all' === browser ? 'all' : browser || browserArg;
|
|
9642
10147
|
const { extensionUninstall, getManagedBrowsersCacheRoot, getManagedBrowserInstallDir } = await import("extension-install");
|
|
@@ -9704,14 +10209,15 @@ Cross-browser compatibility
|
|
|
9704
10209
|
'Manifest file not found'
|
|
9705
10210
|
];
|
|
9706
10211
|
function registerPreviewCommand(program) {
|
|
9707
|
-
program.command('preview').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.preview).addHelpText('after', '\nAdditional option:\n --no-browser do not launch the browser\n').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').
|
|
9708
|
-
const { browser
|
|
10212
|
+
program.command('preview').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.preview).addHelpText('after', '\nAdditional option:\n --no-browser do not launch the browser\n').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--output-path <dir>', 'path to an existing unpacked extension directory. Defaults to dist/<browser> when available').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, options, command)=>{
|
|
10213
|
+
const { browser: cliBrowser, ...previewOptions } = options;
|
|
10214
|
+
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'preview') ?? 'chromium';
|
|
9709
10215
|
if (previewOptions.debug || previewOptions.author || previewOptions.authorMode) {
|
|
9710
10216
|
process.env.EXTENSION_DEBUG = '1';
|
|
9711
10217
|
process.env.EXTENSION_AUTHOR_MODE = 'true';
|
|
9712
10218
|
if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
|
|
9713
10219
|
}
|
|
9714
|
-
const asJson =
|
|
10220
|
+
const asJson = isJsonOutput(previewOptions);
|
|
9715
10221
|
if (asJson) process.env.EXTENSION_OUTPUT = 'json';
|
|
9716
10222
|
const emit = (frame)=>{
|
|
9717
10223
|
console.log(JSON.stringify(frame));
|
|
@@ -9756,7 +10262,7 @@ Cross-browser compatibility
|
|
|
9756
10262
|
profile: (0, resolve_profile.Md)(previewOptions.profile),
|
|
9757
10263
|
browser: vendor,
|
|
9758
10264
|
chromiumBinary: previewOptions.chromiumBinary,
|
|
9759
|
-
geckoBinary: previewOptions
|
|
10265
|
+
geckoBinary: cliGeckoBinary(previewOptions),
|
|
9760
10266
|
startingUrl: previewOptions.startingUrl,
|
|
9761
10267
|
port: previewOptions.port,
|
|
9762
10268
|
noBrowser: await resolveNoBrowser(pathOrRemoteUrl || process.cwd(), 'preview'),
|
|
@@ -9882,7 +10388,7 @@ Cross-browser compatibility
|
|
|
9882
10388
|
}
|
|
9883
10389
|
function registerPublishCommand(program) {
|
|
9884
10390
|
program.command('publish').arguments('[project-path]').usage('[project-path] [options]').description(commandDescriptions.publish).option('--token <token>', 'platform access token (or EXTENSION_DEV_TOKEN, or the stored login)').option('--api <url>', 'platform base URL (or EXTENSION_DEV_API_URL)').option('--ttl <hours>', 'share-link lifetime in hours (1–168, default 24)').option('--build-sha <sha>', 'pin the share URL to a specific build').option('--project <slug>', 'name the project this publish is for, when it is not the directory you are in').option('--output <pretty|json>', 'output format (default pretty)').action(async (projectPathArg, opts)=>{
|
|
9885
|
-
const asJson =
|
|
10391
|
+
const asJson = isJsonOutput(opts);
|
|
9886
10392
|
const failWith = async (status, error, prose, hint)=>{
|
|
9887
10393
|
if (asJson) console.log(JSON.stringify(messaging.Pr.fail('publish', status, error, hint ? {
|
|
9888
10394
|
hint
|
|
@@ -9968,8 +10474,9 @@ Cross-browser compatibility
|
|
|
9968
10474
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
9969
10475
|
}
|
|
9970
10476
|
function registerStartCommand(program) {
|
|
9971
|
-
program.command('start').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.start).addHelpText('after', '\nAdditional options:\n --no-browser do not launch the browser (build still runs)\n --wait wait for ready contract and exit; pair with --output json for machine output\n').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').
|
|
9972
|
-
const { browser
|
|
10477
|
+
program.command('start').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.start).addHelpText('after', '\nAdditional options:\n --no-browser do not launch the browser (build still runs)\n --wait wait for ready contract and exit; pair with --output json for machine output\n').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`--browser <${NO_SAFARI_BROWSER_TARGETS_HELP}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`', parseOptionalBoolean).option('--no-polyfill', 'disable the cross-browser polyfill').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'connectable host the browser (HMR + reload bridge) dials when it differs from the bind host (e.g. a remote/devcontainer). Defaults to the bind host, or 127.0.0.1 when bound to 0.0.0.0').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', parseOptionalBoolean).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, options, command)=>{
|
|
10478
|
+
const { browser: cliBrowser, ...startOptions } = options;
|
|
10479
|
+
const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'start') ?? 'chromium';
|
|
9973
10480
|
if (startOptions.debug || startOptions.author || startOptions.authorMode) {
|
|
9974
10481
|
process.env.EXTENSION_DEBUG = '1';
|
|
9975
10482
|
process.env.EXTENSION_AUTHOR_MODE = 'true';
|
|
@@ -10069,7 +10576,7 @@ Cross-browser compatibility
|
|
|
10069
10576
|
profile: (0, resolve_profile.Md)(startOptions.profile),
|
|
10070
10577
|
browser: vendor,
|
|
10071
10578
|
chromiumBinary: startOptions.chromiumBinary,
|
|
10072
|
-
geckoBinary: startOptions
|
|
10579
|
+
geckoBinary: cliGeckoBinary(startOptions),
|
|
10073
10580
|
startingUrl: startOptions.startingUrl,
|
|
10074
10581
|
port: startOptions.port,
|
|
10075
10582
|
host: startOptions.host,
|
|
@@ -10090,7 +10597,7 @@ Cross-browser compatibility
|
|
|
10090
10597
|
function registerTelemetryCommand(program) {
|
|
10091
10598
|
program.command('telemetry').argument('[action]', 'enable | disable | status (default: status)').description(commandDescriptions.telemetry).option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').action(async (action, opts = {})=>{
|
|
10092
10599
|
const normalized = String(action || 'status').trim().toLowerCase();
|
|
10093
|
-
const asJson =
|
|
10600
|
+
const asJson = isJsonOutput(opts);
|
|
10094
10601
|
const emit = (frame)=>{
|
|
10095
10602
|
console.log(JSON.stringify(frame));
|
|
10096
10603
|
};
|
|
@@ -10165,12 +10672,6 @@ Cross-browser compatibility
|
|
|
10165
10672
|
return resolveExtensionDevelopVersion(__dirname, index_cliPackageJson.version);
|
|
10166
10673
|
}
|
|
10167
10674
|
process.env.EXTENSION_DEVELOP_VERSION = developVersion();
|
|
10168
|
-
function scanArgvValue(argv, flag) {
|
|
10169
|
-
const equalArg = argv.find((arg)=>arg.startsWith(`${flag}=`));
|
|
10170
|
-
if (equalArg) return equalArg.slice(flag.length + 1);
|
|
10171
|
-
const flagIndex = argv.indexOf(flag);
|
|
10172
|
-
if (flagIndex >= 0) return argv[flagIndex + 1] || '';
|
|
10173
|
-
}
|
|
10174
10675
|
function resolveAIHelpFormatFromArgv(argv) {
|
|
10175
10676
|
const direct = scanArgvValue(argv, '--output');
|
|
10176
10677
|
if (void 0 !== direct) return direct;
|
|
@@ -10181,29 +10682,21 @@ Cross-browser compatibility
|
|
|
10181
10682
|
}
|
|
10182
10683
|
return 'pretty';
|
|
10183
10684
|
}
|
|
10184
|
-
|
|
10185
|
-
|
|
10186
|
-
|
|
10187
|
-
if (!arg.startsWith('-')) return arg;
|
|
10188
|
-
}
|
|
10685
|
+
let valuedLongFlags = new Set();
|
|
10686
|
+
function index_resolveCommandFromArgv(argv) {
|
|
10687
|
+
return resolveCommandFromArgv(argv, valuedLongFlags);
|
|
10189
10688
|
}
|
|
10190
10689
|
function failBeforeParse(argv, humanMessage, code, plainMessage, flag) {
|
|
10191
10690
|
console.error(humanMessage);
|
|
10192
|
-
if (wantsJsonOutput(argv)) writeStdoutFrame(earlyExitEnvelope(
|
|
10691
|
+
if (wantsJsonOutput(argv)) writeStdoutFrame(earlyExitEnvelope(index_resolveCommandFromArgv(argv) || 'extension', code, plainMessage, {
|
|
10193
10692
|
flag
|
|
10194
10693
|
}));
|
|
10195
10694
|
process.exit(1);
|
|
10196
10695
|
}
|
|
10197
10696
|
function applyOutputAliasArgvShim(argv) {
|
|
10198
|
-
const index = argv.findIndex((arg)=>'--format' === arg || arg.startsWith('--format='));
|
|
10199
|
-
if (index < 0) return argv;
|
|
10200
10697
|
if (argv.includes('--ai-help')) return argv;
|
|
10201
|
-
const next =
|
|
10202
|
-
|
|
10203
|
-
];
|
|
10204
|
-
if (next[index].startsWith('--format=')) next[index] = `--output=${next[index].slice(9)}`;
|
|
10205
|
-
else next[index] = '--output';
|
|
10206
|
-
warnDeprecatedOutputAlias('--format');
|
|
10698
|
+
const { argv: next, rewritten } = rewriteOutputAliasArgv(argv, valuedLongFlags);
|
|
10699
|
+
if (rewritten) warnDeprecatedOutputAlias('--format');
|
|
10207
10700
|
return next;
|
|
10208
10701
|
}
|
|
10209
10702
|
function applyNoBrowserArgvShim(argv) {
|
|
@@ -10212,7 +10705,7 @@ Cross-browser compatibility
|
|
|
10212
10705
|
let nextArgv = argv;
|
|
10213
10706
|
const hasNoReload = nextArgv.includes('--no-reload');
|
|
10214
10707
|
if (hasNoReload) {
|
|
10215
|
-
const command =
|
|
10708
|
+
const command = index_resolveCommandFromArgv(nextArgv);
|
|
10216
10709
|
if ('dev' !== command) {
|
|
10217
10710
|
const message = `--no-reload is only supported on \`extension dev\` (got: ${command || 'no command'}).`;
|
|
10218
10711
|
failBeforeParse(nextArgv, message, messaging.Lp.E_FLAG_NOT_SUPPORTED_HERE, message, '--no-reload');
|
|
@@ -10222,7 +10715,7 @@ Cross-browser compatibility
|
|
|
10222
10715
|
}
|
|
10223
10716
|
const hasNoBrowser = nextArgv.includes('--no-browser');
|
|
10224
10717
|
if (!hasNoBrowser) return nextArgv;
|
|
10225
|
-
const command =
|
|
10718
|
+
const command = index_resolveCommandFromArgv(nextArgv);
|
|
10226
10719
|
const supportsNoBrowser = 'dev' === command || 'start' === command || 'preview' === command;
|
|
10227
10720
|
if (!supportsNoBrowser) failBeforeParse(nextArgv, noBrowserNotSupportedForCommand(command), messaging.Lp.E_FLAG_NOT_SUPPORTED_HERE, command ? `--no-browser is not supported on \`extension ${command}\`.` : '--no-browser needs a command that launches a browser.', '--no-browser');
|
|
10228
10721
|
process.env.EXTENSION_CLI_NO_BROWSER = '1';
|
|
@@ -10249,6 +10742,7 @@ Cross-browser compatibility
|
|
|
10249
10742
|
registerTelemetryCommand(extensionJs);
|
|
10250
10743
|
registerDoctorCommand(extensionJs);
|
|
10251
10744
|
registerCapabilitiesCommand(extensionJs);
|
|
10745
|
+
valuedLongFlags = collectValuedLongFlags(extensionJs);
|
|
10252
10746
|
function runAIHelp() {
|
|
10253
10747
|
const format = resolveAIHelpFormatFromArgv(process.argv).trim().toLowerCase();
|
|
10254
10748
|
if ('json' === format) {
|
|
@@ -10272,7 +10766,7 @@ Cross-browser compatibility
|
|
|
10272
10766
|
else {
|
|
10273
10767
|
const argv = applyNoBrowserArgvShim(applyOutputAliasArgvShim(process.argv));
|
|
10274
10768
|
const asJson = wantsJsonOutput(argv);
|
|
10275
|
-
const commandName =
|
|
10769
|
+
const commandName = index_resolveCommandFromArgv(argv) || 'extension';
|
|
10276
10770
|
(async ()=>{
|
|
10277
10771
|
try {
|
|
10278
10772
|
await extensionJs.parseAsync(argv);
|