extension 4.0.28 → 4.0.29-next.0
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/browsers.cjs +39 -5
- package/dist/cli.cjs +221 -178
- package/dist/extension/browsers/run-firefox/firefox-types.d.ts +3 -0
- package/dist/extension/browsers/run-firefox/rdp/rdp-extension-controller/index.d.ts +3 -0
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/firefox-utils.d.ts +5 -1
- package/dist/extension/browsers/run-firefox/rdp/remote-firefox/index.d.ts +3 -0
- package/dist/extension/browsers/run-safari/safari-packager.d.ts +2 -0
- package/dist/extension/browsers/run-safari/safari-types.d.ts +1 -0
- package/dist/extension/commands/logs.d.ts +14 -0
- package/dist/extension/helpers/messages.d.ts +1 -1
- package/dist/extension/helpers/vendors.d.ts +3 -0
- package/package.json +4 -4
package/dist/browsers.cjs
CHANGED
|
@@ -2423,7 +2423,6 @@ var __webpack_modules__ = {
|
|
|
2423
2423
|
'--disable-breakpad',
|
|
2424
2424
|
'--disable-component-update',
|
|
2425
2425
|
'--disable-domain-reliability',
|
|
2426
|
-
'--disable-sync',
|
|
2427
2426
|
'--no-pings',
|
|
2428
2427
|
'--enable-features=SidePanelUpdates',
|
|
2429
2428
|
'--disable-features=DisableLoadExtensionCommandLineSwitch',
|
|
@@ -3890,7 +3889,7 @@ var __webpack_modules__ = {
|
|
|
3890
3889
|
}
|
|
3891
3890
|
return false;
|
|
3892
3891
|
}
|
|
3893
|
-
async function printRunningInDevelopmentSummary(candidateAddonPaths, browser, extensionId, browserVersionLine) {
|
|
3892
|
+
async function printRunningInDevelopmentSummary(candidateAddonPaths, browser, extensionId, browserVersionLine, launchIdentity) {
|
|
3894
3893
|
try {
|
|
3895
3894
|
let chosenPath = null;
|
|
3896
3895
|
for (const p of candidateAddonPaths){
|
|
@@ -3928,7 +3927,10 @@ var __webpack_modules__ = {
|
|
|
3928
3927
|
name: manifest.name,
|
|
3929
3928
|
version: manifest.version
|
|
3930
3929
|
}),
|
|
3931
|
-
browserVersionLine
|
|
3930
|
+
browserVersionLine,
|
|
3931
|
+
profilePath: launchIdentity?.profilePath,
|
|
3932
|
+
binaryPath: launchIdentity?.binaryPath,
|
|
3933
|
+
binaryProvenance: launchIdentity?.binaryProvenance
|
|
3932
3934
|
});
|
|
3933
3935
|
return printed;
|
|
3934
3936
|
} catch {
|
|
@@ -4587,7 +4589,11 @@ var __webpack_modules__ = {
|
|
|
4587
4589
|
}
|
|
4588
4590
|
} catch {}
|
|
4589
4591
|
this.lastInstalledAddonPath = primaryAddonPath;
|
|
4590
|
-
const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, 'firefox', this.derivedExtensionId, this.options.browserVersionLine
|
|
4592
|
+
const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, 'firefox', this.derivedExtensionId, this.options.browserVersionLine, {
|
|
4593
|
+
profilePath: this.options.launchProfilePath,
|
|
4594
|
+
binaryPath: this.options.launchBinaryPath,
|
|
4595
|
+
binaryProvenance: this.options.launchBinaryProvenance
|
|
4596
|
+
});
|
|
4591
4597
|
if (!bannerPrinted) throw new Error(messages.WV(this.options.browser, 'Failed to print runningInDevelopment banner; add-on may not be installed.'));
|
|
4592
4598
|
}
|
|
4593
4599
|
async enableUnifiedLogging(opts) {
|
|
@@ -4665,7 +4671,10 @@ var __webpack_modules__ = {
|
|
|
4665
4671
|
instanceId: plugin.instanceId,
|
|
4666
4672
|
port: debugPort,
|
|
4667
4673
|
resolvedRdpPort: normalizedDebugPort,
|
|
4668
|
-
browserVersionLine: plugin.browserVersionLine
|
|
4674
|
+
browserVersionLine: plugin.browserVersionLine,
|
|
4675
|
+
launchProfilePath: plugin.launchProfilePath,
|
|
4676
|
+
launchBinaryPath: plugin.launchBinaryPath,
|
|
4677
|
+
launchBinaryProvenance: plugin.launchBinaryProvenance
|
|
4669
4678
|
});
|
|
4670
4679
|
this.debugPort = normalizedDebugPort;
|
|
4671
4680
|
}
|
|
@@ -4928,6 +4937,12 @@ var __webpack_modules__ = {
|
|
|
4928
4937
|
}
|
|
4929
4938
|
const binaryPath = browserBinaryLocation;
|
|
4930
4939
|
const wslFallbackBinary = (0, wsl_support.EV)() && !engineBased ? resolveWslFallback() : null;
|
|
4940
|
+
this.host.launchBinaryPath = binaryPath;
|
|
4941
|
+
this.host.launchBinaryProvenance = (0, shared_utils.RU)({
|
|
4942
|
+
binaryPath,
|
|
4943
|
+
managedCacheRoot: String((0, output_binaries_resolver.LB)(compilation) || ''),
|
|
4944
|
+
pinnedByFlag: Boolean(this.host.geckoBinary)
|
|
4945
|
+
});
|
|
4931
4946
|
if (!isFlatpak) try {
|
|
4932
4947
|
this.host.browserVersionLine = (0, external_firefox_location2_.getFirefoxVersion)(binaryPath, {
|
|
4933
4948
|
allowExec: true
|
|
@@ -4961,6 +4976,7 @@ var __webpack_modules__ = {
|
|
|
4961
4976
|
if (profileMatch) {
|
|
4962
4977
|
const profilePath = profileMatch[1];
|
|
4963
4978
|
const { binary, args } = FirefoxBinaryDetector.generateFirefoxArgs(binaryPath, profilePath, debugPort, firefoxArgs, isFirefoxHeadlessRequested());
|
|
4979
|
+
this.host.launchProfilePath = profilePath;
|
|
4964
4980
|
this.child = await this.spawnFirefoxChild(binary, args, wslFallbackBinary);
|
|
4965
4981
|
(0, ready_stamp.M)(this.extensionOutputPath, {
|
|
4966
4982
|
profilePath,
|
|
@@ -5325,7 +5341,9 @@ var __webpack_modules__ = {
|
|
|
5325
5341
|
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
5326
5342
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
5327
5343
|
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
5344
|
+
var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
|
|
5328
5345
|
var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
|
|
5346
|
+
var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
|
|
5329
5347
|
function logSafariDryRun(converterCmd, xcodebuildCmd) {
|
|
5330
5348
|
if ((0, messaging._o)()) (0, messaging._w)(messages.KP());
|
|
5331
5349
|
(0, messaging._w)(messages.yc());
|
|
@@ -5491,6 +5509,20 @@ var __webpack_modules__ = {
|
|
|
5491
5509
|
severity: 'ok'
|
|
5492
5510
|
};
|
|
5493
5511
|
}
|
|
5512
|
+
async function announceSafariDevSession(host, config, appPath) {
|
|
5513
|
+
try {
|
|
5514
|
+
await (0, banner.ai)({
|
|
5515
|
+
browser: host.browser,
|
|
5516
|
+
outPath: config.extensionDir,
|
|
5517
|
+
getInfo: async ()=>({
|
|
5518
|
+
extensionId: `${config.bundleIdentifier}.Extension`,
|
|
5519
|
+
name: config.appName
|
|
5520
|
+
}),
|
|
5521
|
+
binaryPath: appPath
|
|
5522
|
+
});
|
|
5523
|
+
(0, messaging._w)((0, ready_message.G)('development', String(host.browser)));
|
|
5524
|
+
} catch {}
|
|
5525
|
+
}
|
|
5494
5526
|
async function runSafariPipeline(compilation, host, logger, mode) {
|
|
5495
5527
|
const config = (0, safari_config.F7)(compilation, host);
|
|
5496
5528
|
const converterArgs = (0, safari_config.w7)(config);
|
|
@@ -5555,6 +5587,7 @@ var __webpack_modules__ = {
|
|
|
5555
5587
|
logger.info?.(messages.Rl(appPath));
|
|
5556
5588
|
if (!config.open) {
|
|
5557
5589
|
logger.info?.(messages.aO(appPath, config.appName));
|
|
5590
|
+
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
5558
5591
|
return describePackage(config);
|
|
5559
5592
|
}
|
|
5560
5593
|
const target = external_node_fs_.existsSync(appPath) ? appPath : (0, safari_config.Gi)(config);
|
|
@@ -5569,6 +5602,7 @@ var __webpack_modules__ = {
|
|
|
5569
5602
|
logger.info?.(messages.fO(config.appName));
|
|
5570
5603
|
if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
|
|
5571
5604
|
else logger.info?.(messages.qY(config.appName));
|
|
5605
|
+
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
5572
5606
|
return describePackage(config);
|
|
5573
5607
|
}
|
|
5574
5608
|
async function packageSafariExtension(host, outputPath, logger, mode = 'full') {
|
package/dist/cli.cjs
CHANGED
|
@@ -2414,7 +2414,6 @@ var __webpack_modules__ = {
|
|
|
2414
2414
|
'--disable-breakpad',
|
|
2415
2415
|
'--disable-component-update',
|
|
2416
2416
|
'--disable-domain-reliability',
|
|
2417
|
-
'--disable-sync',
|
|
2418
2417
|
'--no-pings',
|
|
2419
2418
|
'--enable-features=SidePanelUpdates',
|
|
2420
2419
|
'--disable-features=DisableLoadExtensionCommandLineSwitch',
|
|
@@ -3881,7 +3880,7 @@ var __webpack_modules__ = {
|
|
|
3881
3880
|
}
|
|
3882
3881
|
return false;
|
|
3883
3882
|
}
|
|
3884
|
-
async function printRunningInDevelopmentSummary(candidateAddonPaths, browser, extensionId, browserVersionLine) {
|
|
3883
|
+
async function printRunningInDevelopmentSummary(candidateAddonPaths, browser, extensionId, browserVersionLine, launchIdentity) {
|
|
3885
3884
|
try {
|
|
3886
3885
|
let chosenPath = null;
|
|
3887
3886
|
for (const p of candidateAddonPaths){
|
|
@@ -3919,7 +3918,10 @@ var __webpack_modules__ = {
|
|
|
3919
3918
|
name: manifest.name,
|
|
3920
3919
|
version: manifest.version
|
|
3921
3920
|
}),
|
|
3922
|
-
browserVersionLine
|
|
3921
|
+
browserVersionLine,
|
|
3922
|
+
profilePath: launchIdentity?.profilePath,
|
|
3923
|
+
binaryPath: launchIdentity?.binaryPath,
|
|
3924
|
+
binaryProvenance: launchIdentity?.binaryProvenance
|
|
3923
3925
|
});
|
|
3924
3926
|
return printed;
|
|
3925
3927
|
} catch {
|
|
@@ -4578,7 +4580,11 @@ var __webpack_modules__ = {
|
|
|
4578
4580
|
}
|
|
4579
4581
|
} catch {}
|
|
4580
4582
|
this.lastInstalledAddonPath = primaryAddonPath;
|
|
4581
|
-
const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, 'firefox', this.derivedExtensionId, this.options.browserVersionLine
|
|
4583
|
+
const bannerPrinted = await printRunningInDevelopmentSummary(candidateAddonPaths, 'firefox', this.derivedExtensionId, this.options.browserVersionLine, {
|
|
4584
|
+
profilePath: this.options.launchProfilePath,
|
|
4585
|
+
binaryPath: this.options.launchBinaryPath,
|
|
4586
|
+
binaryProvenance: this.options.launchBinaryProvenance
|
|
4587
|
+
});
|
|
4582
4588
|
if (!bannerPrinted) throw new Error(messages.WV(this.options.browser, 'Failed to print runningInDevelopment banner; add-on may not be installed.'));
|
|
4583
4589
|
}
|
|
4584
4590
|
async enableUnifiedLogging(opts) {
|
|
@@ -4656,7 +4662,10 @@ var __webpack_modules__ = {
|
|
|
4656
4662
|
instanceId: plugin.instanceId,
|
|
4657
4663
|
port: debugPort,
|
|
4658
4664
|
resolvedRdpPort: normalizedDebugPort,
|
|
4659
|
-
browserVersionLine: plugin.browserVersionLine
|
|
4665
|
+
browserVersionLine: plugin.browserVersionLine,
|
|
4666
|
+
launchProfilePath: plugin.launchProfilePath,
|
|
4667
|
+
launchBinaryPath: plugin.launchBinaryPath,
|
|
4668
|
+
launchBinaryProvenance: plugin.launchBinaryProvenance
|
|
4660
4669
|
});
|
|
4661
4670
|
this.debugPort = normalizedDebugPort;
|
|
4662
4671
|
}
|
|
@@ -4919,6 +4928,12 @@ var __webpack_modules__ = {
|
|
|
4919
4928
|
}
|
|
4920
4929
|
const binaryPath = browserBinaryLocation;
|
|
4921
4930
|
const wslFallbackBinary = (0, wsl_support.EV)() && !engineBased ? resolveWslFallback() : null;
|
|
4931
|
+
this.host.launchBinaryPath = binaryPath;
|
|
4932
|
+
this.host.launchBinaryProvenance = (0, shared_utils.RU)({
|
|
4933
|
+
binaryPath,
|
|
4934
|
+
managedCacheRoot: String((0, output_binaries_resolver.LB)(compilation) || ''),
|
|
4935
|
+
pinnedByFlag: Boolean(this.host.geckoBinary)
|
|
4936
|
+
});
|
|
4922
4937
|
if (!isFlatpak) try {
|
|
4923
4938
|
this.host.browserVersionLine = (0, external_firefox_location2_.getFirefoxVersion)(binaryPath, {
|
|
4924
4939
|
allowExec: true
|
|
@@ -4952,6 +4967,7 @@ var __webpack_modules__ = {
|
|
|
4952
4967
|
if (profileMatch) {
|
|
4953
4968
|
const profilePath = profileMatch[1];
|
|
4954
4969
|
const { binary, args } = FirefoxBinaryDetector.generateFirefoxArgs(binaryPath, profilePath, debugPort, firefoxArgs, isFirefoxHeadlessRequested());
|
|
4970
|
+
this.host.launchProfilePath = profilePath;
|
|
4955
4971
|
this.child = await this.spawnFirefoxChild(binary, args, wslFallbackBinary);
|
|
4956
4972
|
(0, ready_stamp.M)(this.extensionOutputPath, {
|
|
4957
4973
|
profilePath,
|
|
@@ -5316,7 +5332,9 @@ var __webpack_modules__ = {
|
|
|
5316
5332
|
var external_node_child_process_ = __webpack_require__("node:child_process");
|
|
5317
5333
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
5318
5334
|
var messaging = __webpack_require__("./helpers/messaging.ts");
|
|
5335
|
+
var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
|
|
5319
5336
|
var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
|
|
5337
|
+
var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
|
|
5320
5338
|
function logSafariDryRun(converterCmd, xcodebuildCmd) {
|
|
5321
5339
|
if ((0, messaging._o)()) (0, messaging._w)(messages.KP());
|
|
5322
5340
|
(0, messaging._w)(messages.yc());
|
|
@@ -5482,6 +5500,20 @@ var __webpack_modules__ = {
|
|
|
5482
5500
|
severity: 'ok'
|
|
5483
5501
|
};
|
|
5484
5502
|
}
|
|
5503
|
+
async function announceSafariDevSession(host, config, appPath) {
|
|
5504
|
+
try {
|
|
5505
|
+
await (0, banner.ai)({
|
|
5506
|
+
browser: host.browser,
|
|
5507
|
+
outPath: config.extensionDir,
|
|
5508
|
+
getInfo: async ()=>({
|
|
5509
|
+
extensionId: `${config.bundleIdentifier}.Extension`,
|
|
5510
|
+
name: config.appName
|
|
5511
|
+
}),
|
|
5512
|
+
binaryPath: appPath
|
|
5513
|
+
});
|
|
5514
|
+
(0, messaging._w)((0, ready_message.G)('development', String(host.browser)));
|
|
5515
|
+
} catch {}
|
|
5516
|
+
}
|
|
5485
5517
|
async function runSafariPipeline(compilation, host, logger, mode) {
|
|
5486
5518
|
const config = (0, safari_config.F7)(compilation, host);
|
|
5487
5519
|
const converterArgs = (0, safari_config.w7)(config);
|
|
@@ -5546,6 +5578,7 @@ var __webpack_modules__ = {
|
|
|
5546
5578
|
logger.info?.(messages.Rl(appPath));
|
|
5547
5579
|
if (!config.open) {
|
|
5548
5580
|
logger.info?.(messages.aO(appPath, config.appName));
|
|
5581
|
+
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
5549
5582
|
return describePackage(config);
|
|
5550
5583
|
}
|
|
5551
5584
|
const target = external_node_fs_.existsSync(appPath) ? appPath : (0, safari_config.Gi)(config);
|
|
@@ -5560,6 +5593,7 @@ var __webpack_modules__ = {
|
|
|
5560
5593
|
logger.info?.(messages.fO(config.appName));
|
|
5561
5594
|
if (await confirmRegisteredWithSafari(config.bundleIdentifier)) logger.info?.(messages.fd(config.appName));
|
|
5562
5595
|
else logger.info?.(messages.qY(config.appName));
|
|
5596
|
+
if (host.announceDevReady) await announceSafariDevSession(host, config, appPath);
|
|
5563
5597
|
return describePackage(config);
|
|
5564
5598
|
}
|
|
5565
5599
|
async function packageSafariExtension(host, outputPath, logger, mode = 'full') {
|
|
@@ -7248,12 +7282,6 @@ Public & special folders (output behavior)
|
|
|
7248
7282
|
- ${external_pintor_default().underline(messages_code('pages/'))} files emit as ${messages_code('pages/<name>.html')}. Relative assets referenced inside page HTML are emitted under ${messages_code('assets/')} preserving relative structure, public-root URLs are preserved.
|
|
7249
7283
|
- ${external_pintor_default().underline(messages_code("scripts/"))} files emit as ${messages_code("scripts/<name>.js")} with extracted CSS when applicable.
|
|
7250
7284
|
|
|
7251
|
-
Shadow DOM for content scripts
|
|
7252
|
-
- Add ${messages_code('use shadow-dom')} directive to content scripts for style isolation
|
|
7253
|
-
- Automatically creates ${messages_code('#extension-root')} element with shadow DOM
|
|
7254
|
-
- All CSS imports are automatically injected into shadow DOM
|
|
7255
|
-
- Prevents style conflicts with host page
|
|
7256
|
-
|
|
7257
7285
|
Environment variables
|
|
7258
7286
|
- Use ${messages_code(messages_arg('EXTENSION_PUBLIC_*'))} prefix for variables accessible in extension code
|
|
7259
7287
|
- Supported in both ${messages_code('process.env')} and ${messages_code('import.meta.env')}
|
|
@@ -7410,9 +7438,11 @@ Cross-browser compatibility
|
|
|
7410
7438
|
...group.templates
|
|
7411
7439
|
]
|
|
7412
7440
|
})),
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7441
|
+
...TEMPLATE_ALIASES.length > 0 && {
|
|
7442
|
+
aliases: TEMPLATE_ALIASES.map((alias)=>({
|
|
7443
|
+
...alias
|
|
7444
|
+
}))
|
|
7445
|
+
},
|
|
7416
7446
|
notes: [
|
|
7417
7447
|
`extension create <name> with no --template scaffolds ${DEFAULT_TEMPLATE}`,
|
|
7418
7448
|
`${DEFAULT_TEMPLATE} is bundled with the CLI and scaffolds offline. Every other name downloads the examples archive at create time`,
|
|
@@ -7454,7 +7484,8 @@ Cross-browser compatibility
|
|
|
7454
7484
|
statuses: [
|
|
7455
7485
|
'starting',
|
|
7456
7486
|
'ready',
|
|
7457
|
-
'error'
|
|
7487
|
+
'error',
|
|
7488
|
+
'stopped'
|
|
7458
7489
|
],
|
|
7459
7490
|
readyFields: [
|
|
7460
7491
|
'status',
|
|
@@ -7478,7 +7509,7 @@ Cross-browser compatibility
|
|
|
7478
7509
|
],
|
|
7479
7510
|
notes: [
|
|
7480
7511
|
'ready.json is written atomically by the build (dev/start) on each compile',
|
|
7481
|
-
'events.ndjson is
|
|
7512
|
+
'events.ndjson is reset at every run start and appends entries with runId, durationMs and errorCount for that run only, join on runId across runs',
|
|
7482
7513
|
'--wait requires a local project path (remote URLs are not supported)',
|
|
7483
7514
|
'consumers should verify pid liveness and recency before trusting a contract'
|
|
7484
7515
|
]
|
|
@@ -7526,6 +7557,146 @@ Cross-browser compatibility
|
|
|
7526
7557
|
function noBrowserNotSupportedForCommand(command) {
|
|
7527
7558
|
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)')}`;
|
|
7528
7559
|
}
|
|
7560
|
+
const LEVEL_ORDER = [
|
|
7561
|
+
'error',
|
|
7562
|
+
'warn',
|
|
7563
|
+
'info',
|
|
7564
|
+
'debug',
|
|
7565
|
+
'trace'
|
|
7566
|
+
];
|
|
7567
|
+
function levelRank(level) {
|
|
7568
|
+
const l = 'log' === level ? 'info' : level;
|
|
7569
|
+
const i = LEVEL_ORDER.indexOf(l);
|
|
7570
|
+
return -1 === i ? LEVEL_ORDER.length : i;
|
|
7571
|
+
}
|
|
7572
|
+
function makeUrlMatcher(pattern) {
|
|
7573
|
+
const hasGlob = pattern.includes('*');
|
|
7574
|
+
let re = null;
|
|
7575
|
+
if (hasGlob) {
|
|
7576
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
7577
|
+
re = new RegExp(escaped);
|
|
7578
|
+
}
|
|
7579
|
+
return (event)=>{
|
|
7580
|
+
const candidates = [
|
|
7581
|
+
event.url,
|
|
7582
|
+
event.hostname
|
|
7583
|
+
].filter((v)=>'string' == typeof v);
|
|
7584
|
+
if (0 === candidates.length) return false;
|
|
7585
|
+
return candidates.some((c)=>re ? re.test(c) : c.includes(pattern));
|
|
7586
|
+
};
|
|
7587
|
+
}
|
|
7588
|
+
function makeFilter(opts) {
|
|
7589
|
+
const minLevel = String(opts.level || 'all').toLowerCase();
|
|
7590
|
+
const contexts = opts.context && 'all' !== opts.context.toLowerCase() ? new Set(opts.context.split(',').map((c)=>c.trim())) : null;
|
|
7591
|
+
const sinceSeq = null != opts.since ? Number(opts.since) : null;
|
|
7592
|
+
const urlMatches = opts.url ? makeUrlMatcher(opts.url) : null;
|
|
7593
|
+
const tabId = null != opts.tab && '' !== opts.tab ? Number(opts.tab) : null;
|
|
7594
|
+
return (event)=>{
|
|
7595
|
+
if (!event || 'object' != typeof event) return false;
|
|
7596
|
+
if ('header' === event.type) return false;
|
|
7597
|
+
if (opts.signalsOnly && 'dx.signal' !== event.eventType) return false;
|
|
7598
|
+
if (contexts && !contexts.has(String(event.context))) return false;
|
|
7599
|
+
if ('all' !== minLevel && 'off' !== minLevel) {
|
|
7600
|
+
if (levelRank(String(event.level || '')) > levelRank(minLevel)) return false;
|
|
7601
|
+
}
|
|
7602
|
+
if (null != sinceSeq && Number.isFinite(sinceSeq) && 'number' == typeof event.seq && event.seq <= sinceSeq) return false;
|
|
7603
|
+
if (urlMatches && !urlMatches(event)) return false;
|
|
7604
|
+
if (null != tabId && Number.isFinite(tabId) && event.tabId !== tabId) return false;
|
|
7605
|
+
return true;
|
|
7606
|
+
};
|
|
7607
|
+
}
|
|
7608
|
+
function resolveFormat(opts) {
|
|
7609
|
+
if (opts.output) return opts.output;
|
|
7610
|
+
return process.stdout.isTTY ? 'pretty' : 'ndjson';
|
|
7611
|
+
}
|
|
7612
|
+
function printEvent(event, format) {
|
|
7613
|
+
if ('ndjson' === format) return void console.log(JSON.stringify(event));
|
|
7614
|
+
if ('json' === format) return void console.log(JSON.stringify(event, null, 2));
|
|
7615
|
+
console.log(formatPrettyLogLine(event));
|
|
7616
|
+
}
|
|
7617
|
+
function formatPrettyLogLine(event) {
|
|
7618
|
+
const parts = Array.isArray(event.messageParts) ? event.messageParts.map((p)=>'string' == typeof p ? p : JSON.stringify(p)).join(' ') : '';
|
|
7619
|
+
const code = event.code ? ` ${event.code}` : '';
|
|
7620
|
+
const remediation = event.remediation ? `\n ↳ ${event.remediation}` : '';
|
|
7621
|
+
return `[${event.seq ?? '-'}] ${String(event.level || 'log').toUpperCase()} (${event.context})${code} ${parts}${remediation}`;
|
|
7622
|
+
}
|
|
7623
|
+
function writeFrame(frame) {
|
|
7624
|
+
try {
|
|
7625
|
+
external_node_fs_default().writeSync(1, `${JSON.stringify(frame)}\n`);
|
|
7626
|
+
} catch {
|
|
7627
|
+
console.log(JSON.stringify(frame));
|
|
7628
|
+
}
|
|
7629
|
+
}
|
|
7630
|
+
function logsFilePath(projectPath, browser) {
|
|
7631
|
+
return external_node_path_default().resolve(projectPath, 'dist', 'extension-js', browser, 'logs.ndjson');
|
|
7632
|
+
}
|
|
7633
|
+
function registerLogsCommand(program) {
|
|
7634
|
+
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)=>{
|
|
7635
|
+
const projectPath = external_node_path_default().resolve(projectPathArg || process.cwd());
|
|
7636
|
+
const browser = options.browser || 'chromium';
|
|
7637
|
+
const format = resolveFormat(options);
|
|
7638
|
+
const matches = makeFilter(options);
|
|
7639
|
+
if (options.follow) return void await followLogs(projectPath, browser, format, matches);
|
|
7640
|
+
const file = logsFilePath(projectPath, browser);
|
|
7641
|
+
if (!external_node_fs_default().existsSync(file)) {
|
|
7642
|
+
const message = `No logs found at ${file}. Start a dev session (extension dev) first, or pass --browser to match it.`;
|
|
7643
|
+
console.error(message);
|
|
7644
|
+
if ('pretty' !== format) writeFrame(messaging.Pr.fail('logs', 'not-found', {
|
|
7645
|
+
code: messaging.Lp.E_LOGS_NOT_FOUND,
|
|
7646
|
+
message,
|
|
7647
|
+
name: 'CliError'
|
|
7648
|
+
}));
|
|
7649
|
+
process.exit(1);
|
|
7650
|
+
}
|
|
7651
|
+
const lines = external_node_fs_default().readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
7652
|
+
for (const line of lines){
|
|
7653
|
+
let event;
|
|
7654
|
+
try {
|
|
7655
|
+
event = JSON.parse(line);
|
|
7656
|
+
} catch {
|
|
7657
|
+
continue;
|
|
7658
|
+
}
|
|
7659
|
+
if (matches(event)) printEvent(event, format);
|
|
7660
|
+
}
|
|
7661
|
+
});
|
|
7662
|
+
}
|
|
7663
|
+
async function followLogs(projectPath, browser, format, matches) {
|
|
7664
|
+
const { BridgeConsumer, readReadyContract } = await loadExtensionDevelopBridgeModule();
|
|
7665
|
+
const ready = readReadyContract(projectPath, browser);
|
|
7666
|
+
if (!ready) {
|
|
7667
|
+
const message = `No active dev session control channel found for ${browser}. Run \`extension dev --browser=${browser}\` first.`;
|
|
7668
|
+
console.error(message);
|
|
7669
|
+
if ('pretty' !== format) writeFrame(messaging.Pr.fail('logs', 'not-found', {
|
|
7670
|
+
code: messaging.Lp.E_SESSION_NOT_FOUND,
|
|
7671
|
+
message,
|
|
7672
|
+
name: 'CliError'
|
|
7673
|
+
}));
|
|
7674
|
+
process.exit(1);
|
|
7675
|
+
}
|
|
7676
|
+
const consumer = new BridgeConsumer({
|
|
7677
|
+
controlPort: ready.controlPort,
|
|
7678
|
+
instanceId: ready.instanceId,
|
|
7679
|
+
reconnect: true,
|
|
7680
|
+
onLog: (event)=>{
|
|
7681
|
+
if (matches(event)) printEvent(event, format);
|
|
7682
|
+
},
|
|
7683
|
+
onGap: (gap)=>{
|
|
7684
|
+
console.error(`… ${gap.dropped} event(s) dropped (${gap.reason}), stream is behind`);
|
|
7685
|
+
}
|
|
7686
|
+
});
|
|
7687
|
+
const shutdown = (signal)=>{
|
|
7688
|
+
consumer.close();
|
|
7689
|
+
if ('pretty' !== format) console.log(JSON.stringify(messaging.Pr.ok('logs', 'interrupted', {
|
|
7690
|
+
signal,
|
|
7691
|
+
follow: true
|
|
7692
|
+
})));
|
|
7693
|
+
exitAfterDrain(0);
|
|
7694
|
+
};
|
|
7695
|
+
process.on('SIGINT', ()=>shutdown('SIGINT'));
|
|
7696
|
+
process.on('SIGTERM', ()=>shutdown('SIGTERM'));
|
|
7697
|
+
consumer.start();
|
|
7698
|
+
await new Promise(()=>{});
|
|
7699
|
+
}
|
|
7529
7700
|
function readRecentConsole(projectPath, browser, target, limit) {
|
|
7530
7701
|
const file = external_node_path_default().resolve(projectPath, 'dist', 'extension-js', browser, 'logs.ndjson');
|
|
7531
7702
|
let lines;
|
|
@@ -7615,7 +7786,7 @@ Cross-browser compatibility
|
|
|
7615
7786
|
})
|
|
7616
7787
|
};
|
|
7617
7788
|
}
|
|
7618
|
-
function
|
|
7789
|
+
function act_writeFrame(frame) {
|
|
7619
7790
|
try {
|
|
7620
7791
|
external_node_fs_default().writeSync(1, `${JSON.stringify(frame)}\n`);
|
|
7621
7792
|
} catch {
|
|
@@ -7624,7 +7795,7 @@ Cross-browser compatibility
|
|
|
7624
7795
|
}
|
|
7625
7796
|
function fail(message, frame) {
|
|
7626
7797
|
console.error(message);
|
|
7627
|
-
if (frame && 'json' === frame.output)
|
|
7798
|
+
if (frame && 'json' === frame.output) act_writeFrame(messaging.Pr.fail(frame.command, statusForCode(frame.code), {
|
|
7628
7799
|
code: frame.code,
|
|
7629
7800
|
message,
|
|
7630
7801
|
name: 'CliError'
|
|
@@ -7636,6 +7807,11 @@ Cross-browser compatibility
|
|
|
7636
7807
|
if (result.ok) {
|
|
7637
7808
|
const value = result.value;
|
|
7638
7809
|
console.log('string' == typeof value ? value : JSON.stringify(value, null, 2));
|
|
7810
|
+
const consoleRecords = result.console;
|
|
7811
|
+
if (Array.isArray(consoleRecords)) {
|
|
7812
|
+
if (0 === consoleRecords.length) console.log('(no console lines captured)');
|
|
7813
|
+
for (const record of consoleRecords)console.log(formatPrettyLogLine(record));
|
|
7814
|
+
}
|
|
7639
7815
|
if (result.truncated) console.error('… result truncated (byte cap)');
|
|
7640
7816
|
return;
|
|
7641
7817
|
}
|
|
@@ -7782,7 +7958,7 @@ Cross-browser compatibility
|
|
|
7782
7958
|
opts
|
|
7783
7959
|
});
|
|
7784
7960
|
});
|
|
7785
|
-
commonOptions(program.command('inspect').arguments('[project-path]').description(commandDescriptions.inspect).option('--context <content|page|popup|options|sidebar|devtools|newtab|history|bookmarks>', 'what to inspect: content/page or an open surface, including url-override pages (default content)').option('--url <glob|substring>', 'for content/page: document to target (resolved to its tab)').option('--tab <id>', 'for content/page: a specific tab (default: the --url match, else the active tab)').option('--list-tabs', 'list open tabs as {
|
|
7961
|
+
commonOptions(program.command('inspect').arguments('[project-path]').description(commandDescriptions.inspect).option('--context <content|page|popup|options|sidebar|devtools|newtab|history|bookmarks>', 'what to inspect: content/page or an open surface, including url-override pages (default content)').option('--url <glob|substring>', 'for content/page: document to target (resolved to its tab)').option('--tab <id>', 'for content/page: a specific tab (default: the --url match, else the active tab)').option('--list-tabs', 'list open tabs as {id,url,title,active,windowId} and exit (pass id to --tab)').option('--include <list>', 'comma-separated: html,summary (default summary)').option('--max-bytes <n>', 'cap on returned HTML bytes (default 262144)').option('--with-console [n]', 'also include the last n console lines for the target (default 20)')).action(async (projectPathArg, opts)=>{
|
|
7786
7962
|
if (opts.listTabs) return void await runCommand({
|
|
7787
7963
|
projectPathArg,
|
|
7788
7964
|
command: 'inspect',
|
|
@@ -7872,6 +8048,25 @@ Cross-browser compatibility
|
|
|
7872
8048
|
function isSafariVendor(value) {
|
|
7873
8049
|
return 'safari' === value || 'webkit-based' === value;
|
|
7874
8050
|
}
|
|
8051
|
+
const SUPPORTED_BROWSER_TARGETS = [
|
|
8052
|
+
'chrome',
|
|
8053
|
+
'chromium',
|
|
8054
|
+
'edge',
|
|
8055
|
+
'firefox',
|
|
8056
|
+
'brave',
|
|
8057
|
+
'opera',
|
|
8058
|
+
'vivaldi',
|
|
8059
|
+
'yandex',
|
|
8060
|
+
'waterfox',
|
|
8061
|
+
'librewolf',
|
|
8062
|
+
'chromium-based',
|
|
8063
|
+
'gecko-based',
|
|
8064
|
+
'firefox-based',
|
|
8065
|
+
'safari',
|
|
8066
|
+
'webkit-based'
|
|
8067
|
+
];
|
|
8068
|
+
const BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.join(' | ');
|
|
8069
|
+
const NO_SAFARI_BROWSER_TARGETS_HELP = SUPPORTED_BROWSER_TARGETS.filter((target)=>!isSafariVendor(target)).join(' | ');
|
|
7875
8070
|
function parseOptionalBoolean(value) {
|
|
7876
8071
|
if (void 0 === value) return true;
|
|
7877
8072
|
const normalized = String(value).trim().toLowerCase();
|
|
@@ -7897,23 +8092,7 @@ Cross-browser compatibility
|
|
|
7897
8092
|
'firefox'
|
|
7898
8093
|
] : vendors(browser);
|
|
7899
8094
|
function validateVendors(vendorsList, onInvalid) {
|
|
7900
|
-
const supported =
|
|
7901
|
-
'chrome',
|
|
7902
|
-
'edge',
|
|
7903
|
-
'firefox',
|
|
7904
|
-
'chromium',
|
|
7905
|
-
'brave',
|
|
7906
|
-
'opera',
|
|
7907
|
-
'vivaldi',
|
|
7908
|
-
'yandex',
|
|
7909
|
-
'waterfox',
|
|
7910
|
-
'librewolf',
|
|
7911
|
-
'chromium-based',
|
|
7912
|
-
'gecko-based',
|
|
7913
|
-
'firefox-based',
|
|
7914
|
-
'safari',
|
|
7915
|
-
'webkit-based'
|
|
7916
|
-
];
|
|
8095
|
+
const supported = SUPPORTED_BROWSER_TARGETS;
|
|
7917
8096
|
for (const v of vendorsList)if (!supported.includes(v)) {
|
|
7918
8097
|
onInvalid(v, supported);
|
|
7919
8098
|
return false;
|
|
@@ -7921,7 +8100,7 @@ Cross-browser compatibility
|
|
|
7921
8100
|
return true;
|
|
7922
8101
|
}
|
|
7923
8102
|
function registerBuildCommand(program) {
|
|
7924
|
-
program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(
|
|
8103
|
+
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('--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 = 'chromium', ...buildOptions })=>{
|
|
7925
8104
|
if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
|
|
7926
8105
|
process.env.EXTENSION_DEBUG = '1';
|
|
7927
8106
|
process.env.EXTENSION_AUTHOR_MODE = 'true';
|
|
@@ -8508,7 +8687,7 @@ Cross-browser compatibility
|
|
|
8508
8687
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
8509
8688
|
}
|
|
8510
8689
|
function registerDevCommand(program) {
|
|
8511
|
-
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(
|
|
8690
|
+
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').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').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('--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)=>{
|
|
8512
8691
|
const { browser = 'chromium', ...devOptions } = options;
|
|
8513
8692
|
if (devOptions.debug || devOptions.author || devOptions.authorMode) {
|
|
8514
8693
|
process.env.EXTENSION_DEBUG = '1';
|
|
@@ -8654,7 +8833,8 @@ Cross-browser compatibility
|
|
|
8654
8833
|
launcher: noBrowser ? void 0 : browsers.launchBrowser,
|
|
8655
8834
|
safariPackager: (0, safari_packager.P)({
|
|
8656
8835
|
browser: vendor,
|
|
8657
|
-
noOpen: explicitNoOpen ?? false
|
|
8836
|
+
noOpen: explicitNoOpen ?? false,
|
|
8837
|
+
announceDevReady: true
|
|
8658
8838
|
})
|
|
8659
8839
|
};
|
|
8660
8840
|
try {
|
|
@@ -9102,150 +9282,13 @@ Cross-browser compatibility
|
|
|
9102
9282
|
}));
|
|
9103
9283
|
});
|
|
9104
9284
|
}
|
|
9105
|
-
const LEVEL_ORDER = [
|
|
9106
|
-
'error',
|
|
9107
|
-
'warn',
|
|
9108
|
-
'info',
|
|
9109
|
-
'debug',
|
|
9110
|
-
'trace'
|
|
9111
|
-
];
|
|
9112
|
-
function levelRank(level) {
|
|
9113
|
-
const l = 'log' === level ? 'info' : level;
|
|
9114
|
-
const i = LEVEL_ORDER.indexOf(l);
|
|
9115
|
-
return -1 === i ? LEVEL_ORDER.length : i;
|
|
9116
|
-
}
|
|
9117
|
-
function makeUrlMatcher(pattern) {
|
|
9118
|
-
const hasGlob = pattern.includes('*');
|
|
9119
|
-
let re = null;
|
|
9120
|
-
if (hasGlob) {
|
|
9121
|
-
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
9122
|
-
re = new RegExp(escaped);
|
|
9123
|
-
}
|
|
9124
|
-
return (event)=>{
|
|
9125
|
-
const candidates = [
|
|
9126
|
-
event.url,
|
|
9127
|
-
event.hostname
|
|
9128
|
-
].filter((v)=>'string' == typeof v);
|
|
9129
|
-
if (0 === candidates.length) return false;
|
|
9130
|
-
return candidates.some((c)=>re ? re.test(c) : c.includes(pattern));
|
|
9131
|
-
};
|
|
9132
|
-
}
|
|
9133
|
-
function makeFilter(opts) {
|
|
9134
|
-
const minLevel = String(opts.level || 'all').toLowerCase();
|
|
9135
|
-
const contexts = opts.context && 'all' !== opts.context.toLowerCase() ? new Set(opts.context.split(',').map((c)=>c.trim())) : null;
|
|
9136
|
-
const sinceSeq = null != opts.since ? Number(opts.since) : null;
|
|
9137
|
-
const urlMatches = opts.url ? makeUrlMatcher(opts.url) : null;
|
|
9138
|
-
const tabId = null != opts.tab && '' !== opts.tab ? Number(opts.tab) : null;
|
|
9139
|
-
return (event)=>{
|
|
9140
|
-
if (!event || 'object' != typeof event) return false;
|
|
9141
|
-
if ('header' === event.type) return false;
|
|
9142
|
-
if (opts.signalsOnly && 'dx.signal' !== event.eventType) return false;
|
|
9143
|
-
if (contexts && !contexts.has(String(event.context))) return false;
|
|
9144
|
-
if ('all' !== minLevel && 'off' !== minLevel) {
|
|
9145
|
-
if (levelRank(String(event.level || '')) > levelRank(minLevel)) return false;
|
|
9146
|
-
}
|
|
9147
|
-
if (null != sinceSeq && Number.isFinite(sinceSeq) && 'number' == typeof event.seq && event.seq <= sinceSeq) return false;
|
|
9148
|
-
if (urlMatches && !urlMatches(event)) return false;
|
|
9149
|
-
if (null != tabId && Number.isFinite(tabId) && event.tabId !== tabId) return false;
|
|
9150
|
-
return true;
|
|
9151
|
-
};
|
|
9152
|
-
}
|
|
9153
|
-
function resolveFormat(opts) {
|
|
9154
|
-
if (opts.output) return opts.output;
|
|
9155
|
-
return process.stdout.isTTY ? 'pretty' : 'ndjson';
|
|
9156
|
-
}
|
|
9157
|
-
function printEvent(event, format) {
|
|
9158
|
-
if ('ndjson' === format) return void console.log(JSON.stringify(event));
|
|
9159
|
-
if ('json' === format) return void console.log(JSON.stringify(event, null, 2));
|
|
9160
|
-
const parts = Array.isArray(event.messageParts) ? event.messageParts.map((p)=>'string' == typeof p ? p : JSON.stringify(p)).join(' ') : '';
|
|
9161
|
-
const code = event.code ? ` ${event.code}` : '';
|
|
9162
|
-
const remediation = event.remediation ? `\n ↳ ${event.remediation}` : '';
|
|
9163
|
-
console.log(`[${event.seq ?? '-'}] ${String(event.level || 'log').toUpperCase()} (${event.context})${code} ${parts}${remediation}`);
|
|
9164
|
-
}
|
|
9165
|
-
function logs_writeFrame(frame) {
|
|
9166
|
-
try {
|
|
9167
|
-
external_node_fs_default().writeSync(1, `${JSON.stringify(frame)}\n`);
|
|
9168
|
-
} catch {
|
|
9169
|
-
console.log(JSON.stringify(frame));
|
|
9170
|
-
}
|
|
9171
|
-
}
|
|
9172
|
-
function logsFilePath(projectPath, browser) {
|
|
9173
|
-
return external_node_path_default().resolve(projectPath, 'dist', 'extension-js', browser, 'logs.ndjson');
|
|
9174
|
-
}
|
|
9175
|
-
function registerLogsCommand(program) {
|
|
9176
|
-
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', 'show only structured dx.signal diagnostics').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)=>{
|
|
9177
|
-
const projectPath = external_node_path_default().resolve(projectPathArg || process.cwd());
|
|
9178
|
-
const browser = options.browser || 'chromium';
|
|
9179
|
-
const format = resolveFormat(options);
|
|
9180
|
-
const matches = makeFilter(options);
|
|
9181
|
-
if (options.follow) return void await followLogs(projectPath, browser, format, matches);
|
|
9182
|
-
const file = logsFilePath(projectPath, browser);
|
|
9183
|
-
if (!external_node_fs_default().existsSync(file)) {
|
|
9184
|
-
const message = `No logs found at ${file}. Start a dev session (extension dev) first, or pass --browser to match it.`;
|
|
9185
|
-
console.error(message);
|
|
9186
|
-
if ('pretty' !== format) logs_writeFrame(messaging.Pr.fail('logs', 'not-found', {
|
|
9187
|
-
code: messaging.Lp.E_LOGS_NOT_FOUND,
|
|
9188
|
-
message,
|
|
9189
|
-
name: 'CliError'
|
|
9190
|
-
}));
|
|
9191
|
-
process.exit(1);
|
|
9192
|
-
}
|
|
9193
|
-
const lines = external_node_fs_default().readFileSync(file, 'utf-8').split('\n').filter(Boolean);
|
|
9194
|
-
for (const line of lines){
|
|
9195
|
-
let event;
|
|
9196
|
-
try {
|
|
9197
|
-
event = JSON.parse(line);
|
|
9198
|
-
} catch {
|
|
9199
|
-
continue;
|
|
9200
|
-
}
|
|
9201
|
-
if (matches(event)) printEvent(event, format);
|
|
9202
|
-
}
|
|
9203
|
-
});
|
|
9204
|
-
}
|
|
9205
|
-
async function followLogs(projectPath, browser, format, matches) {
|
|
9206
|
-
const { BridgeConsumer, readReadyContract } = await loadExtensionDevelopBridgeModule();
|
|
9207
|
-
const ready = readReadyContract(projectPath, browser);
|
|
9208
|
-
if (!ready) {
|
|
9209
|
-
const message = `No active dev session control channel found for ${browser}. Run \`extension dev --browser=${browser}\` first.`;
|
|
9210
|
-
console.error(message);
|
|
9211
|
-
if ('pretty' !== format) logs_writeFrame(messaging.Pr.fail('logs', 'not-found', {
|
|
9212
|
-
code: messaging.Lp.E_SESSION_NOT_FOUND,
|
|
9213
|
-
message,
|
|
9214
|
-
name: 'CliError'
|
|
9215
|
-
}));
|
|
9216
|
-
process.exit(1);
|
|
9217
|
-
}
|
|
9218
|
-
const consumer = new BridgeConsumer({
|
|
9219
|
-
controlPort: ready.controlPort,
|
|
9220
|
-
instanceId: ready.instanceId,
|
|
9221
|
-
reconnect: true,
|
|
9222
|
-
onLog: (event)=>{
|
|
9223
|
-
if (matches(event)) printEvent(event, format);
|
|
9224
|
-
},
|
|
9225
|
-
onGap: (gap)=>{
|
|
9226
|
-
console.error(`… ${gap.dropped} event(s) dropped (${gap.reason}), stream is behind`);
|
|
9227
|
-
}
|
|
9228
|
-
});
|
|
9229
|
-
const shutdown = (signal)=>{
|
|
9230
|
-
consumer.close();
|
|
9231
|
-
if ('pretty' !== format) console.log(JSON.stringify(messaging.Pr.ok('logs', 'interrupted', {
|
|
9232
|
-
signal,
|
|
9233
|
-
follow: true
|
|
9234
|
-
})));
|
|
9235
|
-
exitAfterDrain(0);
|
|
9236
|
-
};
|
|
9237
|
-
process.on('SIGINT', ()=>shutdown('SIGINT'));
|
|
9238
|
-
process.on('SIGTERM', ()=>shutdown('SIGTERM'));
|
|
9239
|
-
consumer.start();
|
|
9240
|
-
await new Promise(()=>{});
|
|
9241
|
-
}
|
|
9242
9285
|
var run_only = __webpack_require__("./browsers/run-only.ts");
|
|
9243
9286
|
const PREVIEW_NOT_FOUND_NEEDLES = [
|
|
9244
9287
|
'Preview is run-only',
|
|
9245
9288
|
'Manifest file not found'
|
|
9246
9289
|
];
|
|
9247
9290
|
function registerPreviewCommand(program) {
|
|
9248
|
-
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(
|
|
9291
|
+
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').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').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 <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)=>{
|
|
9249
9292
|
const { browser = 'chromium', ...previewOptions } = options;
|
|
9250
9293
|
if (previewOptions.debug || previewOptions.author || previewOptions.authorMode) {
|
|
9251
9294
|
process.env.EXTENSION_DEBUG = '1';
|
|
@@ -9496,7 +9539,7 @@ Cross-browser compatibility
|
|
|
9496
9539
|
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : 8080;
|
|
9497
9540
|
}
|
|
9498
9541
|
function registerStartCommand(program) {
|
|
9499
|
-
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(
|
|
9542
|
+
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').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').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)=>{
|
|
9500
9543
|
const { browser = 'chromium', ...startOptions } = options;
|
|
9501
9544
|
if (startOptions.debug || startOptions.author || startOptions.authorMode) {
|
|
9502
9545
|
process.env.EXTENSION_DEBUG = '1';
|
|
@@ -6,6 +6,9 @@ export type FirefoxPluginLike = Pick<PluginInterface, 'extension' | 'browserFlag
|
|
|
6
6
|
export interface FirefoxPluginRuntime extends FirefoxPluginLike {
|
|
7
7
|
rdpController?: FirefoxRDPController;
|
|
8
8
|
browserVersionLine?: string;
|
|
9
|
+
launchProfilePath?: string;
|
|
10
|
+
launchBinaryPath?: string;
|
|
11
|
+
launchBinaryProvenance?: 'managed' | 'pinned' | 'system' | 'snapshot';
|
|
9
12
|
logSink?: BrowserLogSink;
|
|
10
13
|
extensionLoadRefused?: string;
|
|
11
14
|
retryAddonInstall?: () => Promise<ExtensionLoadRetryResult>;
|
|
@@ -12,6 +12,9 @@ type PluginLike = {
|
|
|
12
12
|
watchSource?: boolean;
|
|
13
13
|
port?: number | string;
|
|
14
14
|
browserVersionLine?: string;
|
|
15
|
+
launchProfilePath?: string;
|
|
16
|
+
launchBinaryPath?: string;
|
|
17
|
+
launchBinaryProvenance?: 'managed' | 'pinned' | 'system' | 'snapshot';
|
|
15
18
|
};
|
|
16
19
|
export declare class FirefoxRDPController {
|
|
17
20
|
private readonly remote;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export declare function printRunningInDevelopmentSummary(candidateAddonPaths: string[], browser: 'firefox', extensionId?: string, browserVersionLine?: string
|
|
1
|
+
export declare function printRunningInDevelopmentSummary(candidateAddonPaths: string[], browser: 'firefox', extensionId?: string, browserVersionLine?: string, launchIdentity?: {
|
|
2
|
+
profilePath?: string;
|
|
3
|
+
binaryPath?: string;
|
|
4
|
+
binaryProvenance?: 'managed' | 'pinned' | 'system' | 'snapshot';
|
|
5
|
+
}): Promise<boolean>;
|
|
2
6
|
export declare function printLogEventPretty(event: {
|
|
3
7
|
id: string;
|
|
4
8
|
timestamp: number;
|
|
@@ -13,6 +13,9 @@ export declare class RemoteFirefox {
|
|
|
13
13
|
constructor(configOptions: PluginInterface & {
|
|
14
14
|
browserVersionLine?: string;
|
|
15
15
|
resolvedRdpPort?: number;
|
|
16
|
+
launchProfilePath?: string;
|
|
17
|
+
launchBinaryPath?: string;
|
|
18
|
+
launchBinaryProvenance?: 'managed' | 'pinned' | 'system' | 'snapshot';
|
|
16
19
|
});
|
|
17
20
|
private resolveRdpPort;
|
|
18
21
|
private connectClient;
|
|
@@ -16,6 +16,8 @@ export interface SafariPackagerOverrides {
|
|
|
16
16
|
export interface SafariPackagerOptions extends SafariPackagerOverrides {
|
|
17
17
|
/** 'safari' or 'webkit-based'. Defaults to 'safari'. */
|
|
18
18
|
browser?: 'safari' | 'webkit-based';
|
|
19
|
+
/** Print the dev identity card and ready line after the first full package. */
|
|
20
|
+
announceDevReady?: boolean;
|
|
19
21
|
/** Skip opening the packaged app. Defaults to true: packaging is not launching. */
|
|
20
22
|
noOpen?: boolean;
|
|
21
23
|
/** Print the commands instead of running them. */
|
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
export interface LogEventLike {
|
|
3
|
+
type?: unknown;
|
|
4
|
+
eventType?: unknown;
|
|
5
|
+
context?: unknown;
|
|
6
|
+
level?: unknown;
|
|
7
|
+
seq?: unknown;
|
|
8
|
+
url?: unknown;
|
|
9
|
+
hostname?: unknown;
|
|
10
|
+
tabId?: unknown;
|
|
11
|
+
messageParts?: unknown;
|
|
12
|
+
code?: unknown;
|
|
13
|
+
remediation?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export declare function formatPrettyLogLine(event: LogEventLike): string;
|
|
2
16
|
export declare function registerLogsCommand(program: Command): void;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export type Browser = 'chrome' | 'edge' | 'firefox' | 'chromium' | 'chromium-based' | 'gecko-based' | 'firefox-based' | 'safari' | 'webkit-based';
|
|
2
2
|
export declare function isSafariVendor(value: string): boolean;
|
|
3
|
+
export declare const SUPPORTED_BROWSER_TARGETS: string[];
|
|
4
|
+
export declare const BROWSER_TARGETS_HELP: string;
|
|
5
|
+
export declare const NO_SAFARI_BROWSER_TARGETS_HELP: string;
|
|
3
6
|
export declare function parseOptionalBoolean(value?: string): boolean;
|
|
4
7
|
export declare const vendors: (browser?: Browser | 'all') => string[];
|
|
5
8
|
export declare const installTargets: (browser?: Browser | 'all') => string[];
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"extension": "./bin/extension.cjs"
|
|
39
39
|
},
|
|
40
40
|
"name": "extension",
|
|
41
|
-
"version": "4.0.
|
|
41
|
+
"version": "4.0.29-next.0",
|
|
42
42
|
"description": "The cross-browser extension framework. Build Chrome, Edge, Firefox, and Safari extensions with no build configuration.",
|
|
43
43
|
"homepage": "https://extension.js.org/",
|
|
44
44
|
"bugs": {
|
|
@@ -106,9 +106,9 @@
|
|
|
106
106
|
"vivaldi-location2": "2.1.1",
|
|
107
107
|
"waterfox-location": "2.1.1",
|
|
108
108
|
"yandex-location": "2.1.1",
|
|
109
|
-
"extension-create": "4.0.
|
|
110
|
-
"extension-develop": "4.0.
|
|
111
|
-
"extension-install": "4.0.
|
|
109
|
+
"extension-create": "4.0.29-next.0",
|
|
110
|
+
"extension-develop": "4.0.29-next.0",
|
|
111
|
+
"extension-install": "4.0.29-next.0",
|
|
112
112
|
"commander": "^15.0.0",
|
|
113
113
|
"pintor": "0.3.0",
|
|
114
114
|
"semver": "^7.7.3",
|