sandboxedjs 0.1.26 → 0.1.27
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/README.md +28 -11
- package/dist/index.cjs +200 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -10
- package/dist/index.d.ts +24 -10
- package/dist/index.js +200 -15
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -577,8 +577,8 @@ its kill signal.
|
|
|
577
577
|
|
|
578
578
|
## Running in a browser
|
|
579
579
|
|
|
580
|
-
|
|
581
|
-
|
|
580
|
+
The same `createContainer()` API runs under Node and in modern browsers. Browser execution is
|
|
581
|
+
tested under Vite 8; the remaining browser-specific limits are listed below.
|
|
582
582
|
|
|
583
583
|
**Done — the package no longer hard-depends on Node at import time.** Compression and hashing
|
|
584
584
|
resolve their implementation at call time (`node:zlib`/`node:crypto` on Node,
|
|
@@ -607,7 +607,24 @@ $ node -p process.version v22.12.0
|
|
|
607
607
|
$ cat /etc/os-release SandboxedJS 1.0 (sandbox)
|
|
608
608
|
```
|
|
609
609
|
|
|
610
|
-
**
|
|
610
|
+
**Vite 8 works through Rolldown's official WASI binding.** Because that binding uses shared
|
|
611
|
+
WebAssembly memory and workers, the page must be cross-origin isolated. For example:
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
// vite.config.ts
|
|
615
|
+
export default {
|
|
616
|
+
server: { headers: {
|
|
617
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
618
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
619
|
+
} },
|
|
620
|
+
};
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
Production hosting must return the same two headers. Without them SandboxedJS reports a direct
|
|
624
|
+
configuration error when Vite/Rolldown starts. The compiler is loaded only when an installed
|
|
625
|
+
project actually contains Rolldown, so ordinary container boot does not pay its WASM startup cost.
|
|
626
|
+
|
|
627
|
+
**Not done — these things still stand between this and a complete browser IDE.**
|
|
611
628
|
|
|
612
629
|
- *A service worker.* A preview iframe needs a real URL, and giving it one means a worker on your
|
|
613
630
|
own origin that intercepts requests and routes them into the container. `request()` works
|
|
@@ -617,11 +634,10 @@ $ cat /etc/os-release SandboxedJS 1.0 (sandbox)
|
|
|
617
634
|
- *Worker isolation.* The runtime executes in whichever realm you boot it from, which in a browser
|
|
618
635
|
is the main thread — so a long build blocks the UI, and container code can reach page globals.
|
|
619
636
|
`comlink` is a dependency in anticipation of this and is not used yet.
|
|
620
|
-
- *esbuild.* The runtime cannot execute any build of esbuild itself: one dlopens a compiled addon,
|
|
637
|
+
- *esbuild-dependent tools.* The runtime cannot execute any build of esbuild itself: one dlopens a compiled addon,
|
|
621
638
|
the other drives a Go program through facilities the sandbox does not have. On Node it borrows
|
|
622
|
-
the host's `esbuild-wasm
|
|
623
|
-
|
|
624
|
-
the sandbox.
|
|
639
|
+
the host's `esbuild-wasm`. Vite 8's Rolldown path works in a browser, but tools which call
|
|
640
|
+
esbuild directly still fail until esbuild-wasm runs *inside* the sandbox.
|
|
625
641
|
|
|
626
642
|
Vite prints two warnings about `util` being externalized. They come from `readable-stream`, which
|
|
627
643
|
declares `"util": false` for browsers and falls back on its own; nothing in this package imports
|
|
@@ -637,7 +653,6 @@ built on `fetch`, `acorn`, `resolve.exports`, `@noble/hashes` and `pako`.
|
|
|
637
653
|
- `copyIn()` / `copyOut()` — they read and write the host filesystem, which does not exist.
|
|
638
654
|
- `expose()` — it opens a real `node:http` listener. Use `request()` to reach an in-container
|
|
639
655
|
server instead of a host port.
|
|
640
|
-
- `python3` — see below.
|
|
641
656
|
- The `sandboxedjs` CLI, obviously.
|
|
642
657
|
|
|
643
658
|
Those use dynamic imports, so they only fail if you call them.
|
|
@@ -750,9 +765,11 @@ Honest list of what does not work:
|
|
|
750
765
|
- **Compiled native addons.** A `.node` file cannot be loaded, so a package that ships one has to
|
|
751
766
|
have a JavaScript or WebAssembly build to fall back on. `rollup` and `esbuild` do, and the
|
|
752
767
|
runtime redirects those two names to `@rollup/wasm-node` and `esbuild-wasm` automatically when
|
|
753
|
-
they are installed.
|
|
754
|
-
|
|
755
|
-
|
|
768
|
+
they are installed. Vite 8 is supported through Rolldown's official WASI build (with the browser
|
|
769
|
+
isolation headers above). Express, Koa, Fastify-style apps and plain `http` servers also run.
|
|
770
|
+
- **Concurrent browser Rolldown projects need distinct absolute working directories.** The
|
|
771
|
+
official binding owns one WASI memfs per page; SandboxedJS mirrors each project into it before
|
|
772
|
+
startup. Two live projects using the same path such as `/workspace` can overwrite that mirror.
|
|
756
773
|
- **`child_process` is asynchronous only.** `spawn`, `exec` and `execFile` run through the kernel,
|
|
757
774
|
so a child sees the same filesystem and coreutils as the shell. `execSync`, `spawnSync` and
|
|
758
775
|
`execFileSync` throw `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`: blocking the JavaScript thread on
|
package/dist/index.cjs
CHANGED
|
@@ -6823,7 +6823,7 @@ var NetworkStack = class {
|
|
|
6823
6823
|
}
|
|
6824
6824
|
return [...out.values()].sort((a, b) => a.port - b.port);
|
|
6825
6825
|
}
|
|
6826
|
-
/** Ports
|
|
6826
|
+
/** Ports the pod's proxy has registered for this instance. */
|
|
6827
6827
|
knownPodPorts() {
|
|
6828
6828
|
try {
|
|
6829
6829
|
return this.pod.proxy.activePorts(this.pod.instanceId) ?? [];
|
|
@@ -18180,7 +18180,33 @@ function ffmpegCommands() {
|
|
|
18180
18180
|
return [ffmpeg, ffprobe];
|
|
18181
18181
|
}
|
|
18182
18182
|
var platformBuffer = globalThis.Buffer;
|
|
18183
|
-
var Buffer2 = platformBuffer ?? index_js.Buffer;
|
|
18183
|
+
var Buffer2 = platformBuffer ?? addBase64UrlSupport(index_js.Buffer);
|
|
18184
|
+
function addBase64UrlSupport(BufferClass) {
|
|
18185
|
+
const target = BufferClass;
|
|
18186
|
+
if (target.__sandboxedBase64Url) return BufferClass;
|
|
18187
|
+
Object.defineProperty(target, "__sandboxedBase64Url", { value: true });
|
|
18188
|
+
const from = target.from.bind(target);
|
|
18189
|
+
target.from = (value, encodingOrOffset, length) => from(value, normalizeEncoding(encodingOrOffset), length);
|
|
18190
|
+
const byteLength = target.byteLength.bind(target);
|
|
18191
|
+
target.byteLength = (value, encoding) => byteLength(value, normalizeEncoding(encoding));
|
|
18192
|
+
const isEncoding = target.isEncoding?.bind(target);
|
|
18193
|
+
if (isEncoding) target.isEncoding = (encoding) => encoding.toLowerCase() === "base64url" || isEncoding(encoding);
|
|
18194
|
+
const toString = target.prototype.toString;
|
|
18195
|
+
target.prototype.toString = function(encoding, start2, end) {
|
|
18196
|
+
if (encoding?.toLowerCase() !== "base64url") return toString.call(this, encoding, start2, end);
|
|
18197
|
+
return toString.call(this, "base64", start2, end).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
18198
|
+
};
|
|
18199
|
+
const write = target.prototype.write;
|
|
18200
|
+
target.prototype.write = function(...args) {
|
|
18201
|
+
const index = typeof args[1] === "string" ? 1 : typeof args[2] === "string" ? 2 : 3;
|
|
18202
|
+
if (typeof args[index] === "string") args[index] = normalizeEncoding(args[index]);
|
|
18203
|
+
return write.apply(this, args);
|
|
18204
|
+
};
|
|
18205
|
+
return BufferClass;
|
|
18206
|
+
}
|
|
18207
|
+
function normalizeEncoding(value) {
|
|
18208
|
+
return typeof value === "string" && value.toLowerCase() === "base64url" ? "base64" : value;
|
|
18209
|
+
}
|
|
18184
18210
|
|
|
18185
18211
|
// src/pkg/clean-installer.ts
|
|
18186
18212
|
init_path();
|
|
@@ -18222,6 +18248,9 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
|
|
|
18222
18248
|
const version = resolveVersion(metadata, range);
|
|
18223
18249
|
const manifest = metadata.versions[version];
|
|
18224
18250
|
if (!manifest) throw new Error(`No matching version found for ${name}@${range}`);
|
|
18251
|
+
if (!supportsPlatform(manifest)) {
|
|
18252
|
+
throw new Error(`${name}@${version} is not compatible with linux/x64/glibc`);
|
|
18253
|
+
}
|
|
18225
18254
|
const identity = `${name}@${version}`;
|
|
18226
18255
|
const target = join(modulesRoot, name);
|
|
18227
18256
|
const installed2 = this.tryReadJson(join(target, "package.json"));
|
|
@@ -18316,6 +18345,15 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
|
|
|
18316
18345
|
}
|
|
18317
18346
|
}
|
|
18318
18347
|
};
|
|
18348
|
+
function supportsPlatform(manifest) {
|
|
18349
|
+
return !manifest.main?.endsWith(".node") && platformListAllows(manifest.os, "linux") && platformListAllows(manifest.cpu, "x64") && platformListAllows(manifest.libc, "glibc");
|
|
18350
|
+
}
|
|
18351
|
+
function platformListAllows(values, current) {
|
|
18352
|
+
if (!values?.length) return true;
|
|
18353
|
+
if (values.includes(`!${current}`)) return false;
|
|
18354
|
+
const positive = values.filter((value) => !value.startsWith("!"));
|
|
18355
|
+
return positive.length === 0 || positive.includes(current) || positive.includes("any");
|
|
18356
|
+
}
|
|
18319
18357
|
function resolveVersion(metadata, range) {
|
|
18320
18358
|
const tag2 = metadata["dist-tags"]?.[range];
|
|
18321
18359
|
if (tag2) return tag2;
|
|
@@ -22276,6 +22314,7 @@ function createCoreModules(options) {
|
|
|
22276
22314
|
globals,
|
|
22277
22315
|
process: processObject,
|
|
22278
22316
|
pendingHandles: timers.pending,
|
|
22317
|
+
pendingUnrefed: timers.pendingUnrefed,
|
|
22279
22318
|
writeStdin: (data) => {
|
|
22280
22319
|
if (options.interactiveStdin) stdin.write(data);
|
|
22281
22320
|
},
|
|
@@ -22871,33 +22910,78 @@ var ERRNO_CONSTANTS = {
|
|
|
22871
22910
|
};
|
|
22872
22911
|
function createTrackedTimers() {
|
|
22873
22912
|
const live = /* @__PURE__ */ new Set();
|
|
22874
|
-
const
|
|
22913
|
+
const unrefed = /* @__PURE__ */ new Set();
|
|
22914
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
22915
|
+
const track = (native) => {
|
|
22916
|
+
const state = { native, active: true, referenced: true };
|
|
22917
|
+
const handle = {
|
|
22918
|
+
ref() {
|
|
22919
|
+
state.referenced = true;
|
|
22920
|
+
unrefed.delete(handle);
|
|
22921
|
+
if (state.active) live.add(handle);
|
|
22922
|
+
state.native?.ref?.();
|
|
22923
|
+
return handle;
|
|
22924
|
+
},
|
|
22925
|
+
unref() {
|
|
22926
|
+
state.referenced = false;
|
|
22927
|
+
live.delete(handle);
|
|
22928
|
+
if (state.active) unrefed.add(handle);
|
|
22929
|
+
state.native?.unref?.();
|
|
22930
|
+
return handle;
|
|
22931
|
+
},
|
|
22932
|
+
hasRef: () => state.referenced,
|
|
22933
|
+
refresh() {
|
|
22934
|
+
state.native?.refresh?.();
|
|
22935
|
+
return handle;
|
|
22936
|
+
},
|
|
22937
|
+
[Symbol.toPrimitive]: () => Number(state.native)
|
|
22938
|
+
};
|
|
22939
|
+
states.set(handle, state);
|
|
22875
22940
|
live.add(handle);
|
|
22876
22941
|
return handle;
|
|
22877
22942
|
};
|
|
22943
|
+
const complete = (handle) => {
|
|
22944
|
+
const state = states.get(handle);
|
|
22945
|
+
if (state) state.active = false;
|
|
22946
|
+
live.delete(handle);
|
|
22947
|
+
unrefed.delete(handle);
|
|
22948
|
+
};
|
|
22878
22949
|
const setTimeoutTracked = (fn, delay, ...args) => {
|
|
22879
|
-
|
|
22950
|
+
let handle;
|
|
22951
|
+
const native = setTimeout(
|
|
22880
22952
|
(...inner) => {
|
|
22881
|
-
|
|
22953
|
+
complete(handle);
|
|
22882
22954
|
fn(...inner);
|
|
22883
22955
|
},
|
|
22884
22956
|
delay,
|
|
22885
22957
|
...args
|
|
22886
22958
|
);
|
|
22887
|
-
|
|
22959
|
+
handle = track(native);
|
|
22888
22960
|
return handle;
|
|
22889
22961
|
};
|
|
22890
22962
|
const setIntervalTracked = (fn, delay, ...args) => track(setInterval(fn, delay, ...args));
|
|
22891
22963
|
const hostSetImmediate = globalThis.setImmediate;
|
|
22892
22964
|
const setImmediateTracked = (fn, ...args) => {
|
|
22893
|
-
|
|
22894
|
-
|
|
22965
|
+
if (!hostSetImmediate) return setTimeoutTracked(fn, 0, ...args);
|
|
22966
|
+
let handle;
|
|
22967
|
+
const native = hostSetImmediate((...inner) => {
|
|
22968
|
+
complete(handle);
|
|
22895
22969
|
fn(...inner);
|
|
22896
|
-
}, ...args)
|
|
22897
|
-
|
|
22970
|
+
}, ...args);
|
|
22971
|
+
handle = track(native);
|
|
22898
22972
|
return handle;
|
|
22899
22973
|
};
|
|
22900
22974
|
const clear2 = (handle, native) => {
|
|
22975
|
+
if (typeof handle === "object" && handle !== null) {
|
|
22976
|
+
const state = states.get(handle);
|
|
22977
|
+
if (state) {
|
|
22978
|
+
state.active = false;
|
|
22979
|
+
live.delete(handle);
|
|
22980
|
+
unrefed.delete(handle);
|
|
22981
|
+
native(state.native);
|
|
22982
|
+
return;
|
|
22983
|
+
}
|
|
22984
|
+
}
|
|
22901
22985
|
live.delete(handle);
|
|
22902
22986
|
native(handle);
|
|
22903
22987
|
};
|
|
@@ -22910,7 +22994,8 @@ function createTrackedTimers() {
|
|
|
22910
22994
|
clearInterval: (handle) => clear2(handle, clearInterval),
|
|
22911
22995
|
clearImmediate: (handle) => clear2(handle, globalThis.clearImmediate ?? clearTimeout)
|
|
22912
22996
|
},
|
|
22913
|
-
pending: () => live.size
|
|
22997
|
+
pending: () => live.size,
|
|
22998
|
+
pendingUnrefed: () => unrefed.size
|
|
22914
22999
|
};
|
|
22915
23000
|
}
|
|
22916
23001
|
function createTimerPromises() {
|
|
@@ -23432,7 +23517,26 @@ function ensureProcessGlobal() {
|
|
|
23432
23517
|
});
|
|
23433
23518
|
}
|
|
23434
23519
|
|
|
23520
|
+
// src/runtime/host-rolldown.ts
|
|
23521
|
+
async function loadHostRolldownBinding() {
|
|
23522
|
+
if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) {
|
|
23523
|
+
throw new Error(
|
|
23524
|
+
"Vite 8/Rolldown requires cross-origin isolation. Serve the app with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers."
|
|
23525
|
+
);
|
|
23526
|
+
}
|
|
23527
|
+
try {
|
|
23528
|
+
const loaded = await import('@rolldown/binding-wasm32-wasi');
|
|
23529
|
+
return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
|
|
23530
|
+
} catch (error) {
|
|
23531
|
+
if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
|
|
23532
|
+
console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
|
|
23533
|
+
}
|
|
23534
|
+
throw new Error("The optional Rolldown WASI binding could not be loaded.", { cause: error });
|
|
23535
|
+
}
|
|
23536
|
+
}
|
|
23537
|
+
|
|
23435
23538
|
// src/runtime/local-runtime-pod.ts
|
|
23539
|
+
init_path();
|
|
23436
23540
|
var WASM_ALIASES = {
|
|
23437
23541
|
esbuild: "esbuild-wasm",
|
|
23438
23542
|
rollup: "@rollup/wasm-node"
|
|
@@ -23683,6 +23787,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
23683
23787
|
aliases;
|
|
23684
23788
|
modules;
|
|
23685
23789
|
esbuild;
|
|
23790
|
+
rolldownBinding;
|
|
23686
23791
|
constructor(options) {
|
|
23687
23792
|
ensureProcessGlobal();
|
|
23688
23793
|
this.workdir = options.workdir ?? "/";
|
|
@@ -23716,6 +23821,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
23716
23821
|
const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
|
|
23717
23822
|
const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
|
|
23718
23823
|
return new LocalProcess(async (proc) => {
|
|
23824
|
+
await this.prepareRolldown(cwd, env2);
|
|
23719
23825
|
const untrack = trackProcess(proc);
|
|
23720
23826
|
let requestedExit = 0;
|
|
23721
23827
|
let engine;
|
|
@@ -23752,7 +23858,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
23752
23858
|
});
|
|
23753
23859
|
try {
|
|
23754
23860
|
await engine.run(script);
|
|
23755
|
-
await this.settle(owner, core.pendingHandles, core.readingStdin);
|
|
23861
|
+
await this.settle(owner, core.pendingHandles, core.pendingUnrefed, core.readingStdin);
|
|
23756
23862
|
if (this.router.activePorts(owner).length) {
|
|
23757
23863
|
await proc.waitForKill();
|
|
23758
23864
|
return 137;
|
|
@@ -23764,6 +23870,25 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
23764
23870
|
}
|
|
23765
23871
|
});
|
|
23766
23872
|
}
|
|
23873
|
+
/**
|
|
23874
|
+
* Rolldown's JavaScript API synchronously requires its compiled binding.
|
|
23875
|
+
* When a project contains Rolldown, preload the official WASI build in the
|
|
23876
|
+
* host and expose it through the module override table before evaluation.
|
|
23877
|
+
* Keeping this demand-driven avoids adding WASM startup cost to ordinary
|
|
23878
|
+
* shells and Node programs.
|
|
23879
|
+
*/
|
|
23880
|
+
async prepareRolldown(cwd, env2) {
|
|
23881
|
+
const specifier = "@rolldown/binding-wasm32-wasi";
|
|
23882
|
+
if (!this.modules[specifier] && packageInstalled(this.volume, cwd, "rolldown")) {
|
|
23883
|
+
this.rolldownBinding ??= loadHostRolldownBinding();
|
|
23884
|
+
const binding = await this.rolldownBinding;
|
|
23885
|
+
if (binding) this.modules[specifier] = binding;
|
|
23886
|
+
}
|
|
23887
|
+
if (this.modules[specifier]) {
|
|
23888
|
+
syncRolldownFileSystem(this.modules[specifier], this.volume, cwd);
|
|
23889
|
+
env2.NAPI_RS_FORCE_WASI ??= "true";
|
|
23890
|
+
}
|
|
23891
|
+
}
|
|
23767
23892
|
/**
|
|
23768
23893
|
* Wait until the process has either started serving or genuinely run out of
|
|
23769
23894
|
* work.
|
|
@@ -23779,11 +23904,17 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
23779
23904
|
* A plain script that has genuinely finished falls straight through both,
|
|
23780
23905
|
* costing a handful of empty turns.
|
|
23781
23906
|
*/
|
|
23782
|
-
async settle(owner, pendingHandles, readingStdin) {
|
|
23907
|
+
async settle(owner, pendingHandles, pendingUnrefed, readingStdin) {
|
|
23783
23908
|
for (let turn = 0; turn < DRAIN_TURNS; turn++) {
|
|
23784
23909
|
if (this.router.activePorts(owner).length) return;
|
|
23785
23910
|
await new Promise((resolve2) => setTimeout(resolve2, 0));
|
|
23786
23911
|
}
|
|
23912
|
+
if (pendingHandles() === 0 && pendingUnrefed() > 0 && !readingStdin()) {
|
|
23913
|
+
const deadline = Date.now() + 1e3;
|
|
23914
|
+
while (!this.router.activePorts(owner).length && Date.now() < deadline) {
|
|
23915
|
+
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
23916
|
+
}
|
|
23917
|
+
}
|
|
23787
23918
|
while (!this.router.activePorts(owner).length && (pendingHandles() > 0 || readingStdin())) {
|
|
23788
23919
|
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
23789
23920
|
}
|
|
@@ -23836,6 +23967,60 @@ function formatError(error) {
|
|
|
23836
23967
|
function isRecord(value) {
|
|
23837
23968
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23838
23969
|
}
|
|
23970
|
+
function packageInstalled(volume, cwd, wanted) {
|
|
23971
|
+
for (let dir3 = clean(cwd); ; dir3 = dirname(dir3)) {
|
|
23972
|
+
if (packageTreeContains(volume, join(dir3, "node_modules"), wanted, /* @__PURE__ */ new Set())) return true;
|
|
23973
|
+
if (dir3 === "/") return false;
|
|
23974
|
+
}
|
|
23975
|
+
}
|
|
23976
|
+
function packageTreeContains(volume, modulesRoot, wanted, visited) {
|
|
23977
|
+
if (visited.has(modulesRoot) || !directory(volume, modulesRoot)) return false;
|
|
23978
|
+
visited.add(modulesRoot);
|
|
23979
|
+
if (directory(volume, join(modulesRoot, wanted))) return true;
|
|
23980
|
+
for (const entry of volume.readdirSync(modulesRoot)) {
|
|
23981
|
+
if (entry === ".bin") continue;
|
|
23982
|
+
const first = join(modulesRoot, entry);
|
|
23983
|
+
const packages = entry.startsWith("@") && directory(volume, first) ? volume.readdirSync(first).map((name) => join(first, name)) : [first];
|
|
23984
|
+
for (const root of packages) {
|
|
23985
|
+
if (directory(volume, root) && packageTreeContains(volume, join(root, "node_modules"), wanted, visited)) {
|
|
23986
|
+
return true;
|
|
23987
|
+
}
|
|
23988
|
+
}
|
|
23989
|
+
}
|
|
23990
|
+
return false;
|
|
23991
|
+
}
|
|
23992
|
+
function directory(volume, path) {
|
|
23993
|
+
try {
|
|
23994
|
+
return volume.lstatSync(path).isDirectory();
|
|
23995
|
+
} catch {
|
|
23996
|
+
return false;
|
|
23997
|
+
}
|
|
23998
|
+
}
|
|
23999
|
+
function syncRolldownFileSystem(binding, volume, root) {
|
|
24000
|
+
const fs = binding?.__fs;
|
|
24001
|
+
if (!fs?.mkdirSync || !fs?.writeFileSync) return;
|
|
24002
|
+
try {
|
|
24003
|
+
fs.rmSync?.(root, { recursive: true, force: true });
|
|
24004
|
+
} catch {
|
|
24005
|
+
}
|
|
24006
|
+
const copy = (path) => {
|
|
24007
|
+
const stat2 = volume.lstatSync(path);
|
|
24008
|
+
if (stat2.isDirectory()) {
|
|
24009
|
+
fs.mkdirSync(path, { recursive: true });
|
|
24010
|
+
for (const name of volume.readdirSync(path)) copy(join(path, name));
|
|
24011
|
+
} else if (stat2.isSymbolicLink()) {
|
|
24012
|
+
fs.mkdirSync(dirname(path), { recursive: true });
|
|
24013
|
+
try {
|
|
24014
|
+
fs.symlinkSync(volume.readlinkSync(path), path);
|
|
24015
|
+
} catch {
|
|
24016
|
+
}
|
|
24017
|
+
} else if (!path.endsWith(".node")) {
|
|
24018
|
+
fs.mkdirSync(dirname(path), { recursive: true });
|
|
24019
|
+
fs.writeFileSync(path, volume.readFileSync(path));
|
|
24020
|
+
}
|
|
24021
|
+
};
|
|
24022
|
+
copy(clean(root));
|
|
24023
|
+
}
|
|
23839
24024
|
|
|
23840
24025
|
// src/container/container.ts
|
|
23841
24026
|
var Container = class _Container {
|
|
@@ -24179,7 +24364,7 @@ var Container = class _Container {
|
|
|
24179
24364
|
/**
|
|
24180
24365
|
* Deliver a request whose body is bytes, without letting them become text.
|
|
24181
24366
|
*
|
|
24182
|
-
*
|
|
24367
|
+
* A RuntimePod's public `request()` may run the body through `toString("utf8")` on
|
|
24183
24368
|
* its way in, so anything above `0x7f` is replaced: a five-byte payload
|
|
24184
24369
|
* containing `0x89` and `0xff` arrives as nine. That silently destroys every
|
|
24185
24370
|
* upload — an image or a video reaches the server the wrong size and no
|
|
@@ -24281,7 +24466,7 @@ var Container = class _Container {
|
|
|
24281
24466
|
assertActive() {
|
|
24282
24467
|
if (this.disposed) throw new Error("container has been disposed");
|
|
24283
24468
|
}
|
|
24284
|
-
/** Tear down every process and release the
|
|
24469
|
+
/** Tear down every process and release the runtime pod. */
|
|
24285
24470
|
dispose() {
|
|
24286
24471
|
if (this.disposed) return;
|
|
24287
24472
|
this.disposed = true;
|