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