@aryanduntley/pwa-debug 0.1.4 → 0.1.6
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/main.js +71 -15
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -12818,13 +12818,20 @@ const freshFlags = (port, userDataDir) => Object.freeze([
|
|
|
12818
12818
|
* --load-extension, and --disable-extensions-except would additionally block
|
|
12819
12819
|
* the manual Load-unpack the user is steered to. The profile/port still come
|
|
12820
12820
|
* up; the extension is provisioned by hand afterward.
|
|
12821
|
+
*
|
|
12822
|
+
* `isolate` (default true) controls --disable-extensions-except, which pins the
|
|
12823
|
+
* profile to ONLY pwa-debug — Chromium disables every other extension, including
|
|
12824
|
+
* ones already in the persistent profile or Load-unpacked/installed after launch.
|
|
12825
|
+
* Pass false to drop it so other extensions coexist: --load-extension still
|
|
12826
|
+
* preloads pwa-debug, while the profile's other extensions stay enabled. No-op
|
|
12827
|
+
* under 'manual-guided' (the flag is already omitted there).
|
|
12821
12828
|
*/
|
|
12822
|
-
const sandboxFlags = (port, userDataDir, extensionPath, strategy) => {
|
|
12829
|
+
const sandboxFlags = (port, userDataDir, extensionPath, strategy, isolate) => {
|
|
12823
12830
|
const extensionFlags = strategy === 'manual-guided'
|
|
12824
12831
|
? []
|
|
12825
12832
|
: [
|
|
12826
12833
|
`--load-extension=${extensionPath}`,
|
|
12827
|
-
`--disable-extensions-except=${extensionPath}
|
|
12834
|
+
...(isolate ? [`--disable-extensions-except=${extensionPath}`] : []),
|
|
12828
12835
|
...(strategy === 'load-flag-escape-hatch'
|
|
12829
12836
|
? ['--disable-features=DisableLoadExtensionCommandLineSwitch']
|
|
12830
12837
|
: []),
|
|
@@ -12872,7 +12879,8 @@ const buildNewWindowFlatpakArgs = (appId) => flatpakRun(appId, Object.freeze(['-
|
|
|
12872
12879
|
/**
|
|
12873
12880
|
* Sandbox launch: dedicated profile + the pwa-debug extension preloaded BEFORE
|
|
12874
12881
|
* any tab opens (so the content-script injection race cannot occur).
|
|
12875
|
-
* --disable-extensions-except pins the profile to only our extension
|
|
12882
|
+
* --disable-extensions-except pins the profile to only our extension when
|
|
12883
|
+
* `isolate` is true (the default); pass false to let other extensions coexist.
|
|
12876
12884
|
*
|
|
12877
12885
|
* --disable-session-crashed-bubble + --hide-crash-restore-bubble suppress the
|
|
12878
12886
|
* "Brave/Chrome didn't shut down correctly — restore tabs?" prompt on the NEXT
|
|
@@ -12883,9 +12891,9 @@ const buildNewWindowFlatpakArgs = (appId) => flatpakRun(appId, Object.freeze(['-
|
|
|
12883
12891
|
* Applied to sandbox modes only — an 'existing'-mode launch is the user's real
|
|
12884
12892
|
* profile, where a genuine restore prompt should be left intact.
|
|
12885
12893
|
*/
|
|
12886
|
-
const buildSandboxSpawnArgs = (execPath, port, userDataDir, extensionPath, strategy) => Object.freeze({
|
|
12894
|
+
const buildSandboxSpawnArgs = (execPath, port, userDataDir, extensionPath, strategy, isolate = true) => Object.freeze({
|
|
12887
12895
|
cmd: execPath,
|
|
12888
|
-
args: sandboxFlags(port, userDataDir, extensionPath, strategy),
|
|
12896
|
+
args: sandboxFlags(port, userDataDir, extensionPath, strategy, isolate),
|
|
12889
12897
|
});
|
|
12890
12898
|
/**
|
|
12891
12899
|
* Sandbox launch for a flatpak browser: `flatpak run <app-id> <sandbox flags>`.
|
|
@@ -12894,7 +12902,7 @@ const buildSandboxSpawnArgs = (execPath, port, userDataDir, extensionPath, strat
|
|
|
12894
12902
|
* (`flatpak override --user --filesystem=host <app-id>`) for these to resolve
|
|
12895
12903
|
* inside the sandbox — the same prerequisite the NMH path documents.
|
|
12896
12904
|
*/
|
|
12897
|
-
const buildSandboxFlatpakArgs = (appId, port, userDataDir, extensionPath, strategy) => flatpakRun(appId, sandboxFlags(port, userDataDir, extensionPath, strategy));
|
|
12905
|
+
const buildSandboxFlatpakArgs = (appId, port, userDataDir, extensionPath, strategy, isolate = true) => flatpakRun(appId, sandboxFlags(port, userDataDir, extensionPath, strategy, isolate));
|
|
12898
12906
|
|
|
12899
12907
|
/**
|
|
12900
12908
|
* 'existing'-mode launch: the graceful-degradation triad orchestrated over the
|
|
@@ -13002,9 +13010,11 @@ const launchSandbox = async (input, deps) => {
|
|
|
13002
13010
|
// refuse the unpacked --load-extension (#318). Seed developer_mode=true into the
|
|
13003
13011
|
// profile's Preferences before spawn so the extension loads with no manual step.
|
|
13004
13012
|
await deps.seedDeveloperMode(input.userDataDir);
|
|
13013
|
+
// Default to isolation (clean-room) when unset; false lets other extensions coexist.
|
|
13014
|
+
const isolate = input.isolateExtensions ?? true;
|
|
13005
13015
|
const { cmd, args } = input.appId
|
|
13006
|
-
? buildSandboxFlatpakArgs(input.appId, input.port, input.userDataDir, input.extensionPath, input.loadStrategy)
|
|
13007
|
-
: buildSandboxSpawnArgs(input.execPath, input.port, input.userDataDir, input.extensionPath, input.loadStrategy);
|
|
13016
|
+
? buildSandboxFlatpakArgs(input.appId, input.port, input.userDataDir, input.extensionPath, input.loadStrategy, isolate)
|
|
13017
|
+
: buildSandboxSpawnArgs(input.execPath, input.port, input.userDataDir, input.extensionPath, input.loadStrategy, isolate);
|
|
13008
13018
|
const { pid } = await deps.spawnBrowser(cmd, args);
|
|
13009
13019
|
if (input.mode === 'sandbox-temp') {
|
|
13010
13020
|
deps.registerTempProfile(input.userDataDir);
|
|
@@ -14009,6 +14019,7 @@ const inputSchema$5 = {
|
|
|
14009
14019
|
port: numberType().int().min(1).max(65535).optional(),
|
|
14010
14020
|
mode: enumType(MODES).optional(),
|
|
14011
14021
|
packaging: enumType(PACKAGINGS).optional(),
|
|
14022
|
+
isolateExtensions: booleanType().optional(),
|
|
14012
14023
|
};
|
|
14013
14024
|
const isSandboxMode = (mode) => mode === 'sandbox-persistent' || mode === 'sandbox-temp';
|
|
14014
14025
|
/**
|
|
@@ -14200,6 +14211,9 @@ const launchBrowserCore = async (args, platform, env, deps) => {
|
|
|
14200
14211
|
loadStrategy,
|
|
14201
14212
|
mode,
|
|
14202
14213
|
refreshExtension: refreshExtensionEnabled(mode, env),
|
|
14214
|
+
...(args.isolateExtensions !== undefined
|
|
14215
|
+
? { isolateExtensions: args.isolateExtensions }
|
|
14216
|
+
: {}),
|
|
14203
14217
|
...(target.appId !== undefined ? { appId: target.appId } : {}),
|
|
14204
14218
|
...(snapPkg ? { snapPackage: snapPkg } : {}),
|
|
14205
14219
|
});
|
|
@@ -14250,7 +14264,7 @@ const launchBrowserHandler = async (args, ctx) => launchBrowserCore(args, proces
|
|
|
14250
14264
|
});
|
|
14251
14265
|
const launchBrowserTool = Object.freeze({
|
|
14252
14266
|
name: 'pdl_launch_browser',
|
|
14253
|
-
description: "Launch or attach to a Chromium-family browser with a live remote-debugging port, for use alongside chrome-devtools-mcp. Modes: mode='existing' (default) targets the user's normal profile and degrades gracefully — (a) port already live → attach; (b) running without a debug port → opens a NEW WINDOW in the existing session (never kills it), attached:false + degradation message; (c) not running → spawns fresh with --remote-debugging-port + --user-data-dir=<your profile>. mode='sandbox-persistent' spawns a dedicated, persistent dev profile at ~/.pwa-debug/profiles/<browser>/ beside your normal browser, with the pwa-debug extension PRELOADED (no reload needed); mode='sandbox-temp' is the same but in a throwaway mkdtemp profile cleaned up on host shutdown. Sandbox modes always work standalone (separate profile → no lock collision) and both pwa-debug + CDP tools are available. Args: browser? (chrome|chromium|edge|brave|vivaldi|opera; defaults to system-default), port? (default 9222), mode?, packaging? (native|snap|flatpak). When the same browser is installed under multiple packagings (e.g. snap AND flatpak chromium), pass packaging to pick one; without it the default preference is native > snap > flatpak and next_steps lists the alternatives so you can re-target. Linux is first-class; macOS/Windows deferred. Follow next_steps[] — it carries the chrome-devtools-mcp registration snippet, the profile location, the flatpak onboarding steps, or the degradation guidance.",
|
|
14267
|
+
description: "Launch or attach to a Chromium-family browser with a live remote-debugging port, for use alongside chrome-devtools-mcp. Modes: mode='existing' (default) targets the user's normal profile and degrades gracefully — (a) port already live → attach; (b) running without a debug port → opens a NEW WINDOW in the existing session (never kills it), attached:false + degradation message; (c) not running → spawns fresh with --remote-debugging-port + --user-data-dir=<your profile>. mode='sandbox-persistent' spawns a dedicated, persistent dev profile at ~/.pwa-debug/profiles/<browser>/ beside your normal browser, with the pwa-debug extension PRELOADED (no reload needed); mode='sandbox-temp' is the same but in a throwaway mkdtemp profile cleaned up on host shutdown. Sandbox modes always work standalone (separate profile → no lock collision) and both pwa-debug + CDP tools are available. Args: browser? (chrome|chromium|edge|brave|vivaldi|opera; defaults to system-default), port? (default 9222), mode?, packaging? (native|snap|flatpak). When the same browser is installed under multiple packagings (e.g. snap AND flatpak chromium), pass packaging to pick one; without it the default preference is native > snap > flatpak and next_steps lists the alternatives so you can re-target. isolateExtensions? (sandbox modes only, default true): true pins the dedicated profile to ONLY the pwa-debug extension (clean room — every other extension is disabled); pass false to let other extensions coexist (pwa-debug still preloads, while extensions already in the persistent profile or Load-unpacked/installed after launch stay enabled) — use this to debug a PWA alongside other extensions or to test your own extension with pwa-debug. existing mode already keeps all your normal-profile extensions. Linux is first-class; macOS/Windows deferred. Follow next_steps[] — it carries the chrome-devtools-mcp registration snippet, the profile location, the flatpak onboarding steps, or the degradation guidance.",
|
|
14254
14268
|
inputSchema: inputSchema$5,
|
|
14255
14269
|
handler: launchBrowserHandler,
|
|
14256
14270
|
});
|
|
@@ -15027,6 +15041,21 @@ const snapshotConn = (c) => Object.freeze({
|
|
|
15027
15041
|
connectedAt: c.connectedAt,
|
|
15028
15042
|
lastSeenAt: c.lastSeenAt,
|
|
15029
15043
|
});
|
|
15044
|
+
// Probe whether a unix socket path has a live listener. Resolves 'live' if a
|
|
15045
|
+
// connection is accepted, 'stale' if the path refuses connection (ECONNREFUSED)
|
|
15046
|
+
// or is gone (ENOENT) — i.e. an orphaned socket file left behind by a host that
|
|
15047
|
+
// was hard-killed (SIGKILL / terminal close / crash) before close() could
|
|
15048
|
+
// unlink it. Used to decide whether an EADDRINUSE bind failure is a genuine
|
|
15049
|
+
// conflict (another host is up) or a reclaimable stale file.
|
|
15050
|
+
const probeSocketLiveness = (path) => new Promise((resolve) => {
|
|
15051
|
+
const probe = createConnection(path);
|
|
15052
|
+
const settle = (result) => {
|
|
15053
|
+
probe.destroy();
|
|
15054
|
+
resolve(result);
|
|
15055
|
+
};
|
|
15056
|
+
probe.once('connect', () => settle('live'));
|
|
15057
|
+
probe.once('error', () => settle('stale'));
|
|
15058
|
+
});
|
|
15030
15059
|
const createIpcServer = async (opts) => {
|
|
15031
15060
|
const connections = new Map();
|
|
15032
15061
|
const pending = new Map();
|
|
@@ -15117,12 +15146,39 @@ const createIpcServer = async (opts) => {
|
|
|
15117
15146
|
const socketPaths = [opts.socketPath, ...(opts.extraSocketPaths ?? [])];
|
|
15118
15147
|
const servers = socketPaths.map(() => createServer(handleSocket));
|
|
15119
15148
|
const listenOne = (server, path) => new Promise((resolve, reject) => {
|
|
15120
|
-
const
|
|
15121
|
-
|
|
15122
|
-
|
|
15123
|
-
|
|
15124
|
-
|
|
15125
|
-
|
|
15149
|
+
const attempt = (recovered) => {
|
|
15150
|
+
const onError = (err) => {
|
|
15151
|
+
const recoverable = err.code === 'EADDRINUSE' &&
|
|
15152
|
+
!recovered &&
|
|
15153
|
+
process.platform !== 'win32';
|
|
15154
|
+
if (!recoverable) {
|
|
15155
|
+
reject(err);
|
|
15156
|
+
return;
|
|
15157
|
+
}
|
|
15158
|
+
// A prior host may have been hard-killed without unlinking its socket.
|
|
15159
|
+
// Probe before clobbering: only reclaim a path nothing is listening on
|
|
15160
|
+
// — never unlink out from under a host that is genuinely up.
|
|
15161
|
+
void probeSocketLiveness(path).then(async (liveness) => {
|
|
15162
|
+
if (liveness === 'live') {
|
|
15163
|
+
reject(new Error(`ipc server: another pwa-debug host is already listening on ${path}`));
|
|
15164
|
+
return;
|
|
15165
|
+
}
|
|
15166
|
+
try {
|
|
15167
|
+
await unlink(path);
|
|
15168
|
+
}
|
|
15169
|
+
catch {
|
|
15170
|
+
// already gone — fine, just retry the bind
|
|
15171
|
+
}
|
|
15172
|
+
attempt(true);
|
|
15173
|
+
});
|
|
15174
|
+
};
|
|
15175
|
+
server.once('error', onError);
|
|
15176
|
+
server.listen(path, () => {
|
|
15177
|
+
server.off('error', onError);
|
|
15178
|
+
resolve();
|
|
15179
|
+
});
|
|
15180
|
+
};
|
|
15181
|
+
attempt(false);
|
|
15126
15182
|
});
|
|
15127
15183
|
await Promise.all(servers.map((s, i) => listenOne(s, socketPaths[i])));
|
|
15128
15184
|
const sendTo = (extensionId, env) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aryanduntley/pwa-debug",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"@types/winreg": "^1.2.36",
|
|
64
64
|
"rollup": "^4.27.4",
|
|
65
65
|
"tslib": "^2.8.1",
|
|
66
|
-
"@pwa-debug/extension": "0.1.
|
|
67
|
-
"@pwa-debug/shared": "0.1.
|
|
66
|
+
"@pwa-debug/extension": "0.1.6",
|
|
67
|
+
"@pwa-debug/shared": "0.1.6"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"typecheck": "tsc --noEmit",
|