@mochi.js/core 0.3.0 → 0.6.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 +19 -10
- package/package.json +4 -4
- package/src/__tests__/cookies-jar.test.ts +361 -0
- package/src/__tests__/default-profile.test.ts +181 -0
- package/src/__tests__/dx-cluster.e2e.test.ts +245 -0
- package/src/__tests__/init-injector.e2e.test.ts +144 -0
- package/src/__tests__/init-injector.test.ts +249 -0
- package/src/__tests__/inject.test.ts +80 -164
- package/src/__tests__/page-dx-cluster.test.ts +292 -0
- package/src/__tests__/proc-linux-server.test.ts +243 -0
- package/src/__tests__/proxy-auth.test.ts +22 -55
- package/src/__tests__/screenshot.e2e.test.ts +126 -0
- package/src/__tests__/screenshot.test.ts +363 -0
- package/src/cdp/init-injector.ts +644 -0
- package/src/default-profile.ts +112 -0
- package/src/index.ts +33 -1
- package/src/launch.ts +199 -10
- package/src/linux-server.ts +157 -0
- package/src/page.ts +410 -8
- package/src/proc.ts +48 -5
- package/src/proxy-auth.ts +26 -107
- package/src/session.ts +367 -68
package/src/proxy-auth.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Proxy
|
|
2
|
+
* Proxy URL parsing helpers + (legacy) `Fetch.authRequired` installer.
|
|
3
3
|
*
|
|
4
4
|
* Background
|
|
5
5
|
* ----------
|
|
@@ -11,16 +11,14 @@
|
|
|
11
11
|
* weirdness, observable extension ids) and so is forbidden by mochi's
|
|
12
12
|
* stealth invariants.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* separately fire `Fetch.authRequired`; we answer those with
|
|
23
|
-
* `Fetch.continueWithAuth` carrying the parsed credentials.
|
|
14
|
+
* Task 0266 unifies proxy auth + init-script delivery under a single
|
|
15
|
+
* `Fetch.enable` call (see {@link installInitInjector} in
|
|
16
|
+
* `cdp/init-injector.ts`). `Session` now installs ONE Fetch handler that
|
|
17
|
+
* owns BOTH the document-body splice (for the inject payload) AND
|
|
18
|
+
* `Fetch.authRequired` answering (when proxy creds are present). The
|
|
19
|
+
* legacy {@link installProxyAuth} export below is preserved as a thin
|
|
20
|
+
* delegating wrapper for any out-of-tree caller still wiring it directly,
|
|
21
|
+
* but the session no longer uses it.
|
|
24
22
|
*
|
|
25
23
|
* PLAN.md §8.2 invariant check
|
|
26
24
|
* ----------------------------
|
|
@@ -30,11 +28,7 @@
|
|
|
30
28
|
* isolated world) are forbidden. `Fetch.enable` operates at the network
|
|
31
29
|
* layer below page script — it does not produce execution-context-creation
|
|
32
30
|
* events, does not surface a `chrome.devtools` global, and is not
|
|
33
|
-
* detectable from page JavaScript.
|
|
34
|
-
* every request pauses for one CDP round-trip before continuing — that's
|
|
35
|
-
* a measurable but bounded overhead (sub-ms per request on modern
|
|
36
|
-
* hardware) and only active on sessions with proxy auth credentials
|
|
37
|
-
* (the function early-returns when `auth` is undefined).
|
|
31
|
+
* detectable from page JavaScript.
|
|
38
32
|
*
|
|
39
33
|
* Protocols
|
|
40
34
|
* ---------
|
|
@@ -46,9 +40,11 @@
|
|
|
46
40
|
*
|
|
47
41
|
* @see PLAN.md §8.2 / §10
|
|
48
42
|
* @see tasks/0160-proxy-auth-and-ci-fix.md
|
|
43
|
+
* @see tasks/0266-fetch-fulfill-init-script.md
|
|
49
44
|
*/
|
|
50
45
|
|
|
51
|
-
import
|
|
46
|
+
import { installInitInjector } from "./cdp/init-injector";
|
|
47
|
+
import type { MessageRouter } from "./cdp/router";
|
|
52
48
|
|
|
53
49
|
/** Parsed proxy URL — what `parseProxyUrl` returns. */
|
|
54
50
|
export interface ParsedProxy {
|
|
@@ -148,105 +144,28 @@ export interface ProxyAuthHandle {
|
|
|
148
144
|
}
|
|
149
145
|
|
|
150
146
|
/**
|
|
151
|
-
* Wire proxy-auth handling into a {@link MessageRouter}.
|
|
152
|
-
*
|
|
153
|
-
*
|
|
147
|
+
* Wire proxy-auth handling into a {@link MessageRouter}. Thin compatibility
|
|
148
|
+
* shim — delegates to {@link installInitInjector} with `payloadCode: null`
|
|
149
|
+
* so the proxy-auth-only call path still works for any out-of-tree caller.
|
|
154
150
|
*
|
|
155
|
-
*
|
|
151
|
+
* The Session no longer uses this directly (task 0266); proxy auth and
|
|
152
|
+
* init-script delivery share a single `Fetch.enable` owner.
|
|
153
|
+
*
|
|
154
|
+
* Behavior (unchanged contract):
|
|
156
155
|
* - Sends `Fetch.enable { handleAuthRequests: true, patterns: [{
|
|
157
|
-
* urlPattern: "*" }] }
|
|
156
|
+
* urlPattern: "*", resourceType: "Document" }, { urlPattern: "*" }] }`.
|
|
158
157
|
* - On `Fetch.authRequired`, replies with `Fetch.continueWithAuth` and
|
|
159
158
|
* the parsed creds.
|
|
160
159
|
* - On `Fetch.requestPaused`, forwards `Fetch.continueRequest`
|
|
161
|
-
* immediately
|
|
162
|
-
* still flows; we just take one CDP round-trip to wave it through).
|
|
160
|
+
* immediately (no body splice when `payloadCode` is null).
|
|
163
161
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* with `-32602 Can't specify empty patterns with handleAuth set`. The
|
|
167
|
-
* wildcard plus an immediate-continue handler is the equivalent of
|
|
168
|
-
* "auth-only interception" with one extra round-trip per request — only
|
|
169
|
-
* active on proxy-authed sessions.
|
|
162
|
+
* @deprecated Prefer {@link installInitInjector} directly. This wrapper is
|
|
163
|
+
* preserved only for backward compatibility.
|
|
170
164
|
*/
|
|
171
165
|
export async function installProxyAuth(
|
|
172
166
|
router: MessageRouter,
|
|
173
167
|
auth: { username: string; password: string },
|
|
174
168
|
): Promise<ProxyAuthHandle> {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const offAuth: Unsubscribe = router.on("Fetch.authRequired", (params) => {
|
|
178
|
-
const requestId = (params as { requestId?: string } | null)?.requestId;
|
|
179
|
-
if (typeof requestId !== "string") return;
|
|
180
|
-
// Fire-and-forget — failures here are non-fatal (the request will
|
|
181
|
-
// simply 407 and the page-level fetch will see it). We log on
|
|
182
|
-
// unexpected errors so users can diagnose creds issues.
|
|
183
|
-
router
|
|
184
|
-
.send("Fetch.continueWithAuth", {
|
|
185
|
-
requestId,
|
|
186
|
-
authChallengeResponse: {
|
|
187
|
-
response: "ProvideCredentials",
|
|
188
|
-
username: auth.username,
|
|
189
|
-
password: auth.password,
|
|
190
|
-
},
|
|
191
|
-
})
|
|
192
|
-
.catch((err: unknown) => {
|
|
193
|
-
if (!isClosedError(err)) {
|
|
194
|
-
console.warn("[mochi] Fetch.continueWithAuth failed:", err);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Pattern is REQUIRED with handleAuthRequests: true. Modern Chromium
|
|
200
|
-
// rejects an empty `patterns` array with `-32602 Can't specify empty
|
|
201
|
-
// patterns with handleAuth set` (verified on CfT linux ~2026-05). Use
|
|
202
|
-
// a wildcard pattern so every request paus es, then immediately
|
|
203
|
-
// forward in the requestPaused handler below — that gets us auth
|
|
204
|
-
// challenge interception without altering the user-visible network
|
|
205
|
-
// model. The per-request CDP round-trip is real overhead but only
|
|
206
|
-
// active when the session has proxy auth credentials (this whole
|
|
207
|
-
// function early-returns when `auth` is undefined), so non-proxied
|
|
208
|
-
// sessions pay zero cost.
|
|
209
|
-
const offPaused: Unsubscribe = router.on("Fetch.requestPaused", (params) => {
|
|
210
|
-
const requestId = (params as { requestId?: string } | null)?.requestId;
|
|
211
|
-
if (typeof requestId !== "string") return;
|
|
212
|
-
router.send("Fetch.continueRequest", { requestId }).catch((err: unknown) => {
|
|
213
|
-
if (!isClosedError(err)) {
|
|
214
|
-
console.warn("[mochi] Fetch.continueRequest failed:", err);
|
|
215
|
-
}
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
await router.send("Fetch.enable", {
|
|
220
|
-
handleAuthRequests: true,
|
|
221
|
-
patterns: [{ urlPattern: "*" }],
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
let disposed = false;
|
|
225
|
-
return {
|
|
226
|
-
async dispose(): Promise<void> {
|
|
227
|
-
if (disposed) return;
|
|
228
|
-
disposed = true;
|
|
229
|
-
offAuth();
|
|
230
|
-
offPaused();
|
|
231
|
-
try {
|
|
232
|
-
await router.send("Fetch.disable");
|
|
233
|
-
} catch (err) {
|
|
234
|
-
// Closed-pipe failures are expected during session teardown.
|
|
235
|
-
if (!isClosedError(err)) {
|
|
236
|
-
console.warn("[mochi] Fetch.disable failed:", err);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/** True when an error reflects the transport already being closed. */
|
|
244
|
-
function isClosedError(err: unknown): boolean {
|
|
245
|
-
if (err instanceof Error) {
|
|
246
|
-
return (
|
|
247
|
-
err.name === "BrowserCrashedError" ||
|
|
248
|
-
/transport already closed|pipe closed|browser process exited/i.test(err.message)
|
|
249
|
-
);
|
|
250
|
-
}
|
|
251
|
-
return false;
|
|
169
|
+
const handle = await installInitInjector(router, { payloadCode: null, auth });
|
|
170
|
+
return handle;
|
|
252
171
|
}
|