sandboxedjs 0.1.0 → 0.1.2

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/index.cjs CHANGED
@@ -3,8 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var headless = require('@scelar/nodepod/headless');
6
- var zlib = require('zlib');
7
- var crypto$1 = require('crypto');
6
+ var acorn = require('acorn');
8
7
 
9
8
  var __defProp = Object.defineProperty;
10
9
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -15137,6 +15136,206 @@ var commands5 = [grep, find, xargs, diff, cmp];
15137
15136
  // src/bin/archive.ts
15138
15137
  init_mode();
15139
15138
  init_path();
15139
+
15140
+ // src/util/binary.ts
15141
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
15142
+ async function nodeBuiltin(name) {
15143
+ const specifier = `node:${name}`;
15144
+ return await import(
15145
+ /* @vite-ignore */
15146
+ /* webpackIgnore: true */
15147
+ specifier
15148
+ );
15149
+ }
15150
+ var zlibPromise = null;
15151
+ function nodeZlib() {
15152
+ zlibPromise ??= nodeBuiltin("zlib");
15153
+ return zlibPromise;
15154
+ }
15155
+ async function throughStream(data, stream) {
15156
+ const source = new Blob([data]).stream();
15157
+ const piped = source.pipeThrough(stream);
15158
+ return new Uint8Array(await new Response(piped).arrayBuffer());
15159
+ }
15160
+ async function gzip(data) {
15161
+ if (isNode) return new Uint8Array((await nodeZlib()).gzipSync(data));
15162
+ return throughStream(data, new CompressionStream("gzip"));
15163
+ }
15164
+ async function gunzip(data) {
15165
+ if (isNode) return new Uint8Array((await nodeZlib()).gunzipSync(data));
15166
+ return throughStream(data, new DecompressionStream("gzip"));
15167
+ }
15168
+ async function deflate(data) {
15169
+ if (isNode) return new Uint8Array((await nodeZlib()).deflateSync(data));
15170
+ return throughStream(data, new CompressionStream("deflate"));
15171
+ }
15172
+ async function inflate(data) {
15173
+ if (isNode) return new Uint8Array((await nodeZlib()).inflateSync(data));
15174
+ return throughStream(data, new DecompressionStream("deflate"));
15175
+ }
15176
+ async function inflateRaw(data) {
15177
+ if (isNode) return new Uint8Array((await nodeZlib()).inflateRawSync(data));
15178
+ return throughStream(data, new DecompressionStream("deflate-raw"));
15179
+ }
15180
+ var cryptoPromise = null;
15181
+ function nodeCrypto() {
15182
+ cryptoPromise ??= nodeBuiltin("crypto");
15183
+ return cryptoPromise;
15184
+ }
15185
+ var SUBTLE_NAMES = {
15186
+ sha1: "SHA-1",
15187
+ sha256: "SHA-256",
15188
+ sha384: "SHA-384",
15189
+ sha512: "SHA-512"
15190
+ };
15191
+ var UnsupportedAlgorithmError = class extends Error {
15192
+ constructor(algorithm) {
15193
+ super(`${algorithm} is not available in this environment`);
15194
+ this.name = "UnsupportedAlgorithmError";
15195
+ }
15196
+ };
15197
+ async function digestHex(algorithm, data) {
15198
+ if (isNode) {
15199
+ const { createHash } = await nodeCrypto();
15200
+ return createHash(algorithm).update(data).digest("hex");
15201
+ }
15202
+ if (algorithm === "md5") return md5Hex(data);
15203
+ const name = SUBTLE_NAMES[algorithm];
15204
+ if (!name) throw new UnsupportedAlgorithmError(algorithm);
15205
+ const buffer = await crypto.subtle.digest(name, data);
15206
+ return toHex(new Uint8Array(buffer));
15207
+ }
15208
+ async function randomUuid() {
15209
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
15210
+ const { randomUUID } = await nodeCrypto();
15211
+ return randomUUID();
15212
+ }
15213
+ function toHex(bytes) {
15214
+ let out = "";
15215
+ for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
15216
+ return out;
15217
+ }
15218
+ function md5Hex(input) {
15219
+ const S = [
15220
+ 7,
15221
+ 12,
15222
+ 17,
15223
+ 22,
15224
+ 7,
15225
+ 12,
15226
+ 17,
15227
+ 22,
15228
+ 7,
15229
+ 12,
15230
+ 17,
15231
+ 22,
15232
+ 7,
15233
+ 12,
15234
+ 17,
15235
+ 22,
15236
+ 5,
15237
+ 9,
15238
+ 14,
15239
+ 20,
15240
+ 5,
15241
+ 9,
15242
+ 14,
15243
+ 20,
15244
+ 5,
15245
+ 9,
15246
+ 14,
15247
+ 20,
15248
+ 5,
15249
+ 9,
15250
+ 14,
15251
+ 20,
15252
+ 4,
15253
+ 11,
15254
+ 16,
15255
+ 23,
15256
+ 4,
15257
+ 11,
15258
+ 16,
15259
+ 23,
15260
+ 4,
15261
+ 11,
15262
+ 16,
15263
+ 23,
15264
+ 4,
15265
+ 11,
15266
+ 16,
15267
+ 23,
15268
+ 6,
15269
+ 10,
15270
+ 15,
15271
+ 21,
15272
+ 6,
15273
+ 10,
15274
+ 15,
15275
+ 21,
15276
+ 6,
15277
+ 10,
15278
+ 15,
15279
+ 21,
15280
+ 6,
15281
+ 10,
15282
+ 15,
15283
+ 21
15284
+ ];
15285
+ const K = new Uint32Array(64);
15286
+ for (let i = 0; i < 64; i++) K[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 2 ** 32);
15287
+ const bitLength = input.length * 8;
15288
+ const padded = new Uint8Array(((input.length + 8 >> 6) + 1) * 64);
15289
+ padded.set(input);
15290
+ padded[input.length] = 128;
15291
+ const view = new DataView(padded.buffer);
15292
+ view.setUint32(padded.length - 8, bitLength >>> 0, true);
15293
+ view.setUint32(padded.length - 4, Math.floor(bitLength / 2 ** 32), true);
15294
+ let a0 = 1732584193;
15295
+ let b0 = 4023233417;
15296
+ let c0 = 2562383102;
15297
+ let d0 = 271733878;
15298
+ for (let chunk = 0; chunk < padded.length; chunk += 64) {
15299
+ const M = new Uint32Array(16);
15300
+ for (let i = 0; i < 16; i++) M[i] = view.getUint32(chunk + i * 4, true);
15301
+ let [a, b, c, d] = [a0, b0, c0, d0];
15302
+ for (let i = 0; i < 64; i++) {
15303
+ let f;
15304
+ let g;
15305
+ if (i < 16) {
15306
+ f = b & c | ~b & d;
15307
+ g = i;
15308
+ } else if (i < 32) {
15309
+ f = d & b | ~d & c;
15310
+ g = (5 * i + 1) % 16;
15311
+ } else if (i < 48) {
15312
+ f = b ^ c ^ d;
15313
+ g = (3 * i + 5) % 16;
15314
+ } else {
15315
+ f = c ^ (b | ~d);
15316
+ g = 7 * i % 16;
15317
+ }
15318
+ const tmp = d;
15319
+ d = c;
15320
+ c = b;
15321
+ const sum = a + f + K[i] + M[g] >>> 0;
15322
+ b = b + (sum << S[i] | sum >>> 32 - S[i]) >>> 0;
15323
+ a = tmp;
15324
+ }
15325
+ a0 = a0 + a >>> 0;
15326
+ b0 = b0 + b >>> 0;
15327
+ c0 = c0 + c >>> 0;
15328
+ d0 = d0 + d >>> 0;
15329
+ }
15330
+ const out = new Uint8Array(16);
15331
+ new DataView(out.buffer).setUint32(0, a0, true);
15332
+ new DataView(out.buffer).setUint32(4, b0, true);
15333
+ new DataView(out.buffer).setUint32(8, c0, true);
15334
+ new DataView(out.buffer).setUint32(12, d0, true);
15335
+ return toHex(out);
15336
+ }
15337
+
15338
+ // src/bin/archive.ts
15140
15339
  var BLOCK = 512;
