@volter/tabnode 0.5.47 → 0.5.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{runtime-worker-4iI8R3l-.js → runtime-worker-C1IV4qnr.js} +284 -16
- package/dist/fetch-transport.d.ts +0 -1
- package/dist/index.mjs +288 -20
- package/dist/node-body.d.ts +9 -0
- package/dist/node-response.d.ts +8 -0
- package/package.json +1 -1
- package/src/fetch-transport.ts +7 -3
- package/src/node-body.ts +88 -0
- package/src/node-response.ts +160 -0
- package/src/runtime.ts +10 -0
- package/src/shims/child_process.ts +49 -6
- package/src/shims/shell-jobs.ts +72 -0
package/dist/index.mjs
CHANGED
|
@@ -5132,7 +5132,7 @@ function parse$1(urlString, parseQueryString = false, slashesDenoteHost = false)
|
|
|
5132
5132
|
hostname: null,
|
|
5133
5133
|
hash: __hash,
|
|
5134
5134
|
search: __search,
|
|
5135
|
-
query: parseQueryString ? Object.fromEntries(new URLSearchParams(__search || "")) : __search ? __search.slice(1) : null,
|
|
5135
|
+
query: parseQueryString ? Object.fromEntries(new URLSearchParams$1(__search || "")) : __search ? __search.slice(1) : null,
|
|
5136
5136
|
pathname: __pathname || null,
|
|
5137
5137
|
path: __pathname + (__search || "") || null,
|
|
5138
5138
|
href: urlString
|
|
@@ -5206,7 +5206,7 @@ function format$1(urlObject) {
|
|
|
5206
5206
|
if (typeof urlObject.query === "string") {
|
|
5207
5207
|
result += "?" + urlObject.query;
|
|
5208
5208
|
} else {
|
|
5209
|
-
const params = new URLSearchParams();
|
|
5209
|
+
const params = new URLSearchParams$1();
|
|
5210
5210
|
for (const [key, value] of Object.entries(urlObject.query)) {
|
|
5211
5211
|
if (Array.isArray(value)) {
|
|
5212
5212
|
for (const v of value) {
|
|
@@ -5235,7 +5235,7 @@ function resolve$2(from, to) {
|
|
|
5235
5235
|
}
|
|
5236
5236
|
}
|
|
5237
5237
|
const URL$1 = globalThis.URL;
|
|
5238
|
-
const URLSearchParams = globalThis.URLSearchParams;
|
|
5238
|
+
const URLSearchParams$1 = globalThis.URLSearchParams;
|
|
5239
5239
|
function fileURLToPath(url2) {
|
|
5240
5240
|
const urlObj = typeof url2 === "string" ? new globalThis.URL(url2) : url2;
|
|
5241
5241
|
if (urlObj.protocol !== "file:") {
|
|
@@ -5258,7 +5258,7 @@ const url$1 = {
|
|
|
5258
5258
|
format: format$1,
|
|
5259
5259
|
resolve: resolve$2,
|
|
5260
5260
|
URL: URL$1,
|
|
5261
|
-
URLSearchParams,
|
|
5261
|
+
URLSearchParams: URLSearchParams$1,
|
|
5262
5262
|
URLPattern: URLPattern$1,
|
|
5263
5263
|
fileURLToPath,
|
|
5264
5264
|
pathToFileURL
|
|
@@ -5267,7 +5267,7 @@ const urlShim = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePrope
|
|
|
5267
5267
|
__proto__: null,
|
|
5268
5268
|
URL: URL$1,
|
|
5269
5269
|
URLPattern: URLPattern$1,
|
|
5270
|
-
URLSearchParams,
|
|
5270
|
+
URLSearchParams: URLSearchParams$1,
|
|
5271
5271
|
default: url$1,
|
|
5272
5272
|
fileURLToPath,
|
|
5273
5273
|
format: format$1,
|
|
@@ -32424,6 +32424,68 @@ function guestPromise(owner) {
|
|
|
32424
32424
|
}
|
|
32425
32425
|
return constructor;
|
|
32426
32426
|
}
|
|
32427
|
+
const kIsDisturbed = Symbol.for("nodejs.stream.disturbed");
|
|
32428
|
+
function isAsyncIterableBody(body) {
|
|
32429
|
+
if (body === null || typeof body !== "object") return false;
|
|
32430
|
+
if (typeof ReadableStream === "function" && body instanceof ReadableStream) return false;
|
|
32431
|
+
if (typeof Blob === "function" && body instanceof Blob) return false;
|
|
32432
|
+
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return false;
|
|
32433
|
+
if (typeof FormData === "function" && body instanceof FormData) return false;
|
|
32434
|
+
if (body instanceof URLSearchParams) return false;
|
|
32435
|
+
return typeof body[Symbol.asyncIterator] === "function";
|
|
32436
|
+
}
|
|
32437
|
+
function refuseDisturbed(body) {
|
|
32438
|
+
const stream = body;
|
|
32439
|
+
const disturbed = stream[kIsDisturbed] !== void 0 ? Boolean(stream[kIsDisturbed]) : Boolean(stream.readableDidRead || stream.readableAborted);
|
|
32440
|
+
if (disturbed || stream.locked === true) throw new TypeError("Response body object should not be disturbed or locked");
|
|
32441
|
+
}
|
|
32442
|
+
function streamFrom(iterable) {
|
|
32443
|
+
let iterator;
|
|
32444
|
+
return new ReadableStream({
|
|
32445
|
+
async start() {
|
|
32446
|
+
iterator = iterable[Symbol.asyncIterator]();
|
|
32447
|
+
},
|
|
32448
|
+
async pull(controller) {
|
|
32449
|
+
for (; ; ) {
|
|
32450
|
+
const { done, value } = await iterator.next();
|
|
32451
|
+
if (done) {
|
|
32452
|
+
controller.close();
|
|
32453
|
+
return;
|
|
32454
|
+
}
|
|
32455
|
+
const bytes2 = Buffer$9.isBuffer(value) ? value : Buffer$9.from(value);
|
|
32456
|
+
if (bytes2.byteLength) {
|
|
32457
|
+
controller.enqueue(new Uint8Array(bytes2));
|
|
32458
|
+
return;
|
|
32459
|
+
}
|
|
32460
|
+
}
|
|
32461
|
+
},
|
|
32462
|
+
async cancel() {
|
|
32463
|
+
var _a2;
|
|
32464
|
+
await ((_a2 = iterator == null ? void 0 : iterator.return) == null ? void 0 : _a2.call(iterator));
|
|
32465
|
+
}
|
|
32466
|
+
}, { highWaterMark: 0 });
|
|
32467
|
+
}
|
|
32468
|
+
const REQUEST_INIT_MEMBERS = ["method", "headers", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive", "signal", "window", "duplex", "priority"];
|
|
32469
|
+
function withNodeRequestBody(init) {
|
|
32470
|
+
if (!init) return init;
|
|
32471
|
+
const body = init.body;
|
|
32472
|
+
if (!isAsyncIterableBody(body)) return init;
|
|
32473
|
+
refuseDisturbed(body);
|
|
32474
|
+
const copy2 = {};
|
|
32475
|
+
for (const member of Object.keys(init)) if (member !== "body") copy2[member] = init[member];
|
|
32476
|
+
for (const member of REQUEST_INIT_MEMBERS) {
|
|
32477
|
+
if (member in copy2) continue;
|
|
32478
|
+
const value = init[member];
|
|
32479
|
+
if (value !== void 0) copy2[member] = value;
|
|
32480
|
+
}
|
|
32481
|
+
copy2.body = streamFrom(body);
|
|
32482
|
+
return copy2;
|
|
32483
|
+
}
|
|
32484
|
+
function nodeResponseBody(body) {
|
|
32485
|
+
if (!isAsyncIterableBody(body)) return body;
|
|
32486
|
+
refuseDisturbed(body);
|
|
32487
|
+
return streamFrom(body);
|
|
32488
|
+
}
|
|
32427
32489
|
let transport;
|
|
32428
32490
|
const staticRequestBodies = /* @__PURE__ */ new WeakSet();
|
|
32429
32491
|
function rememberRequestBodySource(request, input, init) {
|
|
@@ -32478,14 +32540,19 @@ function activity(owner, cancel) {
|
|
|
32478
32540
|
function guestFetch(process2, fallback) {
|
|
32479
32541
|
return function fetch2(input, init) {
|
|
32480
32542
|
const adapter = transport;
|
|
32481
|
-
|
|
32482
|
-
const owner = __tokenForProcess(process2);
|
|
32543
|
+
const owner = adapter ? __tokenForProcess(process2) : null;
|
|
32483
32544
|
const ended = () => {
|
|
32484
32545
|
var _a2;
|
|
32485
32546
|
return owner !== null && ((_a2 = __runFor(owner)) == null ? void 0 : _a2.process) !== process2;
|
|
32486
32547
|
};
|
|
32487
32548
|
const stopped2 = () => new DOMException("The requesting process has ended.", "AbortError");
|
|
32488
|
-
if (ended()) return Promise.reject(stopped2());
|
|
32549
|
+
if (adapter && ended()) return Promise.reject(stopped2());
|
|
32550
|
+
try {
|
|
32551
|
+
init = withNodeRequestBody(init);
|
|
32552
|
+
} catch (error) {
|
|
32553
|
+
return Promise.reject(error);
|
|
32554
|
+
}
|
|
32555
|
+
if (!adapter) return fallback.call(globalThis, input, init);
|
|
32489
32556
|
const context2 = { begin(cancel) {
|
|
32490
32557
|
if (ended()) throw stopped2();
|
|
32491
32558
|
return activity(owner, cancel);
|
|
@@ -32494,6 +32561,124 @@ function guestFetch(process2, fallback) {
|
|
|
32494
32561
|
return owner === null ? dispatch() : enterRun(owner, dispatch);
|
|
32495
32562
|
};
|
|
32496
32563
|
}
|
|
32564
|
+
const INSTALLED = Symbol.for("tabnode.response.keepsSetCookie");
|
|
32565
|
+
function withCookies(own, given) {
|
|
32566
|
+
const headers = new Headers(own);
|
|
32567
|
+
if (!given) return headers;
|
|
32568
|
+
const cookies = [];
|
|
32569
|
+
if (typeof given.getSetCookie === "function") cookies.push(...given.getSetCookie());
|
|
32570
|
+
else given.forEach((value, name) => {
|
|
32571
|
+
if (name === "set-cookie") cookies.push(value);
|
|
32572
|
+
});
|
|
32573
|
+
if (cookies.length) {
|
|
32574
|
+
headers.delete("set-cookie");
|
|
32575
|
+
for (const cookie of cookies) headers.append("set-cookie", cookie);
|
|
32576
|
+
}
|
|
32577
|
+
const cookie2 = given.get("set-cookie2");
|
|
32578
|
+
if (cookie2 !== null) headers.set("set-cookie2", cookie2);
|
|
32579
|
+
return headers;
|
|
32580
|
+
}
|
|
32581
|
+
function givenHeaders(init) {
|
|
32582
|
+
const headers = init == null ? void 0 : init.headers;
|
|
32583
|
+
return headers === void 0 || headers === null ? void 0 : new Headers(headers);
|
|
32584
|
+
}
|
|
32585
|
+
function withHeaders(init, headers) {
|
|
32586
|
+
const status = init == null ? void 0 : init.status;
|
|
32587
|
+
const statusText = init == null ? void 0 : init.statusText;
|
|
32588
|
+
return {
|
|
32589
|
+
headers,
|
|
32590
|
+
...status === void 0 ? {} : { status },
|
|
32591
|
+
...statusText === void 0 ? {} : { statusText }
|
|
32592
|
+
};
|
|
32593
|
+
}
|
|
32594
|
+
function installNodeResponse(target) {
|
|
32595
|
+
var _a2;
|
|
32596
|
+
const Native = target.Response;
|
|
32597
|
+
if (typeof Native !== "function" || Native[INSTALLED]) return;
|
|
32598
|
+
const proto = Native.prototype;
|
|
32599
|
+
let nativeHeaders;
|
|
32600
|
+
for (let at2 = proto; at2 && !nativeHeaders; at2 = Object.getPrototypeOf(at2)) nativeHeaders = (_a2 = Object.getOwnPropertyDescriptor(at2, "headers")) == null ? void 0 : _a2.get;
|
|
32601
|
+
const nativeFormData = proto.formData;
|
|
32602
|
+
const nativeBlob = proto.blob;
|
|
32603
|
+
const nativeArrayBuffer = proto.arrayBuffer;
|
|
32604
|
+
const nativeClone = proto.clone;
|
|
32605
|
+
if (!nativeHeaders) return;
|
|
32606
|
+
const kept = /* @__PURE__ */ new WeakMap();
|
|
32607
|
+
const NodeResponse = function Response(body, init) {
|
|
32608
|
+
if (!new.target) throw new TypeError("Class constructor Response cannot be invoked without 'new'");
|
|
32609
|
+
const given = givenHeaders(init);
|
|
32610
|
+
const response = Reflect.construct(Native, [nodeResponseBody(body), given ? withHeaders(init, given) : init], new.target === NodeResponse ? Native : new.target);
|
|
32611
|
+
kept.set(response, withCookies(nativeHeaders.call(response), given));
|
|
32612
|
+
return response;
|
|
32613
|
+
};
|
|
32614
|
+
NodeResponse.prototype = proto;
|
|
32615
|
+
Object.defineProperty(NodeResponse, "length", { value: 0, configurable: true });
|
|
32616
|
+
Object.defineProperty(NodeResponse, INSTALLED, { value: true });
|
|
32617
|
+
Object.setPrototypeOf(NodeResponse, Object.getPrototypeOf(Native));
|
|
32618
|
+
Object.defineProperty(NodeResponse, "json", {
|
|
32619
|
+
value: function json(data2, init) {
|
|
32620
|
+
const given = givenHeaders(init);
|
|
32621
|
+
const response = Native.json(data2, given ? withHeaders(init, given) : init);
|
|
32622
|
+
kept.set(response, withCookies(nativeHeaders.call(response), given));
|
|
32623
|
+
return response;
|
|
32624
|
+
},
|
|
32625
|
+
writable: true,
|
|
32626
|
+
configurable: true
|
|
32627
|
+
});
|
|
32628
|
+
Object.defineProperty(NodeResponse, "redirect", { value: function redirect(url2, status) {
|
|
32629
|
+
return Native.redirect(url2, status);
|
|
32630
|
+
}, writable: true, configurable: true });
|
|
32631
|
+
Object.defineProperty(NodeResponse, "error", { value: function error() {
|
|
32632
|
+
return Native.error();
|
|
32633
|
+
}, writable: true, configurable: true });
|
|
32634
|
+
defineOnHost(proto, "headers", {
|
|
32635
|
+
get() {
|
|
32636
|
+
return kept.get(this) ?? nativeHeaders.call(this);
|
|
32637
|
+
},
|
|
32638
|
+
enumerable: true,
|
|
32639
|
+
configurable: true
|
|
32640
|
+
});
|
|
32641
|
+
defineOnHost(proto, "constructor", { value: NodeResponse, writable: true, enumerable: false, configurable: true });
|
|
32642
|
+
defineOnHost(proto, "clone", {
|
|
32643
|
+
value: function clone() {
|
|
32644
|
+
const copy2 = nativeClone.call(this);
|
|
32645
|
+
const headers = kept.get(this);
|
|
32646
|
+
if (headers) kept.set(copy2, new Headers(headers));
|
|
32647
|
+
return copy2;
|
|
32648
|
+
},
|
|
32649
|
+
writable: true,
|
|
32650
|
+
enumerable: true,
|
|
32651
|
+
configurable: true
|
|
32652
|
+
});
|
|
32653
|
+
const changedType = (response) => {
|
|
32654
|
+
const headers = kept.get(response);
|
|
32655
|
+
if (!headers) return void 0;
|
|
32656
|
+
const current3 = headers.get("content-type");
|
|
32657
|
+
return current3 === nativeHeaders.call(response).get("content-type") ? void 0 : current3;
|
|
32658
|
+
};
|
|
32659
|
+
defineOnHost(proto, "formData", {
|
|
32660
|
+
value: async function formData() {
|
|
32661
|
+
const type2 = changedType(this);
|
|
32662
|
+
if (type2 === void 0) return nativeFormData.call(this);
|
|
32663
|
+
const bytes2 = await nativeArrayBuffer.call(this);
|
|
32664
|
+
return nativeFormData.call(Reflect.construct(Native, [bytes2, type2 === null ? {} : { headers: { "content-type": type2 } }]));
|
|
32665
|
+
},
|
|
32666
|
+
writable: true,
|
|
32667
|
+
enumerable: true,
|
|
32668
|
+
configurable: true
|
|
32669
|
+
});
|
|
32670
|
+
defineOnHost(proto, "blob", {
|
|
32671
|
+
value: async function blob() {
|
|
32672
|
+
const type2 = changedType(this);
|
|
32673
|
+
if (type2 === void 0) return nativeBlob.call(this);
|
|
32674
|
+
return new Blob([await nativeArrayBuffer.call(this)], type2 === null ? {} : { type: type2 });
|
|
32675
|
+
},
|
|
32676
|
+
writable: true,
|
|
32677
|
+
enumerable: true,
|
|
32678
|
+
configurable: true
|
|
32679
|
+
});
|
|
32680
|
+
takeFromHost(target, "Response", NodeResponse);
|
|
32681
|
+
}
|
|
32497
32682
|
function simpleHash(str) {
|
|
32498
32683
|
let hash2 = 0;
|
|
32499
32684
|
for (let i2 = 0; i2 < str.length; i2++) {
|
|
@@ -33692,6 +33877,63 @@ function installShellJobs(bash, host2) {
|
|
|
33692
33877
|
if (shell.jobs.size === 0) shells$1.delete(id);
|
|
33693
33878
|
return { stdout: held.stdout, stderr: held.stderr + stderr, exitCode: status };
|
|
33694
33879
|
}));
|
|
33880
|
+
for (const shell of ["sh", "bash"]) {
|
|
33881
|
+
bash.registerCommand(defineCommand(shell, async (args, ctx) => {
|
|
33882
|
+
var _a2;
|
|
33883
|
+
const exec = ctx.exec;
|
|
33884
|
+
if (!exec) return { stdout: "", stderr: `bash: ${shell}: needs a shell that can run a script
|
|
33885
|
+
`, exitCode: 1 };
|
|
33886
|
+
let script;
|
|
33887
|
+
let zero2;
|
|
33888
|
+
let positional;
|
|
33889
|
+
let sourced;
|
|
33890
|
+
let at2 = 0;
|
|
33891
|
+
while (at2 < args.length && /^[-+][a-bd-zA-Z]+$/u.test(args[at2])) at2++;
|
|
33892
|
+
args = args.slice(at2);
|
|
33893
|
+
if (args[0] === "-c" && args.length >= 2) {
|
|
33894
|
+
script = args[1];
|
|
33895
|
+
zero2 = args[2] ?? shell;
|
|
33896
|
+
positional = args.slice(3);
|
|
33897
|
+
} else if (args.length === 0) {
|
|
33898
|
+
if (!((_a2 = ctx.stdin) == null ? void 0 : _a2.trim())) return { stdout: "", stderr: "", exitCode: 0 };
|
|
33899
|
+
script = ctx.stdin;
|
|
33900
|
+
zero2 = shell;
|
|
33901
|
+
positional = [];
|
|
33902
|
+
} else {
|
|
33903
|
+
const path2 = ctx.fs.resolvePath(ctx.cwd, args[0]);
|
|
33904
|
+
try {
|
|
33905
|
+
script = String(await ctx.fs.readFile(path2));
|
|
33906
|
+
} catch {
|
|
33907
|
+
return { stdout: "", stderr: `${shell}: ${args[0]}: No such file or directory
|
|
33908
|
+
`, exitCode: 127 };
|
|
33909
|
+
}
|
|
33910
|
+
zero2 = args[0];
|
|
33911
|
+
positional = args.slice(1);
|
|
33912
|
+
sourced = path2;
|
|
33913
|
+
}
|
|
33914
|
+
if (script.startsWith("#!")) {
|
|
33915
|
+
const newline = script.indexOf("\n");
|
|
33916
|
+
if (newline !== -1) script = script.slice(newline + 1);
|
|
33917
|
+
}
|
|
33918
|
+
const env = { ...ctx.exportedEnv ?? {}, "0": zero2, "#": String(positional.length), "@": positional.join(" "), "*": positional.join(" ") };
|
|
33919
|
+
positional.forEach((word, index2) => {
|
|
33920
|
+
env[String(index2 + 1)] = word;
|
|
33921
|
+
});
|
|
33922
|
+
const token = ctx.env.get(PROCESS_TOKEN_ENV);
|
|
33923
|
+
if (token) env[PROCESS_TOKEN_ENV] = token;
|
|
33924
|
+
if (sourced !== void 0) script = `. ${sourced.replace(/'/gu, "'\\''").replace(/^(.*)$/su, "'$1'")}`;
|
|
33925
|
+
const result = await exec(script, { env, cwd: ctx.cwd, stdin: ctx.stdin, signal: ctx.signal });
|
|
33926
|
+
return { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: result.exitCode ?? 0 };
|
|
33927
|
+
}));
|
|
33928
|
+
}
|
|
33929
|
+
bash.registerCommand(defineCommand("exec", async (args, ctx) => {
|
|
33930
|
+
if (args.length === 0) return { stdout: "", stderr: "", exitCode: 0 };
|
|
33931
|
+
if (!ctx.exec) return { stdout: "", stderr: "bash: exec: needs a shell that can run a line\n", exitCode: 1 };
|
|
33932
|
+
const line = args.map((word) => /^[A-Za-z0-9_./:=@%+,-]+$/u.test(word) ? word : `'${word.replace(/'/gu, "'\\''")}'`).join(" ");
|
|
33933
|
+
const env = Object.fromEntries(ctx.env);
|
|
33934
|
+
const result = await ctx.exec(line, { env, cwd: ctx.cwd, replaceEnv: true });
|
|
33935
|
+
return { stdout: result.stdout ?? "", stderr: result.stderr ?? "", exitCode: result.exitCode ?? 0 };
|
|
33936
|
+
}));
|
|
33695
33937
|
bash.registerCommand(defineCommand("kill", async (args) => {
|
|
33696
33938
|
let signal = "SIGTERM";
|
|
33697
33939
|
let index2 = 0;
|
|
@@ -33892,6 +34134,18 @@ function registerRunStreams(token, streams2) {
|
|
|
33892
34134
|
}
|
|
33893
34135
|
function releaseRunStreams(token) {
|
|
33894
34136
|
_runStreams.delete(token);
|
|
34137
|
+
shellRuns.delete(token);
|
|
34138
|
+
hostedNodes.delete(token);
|
|
34139
|
+
}
|
|
34140
|
+
const shellRuns = /* @__PURE__ */ new Set();
|
|
34141
|
+
const hostedNodes = /* @__PURE__ */ new Set();
|
|
34142
|
+
function nestedNodeToken(parentToken, args, cwd) {
|
|
34143
|
+
var _a2;
|
|
34144
|
+
const token = `child-${__nextChildRun++}`;
|
|
34145
|
+
setRunPid(token, mintPid(), ((_a2 = runPid(parentToken)) == null ? void 0 : _a2.pid) ?? 0, { argv: ["node", ...args], ...cwd ? { cwd } : {} });
|
|
34146
|
+
const parentStreams = runStreamsFor(parentToken);
|
|
34147
|
+
if (parentStreams) registerRunStreams(token, parentStreams);
|
|
34148
|
+
return token;
|
|
33895
34149
|
}
|
|
33896
34150
|
function runStreamsFor(token) {
|
|
33897
34151
|
return _runStreams.get(token);
|
|
@@ -33983,19 +34237,26 @@ function initChildProcess(vfs2) {
|
|
|
33983
34237
|
if (!tree2) {
|
|
33984
34238
|
return { stdout: "", stderr: "VFS not initialized\n", exitCode: 1 };
|
|
33985
34239
|
}
|
|
33986
|
-
const
|
|
34240
|
+
const parentToken = runTokenOf(ctx);
|
|
34241
|
+
const nested = parentToken !== null && (shellRuns.has(parentToken) || hostedNodes.has(parentToken));
|
|
34242
|
+
const runToken = nested ? nestedNodeToken(parentToken, args, ctx.cwd) : parentToken;
|
|
33987
34243
|
const streams2 = runToken === null ? void 0 : runStreamsFor(runToken);
|
|
33988
34244
|
const processHost = nodeProcessHostFor(runToken);
|
|
33989
34245
|
if (processHost && runToken !== null) {
|
|
33990
|
-
|
|
33991
|
-
|
|
33992
|
-
|
|
33993
|
-
|
|
33994
|
-
|
|
33995
|
-
|
|
33996
|
-
|
|
33997
|
-
|
|
33998
|
-
|
|
34246
|
+
if (!nested) hostedNodes.add(runToken);
|
|
34247
|
+
try {
|
|
34248
|
+
return await runHostedNode(processHost, {
|
|
34249
|
+
token: runToken,
|
|
34250
|
+
argv: [...args],
|
|
34251
|
+
cwd: ctx.cwd,
|
|
34252
|
+
filesystem: tree2,
|
|
34253
|
+
env: guestEnvironmentOf(ctx),
|
|
34254
|
+
...typeof ctx.stdin === "string" ? { stdin: ctx.stdin } : {},
|
|
34255
|
+
...streams2 ? { streams: streams2 } : {}
|
|
34256
|
+
});
|
|
34257
|
+
} finally {
|
|
34258
|
+
if (nested) releaseRunStreams(runToken);
|
|
34259
|
+
}
|
|
33999
34260
|
}
|
|
34000
34261
|
const execArgv = [];
|
|
34001
34262
|
let first = 0;
|
|
@@ -34901,6 +35162,7 @@ function existsInTree(path2) {
|
|
|
34901
35162
|
return false;
|
|
34902
35163
|
}
|
|
34903
35164
|
}
|
|
35165
|
+
const SHELL_PROGRAMS = /* @__PURE__ */ new Set(["sh", "bash", "dash", "/bin/sh", "/bin/bash", "/usr/bin/sh", "/usr/bin/bash"]);
|
|
34904
35166
|
function engineProgramFor(file, cwd) {
|
|
34905
35167
|
const name = __substrateProgramName(file);
|
|
34906
35168
|
if (!name.includes("/")) return name;
|
|
@@ -34947,6 +35209,7 @@ function startChildRun(request) {
|
|
|
34947
35209
|
const controller = new AbortController();
|
|
34948
35210
|
const pendingStdin = [];
|
|
34949
35211
|
const admittedNode = nodeProcessHostInstalled() && engineProgramFor(request.file, request.cwd) === "node";
|
|
35212
|
+
if (!admittedNode) shellRuns.add(token);
|
|
34950
35213
|
const hostTerminal = request.terminal !== void 0 && hostExecutor() !== null && !admittedNode;
|
|
34951
35214
|
let wakeInput;
|
|
34952
35215
|
let liveInput = false;
|
|
@@ -35045,7 +35308,8 @@ function startChildRun(request) {
|
|
|
35045
35308
|
const begin = () => {
|
|
35046
35309
|
if (started2 || finished) return;
|
|
35047
35310
|
started2 = true;
|
|
35048
|
-
const
|
|
35311
|
+
const shellChild = SHELL_PROGRAMS.has(engineProgramFor(request.file, request.cwd)) && hostExecutor() !== null;
|
|
35312
|
+
const engineFirst = !hostTerminal && !shellChild && programExists(request.file, request.cwd, request.env);
|
|
35049
35313
|
liveInput = !hostTerminal && !admittedNode && request.stdinIsPipe && !engineFirst;
|
|
35050
35314
|
if (liveInput) {
|
|
35051
35315
|
pendingStdin.unshift(...initialStdin);
|
|
@@ -40103,6 +40367,7 @@ forGuestRealm(() => {
|
|
|
40103
40367
|
const kept = /* @__PURE__ */ new WeakMap();
|
|
40104
40368
|
class NodeRequest extends Native {
|
|
40105
40369
|
constructor(input, init) {
|
|
40370
|
+
init = withNodeRequestBody(init);
|
|
40106
40371
|
super(input, init);
|
|
40107
40372
|
rememberRequestBodySource(this, input, init);
|
|
40108
40373
|
const asked = new Headers((init == null ? void 0 : init.headers) ?? (input instanceof Native ? input.headers : void 0));
|
|
@@ -40126,6 +40391,9 @@ forGuestRealm(() => {
|
|
|
40126
40391
|
takeFromHost(globalThis, "Request", NodeRequest);
|
|
40127
40392
|
}
|
|
40128
40393
|
});
|
|
40394
|
+
forGuestRealm(() => {
|
|
40395
|
+
installNodeResponse(globalThis);
|
|
40396
|
+
});
|
|
40129
40397
|
forGuestRealm(() => {
|
|
40130
40398
|
const kIsClosedPromise = Symbol.for("nodejs.webstream.isClosedPromise");
|
|
40131
40399
|
const Native = globalThis.ReadableStream;
|
|
@@ -40428,7 +40696,7 @@ class WorkerRuntime {
|
|
|
40428
40696
|
this.worker = new Worker(
|
|
40429
40697
|
new URL(
|
|
40430
40698
|
/* @vite-ignore */
|
|
40431
|
-
"/assets/runtime-worker-
|
|
40699
|
+
"/assets/runtime-worker-C1IV4qnr.js",
|
|
40432
40700
|
import.meta.url
|
|
40433
40701
|
),
|
|
40434
40702
|
{ type: "module" }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The init with an async-iterable body read as a stream, or the init itself.
|
|
3
|
+
* The body is read once; the replacement is built member by member (an init
|
|
4
|
+
* may carry its members on getters of its prototype, as a `Request` passed as
|
|
5
|
+
* an init does), with the init's own other members as they are.
|
|
6
|
+
*/
|
|
7
|
+
export declare function withNodeRequestBody<T extends RequestInit | undefined>(init: T): T;
|
|
8
|
+
/** A response body as undici takes it: an async iterable read as a stream, anything else as given. */
|
|
9
|
+
export declare function nodeResponseBody(body: unknown): unknown;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install the corrected constructor on `target` (the realm's global object),
|
|
3
|
+
* over the `Response` it has. Every property it changes is remembered for the
|
|
4
|
+
* host to have back (`restoreHostGlobals`); a realm that has it already is left.
|
|
5
|
+
*/
|
|
6
|
+
export declare function installNodeResponse(target: {
|
|
7
|
+
Response?: typeof Response;
|
|
8
|
+
}): void;
|
package/package.json
CHANGED
package/src/fetch-transport.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** Host Fetch I/O uses the same process-owned liveness registry as sockets. */
|
|
2
|
+
import { withNodeRequestBody } from './node-body';
|
|
2
3
|
import type { Process } from './shims/process';
|
|
3
4
|
import { __tokenForProcess, __runFor, enterRun, type ProcessToken } from './process-tokens';
|
|
4
5
|
import { registerHandle, __adoptHandle, refHandle, unrefHandle, releaseHandle } from './node-lib/binding/handles';
|
|
@@ -83,11 +84,14 @@ function activity(owner: ProcessToken | null, cancel: () => void): FetchActivity
|
|
|
83
84
|
export function guestFetch(process: Process, fallback: typeof globalThis.fetch): typeof globalThis.fetch {
|
|
84
85
|
return function fetch(input, init) {
|
|
85
86
|
const adapter = transport;
|
|
86
|
-
|
|
87
|
-
const owner = __tokenForProcess(process);
|
|
87
|
+
const owner = adapter ? __tokenForProcess(process) : null;
|
|
88
88
|
const ended = () => owner !== null && __runFor(owner)?.process !== process;
|
|
89
89
|
const stopped = () => new DOMException('The requesting process has ended.', 'AbortError');
|
|
90
|
-
if (ended()) return Promise.reject(stopped());
|
|
90
|
+
if (adapter && ended()) return Promise.reject(stopped());
|
|
91
|
+
// A stream body is read as undici reads it, whichever door the fetch
|
|
92
|
+
// leaves by; a body undici refuses rejects the fetch, as Node's does.
|
|
93
|
+
try { init = withNodeRequestBody(init); } catch (error) { return Promise.reject(error); }
|
|
94
|
+
if (!adapter) return fallback.call(globalThis, input, init);
|
|
91
95
|
const context: FetchTransportContext = { begin(cancel) {
|
|
92
96
|
if (ended()) throw stopped();
|
|
93
97
|
return activity(owner, cancel);
|
package/src/node-body.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A body as Node's fetch (undici's `extractBody`) accepts it: besides what a
|
|
3
|
+
* browser takes, any async iterable (a Node `Readable`, an `http.IncomingMessage`,
|
|
4
|
+
* an async generator) is read as a stream of its chunks, each a `Buffer`,
|
|
5
|
+
* a typed array or a string (UTF-8). A browser's `Request` and `Response` take
|
|
6
|
+
* such an object for a string: `new Request(url, { method: 'POST', body:
|
|
7
|
+
* incomingMessage, duplex: 'half' })` has the body "[object Object]". Next's
|
|
8
|
+
* App Router builds every route handler's request exactly that way (its
|
|
9
|
+
* request adapter passes the Node request as the body, "handled by undici"),
|
|
10
|
+
* so every POST a route handler read was that string, and NextAuth's
|
|
11
|
+
* credentials callback found no CSRF token in it.
|
|
12
|
+
*
|
|
13
|
+
* Only such a body is changed; every other init is handed on untouched.
|
|
14
|
+
*/
|
|
15
|
+
import { Buffer } from './node-lib/buffer-module';
|
|
16
|
+
|
|
17
|
+
/** The mark Node's streams carry once read (`internal/streams/utils`, `kIsDisturbed`). */
|
|
18
|
+
const kIsDisturbed = Symbol.for('nodejs.stream.disturbed');
|
|
19
|
+
|
|
20
|
+
function isAsyncIterableBody(body: unknown): body is AsyncIterable<unknown> {
|
|
21
|
+
if (body === null || typeof body !== 'object') return false;
|
|
22
|
+
if (typeof ReadableStream === 'function' && body instanceof ReadableStream) return false;
|
|
23
|
+
if (typeof Blob === 'function' && body instanceof Blob) return false;
|
|
24
|
+
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return false;
|
|
25
|
+
if (typeof FormData === 'function' && body instanceof FormData) return false;
|
|
26
|
+
if (body instanceof URLSearchParams) return false;
|
|
27
|
+
return typeof (body as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Node's `isDisturbed`, and undici's refusal of a body already read or locked. */
|
|
31
|
+
function refuseDisturbed(body: object): void {
|
|
32
|
+
const stream = body as { locked?: unknown; readableDidRead?: unknown; readableAborted?: unknown; [kIsDisturbed]?: unknown };
|
|
33
|
+
const disturbed = stream[kIsDisturbed] !== undefined ? Boolean(stream[kIsDisturbed]) : Boolean(stream.readableDidRead || stream.readableAborted);
|
|
34
|
+
if (disturbed || stream.locked === true) throw new TypeError('Response body object should not be disturbed or locked');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* undici's `ReadableStreamFrom`: the iterator made when the stream starts,
|
|
39
|
+
* each chunk `Buffer.from`'d as Node's is (a chunk `Buffer.from` refuses
|
|
40
|
+
* errors the stream), an empty chunk passed over for the next, and the
|
|
41
|
+
* iterator returned, with no argument, on cancel.
|
|
42
|
+
*/
|
|
43
|
+
function streamFrom(iterable: AsyncIterable<unknown>): ReadableStream<Uint8Array> {
|
|
44
|
+
let iterator: AsyncIterator<unknown> | undefined;
|
|
45
|
+
return new ReadableStream<Uint8Array>({
|
|
46
|
+
async start() { iterator = iterable[Symbol.asyncIterator](); },
|
|
47
|
+
async pull(controller) {
|
|
48
|
+
for (;;) {
|
|
49
|
+
const { done, value } = await iterator!.next();
|
|
50
|
+
if (done) { controller.close(); return; }
|
|
51
|
+
const bytes = (Buffer.isBuffer(value) ? value : (Buffer.from as (chunk: unknown) => Uint8Array)(value)) as Uint8Array;
|
|
52
|
+
if (bytes.byteLength) { controller.enqueue(new Uint8Array(bytes)); return; }
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async cancel() { await iterator?.return?.(); },
|
|
56
|
+
}, { highWaterMark: 0 });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const REQUEST_INIT_MEMBERS = ['method', 'headers', 'referrer', 'referrerPolicy', 'mode', 'credentials', 'cache', 'redirect', 'integrity', 'keepalive', 'signal', 'window', 'duplex', 'priority'] as const;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The init with an async-iterable body read as a stream, or the init itself.
|
|
63
|
+
* The body is read once; the replacement is built member by member (an init
|
|
64
|
+
* may carry its members on getters of its prototype, as a `Request` passed as
|
|
65
|
+
* an init does), with the init's own other members as they are.
|
|
66
|
+
*/
|
|
67
|
+
export function withNodeRequestBody<T extends RequestInit | undefined>(init: T): T {
|
|
68
|
+
if (!init) return init;
|
|
69
|
+
const body = (init as RequestInit).body as unknown;
|
|
70
|
+
if (!isAsyncIterableBody(body)) return init;
|
|
71
|
+
refuseDisturbed(body);
|
|
72
|
+
const copy: Record<string, unknown> = {};
|
|
73
|
+
for (const member of Object.keys(init)) if (member !== 'body') copy[member] = (init as Record<string, unknown>)[member];
|
|
74
|
+
for (const member of REQUEST_INIT_MEMBERS) {
|
|
75
|
+
if (member in copy) continue;
|
|
76
|
+
const value = (init as Record<string, unknown>)[member];
|
|
77
|
+
if (value !== undefined) copy[member] = value;
|
|
78
|
+
}
|
|
79
|
+
copy.body = streamFrom(body);
|
|
80
|
+
return copy as T;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** A response body as undici takes it: an async iterable read as a stream, anything else as given. */
|
|
84
|
+
export function nodeResponseBody(body: unknown): unknown {
|
|
85
|
+
if (!isAsyncIterableBody(body)) return body;
|
|
86
|
+
refuseDisturbed(body);
|
|
87
|
+
return streamFrom(body);
|
|
88
|
+
}
|