sandboxedjs 0.1.0 → 0.1.1

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,6 @@
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');
8
6
 
9
7
  var __defProp = Object.defineProperty;
10
8
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -15137,6 +15135,206 @@ var commands5 = [grep, find, xargs, diff, cmp];
15137
15135
  // src/bin/archive.ts
15138
15136
  init_mode();
15139
15137
  init_path();
15138
+
15139
+ // src/util/binary.ts
15140
+ var isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
15141
+ async function nodeBuiltin(name) {
15142
+ const specifier = `node:${name}`;
15143
+ return await import(
15144
+ /* @vite-ignore */
15145
+ /* webpackIgnore: true */
15146
+ specifier
15147
+ );
15148
+ }
15149
+ var zlibPromise = null;
15150
+ function nodeZlib() {
15151
+ zlibPromise ??= nodeBuiltin("zlib");
15152
+ return zlibPromise;
15153
+ }
15154
+ async function throughStream(data, stream) {
15155
+ const source = new Blob([data]).stream();
15156
+ const piped = source.pipeThrough(stream);
15157
+ return new Uint8Array(await new Response(piped).arrayBuffer());
15158
+ }
15159
+ async function gzip(data) {
15160
+ if (isNode) return new Uint8Array((await nodeZlib()).gzipSync(data));
15161
+ return throughStream(data, new CompressionStream("gzip"));
15162
+ }
15163
+ async function gunzip(data) {
15164
+ if (isNode) return new Uint8Array((await nodeZlib()).gunzipSync(data));
15165
+ return throughStream(data, new DecompressionStream("gzip"));
15166
+ }
15167
+ async function deflate(data) {
15168
+ if (isNode) return new Uint8Array((await nodeZlib()).deflateSync(data));
15169
+ return throughStream(data, new CompressionStream("deflate"));
15170
+ }
15171
+ async function inflate(data) {
15172
+ if (isNode) return new Uint8Array((await nodeZlib()).inflateSync(data));
15173
+ return throughStream(data, new DecompressionStream("deflate"));
15174
+ }
15175
+ async function inflateRaw(data) {
15176
+ if (isNode) return new Uint8Array((await nodeZlib()).inflateRawSync(data));
15177
+ return throughStream(data, new DecompressionStream("deflate-raw"));
15178
+ }
15179
+ var cryptoPromise = null;
15180
+ function nodeCrypto() {
15181
+ cryptoPromise ??= nodeBuiltin("crypto");
15182
+ return cryptoPromise;
15183
+ }
15184
+ var SUBTLE_NAMES = {
15185
+ sha1: "SHA-1",
15186
+ sha256: "SHA-256",
15187
+ sha384: "SHA-384",
15188
+ sha512: "SHA-512"
15189
+ };
15190
+ var UnsupportedAlgorithmError = class extends Error {
15191
+ constructor(algorithm) {
15192
+ super(`${algorithm} is not available in this environment`);
15193
+ this.name = "UnsupportedAlgorithmError";
15194
+ }
15195
+ };
15196
+ async function digestHex(algorithm, data) {
15197
+ if (isNode) {
15198
+ const { createHash } = await nodeCrypto();
15199
+ return createHash(algorithm).update(data).digest("hex");
15200
+ }
15201
+ if (algorithm === "md5") return md5Hex(data);
15202
+ const name = SUBTLE_NAMES[algorithm];
15203
+ if (!name) throw new UnsupportedAlgorithmError(algorithm);
15204
+ const buffer = await crypto.subtle.digest(name, data);
15205
+ return toHex(new Uint8Array(buffer));
15206
+ }
15207
+ async function randomUuid() {
15208
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
15209
+ const { randomUUID } = await nodeCrypto();
15210
+ return randomUUID();
15211
+ }
15212
+ function toHex(bytes) {
15213
+ let out = "";
15214
+ for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
15215
+ return out;
15216
+ }
15217
+ function md5Hex(input) {
15218
+ const S = [
15219
+ 7,
15220
+ 12,
15221
+ 17,
15222
+ 22,
15223
+ 7,
15224
+ 12,
15225
+ 17,
15226
+ 22,
15227
+ 7,
15228
+ 12,
15229
+ 17,
15230
+ 22,
15231
+ 7,
15232
+ 12,
15233
+ 17,
15234
+ 22,
15235
+ 5,
15236
+ 9,
15237
+ 14,
15238
+ 20,
15239
+ 5,
15240
+ 9,
15241
+ 14,
15242
+ 20,
15243
+ 5,
15244
+ 9,
15245
+ 14,
15246
+ 20,
15247
+ 5,
15248
+ 9,
15249
+ 14,
15250
+ 20,
15251
+ 4,
15252
+ 11,
15253
+ 16,
15254
+ 23,
15255
+ 4,
15256
+ 11,
15257
+ 16,
15258
+ 23,
15259
+ 4,
15260
+ 11,
15261
+ 16,
15262
+ 23,
15263
+ 4,
15264
+ 11,
15265
+ 16,
15266
+ 23,
15267
+ 6,
15268
+ 10,
15269
+ 15,
15270
+ 21,
15271
+ 6,
15272
+ 10,
15273
+ 15,
15274
+ 21,
15275
+ 6,
15276
+ 10,
15277
+ 15,
15278
+ 21,
15279
+ 6,
15280
+ 10,
15281
+ 15,
15282
+ 21
15283
+ ];
15284
+ const K = new Uint32Array(64);
15285
+ for (let i = 0; i < 64; i++) K[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 2 ** 32);
15286
+ const bitLength = input.length * 8;
15287
+ const padded = new Uint8Array(((input.length + 8 >> 6) + 1) * 64);
15288
+ padded.set(input);
15289
+ padded[input.length] = 128;
15290
+ const view = new DataView(padded.buffer);
15291
+ view.setUint32(padded.length - 8, bitLength >>> 0, true);
15292
+ view.setUint32(padded.length - 4, Math.floor(bitLength / 2 ** 32), true);
15293
+ let a0 = 1732584193;
15294
+ let b0 = 4023233417;
15295
+ let c0 = 2562383102;
15296
+ let d0 = 271733878;
15297
+ for (let chunk = 0; chunk < padded.length; chunk += 64) {
15298
+ const M = new Uint32Array(16);
15299
+ for (let i = 0; i < 16; i++) M[i] = view.getUint32(chunk + i * 4, true);
15300
+ let [a, b, c, d] = [a0, b0, c0, d0];
15301
+ for (let i = 0; i < 64; i++) {
15302
+ let f;
15303
+ let g;
15304
+ if (i < 16) {
15305
+ f = b & c | ~b & d;
15306
+ g = i;
15307
+ } else if (i < 32) {
15308
+ f = d & b | ~d & c;
15309
+ g = (5 * i + 1) % 16;
15310
+ } else if (i < 48) {
15311
+ f = b ^ c ^ d;
15312
+ g = (3 * i + 5) % 16;
15313
+ } else {
15314
+ f = c ^ (b | ~d);
15315
+ g = 7 * i % 16;
15316
+ }
15317
+ const tmp = d;
15318
+ d = c;
15319
+ c = b;
15320
+ const sum = a + f + K[i] + M[g] >>> 0;
15321
+ b = b + (sum << S[i] | sum >>> 32 - S[i]) >>> 0;
15322
+ a = tmp;
15323
+ }
15324
+ a0 = a0 + a >>> 0;
15325
+ b0 = b0 + b >>> 0;
15326
+ c0 = c0 + c >>> 0;
15327
+ d0 = d0 + d >>> 0;
15328
+ }
15329
+ const out = new Uint8Array(16);
15330
+ new DataView(out.buffer).setUint32(0, a0, true);
15331
+ new DataView(out.buffer).setUint32(4, b0, true);
15332
+ new DataView(out.buffer).setUint32(8, c0, true);
15333
+ new DataView(out.buffer).setUint32(12, d0, true);
15334
+ return toHex(out);
15335
+ }
15336
+
15337
+ // src/bin/archive.ts
15140
15338
  var BLOCK = 512;
