sandboxedjs 0.1.35 → 0.1.36

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.
@@ -203,8 +203,8 @@ async function printReplBanner(box, opts) {
203
203
  " npm create vite@latest app -- --template react && cd app && npm i && npm run dev",
204
204
  " ffmpeg -f lavfi -i testsrc=size=64x64:rate=5:duration=1 out.mp4 && ls -l out.mp4",
205
205
  "",
206
- `${DIM}Known limits: no native binaries, no raw sockets, and esbuild-based`,
207
- `toolchains (Vite 4 and its contemporaries) cannot start. Current Vite works.${RESET}`,
206
+ `${DIM}Known limits: no raw sockets, and esbuild-based toolchains (Vite 4 and`,
207
+ `its contemporaries) cannot start. Current Vite works, build and dev server.${RESET}`,
208
208
  "",
209
209
  `${DIM}Ctrl-D or \`exit\` to leave.${RESET}`,
210
210
  "",
package/dist/index.cjs CHANGED
@@ -21,6 +21,10 @@ var timersModule = require('timers-browserify');
21
21
  var legacyUrl = require('url/url.js');
22
22
  var legacy$1 = require('@noble/hashes/legacy');
23
23
  var hmac = require('@noble/hashes/hmac');
24
+ var module$1 = require('module');
25
+ var fs = require('fs');
26
+ var path = require('path');
27
+ var url = require('url');
24
28
 
25
29
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
26
30
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -18677,9 +18681,9 @@ async function resolveIndexUrl() {
18677
18681
  if (indexUrl) return indexUrl;
18678
18682
  if (!isNode2) return DEFAULT_BROWSER_INDEX_URL;
18679
18683
  try {
18680
- const { createRequire } = await nodeBuiltin("module");
18684
+ const { createRequire: createRequire2 } = await nodeBuiltin("module");
18681
18685
  const path = await nodeBuiltin("path");
18682
- const require2 = createRequire(path.join(process.cwd(), "index.js"));
18686
+ const require2 = createRequire2(path.join(process.cwd(), "index.js"));
18683
18687
  return `${path.dirname(require2.resolve("pyodide/package.json"))}/`;
18684
18688
  } catch {
18685
18689
  return void 0;
@@ -19144,15 +19148,15 @@ function pythonCommands() {
19144
19148
  var INSTALL_HINT = "ffmpeg is not installed in this container.\nThe FFmpeg runtime ships separately because it is a ~31MB WebAssembly build:\n npm install @ffmpeg/core";
19145
19149
  var compiled = null;
19146
19150
  async function loadFactory() {
19147
- const { createRequire } = await nodeBuiltin("module");
19151
+ const { createRequire: createRequire2 } = await nodeBuiltin("module");
19148
19152
  const fs = await nodeBuiltin("fs/promises");
19149
19153
  const path = await nodeBuiltin("path");
19150
- const packageRequire = createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
19154
+ const packageRequire = createRequire2((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
19151
19155
  let require2 = packageRequire;
19152
19156
  try {
19153
19157
  require2.resolve("@ffmpeg/core/wasm");
19154
19158
  } catch {
19155
- require2 = createRequire(path.join(process.cwd(), "index.js"));
19159
+ require2 = createRequire2(path.join(process.cwd(), "index.js"));
19156
19160
  }
19157
19161
  const wasmPath = require2.resolve("@ffmpeg/core/wasm");
19158
19162
  const wasm = await fs.readFile(wasmPath);
@@ -25022,6 +25026,7 @@ function createCoreModules(options) {
25022
25026
  zlib: zlib_module_default
25023
25027
  };
25024
25028
  for (const name of stubNames) builtins[name] = createUnsupportedModule(name);
25029
+ builtins.net = createNetModule();
25025
25030
  const globals = {
25026
25031
  Buffer: Buffer2,
25027
25032
  console: consoleObject,
@@ -25850,15 +25855,43 @@ function createStreamPromises() {
25850
25855
  })
25851
25856
  };
25852
25857
  }
25853
- function createUnsupportedModule(name) {
25858
+ function createUnsupportedModule(name, supported = {}) {
25854
25859
  const unsupported = () => {
25855
25860
  const error = new Error(`${name} is unavailable in the browser runtime`);
25856
25861
  error.code = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
25857
25862
  throw error;
25858
25863
  };
25859
- return new Proxy({ unsupported }, { get(target, key) {
25860
- return key in target ? target[key] : unsupported;
25861
- } });
25864
+ const target = { unsupported, ...supported };
25865
+ const module = new Proxy(target, {
25866
+ get(object, key) {
25867
+ if (key === "default") return module;
25868
+ return key in object ? object[key] : unsupported;
25869
+ }
25870
+ });
25871
+ return module;
25872
+ }
25873
+ function createNetModule() {
25874
+ const isIPv4 = (value) => {
25875
+ const parts = String(value).split(".");
25876
+ return parts.length === 4 && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255 && String(Number(part)) === part);
25877
+ };
25878
+ const isIPv6 = (value) => {
25879
+ const text2 = String(value);
25880
+ if (!text2.includes(":")) return false;
25881
+ const [head2, tail2] = [text2.slice(0, text2.lastIndexOf(":")), text2.slice(text2.lastIndexOf(":") + 1)];
25882
+ const normalised = isIPv4(tail2) ? `${head2}:0:0` : text2;
25883
+ const halves = normalised.split("::");
25884
+ if (halves.length > 2) return false;
25885
+ const groups = halves.map((half) => half === "" ? [] : half.split(":"));
25886
+ if (groups.some((half) => half.some((group) => !/^[0-9a-fA-F]{1,4}$/.test(group)))) return false;
25887
+ const count = groups.reduce((total, half) => total + half.length, 0);
25888
+ return halves.length === 2 ? count <= 7 : count === 8;
25889
+ };
25890
+ return createUnsupportedModule("net", {
25891
+ isIPv4,
25892
+ isIPv6,
25893
+ isIP: (value) => isIPv4(value) ? 4 : isIPv6(value) ? 6 : 0
25894
+ });
25862
25895
  }
25863
25896
  var stubNames = ["cluster", "dgram", "diagnostics_channel", "domain", "http2", "inspector", "net", "tls", "v8", "vm", "worker_threads"];
25864
25897
  var builtinNames2 = [
@@ -26267,6 +26300,77 @@ var MirroringVolume = class {
26267
26300
  };
26268
26301
  copy(this.root);
26269
26302
  }
26303
+ /**
26304
+ * Bring back what the mirrored engine wrote.
26305
+ *
26306
+ * The mirror exists because Rolldown's resolver reads through WASI rather
26307
+ * than through anything JavaScript can hand it — but Rolldown also *writes*
26308
+ * through WASI, so `vite build` leaves its output in the mirror and the
26309
+ * container sees an empty `dist/`. This is the return leg, and it is why the
26310
+ * mirror is no longer strictly one-way.
26311
+ *
26312
+ * Called when a process ends rather than on a timer: that is the moment a
26313
+ * build's output is complete, and a dev server — which serves from memory
26314
+ * and writes nothing — pays for it only once, at exit.
26315
+ */
26316
+ absorb() {
26317
+ const mirror = this.mirror;
26318
+ if (!mirror?.readdirSync || !mirror.readFileSync || !mirror.lstatSync) return;
26319
+ const visit = (path) => {
26320
+ if (basename(path) === "node_modules") return;
26321
+ let stat2;
26322
+ try {
26323
+ stat2 = mirror.lstatSync(path);
26324
+ } catch {
26325
+ return;
26326
+ }
26327
+ if (stat2.isSymbolicLink()) return;
26328
+ if (stat2.isDirectory()) {
26329
+ let names;
26330
+ try {
26331
+ names = mirror.readdirSync(path);
26332
+ } catch {
26333
+ return;
26334
+ }
26335
+ for (const name of names) visit(join(path, name));
26336
+ return;
26337
+ }
26338
+ let produced;
26339
+ try {
26340
+ produced = mirror.readFileSync(path);
26341
+ } catch {
26342
+ return;
26343
+ }
26344
+ try {
26345
+ const current = this.inner.readFileSync(path);
26346
+ if (sameBytes(current, produced)) return;
26347
+ } catch {
26348
+ }
26349
+ try {
26350
+ this.ensureDirectory(dirname(path));
26351
+ this.inner.writeFileSync(path, produced);
26352
+ } catch {
26353
+ }
26354
+ };
26355
+ visit(this.root);
26356
+ }
26357
+ /** `mkdir -p`, which the volume does not offer directly. */
26358
+ ensureDirectory(path) {
26359
+ const parts = clean(path).split("/").filter(Boolean);
26360
+ let current = "";
26361
+ for (const part of parts) {
26362
+ current += `/${part}`;
26363
+ try {
26364
+ if (this.inner.lstatSync(current).isDirectory()) continue;
26365
+ return;
26366
+ } catch {
26367
+ }
26368
+ try {
26369
+ this.inner.mkdirSync(current);
26370
+ } catch {
26371
+ }
26372
+ }
26373
+ }
26270
26374
  /** Is this path inside the mirrored subtree? */
26271
26375
  mirrored(path) {
26272
26376
  if (!this.mirror) return false;
@@ -26398,6 +26502,11 @@ var MirroringVolume = class {
26398
26502
  this.seed();
26399
26503
  }
26400
26504
  };
26505
+ function sameBytes(a, b) {
26506
+ if (a.length !== b.length) return false;
26507
+ for (let index = 0; index < a.length; index++) if (a[index] !== b[index]) return false;
26508
+ return true;
26509
+ }
26401
26510
 
26402
26511
  // src/runtime/host-esbuild.ts
26403
26512
  var ASYNC_API = ["transform", "build", "context", "formatMessages", "analyzeMetafile"];
@@ -26466,12 +26575,142 @@ function ensureProcessGlobal() {
26466
26575
  configurable: true
26467
26576
  });
26468
26577
  }
26578
+ var BINDING_PACKAGE = "@rolldown/binding-wasm32-wasi";
26579
+ var ASYNC_WORK_POOL_SIZE = 4;
26580
+ var WORKER_FILE = "rolldown-wasi-worker.js";
26581
+ async function loadNodeRolldownMemfsBinding() {
26582
+ const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
26583
+ let packageDir;
26584
+ try {
26585
+ packageDir = path.dirname(require2.resolve(`${BINDING_PACKAGE}/package.json`));
26586
+ } catch {
26587
+ return null;
26588
+ }
26589
+ const fromBinding = module$1.createRequire(path.join(packageDir, "package.json"));
26590
+ let runtime;
26591
+ let fsModuleUrl;
26592
+ let createContext2;
26593
+ try {
26594
+ runtime = fromBinding("@napi-rs/wasm-runtime");
26595
+ fsModuleUrl = resolveSubpath(fromBinding, "@napi-rs/wasm-runtime", "./fs");
26596
+ ({ createContext: createContext2 } = fromBinding("@emnapi/runtime"));
26597
+ } catch {
26598
+ return null;
26599
+ }
26600
+ const { memfs } = await import(fsModuleUrl);
26601
+ const { Worker: Worker2 } = await import('worker_threads');
26602
+ const { fs: memoryFs, vol } = memfs();
26603
+ const wasi2 = new runtime.WASI({
26604
+ version: "preview1",
26605
+ fs: memoryFs,
26606
+ preopens: { "/": "/" }
26607
+ });
26608
+ const wasmFile = fs.readFileSync(path.join(packageDir, "rolldown-binding.wasm32-wasi.wasm"));
26609
+ const sharedMemory = new WebAssembly.Memory({ initial: 16384, maximum: 65536, shared: true });
26610
+ const workerPoolSize = Math.max(2, cpuCount());
26611
+ const context = createContext2({ autoDestroy: false });
26612
+ context.suppressDestroy();
26613
+ const workerPath = resolveWorkerPath();
26614
+ if (!workerPath) return null;
26615
+ const runtimeAnchor = url.pathToFileURL(path.join(packageDir, "package.json")).href;
26616
+ const workers = /* @__PURE__ */ new Set();
26617
+ let started = false;
26618
+ const { napiModule } = await runtime.instantiateNapiModule(wasmFile, {
26619
+ context,
26620
+ asyncWorkPoolSize: ASYNC_WORK_POOL_SIZE,
26621
+ reuseWorker: { size: ASYNC_WORK_POOL_SIZE + workerPoolSize },
26622
+ plugins: [runtime.emnapiAsyncWorkPlugin, runtime.emnapiTSFNPlugin],
26623
+ wasi: wasi2,
26624
+ onCreateWorker() {
26625
+ const worker = new Worker2(workerPath, {
26626
+ env: process.env,
26627
+ workerData: { runtimeAnchor, fsModuleUrl },
26628
+ /*
26629
+ * Deliberately no `execArgv`.
26630
+ *
26631
+ * A worker inherits the parent's flags by default, and this worker is
26632
+ * a plain JavaScript file we ship — it needs none of them. Inheriting
26633
+ * them is actively harmful: under a host started with a module loader
26634
+ * (`tsx`, `ts-node`, `--import`), the worker's module resolution then
26635
+ * needs the main thread, which is at that moment blocked waiting for
26636
+ * this very worker to report itself ready. The result is a deadlock at
26637
+ * startup with no error, and it took a while to find.
26638
+ */
26639
+ execArgv: []
26640
+ });
26641
+ workers.add(worker);
26642
+ const serveFsRequest = runtime.createOnMessage(memoryFs);
26643
+ worker.on("message", (data) => serveFsRequest({ data }));
26644
+ worker.on("exit", () => workers.delete(worker));
26645
+ if (started) unreferenceWorker(worker);
26646
+ return worker;
26647
+ },
26648
+ overwriteImports(importObject) {
26649
+ importObject.env = {
26650
+ ...importObject.env,
26651
+ ...importObject.napi,
26652
+ ...importObject.emnapi,
26653
+ memory: sharedMemory
26654
+ };
26655
+ return importObject;
26656
+ },
26657
+ beforeInit({ instance }) {
26658
+ for (const name of Object.keys(instance.exports)) {
26659
+ if (name.startsWith("__napi_register__")) instance.exports[name]();
26660
+ }
26661
+ }
26662
+ });
26663
+ started = true;
26664
+ for (const worker of workers) unreferenceWorker(worker);
26665
+ return { ...napiModule.exports, __fs: memoryFs, __volume: vol };
26666
+ }
26667
+ function resolveWorkerPath() {
26668
+ const here = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
26669
+ const candidates = [
26670
+ path.join(here, WORKER_FILE),
26671
+ /* src/runtime → dist, for a checkout that has been built. */
26672
+ path.join(here, "..", "..", "dist", WORKER_FILE)
26673
+ ];
26674
+ return candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
26675
+ }
26676
+ function resolveSubpath(require2, packageName, subpath) {
26677
+ const packageDir = path.dirname(require2.resolve(packageName));
26678
+ const manifest = JSON.parse(fs.readFileSync(path.join(packageDir, "package.json"), "utf8"));
26679
+ const entry = manifest?.exports?.[subpath];
26680
+ const target = typeof entry === "string" ? entry : entry?.import ?? entry?.default;
26681
+ if (typeof target !== "string") {
26682
+ throw new Error(`${packageName} does not export ${subpath}`);
26683
+ }
26684
+ return url.pathToFileURL(path.join(packageDir, target)).href;
26685
+ }
26686
+ function cpuCount() {
26687
+ try {
26688
+ return process.availableParallelism?.() ?? 4;
26689
+ } catch {
26690
+ return 4;
26691
+ }
26692
+ }
26693
+ function unreferenceWorker(worker) {
26694
+ for (const key of Object.getOwnPropertySymbols(worker)) {
26695
+ if (key.toString().includes("kPublicPort") || key.toString().includes("kHandle")) {
26696
+ const handle = worker[key];
26697
+ if (handle && typeof handle === "object") handle.ref = () => {
26698
+ };
26699
+ }
26700
+ }
26701
+ worker.unref();
26702
+ }
26469
26703
 
26470
26704
  // src/runtime/host-rolldown.ts
26471
26705
  var BUNDLER_HINT = "If this is a bundler pre-bundling the worker away, exclude the binding from dependency optimisation \u2014 in Vite:\n\n optimizeDeps: { exclude: ['@rolldown/binding-wasm32-wasi'] }";
26706
+ var isNodeHost = typeof process !== "undefined" && Boolean(process.versions?.node);
26472
26707
  async function loadHostRolldownBinding() {
26473
26708
  const reason = syncChannelUnavailableReason();
26474
26709
  if (reason) throw new Error(`SandboxedJs threaded WASM unavailable: ${reason}`);
26710
+ if (isNodeHost) {
26711
+ const binding = await loadNodeRolldownMemfsBinding();
26712
+ if (binding) return binding;
26713
+ }
26475
26714
  try {
26476
26715
  const loaded = await import('@rolldown/binding-wasm32-wasi');
26477
26716
  return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
@@ -26871,6 +27110,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
26871
27110
  core.cancelTimers();
26872
27111
  untrack();
26873
27112
  this.router.closeOwner(owner);
27113
+ this.volume.absorb();
26874
27114
  }
26875
27115
  });
26876
27116
  this.running.add(process2);