sandboxedjs 0.2.22 → 0.2.23

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.
@@ -1,4 +1,4 @@
1
- import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-BHo4LdY2.js';
1
+ import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-BFG82pSs.js';
2
2
 
3
3
  type NodeKind = "file" | "directory" | "symlink";
4
4
  interface MemoryVolumeSnapshotEntry {
@@ -1,4 +1,4 @@
1
- import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-BHo4LdY2.cjs';
1
+ import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-BFG82pSs.cjs';
2
2
 
3
3
  type NodeKind = "file" | "directory" | "symlink";
4
4
  interface MemoryVolumeSnapshotEntry {
@@ -1,6 +1,6 @@
1
- import { V as Vfs, C as Cred, a as VirtualTcpNetwork } from './contracts-BHo4LdY2.cjs';
2
- export { m as ROOT_CRED, v as makeCred } from './contracts-BHo4LdY2.cjs';
3
- export { M as MemoryVolume } from './memory-volume-e-uJFRnG.cjs';
1
+ import { V as Vfs, C as Cred, a as VirtualTcpNetwork } from './contracts-BFG82pSs.cjs';
2
+ export { m as ROOT_CRED, x as makeCred } from './contracts-BFG82pSs.cjs';
3
+ export { M as MemoryVolume } from './memory-volume-Din7xmmT.cjs';
4
4
 
5
5
  /**
6
6
  * Open-file descriptions: the thing a descriptor points *at*.
@@ -1,6 +1,6 @@
1
- import { V as Vfs, C as Cred, a as VirtualTcpNetwork } from './contracts-BHo4LdY2.js';
2
- export { m as ROOT_CRED, v as makeCred } from './contracts-BHo4LdY2.js';
3
- export { M as MemoryVolume } from './memory-volume-meoRW8ST.js';
1
+ import { V as Vfs, C as Cred, a as VirtualTcpNetwork } from './contracts-BFG82pSs.js';
2
+ export { m as ROOT_CRED, x as makeCred } from './contracts-BFG82pSs.js';
3
+ export { M as MemoryVolume } from './memory-volume-DhGUwDqX.js';
4
4
 
5
5
  /**
6
6
  * Open-file descriptions: the thing a descriptor points *at*.
@@ -8659,10 +8659,10 @@ var require_buffer = __commonJS({
8659
8659
  return out;
8660
8660
  }
8661
8661
  function utf16leSlice(buf, start, end) {
8662
- const bytes2 = buf.slice(start, end);
8662
+ const bytes3 = buf.slice(start, end);
8663
8663
  let res = "";
8664
- for (let i = 0; i < bytes2.length - 1; i += 2) {
8665
- res += String.fromCharCode(bytes2[i] + bytes2[i + 1] * 256);
8664
+ for (let i = 0; i < bytes3.length - 1; i += 2) {
8665
+ res += String.fromCharCode(bytes3[i] + bytes3[i + 1] * 256);
8666
8666
  }
8667
8667
  return res;
8668
8668
  }
@@ -9185,13 +9185,13 @@ var require_buffer = __commonJS({
9185
9185
  this[i] = val;
9186
9186
  }
9187
9187
  } else {
9188
- const bytes2 = Buffer3.isBuffer(val) ? val : Buffer3.from(val, encoding);
9189
- const len = bytes2.length;
9188
+ const bytes3 = Buffer3.isBuffer(val) ? val : Buffer3.from(val, encoding);
9189
+ const len = bytes3.length;
9190
9190
  if (len === 0) {
9191
9191
  throw new TypeError('The value "' + val + '" is invalid for argument "value"');
9192
9192
  }
9193
9193
  for (i = 0; i < end - start; ++i) {
9194
- this[i + start] = bytes2[i % len];
9194
+ this[i + start] = bytes3[i % len];
9195
9195
  }
9196
9196
  }
9197
9197
  return this;
@@ -9326,50 +9326,50 @@ var require_buffer = __commonJS({
9326
9326
  let codePoint;
9327
9327
  const length = string.length;
9328
9328
  let leadSurrogate = null;
9329
- const bytes2 = [];
9329
+ const bytes3 = [];
9330
9330
  for (let i = 0; i < length; ++i) {
9331
9331
  codePoint = string.charCodeAt(i);
9332
9332
  if (codePoint > 55295 && codePoint < 57344) {
9333
9333
  if (!leadSurrogate) {
9334
9334
  if (codePoint > 56319) {
9335
- if ((units -= 3) > -1) bytes2.push(239, 191, 189);
9335
+ if ((units -= 3) > -1) bytes3.push(239, 191, 189);
9336
9336
  continue;
9337
9337
  } else if (i + 1 === length) {
9338
- if ((units -= 3) > -1) bytes2.push(239, 191, 189);
9338
+ if ((units -= 3) > -1) bytes3.push(239, 191, 189);
9339
9339
  continue;
9340
9340
  }
9341
9341
  leadSurrogate = codePoint;
9342
9342
  continue;
9343
9343
  }
9344
9344
  if (codePoint < 56320) {
9345
- if ((units -= 3) > -1) bytes2.push(239, 191, 189);
9345
+ if ((units -= 3) > -1) bytes3.push(239, 191, 189);
9346
9346
  leadSurrogate = codePoint;
9347
9347
  continue;
9348
9348
  }
9349
9349
  codePoint = (leadSurrogate - 55296 << 10 | codePoint - 56320) + 65536;
9350
9350
  } else if (leadSurrogate) {
9351
- if ((units -= 3) > -1) bytes2.push(239, 191, 189);
9351
+ if ((units -= 3) > -1) bytes3.push(239, 191, 189);
9352
9352
  }
9353
9353
  leadSurrogate = null;
9354
9354
  if (codePoint < 128) {
9355
9355
  if ((units -= 1) < 0) break;
9356
- bytes2.push(codePoint);
9356
+ bytes3.push(codePoint);
9357
9357
  } else if (codePoint < 2048) {
9358
9358
  if ((units -= 2) < 0) break;
9359
- bytes2.push(
9359
+ bytes3.push(
9360
9360
  codePoint >> 6 | 192,
9361
9361
  codePoint & 63 | 128
9362
9362
  );
9363
9363
  } else if (codePoint < 65536) {
9364
9364
  if ((units -= 3) < 0) break;
9365
- bytes2.push(
9365
+ bytes3.push(
9366
9366
  codePoint >> 12 | 224,
9367
9367
  codePoint >> 6 & 63 | 128,
9368
9368
  codePoint & 63 | 128
9369
9369
  );
9370
9370
  } else if (codePoint < 1114112) {
9371
9371
  if ((units -= 4) < 0) break;
9372
- bytes2.push(
9372
+ bytes3.push(
9373
9373
  codePoint >> 18 | 240,
9374
9374
  codePoint >> 12 & 63 | 128,
9375
9375
  codePoint >> 6 & 63 | 128,
@@ -9379,7 +9379,7 @@ var require_buffer = __commonJS({
9379
9379
  throw new Error("Invalid code point");
9380
9380
  }
9381
9381
  }
9382
- return bytes2;
9382
+ return bytes3;
9383
9383
  }
9384
9384
  function asciiToBytes(str) {
9385
9385
  const byteArray = [];
@@ -49702,18 +49702,18 @@ var import_events = __toESM(require_events(), 1);
49702
49702
  var import_stream_browserify3 = __toESM(require_stream_browserify(), 1);
49703
49703
 
49704
49704
  // src/net/proxy-fetch.ts
49705
- function toBase64(bytes2) {
49705
+ function toBase64(bytes3) {
49706
49706
  let text = "";
49707
- for (let at2 = 0; at2 < bytes2.length; at2 += 32768) {
49708
- text += String.fromCharCode(...bytes2.subarray(at2, at2 + 32768));
49707
+ for (let at2 = 0; at2 < bytes3.length; at2 += 32768) {
49708
+ text += String.fromCharCode(...bytes3.subarray(at2, at2 + 32768));
49709
49709
  }
49710
49710
  return btoa(text);
49711
49711
  }
49712
49712
  function fromBase64(text) {
49713
49713
  const binary = atob(text);
49714
- const bytes2 = new Uint8Array(binary.length);
49715
- for (let at2 = 0; at2 < binary.length; at2 += 1) bytes2[at2] = binary.charCodeAt(at2);
49716
- return bytes2;
49714
+ const bytes3 = new Uint8Array(binary.length);
49715
+ for (let at2 = 0; at2 < binary.length; at2 += 1) bytes3[at2] = binary.charCodeAt(at2);
49716
+ return bytes3;
49717
49717
  }
49718
49718
  async function proxyExchange(proxy, request, fetchImpl = fetch) {
49719
49719
  let answer2;
@@ -49800,6 +49800,93 @@ async function discoverEgress(fetchImpl = fetch) {
49800
49800
  return await found;
49801
49801
  }
49802
49802
 
49803
+ // src/net/secrets.ts
49804
+ var PLACEHOLDER = /\{\{secret:([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
49805
+ var REDACTED = "[sealed]";
49806
+ var SecretRefused = class extends Error {
49807
+ code = "EACCES";
49808
+ };
49809
+ function hostBound(secret, hostname) {
49810
+ return secret.hosts.some((host) => hostname === host || hostname.endsWith(`.${host}`));
49811
+ }
49812
+ function mentionsSecret(text) {
49813
+ PLACEHOLDER.lastIndex = 0;
49814
+ return PLACEHOLDER.test(text);
49815
+ }
49816
+ function substituteSecrets(text, hostname, secrets) {
49817
+ return text.replace(PLACEHOLDER, (_match, name) => {
49818
+ const secret = Object.prototype.hasOwnProperty.call(secrets, name) ? secrets[name] : void 0;
49819
+ if (!secret) {
49820
+ throw new SecretRefused(`no sealed secret named ${name} is configured for this container`);
49821
+ }
49822
+ if (!hostBound(secret, hostname)) {
49823
+ throw new SecretRefused(
49824
+ `the sealed secret ${name} is not bound to ${hostname}; it may only be sent to ${secret.hosts.join(", ") || "no host"}`
49825
+ );
49826
+ }
49827
+ return secret.value;
49828
+ });
49829
+ }
49830
+ function sealRequest(request, secrets) {
49831
+ const url = new URL(request.url);
49832
+ if (mentionsSecret(decodeURIComponent(url.href))) {
49833
+ throw new SecretRefused("a sealed secret can only be used in a request header, not in the URL");
49834
+ }
49835
+ const used = [];
49836
+ let headers = null;
49837
+ request.headers.forEach((value, name) => {
49838
+ if (!mentionsSecret(value)) return;
49839
+ headers ??= new Headers(request.headers);
49840
+ headers.set(name, substituteSecrets(value, url.hostname, secrets));
49841
+ PLACEHOLDER.lastIndex = 0;
49842
+ for (const match3 of value.matchAll(PLACEHOLDER)) used.push(match3[1]);
49843
+ });
49844
+ return headers ? { request: new Request(request, { headers }), used } : { request, used };
49845
+ }
49846
+ function redactResponse(response, secrets) {
49847
+ const values = Object.values(secrets).map((secret) => secret.value).filter((value) => value.length > 0);
49848
+ if (values.length === 0) return response;
49849
+ const headers = new Headers();
49850
+ response.headers.forEach((value, name) => headers.set(name, redactText(value, values)));
49851
+ const init = { status: response.status, statusText: response.statusText, headers };
49852
+ if (!response.body) return new Response(null, init);
49853
+ headers.delete("content-length");
49854
+ return new Response(response.body.pipeThrough(redactingStream(values)), init);
49855
+ }
49856
+ function redactText(text, values) {
49857
+ let out = text;
49858
+ for (const value of values) out = out.split(value).join(REDACTED);
49859
+ return out;
49860
+ }
49861
+ function redactingStream(values) {
49862
+ const needles = values.map((value) => latin1(new TextEncoder().encode(value)));
49863
+ const hold = Math.max(...needles.map((needle) => needle.length)) - 1;
49864
+ let pending = "";
49865
+ return new TransformStream({
49866
+ transform(chunk, controller) {
49867
+ pending = redactText(pending + latin1(chunk), needles);
49868
+ if (pending.length <= hold) return;
49869
+ controller.enqueue(bytes2(pending.slice(0, pending.length - hold)));
49870
+ pending = pending.slice(pending.length - hold);
49871
+ },
49872
+ flush(controller) {
49873
+ if (pending) controller.enqueue(bytes2(redactText(pending, needles)));
49874
+ }
49875
+ });
49876
+ }
49877
+ function latin1(chunk) {
49878
+ let out = "";
49879
+ for (let at2 = 0; at2 < chunk.length; at2 += 32768) {
49880
+ out += String.fromCharCode(...chunk.subarray(at2, at2 + 32768));
49881
+ }
49882
+ return out;
49883
+ }
49884
+ function bytes2(text) {
49885
+ const out = new Uint8Array(text.length);
49886
+ for (let index = 0; index < text.length; index += 1) out[index] = text.charCodeAt(index);
49887
+ return out;
49888
+ }
49889
+
49803
49890
  // src/net/policy.ts
49804
49891
  function isLoopbackHostname(hostname) {
49805
49892
  const host = hostname.replace(/^\[|\]$/g, "").toLowerCase();
@@ -49837,6 +49924,24 @@ function requestUrl(input2) {
49837
49924
  return input2.url;
49838
49925
  }
49839
49926
  function policedFetch(policy, fetchImpl) {
49927
+ const secrets = policy.secrets && Object.keys(policy.secrets).length > 0 ? policy.secrets : null;
49928
+ if (!secrets) return policedPlainFetch(policy, fetchImpl);
49929
+ const plain = policedPlainFetch(policy, fetchImpl);
49930
+ return (async (input2, init) => {
49931
+ const url = requestUrl(input2);
49932
+ if (!outboundAllowed(policy, url)) {
49933
+ throw Object.assign(new TypeError("fetch failed"), { cause: outboundBlockedError(url) });
49934
+ }
49935
+ let sealed;
49936
+ try {
49937
+ sealed = sealRequest(new Request(input2, init), secrets).request;
49938
+ } catch (error) {
49939
+ throw Object.assign(new TypeError("fetch failed"), { cause: error });
49940
+ }
49941
+ return redactResponse(await plain(sealed), secrets);
49942
+ });
49943
+ }
49944
+ function policedPlainFetch(policy, fetchImpl) {
49840
49945
  return (async (input2, init) => {
49841
49946
  const url = requestUrl(input2);
49842
49947
  if (!outboundAllowed(policy, url)) {
@@ -49961,6 +50066,8 @@ var VirtualServerResponse = class extends import_stream_browserify3.default.Writ
49961
50066
  completed;
49962
50067
  constructor(request) {
49963
50068
  super();
50069
+ this.on("error", () => {
50070
+ });
49964
50071
  this.req = request;
49965
50072
  this.completed = new Promise((resolve2) => {
49966
50073
  this.resolve = resolve2;
@@ -50090,9 +50197,9 @@ var VirtualSocket = class extends import_stream_browserify3.default.Duplex {
50090
50197
  _read() {
50091
50198
  }
50092
50199
  _write(chunk, encoding, callback) {
50093
- const bytes2 = Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk, encoding);
50200
+ const bytes3 = Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk, encoding);
50094
50201
  try {
50095
- this.peer?.data(new Uint8Array(bytes2));
50202
+ this.peer?.data(new Uint8Array(bytes3));
50096
50203
  callback();
50097
50204
  } catch (error) {
50098
50205
  callback(error);
@@ -50116,9 +50223,9 @@ var VirtualSocket = class extends import_stream_browserify3.default.Duplex {
50116
50223
  this.peer = null;
50117
50224
  }
50118
50225
  /** Bytes arriving from the far end. */
50119
- deliver(bytes2) {
50226
+ deliver(bytes3) {
50120
50227
  if (this.destroyed || this.hungUp) return;
50121
- this.push(Buffer2.from(bytes2));
50228
+ this.push(Buffer2.from(bytes3));
50122
50229
  }
50123
50230
  /** The far end went away; let the server's stream end cleanly. */
50124
50231
  peerClosed() {
@@ -50273,7 +50380,7 @@ var VirtualHttpRouter = class {
50273
50380
  request.socket = socket;
50274
50381
  item.server.emit("upgrade", request, socket, Buffer2.alloc(0));
50275
50382
  return {
50276
- send: (bytes2) => socket.deliver(bytes2),
50383
+ send: (bytes3) => socket.deliver(bytes3),
50277
50384
  close: () => socket.peerClosed()
50278
50385
  };
50279
50386
  }
@@ -50499,9 +50606,9 @@ var VirtualClientRequest = class extends import_stream_browserify3.default.Writa
50499
50606
  }
50500
50607
  const result = remote ?? await this.router.request(this.target.port, init);
50501
50608
  const body_ = result.body;
50502
- const bytes2 = typeof body_ === "string" ? new TextEncoder().encode(body_) : body_ instanceof ArrayBuffer ? new Uint8Array(body_) : body_ ?? new Uint8Array();
50609
+ const bytes3 = typeof body_ === "string" ? new TextEncoder().encode(body_) : body_ instanceof ArrayBuffer ? new Uint8Array(body_) : body_ ?? new Uint8Array();
50503
50610
  const status = result.statusCode ?? 200;
50504
- return new VirtualClientResponse(status, result.statusMessage ?? STATUS_CODES[status] ?? "", lowercaseHeaders(result.headers), bytes2);
50611
+ return new VirtualClientResponse(status, result.statusMessage ?? STATUS_CODES[status] ?? "", lowercaseHeaders(result.headers), bytes3);
50505
50612
  }
50506
50613
  async viaFetch(body) {
50507
50614
  const fetchImpl = this.fetchImpl ?? globalThis.fetch;
@@ -50525,8 +50632,8 @@ var VirtualClientRequest = class extends import_stream_browserify3.default.Writa
50525
50632
  response.headers.forEach((value, key) => {
50526
50633
  received[key.toLowerCase()] = value;
50527
50634
  });
50528
- const bytes2 = new Uint8Array(await response.arrayBuffer());
50529
- return new VirtualClientResponse(response.status, response.statusText, received, bytes2);
50635
+ const bytes3 = new Uint8Array(await response.arrayBuffer());
50636
+ return new VirtualClientResponse(response.status, response.statusText, received, bytes3);
50530
50637
  }
50531
50638
  };
50532
50639
  function lowercaseHeaders(headers) {
@@ -50618,9 +50725,9 @@ function createVirtualFetch(router, options = {}) {
50618
50725
  for (const part of Array.isArray(value) ? value : [value]) responseHeaders.append(name, String(part));
50619
50726
  }
50620
50727
  const raw = result.body;
50621
- const bytes2 = typeof raw === "string" ? new TextEncoder().encode(raw) : raw instanceof ArrayBuffer ? new Uint8Array(raw) : raw ?? new Uint8Array();
50728
+ const bytes3 = typeof raw === "string" ? new TextEncoder().encode(raw) : raw instanceof ArrayBuffer ? new Uint8Array(raw) : raw ?? new Uint8Array();
50622
50729
  const nullBody = status === 204 || status === 205 || status === 304 || request.method === "HEAD";
50623
- return new Response(nullBody ? null : new Uint8Array(bytes2), {
50730
+ return new Response(nullBody ? null : new Uint8Array(bytes3), {
50624
50731
  status,
50625
50732
  statusText: result.statusMessage ?? STATUS_CODES[status] ?? "",
50626
50733
  headers: responseHeaders
@@ -52324,7 +52431,7 @@ var ChildProcess = class extends import_events2.default {
52324
52431
  this.stdin = new import_stream_browserify4.default.Writable({
52325
52432
  write: (chunk, _encoding, done) => {
52326
52433
  try {
52327
- handle.sendStdin(typeof chunk === "string" ? chunk : Buffer2.from(chunk).toString("utf8"));
52434
+ handle.sendStdin(typeof chunk === "string" ? chunk : new Uint8Array(chunk));
52328
52435
  } catch {
52329
52436
  }
52330
52437
  done();
@@ -52343,8 +52450,8 @@ var ChildProcess = class extends import_events2.default {
52343
52450
  const pipe = this.stdio[event.fd];
52344
52451
  pipe?.push(Buffer2.from(event.text));
52345
52452
  });
52346
- handle.on("stdout", (text) => this.stdout.write(text));
52347
- handle.on("stderr", (text) => this.stderr.write(text));
52453
+ handle.on("stdout", (value) => this.stdout.write(typeof value === "string" ? value : Buffer2.from(value)));
52454
+ handle.on("stderr", (value) => this.stderr.write(typeof value === "string" ? value : Buffer2.from(value)));
52348
52455
  handle.on("exit", (code) => this.finish(code));
52349
52456
  referenceChanged(1);
52350
52457
  try {
@@ -53373,7 +53480,7 @@ function createCoreModules(options) {
53373
53480
  });
53374
53481
  processObject.stdin = stdin;
53375
53482
  Reflect.deleteProperty(processObject, "browser");
53376
- const fs = createFsModule(volume, () => cwd, options.stdinPath, defer);
53483
+ const fs = createFsModule(volume, () => cwd, options.stdinPath, defer, stdin);
53377
53484
  processObject.loadEnvFile = (path2 = ".env") => {
53378
53485
  const parsed = parseEnv(fs.readFileSync(path2, "utf8"));
53379
53486
  for (const [key, value] of Object.entries(parsed)) {
@@ -53745,7 +53852,7 @@ function createPathModule(cwd) {
53745
53852
  path.default = path;
53746
53853
  return path;
53747
53854
  }
53748
- function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
53855
+ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask, stdin) {
53749
53856
  const fds = /* @__PURE__ */ new Map();
53750
53857
  let nextFd = 3;
53751
53858
  if (stdinPath) fds.set(0, { path: stdinPath, position: 0, flags: "r" });
@@ -53756,7 +53863,7 @@ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
53756
53863
  if (typeof value !== "string") throw new TypeError("path must be a string, Buffer, or URL");
53757
53864
  return value.startsWith("/") ? clean(value) : resolve(cwd(), value);
53758
53865
  };
53759
- const bytes2 = (data2, encoding) => {
53866
+ const bytes3 = (data2, encoding) => {
53760
53867
  if (typeof data2 === "string") return new Uint8Array(Buffer2.from(data2, encoding));
53761
53868
  if (Buffer2.isBuffer(data2) || data2 instanceof Uint8Array) return new Uint8Array(data2);
53762
53869
  if (data2 instanceof ArrayBuffer) return new Uint8Array(data2);
@@ -53818,12 +53925,12 @@ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
53818
53925
  readFileSync: (path, options) => read(path, typeof options === "object" && options ? options.encoding : options),
53819
53926
  writeFileSync: (path, data2, options) => {
53820
53927
  const encoding = typeof options === "object" && options ? options.encoding : options === "buffer" ? void 0 : options ?? void 0;
53821
- volume.writeFileSync(abs(path), bytes2(data2, encoding ?? void 0));
53928
+ volume.writeFileSync(abs(path), bytes3(data2, encoding ?? void 0));
53822
53929
  if (typeof options === "object" && options?.mode !== void 0) volume.chmodSync(abs(path), options.mode);
53823
53930
  },
53824
53931
  appendFileSync: (path, data2, options) => {
53825
53932
  const encoding = typeof options === "object" && options ? options.encoding : options === "buffer" ? void 0 : options ?? void 0;
53826
- volume.appendFileSync(abs(path), bytes2(data2, encoding ?? void 0));
53933
+ volume.appendFileSync(abs(path), bytes3(data2, encoding ?? void 0));
53827
53934
  },
53828
53935
  existsSync: (path) => {
53829
53936
  try {
@@ -53914,7 +54021,7 @@ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
53914
54021
  offset2 = 0;
53915
54022
  length = data2.length;
53916
54023
  }
53917
- const input2 = bytes2(data2);
54024
+ const input2 = bytes3(data2);
53918
54025
  const chunk = input2.subarray(offset2 ?? 0, (offset2 ?? 0) + (length ?? input2.length));
53919
54026
  const size = volume.lstatSync(file.path).size;
53920
54027
  const append = file.flags.startsWith("a") || (position ?? file.position) >= size;
@@ -54039,9 +54146,9 @@ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
54039
54146
  const self2 = this;
54040
54147
  const append = () => {
54041
54148
  try {
54042
- const bytes3 = typeof chunk === "string" ? Buffer2.from(chunk, encoding) : chunk;
54043
- volume.appendFileSync(self2.path, new Uint8Array(bytes3));
54044
- self2.bytesWritten += bytes3.length;
54149
+ const bytes4 = typeof chunk === "string" ? Buffer2.from(chunk, encoding) : chunk;
54150
+ volume.appendFileSync(self2.path, new Uint8Array(bytes4));
54151
+ self2.bytesWritten += bytes4.length;
54045
54152
  done();
54046
54153
  } catch (error) {
54047
54154
  done(error);
@@ -54242,6 +54349,57 @@ function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
54242
54349
  ({ offset: offset2, length, position } = options);
54243
54350
  }
54244
54351
  const start = offset2 ?? 0;
54352
+ if (fd === 0 && stdin) {
54353
+ const requested = length ?? buffer.byteLength - start;
54354
+ const finish = (chunk) => {
54355
+ const source = Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk);
54356
+ const count = Math.min(requested, source.byteLength);
54357
+ buffer.set(source.subarray(0, count), start);
54358
+ if (count < source.byteLength && typeof stdin.unshift === "function") {
54359
+ stdin.unshift(source.subarray(count));
54360
+ }
54361
+ cb(null, count, buffer);
54362
+ };
54363
+ const available = stdin.read();
54364
+ if (available !== null) {
54365
+ defer(() => finish(available));
54366
+ return;
54367
+ }
54368
+ if (stdin.readableEnded || stdin.destroyed) {
54369
+ defer(() => cb(null, 0, buffer));
54370
+ return;
54371
+ }
54372
+ let settled = false;
54373
+ const cleanup = () => {
54374
+ stdin.removeListener("readable", onReadable);
54375
+ stdin.removeListener("end", onEnd);
54376
+ stdin.removeListener("error", onError);
54377
+ };
54378
+ const onReadable = () => {
54379
+ if (settled) return;
54380
+ const chunk = stdin.read();
54381
+ if (chunk === null) return;
54382
+ settled = true;
54383
+ cleanup();
54384
+ finish(chunk);
54385
+ };
54386
+ const onEnd = () => {
54387
+ if (settled) return;
54388
+ settled = true;
54389
+ cleanup();
54390
+ cb(null, 0, buffer);
54391
+ };
54392
+ const onError = (error) => {
54393
+ if (settled) return;
54394
+ settled = true;
54395
+ cleanup();
54396
+ cb(error);
54397
+ };
54398
+ stdin.on("readable", onReadable);
54399
+ stdin.once("end", onEnd);
54400
+ stdin.once("error", onError);
54401
+ return;
54402
+ }
54245
54403
  runThenCall(() => [fs.readSync(fd, buffer, start, length ?? buffer.byteLength - start, position ?? null), buffer], cb);
54246
54404
  };
54247
54405
  fs.write = (fd, data2, ...rest) => {
@@ -54333,8 +54491,8 @@ function createBufferBuiltin() {
54333
54491
  }
54334
54492
  },
54335
54493
  isAscii: (input2) => {
54336
- const bytes2 = input2 instanceof ArrayBuffer ? new Uint8Array(input2) : new Uint8Array(input2.buffer, input2.byteOffset, input2.byteLength);
54337
- for (const byte of bytes2) if (byte > 127) return false;
54494
+ const bytes3 = input2 instanceof ArrayBuffer ? new Uint8Array(input2) : new Uint8Array(input2.buffer, input2.byteOffset, input2.byteLength);
54495
+ for (const byte of bytes3) if (byte > 127) return false;
54338
54496
  return true;
54339
54497
  }
54340
54498
  };
@@ -54955,12 +55113,12 @@ var RemoteVolume = class {
54955
55113
  return new Uint8Array(this.call("readFileSync", [path]).body);
54956
55114
  }
54957
55115
  writeFileSync(path, data2) {
54958
- const bytes2 = typeof data2 === "string" ? encoder.encode(data2) : data2;
54959
- this.call("writeFileSync", [path], bytes2);
55116
+ const bytes3 = typeof data2 === "string" ? encoder.encode(data2) : data2;
55117
+ this.call("writeFileSync", [path], bytes3);
54960
55118
  }
54961
55119
  appendFileSync(path, data2) {
54962
- const bytes2 = typeof data2 === "string" ? encoder.encode(data2) : data2;
54963
- this.call("appendFileSync", [path], bytes2);
55120
+ const bytes3 = typeof data2 === "string" ? encoder.encode(data2) : data2;
55121
+ this.call("appendFileSync", [path], bytes3);
54964
55122
  }
54965
55123
  readdirSync(path) {
54966
55124
  return this.call("readdirSync", [path]).value;
@@ -55083,6 +55241,7 @@ async function main() {
55083
55241
  port.postMessage({ type: "sandboxedjs:ready" });
55084
55242
  }
55085
55243
  async function run(port, start) {
55244
+ const hostThreadProcess = globalThis.process;
55086
55245
  installPromiseContext();
55087
55246
  const channel = new SyncChannelClient(start.buffers, () => port.postMessage({ type: "wake" }));
55088
55247
  const volume = new RemoteVolume(channel);
@@ -55122,6 +55281,8 @@ async function run(port, start) {
55122
55281
  onRawMode: (enabled) => port.postMessage({ type: "rawmode", enabled })
55123
55282
  });
55124
55283
  const guestGlobals = globalThis;
55284
+ guestGlobals.process = core.globals.process;
55285
+ guestGlobals.Buffer = core.globals.Buffer;
55125
55286
  if (typeof core.globals.fetch === "function") guestGlobals.fetch = core.globals.fetch;
55126
55287
  if (typeof core.globals.WebSocket === "function") guestGlobals.WebSocket = core.globals.WebSocket;
55127
55288
  if (typeof self !== "undefined" && typeof self.addEventListener === "function") {
@@ -55135,9 +55296,8 @@ async function run(port, start) {
55135
55296
  core.reportUnhandledRejection(event.reason);
55136
55297
  });
55137
55298
  } else {
55138
- const threadProcess = globalThis.process;
55139
- threadProcess?.on?.("uncaughtException", (error) => core.reportUncaught(error));
55140
- threadProcess?.on?.("unhandledRejection", (reason) => core.reportUnhandledRejection(reason));
55299
+ hostThreadProcess?.on?.("uncaughtException", (error) => core.reportUncaught(error));
55300
+ hostThreadProcess?.on?.("unhandledRejection", (reason) => core.reportUnhandledRejection(reason));
55141
55301
  }
55142
55302
  const finish = (code) => {
55143
55303
  if (finished) return;
@@ -55210,7 +55370,7 @@ async function settle(router, owner, core, killed) {
55210
55370
  var sockets = /* @__PURE__ */ new Map();
55211
55371
  function openSocket(port, router, message) {
55212
55372
  const opened = router.connect(message.port, message.init, {
55213
- data: (bytes2) => port.postMessage({ type: "ws-data", id: message.id, data: bytes2 }),
55373
+ data: (bytes3) => port.postMessage({ type: "ws-data", id: message.id, data: bytes3 }),
55214
55374
  close: () => {
55215
55375
  sockets.delete(message.id);
55216
55376
  port.postMessage({ type: "ws-close", id: message.id });
@@ -0,0 +1,17 @@
1
+ # Next.js capability probe
2
+
3
+ Run `node examples/nextjs-probe.mjs` against a local build. It installs Next 16.3.8,
4
+ React 19.2 and requests a genuine App Router page. Successful CLI startup alone is
5
+ not sufficient: HTTP 200 and the rendered marker are required.
6
+
7
+ Observed on 2026-10-04: package installation succeeds and the CLI prints its startup
8
+ banner, but initialization fails with an undefined `typescript` property during
9
+ dev-bundler setup. The probe therefore exits unsuccessfully. Full Next.js support
10
+ is **not verified**. Do not publish a support claim or relabel a Vite app as Next.js.
11
+
12
+ For an interactive course, keep the real Next.js application as the download and
13
+ use a separately labeled Vite adapter importing the same React components for the
14
+ browser preview. Keep FastAPI and API contracts unchanged. Next-specific routing,
15
+ server components and builds still need a native Node environment until verified.
16
+
17
+ The probe is diagnostic only; no npm version bump or publication is included.