@juxtapose/core 0.2.0 → 0.5.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.
Files changed (141) hide show
  1. package/dist/agent/handoff.d.ts +8 -1
  2. package/dist/agent/handoff.js +75 -7
  3. package/dist/agent/handoff.js.map +1 -1
  4. package/dist/analysis/affected.d.ts +58 -0
  5. package/dist/analysis/affected.js +134 -22
  6. package/dist/analysis/affected.js.map +1 -1
  7. package/dist/analysis/cause.d.ts +32 -0
  8. package/dist/analysis/cause.js +187 -0
  9. package/dist/analysis/cause.js.map +1 -0
  10. package/dist/baseline/approve.d.ts +24 -0
  11. package/dist/baseline/approve.js +54 -0
  12. package/dist/baseline/approve.js.map +1 -0
  13. package/dist/baseline/git-store.d.ts +4 -0
  14. package/dist/baseline/git-store.js +22 -0
  15. package/dist/baseline/git-store.js.map +1 -1
  16. package/dist/browser/acquire.d.ts +11 -0
  17. package/dist/browser/acquire.js +15 -0
  18. package/dist/browser/acquire.js.map +1 -0
  19. package/dist/browser/browser.d.ts +53 -0
  20. package/dist/browser/browser.js +122 -0
  21. package/dist/browser/browser.js.map +1 -0
  22. package/dist/browser/cdp.d.ts +81 -0
  23. package/dist/browser/cdp.js +230 -0
  24. package/dist/browser/cdp.js.map +1 -0
  25. package/dist/browser/index.d.ts +9 -0
  26. package/dist/browser/index.js +10 -0
  27. package/dist/browser/index.js.map +1 -0
  28. package/dist/browser/install.d.ts +33 -0
  29. package/dist/browser/install.js +167 -0
  30. package/dist/browser/install.js.map +1 -0
  31. package/dist/browser/launch.d.ts +37 -0
  32. package/dist/browser/launch.js +265 -0
  33. package/dist/browser/launch.js.map +1 -0
  34. package/dist/browser/page.d.ts +125 -0
  35. package/dist/browser/page.js +564 -0
  36. package/dist/browser/page.js.map +1 -0
  37. package/dist/browser/pins.d.ts +12 -0
  38. package/dist/browser/pins.js +57 -0
  39. package/dist/browser/pins.js.map +1 -0
  40. package/dist/browser/resolve.d.ts +25 -0
  41. package/dist/browser/resolve.js +115 -0
  42. package/dist/browser/resolve.js.map +1 -0
  43. package/dist/browser/selectors.d.ts +10 -0
  44. package/dist/browser/selectors.js +60 -0
  45. package/dist/browser/selectors.js.map +1 -0
  46. package/dist/browser/transport.d.ts +39 -0
  47. package/dist/browser/transport.js +99 -0
  48. package/dist/browser/transport.js.map +1 -0
  49. package/dist/browser/zip.d.ts +27 -0
  50. package/dist/browser/zip.js +241 -0
  51. package/dist/browser/zip.js.map +1 -0
  52. package/dist/capture/capture.d.ts +7 -1
  53. package/dist/capture/capture.js +27 -3
  54. package/dist/capture/capture.js.map +1 -1
  55. package/dist/capture/env.d.ts +8 -0
  56. package/dist/capture/env.js +38 -0
  57. package/dist/capture/env.js.map +1 -0
  58. package/dist/capture/launch.d.ts +19 -1
  59. package/dist/capture/launch.js +91 -1
  60. package/dist/capture/launch.js.map +1 -1
  61. package/dist/capture/pool.d.ts +1 -1
  62. package/dist/capture/pool.js +41 -8
  63. package/dist/capture/pool.js.map +1 -1
  64. package/dist/capture/settle.d.ts +1 -1
  65. package/dist/capture/settle.js +2 -0
  66. package/dist/capture/settle.js.map +1 -1
  67. package/dist/capture/snap.d.ts +43 -0
  68. package/dist/capture/snap.js +103 -0
  69. package/dist/capture/snap.js.map +1 -0
  70. package/dist/capture/structure.d.ts +77 -0
  71. package/dist/capture/structure.js +498 -0
  72. package/dist/capture/structure.js.map +1 -0
  73. package/dist/diff/compare.d.ts +19 -0
  74. package/dist/diff/compare.js +19 -0
  75. package/dist/diff/compare.js.map +1 -0
  76. package/dist/diff/crops.d.ts +26 -0
  77. package/dist/diff/crops.js +92 -0
  78. package/dist/diff/crops.js.map +1 -0
  79. package/dist/diff/structural/classify.d.ts +29 -0
  80. package/dist/diff/structural/classify.js +113 -0
  81. package/dist/diff/structural/classify.js.map +1 -0
  82. package/dist/diff/structural/coverage.d.ts +11 -0
  83. package/dist/diff/structural/coverage.js +37 -0
  84. package/dist/diff/structural/coverage.js.map +1 -0
  85. package/dist/diff/structural/deltas.d.ts +29 -0
  86. package/dist/diff/structural/deltas.js +218 -0
  87. package/dist/diff/structural/deltas.js.map +1 -0
  88. package/dist/diff/structural/disambiguate.d.ts +3 -0
  89. package/dist/diff/structural/disambiguate.js +89 -0
  90. package/dist/diff/structural/disambiguate.js.map +1 -0
  91. package/dist/diff/structural/label.d.ts +15 -0
  92. package/dist/diff/structural/label.js +64 -0
  93. package/dist/diff/structural/label.js.map +1 -0
  94. package/dist/diff/structural/match.d.ts +13 -0
  95. package/dist/diff/structural/match.js +135 -0
  96. package/dist/diff/structural/match.js.map +1 -0
  97. package/dist/diff/structural/shift.d.ts +2 -0
  98. package/dist/diff/structural/shift.js +144 -0
  99. package/dist/diff/structural/shift.js.map +1 -0
  100. package/dist/diff/structural/summary.d.ts +31 -0
  101. package/dist/diff/structural/summary.js +420 -0
  102. package/dist/diff/structural/summary.js.map +1 -0
  103. package/dist/diff/structural.d.ts +40 -0
  104. package/dist/diff/structural.js +219 -0
  105. package/dist/diff/structural.js.map +1 -0
  106. package/dist/index.d.ts +34 -12
  107. package/dist/index.js +55 -11
  108. package/dist/index.js.map +1 -1
  109. package/dist/platform.d.ts +1 -1
  110. package/dist/platforms/urls.d.ts +3 -0
  111. package/dist/platforms/urls.js +89 -0
  112. package/dist/platforms/urls.js.map +1 -0
  113. package/dist/report/comment.d.ts +2 -1
  114. package/dist/report/comment.js +305 -57
  115. package/dist/report/comment.js.map +1 -1
  116. package/dist/report/format.d.ts +20 -0
  117. package/dist/report/format.js +32 -0
  118. package/dist/report/format.js.map +1 -0
  119. package/dist/report/github.d.ts +12 -0
  120. package/dist/report/github.js +21 -0
  121. package/dist/report/github.js.map +1 -1
  122. package/dist/report/html.d.ts +12 -0
  123. package/dist/report/html.js +202 -0
  124. package/dist/report/html.js.map +1 -0
  125. package/dist/run/groups.d.ts +2 -0
  126. package/dist/run/groups.js +45 -0
  127. package/dist/run/groups.js.map +1 -0
  128. package/dist/run/phases.d.ts +19 -0
  129. package/dist/run/phases.js +50 -0
  130. package/dist/run/phases.js.map +1 -0
  131. package/dist/run/run.d.ts +10 -2
  132. package/dist/run/run.js +97 -9
  133. package/dist/run/run.js.map +1 -1
  134. package/dist/shell-quote.d.ts +2 -0
  135. package/dist/shell-quote.js +10 -0
  136. package/dist/shell-quote.js.map +1 -0
  137. package/dist/types.d.ts +234 -3
  138. package/dist/url-platform.d.ts +2 -2
  139. package/dist/url-platform.js +2 -2
  140. package/dist/url-platform.js.map +1 -1
  141. package/package.json +14 -10