15141
15340
  var encoder4 = new TextEncoder();
15142
15341
  var decoder6 = new TextDecoder();
@@ -15294,7 +15493,7 @@ var tar = defineCommand({
15294
15493
  };
15295
15494
  for (const operand of args.positional) add(resolve(baseDir, operand), operand);
15296
15495
  let bytes2 = createTar(entries2);
15297
- if (compressed) bytes2 = new Uint8Array(zlib.gzipSync(bytes2));
15496
+ if (compressed) bytes2 = await gzip(bytes2);
15298
15497
  if (archive === void 0 || archive === "-") ctx.write(bytes2);
15299
15498
  else ctx.vfs.writeFile(ctx.path(archive), bytes2, { cred: ctx.cred, mode: 420 });
15300
15499
  return 0;
@@ -15308,7 +15507,7 @@ var tar = defineCommand({
15308
15507
  return ctx.reportError(e, archive);
15309
15508
  }
15310
15509
  }
15311
- if (bytes[0] === 31 && bytes[1] === 139) bytes = new Uint8Array(zlib.gunzipSync(bytes));
15510
+ if (bytes[0] === 31 && bytes[1] === 139) bytes = await gunzip(bytes);
15312
15511
  const entries = readTar(bytes);
15313
15512
  const strip = args.num("strip-components", 0);
15314
15513
  if (args.has("list")) {
@@ -15354,7 +15553,7 @@ var tar = defineCommand({
15354
15553
  return 2;
15355
15554
  }
15356
15555
  });
15357
- var gzip = defineCommand({
15556
+ var gzip2 = defineCommand({
15358
15557
  name: "gzip",
15359
15558
  path: "/bin/gzip",
15360
15559
  summary: "compress files",
@@ -15377,28 +15576,28 @@ var gzip = defineCommand({
15377
15576
  toStdout,
15378
15577
  keep: args.has("keep") || ctx.name === "zcat",
15379
15578
  suffix: ".gz",
15380
- compress: (data) => new Uint8Array(zlib.gzipSync(data)),
15381
- expand: (data) => new Uint8Array(zlib.gunzipSync(data))
15579
+ compress: (data) => gzip(data),
15580
+ expand: (data) => gunzip(data)
15382
15581
  });
15383
15582
  }
15384
15583
  });
15385
- var gunzip = defineCommand({
15584
+ var gunzip2 = defineCommand({
15386
15585
  name: "gunzip",
15387
15586
  path: "/bin/gunzip",
15388
15587
  summary: "decompress files",
15389
- run: (ctx) => gzip.run(ctx)
15588
+ run: (ctx) => gzip2.run(ctx)
15390
15589
  });
15391
15590
  var zcat = defineCommand({
15392
15591
  name: "zcat",
15393
15592
  path: "/bin/zcat",
15394
15593
  summary: "decompress files to standard output",
15395
- run: (ctx) => gzip.run(ctx)
15594
+ run: (ctx) => gzip2.run(ctx)
15396
15595
  });
15397
15596
  async function runCompressor(ctx, operands, opts) {
15398
15597
  if (operands.length === 0) {
15399
15598
  const data = await ctx.stdin.readAll();
15400
15599
  try {
15401
- ctx.write(opts.decompress ? opts.expand(data) : opts.compress(data));
15600
+ ctx.write(opts.decompress ? await opts.expand(data) : await opts.compress(data));
15402
15601
  return 0;
15403
15602
  } catch (e) {
15404
15603
  return ctx.fail(e instanceof Error ? e.message : String(e));
@@ -15415,7 +15614,7 @@ async function runCompressor(ctx, operands, opts) {
15415
15614
  continue;
15416
15615
  }
15417
15616
  try {
15418
- const result = opts.decompress ? opts.expand(data) : opts.compress(data);
15617
+ const result = opts.decompress ? await opts.expand(data) : await opts.compress(data);
15419
15618
  if (opts.toStdout) {
15420
15619
  ctx.write(result);
15421
15620
  continue;
@@ -15441,12 +15640,14 @@ var zlibCompress = defineCommand({
15441
15640
  toStdout: args.has("stdout"),
15442
15641
  keep: false,
15443
15642
  suffix: ".Z",
15444
- compress: (data) => new Uint8Array(zlib.deflateSync(data)),
15445
- expand: (data) => new Uint8Array(zlib.inflateSync(data))
15643
+ compress: (data) => deflate(data),
15644
+ expand: (data) => inflate(data)
15446
15645
  });
15447
15646
  }
15448
15647
  });
15449
- var commands6 = [tar, gzip, gunzip, zcat, zlibCompress];
15648
+ var commands6 = [tar, gzip2, gunzip2, zcat, zlibCompress];
15649
+
15650
+ // src/bin/hash.ts
15450
15651
  function makeSum(name, algorithm, path) {
15451
15652
  return defineCommand({
15452
15653
  name,
@@ -15465,7 +15666,7 @@ function makeSum(name, algorithm, path) {
15465
15666
  if (args.has("check")) return checkSums(ctx, algorithm, args.positional, args.has("quiet") || args.has("status"));
15466
15667
  const { sources, ok } = await readInputs(ctx, args.positional, { stdinName: "-" });
15467
15668
  for (const source of sources) {
15468
- const digest = crypto$1.createHash(algorithm).update(source.bytes).digest("hex");
15669
+ const digest = await digestHex(algorithm, source.bytes);
15469
15670
  if (args.has("tag")) ctx.line(`${algorithm.toUpperCase()} (${source.name}) = ${digest}`);
15470
15671
  else ctx.line(`${digest} ${source.name}`);
15471
15672
  }
@@ -15486,7 +15687,7 @@ async function checkSums(ctx, algorithm, files, quiet) {
15486
15687
  const [, expected, name] = m;
15487
15688
  try {
15488
15689
  const bytes = ctx.vfs.readFile(ctx.path(name), ctx.cred);
15489
- const actual = crypto$1.createHash(algorithm).update(bytes).digest("hex");
15690
+ const actual = await digestHex(algorithm, bytes);
15490
15691
  if (actual === expected.toLowerCase()) {
15491
15692
  if (!quiet) ctx.line(`${name}: OK`);
15492
15693
  } else {
@@ -15617,8 +15818,8 @@ var uuidgen = defineCommand({
15617
15818
  name: "uuidgen",
15618
15819
  path: "/usr/bin/uuidgen",
15619
15820
  summary: "create a new UUID value",
15620
- run(ctx) {
15621
- ctx.line(crypto$1.randomUUID());
15821
+ async run(ctx) {
15822
+ ctx.line(await randomUuid());
15622
15823
  return 0;
15623
15824
  }
15624
15825
  });
@@ -17692,7 +17893,7 @@ var pip = defineCommand({
17692
17893
  }
17693
17894
  const data = new Uint8Array(await (await fetch(wheel.url)).arrayBuffer());
17694
17895
  ctx.line(` Downloading ${wheel.filename} (${Math.round(data.length / 1024)} kB)`);
17695
- installWheel(ctx, siteDir, data, name, chosen);
17896
+ await installWheel(ctx, siteDir, data, name, chosen);
17696
17897
  ctx.line(`Successfully installed ${name}-${chosen}`);
17697
17898
  } catch (e) {
17698
17899
  ctx.warn(`ERROR: Could not install ${spec}: ${e instanceof Error ? e.message : String(e)}`);
@@ -17702,8 +17903,8 @@ var pip = defineCommand({
17702
17903
  return status;
17703
17904
  }
17704
17905
  });
17705
- function installWheel(ctx, siteDir, data, name, version) {
17706
- const entries = readZip(data);
17906
+ async function installWheel(ctx, siteDir, data, name, version) {
17907
+ const entries = await readZip(data);
17707
17908
  for (const entry of entries) {
17708
17909
  if (entry.name.endsWith("/")) continue;
17709
17910
  const target = join(siteDir, entry.name);
@@ -17717,7 +17918,7 @@ function installWheel(ctx, siteDir, data, name, version) {
17717
17918
  Version: ${version}
17718
17919
  `, { cred: ctx.cred });
17719
17920
  }
17720
- function readZip(data) {
17921
+ async function readZip(data) {
17721
17922
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
17722
17923
  const entries = [];
17723
17924
  let eocd = -1;
@@ -17743,7 +17944,7 @@ function readZip(data) {
17743
17944
  const localExtraLength = view.getUint16(localOffset + 28, true);
17744
17945
  const dataStart = localOffset + 30 + localNameLength + localExtraLength;
17745
17946
  const raw = data.subarray(dataStart, dataStart + compressedSize);
17746
- entries.push({ name, data: method === 0 ? raw.slice() : new Uint8Array(zlib.inflateRawSync(raw)) });
17947
+ entries.push({ name, data: method === 0 ? raw.slice() : await inflateRaw(raw) });
17747
17948
  offset += 46 + nameLength + extraLength + commentLength;
17748
17949
  }
17749
17950
  return entries;
@@ -17751,6 +17952,226 @@ function readZip(data) {
17751
17952
  function pythonCommands() {
17752
17953
  return [python, pip];
17753
17954
  }
17955
+ var DECLARES_EXPORTS = /(?:^|[\s;{)])(?:var|let|const|function|class)\s+exports\b/;
17956
+ var NAME = "exports";
17957
+ function renameShadowedExports(source) {
17958
+ if (!DECLARES_EXPORTS.test(source)) return null;
17959
+ let ast;
17960
+ try {
17961
+ ast = acorn.parse(source, {
17962
+ ecmaVersion: "latest",
17963
+ sourceType: "module",
17964
+ allowAwaitOutsideFunction: true,
17965
+ allowHashBang: true
17966
+ });
17967
+ } catch {
17968
+ return null;
17969
+ }
17970
+ const body = ast.body;
17971
+ const isModule = body.some(
17972
+ (node2) => node2.type.startsWith("Import") || node2.type.startsWith("Export")
17973
+ );
17974
+ if (!isModule) return null;
17975
+ const programScope = { bindsExports: hoistedNames(body).has(NAME), parent: null };
17976
+ if (!programScope.bindsExports) return null;
17977
+ const targets = [];
17978
+ let bail = false;
17979
+ visit(ast, programScope);
17980
+ if (bail || targets.length === 0) return null;
17981
+ const replacement = freshName(source);
17982
+ let out = source;
17983
+ for (const target of [...targets].sort((a, b) => b.start - a.start)) {
17984
+ const text = target.shorthand ? `${NAME}: ${replacement}` : replacement;
17985
+ out = out.slice(0, target.start) + text + out.slice(target.end);
17986
+ }
17987
+ return out;
17988
+ function visit(node2, scope) {
17989
+ if (bail) return;
17990
+ let childScope = scope;
17991
+ let skip = NOTHING;
17992
+ switch (node2.type) {
17993
+ case "FunctionDeclaration":
17994
+ case "FunctionExpression":
17995
+ case "ArrowFunctionExpression": {
17996
+ const names = /* @__PURE__ */ new Set();
17997
+ for (const param of node2.params ?? []) collectPattern(param, names);
17998
+ if (isExports(node2.id) && node2.type === "FunctionExpression") names.add(NAME);
17999
+ const fnBody = node2.body;
18000
+ if (fnBody?.type === "BlockStatement") {
18001
+ for (const name of hoistedNames(fnBody.body)) names.add(name);
18002
+ }
18003
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18004
+ break;
18005
+ }
18006
+ case "CatchClause": {
18007
+ const names = /* @__PURE__ */ new Set();
18008
+ if (node2.param) collectPattern(node2.param, names);
18009
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18010
+ break;
18011
+ }
18012
+ case "ClassDeclaration":
18013
+ case "ClassExpression":
18014
+ if (isExports(node2.id) && node2.type === "ClassExpression") {
18015
+ childScope = { bindsExports: true, parent: scope };
18016
+ }
18017
+ break;
18018
+ case "BlockStatement":
18019
+ case "StaticBlock":
18020
+ if (node2 !== ast.body) {
18021
+ childScope = {
18022
+ bindsExports: blockNames(node2.body).has(NAME),
18023
+ parent: scope
18024
+ };
18025
+ }
18026
+ break;
18027
+ case "ForStatement":
18028
+ case "ForInStatement":
18029
+ case "ForOfStatement": {
18030
+ const head2 = node2.init ?? node2.left;
18031
+ if (head2?.type === "VariableDeclaration" && head2.kind !== "var") {
18032
+ const names = /* @__PURE__ */ new Set();
18033
+ for (const declarator of head2.declarations) {
18034
+ collectPattern(declarator.id, names);
18035
+ }
18036
+ childScope = { bindsExports: names.has(NAME), parent: scope };
18037
+ }
18038
+ break;
18039
+ }
18040
+ /* `export { exports }` would have to become `exports as exports`, and
18041
+ * `import { exports as x }` names someone else's binding. Neither is
18042
+ * worth handling; refuse rather than rewrite them wrongly. */
18043
+ case "ExportSpecifier":
18044
+ case "ImportSpecifier":
18045
+ if (isExports(node2.local) || isExports(node2.exported) || isExports(node2.imported)) {
18046
+ bail = true;
18047
+ }
18048
+ return;
18049
+ case "Identifier":
18050
+ if (node2.name === NAME && resolvesToProgram(scope)) {
18051
+ targets.push({ start: node2.start, end: node2.end, shorthand: false });
18052
+ }
18053
+ return;
18054
+ // Property positions are names, not references to the binding.
18055
+ case "MemberExpression":
18056
+ case "MethodDefinition":
18057
+ case "PropertyDefinition":
18058
+ skip = node2.computed ? NOTHING : PROPERTY;
18059
+ break;
18060
+ case "Property":
18061
+ if (node2.computed) break;
18062
+ if (node2.shorthand) {
18063
+ const value = node2.value;
18064
+ if (isExports(value) && resolvesToProgram(scope)) {
18065
+ targets.push({ start: value.start, end: value.end, shorthand: true });
18066
+ }
18067
+ return;
18068
+ }
18069
+ skip = PROPERTY;
18070
+ break;
18071
+ case "LabeledStatement":
18072
+ case "BreakStatement":
18073
+ case "ContinueStatement":
18074
+ skip = LABEL;
18075
+ break;
18076
+ }
18077
+ for (const [key, value] of Object.entries(node2)) {
18078
+ if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
18079
+ if (Array.isArray(value)) {
18080
+ for (const item of value) if (isNode2(item)) visit(item, childScope);
18081
+ } else if (isNode2(value)) {
18082
+ visit(value, childScope);
18083
+ }
18084
+ }
18085
+ }
18086
+ }
18087
+ function resolvesToProgram(scope) {
18088
+ for (let current = scope; current; current = current.parent) {
18089
+ if (current.bindsExports) return current.parent === null;
18090
+ }
18091
+ return false;
18092
+ }
18093
+ function hoistedNames(body) {
18094
+ const names = blockNames(body);
18095
+ collectVars(body, names);
18096
+ return names;
18097
+ }
18098
+ function blockNames(body) {
18099
+ const names = /* @__PURE__ */ new Set();
18100
+ for (const node2 of body ?? []) {
18101
+ if (node2.type === "VariableDeclaration" && node2.kind !== "var") {
18102
+ for (const declarator of node2.declarations) {
18103
+ collectPattern(declarator.id, names);
18104
+ }
18105
+ } else if (node2.type === "ClassDeclaration" && isNode2(node2.id)) {
18106
+ names.add(node2.id.name);
18107
+ } else if (node2.type === "FunctionDeclaration" && isNode2(node2.id)) {
18108
+ names.add(node2.id.name);
18109
+ }
18110
+ }
18111
+ return names;
18112
+ }
18113
+ function collectVars(nodes, names) {
18114
+ if (Array.isArray(nodes)) {
18115
+ for (const item of nodes) collectVars(item, names);
18116
+ return;
18117
+ }
18118
+ if (!isNode2(nodes)) return;
18119
+ const node2 = nodes;
18120
+ if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
18121
+ if (isNode2(node2.id)) names.add(node2.id.name);
18122
+ return;
18123
+ }
18124
+ if (node2.type === "VariableDeclaration" && node2.kind === "var") {
18125
+ for (const declarator of node2.declarations) {
18126
+ collectPattern(declarator.id, names);
18127
+ }
18128
+ }
18129
+ for (const [key, value] of Object.entries(node2)) {
18130
+ if (key === "type" || key === "start" || key === "end") continue;
18131
+ collectVars(value, names);
18132
+ }
18133
+ }
18134
+ function collectPattern(node2, names) {
18135
+ if (!isNode2(node2)) return;
18136
+ switch (node2.type) {
18137
+ case "Identifier":
18138
+ names.add(node2.name);
18139
+ return;
18140
+ case "ObjectPattern":
18141
+ for (const property of node2.properties) {
18142
+ collectPattern(property.value ?? property.argument, names);
18143
+ }
18144
+ return;
18145
+ case "ArrayPattern":
18146
+ for (const element of node2.elements) collectPattern(element, names);
18147
+ return;
18148
+ case "AssignmentPattern":
18149
+ collectPattern(node2.left, names);
18150
+ return;
18151
+ case "RestElement":
18152
+ collectPattern(node2.argument, names);
18153
+ return;
18154
+ default:
18155
+ return;
18156
+ }
18157
+ }
18158
+ function isExports(value) {
18159
+ return isNode2(value) && value.type === "Identifier" && value.name === NAME;
18160
+ }
18161
+ function freshName(source) {
18162
+ let name = "__sandboxedjs_exports";
18163
+ let suffix = 0;
18164
+ while (source.includes(name)) name = `__sandboxedjs_exports${++suffix}`;
18165
+ return name;
18166
+ }
18167
+ function isNode2(value) {
18168
+ return typeof value === "object" && value !== null && typeof value.type === "string";
18169
+ }
18170
+ var NOTHING = [];
18171
+ var PROPERTY = ["property", "key"];
18172
+ var LABEL = ["label"];
18173
+
18174
+ // src/pkg/index.ts
17754
18175
  init_path();
17755
18176
  var NPM_VERSION = "10.9.0";
17756
18177
  function readManifest(ctx, dir3) {
@@ -17774,9 +18195,17 @@ function findProjectRoot(ctx) {
17774
18195
  function writeManifest(ctx, path, manifest) {
17775
18196
  ctx.vfs.writeFile(path, JSON.stringify(manifest, null, 2) + "\n", { cred: ctx.cred, mode: 420 });
17776
18197
  }
18198
+ function splitPackageSpec(spec) {
18199
+ const at = spec.lastIndexOf("@");
18200
+ if (at <= 0) return { name: spec };
18201
+ return { name: spec.slice(0, at), version: spec.slice(at + 1) };
18202
+ }
17777
18203
  async function installPackages(ctx, specs, opts) {
17778
18204
  const installer = opts.cwd === "/" ? ctx.kernel.pod.packages : new headless.DependencyInstaller(ctx.vfs.volume, { cwd: opts.cwd });
17779
- const onProgress = (message) => ctx.stderr.write(message.endsWith("\n") ? message : message + "\n");
18205
+ const onProgress = (message) => {
18206
+ if (!opts.quiet) ctx.stderr.write(message.endsWith("\n") ? message : message + "\n");
18207
+ };
18208
+ const note = (text) => opts.quiet ? ctx.stderr.write(text + "\n") : ctx.line(text);
17780
18209
  if (!ctx.kernel.net.options.allowOutbound) {
17781
18210
  ctx.warn("npm error code ENOTFOUND");
17782
18211
  ctx.warn("npm error network request to https://registry.npmjs.org failed");
@@ -17786,7 +18215,7 @@ async function installPackages(ctx, specs, opts) {
17786
18215
  }
17787
18216
  try {
17788
18217
  if (specs.length === 0) {
17789
- ctx.line(`npm install (project at ${opts.cwd})`);
18218
+ note(`npm install (project at ${opts.cwd})`);
17790
18219
  await installer.installFromManifest(join(opts.cwd, "package.json"), {
17791
18220
  withDevDeps: true,
17792
18221
  onProgress,
@@ -17794,11 +18223,8 @@ async function installPackages(ctx, specs, opts) {
17794
18223
  });
17795
18224
  } else {
17796
18225
  for (const spec of specs) {
17797
- const at = spec.lastIndexOf("@");
17798
- const scoped = spec.startsWith("@");
17799
- const name = at > 0 && !(scoped && at === 0) ? spec.slice(0, at) : spec;
17800
- const version = at > 0 && !(scoped && at === 0) ? spec.slice(at + 1) : void 0;
17801
- ctx.line(`added ${name}${version ? `@${version}` : ""}`);
18226
+ const { name, version } = splitPackageSpec(spec);
18227
+ note(`added ${name}${version ? `@${version}` : ""}`);
17802
18228
  await installer.install(name, version, {
17803
18229
  onProgress,
17804
18230
  persist: opts.save !== false,
@@ -17807,6 +18233,7 @@ async function installPackages(ctx, specs, opts) {
17807
18233
  }
17808
18234
  }
17809
18235
  normalizeBinDirectories(ctx, opts.cwd);
18236
+ normalizeEsmExports(ctx, opts.cwd);
17810
18237
  return 0;
17811
18238
  } catch (e) {
17812
18239
  ctx.warn(`npm error ${e instanceof Error ? e.message : String(e)}`);
@@ -18030,6 +18457,20 @@ function normalizeBinDirectories(ctx, root) {
18030
18457
  if (basename(path) === ".bin" && path !== join(modules, ".bin")) visit(path);
18031
18458
  }
18032
18459
  }
18460
+ function normalizeEsmExports(ctx, root) {
18461
+ const modules = join(root, "node_modules");
18462
+ if (!ctx.vfs.lexists(modules)) return;
18463
+ for (const path of ctx.vfs.walk(modules, { cred: ctx.cred })) {
18464
+ if (!/\.(?:js|mjs)$/.test(path)) continue;
18465
+ try {
18466
+ if (!ctx.vfs.lstat(path).isFile()) continue;
18467
+ const source = ctx.vfs.readText(path, ctx.cred);
18468
+ const repaired = renameShadowedExports(source);
18469
+ if (repaired !== null) ctx.vfs.writeFile(path, repaired, { privileged: true });
18470
+ } catch {
18471
+ }
18472
+ }
18473
+ }
18033
18474
  function printNpmHelp(ctx) {
18034
18475
  ctx.line(`npm <command>`);
18035
18476
  ctx.line("");
@@ -18042,33 +18483,127 @@ function printNpmHelp(ctx) {
18042
18483
  ctx.line("");
18043
18484
  ctx.line(`npm@${NPM_VERSION} /usr/lib/node_modules/npm`);
18044
18485
  }
18486
+ function packageBinaries(ctx, root, packageName) {
18487
+ const manifestPath = join(root, "node_modules", packageName, "package.json");
18488
+ try {
18489
+ const manifest = JSON.parse(ctx.vfs.readText(manifestPath, ctx.cred));
18490
+ if (typeof manifest.bin === "string") return [basename(packageName)];
18491
+ if (manifest.bin && typeof manifest.bin === "object") return Object.keys(manifest.bin);
18492
+ } catch {
18493
+ }
18494
+ return [];
18495
+ }
18496
+ function findLocalBin(ctx, name) {
18497
+ let dir3 = ctx.cwd;
18498
+ for (let i = 0; i < 64; i++) {
18499
+ const candidate = join(dir3, "node_modules", ".bin", name);
18500
+ if (ctx.vfs.lexists(candidate)) return candidate;
18501
+ const parent = dirname(dir3);
18502
+ if (parent === dir3) break;
18503
+ dir3 = parent;
18504
+ }
18505
+ return null;
18506
+ }
18045
18507
  var npx = defineCommand({
18046
18508
  name: "npx",
18047
18509
  path: "/usr/bin/npx",
18048
18510
  summary: "run a command from a local or remote npm package",
18511
+ usage: "npx [-y] [-p package] <command> [args]",
18512
+ manual: `Runs a package binary, installing the package first if it is not
18513
+ already present. Installation needs outbound network access, which is off
18514
+ unless the container was created with network: { allowOutbound: true }.`,
18049
18515
  async run(ctx) {
18050
- const args = parseArgs(ctx.args, [{ short: "y", long: "yes" }, { long: "no-install" }, { short: "p", long: "package", arg: true }], {
18051
- stopAtFirstPositional: true
18052
- });
18053
- if (args.positional.length === 0) return ctx.fail("npx: a command is required", 1);
18516
+ const args = parseArgs(
18517
+ ctx.args,
18518
+ [
18519
+ { short: "y", long: "yes" },
18520
+ { long: "no-install" },
18521
+ { short: "p", long: "package", arg: true, multiple: true },
18522
+ { short: "q", long: "quiet" },
18523
+ { short: "c", long: "call", arg: true },
18524
+ { long: "version" },
18525
+ { long: "help" }
18526
+ ],
18527
+ { stopAtFirstPositional: true, allowUnknown: true }
18528
+ );
18529
+ if (args.has("version")) {
18530
+ ctx.line(NPM_VERSION);
18531
+ return 0;
18532
+ }
18533
+ if (args.has("help")) {
18534
+ ctx.line("Usage: npx [options] <command>[@version] [command-arg]...");
18535
+ ctx.line("");
18536
+ ctx.line("Options:");
18537
+ ctx.line(" -y, --yes skip the install confirmation (always implied here)");
18538
+ ctx.line(" -p, --package <pkg> package providing the command (repeatable)");
18539
+ ctx.line(" --no-install fail instead of installing a missing package");
18540
+ ctx.line(" -q, --quiet suppress install progress");
18541
+ return 0;
18542
+ }
18543
+ const call = args.str("call");
18544
+ const operands = call ? call.split(/\s+/).filter(Boolean) : args.positional;
18545
+ if (operands.length === 0) {
18546
+ ctx.warn("a command is required");
18547
+ ctx.warn("usage: npx [options] <command>[@version] [command-arg]...");
18548
+ return 1;
18549
+ }
18054
18550
  const root = findProjectRoot(ctx);
18055
- const [name, ...rest] = args.positional;
18056
- const binPath = join(root, "node_modules", ".bin", name);
18057
- if (!ctx.vfs.lexists(binPath) && ctx.kernel.net.options.allowOutbound) {
18058
- ctx.stderr.write(`npx: installing ${name}...
18551
+ const binDir = join(root, "node_modules", ".bin");
18552
+ const [spec, ...rest] = operands;
18553
+ const { name: specName, version } = splitPackageSpec(spec);
18554
+ const packages = args.list("package");
18555
+ const packageSpec = packages[0] ?? spec;
18556
+ const packageName = packages[0] ? splitPackageSpec(packages[0]).name : specName;
18557
+ let command = packages.length > 0 ? spec : basename(specName);
18558
+ const run = async (binary) => {
18559
+ const env2 = {
18560
+ ...ctx.env,
18561
+ PATH: `${binDir}:${ctx.env.PATH ?? ""}`,
18562
+ npm_config_user_agent: `npm/${NPM_VERSION} node/${NODE_VERSION} linux x64`
18563
+ };
18564
+ return await ctx.kernel.spawn([binary, ...rest], {
18565
+ cwd: ctx.cwd,
18566
+ env: env2,
18567
+ cred: ctx.cred,
18568
+ ppid: ctx.proc.pid,
18569
+ stdin: ctx.stdin,
18570
+ stdout: ctx.stdout,
18571
+ stderr: ctx.stderr
18572
+ }).wait();
18573
+ };
18574
+ if (!version) {
18575
+ if (findLocalBin(ctx, command)) return run(command);
18576
+ if (ctx.kernel.which(command, ctx.cwd, ctx.env, ctx.cred)) return run(command);
18577
+ }
18578
+ if (args.has("no-install")) {
18579
+ ctx.warn(`command not found: ${command}`);
18580
+ return 127;
18581
+ }
18582
+ if (!ctx.kernel.net.options.allowOutbound) {
18583
+ ctx.warn(`could not determine executable to run: ${command}`);
18584
+ ctx.warn(`'${packageName}' is not installed, and installing it needs network access.`);
18585
+ ctx.warn("Outbound network access is disabled for this container.");
18586
+ ctx.warn("Enable it with createContainer({ network: { allowOutbound: true } }).");
18587
+ return 127;
18588
+ }
18589
+ ctx.stderr.write(`npx: installing ${packageSpec}...
18059
18590
  `);
18060
- await installPackages(ctx, [name], { cwd: root, save: false });
18591
+ const installed = await installPackages(ctx, [packageSpec], {
18592
+ cwd: root,
18593
+ save: false,
18594
+ quiet: true
18595
+ });
18596
+ if (installed !== 0) return installed;
18597
+ if (!findLocalBin(ctx, command)) {
18598
+ const binaries = packageBinaries(ctx, root, packageName);
18599
+ const chosen = binaries.includes(command) ? command : binaries[0];
18600
+ if (chosen === void 0) {
18601
+ ctx.warn(`could not determine executable to run: ${packageName} provides no binary`);
18602
+ return 127;
18603
+ }
18604
+ command = chosen;
18061
18605
  }
18062
- const env2 = { ...ctx.env, PATH: `${join(root, "node_modules", ".bin")}:${ctx.env.PATH ?? ""}` };
18063
- return await ctx.kernel.spawn([name, ...rest], {
18064
- cwd: ctx.cwd,
18065
- env: env2,
18066
- cred: ctx.cred,
18067
- ppid: ctx.proc.pid,
18068
- stdin: ctx.stdin,
18069
- stdout: ctx.stdout,
18070
- stderr: ctx.stderr
18071
- }).wait();
18606
+ return run(command);
18072
18607
  }
18073
18608
  });
18074
18609
  function makeNpmAlias(name, path) {
@@ -18487,7 +19022,7 @@ var Container = class _Container {
18487
19022
  }
18488
19023
  // ── boot ──────────────────────────────────────────────────────────────────
18489
19024
  static async create(opts = {}) {
18490
- const pod = await headless.Nodepod.boot({
19025
+ const pod = opts.pod ?? await headless.Nodepod.boot({
18491
19026
  headless: true,
18492
19027
  serviceWorker: false,
18493
19028
  env: opts.env ?? {},
@@ -18538,8 +19073,8 @@ var Container = class _Container {
18538
19073
  /** Copy a directory tree from the host filesystem into the container. */
18539
19074
  async copyIn(hostPath, containerPath) {
18540
19075
  this.assertActive();
18541
- const { readdir, readFile, stat: stat2 } = await import('fs/promises');
18542
- const nodePath = await import('path');
19076
+ const { readdir, readFile, stat: stat2 } = await nodeBuiltin("fs/promises");
19077
+ const nodePath = await nodeBuiltin("path");
18543
19078
  const walk = async (src, dest) => {
18544
19079
  const st = await stat2(src);
18545
19080
  if (st.isDirectory()) {
@@ -18566,8 +19101,8 @@ var Container = class _Container {
18566
19101
  /** Copy a file or directory out of the container onto the host. */
18567
19102
  async copyOut(containerPath, hostPath) {
18568
19103
  this.assertActive();
18569
- const { mkdir: mkdir2, writeFile } = await import('fs/promises');
18570
- const nodePath = await import('path');
19104
+ const { mkdir: mkdir2, writeFile } = await nodeBuiltin("fs/promises");
19105
+ const nodePath = await nodeBuiltin("path");
18571
19106
  const src = resolve(this.defaults.cwd, containerPath);
18572
19107
  const walk = async (from, to) => {
18573
19108
  const st = this.kernel.vfs.lstat(from);
@@ -18791,7 +19326,7 @@ var Container = class _Container {
18791
19326
  */
18792
19327
  async expose(port, opts = {}) {
18793
19328
  this.assertActive();
18794
- const http = await import('http');
19329
+ const http = await nodeBuiltin("http");
18795
19330
  const container = this;
18796
19331
  const server = http.createServer((req, res) => {
18797
19332
  const chunks = [];