15141
15339
  var encoder4 = new TextEncoder();
15142
15340
  var decoder6 = new TextDecoder();
@@ -15294,7 +15492,7 @@ var tar = defineCommand({
15294
15492
  };
15295
15493
  for (const operand of args.positional) add(resolve(baseDir, operand), operand);
15296
15494
  let bytes2 = createTar(entries2);
15297
- if (compressed) bytes2 = new Uint8Array(zlib.gzipSync(bytes2));
15495
+ if (compressed) bytes2 = await gzip(bytes2);
15298
15496
  if (archive === void 0 || archive === "-") ctx.write(bytes2);
15299
15497
  else ctx.vfs.writeFile(ctx.path(archive), bytes2, { cred: ctx.cred, mode: 420 });
15300
15498
  return 0;
@@ -15308,7 +15506,7 @@ var tar = defineCommand({
15308
15506
  return ctx.reportError(e, archive);
15309
15507
  }
15310
15508
  }
15311
- if (bytes[0] === 31 && bytes[1] === 139) bytes = new Uint8Array(zlib.gunzipSync(bytes));
15509
+ if (bytes[0] === 31 && bytes[1] === 139) bytes = await gunzip(bytes);
15312
15510
  const entries = readTar(bytes);
15313
15511
  const strip = args.num("strip-components", 0);
15314
15512
  if (args.has("list")) {
@@ -15354,7 +15552,7 @@ var tar = defineCommand({
15354
15552
  return 2;
15355
15553
  }
15356
15554
  });
15357
- var gzip = defineCommand({
15555
+ var gzip2 = defineCommand({
15358
15556
  name: "gzip",
15359
15557
  path: "/bin/gzip",
15360
15558
  summary: "compress files",
@@ -15377,28 +15575,28 @@ var gzip = defineCommand({
15377
15575
  toStdout,
15378
15576
  keep: args.has("keep") || ctx.name === "zcat",
15379
15577
  suffix: ".gz",
15380
- compress: (data) => new Uint8Array(zlib.gzipSync(data)),
15381
- expand: (data) => new Uint8Array(zlib.gunzipSync(data))
15578
+ compress: (data) => gzip(data),
15579
+ expand: (data) => gunzip(data)
15382
15580
  });
15383
15581
  }
15384
15582
  });
15385
- var gunzip = defineCommand({
15583
+ var gunzip2 = defineCommand({
15386
15584
  name: "gunzip",
15387
15585
  path: "/bin/gunzip",
15388
15586
  summary: "decompress files",
15389
- run: (ctx) => gzip.run(ctx)
15587
+ run: (ctx) => gzip2.run(ctx)
15390
15588
  });
15391
15589
  var zcat = defineCommand({
15392
15590
  name: "zcat",
15393
15591
  path: "/bin/zcat",
15394
15592
  summary: "decompress files to standard output",
15395
- run: (ctx) => gzip.run(ctx)
15593
+ run: (ctx) => gzip2.run(ctx)
15396
15594
  });
15397
15595
  async function runCompressor(ctx, operands, opts) {
15398
15596
  if (operands.length === 0) {
15399
15597
  const data = await ctx.stdin.readAll();
15400
15598
  try {
15401
- ctx.write(opts.decompress ? opts.expand(data) : opts.compress(data));
15599
+ ctx.write(opts.decompress ? await opts.expand(data) : await opts.compress(data));
15402
15600
  return 0;
15403
15601
  } catch (e) {
15404
15602
  return ctx.fail(e instanceof Error ? e.message : String(e));
@@ -15415,7 +15613,7 @@ async function runCompressor(ctx, operands, opts) {
15415
15613
  continue;
15416
15614
  }
15417
15615
  try {
15418
- const result = opts.decompress ? opts.expand(data) : opts.compress(data);
15616
+ const result = opts.decompress ? await opts.expand(data) : await opts.compress(data);
15419
15617
  if (opts.toStdout) {
15420
15618
  ctx.write(result);
15421
15619
  continue;
@@ -15441,12 +15639,14 @@ var zlibCompress = defineCommand({
15441
15639
  toStdout: args.has("stdout"),
15442
15640
  keep: false,
15443
15641
  suffix: ".Z",
15444
- compress: (data) => new Uint8Array(zlib.deflateSync(data)),
15445
- expand: (data) => new Uint8Array(zlib.inflateSync(data))
15642
+ compress: (data) => deflate(data),
15643
+ expand: (data) => inflate(data)
15446
15644
  });
15447
15645
  }
15448
15646
  });
15449
- var commands6 = [tar, gzip, gunzip, zcat, zlibCompress];
15647
+ var commands6 = [tar, gzip2, gunzip2, zcat, zlibCompress];
15648
+
15649
+ // src/bin/hash.ts
15450
15650
  function makeSum(name, algorithm, path) {
15451
15651
  return defineCommand({
15452
15652
  name,
@@ -15465,7 +15665,7 @@ function makeSum(name, algorithm, path) {
15465
15665
  if (args.has("check")) return checkSums(ctx, algorithm, args.positional, args.has("quiet") || args.has("status"));
15466
15666
  const { sources, ok } = await readInputs(ctx, args.positional, { stdinName: "-" });
15467
15667
  for (const source of sources) {
15468
- const digest = crypto$1.createHash(algorithm).update(source.bytes).digest("hex");
15668
+ const digest = await digestHex(algorithm, source.bytes);
15469
15669
  if (args.has("tag")) ctx.line(`${algorithm.toUpperCase()} (${source.name}) = ${digest}`);
15470
15670
  else ctx.line(`${digest} ${source.name}`);
15471
15671
  }
@@ -15486,7 +15686,7 @@ async function checkSums(ctx, algorithm, files, quiet) {
15486
15686
  const [, expected, name] = m;
15487
15687
  try {
15488
15688
  const bytes = ctx.vfs.readFile(ctx.path(name), ctx.cred);
15489
- const actual = crypto$1.createHash(algorithm).update(bytes).digest("hex");
15689
+ const actual = await digestHex(algorithm, bytes);
15490
15690
  if (actual === expected.toLowerCase()) {
15491
15691
  if (!quiet) ctx.line(`${name}: OK`);
15492
15692
  } else {
@@ -15617,8 +15817,8 @@ var uuidgen = defineCommand({
15617
15817
  name: "uuidgen",
15618
15818
  path: "/usr/bin/uuidgen",
15619
15819
  summary: "create a new UUID value",
15620
- run(ctx) {
15621
- ctx.line(crypto$1.randomUUID());
15820
+ async run(ctx) {
15821
+ ctx.line(await randomUuid());
15622
15822
  return 0;
15623
15823
  }
15624
15824
  });
@@ -17692,7 +17892,7 @@ var pip = defineCommand({
17692
17892
  }
17693
17893
  const data = new Uint8Array(await (await fetch(wheel.url)).arrayBuffer());
17694
17894
  ctx.line(` Downloading ${wheel.filename} (${Math.round(data.length / 1024)} kB)`);
17695
- installWheel(ctx, siteDir, data, name, chosen);
17895
+ await installWheel(ctx, siteDir, data, name, chosen);
17696
17896
  ctx.line(`Successfully installed ${name}-${chosen}`);
17697
17897
  } catch (e) {
17698
17898
  ctx.warn(`ERROR: Could not install ${spec}: ${e instanceof Error ? e.message : String(e)}`);
@@ -17702,8 +17902,8 @@ var pip = defineCommand({
17702
17902
  return status;
17703
17903
  }
17704
17904
  });
17705
- function installWheel(ctx, siteDir, data, name, version) {
17706
- const entries = readZip(data);
17905
+ async function installWheel(ctx, siteDir, data, name, version) {
17906
+ const entries = await readZip(data);
17707
17907
  for (const entry of entries) {
17708
17908
  if (entry.name.endsWith("/")) continue;
17709
17909
  const target = join(siteDir, entry.name);
@@ -17717,7 +17917,7 @@ function installWheel(ctx, siteDir, data, name, version) {
17717
17917
  Version: ${version}
17718
17918
  `, { cred: ctx.cred });
17719
17919
  }
17720
- function readZip(data) {
17920
+ async function readZip(data) {
17721
17921
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
17722
17922
  const entries = [];
17723
17923
  let eocd = -1;
@@ -17743,7 +17943,7 @@ function readZip(data) {
17743
17943
  const localExtraLength = view.getUint16(localOffset + 28, true);
17744
17944
  const dataStart = localOffset + 30 + localNameLength + localExtraLength;
17745
17945
  const raw = data.subarray(dataStart, dataStart + compressedSize);
17746
- entries.push({ name, data: method === 0 ? raw.slice() : new Uint8Array(zlib.inflateRawSync(raw)) });
17946
+ entries.push({ name, data: method === 0 ? raw.slice() : await inflateRaw(raw) });
17747
17947
  offset += 46 + nameLength + extraLength + commentLength;
17748
17948
  }
17749
17949
  return entries;
@@ -17774,9 +17974,17 @@ function findProjectRoot(ctx) {
17774
17974
  function writeManifest(ctx, path, manifest) {
17775
17975
  ctx.vfs.writeFile(path, JSON.stringify(manifest, null, 2) + "\n", { cred: ctx.cred, mode: 420 });
17776
17976
  }
17977
+ function splitPackageSpec(spec) {
17978
+ const at = spec.lastIndexOf("@");
17979
+ if (at <= 0) return { name: spec };
17980
+ return { name: spec.slice(0, at), version: spec.slice(at + 1) };
17981
+ }
17777
17982
  async function installPackages(ctx, specs, opts) {
17778
17983
  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");
17984
+ const onProgress = (message) => {
17985
+ if (!opts.quiet) ctx.stderr.write(message.endsWith("\n") ? message : message + "\n");
17986
+ };
17987
+ const note = (text) => opts.quiet ? ctx.stderr.write(text + "\n") : ctx.line(text);
17780
17988
  if (!ctx.kernel.net.options.allowOutbound) {
17781
17989
  ctx.warn("npm error code ENOTFOUND");
17782
17990
  ctx.warn("npm error network request to https://registry.npmjs.org failed");
@@ -17786,7 +17994,7 @@ async function installPackages(ctx, specs, opts) {
17786
17994
  }
17787
17995
  try {
17788
17996
  if (specs.length === 0) {
17789
- ctx.line(`npm install (project at ${opts.cwd})`);
17997
+ note(`npm install (project at ${opts.cwd})`);
17790
17998
  await installer.installFromManifest(join(opts.cwd, "package.json"), {
17791
17999
  withDevDeps: true,
17792
18000
  onProgress,
@@ -17794,11 +18002,8 @@ async function installPackages(ctx, specs, opts) {
17794
18002
  });
17795
18003
  } else {
17796
18004
  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}` : ""}`);
18005
+ const { name, version } = splitPackageSpec(spec);
18006
+ note(`added ${name}${version ? `@${version}` : ""}`);
17802
18007
  await installer.install(name, version, {
17803
18008
  onProgress,
17804
18009
  persist: opts.save !== false,
@@ -18042,33 +18247,127 @@ function printNpmHelp(ctx) {
18042
18247
  ctx.line("");
18043
18248
  ctx.line(`npm@${NPM_VERSION} /usr/lib/node_modules/npm`);
18044
18249
  }
18250
+ function packageBinaries(ctx, root, packageName) {
18251
+ const manifestPath = join(root, "node_modules", packageName, "package.json");
18252
+ try {
18253
+ const manifest = JSON.parse(ctx.vfs.readText(manifestPath, ctx.cred));
18254
+ if (typeof manifest.bin === "string") return [basename(packageName)];
18255
+ if (manifest.bin && typeof manifest.bin === "object") return Object.keys(manifest.bin);
18256
+ } catch {
18257
+ }
18258
+ return [];
18259
+ }
18260
+ function findLocalBin(ctx, name) {
18261
+ let dir3 = ctx.cwd;
18262
+ for (let i = 0; i < 64; i++) {
18263
+ const candidate = join(dir3, "node_modules", ".bin", name);
18264
+ if (ctx.vfs.lexists(candidate)) return candidate;
18265
+ const parent = dirname(dir3);
18266
+ if (parent === dir3) break;
18267
+ dir3 = parent;
18268
+ }
18269
+ return null;
18270
+ }
18045
18271
  var npx = defineCommand({
18046
18272
  name: "npx",
18047
18273
  path: "/usr/bin/npx",
18048
18274
  summary: "run a command from a local or remote npm package",
18275
+ usage: "npx [-y] [-p package] <command> [args]",
18276
+ manual: `Runs a package binary, installing the package first if it is not
18277
+ already present. Installation needs outbound network access, which is off
18278
+ unless the container was created with network: { allowOutbound: true }.`,
18049
18279
  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);
18280
+ const args = parseArgs(
18281
+ ctx.args,
18282
+ [
18283
+ { short: "y", long: "yes" },
18284
+ { long: "no-install" },
18285
+ { short: "p", long: "package", arg: true, multiple: true },
18286
+ { short: "q", long: "quiet" },
18287
+ { short: "c", long: "call", arg: true },
18288
+ { long: "version" },
18289
+ { long: "help" }
18290
+ ],
18291
+ { stopAtFirstPositional: true, allowUnknown: true }
18292
+ );
18293
+ if (args.has("version")) {
18294
+ ctx.line(NPM_VERSION);
18295
+ return 0;
18296
+ }
18297
+ if (args.has("help")) {
18298
+ ctx.line("Usage: npx [options] <command>[@version] [command-arg]...");
18299
+ ctx.line("");
18300
+ ctx.line("Options:");
18301
+ ctx.line(" -y, --yes skip the install confirmation (always implied here)");
18302
+ ctx.line(" -p, --package <pkg> package providing the command (repeatable)");
18303
+ ctx.line(" --no-install fail instead of installing a missing package");
18304
+ ctx.line(" -q, --quiet suppress install progress");
18305
+ return 0;
18306
+ }
18307
+ const call = args.str("call");
18308
+ const operands = call ? call.split(/\s+/).filter(Boolean) : args.positional;
18309
+ if (operands.length === 0) {
18310
+ ctx.warn("a command is required");
18311
+ ctx.warn("usage: npx [options] <command>[@version] [command-arg]...");
18312
+ return 1;
18313
+ }
18054
18314
  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}...
18315
+ const binDir = join(root, "node_modules", ".bin");
18316
+ const [spec, ...rest] = operands;
18317
+ const { name: specName, version } = splitPackageSpec(spec);
18318
+ const packages = args.list("package");
18319
+ const packageSpec = packages[0] ?? spec;
18320
+ const packageName = packages[0] ? splitPackageSpec(packages[0]).name : specName;
18321
+ let command = packages.length > 0 ? spec : basename(specName);
18322
+ const run = async (binary) => {
18323
+ const env2 = {
18324
+ ...ctx.env,
18325
+ PATH: `${binDir}:${ctx.env.PATH ?? ""}`,
18326
+ npm_config_user_agent: `npm/${NPM_VERSION} node/${NODE_VERSION} linux x64`
18327
+ };
18328
+ return await ctx.kernel.spawn([binary, ...rest], {
18329
+ cwd: ctx.cwd,
18330
+ env: env2,
18331
+ cred: ctx.cred,
18332
+ ppid: ctx.proc.pid,
18333
+ stdin: ctx.stdin,
18334
+ stdout: ctx.stdout,
18335
+ stderr: ctx.stderr
18336
+ }).wait();
18337
+ };
18338
+ if (!version) {
18339
+ if (findLocalBin(ctx, command)) return run(command);
18340
+ if (ctx.kernel.which(command, ctx.cwd, ctx.env, ctx.cred)) return run(command);
18341
+ }
18342
+ if (args.has("no-install")) {
18343
+ ctx.warn(`command not found: ${command}`);
18344
+ return 127;
18345
+ }
18346
+ if (!ctx.kernel.net.options.allowOutbound) {
18347
+ ctx.warn(`could not determine executable to run: ${command}`);
18348
+ ctx.warn(`'${packageName}' is not installed, and installing it needs network access.`);
18349
+ ctx.warn("Outbound network access is disabled for this container.");
18350
+ ctx.warn("Enable it with createContainer({ network: { allowOutbound: true } }).");
18351
+ return 127;
18352
+ }
18353
+ ctx.stderr.write(`npx: installing ${packageSpec}...
18059
18354
  `);
18060
- await installPackages(ctx, [name], { cwd: root, save: false });
18355
+ const installed = await installPackages(ctx, [packageSpec], {
18356
+ cwd: root,
18357
+ save: false,
18358
+ quiet: true
18359
+ });
18360
+ if (installed !== 0) return installed;
18361
+ if (!findLocalBin(ctx, command)) {
18362
+ const binaries = packageBinaries(ctx, root, packageName);
18363
+ const chosen = binaries.includes(command) ? command : binaries[0];
18364
+ if (chosen === void 0) {
18365
+ ctx.warn(`could not determine executable to run: ${packageName} provides no binary`);
18366
+ return 127;
18367
+ }
18368
+ command = chosen;
18061
18369
  }
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();
18370
+ return run(command);
18072
18371
  }
18073
18372
  });
18074
18373
  function makeNpmAlias(name, path) {
@@ -18487,7 +18786,7 @@ var Container = class _Container {
18487
18786
  }
18488
18787
  // ── boot ──────────────────────────────────────────────────────────────────
18489
18788
  static async create(opts = {}) {
18490
- const pod = await headless.Nodepod.boot({
18789
+ const pod = opts.pod ?? await headless.Nodepod.boot({
18491
18790
  headless: true,
18492
18791
  serviceWorker: false,
18493
18792
  env: opts.env ?? {},
@@ -18538,8 +18837,8 @@ var Container = class _Container {
18538
18837
  /** Copy a directory tree from the host filesystem into the container. */
18539
18838
  async copyIn(hostPath, containerPath) {
18540
18839
  this.assertActive();
18541
- const { readdir, readFile, stat: stat2 } = await import('fs/promises');
18542
- const nodePath = await import('path');
18840
+ const { readdir, readFile, stat: stat2 } = await nodeBuiltin("fs/promises");
18841
+ const nodePath = await nodeBuiltin("path");
18543
18842
  const walk = async (src, dest) => {
18544
18843
  const st = await stat2(src);
18545
18844
  if (st.isDirectory()) {
@@ -18566,8 +18865,8 @@ var Container = class _Container {
18566
18865
  /** Copy a file or directory out of the container onto the host. */
18567
18866
  async copyOut(containerPath, hostPath) {
18568
18867
  this.assertActive();
18569
- const { mkdir: mkdir2, writeFile } = await import('fs/promises');
18570
- const nodePath = await import('path');
18868
+ const { mkdir: mkdir2, writeFile } = await nodeBuiltin("fs/promises");
18869
+ const nodePath = await nodeBuiltin("path");
18571
18870
  const src = resolve(this.defaults.cwd, containerPath);
18572
18871
  const walk = async (from, to) => {
18573
18872
  const st = this.kernel.vfs.lstat(from);
@@ -18791,7 +19090,7 @@ var Container = class _Container {
18791
19090
  */
18792
19091
  async expose(port, opts = {}) {
18793
19092
  this.assertActive();
18794
- const http = await import('http');
19093
+ const http = await nodeBuiltin("http");
18795
19094
  const container = this;
18796
19095
  const server = http.createServer((req, res) => {
18797
19096
  const chunks = [];