@@ -0,0 +1,230 @@
1
+ // packages/core/src/browser/cdp.ts
2
+ //
3
+ // The whole protocol client: ids out, replies back, events routed by
4
+ // sessionId. Playwright's CRConnection does the same in ~300 lines plus
5
+ // the parts we never use.
6
+ //
7
+ // Every send has a Node-side timeout. Chrome answers Runtime.evaluate only
8
+ // when the script returns, so a story with a synchronous infinite loop would
9
+ // otherwise hang the worker and the run.
10
+ export const SEND_TIMEOUT_MS = 30_000;
11
+ export class CdpError extends Error {
12
+ code;
13
+ constructor(code, method, message) {
14
+ super(`${method}: ${message}`);
15
+ this.code = code;
16
+ this.name = 'CdpError';
17
+ }
18
+ }
19
+ export class TargetClosedError extends Error {
20
+ constructor(reason = 'browser closed', method) {
21
+ super(`jux: browser connection closed (${reason})${method ? ` while waiting for ${method}` : ''}`);
22
+ this.name = 'TargetClosedError';
23
+ }
24
+ }
25
+ export class SendTimeoutError extends Error {
26
+ constructor(method, timeout) {
27
+ super(`jux: ${method} got no reply from the browser within ${timeout} ms`);
28
+ this.name = 'SendTimeoutError';
29
+ }
30
+ }
31
+ export class CdpConnection {
32
+ transport;
33
+ lastId = 0;
34
+ pending = new Map();
35
+ /** key = `${sessionId ?? ''}\n${method}` */
36
+ handlers = new Map();
37
+ closeWaiters = new Set();
38
+ _closed = false;
39
+ closeReason;
40
+ onClose = null;
41
+ /** Every parsed frame, before routing. The PR 2 supervisor proxies from here. */
42
+ onRaw = null;
43
+ /**
44
+ * A throwing event handler or onRaw must not escape into the stream's data
45
+ * event (an uncaught exception would kill the daemon) nor skip the rest of
46
+ * the chunk. Default: one line on stderr.
47
+ */
48
+ onError = (error, where) => {
49
+ const msg = error instanceof Error ? error.message : String(error);
50
+ process.stderr.write(`jux: ${where} threw: ${msg}\n`);
51
+ };
52
+ constructor(transport) {
53
+ this.transport = transport;
54
+ transport.onMessage = (m) => this.dispatch(m);
55
+ transport.onClose = (reason) => this.handleClose(reason);
56
+ }
57
+ get closed() {
58
+ return this._closed;
59
+ }
60
+ get pendingCount() {
61
+ return this.pending.size;
62
+ }
63
+ /** Number of distinct (session, method) handler keys; empty sets are pruned. */
64
+ get handlerKeyCount() {
65
+ return this.handlers.size;
66
+ }
67
+ /** Total registered handlers, summed over every key; a leak test's yardstick. */
68
+ get handlerCount() {
69
+ let n = 0;
70
+ for (const set of this.handlers.values())
71
+ n += set.size;
72
+ return n;
73
+ }
74
+ /**
75
+ * Call `listener` once when the connection closes (at once if it already
76
+ * has); returns the unsubscribe. Pages use it to fail in-flight work fast
77
+ * instead of waiting out each send's timeout.
78
+ */
79
+ onClosed(listener) {
80
+ if (this._closed) {
81
+ listener(new TargetClosedError(this.closeReason));
82
+ return () => { };
83
+ }
84
+ this.closeWaiters.add(listener);
85
+ return () => this.closeWaiters.delete(listener);
86
+ }
87
+ allocateId() {
88
+ return ++this.lastId;
89
+ }
90
+ /**
91
+ * Throws TargetClosedError once the connection is closed, so a proxying
92
+ * caller (the PR 2 supervisor) learns its client message was not delivered
93
+ * instead of waiting for a reply that cannot come.
94
+ */
95
+ sendRaw(message) {
96
+ if (this._closed)
97
+ throw new TargetClosedError(this.closeReason, message.method);
98
+ this.transport.send(JSON.stringify(message));
99
+ }
100
+ send(method, params = {}, sessionId, opts = {}) {
101
+ if (this._closed)
102
+ return Promise.reject(new TargetClosedError(this.closeReason, method));
103
+ const id = this.allocateId();
104
+ const timeout = opts.timeout ?? SEND_TIMEOUT_MS;
105
+ return new Promise((resolve, reject) => {
106
+ const timer = setTimeout(() => {
107
+ this.pending.delete(id);
108
+ reject(new SendTimeoutError(method, timeout));
109
+ }, timeout);
110
+ timer.unref();
111
+ this.pending.set(id, {
112
+ method,
113
+ resolve: resolve,
114
+ reject,
115
+ timer,
116
+ });
117
+ try {
118
+ this.sendRaw(sessionId ? { id, method, params, sessionId } : { id, method, params });
119
+ }
120
+ catch (e) {
121
+ clearTimeout(timer);
122
+ this.pending.delete(id);
123
+ reject(e instanceof Error ? e : new Error(String(e)));
124
+ }
125
+ });
126
+ }
127
+ on(method, handler, sessionId) {
128
+ const key = `${sessionId ?? ''}\n${method}`;
129
+ let set = this.handlers.get(key);
130
+ if (!set)
131
+ this.handlers.set(key, (set = new Set()));
132
+ set.add(handler);
133
+ return () => {
134
+ set.delete(handler);
135
+ if (set.size === 0 && this.handlers.get(key) === set)
136
+ this.handlers.delete(key);
137
+ };
138
+ }
139
+ /**
140
+ * Without a sessionId this listens on the browser session only, where
141
+ * session-scoped events never arrive; pass the page's sessionId for page
142
+ * events.
143
+ */
144
+ once(method, sessionId, predicate = () => true) {
145
+ if (this._closed)
146
+ return Promise.reject(new TargetClosedError(this.closeReason, method));
147
+ return new Promise((resolve, reject) => {
148
+ const onClosed = (e) => {
149
+ off();
150
+ reject(e);
151
+ };
152
+ const off = this.on(method, (params) => {
153
+ if (!predicate(params))
154
+ return;
155
+ off();
156
+ this.closeWaiters.delete(onClosed);
157
+ resolve(params);
158
+ }, sessionId);
159
+ this.closeWaiters.add(onClosed);
160
+ });
161
+ }
162
+ close() {
163
+ this.transport.close();
164
+ }
165
+ dispatch(raw) {
166
+ let m;
167
+ try {
168
+ m = JSON.parse(raw);
169
+ }
170
+ catch {
171
+ return; // Chrome never sends non-JSON frames; nothing to do but ignore.
172
+ }
173
+ try {
174
+ this.onRaw?.(m);
175
+ }
176
+ catch (e) {
177
+ this.onError(e, 'onRaw');
178
+ }
179
+ if (m.id !== undefined) {
180
+ const p = this.pending.get(m.id);
181
+ if (!p)
182
+ return; // a raw (proxied) id, or a reply after its timeout
183
+ this.pending.delete(m.id);
184
+ clearTimeout(p.timer);
185
+ if (m.error)
186
+ p.reject(new CdpError(m.error.code, p.method, m.error.message));
187
+ else
188
+ p.resolve(m.result);
189
+ return;
190
+ }
191
+ if (m.method) {
192
+ const set = this.handlers.get(`${m.sessionId ?? ''}\n${m.method}`);
193
+ if (set)
194
+ this.runHandlers(set, m);
195
+ // Session-less listeners see every event (the browser session's Target.* events).
196
+ if (m.sessionId) {
197
+ const all = this.handlers.get(`\n${m.method}`);
198
+ if (all)
199
+ this.runHandlers(all, m);
200
+ }
201
+ }
202
+ }
203
+ runHandlers(set, m) {
204
+ for (const h of [...set]) {
205
+ try {
206
+ h(m.params, m.sessionId);
207
+ }
208
+ catch (e) {
209
+ this.onError(e, 'handler');
210
+ }
211
+ }
212
+ }
213
+ handleClose(reason) {
214
+ if (this._closed)
215
+ return;
216
+ this._closed = true;
217
+ this.closeReason = reason;
218
+ for (const p of this.pending.values()) {
219
+ clearTimeout(p.timer);
220
+ p.reject(new TargetClosedError(reason, p.method));
221
+ }
222
+ this.pending.clear();
223
+ const err = new TargetClosedError(reason);
224
+ for (const w of [...this.closeWaiters])
225
+ w(err);
226
+ this.closeWaiters.clear();
227
+ this.onClose?.(reason);
228
+ }
229
+ }
230
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../src/browser/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { Browser, BrowserContext, type ContextOptions } from './browser.js';
2
+ export { CdpPage, PageCrashedError, TimeoutError, type Page } from './page.js';
3
+ export { CdpConnection, CdpError, SendTimeoutError, TargetClosedError, SEND_TIMEOUT_MS, type RawMessage, } from './cdp.js';
4
+ export { PipeTransport, SocketTransport, FramedTransport, NullFramer, type Transport, } from './transport.js';
5
+ export { launchChrome, terminateAll, type LaunchedChrome, type SpawnFn, } from './launch.js';
6
+ export { resolveChrome, juxCacheDir, chromeInstallDir, chromeBinaryPath, msPlaywrightBinaryPath, noBrowserMessage, NO_BROWSER_MESSAGE, INSTALL_MARKER, type ResolvedChrome, type ResolveOptions, type ChromeSource, } from './resolve.js';
7
+ export { installChrome, proxyHint, type InstallOptions, type InstallResult, } from './install.js';
8
+ export { CHROME_VERSION, CHROME_PINS, MS_PLAYWRIGHT_REVISION, chromePlatform, type ChromePlatform, type ChromePin, } from './pins.js';
9
+ export { isCssSelector, assertCssSelector, QUERY_ALL_SOURCE, queryAllExpression, } from './selectors.js';
@@ -0,0 +1,10 @@
1
+ export { Browser, BrowserContext } from './browser.js';
2
+ export { CdpPage, PageCrashedError, TimeoutError } from './page.js';
3
+ export { CdpConnection, CdpError, SendTimeoutError, TargetClosedError, SEND_TIMEOUT_MS, } from './cdp.js';
4
+ export { PipeTransport, SocketTransport, FramedTransport, NullFramer, } from './transport.js';
5
+ export { launchChrome, terminateAll, } from './launch.js';
6
+ export { resolveChrome, juxCacheDir, chromeInstallDir, chromeBinaryPath, msPlaywrightBinaryPath, noBrowserMessage, NO_BROWSER_MESSAGE, INSTALL_MARKER, } from './resolve.js';
7
+ export { installChrome, proxyHint, } from './install.js';
8
+ export { CHROME_VERSION, CHROME_PINS, MS_PLAYWRIGHT_REVISION, chromePlatform, } from './pins.js';
9
+ export { isCssSelector, assertCssSelector, QUERY_ALL_SOURCE, queryAllExpression, } from './selectors.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAuB,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAa,MAAM,WAAW,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAEhB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,aAAa,EACb,eAAe,EACf,eAAe,EACf,UAAU,GAEX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,YAAY,GAGb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,GAIf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,SAAS,GAGV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,WAAW,EACX,sBAAsB,EACtB,cAAc,GAGf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type ChromePin, type ChromePlatform } from './pins.js';
2
+ import { type ChromeSource } from './resolve.js';
3
+ import { installZip } from './zip.js';
4
+ export interface InstallOptions {
5
+ cacheDir: string;
6
+ platform?: ChromePlatform;
7
+ fetch?: typeof fetch;
8
+ env?: NodeJS.ProcessEnv;
9
+ onProgress?: (received: number, total: number | null) => void;
10
+ /** Test seam: a pin for a fixture zip. */
11
+ pin?: ChromePin;
12
+ /** Reinstall even when a usable browser is already in the jux or Playwright cache. */
13
+ force?: boolean;
14
+ /** Test seams: the flags this Node accepts, and the zip installer. */
15
+ nodeFlags?: ReadonlySet<string>;
16
+ installZip?: typeof installZip;
17
+ }
18
+ export interface InstallResult {
19
+ path: string;
20
+ version: string;
21
+ alreadyInstalled: boolean;
22
+ /** Where an existing browser was found; absent after a fresh install. */
23
+ source?: ChromeSource;
24
+ }
25
+ export declare function proxyHint(env: NodeJS.ProcessEnv, nodeFlags?: ReadonlySet<string>): string;
26
+ /**
27
+ * Extra node args for the CLI to re-exec with, or null. Detects the flag
28
+ * rather than comparing versions: it is whatever this Node accepts.
29
+ */
30
+ export declare function proxyReexecArgs(env: NodeJS.ProcessEnv, nodeFlags?: ReadonlySet<string>, execArgv?: readonly string[]): string[] | null;
31
+ /** A progress callback for stderr, or undefined when stderr is not a TTY. */
32
+ export declare function stderrProgress(stream?: Pick<NodeJS.WriteStream, 'isTTY' | 'write'>): InstallOptions['onProgress'];
33
+ export declare function installChrome(opts: InstallOptions): Promise<InstallResult>;
@@ -0,0 +1,167 @@
1
+ // packages/core/src/browser/install.ts
2
+ //
3
+ // Download -> sha256 + byte length -> installZip (extract to a temp sibling,
4
+ // marker written inside it, atomic swap) -> verify the result runs. The marker
5
+ // is what resolve.ts trusts, so it goes in before the swap and an interrupted
6
+ // install can never be mistaken for a working one.
7
+ //
8
+ // Proxies: Node's global fetch ignores HTTPS_PROXY unless the process runs
9
+ // with NODE_USE_ENV_PROXY=1 / --use-env-proxy (Node 24+). We cannot set that
10
+ // inside a running process, so the CLI re-executes itself with the flag when
11
+ // a proxy variable is present (`proxyReexecArgs`), and this module names the
12
+ // variable in the error for every other caller (Node 22 included).
13
+ import { execFile } from 'node:child_process';
14
+ import { createHash } from 'node:crypto';
15
+ import { stat, rm } from 'node:fs/promises';
16
+ import path from 'node:path';
17
+ import { CHROME_PINS, CHROME_VERSION, chromePlatform, } from './pins.js';
18
+ import { chromeBinaryPath, chromeInstallDir, INSTALL_MARKER, resolveChrome, } from './resolve.js';
19
+ import { installZip } from './zip.js';
20
+ const PROXY_VARS = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy'];
21
+ const PROXY_FLAG = '--use-env-proxy';
22
+ export function proxyHint(env, nodeFlags = process.allowedNodeEnvironmentFlags) {
23
+ const set = PROXY_VARS.find((v) => env[v]);
24
+ if (!set)
25
+ return '';
26
+ const fix = nodeFlags.has(PROXY_FLAG)
27
+ ? 're-run with NODE_USE_ENV_PROXY=1, or'
28
+ : `this Node lacks ${PROXY_FLAG}, so`;
29
+ return ` ${set} is set but Node's fetch does not use it by default: ${fix} download the zip yourself and set JUX_CHROME.`;
30
+ }
31
+ /**
32
+ * Extra node args for the CLI to re-exec with, or null. Detects the flag
33
+ * rather than comparing versions: it is whatever this Node accepts.
34
+ */
35
+ export function proxyReexecArgs(env, nodeFlags = process.allowedNodeEnvironmentFlags, execArgv = process.execArgv) {
36
+ if (!PROXY_VARS.some((v) => env[v]))
37
+ return null;
38
+ if (env.NODE_USE_ENV_PROXY === '1' || execArgv.includes(PROXY_FLAG))
39
+ return null;
40
+ return nodeFlags.has(PROXY_FLAG) ? [PROXY_FLAG] : null;
41
+ }
42
+ /** A progress callback for stderr, or undefined when stderr is not a TTY. */
43
+ export function stderrProgress(stream = process.stderr) {
44
+ if (!stream.isTTY)
45
+ return undefined;
46
+ return (received, total) => {
47
+ const mb = (received / 1048576).toFixed(1);
48
+ const of = total ? ` / ${(total / 1048576).toFixed(1)}` : '';
49
+ stream.write(`\rjux: downloading chrome-headless-shell ${mb}${of} MB`);
50
+ if (total !== null && received >= total)
51
+ stream.write('\n');
52
+ };
53
+ }
54
+ // resolveChrome speaks Node's platform/arch, not Chrome for Testing's.
55
+ const NODE_TARGET = {
56
+ linux64: { platform: 'linux', arch: 'x64' },
57
+ 'mac-arm64': { platform: 'darwin', arch: 'arm64' },
58
+ 'mac-x64': { platform: 'darwin', arch: 'x64' },
59
+ win64: { platform: 'win32', arch: 'x64' },
60
+ };
61
+ export async function installChrome(opts) {
62
+ const platform = opts.platform ?? chromePlatform();
63
+ const pin = opts.pin ?? CHROME_PINS[platform];
64
+ const env = opts.env ?? process.env;
65
+ const installDir = chromeInstallDir(opts.cacheDir, CHROME_VERSION);
66
+ const binary = chromeBinaryPath(installDir, platform);
67
+ if (!opts.force) {
68
+ // JUX_CHROME is not "installed": it may point anywhere, so ignore it here.
69
+ const { JUX_CHROME: _ignored, ...rest } = env;
70
+ const found = resolveChrome({
71
+ ...NODE_TARGET[platform],
72
+ env: { ...rest, JUX_CACHE_DIR: opts.cacheDir },
73
+ });
74
+ if (found) {
75
+ return {
76
+ path: found.path,
77
+ version: CHROME_VERSION,
78
+ alreadyInstalled: true,
79
+ source: found.source,
80
+ };
81
+ }
82
+ }
83
+ const nodeFlags = opts.nodeFlags ?? process.allowedNodeEnvironmentFlags;
84
+ const nextStep = `Retry with \`npx -p @juxtapose/cli jux browser install\`, or download ${pin.url} yourself and set JUX_CHROME to the chrome-headless-shell binary inside it.`;
85
+ const doFetch = opts.fetch ?? fetch;
86
+ let res;
87
+ try {
88
+ res = await doFetch(pin.url);
89
+ }
90
+ catch (err) {
91
+ throw new Error(`jux: download failed for ${pin.url}: ${err.message}.${proxyHint(env, nodeFlags)} ${nextStep}`, { cause: err });
92
+ }
93
+ if (!res.ok || !res.body)
94
+ throw new Error(`jux: download failed: HTTP ${res.status} for ${pin.url}. ${nextStep}`);
95
+ const total = Number(res.headers.get('content-length')) || null;
96
+ // Streamed into the hash and a chunk list: ~120 MB held once, not twice.
97
+ const chunks = [];
98
+ let received = 0;
99
+ let overLength = false;
100
+ const hash = createHash('sha256');
101
+ try {
102
+ for await (const chunk of res.body) {
103
+ const b = Buffer.from(chunk);
104
+ received += b.length;
105
+ // A server streaming past the pinned size is wrong already; stop buffering.
106
+ if (received > pin.bytes) {
107
+ overLength = true;
108
+ break;
109
+ }
110
+ chunks.push(b);
111
+ hash.update(b);
112
+ opts.onProgress?.(received, total);
113
+ }
114
+ }
115
+ catch (err) {
116
+ throw new Error(`jux: download interrupted for ${pin.url}: ${err.message}.${proxyHint(env, nodeFlags)} ${nextStep}`, { cause: err });
117
+ }
118
+ const digest = hash.digest('hex');
119
+ if (!overLength && digest !== pin.sha256) {
120
+ throw new Error(`jux: sha256 mismatch for ${pin.url}: expected ${pin.sha256}, got ${digest}. ` +
121
+ `The download is corrupt or the published file changed; nothing was installed. ${nextStep}`);
122
+ }
123
+ if (overLength || received !== pin.bytes) {
124
+ throw new Error(`jux: length mismatch for ${pin.url}: expected ${pin.bytes} bytes, got ${overLength ? `more than ${pin.bytes}` : received} bytes. ` +
125
+ `The download is truncated or the published file changed; nothing was installed. ${nextStep}`);
126
+ }
127
+ await (opts.installZip ?? installZip)(Buffer.concat(chunks), installDir, {
128
+ marker: INSTALL_MARKER,
129
+ });
130
+ await verifyInstall(installDir, binary);
131
+ return { path: binary, version: CHROME_VERSION, alreadyInstalled: false };
132
+ }
133
+ /**
134
+ * installZip resolves when a concurrent installer "won" the swap, which can
135
+ * also mask a permission error. Trust only what is on disk and runs.
136
+ */
137
+ async function verifyInstall(installDir, binary) {
138
+ const fail = async (why) => {
139
+ // Also removes a concurrent installer's dir when that one is the broken one: it is unusable either way.
140
+ await rm(installDir, { recursive: true, force: true });
141
+ throw new Error(`jux: install of chrome-headless-shell ${CHROME_VERSION} into ${installDir} is not usable: ${why}. ` +
142
+ 'Check permissions on the cache directory (JUX_CACHE_DIR) and retry.');
143
+ };
144
+ if (!(await exists(path.join(installDir, INSTALL_MARKER))))
145
+ return fail(`${INSTALL_MARKER} marker is missing`);
146
+ if (!(await exists(binary)))
147
+ return fail(`${binary} is missing`);
148
+ let out;
149
+ try {
150
+ out = await new Promise((resolve, reject) => execFile(binary, ['--version'], { timeout: 15_000 }, (err, stdout) => err ? reject(err) : resolve(stdout)));
151
+ }
152
+ catch (err) {
153
+ return fail(`\`${binary} --version\` failed: ${err.message}`);
154
+ }
155
+ if (!out.includes(CHROME_VERSION))
156
+ return fail(`\`--version\` printed ${JSON.stringify(out.trim())}, expected ${CHROME_VERSION}`);
157
+ }
158
+ async function exists(p) {
159
+ try {
160
+ await stat(p);
161
+ return true;
162
+ }
163
+ catch {
164
+ return false;
165
+ }
166
+ }
167
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/browser/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { spawn as nodeSpawn } from 'node:child_process';
2
+ import { CdpConnection } from './cdp.js';
3
+ export type SpawnFn = typeof nodeSpawn;
4
+ export interface LaunchedChrome {
5
+ connection: CdpConnection;
6
+ pid: number;
7
+ userDataDir: string;
8
+ close(): Promise<void>;
9
+ }
10
+ /** Kill every live Chrome and remove its profile, synchronously. Exported for tests. */
11
+ export declare function terminateAll(): void;
12
+ /**
13
+ * Remove profiles left by a jux that was SIGKILLed or lost power: named
14
+ * `jux-chrome-<pid>-…`, owner pid dead, untouched for 10 minutes. Anything
15
+ * else in the directory is not ours to touch.
16
+ */
17
+ export declare function sweepStaleProfiles(dir: string): Promise<void>;
18
+ /**
19
+ * The per-user directory every profile lives in. A shared tmpdir lets another
20
+ * user plant `jux-chrome-<dead pid>-x` (or swap one under us) and have our
21
+ * sweep delete through it, so profiles and the sweep stay inside a directory
22
+ * only we can write. Verified with lstat, never chmod/chown'd: a dir that is
23
+ * not ours is refused, not repaired. Windows has no uid; its tmpdir is already
24
+ * per-user.
25
+ */
26
+ export declare function privateProfileRoot(opts?: {
27
+ base?: string;
28
+ uid?: number | undefined;
29
+ }): Promise<string>;
30
+ export declare function launchChrome(opts: {
31
+ executablePath: string;
32
+ args?: string[];
33
+ headless?: boolean;
34
+ spawn?: SpawnFn;
35
+ /** Test seam: how long to wait for Browser.getVersion before giving up. */
36
+ handshakeTimeoutMs?: number;
37
+ }): Promise<LaunchedChrome>;