veryfront 0.1.757 → 0.1.758
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/esm/deno.js +1 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +22 -2
- package/esm/src/agent/streaming/tool-execution-data-event-bridge.d.ts.map +1 -1
- package/esm/src/agent/streaming/tool-execution-data-event-bridge.js +11 -1
- package/esm/src/platform/compat/process/env.d.ts.map +1 -1
- package/esm/src/platform/compat/process/env.js +13 -2
- package/esm/src/security/sandbox/worker-egress-guard.d.ts +20 -0
- package/esm/src/security/sandbox/worker-egress-guard.d.ts.map +1 -1
- package/esm/src/security/sandbox/worker-egress-guard.js +115 -2
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +19 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -206,6 +206,13 @@ export class AgentRuntime {
|
|
|
206
206
|
platform: detectPlatform(),
|
|
207
207
|
};
|
|
208
208
|
const chain = new MiddlewareChain(this.config.middleware);
|
|
209
|
+
// Hold the in-flight agent-loop promise so stream cancellation can detach a
|
|
210
|
+
// no-op rejection handler. When the client cancels, we abort the shared
|
|
211
|
+
// signal; the loop (model fetch / tool execution) then rejects with an
|
|
212
|
+
// AbortError. The `start` body awaits it, but cancellation can land after
|
|
213
|
+
// that await settles, leaving the rejection without a consumer — fatal as
|
|
214
|
+
// an unhandled rejection under Deno (#2334).
|
|
215
|
+
let inFlight;
|
|
209
216
|
return new ReadableStream({
|
|
210
217
|
start: async (controller) => {
|
|
211
218
|
try {
|
|
@@ -226,7 +233,8 @@ export class AgentRuntime {
|
|
|
226
233
|
model: effectiveModel,
|
|
227
234
|
},
|
|
228
235
|
});
|
|
229
|
-
|
|
236
|
+
inFlight = chain.execute(agentContext, () => this.executeAgentLoopStreaming(systemPrompt, memoryMessages, controller, encoder, callbacks, textPartId, toolContext, context, resolvedModelString, languageModel, transport.headers, transport.providerOptions, maxOutputTokensOverride, streamAbortSignal, requestedModel));
|
|
237
|
+
const response = await inFlight;
|
|
230
238
|
throwIfAborted(streamAbortSignal);
|
|
231
239
|
callbacks?.onFinish?.(response);
|
|
232
240
|
throwIfAborted(streamAbortSignal);
|
|
@@ -251,7 +259,19 @@ export class AgentRuntime {
|
|
|
251
259
|
}
|
|
252
260
|
},
|
|
253
261
|
cancel(reason) {
|
|
254
|
-
|
|
262
|
+
// The client disconnected (e.g. the Chat Stop button). Treat this as a
|
|
263
|
+
// clean stop: detach a no-op handler from the in-flight loop so the
|
|
264
|
+
// AbortError it throws when we abort the shared signal cannot surface as
|
|
265
|
+
// an unhandled rejection, then abort. Guard the abort itself so a
|
|
266
|
+
// synchronous signal-abort rejection can never escape here (#2334).
|
|
267
|
+
inFlight?.catch(() => { });
|
|
268
|
+
try {
|
|
269
|
+
streamAbortController.abort(reason);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Aborting an already-aborted controller, or a synchronous reject
|
|
273
|
+
// from a signal consumer, is a no-op for cancellation purposes.
|
|
274
|
+
}
|
|
255
275
|
},
|
|
256
276
|
});
|
|
257
277
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-execution-data-event-bridge.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/streaming/tool-execution-data-event-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,mEAAmE;AACnE,MAAM,MAAM,+BAA+B,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAEtF,iEAAiE;AACjE,MAAM,MAAM,uCAAuC,GAAG;IACpD,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC;CACtE,CAAC;AA6BF,sDAAsD;AACtD,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,uCAAuC,GAC7C,cAAc,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"tool-execution-data-event-bridge.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/streaming/tool-execution-data-event-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,mEAAmE;AACnE,MAAM,MAAM,+BAA+B,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAEtF,iEAAiE;AACjE,MAAM,MAAM,uCAAuC,GAAG;IACpD,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC;CACtE,CAAC;AA6BF,sDAAsD;AACtD,wBAAgB,wCAAwC,CACtD,KAAK,EAAE,uCAAuC,GAC7C,cAAc,CAAC,UAAU,CAAC,CAwD5B"}
|
|
@@ -57,7 +57,17 @@ export function createToolExecutionDataEventBridgeStream(input) {
|
|
|
57
57
|
})();
|
|
58
58
|
},
|
|
59
59
|
async cancel(reason) {
|
|
60
|
-
|
|
60
|
+
// Cancellation is best-effort teardown (the client disconnected / hit
|
|
61
|
+
// Stop). Forwarding the cancel to the base reader can reject — e.g. the
|
|
62
|
+
// upstream agent runtime aborts an in-flight signal whose rejection
|
|
63
|
+
// surfaces through the cancel chain. Swallow it so it does not escape as
|
|
64
|
+
// an unhandled rejection, which is fatal under Deno (#2334).
|
|
65
|
+
try {
|
|
66
|
+
await baseReader?.cancel(reason);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Stream is being torn down; a failed cancel is a clean stop here.
|
|
70
|
+
}
|
|
61
71
|
},
|
|
62
72
|
});
|
|
63
73
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/compat/process/env.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC,CAAC;AAoBF,oDAAoD;AACpD,wBAAgB,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB5C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../../src/src/platform/compat/process/env.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,OAAO,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC,CAAC;AAoBF,oDAAoD;AACpD,wBAAgB,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB5C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoB1D;AAqCD,kEAAkE;AAClE,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWtD;AAKD,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAUD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;AAOpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;AAUpE,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,UAAQ,EAChB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAmBT;AAED,gBAAgB;AAChB,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAgBvD;AAED,6CAA6C;AAC7C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAgB3C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,GAAG,IAAI,CAS/D"}
|
|
@@ -41,8 +41,19 @@ export function getHostEnv(key) {
|
|
|
41
41
|
if (overlayResult.hasValue) {
|
|
42
42
|
return overlayResult.value;
|
|
43
43
|
}
|
|
44
|
-
if (IS_DENO)
|
|
45
|
-
|
|
44
|
+
if (IS_DENO) {
|
|
45
|
+
try {
|
|
46
|
+
return dntShim.Deno.env.get(key);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Under a tightened env permission allowlist (project isolation workers),
|
|
50
|
+
// reading a non-allowlisted variable throws NotCapable. Treat it as absent
|
|
51
|
+
// to match the prior `env: true` behavior where reads never threw, so
|
|
52
|
+
// optional-variable lookups degrade to undefined instead of crashing the
|
|
53
|
+
// request.
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
46
57
|
if (runtimeProcess)
|
|
47
58
|
return runtimeProcess.env[key];
|
|
48
59
|
return undefined;
|
|
@@ -11,5 +11,25 @@ export declare function isInternalEgressOverrideEnabled(value: string | undefine
|
|
|
11
11
|
export declare function isInternalEgressIp(address: string): boolean;
|
|
12
12
|
export declare function assertWorkerEgressAllowed(target: string | URL | Request, options?: WorkerEgressGuardOptions): Promise<void>;
|
|
13
13
|
export declare function assertWorkerHostEgressAllowed(hostname: string, options?: WorkerEgressGuardOptions): Promise<void>;
|
|
14
|
+
/** Dependencies for {@link guardedEgressFetch} (injectable for tests). */
|
|
15
|
+
export interface GuardedEgressFetchDeps {
|
|
16
|
+
/** Underlying fetch implementation (defaults to the global `fetch`). */
|
|
17
|
+
fetchImpl?: typeof fetch;
|
|
18
|
+
/** Egress options applied to the initial URL and every redirect hop. */
|
|
19
|
+
options?: WorkerEgressGuardOptions;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Egress-checked fetch that re-validates EVERY redirect hop.
|
|
23
|
+
*
|
|
24
|
+
* The platform `fetch` follows 3xx redirects transparently, so checking only the
|
|
25
|
+
* initial URL lets a public host redirect to an internal address (loopback,
|
|
26
|
+
* RFC1918, link-local, cloud metadata) that the guard never sees. This forces
|
|
27
|
+
* `redirect: "manual"` on the underlying fetch and re-runs the egress check on
|
|
28
|
+
* each `Location` before following it. The caller's redirect intent is honored:
|
|
29
|
+
* `manual` returns the redirect unfollowed, `error` throws, `follow` (default)
|
|
30
|
+
* follows manually after re-checking. Credential headers are stripped on a
|
|
31
|
+
* cross-origin hop, matching the platform fetch the guard wraps.
|
|
32
|
+
*/
|
|
33
|
+
export declare function guardedEgressFetch(input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1], deps?: GuardedEgressFetchDeps): Promise<Response>;
|
|
14
34
|
export declare function installWorkerEgressGuard(options?: WorkerEgressGuardOptions): void;
|
|
15
35
|
//# sourceMappingURL=worker-egress-guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-egress-guard.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-egress-guard.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,mCAAmC,2CAA2C,CAAC;AAE5F,qBAAa,wBAAyB,SAAQ,KAAK;IACxC,IAAI,SAA8B;CAC5C;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWlF;AAuDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK3D;AA4CD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC9B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CA0Bf;
|
|
1
|
+
{"version":3,"file":"worker-egress-guard.d.ts","sourceRoot":"","sources":["../../../../src/src/security/sandbox/worker-egress-guard.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,mCAAmC,2CAA2C,CAAC;AAE5F,qBAAa,wBAAyB,SAAQ,KAAK;IACxC,IAAI,SAA8B;CAC5C;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAWlF;AAuDD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK3D;AA4CD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,EAC9B,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAmBD,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,wEAAwE;IACxE,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACpC;AASD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAClC,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAClC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,QAAQ,CAAC,CAqGnB;AAED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,wBAA6B,GAAG,IAAI,CAmDrF"}
|
|
@@ -160,6 +160,115 @@ function getAllowInternalEgress() {
|
|
|
160
160
|
return false;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
164
|
+
const MAX_EGRESS_REDIRECTS = 20;
|
|
165
|
+
/** A request body that can be safely replayed across a body-preserving redirect. */
|
|
166
|
+
function isReplayableBody(body) {
|
|
167
|
+
return body == null || typeof body === "string" ||
|
|
168
|
+
body instanceof Uint8Array || body instanceof ArrayBuffer ||
|
|
169
|
+
body instanceof URLSearchParams;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Egress-checked fetch that re-validates EVERY redirect hop.
|
|
173
|
+
*
|
|
174
|
+
* The platform `fetch` follows 3xx redirects transparently, so checking only the
|
|
175
|
+
* initial URL lets a public host redirect to an internal address (loopback,
|
|
176
|
+
* RFC1918, link-local, cloud metadata) that the guard never sees. This forces
|
|
177
|
+
* `redirect: "manual"` on the underlying fetch and re-runs the egress check on
|
|
178
|
+
* each `Location` before following it. The caller's redirect intent is honored:
|
|
179
|
+
* `manual` returns the redirect unfollowed, `error` throws, `follow` (default)
|
|
180
|
+
* follows manually after re-checking. Credential headers are stripped on a
|
|
181
|
+
* cross-origin hop, matching the platform fetch the guard wraps.
|
|
182
|
+
*/
|
|
183
|
+
export async function guardedEgressFetch(input, init, deps = {}) {
|
|
184
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
185
|
+
const options = deps.options ?? {};
|
|
186
|
+
const requestedRedirect = init?.redirect ??
|
|
187
|
+
(input instanceof Request ? input.redirect : "follow");
|
|
188
|
+
let url = input instanceof Request
|
|
189
|
+
? input.url
|
|
190
|
+
: input instanceof URL
|
|
191
|
+
? input.href
|
|
192
|
+
: String(input);
|
|
193
|
+
let method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
194
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
195
|
+
let body;
|
|
196
|
+
if (init?.body != null) {
|
|
197
|
+
body = init.body;
|
|
198
|
+
}
|
|
199
|
+
else if (input instanceof Request && input.body) {
|
|
200
|
+
body = new Uint8Array(await input.arrayBuffer());
|
|
201
|
+
}
|
|
202
|
+
// Preserve request-level options (notably `signal`, so aborts keep working)
|
|
203
|
+
// that would otherwise be dropped when the caller passes a Request object
|
|
204
|
+
// rather than an init bag, and that must persist across every redirect hop.
|
|
205
|
+
const reqInput = input instanceof Request ? input : undefined;
|
|
206
|
+
const carryInit = {
|
|
207
|
+
signal: init?.signal ?? reqInput?.signal,
|
|
208
|
+
credentials: init?.credentials ?? reqInput?.credentials,
|
|
209
|
+
cache: init?.cache ?? reqInput?.cache,
|
|
210
|
+
mode: init?.mode ?? reqInput?.mode,
|
|
211
|
+
referrer: init?.referrer ?? reqInput?.referrer,
|
|
212
|
+
referrerPolicy: init?.referrerPolicy ?? reqInput?.referrerPolicy,
|
|
213
|
+
keepalive: init?.keepalive ?? reqInput?.keepalive,
|
|
214
|
+
};
|
|
215
|
+
for (let hop = 0;; hop++) {
|
|
216
|
+
await assertWorkerEgressAllowed(url, options);
|
|
217
|
+
const response = await doFetch(url, {
|
|
218
|
+
...init,
|
|
219
|
+
...carryInit,
|
|
220
|
+
method,
|
|
221
|
+
headers,
|
|
222
|
+
body,
|
|
223
|
+
redirect: "manual",
|
|
224
|
+
});
|
|
225
|
+
if (!REDIRECT_STATUSES.has(response.status))
|
|
226
|
+
return response;
|
|
227
|
+
const location = response.headers.get("location");
|
|
228
|
+
if (!location)
|
|
229
|
+
return response;
|
|
230
|
+
if (requestedRedirect === "manual")
|
|
231
|
+
return response;
|
|
232
|
+
if (requestedRedirect === "error") {
|
|
233
|
+
throw new WorkerEgressBlockedError("Worker egress: unexpected redirect with redirect mode 'error'");
|
|
234
|
+
}
|
|
235
|
+
if (hop >= MAX_EGRESS_REDIRECTS) {
|
|
236
|
+
throw new WorkerEgressBlockedError("Worker network egress blocked: exceeded maximum redirect count");
|
|
237
|
+
}
|
|
238
|
+
const nextUrl = new URL(location, url);
|
|
239
|
+
// Only follow redirects to http(s). The platform fetch treats a redirect to
|
|
240
|
+
// any other scheme as a network error; following e.g. file:// here would let
|
|
241
|
+
// an attacker-controlled redirect turn a network fetch into a local file
|
|
242
|
+
// read, since assertWorkerEgressAllowed no-ops for hostless (non-network)
|
|
243
|
+
// URLs.
|
|
244
|
+
if (nextUrl.protocol !== "http:" && nextUrl.protocol !== "https:") {
|
|
245
|
+
throw new WorkerEgressBlockedError(`Worker network egress blocked: redirect to non-http(s) scheme ${nextUrl.protocol}`);
|
|
246
|
+
}
|
|
247
|
+
// Cross-origin redirect: strip credential-bearing headers, matching the
|
|
248
|
+
// platform fetch this guard replaces, so a redirect target cannot receive
|
|
249
|
+
// the caller's Authorization/Cookie.
|
|
250
|
+
if (nextUrl.origin !== new URL(url).origin) {
|
|
251
|
+
headers.delete("authorization");
|
|
252
|
+
headers.delete("cookie");
|
|
253
|
+
headers.delete("proxy-authorization");
|
|
254
|
+
}
|
|
255
|
+
url = nextUrl.href;
|
|
256
|
+
// Standard fetch redirect method/body rules: 303, and 301/302 for a
|
|
257
|
+
// non-GET/HEAD method, downgrade to GET and drop the body; 307/308 preserve.
|
|
258
|
+
const downgrades = response.status === 303 ||
|
|
259
|
+
((response.status === 301 || response.status === 302) &&
|
|
260
|
+
method !== "GET" && method !== "HEAD");
|
|
261
|
+
if (downgrades) {
|
|
262
|
+
method = "GET";
|
|
263
|
+
body = undefined;
|
|
264
|
+
headers.delete("content-length");
|
|
265
|
+
headers.delete("content-type");
|
|
266
|
+
}
|
|
267
|
+
else if (!isReplayableBody(body)) {
|
|
268
|
+
throw new WorkerEgressBlockedError("Worker network egress blocked: cannot safely follow a body-preserving redirect");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
163
272
|
export function installWorkerEgressGuard(options = {}) {
|
|
164
273
|
const globalRecord = dntShim.dntGlobalThis;
|
|
165
274
|
if (globalRecord[guardInstalled])
|
|
@@ -170,8 +279,12 @@ export function installWorkerEgressGuard(options = {}) {
|
|
|
170
279
|
};
|
|
171
280
|
const originalFetch = globalThis.fetch.bind(dntShim.dntGlobalThis);
|
|
172
281
|
const fetchWrapper = async (input, init) => {
|
|
173
|
-
|
|
174
|
-
|
|
282
|
+
// guardedEgressFetch checks the initial URL and re-checks every redirect hop,
|
|
283
|
+
// so a public host cannot redirect into an internal address.
|
|
284
|
+
return await guardedEgressFetch(input, init, {
|
|
285
|
+
fetchImpl: originalFetch,
|
|
286
|
+
options: baseOptions,
|
|
287
|
+
});
|
|
175
288
|
};
|
|
176
289
|
Object.defineProperty(fetchWrapper, guardedFetch, { value: true });
|
|
177
290
|
globalThis.fetch = fetchWrapper;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAI5D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAK9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA6IH,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAuBD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,SAAwB,GACnC,IAAI,CAgBN;AAOD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAevD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAmBD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,oDAAoD;AAC3E,eAAe,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAChE,YAAY,SAAwB,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA+J5B"}
|
|
@@ -18,9 +18,26 @@ import { ensureMdxModuleDependencies } from "../module-fetcher/dependency-recove
|
|
|
18
18
|
export { getLocalFs } from "./local-fs.js";
|
|
19
19
|
import { getLocalFs } from "./local-fs.js";
|
|
20
20
|
const MAX_VERIFIED_MODULE_DEPS = 2_000;
|
|
21
|
+
const MAX_MODULE_PATH_CACHE_ENTRIES = 500;
|
|
21
22
|
export const verifiedModuleDeps = new LRUCache({
|
|
22
23
|
maxEntries: MAX_VERIFIED_MODULE_DEPS,
|
|
23
24
|
});
|
|
25
|
+
class BoundedModulePathCache extends Map {
|
|
26
|
+
maxEntries;
|
|
27
|
+
constructor(maxEntries) {
|
|
28
|
+
super();
|
|
29
|
+
this.maxEntries = maxEntries;
|
|
30
|
+
}
|
|
31
|
+
set(key, value) {
|
|
32
|
+
if (!this.has(key) && this.size >= this.maxEntries) {
|
|
33
|
+
const oldestKey = this.keys().next().value;
|
|
34
|
+
if (oldestKey !== undefined) {
|
|
35
|
+
this.delete(oldestKey);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return super.set(key, value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
/**
|
|
25
42
|
* Check if cached code has file:// paths from a different environment.
|
|
26
43
|
* Checks both HTTP bundle paths and MDX ESM cache paths.
|
|
@@ -125,6 +142,7 @@ function getModulePathCacheEntryCount() {
|
|
|
125
142
|
registerCache("mdx-esm-path-caches", () => ({
|
|
126
143
|
name: "mdx-esm-path-caches",
|
|
127
144
|
entries: getModulePathCacheEntryCount(),
|
|
145
|
+
maxEntries: MAX_MODULE_PATH_CACHE_ENTRIES * Math.max(1, modulePathCaches.size),
|
|
128
146
|
cacheDirs: modulePathCaches.size,
|
|
129
147
|
}));
|
|
130
148
|
registerCache("mdx-esm-verified-deps", () => ({
|
|
@@ -136,7 +154,7 @@ export async function getModulePathCache(cacheDir) {
|
|
|
136
154
|
const existing = modulePathCaches.get(cacheDir);
|
|
137
155
|
if (existing && modulePathCacheLoaded.has(cacheDir))
|
|
138
156
|
return existing;
|
|
139
|
-
const cache = existing ?? new
|
|
157
|
+
const cache = existing ?? new BoundedModulePathCache(MAX_MODULE_PATH_CACHE_ENTRIES);
|
|
140
158
|
modulePathCaches.set(cacheDir, cache);
|
|
141
159
|
const indexPath = join(cacheDir, "_index.json");
|
|
142
160
|
try {
|