dorkos 0.98.0 → 0.101.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/README.md +43 -13
- package/dist/bin/cli.js +10649 -8676
- package/dist/browser/fresh-verifier.mjs +3 -2
- package/dist/browser/native/darwin-journal-worker.mjs +2244 -0
- package/dist/browser/native/darwin-process-observer +0 -0
- package/dist/browser/native/darwin-process-observer.c +252 -0
- package/dist/browser/native/darwin-process-observer.h +37 -0
- package/dist/browser/native/darwin-process-observer.manifest.json +1 -0
- package/dist/browser/native/darwin-supervisor-worker.mjs +1996 -0
- package/dist/browser/native/package-manifest.json +1 -0
- package/dist/browser/source-manifest.json +1 -1
- package/dist/client/assets/{AboutPage-DqTcRYx5.js → AboutPage-CwxCTicf.js} +1 -1
- package/dist/client/assets/ActivityRow-D0QQ0SFu.js +1 -0
- package/dist/client/assets/AdapterIcon-CL-MyyKy.js +1 -0
- package/dist/client/assets/AdapterSetupWizard-C8HOvHLF.js +2 -0
- package/dist/client/assets/AgentRequestCard-BLLmoAES.js +12 -0
- package/dist/client/assets/AppearancePage-GqrWckTQ.js +1 -0
- package/dist/client/assets/AttentionSignalRow-sEhnIPBB.js +1 -0
- package/dist/client/assets/{BaseTanStackRouterDevtoolsPanel-B-iktbLX-Bmlsorom.js → BaseTanStackRouterDevtoolsPanel-B-iktbLX-BXjzhT_D.js} +1 -1
- package/dist/client/assets/{BlintzCanvas-BBW7iNEC.js → BlintzCanvas-CXi0fvcM.js} +1 -1
- package/dist/client/assets/{CanvasCsvContent-D6qWSQm4.js → CanvasCsvContent-QhDSf8Pd.js} +2 -2
- package/dist/client/assets/CanvasFileContent-ZZhdofR4.js +2 -0
- package/dist/client/assets/CanvasModel3dContent-DMMMZh4o.js +2 -0
- package/dist/client/assets/{CodeMirrorDiff-DsOh9sIB.js → CodeMirrorDiff-BMG7DBg2.js} +1 -1
- package/dist/client/assets/{CodeMirrorEditor-BxIWDXqr.js → CodeMirrorEditor-BYdz0ipX.js} +1 -1
- package/dist/client/assets/ConnectionAccessLists-PW1uzcGU.js +1 -0
- package/dist/client/assets/{ConnectionsPage-DvxSfsfG.js → ConnectionsPage-EwitZwOE.js} +3 -3
- package/dist/client/assets/ConventionPage-y-Zq3Klp.js +11 -0
- package/dist/client/assets/ExtensionPageRoute-gZKKPhaj.js +6 -0
- package/dist/client/assets/{FloatingTanStackRouterDevtools-CqogiFob-BCrkUo51.js → FloatingTanStackRouterDevtools-CqogiFob-CbKIa11X.js} +1 -1
- package/dist/client/assets/HandlePage-CL3_n1CI.js +1 -0
- package/dist/client/assets/{LexicalField-mvJHHMqo.js → LexicalField-Ceoa9flp.js} +13 -13
- package/dist/client/assets/{ManagesPage-DScJn5uY.js → ManagesPage-Dcqdm6I8.js} +1 -1
- package/dist/client/assets/Marketplace-DsU-q1ZZ.js +36 -0
- package/dist/client/assets/MarketplaceSourcesView-D72YoKNR.js +1 -0
- package/dist/client/assets/McpAppFrame-B1ThSf2U.js +6 -0
- package/dist/client/assets/McpSigninBody-Btg3PnYN.js +1 -0
- package/dist/client/assets/{Model3dViewer-BYNxJNRV.js → Model3dViewer-DlcQ3-LS.js} +1 -1
- package/dist/client/assets/NamePage-Bzqj4Eob.js +1 -0
- package/dist/client/assets/NewDirectMessageMenu-89yeGqvy.js +1 -0
- package/dist/client/assets/{NotificationsPage-CU6oIOwb.js → NotificationsPage-CQQIdLtI.js} +1 -1
- package/dist/client/assets/OperatorIdentityForm-BhiB9tQp.js +1 -0
- package/dist/client/assets/{PermissionsPage-BIatOhyg.js → PermissionsPage-TX-d7aVQ.js} +1 -1
- package/dist/client/assets/PersonalityPicker-C_9JVOva.js +1 -0
- package/dist/client/assets/PersonalityPopover-BoTED73t.js +1 -0
- package/dist/client/assets/PhotoPage-C3fMlebQ.js +1 -0
- package/dist/client/assets/PreviewRefusedNotice-ChCgdKWN.js +1 -0
- package/dist/client/assets/PromptSuggestionChips-B_oUtFMI.js +1 -0
- package/dist/client/assets/RoomSurface-CgtNuYhl.js +39 -0
- package/dist/client/assets/RoomsPage-zOjjpHdA.js +1 -0
- package/dist/client/assets/RunsOnPopover-JTm1cYuw.js +1 -0
- package/dist/client/assets/SessionsPage-D4kyvHQf.js +6 -0
- package/dist/client/assets/SkillsPage-KYUVzuVa.js +1 -0
- package/dist/client/assets/TasksPage-BZapA_v6.js +1 -0
- package/dist/client/assets/{ToolsPage-BMW27c-X.js → ToolsPage-CWpHMlrR.js} +2 -2
- package/dist/client/assets/{TopologyGraph-u-ihEvQa.js → TopologyGraph-BMcPxZsA.js} +3 -3
- package/dist/client/assets/TourHost-VY1-sy1Y.js +1 -0
- package/dist/client/assets/UnlinkDialog-3p38G_9q.js +1 -0
- package/dist/client/assets/UnreadDivider-KSqqcHKN.js +1 -0
- package/dist/client/assets/_shell-DAjwimLg.js +93 -0
- package/dist/client/assets/_shell._home-Bp_p1VUv.js +1 -0
- package/dist/client/assets/_shell._home.activity-tk-XApvX.js +1 -0
- package/dist/client/assets/_shell._home.index-BNVhSN0y.js +3 -0
- package/dist/client/assets/_shell._home.tasks-BsBH_4tZ.js +1 -0
- package/dist/client/assets/_shell._home.workspaces-DuXnjQh0.js +1 -0
- package/dist/client/assets/_shell.channels-DWAHkDPV.js +10 -0
- package/dist/client/assets/_shell.connections-DIm3mUHy.js +6 -0
- package/dist/client/assets/_shell.feedback-requests-Hjv640j9.js +2 -0
- package/dist/client/assets/_shell.marketplace-DF6Y7mc0.js +1 -0
- package/dist/client/assets/_shell.marketplace_.sources-Do8cm7kq.js +1 -0
- package/dist/client/assets/_shell.session-DlN8iOl-.js +43 -0
- package/dist/client/assets/_shell.team-ctLQztjw.js +28 -0
- package/dist/client/assets/_shell.x._extensionId-0Q1rJtud.js +1 -0
- package/dist/client/assets/_shell.x._extensionId_._-0Q1rJtud.js +1 -0
- package/dist/client/assets/agent-attention-Dn__3LQE.js +5 -0
- package/dist/client/assets/{agent-browser-Bn5EG403.js → agent-browser-CCN16ZOz.js} +1 -1
- package/dist/client/assets/banner-DOm9_4l-.js +6 -0
- package/dist/client/assets/composer-insert-BpyATrmR.js +1 -0
- package/dist/client/assets/dorkbot-templates-cu4wApxb.js +1 -0
- package/dist/client/assets/file-drag-GDx2qhdk.js +1 -0
- package/dist/client/assets/file-exclamation-point-BKzL0QhY.js +6 -0
- package/dist/client/assets/format-duration-BCr6uzby.js +1 -0
- package/dist/client/assets/hand-DLUdsiuR.js +6 -0
- package/dist/client/assets/{highlighted-body-KPVGNVTW-CL9x-9e4.js → highlighted-body-KPVGNVTW-DTxMTVdP.js} +1 -1
- package/dist/client/assets/hover-card-qzuFUCaR.js +1 -0
- package/dist/client/assets/{index-nEOi__50.js → index-3lQkXKcq.js} +1 -1
- package/dist/client/assets/{index-CpJvQdyn.js → index-B-z7hA9x.js} +1 -1
- package/dist/client/assets/{index-C-wQjAlh.js → index-BIMClIrX.js} +1 -1
- package/dist/client/assets/{index-lrzDDn8S.js → index-BMOfHKE0.js} +1 -1
- package/dist/client/assets/{index-CK35WFBO.js → index-BPcwoJoz.js} +1 -1
- package/dist/client/assets/{index-CsQv_9cY.js → index-BW5ce4t8.js} +1 -1
- package/dist/client/assets/{index-C2L0bOg6.js → index-BaB-skF0.js} +3 -3
- package/dist/client/assets/{index-DAXybyxB.js → index-Bk98IpMn.js} +1 -1
- package/dist/client/assets/{index-62aJQhJd.js → index-C3XnoXTY.js} +1 -1
- package/dist/client/assets/{index-tY8nAJmx.js → index-C7B2uRgo.js} +2 -2
- package/dist/client/assets/index-C8ZMfyGc.js +1 -0
- package/dist/client/assets/{index-BSl_jWtK.js → index-CDTumWMC.js} +1 -1
- package/dist/client/assets/{index-DuWGfUC7.js → index-CF9fqPef.js} +5 -5
- package/dist/client/assets/{index-DEYZcwYZ.js → index-CIPHHziB.js} +1 -1
- package/dist/client/assets/{index-DOVEs6Rq.js → index-CIfwPLXd.js} +1 -1
- package/dist/client/assets/{index-DnjFcJhW.js → index-CLhD0Bno.js} +36 -36
- package/dist/client/assets/index-CQWqpw_G.js +1 -0
- package/dist/client/assets/index-CScfHuKF.js +1 -0
- package/dist/client/assets/index-CTXNRyRE.js +1 -0
- package/dist/client/assets/{index-C3fr7zOo.js → index-CTai_TxZ.js} +1 -1
- package/dist/client/assets/{index-CniKYwdp.js → index-CVl132_4.js} +1 -1
- package/dist/client/assets/index-CejezM4U.js +1 -0
- package/dist/client/assets/{index-Bc9XDEj8.js → index-CmlaXay_.js} +1 -1
- package/dist/client/assets/{index-KIOfBCox.js → index-CtOB9fS3.js} +1 -1
- package/dist/client/assets/{index-DyFf2nbN.js → index-D3DXMH4x.js} +1 -1
- package/dist/client/assets/index-D5uYwabS.js +1 -0
- package/dist/client/assets/{index-CaEda4s3.js → index-DA-i3I4q.js} +1 -1
- package/dist/client/assets/index-DFMDv6qR.js +1 -0
- package/dist/client/assets/index-DMYBI16t.js +1252 -0
- package/dist/client/assets/{index-DzBsotRj.js → index-DOxEmnH2.js} +1 -1
- package/dist/client/assets/{index-Dxkj6c9m.js → index-DR1JT9Uz.js} +12 -12
- package/dist/client/assets/{index-BO-CpekL.js → index-DT_v3O-B.js} +1 -1
- package/dist/client/assets/index-DbbZNAKk.js +5 -0
- package/dist/client/assets/{index-BBz-vkiB.js → index-Dcs6e-U_.js} +1 -1
- package/dist/client/assets/{index-BE54c4kA.js → index-DgH_dl1a.js} +2 -2
- package/dist/client/assets/{index-DPGgujWh.js → index-DgtF-nBt.js} +1 -1
- package/dist/client/assets/{index-BlbBz069.js → index-DwzSdOh3.js} +1 -1
- package/dist/client/assets/index-IgIVF9T_.js +1 -0
- package/dist/client/assets/{index-aFkVVlMJ.js → index-WjW-NUCp.js} +1 -1
- package/dist/client/assets/layers-CJHXSEKK.js +6 -0
- package/dist/client/assets/lightbulb-DWjxw7lb.js +6 -0
- package/dist/client/assets/mention-pill-akMU3IVs.js +1 -0
- package/dist/client/assets/message-square-off-DEagHpQY.js +6 -0
- package/dist/client/assets/owner-notice-CLsx0s7q.js +1 -0
- package/dist/client/assets/page-container-W7byjRmk.js +1 -0
- package/dist/client/assets/primer-trigger-DuM9vVnV.js +3 -0
- package/dist/client/assets/radio-B8Ozjv9U.js +6 -0
- package/dist/client/assets/{room-files-source-BXJ2jlgd.js → room-files-source-Bsc3YA91.js} +2 -2
- package/dist/client/assets/rotate-ccw-clock-CNcDcTvq.js +6 -0
- package/dist/client/assets/rotate-cw-xvfipJLN.js +6 -0
- package/dist/client/assets/scroll-area-C95q3ss7.js +1 -0
- package/dist/client/assets/search-x-C6SAxw7a.js +6 -0
- package/dist/client/assets/session-strategy-labels-C7Wduch3.js +1 -0
- package/dist/client/assets/shield-x-DxOGc0dW.js +6 -0
- package/dist/client/assets/{soul-file-11avkxYV.js → soul-file-pg0ShYy3.js} +1 -1
- package/dist/client/assets/untrusted-text-1hXdPgLA.js +1 -0
- package/dist/client/assets/use-delete-binding-CZVeHqn0.js +1 -0
- package/dist/client/assets/use-dev-links-Df2WkCic.js +1 -0
- package/dist/client/assets/use-external-adapter-catalog-B0gcY-k7.js +1 -0
- package/dist/client/assets/use-full-activity-feed-SYcgdMZu.js +1 -0
- package/dist/client/assets/use-is-below-desktop-C5_YenEp.js +1 -0
- package/dist/client/assets/use-jump-back-in-DWUPb1gi.js +11 -0
- package/dist/client/assets/use-mesh-topology-HLzZIgis.js +1 -0
- package/dist/client/assets/use-pending-read-BuJknrxG.js +1 -0
- package/dist/client/assets/{use-personality-commit-PCN2Kh8p.js → use-personality-commit-OH7d0xl_.js} +1 -1
- package/dist/client/assets/use-promo-activation-BgdGasXE.js +11 -0
- package/dist/client/assets/use-pulse-freshness-BlD-dM_g.js +1 -0
- package/dist/client/assets/use-rename-session-D3MuyK-F.js +1 -0
- package/dist/client/assets/use-room-follow-claim-CyjhzbRJ.js +1 -0
- package/dist/client/assets/use-roving-tab-list-Be60AWK3.js +1 -0
- package/dist/client/assets/use-session-canvas-Bqs6IQO7.js +64 -0
- package/dist/client/assets/use-session-diagnostics-CfKdB2iY.js +16 -0
- package/dist/client/assets/use-unclaimed-chats-lqMhotUB.js +1 -0
- package/dist/client/index.html +1 -1
- package/dist/client/manifest.webmanifest +1 -1
- package/dist/drizzle/20261005194144_connector_auth_flow_failure_code.sql +1 -0
- package/dist/drizzle/20261005230915_task_run_occurrence.sql +2 -0
- package/dist/drizzle/20261006231015_audit_events.sql +63 -0
- package/dist/drizzle/20261007230701_private_session_identity.sql +15 -0
- package/dist/drizzle/meta/20261005194144_snapshot.json +12238 -0
- package/dist/drizzle/meta/20261005230915_snapshot.json +12252 -0
- package/dist/drizzle/meta/20261006231015_snapshot.json +12519 -0
- package/dist/drizzle/meta/20261007230701_snapshot.json +12611 -0
- package/dist/drizzle/meta/_journal.json +28 -0
- package/dist/server/index.js +161811 -97213
- package/dist/server/index.js.map +2 -2
- package/package.json +5 -5
- package/dist/client/assets/AdapterIcon-CiK683Vv.js +0 -1
- package/dist/client/assets/AppearancePage-CBq2_KUY.js +0 -1
- package/dist/client/assets/CanvasFileContent-jV63reY5.js +0 -2
- package/dist/client/assets/CanvasModel3dContent-DzvsEWGD.js +0 -2
- package/dist/client/assets/ConnectionAccessLists-BWuegEtZ.js +0 -1
- package/dist/client/assets/ConventionPage-CYV7X_nF.js +0 -11
- package/dist/client/assets/HandlePage-CJpRpaLw.js +0 -1
- package/dist/client/assets/NamePage-KoYyo25o.js +0 -1
- package/dist/client/assets/PersonalityPopover-CFRYfO5E.js +0 -1
- package/dist/client/assets/PhotoPage-DkGyFlWQ.js +0 -1
- package/dist/client/assets/RoomsPage-ClT030eV.js +0 -1
- package/dist/client/assets/RunsOnPopover-CNCO9sZk.js +0 -1
- package/dist/client/assets/SessionsPage-5xEcQImi.js +0 -6
- package/dist/client/assets/SkillsPage-ic4TDV4I.js +0 -1
- package/dist/client/assets/TasksPage-C_GFpRgB.js +0 -1
- package/dist/client/assets/index-6COO_Ljw.js +0 -1
- package/dist/client/assets/index-BKl9b2dT.js +0 -1
- package/dist/client/assets/index-BVtk6Sb_.js +0 -1
- package/dist/client/assets/index-Bxrxl2HH.js +0 -1
- package/dist/client/assets/index-C6uVMs3w.js +0 -1
- package/dist/client/assets/index-DEvFAO8t.js +0 -1
- package/dist/client/assets/index-DpSk7iO1.js +0 -1680
|
@@ -0,0 +1,1996 @@
|
|
|
1
|
+
// packages/browser/src/lifecycle/errors.ts
|
|
2
|
+
var codes = /* @__PURE__ */ new Set([
|
|
3
|
+
"BROWSER_LAUNCH_TIMEOUT",
|
|
4
|
+
"BROWSER_STOPPED",
|
|
5
|
+
"CAPTURE_FAILED",
|
|
6
|
+
"CAPTURE_LIMIT",
|
|
7
|
+
"CAPTURE_QUEUE_FULL",
|
|
8
|
+
"CAPTURE_TIMEOUT",
|
|
9
|
+
"COMMAND_UNSUPPORTED",
|
|
10
|
+
"CONTEXT_CLOSE_TIMEOUT",
|
|
11
|
+
"COUNTER_EXHAUSTED",
|
|
12
|
+
"ENGINE_STOPPED",
|
|
13
|
+
"EXECUTABLE_UNAVAILABLE",
|
|
14
|
+
"FIXTURE_PROXY_CLOSE_FAILED",
|
|
15
|
+
"FIXTURE_PROXY_UNAVAILABLE",
|
|
16
|
+
"IDENTITY_MODE_UNAVAILABLE",
|
|
17
|
+
"INITIAL_NAVIGATION_FAILED",
|
|
18
|
+
"LIBRARY_UNAVAILABLE",
|
|
19
|
+
"NETWORK_POLICY_UNSUPPORTED",
|
|
20
|
+
"OPEN_FAILED",
|
|
21
|
+
"OPERATION_FAILED",
|
|
22
|
+
"PAGE_UNAVAILABLE",
|
|
23
|
+
"PLATFORM_UNSUPPORTED",
|
|
24
|
+
"POLICY_REFUSED",
|
|
25
|
+
"POLICY_UNAVAILABLE",
|
|
26
|
+
"PROCESS_ATTRIBUTION_UNAVAILABLE",
|
|
27
|
+
"PROCESS_OBSERVATION_UNAVAILABLE",
|
|
28
|
+
"PROFILE_IN_USE",
|
|
29
|
+
"PROFILE_SETUP_FAILED",
|
|
30
|
+
"PROFILE_UNCERTAIN",
|
|
31
|
+
"RUNTIME_UNAVAILABLE",
|
|
32
|
+
"STALE_BINDING",
|
|
33
|
+
"UNKNOWN_NATIVE_HOLDER",
|
|
34
|
+
"UNSAFE_DIRECTORY"
|
|
35
|
+
]);
|
|
36
|
+
var cleanupCodes = /* @__PURE__ */ new Set([
|
|
37
|
+
"PROFILE_UNCERTAIN",
|
|
38
|
+
"observationUnavailable",
|
|
39
|
+
"closeFailed",
|
|
40
|
+
"processesRemain"
|
|
41
|
+
]);
|
|
42
|
+
var BrowserLifecycleError = class extends Error {
|
|
43
|
+
code;
|
|
44
|
+
cleanupCode;
|
|
45
|
+
constructor(code, cleanupCode) {
|
|
46
|
+
const fixed = codes.has(code) ? code : "OPERATION_FAILED";
|
|
47
|
+
super(`Browser lifecycle failed: ${fixed}`);
|
|
48
|
+
this.name = "BrowserLifecycleError";
|
|
49
|
+
this.code = fixed;
|
|
50
|
+
if (cleanupCode !== void 0)
|
|
51
|
+
this.cleanupCode = cleanupCodes.has(cleanupCode) ? cleanupCode : "observationUnavailable";
|
|
52
|
+
Object.freeze(this);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// packages/browser/src/runtime/default-downloads.ts
|
|
57
|
+
var DefaultDownloadOwner = class {
|
|
58
|
+
constructor(browser, current, lost) {
|
|
59
|
+
this.browser = browser;
|
|
60
|
+
this.current = current;
|
|
61
|
+
this.lost = lost;
|
|
62
|
+
this.ready = Promise.resolve().then(() => {
|
|
63
|
+
if (this.failure) throw this.failure.value;
|
|
64
|
+
return this.acquire();
|
|
65
|
+
});
|
|
66
|
+
void this.ready.catch((value) => {
|
|
67
|
+
this.failure ??= Object.freeze({ value });
|
|
68
|
+
});
|
|
69
|
+
try {
|
|
70
|
+
const on = browser.on;
|
|
71
|
+
if (this.closing) throw new BrowserLifecycleError("ENGINE_STOPPED");
|
|
72
|
+
const off = browser.off;
|
|
73
|
+
if (this.closing) throw new BrowserLifecycleError("ENGINE_STOPPED");
|
|
74
|
+
const disconnected = (original) => {
|
|
75
|
+
if (original === this.browser) this.browserDisconnected = true;
|
|
76
|
+
if (original !== this.browser || !this.closing) {
|
|
77
|
+
this.failure ??= Object.freeze({
|
|
78
|
+
value: new BrowserLifecycleError("OPERATION_FAILED")
|
|
79
|
+
});
|
|
80
|
+
try {
|
|
81
|
+
this.lost();
|
|
82
|
+
} catch (value) {
|
|
83
|
+
this.failure ??= Object.freeze({ value });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
this.removeBrowser = () => {
|
|
88
|
+
Reflect.apply(off, browser, ["disconnected", disconnected]);
|
|
89
|
+
};
|
|
90
|
+
Reflect.apply(on, browser, ["disconnected", disconnected]);
|
|
91
|
+
} catch (value) {
|
|
92
|
+
this.failure ??= Object.freeze({ value });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
browser;
|
|
96
|
+
current;
|
|
97
|
+
lost;
|
|
98
|
+
ready;
|
|
99
|
+
session;
|
|
100
|
+
detach;
|
|
101
|
+
remove;
|
|
102
|
+
removeBrowser;
|
|
103
|
+
browserDisconnected = false;
|
|
104
|
+
closing = false;
|
|
105
|
+
sessionClosed = false;
|
|
106
|
+
joined;
|
|
107
|
+
failure;
|
|
108
|
+
admitted() {
|
|
109
|
+
if (this.closing || !this.current()) throw new BrowserLifecycleError("ENGINE_STOPPED");
|
|
110
|
+
}
|
|
111
|
+
async acquire() {
|
|
112
|
+
this.admitted();
|
|
113
|
+
const contexts = this.browser.contexts;
|
|
114
|
+
const create = this.browser.newBrowserCDPSession;
|
|
115
|
+
this.admitted();
|
|
116
|
+
const original = Reflect.apply(contexts, this.browser, []);
|
|
117
|
+
this.admitted();
|
|
118
|
+
if (original.length !== 1) throw new BrowserLifecycleError("PAGE_UNAVAILABLE");
|
|
119
|
+
const sameContext = () => {
|
|
120
|
+
this.admitted();
|
|
121
|
+
const now = Reflect.apply(contexts, this.browser, []);
|
|
122
|
+
if (now.length !== 1 || now[0] !== original[0])
|
|
123
|
+
throw new BrowserLifecycleError("PAGE_UNAVAILABLE");
|
|
124
|
+
this.admitted();
|
|
125
|
+
};
|
|
126
|
+
sameContext();
|
|
127
|
+
const session = await Reflect.apply(create, this.browser, []);
|
|
128
|
+
this.session = session;
|
|
129
|
+
this.detach = session.detach;
|
|
130
|
+
const on = session.on;
|
|
131
|
+
const off = session.off;
|
|
132
|
+
const closed = () => {
|
|
133
|
+
this.sessionClosed = true;
|
|
134
|
+
if (!this.closing) {
|
|
135
|
+
this.failure ??= Object.freeze({
|
|
136
|
+
value: new BrowserLifecycleError("OPERATION_FAILED")
|
|
137
|
+
});
|
|
138
|
+
try {
|
|
139
|
+
this.lost();
|
|
140
|
+
} catch (value) {
|
|
141
|
+
this.failure ??= Object.freeze({ value });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
this.remove = () => {
|
|
146
|
+
Reflect.apply(off, session, ["close", closed]);
|
|
147
|
+
};
|
|
148
|
+
this.admitted();
|
|
149
|
+
Reflect.apply(on, session, ["close", closed]);
|
|
150
|
+
const send = session.send;
|
|
151
|
+
sameContext();
|
|
152
|
+
await Reflect.apply(send, session, [
|
|
153
|
+
"Browser.setDownloadBehavior",
|
|
154
|
+
{ behavior: "deny", eventsEnabled: false }
|
|
155
|
+
]);
|
|
156
|
+
sameContext();
|
|
157
|
+
if (this.failure) throw this.failure.value;
|
|
158
|
+
if (this.sessionClosed) throw new BrowserLifecycleError("OPERATION_FAILED");
|
|
159
|
+
}
|
|
160
|
+
/** Fence initialization and mark expected SDK closure without releasing the deny override. */
|
|
161
|
+
retire() {
|
|
162
|
+
this.closing = true;
|
|
163
|
+
}
|
|
164
|
+
/** Join original initialization and session cleanup after actual browser shutdown entry. */
|
|
165
|
+
close() {
|
|
166
|
+
this.retire();
|
|
167
|
+
if (this.joined) return this.joined;
|
|
168
|
+
this.joined = Promise.resolve().then(async () => {
|
|
169
|
+
try {
|
|
170
|
+
await this.ready;
|
|
171
|
+
} catch (value) {
|
|
172
|
+
this.failure ??= Object.freeze({ value });
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
if (this.session && !this.sessionClosed && !this.browserDisconnected) {
|
|
176
|
+
if (!this.detach) throw new BrowserLifecycleError("OPERATION_FAILED");
|
|
177
|
+
await Reflect.apply(this.detach, this.session, []);
|
|
178
|
+
}
|
|
179
|
+
} catch (value) {
|
|
180
|
+
this.failure ??= Object.freeze({ value });
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
this.remove?.();
|
|
184
|
+
} catch (value) {
|
|
185
|
+
this.failure ??= Object.freeze({ value });
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
this.removeBrowser?.();
|
|
189
|
+
} catch (value) {
|
|
190
|
+
this.failure ??= Object.freeze({ value });
|
|
191
|
+
}
|
|
192
|
+
if (this.failure) throw this.failure.value;
|
|
193
|
+
});
|
|
194
|
+
void this.joined.catch(() => {
|
|
195
|
+
});
|
|
196
|
+
return this.joined;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
async function closeBrowserAndDownloads(browser, downloads) {
|
|
200
|
+
let first;
|
|
201
|
+
try {
|
|
202
|
+
await browser?.close();
|
|
203
|
+
} catch (value) {
|
|
204
|
+
first = { value };
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
await downloads?.close();
|
|
208
|
+
} catch (value) {
|
|
209
|
+
first ??= { value };
|
|
210
|
+
}
|
|
211
|
+
if (first) throw first.value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// packages/browser/src/runtime/private-proxy-auth.ts
|
|
215
|
+
var retained = /* @__PURE__ */ new Set();
|
|
216
|
+
async function ownPrivateProxyAuthentication(endpoint2, peer, failed) {
|
|
217
|
+
const proxy = new URL(peer.url);
|
|
218
|
+
if (proxy.origin !== peer.url || proxy.protocol !== "http:" || proxy.hostname !== "127.0.0.1" || !proxy.port)
|
|
219
|
+
throw new Error("PROXY_AUTH_PEER_INVALID");
|
|
220
|
+
const socket = new WebSocket(endpoint2);
|
|
221
|
+
const pending = /* @__PURE__ */ new Map();
|
|
222
|
+
const tasks = /* @__PURE__ */ new Set();
|
|
223
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
224
|
+
const fetchFrames = /* @__PURE__ */ new Set();
|
|
225
|
+
const workerParents = /* @__PURE__ */ new Map();
|
|
226
|
+
const coveredWorker = (sessionId) => {
|
|
227
|
+
const visited = /* @__PURE__ */ new Set();
|
|
228
|
+
let current = sessionId;
|
|
229
|
+
while (sessions.has(current) && visited.size < 128 && !visited.has(current)) {
|
|
230
|
+
if (fetchFrames.has(current)) return true;
|
|
231
|
+
visited.add(current);
|
|
232
|
+
const parent = workerParents.get(current);
|
|
233
|
+
if (!parent) return false;
|
|
234
|
+
current = parent;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
};
|
|
238
|
+
const attempts = /* @__PURE__ */ new Set();
|
|
239
|
+
const originalOwner = { socket, pending, tasks, sessions, fetchFrames, workerParents };
|
|
240
|
+
retained.add(originalOwner);
|
|
241
|
+
let sequence2 = 0, stopping = false, uncertain = false, closing;
|
|
242
|
+
const terminal = new Promise(
|
|
243
|
+
(resolve) => socket.addEventListener(
|
|
244
|
+
"close",
|
|
245
|
+
() => {
|
|
246
|
+
if (!stopping) fault();
|
|
247
|
+
for (const request of pending.values()) {
|
|
248
|
+
clearTimeout(request.timer);
|
|
249
|
+
request.reject(new Error("PROXY_AUTH_CHANNEL_CLOSED"));
|
|
250
|
+
}
|
|
251
|
+
pending.clear();
|
|
252
|
+
resolve();
|
|
253
|
+
},
|
|
254
|
+
{ once: true }
|
|
255
|
+
)
|
|
256
|
+
);
|
|
257
|
+
const targetTypes = /* @__PURE__ */ new Set([
|
|
258
|
+
"page",
|
|
259
|
+
"iframe",
|
|
260
|
+
"worker",
|
|
261
|
+
"shared_worker",
|
|
262
|
+
"service_worker",
|
|
263
|
+
"worklet",
|
|
264
|
+
"auction_worklet",
|
|
265
|
+
"background_page",
|
|
266
|
+
"webview",
|
|
267
|
+
"browser",
|
|
268
|
+
"tab",
|
|
269
|
+
"other"
|
|
270
|
+
]);
|
|
271
|
+
function fault() {
|
|
272
|
+
if (uncertain) return;
|
|
273
|
+
uncertain = true;
|
|
274
|
+
failed();
|
|
275
|
+
}
|
|
276
|
+
function send(method, params, sessionId) {
|
|
277
|
+
if (stopping || uncertain || socket.readyState !== WebSocket.OPEN || pending.size >= 128 || sequence2 >= Number.MAX_SAFE_INTEGER)
|
|
278
|
+
return Promise.reject(new Error("PROXY_AUTH_CHANNEL_UNAVAILABLE"));
|
|
279
|
+
const id = ++sequence2;
|
|
280
|
+
return new Promise((resolve, reject) => {
|
|
281
|
+
const timer = setTimeout(() => {
|
|
282
|
+
pending.delete(id);
|
|
283
|
+
reject(new Error("PROXY_AUTH_METHOD_TIMEOUT"));
|
|
284
|
+
fault();
|
|
285
|
+
}, 3e3);
|
|
286
|
+
pending.set(id, { resolve, reject, timer });
|
|
287
|
+
try {
|
|
288
|
+
socket.send(JSON.stringify({ id, method, params, ...sessionId ? { sessionId } : {} }));
|
|
289
|
+
} catch {
|
|
290
|
+
clearTimeout(timer);
|
|
291
|
+
pending.delete(id);
|
|
292
|
+
reject(new Error("PROXY_AUTH_SEND_FAILED"));
|
|
293
|
+
fault();
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const filters = [{ type: "browser", exclude: true }, { type: "tab", exclude: true }, {}];
|
|
298
|
+
async function attach(sessionId, targetType, parentSessionId) {
|
|
299
|
+
if (sessions.has(sessionId) || sessions.size >= 128)
|
|
300
|
+
throw new Error("PROXY_AUTH_TARGET_UNAVAILABLE");
|
|
301
|
+
sessions.add(sessionId);
|
|
302
|
+
if (targetType === "worker") {
|
|
303
|
+
if (!parentSessionId || !coveredWorker(parentSessionId))
|
|
304
|
+
throw new Error("PROXY_AUTH_WORKER_PARENT_UNAVAILABLE");
|
|
305
|
+
workerParents.set(sessionId, parentSessionId);
|
|
306
|
+
} else {
|
|
307
|
+
await send(
|
|
308
|
+
"Fetch.enable",
|
|
309
|
+
{ handleAuthRequests: true, patterns: [{ urlPattern: "*" }] },
|
|
310
|
+
sessionId
|
|
311
|
+
);
|
|
312
|
+
if (targetType === "page" || targetType === "iframe") fetchFrames.add(sessionId);
|
|
313
|
+
}
|
|
314
|
+
await send(
|
|
315
|
+
"Target.setAutoAttach",
|
|
316
|
+
{ autoAttach: true, waitForDebuggerOnStart: true, flatten: true, filter: filters },
|
|
317
|
+
sessionId
|
|
318
|
+
);
|
|
319
|
+
if (targetType === "worker" && !coveredWorker(sessionId))
|
|
320
|
+
throw new Error("PROXY_AUTH_WORKER_PARENT_UNAVAILABLE");
|
|
321
|
+
await send("Runtime.runIfWaitingForDebugger", {}, sessionId);
|
|
322
|
+
}
|
|
323
|
+
function own(task) {
|
|
324
|
+
if (tasks.size >= 128) {
|
|
325
|
+
fault();
|
|
326
|
+
void task.catch(() => {
|
|
327
|
+
});
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
tasks.add(task);
|
|
331
|
+
void task.then(
|
|
332
|
+
() => tasks.delete(task),
|
|
333
|
+
() => {
|
|
334
|
+
tasks.delete(task);
|
|
335
|
+
if (!stopping) fault();
|
|
336
|
+
}
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
socket.addEventListener("error", () => {
|
|
340
|
+
if (!stopping) fault();
|
|
341
|
+
});
|
|
342
|
+
socket.addEventListener("message", (event) => {
|
|
343
|
+
if (stopping || uncertain) return;
|
|
344
|
+
if (typeof event.data !== "string" || Buffer.byteLength(event.data) > 65536) {
|
|
345
|
+
fault();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
let value;
|
|
349
|
+
try {
|
|
350
|
+
value = JSON.parse(event.data);
|
|
351
|
+
} catch {
|
|
352
|
+
fault();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (!value || typeof value !== "object") {
|
|
356
|
+
fault();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (typeof value.id === "number") {
|
|
360
|
+
const original = pending.get(value.id);
|
|
361
|
+
if (!original) {
|
|
362
|
+
fault();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
pending.delete(value.id);
|
|
366
|
+
clearTimeout(original.timer);
|
|
367
|
+
if (value.error) original.reject(new Error("PROXY_AUTH_METHOD_REFUSED"));
|
|
368
|
+
else original.resolve(value.result);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const params = value.params;
|
|
372
|
+
if (value.method === "Target.attachedToTarget") {
|
|
373
|
+
if (!params || typeof params.sessionId !== "string") {
|
|
374
|
+
fault();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const info = params.targetInfo;
|
|
378
|
+
const type = info && typeof info === "object" ? info.type : void 0;
|
|
379
|
+
own(
|
|
380
|
+
attach(
|
|
381
|
+
params.sessionId,
|
|
382
|
+
typeof type === "string" && targetTypes.has(type) ? type : "unknown",
|
|
383
|
+
value.sessionId
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
} else if (value.method === "Target.detachedFromTarget") {
|
|
387
|
+
if (params && typeof params.sessionId === "string") {
|
|
388
|
+
sessions.delete(params.sessionId);
|
|
389
|
+
fetchFrames.delete(params.sessionId);
|
|
390
|
+
workerParents.delete(params.sessionId);
|
|
391
|
+
}
|
|
392
|
+
} else if (value.method === "Fetch.requestPaused") {
|
|
393
|
+
if (!params || typeof params.requestId !== "string" || !value.sessionId || !sessions.has(value.sessionId)) {
|
|
394
|
+
fault();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
own(
|
|
398
|
+
send("Fetch.continueRequest", { requestId: params.requestId }, value.sessionId).then(
|
|
399
|
+
() => {
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
} else if (value.method === "Fetch.authRequired") {
|
|
404
|
+
if (!params || typeof params.requestId !== "string" || !value.sessionId || !sessions.has(value.sessionId)) {
|
|
405
|
+
fault();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const challenge = params.authChallenge;
|
|
409
|
+
const attempt = `${value.sessionId}:${params.requestId}`;
|
|
410
|
+
const first = !attempts.has(attempt);
|
|
411
|
+
let exact = false;
|
|
412
|
+
attempts.add(attempt);
|
|
413
|
+
if (attempts.size > 4096) {
|
|
414
|
+
fault();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
exact = first && challenge?.source === "Proxy" && new URL(challenge.origin).origin === peer.url;
|
|
419
|
+
} catch {
|
|
420
|
+
}
|
|
421
|
+
own(
|
|
422
|
+
send(
|
|
423
|
+
"Fetch.continueWithAuth",
|
|
424
|
+
{
|
|
425
|
+
requestId: params.requestId,
|
|
426
|
+
authChallengeResponse: exact ? {
|
|
427
|
+
response: "ProvideCredentials",
|
|
428
|
+
username: peer.credentials.username,
|
|
429
|
+
password: peer.credentials.password
|
|
430
|
+
} : { response: "CancelAuth" }
|
|
431
|
+
},
|
|
432
|
+
value.sessionId
|
|
433
|
+
).then(() => {
|
|
434
|
+
})
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
const opened = new Promise((resolve, reject) => {
|
|
439
|
+
const timer = setTimeout(() => reject(new Error("PROXY_AUTH_OPEN_TIMEOUT")), 3e3);
|
|
440
|
+
socket.addEventListener(
|
|
441
|
+
"open",
|
|
442
|
+
() => {
|
|
443
|
+
clearTimeout(timer);
|
|
444
|
+
resolve();
|
|
445
|
+
},
|
|
446
|
+
{ once: true }
|
|
447
|
+
);
|
|
448
|
+
socket.addEventListener(
|
|
449
|
+
"error",
|
|
450
|
+
() => {
|
|
451
|
+
clearTimeout(timer);
|
|
452
|
+
reject(new Error("PROXY_AUTH_OPEN_FAILED"));
|
|
453
|
+
},
|
|
454
|
+
{ once: true }
|
|
455
|
+
);
|
|
456
|
+
});
|
|
457
|
+
const close = () => {
|
|
458
|
+
if (closing) return closing;
|
|
459
|
+
stopping = true;
|
|
460
|
+
socket.close();
|
|
461
|
+
closing = Promise.all([terminal, ...tasks]).then(() => {
|
|
462
|
+
if (uncertain) throw new Error("PROXY_AUTH_CUSTODY_UNCERTAIN");
|
|
463
|
+
retained.delete(originalOwner);
|
|
464
|
+
});
|
|
465
|
+
return closing;
|
|
466
|
+
};
|
|
467
|
+
try {
|
|
468
|
+
await opened;
|
|
469
|
+
await send("Target.setAutoAttach", {
|
|
470
|
+
autoAttach: true,
|
|
471
|
+
waitForDebuggerOnStart: true,
|
|
472
|
+
flatten: true,
|
|
473
|
+
filter: filters
|
|
474
|
+
});
|
|
475
|
+
while (tasks.size) await Promise.all([...tasks]);
|
|
476
|
+
if (uncertain) throw new Error("PROXY_AUTH_CUSTODY_UNCERTAIN");
|
|
477
|
+
} catch (error) {
|
|
478
|
+
fault();
|
|
479
|
+
void close().catch(() => {
|
|
480
|
+
});
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
return Object.freeze({
|
|
484
|
+
isCustodyKnown: () => !stopping && !uncertain && socket.readyState === WebSocket.OPEN,
|
|
485
|
+
close
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// packages/browser/src/runtime/darwin-supervisor-browser.ts
|
|
490
|
+
import { constants as constants4 } from "node:fs";
|
|
491
|
+
import { open as open3, lstat as lstat3 } from "node:fs/promises";
|
|
492
|
+
import { join as join3 } from "node:path";
|
|
493
|
+
|
|
494
|
+
// packages/browser/src/runtime/public-library.ts
|
|
495
|
+
import { createRequire } from "node:module";
|
|
496
|
+
import { access, realpath, stat, readdir, lstat, open, readlink } from "node:fs/promises";
|
|
497
|
+
import { constants } from "node:fs";
|
|
498
|
+
import { createHash } from "node:crypto";
|
|
499
|
+
import { join, relative } from "node:path";
|
|
500
|
+
var PUBLIC_DISTRIBUTION_SHA256 = "6bf8e6d392f411f43046a5688021a5ed083fea9129f2f84dbff5aee88b2de728";
|
|
501
|
+
var retainedReads = /* @__PURE__ */ new Set();
|
|
502
|
+
var closeUncertain = false;
|
|
503
|
+
function requireClosedReads() {
|
|
504
|
+
if (closeUncertain) throw new BrowserLifecycleError("LIBRARY_UNAVAILABLE");
|
|
505
|
+
}
|
|
506
|
+
async function closeOriginal(file) {
|
|
507
|
+
try {
|
|
508
|
+
await file.close();
|
|
509
|
+
retainedReads.delete(file);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
closeUncertain = true;
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function sameFile(a, b) {
|
|
516
|
+
return a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.uid === b.uid && a.size === b.size && a.mtimeNs === b.mtimeNs && a.ctimeNs === b.ctimeNs;
|
|
517
|
+
}
|
|
518
|
+
function requireLibrary(value) {
|
|
519
|
+
if (!value) throw new BrowserLifecycleError("LIBRARY_UNAVAILABLE");
|
|
520
|
+
}
|
|
521
|
+
async function hashFile(path, cap = 2 * 1024 * 1024 * 1024) {
|
|
522
|
+
requireClosedReads();
|
|
523
|
+
const named = await lstat(path, { bigint: true });
|
|
524
|
+
requireLibrary(named.isFile() && named.size <= BigInt(cap));
|
|
525
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
526
|
+
retainedReads.add(file);
|
|
527
|
+
let failed = false, primary, digest = "";
|
|
528
|
+
try {
|
|
529
|
+
const before = await file.stat({ bigint: true });
|
|
530
|
+
requireLibrary(sameFile(named, before));
|
|
531
|
+
const hash = createHash("sha256"), buffer = Buffer.alloc(65536);
|
|
532
|
+
let bytes = 0;
|
|
533
|
+
for (; ; ) {
|
|
534
|
+
const read = await file.read(buffer, 0, Math.min(buffer.length, cap + 1 - bytes), bytes);
|
|
535
|
+
if (!read.bytesRead) break;
|
|
536
|
+
bytes += read.bytesRead;
|
|
537
|
+
requireLibrary(bytes <= cap);
|
|
538
|
+
hash.update(buffer.subarray(0, read.bytesRead));
|
|
539
|
+
}
|
|
540
|
+
requireLibrary(
|
|
541
|
+
BigInt(bytes) === before.size && sameFile(before, await file.stat({ bigint: true })) && sameFile(before, await lstat(path, { bigint: true }))
|
|
542
|
+
);
|
|
543
|
+
digest = hash.digest("hex");
|
|
544
|
+
} catch (error) {
|
|
545
|
+
failed = true;
|
|
546
|
+
primary = error;
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
await closeOriginal(file);
|
|
550
|
+
} catch (error) {
|
|
551
|
+
if (!failed) primary = error;
|
|
552
|
+
failed = true;
|
|
553
|
+
}
|
|
554
|
+
if (failed) throw primary;
|
|
555
|
+
return digest;
|
|
556
|
+
}
|
|
557
|
+
async function metadataText(path) {
|
|
558
|
+
requireClosedReads();
|
|
559
|
+
const cap = 65536;
|
|
560
|
+
const named = await lstat(path, { bigint: true });
|
|
561
|
+
requireLibrary(named.isFile() && named.size <= BigInt(cap));
|
|
562
|
+
const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
563
|
+
retainedReads.add(file);
|
|
564
|
+
let failed = false, primary, text2 = "";
|
|
565
|
+
try {
|
|
566
|
+
const before = await file.stat({ bigint: true });
|
|
567
|
+
requireLibrary(before.isFile() && sameFile(named, before));
|
|
568
|
+
const bytes = Buffer.alloc(cap + 1);
|
|
569
|
+
let total = 0;
|
|
570
|
+
while (total < bytes.length) {
|
|
571
|
+
const read = await file.read(bytes, total, bytes.length - total, total);
|
|
572
|
+
if (!read.bytesRead) break;
|
|
573
|
+
total += read.bytesRead;
|
|
574
|
+
requireLibrary(total <= cap);
|
|
575
|
+
}
|
|
576
|
+
requireLibrary(
|
|
577
|
+
BigInt(total) === before.size && sameFile(before, await file.stat({ bigint: true })) && sameFile(before, await lstat(path, { bigint: true }))
|
|
578
|
+
);
|
|
579
|
+
text2 = bytes.subarray(0, total).toString("utf8");
|
|
580
|
+
} catch (error) {
|
|
581
|
+
failed = true;
|
|
582
|
+
primary = error;
|
|
583
|
+
}
|
|
584
|
+
try {
|
|
585
|
+
await closeOriginal(file);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (!failed) primary = error;
|
|
588
|
+
failed = true;
|
|
589
|
+
}
|
|
590
|
+
if (failed) throw primary;
|
|
591
|
+
return text2;
|
|
592
|
+
}
|
|
593
|
+
async function directoryNames(path) {
|
|
594
|
+
requireClosedReads();
|
|
595
|
+
const named = await lstat(path, { bigint: true });
|
|
596
|
+
requireLibrary(named.isDirectory());
|
|
597
|
+
const directory = await open(
|
|
598
|
+
path,
|
|
599
|
+
constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW
|
|
600
|
+
);
|
|
601
|
+
retainedReads.add(directory);
|
|
602
|
+
let failed = false, primary, names = [];
|
|
603
|
+
try {
|
|
604
|
+
requireLibrary(sameFile(named, await directory.stat({ bigint: true })));
|
|
605
|
+
names = await readdir(path);
|
|
606
|
+
requireLibrary(names.length <= 256);
|
|
607
|
+
requireLibrary(
|
|
608
|
+
sameFile(named, await directory.stat({ bigint: true })) && sameFile(named, await lstat(path, { bigint: true }))
|
|
609
|
+
);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
failed = true;
|
|
612
|
+
primary = error;
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
await closeOriginal(directory);
|
|
616
|
+
} catch (error) {
|
|
617
|
+
if (!failed) primary = error;
|
|
618
|
+
failed = true;
|
|
619
|
+
}
|
|
620
|
+
if (failed) throw primary;
|
|
621
|
+
return { names: names.sort(), identity: named };
|
|
622
|
+
}
|
|
623
|
+
async function generatedLibraryMetadata(root, path) {
|
|
624
|
+
const modules = await directoryNames(path), binsPath = join(path, ".bin");
|
|
625
|
+
requireLibrary(modules.names.length === 1 && modules.names[0] === ".bin");
|
|
626
|
+
const bins = await directoryNames(binsPath);
|
|
627
|
+
requireLibrary(bins.names.length === 1 && bins.names[0] === "playwright-core");
|
|
628
|
+
const shim = join(binsPath, "playwright-core"), before = await lstat(shim, { bigint: true });
|
|
629
|
+
if (before.isSymbolicLink()) {
|
|
630
|
+
const target = await readlink(shim);
|
|
631
|
+
requireLibrary(
|
|
632
|
+
Buffer.byteLength(target) <= 65536 && await realpath(shim) === join(root, "cli.js")
|
|
633
|
+
);
|
|
634
|
+
requireLibrary(
|
|
635
|
+
sameFile(before, await lstat(shim, { bigint: true })) && target === await readlink(shim)
|
|
636
|
+
);
|
|
637
|
+
} else {
|
|
638
|
+
requireLibrary(before.isFile());
|
|
639
|
+
await hashFile(shim, 65536);
|
|
640
|
+
requireLibrary(sameFile(before, await lstat(shim, { bigint: true })));
|
|
641
|
+
}
|
|
642
|
+
requireLibrary(
|
|
643
|
+
sameFile(modules.identity, await lstat(path, { bigint: true })) && sameFile(bins.identity, await lstat(binsPath, { bigint: true }))
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
async function distributionHash(root) {
|
|
647
|
+
const files = [];
|
|
648
|
+
let entries = 0;
|
|
649
|
+
const visit = async (path, depth) => {
|
|
650
|
+
requireLibrary(depth <= 32);
|
|
651
|
+
const directory = await directoryNames(path);
|
|
652
|
+
for (const name of directory.names) {
|
|
653
|
+
requireLibrary(++entries <= 256);
|
|
654
|
+
const absolute = join(path, name), relativePath = relative(root, absolute);
|
|
655
|
+
const entry = await lstat(absolute, { bigint: true });
|
|
656
|
+
if (relativePath === "node_modules") {
|
|
657
|
+
requireLibrary(entry.isDirectory());
|
|
658
|
+
await generatedLibraryMetadata(root, absolute);
|
|
659
|
+
} else if (entry.isDirectory()) await visit(absolute, depth + 1);
|
|
660
|
+
else {
|
|
661
|
+
requireLibrary(entry.isFile());
|
|
662
|
+
files.push(relativePath);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
requireLibrary(sameFile(directory.identity, await lstat(path, { bigint: true })));
|
|
666
|
+
};
|
|
667
|
+
await visit(root, 0);
|
|
668
|
+
files.sort();
|
|
669
|
+
if (files.length !== 114) throw new BrowserLifecycleError("LIBRARY_UNAVAILABLE");
|
|
670
|
+
const hash = createHash("sha256");
|
|
671
|
+
for (const file of files)
|
|
672
|
+
hash.update(file + "\0" + await hashFile(join(root, file), 32 * 1024 * 1024) + "\n");
|
|
673
|
+
return hash.digest("hex");
|
|
674
|
+
}
|
|
675
|
+
async function verifiedLibrary(runtime) {
|
|
676
|
+
try {
|
|
677
|
+
requireClosedReads();
|
|
678
|
+
if (runtime.identity.mode !== "native")
|
|
679
|
+
throw new BrowserLifecycleError("IDENTITY_MODE_UNAVAILABLE");
|
|
680
|
+
if (runtime.executable.platform !== process.platform || runtime.executable.arch !== process.arch || process.platform === "win32")
|
|
681
|
+
throw new BrowserLifecycleError("PLATFORM_UNSUPPORTED");
|
|
682
|
+
const root = await realpath(runtime.library.rootDir);
|
|
683
|
+
const pkg = JSON.parse(await metadataText(join(root, "package.json")));
|
|
684
|
+
const manifest = JSON.parse(
|
|
685
|
+
await metadataText(join(root, runtime.library.assets.manifest))
|
|
686
|
+
);
|
|
687
|
+
const chromium = manifest.browsers?.find((entry) => entry.name === "chromium");
|
|
688
|
+
if (pkg.name !== "playwright-core" || pkg.version !== runtime.library.version || chromium?.revision !== runtime.executable.revision || chromium.browserVersion !== runtime.executable.version)
|
|
689
|
+
throw new BrowserLifecycleError("LIBRARY_UNAVAILABLE");
|
|
690
|
+
if (!(await stat(join(root, runtime.library.assets.cli))).isFile() || await distributionHash(root) !== PUBLIC_DISTRIBUTION_SHA256)
|
|
691
|
+
throw new BrowserLifecycleError("LIBRARY_UNAVAILABLE");
|
|
692
|
+
await access(runtime.executable.path, constants.R_OK | constants.X_OK);
|
|
693
|
+
if (!(await stat(runtime.executable.path)).isFile() || await hashFile(runtime.executable.path) !== runtime.executable.sha256)
|
|
694
|
+
throw new BrowserLifecycleError("EXECUTABLE_UNAVAILABLE");
|
|
695
|
+
requireClosedReads();
|
|
696
|
+
const library = createRequire(join(root, "package.json"))(root);
|
|
697
|
+
return library.chromium;
|
|
698
|
+
} catch (error) {
|
|
699
|
+
if (error instanceof BrowserLifecycleError) throw error;
|
|
700
|
+
throw new BrowserLifecycleError("RUNTIME_UNAVAILABLE");
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// packages/browser/src/network/fixture-proxy.ts
|
|
705
|
+
import {
|
|
706
|
+
createServer,
|
|
707
|
+
request as httpRequest
|
|
708
|
+
} from "node:http";
|
|
709
|
+
async function startFixtureProxy(origin) {
|
|
710
|
+
if (new URL(origin).protocol !== "http:")
|
|
711
|
+
throw new BrowserLifecycleError("NETWORK_POLICY_UNSUPPORTED");
|
|
712
|
+
const pending = /* @__PURE__ */ new Set();
|
|
713
|
+
const server = createServer({ maxHeaderSize: 16 * 1024 }, (incoming, response) => {
|
|
714
|
+
let target;
|
|
715
|
+
try {
|
|
716
|
+
target = new URL(incoming.url ?? "");
|
|
717
|
+
} catch {
|
|
718
|
+
response.writeHead(403).end();
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
if (target.origin !== origin || target.username || target.password) {
|
|
722
|
+
response.writeHead(403).end();
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (pending.size >= 32) {
|
|
726
|
+
response.writeHead(503).end();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
const headers = { ...incoming.headers, host: target.host };
|
|
730
|
+
for (const key of ["proxy-authorization", "proxy-connection", "connection", "upgrade"])
|
|
731
|
+
delete headers[key];
|
|
732
|
+
const outgoing = httpRequest(
|
|
733
|
+
target,
|
|
734
|
+
{ method: incoming.method, headers, agent: false },
|
|
735
|
+
(upstream) => {
|
|
736
|
+
response.writeHead(upstream.statusCode ?? 502, upstream.headers);
|
|
737
|
+
let bytes2 = 0;
|
|
738
|
+
upstream.on("data", (chunk) => {
|
|
739
|
+
bytes2 += chunk.length;
|
|
740
|
+
if (bytes2 > 2 * 1024 * 1024) {
|
|
741
|
+
outgoing.destroy();
|
|
742
|
+
response.destroy();
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
upstream.pipe(response);
|
|
746
|
+
}
|
|
747
|
+
);
|
|
748
|
+
pending.add(outgoing);
|
|
749
|
+
const timer = setTimeout(() => {
|
|
750
|
+
outgoing.destroy();
|
|
751
|
+
response.destroy();
|
|
752
|
+
}, 3e3);
|
|
753
|
+
outgoing.on("close", () => {
|
|
754
|
+
clearTimeout(timer);
|
|
755
|
+
pending.delete(outgoing);
|
|
756
|
+
});
|
|
757
|
+
outgoing.on("error", () => {
|
|
758
|
+
if (!response.headersSent) response.writeHead(502);
|
|
759
|
+
response.end();
|
|
760
|
+
});
|
|
761
|
+
incoming.on("aborted", () => outgoing.destroy());
|
|
762
|
+
response.on("close", () => outgoing.destroy());
|
|
763
|
+
let bytes = 0;
|
|
764
|
+
incoming.on("data", (chunk) => {
|
|
765
|
+
bytes += chunk.length;
|
|
766
|
+
if (bytes > 1024 * 1024) {
|
|
767
|
+
outgoing.destroy();
|
|
768
|
+
incoming.destroy();
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
incoming.pipe(outgoing);
|
|
772
|
+
});
|
|
773
|
+
server.on("connect", (_, socket) => socket.destroy());
|
|
774
|
+
server.on("upgrade", (_, socket) => socket.destroy());
|
|
775
|
+
server.requestTimeout = server.headersTimeout = 3e3;
|
|
776
|
+
server.maxConnections = 64;
|
|
777
|
+
server.maxRequestsPerSocket = 100;
|
|
778
|
+
try {
|
|
779
|
+
await new Promise((resolve, reject) => {
|
|
780
|
+
server.once("error", reject);
|
|
781
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
782
|
+
});
|
|
783
|
+
} catch {
|
|
784
|
+
server.close();
|
|
785
|
+
throw new BrowserLifecycleError("FIXTURE_PROXY_UNAVAILABLE");
|
|
786
|
+
}
|
|
787
|
+
const address = server.address();
|
|
788
|
+
if (!address || typeof address === "string")
|
|
789
|
+
throw new BrowserLifecycleError("FIXTURE_PROXY_UNAVAILABLE");
|
|
790
|
+
return {
|
|
791
|
+
url: `http://127.0.0.1:${address.port}`,
|
|
792
|
+
close: () => new Promise((resolve, reject) => {
|
|
793
|
+
for (const request of pending) request.destroy();
|
|
794
|
+
server.closeAllConnections();
|
|
795
|
+
server.close(
|
|
796
|
+
(error) => error ? reject(new BrowserLifecycleError("FIXTURE_PROXY_CLOSE_FAILED")) : resolve()
|
|
797
|
+
);
|
|
798
|
+
})
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// packages/browser/src/runtime/darwin-owned-child.ts
|
|
803
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
804
|
+
|
|
805
|
+
// packages/browser/src/lifecycle/process-journal.ts
|
|
806
|
+
import { constants as constants2 } from "node:fs";
|
|
807
|
+
import { z } from "zod";
|
|
808
|
+
var JOURNAL_LIMITS = Object.freeze({
|
|
809
|
+
bytes: 1048576,
|
|
810
|
+
writerBytes: 4096,
|
|
811
|
+
identities: 512,
|
|
812
|
+
gaps: 32,
|
|
813
|
+
depth: 16,
|
|
814
|
+
pending: 8
|
|
815
|
+
});
|
|
816
|
+
var GAP_CODES = [
|
|
817
|
+
"boot-unknown",
|
|
818
|
+
"boot-changed",
|
|
819
|
+
"identity-unknown",
|
|
820
|
+
"root-pending",
|
|
821
|
+
"parent-changed",
|
|
822
|
+
"association-missing",
|
|
823
|
+
"observer-lost",
|
|
824
|
+
"sequence-gap",
|
|
825
|
+
"frame-invalid",
|
|
826
|
+
"capacity-exceeded",
|
|
827
|
+
"read-uncertain",
|
|
828
|
+
"persistence-uncertain",
|
|
829
|
+
"custody-pending"
|
|
830
|
+
];
|
|
831
|
+
var counter = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
832
|
+
var text = (cap) => z.string().min(1).refine(
|
|
833
|
+
(v) => v.length <= cap && Buffer.byteLength(v) <= cap && Buffer.from(v).toString("utf8") === v && ![...v].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)
|
|
834
|
+
);
|
|
835
|
+
var opaque = text(64).refine((v) => /^[A-Za-z0-9_-]+$/.test(v));
|
|
836
|
+
var digestSchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
837
|
+
var ProcessIdentitySchema = z.object({ pid: counter.refine((v) => v > 0), birth: text(128) }).strict();
|
|
838
|
+
var BootScopeSchema = z.discriminatedUnion("kind", [
|
|
839
|
+
z.object({ kind: z.literal("observed"), value: text(128), sourceIdentityDigest: digestSchema }).strict(),
|
|
840
|
+
z.object({ kind: z.literal("unknown"), cause: z.enum(GAP_CODES) }).strict()
|
|
841
|
+
]);
|
|
842
|
+
var JournalBindingSchema = z.object({
|
|
843
|
+
journalId: opaque,
|
|
844
|
+
browserId: opaque,
|
|
845
|
+
profile: z.discriminatedUnion("kind", [
|
|
846
|
+
z.object({ kind: z.literal("persistent"), profileId: opaque }).strict(),
|
|
847
|
+
z.object({ kind: z.literal("ephemeral") }).strict()
|
|
848
|
+
]),
|
|
849
|
+
browserGeneration: counter,
|
|
850
|
+
reservationNonce: opaque,
|
|
851
|
+
runtimeIdentityDigest: digestSchema,
|
|
852
|
+
manager: ProcessIdentitySchema,
|
|
853
|
+
bootScope: BootScopeSchema
|
|
854
|
+
}).strict();
|
|
855
|
+
var JournalWriterSchema = z.object({ writerId: opaque, epoch: counter, kind: z.enum(["manager", "observer", "reconciler"]) }).strict();
|
|
856
|
+
var ObservationWindowSchema = z.object({
|
|
857
|
+
startSequence: counter,
|
|
858
|
+
checkpointSequence: counter,
|
|
859
|
+
endSequence: counter,
|
|
860
|
+
startMonotonic: z.number().finite().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
861
|
+
endMonotonic: z.number().finite().nonnegative().max(Number.MAX_SAFE_INTEGER)
|
|
862
|
+
}).strict().refine(
|
|
863
|
+
(w) => w.startSequence <= w.checkpointSequence && w.checkpointSequence <= w.endSequence && w.startMonotonic <= w.endMonotonic
|
|
864
|
+
);
|
|
865
|
+
var AssociationSchema = z.object({
|
|
866
|
+
parentBefore: ProcessIdentitySchema,
|
|
867
|
+
parentAfter: ProcessIdentitySchema,
|
|
868
|
+
child: ProcessIdentitySchema,
|
|
869
|
+
childParentPid: counter.refine((v) => v > 0),
|
|
870
|
+
window: ObservationWindowSchema,
|
|
871
|
+
recordedSequence: counter,
|
|
872
|
+
parentDeathSequence: counter.nullable()
|
|
873
|
+
}).strict().refine(
|
|
874
|
+
(a) => sameProcess(a.parentBefore, a.parentAfter) && a.child.pid !== a.parentBefore.pid && a.childParentPid === a.parentBefore.pid && a.window.endSequence <= a.recordedSequence && (a.parentDeathSequence === null || a.recordedSequence < a.parentDeathSequence)
|
|
875
|
+
);
|
|
876
|
+
var retainedSchema = z.object({
|
|
877
|
+
identity: ProcessIdentitySchema,
|
|
878
|
+
role: z.enum(["manager", "root", "descendant"]),
|
|
879
|
+
parent: ProcessIdentitySchema.nullable(),
|
|
880
|
+
association: AssociationSchema.nullable(),
|
|
881
|
+
currentParent: ProcessIdentitySchema.nullable(),
|
|
882
|
+
acquisitionEpoch: counter,
|
|
883
|
+
firstSeenSequence: counter,
|
|
884
|
+
lastSeenSequence: counter,
|
|
885
|
+
relationWindow: ObservationWindowSchema,
|
|
886
|
+
lifecycle: z.enum(["alive", "exited-unreaped", "dead", "replacement", "unknown"])
|
|
887
|
+
}).strict();
|
|
888
|
+
var gapSchema = z.object({
|
|
889
|
+
cause: z.enum(GAP_CODES),
|
|
890
|
+
firstSequence: counter,
|
|
891
|
+
identity: ProcessIdentitySchema.nullable(),
|
|
892
|
+
count: counter.refine((v) => v > 0)
|
|
893
|
+
}).strict();
|
|
894
|
+
var causeSchema = z.object({ cause: z.enum(GAP_CODES), sequence: counter }).strict();
|
|
895
|
+
var JournalSnapshotSchema = z.object({
|
|
896
|
+
schemaVersion: z.literal(1),
|
|
897
|
+
kind: z.literal("browser-process-journal"),
|
|
898
|
+
provenance: z.literal("recorded-data"),
|
|
899
|
+
binding: JournalBindingSchema,
|
|
900
|
+
writer: JournalWriterSchema,
|
|
901
|
+
sequence: counter,
|
|
902
|
+
phase: z.enum([
|
|
903
|
+
"allocated",
|
|
904
|
+
"launch-intent",
|
|
905
|
+
"observing",
|
|
906
|
+
"manager-lost",
|
|
907
|
+
"reconciling",
|
|
908
|
+
"observation-ended",
|
|
909
|
+
"retained"
|
|
910
|
+
]),
|
|
911
|
+
observationWindow: ObservationWindowSchema,
|
|
912
|
+
root: z.discriminatedUnion("kind", [
|
|
913
|
+
z.object({ kind: z.literal("pending") }).strict(),
|
|
914
|
+
z.object({ kind: z.literal("absent-before-launch") }).strict(),
|
|
915
|
+
z.object({
|
|
916
|
+
kind: z.literal("attributed"),
|
|
917
|
+
identity: ProcessIdentitySchema,
|
|
918
|
+
association: AssociationSchema
|
|
919
|
+
}).strict()
|
|
920
|
+
]),
|
|
921
|
+
retainedIdentities: z.array(retainedSchema).max(JOURNAL_LIMITS.identities),
|
|
922
|
+
gaps: z.array(gapSchema).max(JOURNAL_LIMITS.gaps),
|
|
923
|
+
firstCause: causeSchema.nullable()
|
|
924
|
+
}).strict();
|
|
925
|
+
function sameProcess(a, b) {
|
|
926
|
+
return a.pid === b.pid && a.birth === b.birth;
|
|
927
|
+
}
|
|
928
|
+
var readFlags = constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK;
|
|
929
|
+
var createFlags = constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | constants2.O_NOFOLLOW | constants2.O_NONBLOCK;
|
|
930
|
+
|
|
931
|
+
// packages/browser/src/runtime/darwin-process-observer.ts
|
|
932
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
933
|
+
import { constants as constants3 } from "node:fs";
|
|
934
|
+
import { open as open2, realpath as realpath2, lstat as lstat2 } from "node:fs/promises";
|
|
935
|
+
import { spawn } from "node:child_process";
|
|
936
|
+
import { z as z2 } from "zod";
|
|
937
|
+
var decimal = z2.string().regex(/^(0|[1-9][0-9]{0,19})$/).refine(
|
|
938
|
+
(value) => /^(0|[1-9][0-9]{0,19})$/.test(value) && BigInt(value) <= 18446744073709551615n
|
|
939
|
+
);
|
|
940
|
+
var identity = z2.object({
|
|
941
|
+
pid: z2.number().int().positive().max(2147483647),
|
|
942
|
+
seconds: decimal,
|
|
943
|
+
microseconds: decimal
|
|
944
|
+
}).strict();
|
|
945
|
+
var replySchema = z2.object({
|
|
946
|
+
version: z2.literal(1),
|
|
947
|
+
bootSeconds: decimal,
|
|
948
|
+
bootMicroseconds: decimal,
|
|
949
|
+
processes: z2.array(
|
|
950
|
+
z2.discriminatedUnion("kind", [
|
|
951
|
+
z2.object({
|
|
952
|
+
kind: z2.literal("present"),
|
|
953
|
+
identity,
|
|
954
|
+
parentPid: z2.number().int().nonnegative().max(2147483647),
|
|
955
|
+
zombie: z2.boolean()
|
|
956
|
+
}).strict(),
|
|
957
|
+
z2.object({ kind: z2.literal("absent"), pid: z2.number().int().positive().max(2147483647) }).strict(),
|
|
958
|
+
z2.object({
|
|
959
|
+
kind: z2.literal("unknown"),
|
|
960
|
+
pid: z2.number().int().positive().max(2147483647),
|
|
961
|
+
error: z2.number().int()
|
|
962
|
+
}).strict()
|
|
963
|
+
])
|
|
964
|
+
).max(512)
|
|
965
|
+
}).strict();
|
|
966
|
+
var childrenSchema = replySchema.extend({
|
|
967
|
+
parentBefore: identity.nullable(),
|
|
968
|
+
parentAfter: identity.nullable(),
|
|
969
|
+
complete: z2.boolean()
|
|
970
|
+
}).strict();
|
|
971
|
+
function parseDarwinChildrenBatch(bytes, parent) {
|
|
972
|
+
if (bytes.byteLength > 256 * 1024) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
973
|
+
const batch = childrenSchema.parse(
|
|
974
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes))
|
|
975
|
+
);
|
|
976
|
+
if (BigInt(batch.bootMicroseconds) >= 1000000n)
|
|
977
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
978
|
+
const pids = /* @__PURE__ */ new Set();
|
|
979
|
+
for (const fact of batch.processes) {
|
|
980
|
+
const pid = fact.kind === "present" ? fact.identity.pid : fact.pid;
|
|
981
|
+
if (pids.has(pid)) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
982
|
+
pids.add(pid);
|
|
983
|
+
if (fact.kind === "present") darwinBirth(fact.identity);
|
|
984
|
+
}
|
|
985
|
+
if (batch.complete && (!batch.parentBefore || !batch.parentAfter || darwinBirth(batch.parentBefore).birth !== parent.birth || batch.parentBefore.pid !== parent.pid || darwinBirth(batch.parentAfter).birth !== parent.birth || batch.parentAfter.pid !== parent.pid || batch.processes.some(
|
|
986
|
+
(fact) => fact.kind !== "present" || fact.parentPid !== parent.pid || fact.identity.pid === parent.pid
|
|
987
|
+
)))
|
|
988
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
989
|
+
return batch;
|
|
990
|
+
}
|
|
991
|
+
function darwinBirth(value) {
|
|
992
|
+
if (BigInt(value.microseconds) >= 1000000n) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
993
|
+
return Object.freeze({
|
|
994
|
+
pid: value.pid,
|
|
995
|
+
birth: `darwin-bsd-start:${value.seconds}:${value.microseconds}`
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
function parseDarwinProcessBatch(bytes, requested) {
|
|
999
|
+
if (bytes.byteLength > 256 * 1024) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1000
|
+
const batch = replySchema.parse(
|
|
1001
|
+
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes))
|
|
1002
|
+
);
|
|
1003
|
+
if (BigInt(batch.bootMicroseconds) >= 1000000n || batch.processes.length !== requested.length)
|
|
1004
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1005
|
+
const remaining = new Set(requested);
|
|
1006
|
+
for (const fact of batch.processes) {
|
|
1007
|
+
const pid = fact.kind === "present" ? fact.identity.pid : fact.pid;
|
|
1008
|
+
if (!remaining.delete(pid)) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1009
|
+
if (fact.kind === "present") darwinBirth(fact.identity);
|
|
1010
|
+
}
|
|
1011
|
+
if (remaining.size) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1012
|
+
return batch;
|
|
1013
|
+
}
|
|
1014
|
+
var heldReads = /* @__PURE__ */ new Set();
|
|
1015
|
+
var heldChildren = /* @__PURE__ */ new Set();
|
|
1016
|
+
var readCustodyUncertain = false;
|
|
1017
|
+
function createDarwinProcessObserver(artifact) {
|
|
1018
|
+
const descriptor = Object.freeze({ ...artifact });
|
|
1019
|
+
const invoke = async (command, pids) => {
|
|
1020
|
+
if (readCustodyUncertain || process.platform !== "darwin" || !/^[a-f0-9]{64}$/.test(descriptor.sha256) || pids.length < 1 || pids.length > 512 || new Set(pids).size !== pids.length || pids.some((pid) => !Number.isSafeInteger(pid) || pid < 1 || pid > 2147483647))
|
|
1021
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1022
|
+
if (await realpath2(descriptor.path) !== descriptor.path)
|
|
1023
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1024
|
+
const file = await open2(
|
|
1025
|
+
descriptor.path,
|
|
1026
|
+
constants3.O_RDONLY | constants3.O_NOFOLLOW | constants3.O_NONBLOCK
|
|
1027
|
+
);
|
|
1028
|
+
heldReads.add(file);
|
|
1029
|
+
let primary, failed = false;
|
|
1030
|
+
try {
|
|
1031
|
+
const before = await file.stat({ bigint: true });
|
|
1032
|
+
if (!before.isFile() || before.size > 4n * 1024n * 1024n || (before.mode & 0o111n) === 0n)
|
|
1033
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1034
|
+
const hash = createHash2("sha256");
|
|
1035
|
+
const buffer = new Uint8Array(65536);
|
|
1036
|
+
let bytes = 0;
|
|
1037
|
+
for (; ; ) {
|
|
1038
|
+
const read = await file.read(
|
|
1039
|
+
buffer,
|
|
1040
|
+
0,
|
|
1041
|
+
Math.min(buffer.length, 4 * 1024 * 1024 + 1 - bytes),
|
|
1042
|
+
null
|
|
1043
|
+
);
|
|
1044
|
+
if (!read.bytesRead) break;
|
|
1045
|
+
bytes += read.bytesRead;
|
|
1046
|
+
if (bytes > 4 * 1024 * 1024) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1047
|
+
hash.update(buffer.subarray(0, read.bytesRead));
|
|
1048
|
+
}
|
|
1049
|
+
const after = await file.stat({ bigint: true });
|
|
1050
|
+
const named = await lstat2(descriptor.path, { bigint: true });
|
|
1051
|
+
if (!named.isFile() || named.dev !== after.dev || named.ino !== after.ino)
|
|
1052
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1053
|
+
if (hash.digest("hex") !== descriptor.sha256 || before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || before.ctimeNs !== after.ctimeNs)
|
|
1054
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1055
|
+
} catch (error) {
|
|
1056
|
+
primary = error;
|
|
1057
|
+
failed = true;
|
|
1058
|
+
}
|
|
1059
|
+
try {
|
|
1060
|
+
await file.close();
|
|
1061
|
+
heldReads.delete(file);
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
readCustodyUncertain = true;
|
|
1064
|
+
if (!failed) primary = error;
|
|
1065
|
+
failed = true;
|
|
1066
|
+
}
|
|
1067
|
+
if (failed) throw primary;
|
|
1068
|
+
if (readCustodyUncertain) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1069
|
+
const child = spawn(descriptor.path, [command, ...pids.map(String)], {
|
|
1070
|
+
shell: false,
|
|
1071
|
+
detached: false,
|
|
1072
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1073
|
+
env: { PATH: "/usr/bin:/bin", LANG: "C", LC_ALL: "C" }
|
|
1074
|
+
});
|
|
1075
|
+
heldChildren.add(child);
|
|
1076
|
+
let failedChild = false;
|
|
1077
|
+
const terminal = new Promise((done) => {
|
|
1078
|
+
child.on("error", () => {
|
|
1079
|
+
failedChild = true;
|
|
1080
|
+
});
|
|
1081
|
+
child.once("close", (code2) => done(code2));
|
|
1082
|
+
});
|
|
1083
|
+
const pipeReturns = [
|
|
1084
|
+
{ eof: false, closed: false },
|
|
1085
|
+
{ eof: false, closed: false }
|
|
1086
|
+
];
|
|
1087
|
+
const drain = async (stream, duty) => {
|
|
1088
|
+
if (!stream) {
|
|
1089
|
+
failedChild = true;
|
|
1090
|
+
return new Uint8Array();
|
|
1091
|
+
}
|
|
1092
|
+
stream.once("end", () => {
|
|
1093
|
+
duty.eof = true;
|
|
1094
|
+
});
|
|
1095
|
+
stream.once("close", () => {
|
|
1096
|
+
duty.closed = true;
|
|
1097
|
+
});
|
|
1098
|
+
const chunks = [];
|
|
1099
|
+
let bytes = 0;
|
|
1100
|
+
for await (const value of stream) {
|
|
1101
|
+
const chunk = Buffer.from(value);
|
|
1102
|
+
bytes += chunk.length;
|
|
1103
|
+
if (bytes <= 256 * 1024) chunks.push(chunk);
|
|
1104
|
+
else failedChild = true;
|
|
1105
|
+
}
|
|
1106
|
+
if (!stream.readableEnded || !duty.eof) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1107
|
+
return Buffer.concat(chunks);
|
|
1108
|
+
};
|
|
1109
|
+
const streams = await Promise.allSettled([
|
|
1110
|
+
drain(child.stdout, pipeReturns[0]),
|
|
1111
|
+
drain(child.stderr, pipeReturns[1])
|
|
1112
|
+
]);
|
|
1113
|
+
const code = await terminal;
|
|
1114
|
+
const pipesReturned = streams.every((stream) => stream.status === "fulfilled") && pipeReturns.every((duty) => duty.eof && duty.closed);
|
|
1115
|
+
if (pipesReturned) heldChildren.delete(child);
|
|
1116
|
+
else readCustodyUncertain = true;
|
|
1117
|
+
if (readCustodyUncertain || failedChild || code !== 0 || !pipesReturned)
|
|
1118
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1119
|
+
const stdout = streams[0];
|
|
1120
|
+
if (stdout.status !== "fulfilled") throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1121
|
+
return stdout.value;
|
|
1122
|
+
};
|
|
1123
|
+
return Object.freeze({
|
|
1124
|
+
async inspect(pids) {
|
|
1125
|
+
return parseDarwinProcessBatch(await invoke("inspect", pids), pids);
|
|
1126
|
+
},
|
|
1127
|
+
async children(parent) {
|
|
1128
|
+
return parseDarwinChildrenBatch(await invoke("children", [parent.pid]), parent);
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// packages/browser/src/runtime/darwin-owned-child.ts
|
|
1134
|
+
var returnBrand = /* @__PURE__ */ Symbol("Darwin original child return");
|
|
1135
|
+
var ownership = /* @__PURE__ */ new WeakMap();
|
|
1136
|
+
var returns = /* @__PURE__ */ new WeakMap();
|
|
1137
|
+
var retained2 = /* @__PURE__ */ new Set();
|
|
1138
|
+
function acceptsDarwinOwnedChildReturn(child, returned) {
|
|
1139
|
+
return !!returned && typeof returned === "object" && ownership.has(child) && returns.get(returned) === ownership.get(child);
|
|
1140
|
+
}
|
|
1141
|
+
function createDarwinOwnedChildLauncher(options) {
|
|
1142
|
+
const observer = createDarwinProcessObserver(options.artifact);
|
|
1143
|
+
const manager = Object.freeze({ ...options.manager });
|
|
1144
|
+
return Object.freeze({
|
|
1145
|
+
async launch(command) {
|
|
1146
|
+
if (process.platform !== "darwin" || process.pid === manager.pid)
|
|
1147
|
+
throw new Error("SUPERVISOR_PROCESS_REQUIRED");
|
|
1148
|
+
const initial = await observer.inspect([process.pid, manager.pid]);
|
|
1149
|
+
const supervisor = initial.processes.find(
|
|
1150
|
+
(fact) => fact.kind === "present" && fact.identity.pid === process.pid
|
|
1151
|
+
);
|
|
1152
|
+
const observedManager = initial.processes.find(
|
|
1153
|
+
(fact) => fact.kind === "present" && fact.identity.pid === manager.pid
|
|
1154
|
+
);
|
|
1155
|
+
if (!supervisor || supervisor.kind !== "present" || supervisor.zombie || !observedManager || observedManager.kind !== "present" || observedManager.zombie || !sameProcess(darwinBirth(observedManager.identity), manager))
|
|
1156
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1157
|
+
const boot = `${initial.bootSeconds}:${initial.bootMicroseconds}`;
|
|
1158
|
+
const state = { child: null, pending: true, firstCause: null };
|
|
1159
|
+
retained2.add(state);
|
|
1160
|
+
const fail = (cause) => {
|
|
1161
|
+
state.firstCause ??= cause;
|
|
1162
|
+
};
|
|
1163
|
+
let child;
|
|
1164
|
+
try {
|
|
1165
|
+
child = spawn2(command.executable, [...command.argv], {
|
|
1166
|
+
cwd: command.cwd,
|
|
1167
|
+
env: { ...command.env },
|
|
1168
|
+
shell: false,
|
|
1169
|
+
detached: false,
|
|
1170
|
+
stdio: command.ipc ? ["ignore", "pipe", "pipe", "ipc"] : ["ignore", "pipe", "pipe"]
|
|
1171
|
+
});
|
|
1172
|
+
state.child = child;
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
fail("CHILD_ACQUISITION_UNCERTAIN");
|
|
1175
|
+
throw error;
|
|
1176
|
+
}
|
|
1177
|
+
let exitObserved = false, closeObserved = false;
|
|
1178
|
+
let exitCode = null, signal = null;
|
|
1179
|
+
const terminal = new Promise((resolve) => {
|
|
1180
|
+
child.on("error", () => fail("CHILD_ERROR"));
|
|
1181
|
+
child.once("exit", (code, killedBy) => {
|
|
1182
|
+
exitObserved = true;
|
|
1183
|
+
exitCode = code;
|
|
1184
|
+
signal = killedBy;
|
|
1185
|
+
if (killedBy) fail("CHILD_SIGNALED");
|
|
1186
|
+
else if (code !== 0) fail("CHILD_EXIT_FAILED");
|
|
1187
|
+
});
|
|
1188
|
+
child.once("close", (code, killedBy) => {
|
|
1189
|
+
closeObserved = true;
|
|
1190
|
+
if (!exitObserved || code !== exitCode || killedBy !== signal)
|
|
1191
|
+
fail("CHILD_TERMINAL_UNCERTAIN");
|
|
1192
|
+
resolve();
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
1195
|
+
const drain = (original) => {
|
|
1196
|
+
let eof = false, closed = false, overflow = false;
|
|
1197
|
+
const chunks = [];
|
|
1198
|
+
let retainedBytes = 0;
|
|
1199
|
+
const completion2 = new Promise((resolve) => {
|
|
1200
|
+
if (!original) {
|
|
1201
|
+
fail("CHILD_PIPE_UNAVAILABLE");
|
|
1202
|
+
resolve(new Uint8Array());
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
original.once("end", () => {
|
|
1206
|
+
eof = true;
|
|
1207
|
+
});
|
|
1208
|
+
original.on("error", () => fail("CHILD_PIPE_ERROR"));
|
|
1209
|
+
original.once("close", () => {
|
|
1210
|
+
closed = true;
|
|
1211
|
+
if (!eof) fail("CHILD_PIPE_EOF_UNAVAILABLE");
|
|
1212
|
+
try {
|
|
1213
|
+
resolve(Buffer.concat(chunks));
|
|
1214
|
+
} catch {
|
|
1215
|
+
fail("CHILD_PIPE_RETENTION_UNAVAILABLE");
|
|
1216
|
+
resolve(new Uint8Array());
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
original.on("data", (value) => {
|
|
1220
|
+
if (overflow) return;
|
|
1221
|
+
if (value.byteLength > 256 * 1024 - retainedBytes) {
|
|
1222
|
+
overflow = true;
|
|
1223
|
+
fail("CHILD_PIPE_OVERFLOW");
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
try {
|
|
1227
|
+
const copy = Uint8Array.from(value);
|
|
1228
|
+
retainedBytes += copy.byteLength;
|
|
1229
|
+
chunks.push(copy);
|
|
1230
|
+
} catch {
|
|
1231
|
+
overflow = true;
|
|
1232
|
+
fail("CHILD_PIPE_RETENTION_UNAVAILABLE");
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1236
|
+
return { completion: completion2, complete: () => eof && closed };
|
|
1237
|
+
};
|
|
1238
|
+
const stdout = drain(child.stdout), stderr = drain(child.stderr);
|
|
1239
|
+
const identity3 = (async () => {
|
|
1240
|
+
if (!child.pid) throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1241
|
+
const batch = await observer.inspect([process.pid, child.pid]);
|
|
1242
|
+
const parent = batch.processes.find(
|
|
1243
|
+
(fact2) => fact2.kind === "present" && fact2.identity.pid === process.pid
|
|
1244
|
+
);
|
|
1245
|
+
const fact = batch.processes.find(
|
|
1246
|
+
(fact2) => fact2.kind === "present" && fact2.identity.pid === child.pid
|
|
1247
|
+
);
|
|
1248
|
+
if (`${batch.bootSeconds}:${batch.bootMicroseconds}` !== boot || !parent || parent.kind !== "present" || parent.zombie || !sameProcess(darwinBirth(parent.identity), darwinBirth(supervisor.identity)) || !fact || fact.kind !== "present" || fact.zombie || fact.parentPid !== process.pid)
|
|
1249
|
+
throw new Error("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1250
|
+
return Object.freeze(darwinBirth(fact.identity));
|
|
1251
|
+
})();
|
|
1252
|
+
void identity3.catch(() => fail("CHILD_BIRTH_UNAVAILABLE"));
|
|
1253
|
+
let token = null;
|
|
1254
|
+
const completion = (async () => {
|
|
1255
|
+
const [out, err] = await Promise.all([stdout.completion, stderr.completion, terminal]);
|
|
1256
|
+
let birth = null;
|
|
1257
|
+
try {
|
|
1258
|
+
birth = await identity3;
|
|
1259
|
+
} catch {
|
|
1260
|
+
fail("CHILD_BIRTH_UNAVAILABLE");
|
|
1261
|
+
}
|
|
1262
|
+
if (!exitObserved || !closeObserved || !stdout.complete() || !stderr.complete())
|
|
1263
|
+
fail("CHILD_RETURN_UNCERTAIN");
|
|
1264
|
+
if (birth) {
|
|
1265
|
+
try {
|
|
1266
|
+
const batch = await observer.inspect([birth.pid]);
|
|
1267
|
+
if (`${batch.bootSeconds}:${batch.bootMicroseconds}` !== boot || batch.processes[0]?.kind !== "absent")
|
|
1268
|
+
fail("CHILD_NATIVE_RETURN_UNAVAILABLE");
|
|
1269
|
+
} catch {
|
|
1270
|
+
fail("CHILD_NATIVE_RETURN_UNAVAILABLE");
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
if (state.firstCause === null && birth) {
|
|
1274
|
+
token = Object.freeze({ [returnBrand]: true });
|
|
1275
|
+
returns.set(token, state);
|
|
1276
|
+
state.pending = false;
|
|
1277
|
+
retained2.delete(state);
|
|
1278
|
+
}
|
|
1279
|
+
return Object.freeze({
|
|
1280
|
+
exitCode,
|
|
1281
|
+
signal,
|
|
1282
|
+
firstCause: state.firstCause,
|
|
1283
|
+
stdout: out,
|
|
1284
|
+
stderr: err
|
|
1285
|
+
});
|
|
1286
|
+
})();
|
|
1287
|
+
const handle = Object.freeze({
|
|
1288
|
+
child,
|
|
1289
|
+
identity: () => identity3,
|
|
1290
|
+
completion: () => completion,
|
|
1291
|
+
returned: async () => {
|
|
1292
|
+
await completion;
|
|
1293
|
+
return token;
|
|
1294
|
+
},
|
|
1295
|
+
custody: () => Object.freeze({ pending: state.pending, firstCause: state.firstCause })
|
|
1296
|
+
});
|
|
1297
|
+
ownership.set(handle, state);
|
|
1298
|
+
return handle;
|
|
1299
|
+
}
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// packages/browser/src/runtime/host-identity.ts
|
|
1304
|
+
import { readlinkSync } from "node:fs";
|
|
1305
|
+
import { hostname } from "node:os";
|
|
1306
|
+
import { join as join2 } from "node:path";
|
|
1307
|
+
function nativeHolderPid(profileDir) {
|
|
1308
|
+
let target;
|
|
1309
|
+
try {
|
|
1310
|
+
target = readlinkSync(join2(profileDir, "SingletonLock"));
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
if (error.code === "ENOENT") return null;
|
|
1313
|
+
throw new BrowserLifecycleError("UNKNOWN_NATIVE_HOLDER");
|
|
1314
|
+
}
|
|
1315
|
+
const match = /^(.*)-(\d+)$/.exec(target);
|
|
1316
|
+
if (!match || match[1] !== hostname()) throw new BrowserLifecycleError("UNKNOWN_NATIVE_HOLDER");
|
|
1317
|
+
const pid = Number(match[2]);
|
|
1318
|
+
if (!Number.isSafeInteger(pid) || pid < 1 || pid > 2147483647)
|
|
1319
|
+
throw new BrowserLifecycleError("UNKNOWN_NATIVE_HOLDER");
|
|
1320
|
+
return pid;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// packages/browser/src/runtime/darwin-engine-processes.ts
|
|
1324
|
+
function createDarwinEngineProcesses(artifact) {
|
|
1325
|
+
const observer = createDarwinProcessObserver(artifact);
|
|
1326
|
+
let boot;
|
|
1327
|
+
const checkBoot = (batch) => {
|
|
1328
|
+
const value = `${batch.bootSeconds}:${batch.bootMicroseconds}`;
|
|
1329
|
+
if (boot !== void 0 && boot !== value) throw new Error("BOOT_CHANGED");
|
|
1330
|
+
boot = value;
|
|
1331
|
+
};
|
|
1332
|
+
const identity3 = async (pid) => {
|
|
1333
|
+
const batch = await observer.inspect([pid]);
|
|
1334
|
+
checkBoot(batch);
|
|
1335
|
+
const fact = batch.processes[0];
|
|
1336
|
+
if (fact?.kind === "absent") return null;
|
|
1337
|
+
if (fact?.kind !== "present" || fact.zombie)
|
|
1338
|
+
throw new BrowserLifecycleError("PROCESS_OBSERVATION_UNAVAILABLE");
|
|
1339
|
+
return darwinBirth(fact.identity);
|
|
1340
|
+
};
|
|
1341
|
+
const processes = {
|
|
1342
|
+
async observe(original, signal) {
|
|
1343
|
+
if (signal.aborted) return { status: "unknown" };
|
|
1344
|
+
try {
|
|
1345
|
+
const batch = await observer.inspect([original.pid]);
|
|
1346
|
+
checkBoot(batch);
|
|
1347
|
+
if (signal.aborted) return { status: "unknown" };
|
|
1348
|
+
const fact = batch.processes[0];
|
|
1349
|
+
if (fact?.kind === "absent") return { status: "dead" };
|
|
1350
|
+
if (fact?.kind !== "present" || fact.zombie) return { status: "unknown" };
|
|
1351
|
+
return { status: sameProcess(darwinBirth(fact.identity), original) ? "alive" : "dead" };
|
|
1352
|
+
} catch {
|
|
1353
|
+
return { status: "unknown" };
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
async descendants(original, signal) {
|
|
1357
|
+
try {
|
|
1358
|
+
const identities = [original];
|
|
1359
|
+
const pids = /* @__PURE__ */ new Set([original.pid]);
|
|
1360
|
+
for (let index = 0; index < identities.length; index++) {
|
|
1361
|
+
if (signal.aborted || !observer.children) throw new Error();
|
|
1362
|
+
const parent = identities[index];
|
|
1363
|
+
const batch = await observer.children(parent);
|
|
1364
|
+
checkBoot(batch);
|
|
1365
|
+
if (!batch.complete || signal.aborted) throw new Error();
|
|
1366
|
+
for (const fact of batch.processes) {
|
|
1367
|
+
if (fact.kind !== "present" || fact.zombie || fact.parentPid !== parent.pid || pids.has(fact.identity.pid))
|
|
1368
|
+
throw new Error();
|
|
1369
|
+
if (identities.length >= 512) throw new Error();
|
|
1370
|
+
pids.add(fact.identity.pid);
|
|
1371
|
+
identities.push(darwinBirth(fact.identity));
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return { status: "complete", identities };
|
|
1375
|
+
} catch {
|
|
1376
|
+
return { status: "unknown", identities: [] };
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
};
|
|
1380
|
+
return Object.freeze({
|
|
1381
|
+
identity: identity3,
|
|
1382
|
+
processes,
|
|
1383
|
+
/** Only for terminal descendants after original root-child/pipe return; never recovery. */
|
|
1384
|
+
async observeTerminated(original, signal) {
|
|
1385
|
+
if (signal.aborted) return { status: "unknown" };
|
|
1386
|
+
try {
|
|
1387
|
+
const batch = await observer.inspect([original.pid]);
|
|
1388
|
+
checkBoot(batch);
|
|
1389
|
+
if (signal.aborted) return { status: "unknown" };
|
|
1390
|
+
const fact = batch.processes[0];
|
|
1391
|
+
if (fact?.kind === "absent") return { status: "dead" };
|
|
1392
|
+
if (fact?.kind !== "present") return { status: "unknown" };
|
|
1393
|
+
if (!sameProcess(darwinBirth(fact.identity), original) || fact.zombie)
|
|
1394
|
+
return { status: "dead" };
|
|
1395
|
+
return { status: "alive" };
|
|
1396
|
+
} catch {
|
|
1397
|
+
return { status: "unknown" };
|
|
1398
|
+
}
|
|
1399
|
+
},
|
|
1400
|
+
async attributeRoot(manager, root) {
|
|
1401
|
+
if (manager.pid === root.pid) return false;
|
|
1402
|
+
const before = await observer.inspect([manager.pid, root.pid]);
|
|
1403
|
+
checkBoot(before);
|
|
1404
|
+
const parent = before.processes.find(
|
|
1405
|
+
(fact) => fact.kind === "present" && fact.identity.pid === manager.pid
|
|
1406
|
+
);
|
|
1407
|
+
const child = before.processes.find(
|
|
1408
|
+
(fact) => fact.kind === "present" && fact.identity.pid === root.pid
|
|
1409
|
+
);
|
|
1410
|
+
const after = await observer.inspect([manager.pid]);
|
|
1411
|
+
checkBoot(after);
|
|
1412
|
+
const repeated = after.processes[0];
|
|
1413
|
+
return parent?.kind === "present" && !parent.zombie && sameProcess(darwinBirth(parent.identity), manager) && child?.kind === "present" && !child.zombie && child.parentPid === manager.pid && sameProcess(darwinBirth(child.identity), root) && repeated?.kind === "present" && !repeated.zombie && sameProcess(darwinBirth(repeated.identity), manager);
|
|
1414
|
+
},
|
|
1415
|
+
async holder(profileDir) {
|
|
1416
|
+
const pid = nativeHolderPid(profileDir);
|
|
1417
|
+
if (pid === null) return null;
|
|
1418
|
+
const result = await identity3(pid);
|
|
1419
|
+
if (!result) throw new BrowserLifecycleError("UNKNOWN_NATIVE_HOLDER");
|
|
1420
|
+
return result;
|
|
1421
|
+
}
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// packages/browser/src/profiles/owned-directory.ts
|
|
1426
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
1427
|
+
function ownDirectory(path) {
|
|
1428
|
+
const entry = lstatSync(path);
|
|
1429
|
+
if (!entry.isDirectory() || entry.isSymbolicLink() || realpathSync(path) !== path || (entry.mode & 63) !== 0 || process.getuid && entry.uid !== process.getuid())
|
|
1430
|
+
throw new BrowserLifecycleError("PROFILE_UNCERTAIN");
|
|
1431
|
+
return Object.freeze({ path, dev: entry.dev, ino: entry.ino });
|
|
1432
|
+
}
|
|
1433
|
+
function assertDirectory(owner) {
|
|
1434
|
+
let current;
|
|
1435
|
+
try {
|
|
1436
|
+
current = ownDirectory(owner.path);
|
|
1437
|
+
} catch {
|
|
1438
|
+
throw new BrowserLifecycleError("PROFILE_UNCERTAIN");
|
|
1439
|
+
}
|
|
1440
|
+
if (current.dev !== owner.dev || current.ino !== owner.ino)
|
|
1441
|
+
throw new BrowserLifecycleError("PROFILE_UNCERTAIN");
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// packages/browser/src/runtime/darwin-supervisor-browser.ts
|
|
1445
|
+
var retained3 = /* @__PURE__ */ new Set();
|
|
1446
|
+
var endpointReads = /* @__PURE__ */ new Set();
|
|
1447
|
+
var endpointUncertain = false;
|
|
1448
|
+
async function waitWithin(original, milliseconds) {
|
|
1449
|
+
let timer;
|
|
1450
|
+
try {
|
|
1451
|
+
return await Promise.race([
|
|
1452
|
+
original,
|
|
1453
|
+
new Promise((_resolve, reject) => {
|
|
1454
|
+
timer = setTimeout(() => reject(new Error("SUPERVISOR_WAIT_EXPIRED")), milliseconds);
|
|
1455
|
+
})
|
|
1456
|
+
]);
|
|
1457
|
+
} finally {
|
|
1458
|
+
if (timer) clearTimeout(timer);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
function parseOwnedDevToolsEndpoint(bytes) {
|
|
1462
|
+
if (bytes.byteLength > 1024) throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1463
|
+
const value = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
1464
|
+
const match = /^([1-9][0-9]{0,4})\n(\/devtools\/browser\/[a-fA-F0-9-]{36})\n?$/.exec(value);
|
|
1465
|
+
if (!match || Number(match[1]) > 65535) throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1466
|
+
return `ws://127.0.0.1:${match[1]}${match[2]}`;
|
|
1467
|
+
}
|
|
1468
|
+
async function endpoint(file, before, directory) {
|
|
1469
|
+
assertDirectory(directory);
|
|
1470
|
+
const original = await open3(
|
|
1471
|
+
file,
|
|
1472
|
+
constants4.O_RDONLY | constants4.O_NOFOLLOW | constants4.O_NONBLOCK
|
|
1473
|
+
);
|
|
1474
|
+
endpointReads.add(original);
|
|
1475
|
+
let failed = false, primary, result = "";
|
|
1476
|
+
try {
|
|
1477
|
+
const first = await original.stat({ bigint: true });
|
|
1478
|
+
if (!first.isFile() || first.size > 1024n || first.uid !== BigInt(process.getuid()))
|
|
1479
|
+
throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1480
|
+
const fingerprint = `${first.dev}:${first.ino}:${first.size}:${first.mtimeNs}:${first.ctimeNs}`;
|
|
1481
|
+
if (fingerprint === before) throw new Error("DEVTOOLS_ENDPOINT_STALE");
|
|
1482
|
+
const bytes = new Uint8Array(1025);
|
|
1483
|
+
const read = await original.read(bytes, 0, bytes.length, 0);
|
|
1484
|
+
const after = await original.stat({ bigint: true }), named = await lstat3(file, { bigint: true });
|
|
1485
|
+
for (const stat2 of [after, named])
|
|
1486
|
+
if (!stat2.isFile() || stat2.dev !== first.dev || stat2.ino !== first.ino || stat2.size !== first.size || stat2.mtimeNs !== first.mtimeNs || stat2.ctimeNs !== first.ctimeNs)
|
|
1487
|
+
throw new Error("DEVTOOLS_ENDPOINT_CHANGED");
|
|
1488
|
+
if (read.bytesRead !== Number(first.size)) throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1489
|
+
assertDirectory(directory);
|
|
1490
|
+
result = parseOwnedDevToolsEndpoint(bytes.subarray(0, read.bytesRead));
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
failed = true;
|
|
1493
|
+
primary = error;
|
|
1494
|
+
}
|
|
1495
|
+
try {
|
|
1496
|
+
await original.close();
|
|
1497
|
+
endpointReads.delete(original);
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
endpointUncertain = true;
|
|
1500
|
+
throw Object.assign(new Error("DEVTOOLS_CLOSE_UNCERTAIN", { cause: error }), {
|
|
1501
|
+
primaryReadFailure: failed ? primary : null
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
if (failed) throw primary;
|
|
1505
|
+
return result;
|
|
1506
|
+
}
|
|
1507
|
+
async function launchDarwinSupervisorBrowser(options, failed = () => {
|
|
1508
|
+
}, originalRootReturned) {
|
|
1509
|
+
if (endpointUncertain) throw new Error("DEVTOOLS_CLOSE_UNCERTAIN");
|
|
1510
|
+
const directory = ownDirectory(options.profileDir);
|
|
1511
|
+
for (const original of retained3)
|
|
1512
|
+
if (original.directory.path === directory.path || original.directory.dev === directory.dev && original.directory.ino === directory.ino)
|
|
1513
|
+
throw new Error("SUPERVISOR_PROFILE_UNCERTAIN");
|
|
1514
|
+
const state = { directory, uncertain: false };
|
|
1515
|
+
retained3.add(state);
|
|
1516
|
+
const processes = createDarwinEngineProcesses(options.artifact);
|
|
1517
|
+
const file = join3(options.profileDir, "DevToolsActivePort");
|
|
1518
|
+
let before = null;
|
|
1519
|
+
let root;
|
|
1520
|
+
let supervisor;
|
|
1521
|
+
let endpointURL;
|
|
1522
|
+
try {
|
|
1523
|
+
const chromium = await verifiedLibrary(options.runtime);
|
|
1524
|
+
try {
|
|
1525
|
+
const stat2 = await lstat3(file, { bigint: true });
|
|
1526
|
+
if (!stat2.isFile() || stat2.size > 1024n || stat2.uid !== BigInt(process.getuid()))
|
|
1527
|
+
throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1528
|
+
before = `${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}`;
|
|
1529
|
+
} catch (error) {
|
|
1530
|
+
if (error.code !== "ENOENT") throw error;
|
|
1531
|
+
}
|
|
1532
|
+
if (!options.ownedProxy) state.proxy = await startFixtureProxy(options.origin);
|
|
1533
|
+
assertDirectory(directory);
|
|
1534
|
+
state.child = await createDarwinOwnedChildLauncher({
|
|
1535
|
+
artifact: options.artifact,
|
|
1536
|
+
manager: options.manager
|
|
1537
|
+
}).launch({
|
|
1538
|
+
executable: options.runtime.executable.path,
|
|
1539
|
+
cwd: options.profileDir,
|
|
1540
|
+
env: { PATH: "/usr/bin:/bin", HOME: options.profileDir, LANG: "C", LC_ALL: "C" },
|
|
1541
|
+
argv: [
|
|
1542
|
+
"--headless=new",
|
|
1543
|
+
"--remote-debugging-address=127.0.0.1",
|
|
1544
|
+
"--remote-debugging-port=0",
|
|
1545
|
+
"--no-first-run",
|
|
1546
|
+
"--no-default-browser-check",
|
|
1547
|
+
"--disable-background-networking",
|
|
1548
|
+
// Match relevant public launch defaults of the verified pinned library.
|
|
1549
|
+
"--disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,BlockOriginHeaderModificationOnRedirect,Translate,AutoDeElevate,OptimizationHints",
|
|
1550
|
+
"--disable-field-trial-config",
|
|
1551
|
+
"--disable-background-timer-throttling",
|
|
1552
|
+
"--disable-backgrounding-occluded-windows",
|
|
1553
|
+
"--disable-back-forward-cache",
|
|
1554
|
+
"--disable-breakpad",
|
|
1555
|
+
"--disable-client-side-phishing-detection",
|
|
1556
|
+
"--disable-component-extensions-with-background-pages",
|
|
1557
|
+
"--disable-component-update",
|
|
1558
|
+
"--disable-default-apps",
|
|
1559
|
+
"--disable-dev-shm-usage",
|
|
1560
|
+
"--disable-extensions",
|
|
1561
|
+
"--disable-hang-monitor",
|
|
1562
|
+
"--disable-renderer-backgrounding",
|
|
1563
|
+
"--disable-sync",
|
|
1564
|
+
"--no-service-autorun",
|
|
1565
|
+
"--metrics-recording-only",
|
|
1566
|
+
"--force-color-profile=srgb",
|
|
1567
|
+
"--password-store=basic",
|
|
1568
|
+
"--use-mock-keychain",
|
|
1569
|
+
`--user-data-dir=${options.profileDir}`,
|
|
1570
|
+
`--proxy-server=${options.ownedProxy?.url ?? state.proxy.url}`,
|
|
1571
|
+
"--proxy-bypass-list=<-loopback>",
|
|
1572
|
+
"--disable-quic",
|
|
1573
|
+
"--webrtc-ip-handling-policy=disable_non_proxied_udp",
|
|
1574
|
+
"about:blank"
|
|
1575
|
+
]
|
|
1576
|
+
});
|
|
1577
|
+
root = await state.child.identity();
|
|
1578
|
+
const originalRoot = root;
|
|
1579
|
+
state.child.child.once("exit", (code, signal) => {
|
|
1580
|
+
if (code !== 0 || signal !== null) {
|
|
1581
|
+
state.uncertain = true;
|
|
1582
|
+
failed("browser", originalRoot);
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
const end = performance.now() + 1e4;
|
|
1586
|
+
let url;
|
|
1587
|
+
while (performance.now() < end) {
|
|
1588
|
+
try {
|
|
1589
|
+
url = await endpoint(file, before, directory);
|
|
1590
|
+
break;
|
|
1591
|
+
} catch (error) {
|
|
1592
|
+
if (error instanceof Error && error.message === "DEVTOOLS_CLOSE_UNCERTAIN") throw error;
|
|
1593
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
if (!url) throw new Error("DEVTOOLS_ENDPOINT_UNAVAILABLE");
|
|
1597
|
+
endpointURL = url;
|
|
1598
|
+
const holder = await processes.holder(options.profileDir);
|
|
1599
|
+
assertDirectory(directory);
|
|
1600
|
+
if (!holder || !sameProcess(holder, root)) throw new Error("DEVTOOLS_ROOT_MISMATCH");
|
|
1601
|
+
const sender = await processes.identity(process.pid);
|
|
1602
|
+
if (!sender) throw new Error("SUPERVISOR_IDENTITY_UNAVAILABLE");
|
|
1603
|
+
supervisor = sender;
|
|
1604
|
+
if (options.ownedProxy)
|
|
1605
|
+
state.auth = await ownPrivateProxyAuthentication(url, options.ownedProxy, () => {
|
|
1606
|
+
state.uncertain = true;
|
|
1607
|
+
failed("custody");
|
|
1608
|
+
});
|
|
1609
|
+
state.browser = await chromium.connectOverCDP(url, {
|
|
1610
|
+
timeout: Math.max(1, end - performance.now()),
|
|
1611
|
+
noDefaults: true
|
|
1612
|
+
});
|
|
1613
|
+
state.downloads = new DefaultDownloadOwner(
|
|
1614
|
+
state.browser,
|
|
1615
|
+
() => !state.uncertain && performance.now() < end,
|
|
1616
|
+
() => {
|
|
1617
|
+
state.uncertain = true;
|
|
1618
|
+
failed("custody");
|
|
1619
|
+
}
|
|
1620
|
+
);
|
|
1621
|
+
await waitWithin(state.downloads.ready, Math.max(1, end - performance.now()));
|
|
1622
|
+
if (state.browser.contexts().length !== 1) throw new Error("PERSISTENT_CONTEXT_UNAVAILABLE");
|
|
1623
|
+
} catch (error) {
|
|
1624
|
+
state.uncertain = true;
|
|
1625
|
+
state.downloads?.retire();
|
|
1626
|
+
try {
|
|
1627
|
+
state.child?.child.kill("SIGTERM");
|
|
1628
|
+
} catch {
|
|
1629
|
+
}
|
|
1630
|
+
state.cleanup = Promise.allSettled([
|
|
1631
|
+
// Join initialization even if the independent original browser closure refuses.
|
|
1632
|
+
state.downloads?.ready,
|
|
1633
|
+
Promise.resolve().then(() => closeBrowserAndDownloads(state.browser, state.downloads)),
|
|
1634
|
+
Promise.resolve().then(() => state.proxy?.close()),
|
|
1635
|
+
Promise.resolve().then(() => state.auth?.close()),
|
|
1636
|
+
Promise.resolve().then(() => state.child?.completion())
|
|
1637
|
+
]);
|
|
1638
|
+
await waitWithin(state.cleanup, 2e3).catch(() => {
|
|
1639
|
+
});
|
|
1640
|
+
throw error;
|
|
1641
|
+
}
|
|
1642
|
+
const browser = state.browser, child = state.child, proxy = state.proxy;
|
|
1643
|
+
const context = browser.contexts()[0];
|
|
1644
|
+
let closing;
|
|
1645
|
+
return Object.freeze({
|
|
1646
|
+
context,
|
|
1647
|
+
root,
|
|
1648
|
+
child,
|
|
1649
|
+
supervisor,
|
|
1650
|
+
proxyURL: options.ownedProxy?.url ?? proxy.url,
|
|
1651
|
+
endpointURL,
|
|
1652
|
+
close() {
|
|
1653
|
+
if (closing) return closing;
|
|
1654
|
+
state.downloads?.retire();
|
|
1655
|
+
const original = (async () => {
|
|
1656
|
+
const abort = new AbortController();
|
|
1657
|
+
let tree = { status: "unknown", identities: [] };
|
|
1658
|
+
try {
|
|
1659
|
+
tree = await processes.processes.descendants(root, abort.signal);
|
|
1660
|
+
} catch {
|
|
1661
|
+
state.uncertain = true;
|
|
1662
|
+
}
|
|
1663
|
+
if (tree.status !== "complete") state.uncertain = true;
|
|
1664
|
+
const results = await Promise.allSettled([
|
|
1665
|
+
(async () => {
|
|
1666
|
+
const session = await browser.newBrowserCDPSession();
|
|
1667
|
+
await session.send("Browser.close");
|
|
1668
|
+
})(),
|
|
1669
|
+
Promise.resolve().then(() => proxy?.close()),
|
|
1670
|
+
Promise.resolve().then(() => state.auth?.close())
|
|
1671
|
+
]);
|
|
1672
|
+
for (const result of results)
|
|
1673
|
+
if (result.status === "rejected")
|
|
1674
|
+
process.stderr.write(
|
|
1675
|
+
"SUPERVISOR_CLOSE: " + String(
|
|
1676
|
+
result.reason instanceof Error ? result.reason.message.slice(0, 1024) : "unknown"
|
|
1677
|
+
) + "\n"
|
|
1678
|
+
);
|
|
1679
|
+
if (results.some((result) => result.status === "rejected")) state.uncertain = true;
|
|
1680
|
+
const returned = await child.returned();
|
|
1681
|
+
const rootReturnForward = returned && acceptsDarwinOwnedChildReturn(child, returned) && originalRootReturned ? Promise.resolve().then(() => originalRootReturned(Object.freeze({ ...root }))) : Promise.resolve();
|
|
1682
|
+
void rootReturnForward.catch(() => {
|
|
1683
|
+
});
|
|
1684
|
+
if (!returned)
|
|
1685
|
+
process.stderr.write(
|
|
1686
|
+
"SUPERVISOR_CHILD_RETURN: " + String(child.custody().firstCause) + "\n"
|
|
1687
|
+
);
|
|
1688
|
+
let statuses = [];
|
|
1689
|
+
const nativeEnd = performance.now() + 2e3;
|
|
1690
|
+
try {
|
|
1691
|
+
do {
|
|
1692
|
+
statuses = await Promise.all(
|
|
1693
|
+
tree.identities.map((identity3) => processes.observeTerminated(identity3, abort.signal))
|
|
1694
|
+
);
|
|
1695
|
+
if (statuses.length && statuses.every((value) => value.status === "dead")) break;
|
|
1696
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
1697
|
+
} while (performance.now() < nativeEnd);
|
|
1698
|
+
} catch {
|
|
1699
|
+
state.uncertain = true;
|
|
1700
|
+
}
|
|
1701
|
+
try {
|
|
1702
|
+
await closeBrowserAndDownloads(browser, state.downloads);
|
|
1703
|
+
} catch {
|
|
1704
|
+
state.uncertain = true;
|
|
1705
|
+
}
|
|
1706
|
+
try {
|
|
1707
|
+
await rootReturnForward;
|
|
1708
|
+
} catch {
|
|
1709
|
+
state.uncertain = true;
|
|
1710
|
+
}
|
|
1711
|
+
abort.abort();
|
|
1712
|
+
if (!returned || !acceptsDarwinOwnedChildReturn(child, returned) || !statuses.length || statuses.some((value) => value.status !== "dead"))
|
|
1713
|
+
state.uncertain = true;
|
|
1714
|
+
if (!state.uncertain) retained3.delete(state);
|
|
1715
|
+
return !state.uncertain;
|
|
1716
|
+
})();
|
|
1717
|
+
state.cleanup = original;
|
|
1718
|
+
closing = waitWithin(original, 5e3).catch(() => {
|
|
1719
|
+
state.uncertain = true;
|
|
1720
|
+
return false;
|
|
1721
|
+
});
|
|
1722
|
+
return closing;
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
// packages/browser/src/runtime/darwin-supervisor-protocol.ts
|
|
1728
|
+
import { z as z5 } from "zod";
|
|
1729
|
+
|
|
1730
|
+
// packages/browser/src/runtime-descriptor.ts
|
|
1731
|
+
import { isAbsolute, normalize, parse } from "node:path";
|
|
1732
|
+
import { z as z4 } from "zod";
|
|
1733
|
+
|
|
1734
|
+
// packages/browser/src/counters.ts
|
|
1735
|
+
import { z as z3 } from "zod";
|
|
1736
|
+
|
|
1737
|
+
// packages/browser/src/validation.ts
|
|
1738
|
+
var MAX_BYTES = 16 * 1024;
|
|
1739
|
+
|
|
1740
|
+
// packages/browser/src/counters.ts
|
|
1741
|
+
var CounterSchema = z3.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
1742
|
+
|
|
1743
|
+
// packages/browser/src/runtime-descriptor.ts
|
|
1744
|
+
var AbsolutePathSchema = z4.string().min(1).max(4096).refine(
|
|
1745
|
+
(value) => !value.includes("\0") && isAbsolute(value) && normalize(value) === value && parse(value).root !== value
|
|
1746
|
+
);
|
|
1747
|
+
var RuntimeSchema = z4.object({
|
|
1748
|
+
library: z4.object({
|
|
1749
|
+
package: z4.literal("playwright-core"),
|
|
1750
|
+
version: z4.literal("1.63.0"),
|
|
1751
|
+
rootDir: AbsolutePathSchema,
|
|
1752
|
+
assets: z4.object({ manifest: z4.literal("browsers.json"), cli: z4.literal("cli.js") }).strict()
|
|
1753
|
+
}).strict(),
|
|
1754
|
+
executable: z4.object({
|
|
1755
|
+
path: AbsolutePathSchema,
|
|
1756
|
+
sha256: z4.string().regex(/^[a-f0-9]{64}$/),
|
|
1757
|
+
revision: z4.string().min(1).max(16).regex(/^\d+$/),
|
|
1758
|
+
version: z4.string().max(64).regex(/^\d+\.\d+\.\d+(?:\.\d+)?$/),
|
|
1759
|
+
platform: z4.enum(["darwin", "linux", "win32"]),
|
|
1760
|
+
arch: z4.enum(["arm64", "x64"])
|
|
1761
|
+
}).strict(),
|
|
1762
|
+
identity: z4.object({ mode: z4.enum(["native", "chrome-compatible"]), policyRevision: CounterSchema }).strict()
|
|
1763
|
+
}).strict();
|
|
1764
|
+
var RuntimeDescriptorSchema = RuntimeSchema;
|
|
1765
|
+
|
|
1766
|
+
// packages/browser/src/runtime/darwin-supervisor-protocol.ts
|
|
1767
|
+
var counter2 = z5.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
1768
|
+
var identity2 = z5.object({ pid: z5.number().int().positive().max(2147483647), birth: z5.string().min(1).max(128) }).strict();
|
|
1769
|
+
var nonce = z5.string().uuid();
|
|
1770
|
+
var sequence = counter2.refine((value) => value > 0);
|
|
1771
|
+
var SupervisorSeedSchema = z5.object({
|
|
1772
|
+
kind: z5.literal("launch"),
|
|
1773
|
+
nonce,
|
|
1774
|
+
reservationNonce: nonce,
|
|
1775
|
+
manager: identity2,
|
|
1776
|
+
browserId: z5.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/),
|
|
1777
|
+
generation: counter2,
|
|
1778
|
+
runtime: RuntimeDescriptorSchema,
|
|
1779
|
+
profileDir: AbsolutePathSchema,
|
|
1780
|
+
artifact: z5.object({ path: AbsolutePathSchema, sha256: z5.string().regex(/^[a-f0-9]{64}$/) }).strict(),
|
|
1781
|
+
ownedProxy: z5.object({
|
|
1782
|
+
url: z5.string().regex(/^http:\/\/127\.0\.0\.1:[1-9][0-9]{0,4}$/),
|
|
1783
|
+
credentials: z5.object({ username: z5.literal("dorkos"), password: z5.string().min(1).max(4096) }).strict()
|
|
1784
|
+
}).strict().optional(),
|
|
1785
|
+
origin: z5.string().url().max(256).refine((value) => {
|
|
1786
|
+
const url = new URL(value);
|
|
1787
|
+
return value === "about:blank" || url.protocol === "http:" && ["127.0.0.1", "[::1]"].includes(url.hostname) && url.origin === value && !!url.port;
|
|
1788
|
+
})
|
|
1789
|
+
}).strict();
|
|
1790
|
+
var SupervisorActionSchema = z5.discriminatedUnion("kind", [
|
|
1791
|
+
z5.object({ kind: z5.literal("list") }).strict(),
|
|
1792
|
+
z5.object({
|
|
1793
|
+
kind: z5.literal("navigate"),
|
|
1794
|
+
tab: sequence,
|
|
1795
|
+
url: z5.string().url().max(4096).refine((value) => ["http:", "https:"].includes(new URL(value).protocol))
|
|
1796
|
+
}).strict(),
|
|
1797
|
+
z5.object({ kind: z5.literal("close") }).strict()
|
|
1798
|
+
]);
|
|
1799
|
+
var SupervisorCommandSchema = z5.object({ kind: z5.literal("command"), nonce, sequence, action: SupervisorActionSchema }).strict();
|
|
1800
|
+
var tab = z5.object({ tab: sequence, url: z5.string().max(4096) }).strict();
|
|
1801
|
+
var SupervisorReplySchema = z5.discriminatedUnion("kind", [
|
|
1802
|
+
z5.object({
|
|
1803
|
+
kind: z5.literal("ready"),
|
|
1804
|
+
nonce,
|
|
1805
|
+
reservationNonce: nonce,
|
|
1806
|
+
browserId: SupervisorSeedSchema.shape.browserId,
|
|
1807
|
+
generation: counter2,
|
|
1808
|
+
endpointURL: z5.string().max(256).regex(/^ws:\/\/127\.0\.0\.1:[1-9][0-9]{0,4}\/devtools\/browser\/[a-fA-F0-9-]{36}$/),
|
|
1809
|
+
root: identity2,
|
|
1810
|
+
supervisor: identity2,
|
|
1811
|
+
proxyURL: z5.string().max(256).regex(/^http:\/\/127\.0\.0\.1:[1-9][0-9]{0,4}$/)
|
|
1812
|
+
}).strict(),
|
|
1813
|
+
z5.object({
|
|
1814
|
+
kind: z5.literal("reply"),
|
|
1815
|
+
nonce,
|
|
1816
|
+
sequence,
|
|
1817
|
+
value: z5.union([z5.array(tab).max(128), z5.object({ tab: sequence }).strict()])
|
|
1818
|
+
}).strict(),
|
|
1819
|
+
z5.object({ kind: z5.literal("rootReturned"), nonce, sequence, root: identity2 }).strict(),
|
|
1820
|
+
z5.object({ kind: z5.literal("closed"), nonce, sequence, returned: z5.boolean() }).strict(),
|
|
1821
|
+
z5.object({ kind: z5.literal("refused"), nonce, sequence }).strict(),
|
|
1822
|
+
z5.object({ kind: z5.literal("custodyFault"), nonce }).strict(),
|
|
1823
|
+
z5.object({ kind: z5.literal("rootFailure"), nonce, root: identity2 }).strict()
|
|
1824
|
+
]);
|
|
1825
|
+
|
|
1826
|
+
// packages/browser/src/runtime/darwin-supervisor-worker.ts
|
|
1827
|
+
async function runDarwinSupervisorWorker() {
|
|
1828
|
+
let owner;
|
|
1829
|
+
let launching, stopping = false, accepted = false, lastSequence = 0;
|
|
1830
|
+
let seed;
|
|
1831
|
+
let pending = 0, tail = Promise.resolve(), closePromise;
|
|
1832
|
+
let originalCloseSequence;
|
|
1833
|
+
const pages = /* @__PURE__ */ new Map();
|
|
1834
|
+
let nextTab = 1;
|
|
1835
|
+
const sends = /* @__PURE__ */ new Set();
|
|
1836
|
+
const send = async (value) => {
|
|
1837
|
+
if (!process.connected || !process.send) return;
|
|
1838
|
+
const parsed = SupervisorReplySchema.parse(value);
|
|
1839
|
+
if (Buffer.byteLength(JSON.stringify(value)) > 65536)
|
|
1840
|
+
throw new Error("SUPERVISOR_REPLY_EXCEEDED");
|
|
1841
|
+
const original = new Promise(
|
|
1842
|
+
(resolve, reject) => process.send(parsed, (error) => error ? reject(error) : resolve())
|
|
1843
|
+
);
|
|
1844
|
+
sends.add(original);
|
|
1845
|
+
void original.then(
|
|
1846
|
+
() => sends.delete(original),
|
|
1847
|
+
() => {
|
|
1848
|
+
}
|
|
1849
|
+
);
|
|
1850
|
+
await original;
|
|
1851
|
+
};
|
|
1852
|
+
const close = () => {
|
|
1853
|
+
stopping = true;
|
|
1854
|
+
closePromise ??= (async () => {
|
|
1855
|
+
await launching?.catch(() => {
|
|
1856
|
+
});
|
|
1857
|
+
const [result] = await Promise.all([owner ? owner.close() : Promise.resolve(false), tail]);
|
|
1858
|
+
pages.clear();
|
|
1859
|
+
return result && sends.size === 0;
|
|
1860
|
+
})();
|
|
1861
|
+
return closePromise;
|
|
1862
|
+
};
|
|
1863
|
+
const disconnect = () => {
|
|
1864
|
+
void close().then(
|
|
1865
|
+
(returned) => {
|
|
1866
|
+
process.exitCode = returned ? 0 : 1;
|
|
1867
|
+
if (process.connected) process.disconnect();
|
|
1868
|
+
},
|
|
1869
|
+
() => {
|
|
1870
|
+
process.exitCode = 1;
|
|
1871
|
+
if (process.connected) process.disconnect();
|
|
1872
|
+
}
|
|
1873
|
+
);
|
|
1874
|
+
};
|
|
1875
|
+
process.once("disconnect", disconnect);
|
|
1876
|
+
process.on("message", (message) => {
|
|
1877
|
+
if (stopping) return;
|
|
1878
|
+
let bytes;
|
|
1879
|
+
try {
|
|
1880
|
+
bytes = Buffer.byteLength(JSON.stringify(message));
|
|
1881
|
+
} catch {
|
|
1882
|
+
disconnect();
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
if (bytes > 65536) {
|
|
1886
|
+
disconnect();
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
if (!accepted) {
|
|
1890
|
+
accepted = true;
|
|
1891
|
+
const parsed2 = SupervisorSeedSchema.safeParse(message);
|
|
1892
|
+
if (!parsed2.success) {
|
|
1893
|
+
disconnect();
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
seed = parsed2.data;
|
|
1897
|
+
if (seed.manager.pid !== process.ppid) {
|
|
1898
|
+
disconnect();
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
const origin = new URL(seed.origin);
|
|
1902
|
+
if (!seed.ownedProxy && (origin.protocol !== "http:" || !["127.0.0.1", "[::1]"].includes(origin.hostname) || origin.origin !== seed.origin || !origin.port)) {
|
|
1903
|
+
disconnect();
|
|
1904
|
+
return;
|
|
1905
|
+
}
|
|
1906
|
+
launching = (async () => {
|
|
1907
|
+
owner = await launchDarwinSupervisorBrowser(
|
|
1908
|
+
seed,
|
|
1909
|
+
(cause, root) => {
|
|
1910
|
+
void send(
|
|
1911
|
+
cause === "browser" && root ? { kind: "rootFailure", nonce: seed.nonce, root } : { kind: "custodyFault", nonce: seed.nonce }
|
|
1912
|
+
).catch(() => {
|
|
1913
|
+
});
|
|
1914
|
+
disconnect();
|
|
1915
|
+
},
|
|
1916
|
+
async (root) => {
|
|
1917
|
+
if (originalCloseSequence === void 0) return;
|
|
1918
|
+
await send({
|
|
1919
|
+
kind: "rootReturned",
|
|
1920
|
+
nonce: seed.nonce,
|
|
1921
|
+
sequence: originalCloseSequence,
|
|
1922
|
+
root
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
);
|
|
1926
|
+
if (stopping) return;
|
|
1927
|
+
void send({
|
|
1928
|
+
kind: "ready",
|
|
1929
|
+
nonce: seed.nonce,
|
|
1930
|
+
browserId: seed.browserId,
|
|
1931
|
+
reservationNonce: seed.reservationNonce,
|
|
1932
|
+
generation: seed.generation,
|
|
1933
|
+
endpointURL: owner.endpointURL,
|
|
1934
|
+
root: owner.root,
|
|
1935
|
+
supervisor: owner.supervisor,
|
|
1936
|
+
proxyURL: owner.proxyURL
|
|
1937
|
+
}).catch(() => disconnect());
|
|
1938
|
+
})();
|
|
1939
|
+
void launching.catch(() => disconnect());
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
const parsed = SupervisorCommandSchema.safeParse(message);
|
|
1943
|
+
if (!parsed.success || parsed.data.nonce !== seed.nonce || parsed.data.sequence !== lastSequence + 1 || pending >= 8) {
|
|
1944
|
+
disconnect();
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
const request = parsed.data;
|
|
1948
|
+
lastSequence = request.sequence;
|
|
1949
|
+
if (request.action.kind === "close") {
|
|
1950
|
+
originalCloseSequence = request.sequence;
|
|
1951
|
+
void close().then(async (returned) => {
|
|
1952
|
+
await send({ kind: "closed", nonce: seed.nonce, sequence: request.sequence, returned });
|
|
1953
|
+
if (process.connected) process.disconnect();
|
|
1954
|
+
process.exitCode = returned ? 0 : 1;
|
|
1955
|
+
}).catch(disconnect);
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
pending++;
|
|
1959
|
+
const operation = tail.then(async () => {
|
|
1960
|
+
await launching;
|
|
1961
|
+
if (stopping || !owner) throw new Error("SUPERVISOR_STOPPED");
|
|
1962
|
+
let value;
|
|
1963
|
+
if (request.action.kind === "list") {
|
|
1964
|
+
for (const page of owner.context.pages()) {
|
|
1965
|
+
if (![...pages.values()].includes(page)) {
|
|
1966
|
+
if (pages.size >= 128) throw new Error("SUPERVISOR_TAB_LIMIT");
|
|
1967
|
+
pages.set(nextTab++, page);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
value = [...pages].filter(([, page]) => !page.isClosed()).map(([tab2, page]) => ({ tab: tab2, url: page.url().slice(0, 4096) }));
|
|
1971
|
+
} else if (request.action.kind === "navigate") {
|
|
1972
|
+
const page = pages.get(request.action.tab), url = new URL(request.action.url);
|
|
1973
|
+
if (!page || page.isClosed() || !["http:", "https:"].includes(url.protocol) || !seed.ownedProxy && url.origin !== seed.origin || url.username || url.password)
|
|
1974
|
+
throw new Error("SUPERVISOR_TARGET_REFUSED");
|
|
1975
|
+
await page.goto(url.href, { timeout: 5e3 });
|
|
1976
|
+
value = { tab: request.action.tab };
|
|
1977
|
+
} else throw new Error("SUPERVISOR_ACTION_REFUSED");
|
|
1978
|
+
if (!stopping)
|
|
1979
|
+
await send({ kind: "reply", nonce: seed.nonce, sequence: request.sequence, value });
|
|
1980
|
+
});
|
|
1981
|
+
tail = operation.catch(async (error) => {
|
|
1982
|
+
process.stderr.write(
|
|
1983
|
+
(error instanceof Error ? error.message.slice(0, 1024) : "SUPERVISOR_ACTION_FAILED") + "\n"
|
|
1984
|
+
);
|
|
1985
|
+
if (!stopping)
|
|
1986
|
+
await send({ kind: "refused", nonce: seed.nonce, sequence: request.sequence });
|
|
1987
|
+
}).then(() => {
|
|
1988
|
+
pending--;
|
|
1989
|
+
});
|
|
1990
|
+
void tail.catch(disconnect);
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
if (process.argv[2] === "--private-darwin-browser-supervisor") void runDarwinSupervisorWorker();
|
|
1994
|
+
export {
|
|
1995
|
+
runDarwinSupervisorWorker
|
|
1996
|
+
};
|