@poe-platform/safe-js 0.1.800 → 0.1.802
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 +1 -1
- package/dist/safe-js/chunks/{chunk-XAV2RKLO.js → chunk-4KMUWNZD.js} +2 -2
- package/dist/safe-js/chunks/{chunk-SHMRT4QX.js → chunk-6H5VC5W5.js} +8 -8
- package/dist/safe-js/chunks/{chunk-QEDOBN2G.js → chunk-HFRBLE6Y.js} +38 -32
- package/dist/safe-js/chunks/{chunk-LWHXSNF6.js → chunk-IB6WAQAE.js} +1 -1
- package/dist/safe-js/chunks/{chunk-YAHDXC7P.js → chunk-YCFOANSU.js} +22 -17
- package/dist/safe-js/chunks/{cli-runtime-OCWFX4TM.js → cli-runtime-L4IABN2W.js} +4 -4
- package/dist/safe-js/chunks/{mcp-4D3WWY7U.js → mcp-5TMFK3UE.js} +2 -2
- package/dist/safe-js/chunks/{run-3X6J7FPV.js → run-M6N5KCPF.js} +1 -1
- package/dist/safe-js/cli.js +2 -2
- package/dist/safe-js/core.js +2 -2
- package/dist/safe-js/index.js +5 -5
- package/dist/safe-js/modules/fs-config.d.ts +1 -0
- package/dist/safe-js/modules/fs.d.ts +2 -0
- package/dist/safe-js/modules/fs.js +1 -1
- package/dist/safe-js/portable/chunks/{chunk-KYJVK33V.js → chunk-2FNMGWDK.js} +22 -17
- package/dist/safe-js/portable/core.js +39 -33
- package/dist/safe-js/portable/modules/fs.js +1 -1
- package/dist/safe-js/workerd.js +60 -49
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -551,7 +551,7 @@ Factories return exports to register in `modules`; calling a factory alone does
|
|
|
551
551
|
|
|
552
552
|
`spawn.retry(definition, options, retryOptions)` and `defaultRetry` use `{ maxAttempts, backoffMs, isErrorRetryable?, isRetryable? }`. `spawn.parallel(calls, options?)` accepts definition/options tuples or spawn-handle factories; options are `check`, `maxConcurrent`, `failFast`, and `signal`. Usage helpers are `createSpawnUsageAccumulator()` and `runWithSpawnUsageAccumulator(accumulator, operation)`.
|
|
553
553
|
|
|
554
|
-
**Config files.** `parseMcpConfig(json, directory)` accepts `servers` and the three numeric MCP limits, resolving stdio paths against `directory`. `parseFsConfig(json)` accepts `{ adapter: { type, options }, root?, cwd?, readFileMaxBytes?, hostReadMemoryLimit? }`; `resolveFsConfig(config, { registry? })` constructs the adapter for `makeFsModule`. Built-in types are `memory` and `real`; `real` requires an absolute host `options.root`. Outer `root`/`cwd` are absolute virtual paths. Custom registry descriptors supply `validateOptions` and `create`. Signals and injected functions are SDK options, not JSON fields.
|
|
554
|
+
**Config files.** `parseMcpConfig(json, directory)` accepts `servers` and the three numeric MCP limits, resolving stdio paths against `directory`. `parseFsConfig(json)` accepts `{ adapter: { type, options }, root?, cwd?, readFileMaxBytes?, hostReadMemoryLimit? }`; `resolveFsConfig(config, { registry? })` constructs the adapter for `makeFsModule`. Built-in types are `memory` and `real`; `real` requires an absolute host `options.root`. Outer `root`/`cwd` are absolute virtual paths. Custom registry descriptors supply `validateOptions` and `create`. `maxSymlinkFollows` optionally bounds dangling-symlink canonicalization for rooted filesystem modules; it defaults to `Infinity` and accepts the same finite values through filesystem JSON configuration. Actual symlink cycles still fail. Signals and injected functions are SDK options, not JSON fields.
|
|
555
555
|
|
|
556
556
|
</details>
|
|
557
557
|
|
|
@@ -2532,7 +2532,7 @@ import {
|
|
|
2532
2532
|
validateFileSystemConfig
|
|
2533
2533
|
} from "@poe-platform/safe-fs";
|
|
2534
2534
|
function validateFsConfig(value) {
|
|
2535
|
-
const config = readConfigRecord(value, "fs config", ["adapter", "root", "cwd", "readFileMaxBytes", "hostReadMemoryLimit"]);
|
|
2535
|
+
const config = readConfigRecord(value, "fs config", ["adapter", "root", "cwd", "readFileMaxBytes", "hostReadMemoryLimit", "maxSymlinkFollows"]);
|
|
2536
2536
|
const paths = {};
|
|
2537
2537
|
for (const key of ["root", "cwd"]) {
|
|
2538
2538
|
const path = config[key];
|
|
@@ -2543,7 +2543,7 @@ function validateFsConfig(value) {
|
|
|
2543
2543
|
paths[key] = path;
|
|
2544
2544
|
}
|
|
2545
2545
|
const limits = {};
|
|
2546
|
-
for (const key of ["readFileMaxBytes", "hostReadMemoryLimit"]) {
|
|
2546
|
+
for (const key of ["readFileMaxBytes", "hostReadMemoryLimit", "maxSymlinkFollows"]) {
|
|
2547
2547
|
const value2 = config[key];
|
|
2548
2548
|
if (value2 === void 0) continue;
|
|
2549
2549
|
if (value2 !== Infinity && (typeof value2 !== "number" || !Number.isSafeInteger(value2) || value2 < 0))
|
|
@@ -3686,11 +3686,11 @@ function copyBoundedOAuthJson(value, message) {
|
|
|
3686
3686
|
import http from "node:http";
|
|
3687
3687
|
|
|
3688
3688
|
// packages/mcp-oauth/src/client/authorization-state.ts
|
|
3689
|
-
import
|
|
3689
|
+
import crypto2 from "node:crypto";
|
|
3690
3690
|
function createAuthorizationState(input) {
|
|
3691
3691
|
const payload = {
|
|
3692
3692
|
v: 1,
|
|
3693
|
-
n:
|
|
3693
|
+
n: crypto2.randomBytes(16).toString("base64url"),
|
|
3694
3694
|
i: input.issuer,
|
|
3695
3695
|
r: input.requireIssuer
|
|
3696
3696
|
};
|
|
@@ -4198,7 +4198,7 @@ function registrationMatchesRedirect(client, requestedUri, fresh = false) {
|
|
|
4198
4198
|
}
|
|
4199
4199
|
|
|
4200
4200
|
// packages/mcp-oauth/src/client/auth-store-session-store.ts
|
|
4201
|
-
import
|
|
4201
|
+
import crypto3 from "node:crypto";
|
|
4202
4202
|
import path4 from "node:path";
|
|
4203
4203
|
|
|
4204
4204
|
// packages/auth-store/src/encrypted-file-store.ts
|
|
@@ -4956,7 +4956,7 @@ function snapshotPersistenceOptions(options) {
|
|
|
4956
4956
|
}
|
|
4957
4957
|
function createNamedSecretStore(key2, options, defaults, namespace) {
|
|
4958
4958
|
options = snapshotOAuthPersistenceOptions(options);
|
|
4959
|
-
const hash =
|
|
4959
|
+
const hash = crypto3.createHash("sha256").update(namespace === void 0 ? key2 : JSON.stringify([namespace, key2])).digest("hex");
|
|
4960
4960
|
const configuredFilePath = options.fileStore?.filePath;
|
|
4961
4961
|
const parsedFilePath = configuredFilePath === void 0 ? null : path4.parse(configuredFilePath);
|
|
4962
4962
|
const fileStore = {
|
|
@@ -5256,12 +5256,12 @@ async function fetchMcpResponse(fetchImplementation, input, init = {}) {
|
|
|
5256
5256
|
import { URL as URL2 } from "node:url";
|
|
5257
5257
|
|
|
5258
5258
|
// packages/mcp-oauth/src/client/pkce.ts
|
|
5259
|
-
import
|
|
5259
|
+
import crypto4 from "node:crypto";
|
|
5260
5260
|
function generateCodeVerifier() {
|
|
5261
|
-
return
|
|
5261
|
+
return crypto4.randomBytes(32).toString("base64url");
|
|
5262
5262
|
}
|
|
5263
5263
|
function generateCodeChallenge(verifier) {
|
|
5264
|
-
return
|
|
5264
|
+
return crypto4.createHash("sha256").update(verifier).digest("base64url");
|
|
5265
5265
|
}
|
|
5266
5266
|
|
|
5267
5267
|
// packages/mcp-oauth/src/http-response.ts
|
|
@@ -5390,7 +5390,7 @@ async function requestTokens(input) {
|
|
|
5390
5390
|
if (method === "client_secret_basic") {
|
|
5391
5391
|
const encoded = new URLSearchParams({ credential: input.clientId }).toString().slice("credential=".length);
|
|
5392
5392
|
const encodedSecret = new URLSearchParams({ credential: input.clientSecret }).toString().slice("credential=".length);
|
|
5393
|
-
headers.set("Authorization", `Basic ${
|
|
5393
|
+
headers.set("Authorization", `Basic ${btoa(`${encoded}:${encodedSecret}`)}`);
|
|
5394
5394
|
} else {
|
|
5395
5395
|
body.set("client_id", input.clientId);
|
|
5396
5396
|
if (method === "client_secret_post") body.set("client_secret", input.clientSecret);
|
|
@@ -1217,7 +1217,7 @@ var RealmState = class {
|
|
|
1217
1217
|
this.assertOpen();
|
|
1218
1218
|
const closure = readGuestCallback(callback, this);
|
|
1219
1219
|
this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
|
|
1220
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1220
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.queuedCallbacks.has(callback);
|
|
1221
1221
|
const record = {
|
|
1222
1222
|
closure,
|
|
1223
1223
|
prefixComplete: false
|
|
@@ -1599,7 +1599,7 @@ var RealmState = class {
|
|
|
1599
1599
|
await this.dispose();
|
|
1600
1600
|
this.assertOpen();
|
|
1601
1601
|
if (this.active !== void 0) throw new SandboxError("reentry");
|
|
1602
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1602
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0;
|
|
1603
1603
|
if (scheduled && (this.phase.getStore()?.active || [...this.pendingCallbacks].some((record) => !record.prefixComplete)))
|
|
1604
1604
|
throw new SandboxError("reentry");
|
|
1605
1605
|
const rejectionOwner = scheduled ? this.tracker.startOperation() : void 0;
|
|
@@ -1649,13 +1649,13 @@ var RealmState = class {
|
|
|
1649
1649
|
} finally {
|
|
1650
1650
|
this.tracker.finishOperation(rejectionOwner);
|
|
1651
1651
|
if (this.active === pending) this.active = void 0;
|
|
1652
|
-
if (scheduled) this.reconcileWhenIdle();
|
|
1652
|
+
if (scheduled || this.releaseReconciliation !== void 0) this.reconcileWhenIdle();
|
|
1653
1653
|
}
|
|
1654
1654
|
}
|
|
1655
1655
|
close = () => {
|
|
1656
1656
|
this.closed = true;
|
|
1657
1657
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
1658
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
1658
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
1659
1659
|
const disposal = this.dispose();
|
|
1660
1660
|
if (this.phase.getStore()?.active) {
|
|
1661
1661
|
void disposal.catch(() => void 0);
|
|
@@ -1674,7 +1674,7 @@ var RealmState = class {
|
|
|
1674
1674
|
this.closed = true;
|
|
1675
1675
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
1676
1676
|
this.options.signal?.removeEventListener("abort", this.abort);
|
|
1677
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
1677
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
1678
1678
|
this.disposal = Promise.resolve().then(async () => {
|
|
1679
1679
|
while (this.pendingWork.size > 0) await Promise.allSettled([...this.pendingWork]);
|
|
1680
1680
|
await this.sourceGraph?.settle();
|
|
@@ -1836,16 +1836,24 @@ import { createFsBridge } from "@poe-platform/safe-fs/core";
|
|
|
1836
1836
|
var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
|
|
1837
1837
|
var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
|
|
1838
1838
|
var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
1839
|
-
var
|
|
1839
|
+
var adapterOperations = /* @__PURE__ */ new WeakMap();
|
|
1840
1840
|
var FileSnapshotBackend = class {
|
|
1841
1841
|
constructor(path, options = {}) {
|
|
1842
1842
|
this.path = path;
|
|
1843
|
+
const adapter = options.adapter ?? hostFs;
|
|
1844
|
+
let pending = adapterOperations.get(adapter);
|
|
1845
|
+
if (pending === void 0) {
|
|
1846
|
+
pending = /* @__PURE__ */ new Map();
|
|
1847
|
+
adapterOperations.set(adapter, pending);
|
|
1848
|
+
}
|
|
1849
|
+
this.#pendingOperations = pending;
|
|
1843
1850
|
this.#io = options.adapter === void 0 ? hostFs : createFsBridge(options.adapter, { codec: fsCodec });
|
|
1844
1851
|
this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
|
|
1845
1852
|
this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
|
|
1846
1853
|
}
|
|
1847
1854
|
path;
|
|
1848
1855
|
#io;
|
|
1856
|
+
#pendingOperations;
|
|
1849
1857
|
#writeMaxAttempts;
|
|
1850
1858
|
#writeRetryDelayMs;
|
|
1851
1859
|
async read() {
|
|
@@ -1863,6 +1871,7 @@ var FileSnapshotBackend = class {
|
|
|
1863
1871
|
}
|
|
1864
1872
|
async write(snapshot) {
|
|
1865
1873
|
await enqueueOperation(
|
|
1874
|
+
this.#pendingOperations,
|
|
1866
1875
|
this.path,
|
|
1867
1876
|
() => writeSnapshotAtomically(this.#io, this.path, snapshot, {
|
|
1868
1877
|
maxAttempts: this.#writeMaxAttempts,
|
|
@@ -1871,7 +1880,7 @@ var FileSnapshotBackend = class {
|
|
|
1871
1880
|
);
|
|
1872
1881
|
}
|
|
1873
1882
|
async remove() {
|
|
1874
|
-
await enqueueOperation(this.path, async () => {
|
|
1883
|
+
await enqueueOperation(this.#pendingOperations, this.path, async () => {
|
|
1875
1884
|
try {
|
|
1876
1885
|
await this.#io.unlink(this.path);
|
|
1877
1886
|
} catch (error) {
|
|
@@ -1959,7 +1968,7 @@ async function writeSnapshotOnce(io, temporaryPath, snapshotPath, contents) {
|
|
|
1959
1968
|
}
|
|
1960
1969
|
}
|
|
1961
1970
|
}
|
|
1962
|
-
async function enqueueOperation(path, operation) {
|
|
1971
|
+
async function enqueueOperation(pendingOperations, path, operation) {
|
|
1963
1972
|
const previous = pendingOperations.get(path) ?? Promise.resolve();
|
|
1964
1973
|
const pending = previous.catch(() => void 0).then(operation);
|
|
1965
1974
|
const queued = pending.catch(() => void 0);
|
|
@@ -2551,10 +2560,9 @@ function run(source, options = {}) {
|
|
|
2551
2560
|
migration: restoredSnapshot?.migration,
|
|
2552
2561
|
bindings: executionScope.snapshot().bindings,
|
|
2553
2562
|
clock: options.clock,
|
|
2554
|
-
hostCalls
|
|
2555
|
-
replay: hostCalls.snapshotReplay(),
|
|
2563
|
+
hostCalls,
|
|
2556
2564
|
initialInputs: initialInputs.snapshot,
|
|
2557
|
-
promiseReplay
|
|
2565
|
+
promiseReplay,
|
|
2558
2566
|
random,
|
|
2559
2567
|
sourceHash
|
|
2560
2568
|
});
|
|
@@ -2581,12 +2589,11 @@ function run(source, options = {}) {
|
|
|
2581
2589
|
migration: restoredSnapshot?.migration,
|
|
2582
2590
|
bindings: interpreterSnapshot2.bindings,
|
|
2583
2591
|
clock: options.clock,
|
|
2584
|
-
hostCalls
|
|
2592
|
+
hostCalls,
|
|
2585
2593
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
2586
2594
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
2587
|
-
replay: hostCalls.snapshotReplay(),
|
|
2588
2595
|
initialInputs: initialInputs.snapshot,
|
|
2589
|
-
promiseReplay
|
|
2596
|
+
promiseReplay,
|
|
2590
2597
|
random,
|
|
2591
2598
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
2592
2599
|
sourceHash
|
|
@@ -2626,12 +2633,11 @@ function run(source, options = {}) {
|
|
|
2626
2633
|
migration: restoredSnapshot?.migration,
|
|
2627
2634
|
bindings: interpreterSnapshot2.bindings,
|
|
2628
2635
|
clock: options.clock,
|
|
2629
|
-
hostCalls
|
|
2636
|
+
hostCalls,
|
|
2630
2637
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
2631
2638
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
2632
|
-
replay: hostCalls.snapshotReplay(),
|
|
2633
2639
|
initialInputs: initialInputs.snapshot,
|
|
2634
|
-
promiseReplay
|
|
2640
|
+
promiseReplay,
|
|
2635
2641
|
random,
|
|
2636
2642
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
2637
2643
|
sourceHash
|
|
@@ -2648,27 +2654,17 @@ function run(source, options = {}) {
|
|
|
2648
2654
|
await throwIfReturnedPromiseRejected(result2);
|
|
2649
2655
|
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
2650
2656
|
await activeSnapshotScheduler.finish();
|
|
2651
|
-
let replay;
|
|
2652
|
-
let replayError;
|
|
2653
|
-
try {
|
|
2654
|
-
replay = hostCalls.snapshotReplay();
|
|
2655
|
-
} catch (error) {
|
|
2656
|
-
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
2657
|
-
replayError = error.message;
|
|
2658
|
-
}
|
|
2659
2657
|
const snapshot = createRunSnapshot({
|
|
2660
2658
|
executionSemantics,
|
|
2661
2659
|
migration: restoredSnapshot?.migration,
|
|
2662
2660
|
bindings: executionScope.snapshot().bindings,
|
|
2663
2661
|
clock: options.clock,
|
|
2664
|
-
hostCalls
|
|
2665
|
-
replay,
|
|
2662
|
+
hostCalls,
|
|
2666
2663
|
initialInputs: initialInputs.snapshot,
|
|
2667
|
-
promiseReplay
|
|
2664
|
+
promiseReplay,
|
|
2668
2665
|
random,
|
|
2669
2666
|
sourceHash
|
|
2670
2667
|
});
|
|
2671
|
-
if (replayError !== void 0) snapshot.replayError = replayError;
|
|
2672
2668
|
dumpController.finalize(snapshot);
|
|
2673
2669
|
completedSnapshot = snapshot;
|
|
2674
2670
|
reconcileCompiledValues(
|
|
@@ -2845,6 +2841,15 @@ function createExecutableNode(module) {
|
|
|
2845
2841
|
};
|
|
2846
2842
|
}
|
|
2847
2843
|
function createRunSnapshot(input) {
|
|
2844
|
+
let replay;
|
|
2845
|
+
let replayError;
|
|
2846
|
+
try {
|
|
2847
|
+
replay = input.hostCalls.snapshotReplay();
|
|
2848
|
+
} catch (error) {
|
|
2849
|
+
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
2850
|
+
replayError = error.message;
|
|
2851
|
+
}
|
|
2852
|
+
const hostCalls = input.hostCalls.snapshot();
|
|
2848
2853
|
const snapshot = {
|
|
2849
2854
|
version: DUMP_FORMAT_VERSION,
|
|
2850
2855
|
executionSemantics: input.executionSemantics,
|
|
@@ -2852,11 +2857,12 @@ function createRunSnapshot(input) {
|
|
|
2852
2857
|
...input.migration === void 0 ? {} : { migration: structuredClone(input.migration) },
|
|
2853
2858
|
bindings: input.bindings,
|
|
2854
2859
|
clock: input.clock?.snapshot(),
|
|
2855
|
-
...
|
|
2860
|
+
...hostCalls.length === 0 ? {} : { hostCalls },
|
|
2856
2861
|
...input.loopIterations === void 0 ? {} : { loopIterations: input.loopIterations },
|
|
2857
|
-
...
|
|
2862
|
+
...replay === void 0 ? {} : { replay },
|
|
2863
|
+
...replayError === void 0 ? {} : { replayError },
|
|
2858
2864
|
...input.initialInputs === void 0 ? {} : { initialInputs: structuredClone(input.initialInputs) },
|
|
2859
|
-
|
|
2865
|
+
promiseReplay: input.promiseReplay.snapshot(),
|
|
2860
2866
|
...input.pendingAwaits === void 0 || input.pendingAwaits.length === 0 ? {} : { pendingAwaits: input.pendingAwaits },
|
|
2861
2867
|
random: input.random === void 0 ? void 0 : {
|
|
2862
2868
|
seed: input.random.seed,
|
|
@@ -34,11 +34,14 @@ import {
|
|
|
34
34
|
// packages/safe-js/src/modules/canonical-path.ts
|
|
35
35
|
var MISSING_PATH_CODES = ["ENOENT", "ENOTDIR"];
|
|
36
36
|
var NOT_A_SYMLINK_CODES = [...MISSING_PATH_CODES, "EINVAL"];
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
async function resolveCanonicalPath({ realpath, readlink }, path, maxSymlinkFollows = Infinity) {
|
|
38
|
+
if (maxSymlinkFollows !== Infinity && (!Number.isSafeInteger(maxSymlinkFollows) || maxSymlinkFollows < 0)) {
|
|
39
|
+
throw new RangeError("maxSymlinkFollows must be a nonnegative safe integer or Infinity");
|
|
40
|
+
}
|
|
39
41
|
const missingSegments = [];
|
|
40
42
|
let current = path;
|
|
41
43
|
let follows = 0;
|
|
44
|
+
const visited = /* @__PURE__ */ new Set();
|
|
42
45
|
while (true) {
|
|
43
46
|
try {
|
|
44
47
|
const canonicalCurrent = await realpath(current);
|
|
@@ -49,9 +52,10 @@ async function resolveCanonicalPath({ realpath, readlink }, path) {
|
|
|
49
52
|
}
|
|
50
53
|
const target = await readSymlinkTarget(readlink, current);
|
|
51
54
|
if (target !== void 0) {
|
|
52
|
-
if (++follows >
|
|
55
|
+
if (++follows > maxSymlinkFollows || visited.has(current)) {
|
|
53
56
|
throw createLoopError(path);
|
|
54
57
|
}
|
|
58
|
+
visited.add(current);
|
|
55
59
|
current = isAbsolutePath(target) ? target : `${dirname(current)}${sep}${target}`;
|
|
56
60
|
continue;
|
|
57
61
|
}
|
|
@@ -264,9 +268,10 @@ var NULL_BYTE = "\0";
|
|
|
264
268
|
var [ACCESS_DENIED_ERRNO, ACCESS_DENIED_MESSAGE] = accessDeniedSystemError;
|
|
265
269
|
function makeFsModule(options = {}) {
|
|
266
270
|
assertSupportedPlatform();
|
|
271
|
+
const maxSymlinkFollows = options.maxSymlinkFollows ?? Infinity;
|
|
267
272
|
const hostReadMemoryLimit = options.hostReadMemoryLimit ?? Infinity;
|
|
268
273
|
const readFileMaxBytes = options.readFileMaxBytes ?? Infinity;
|
|
269
|
-
for (const limit of [hostReadMemoryLimit, readFileMaxBytes]) {
|
|
274
|
+
for (const limit of [hostReadMemoryLimit, readFileMaxBytes, maxSymlinkFollows]) {
|
|
270
275
|
if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 0))
|
|
271
276
|
throw new TypeError("Filesystem read limits must be non-negative safe integers or Infinity.");
|
|
272
277
|
}
|
|
@@ -288,7 +293,7 @@ function makeFsModule(options = {}) {
|
|
|
288
293
|
cwd: options.root === void 0 ? options.cwd : void 0,
|
|
289
294
|
signal: options.signal
|
|
290
295
|
});
|
|
291
|
-
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal);
|
|
296
|
+
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
292
297
|
let readFile = bindStringResult(fs, "readFile");
|
|
293
298
|
if (options.adapter !== void 0) {
|
|
294
299
|
const boundedRead = async (args, budget) => {
|
|
@@ -316,7 +321,7 @@ function makeFsModule(options = {}) {
|
|
|
316
321
|
}
|
|
317
322
|
});
|
|
318
323
|
const portable = bridge;
|
|
319
|
-
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal);
|
|
324
|
+
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
320
325
|
return await invoke(boundedFs, "readFile", args);
|
|
321
326
|
};
|
|
322
327
|
const directRead = declare("readFile", "re-issue", (...args) => boundedRead(args));
|
|
@@ -408,7 +413,7 @@ function invoke(fs, name, args) {
|
|
|
408
413
|
return Reflect.apply(fs[name], fs, args);
|
|
409
414
|
}
|
|
410
415
|
var rootedFsOperations = /* @__PURE__ */ new WeakMap();
|
|
411
|
-
function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
416
|
+
function makeRootedFs(fs, root, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
412
417
|
if (root.trim().length === 0) {
|
|
413
418
|
throw new Error("fs module root must be a non-empty string.");
|
|
414
419
|
}
|
|
@@ -429,7 +434,7 @@ function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
|
429
434
|
return await invoke(
|
|
430
435
|
fs,
|
|
431
436
|
name,
|
|
432
|
-
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal)
|
|
437
|
+
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal, maxSymlinkFollows)
|
|
433
438
|
);
|
|
434
439
|
} finally {
|
|
435
440
|
release();
|
|
@@ -450,8 +455,8 @@ function assertRootCanConfineOptions(name, args) {
|
|
|
450
455
|
throw createUnsupportedOptionError("cp", "dereference", ROOT_REFUSED_DEREFERENCE_REASON);
|
|
451
456
|
}
|
|
452
457
|
}
|
|
453
|
-
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal) {
|
|
454
|
-
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root));
|
|
458
|
+
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
459
|
+
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root), maxSymlinkFollows);
|
|
455
460
|
const base = cwd ?? canonicalRoot;
|
|
456
461
|
const resolved = [...args];
|
|
457
462
|
if (name === "symlink") {
|
|
@@ -475,7 +480,7 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
475
480
|
await assertInsideRoot(fs, canonicalRoot, name, [checkedTarget, linkPath], adapter, signal, [
|
|
476
481
|
targetPath,
|
|
477
482
|
linkPath
|
|
478
|
-
]);
|
|
483
|
+
], maxSymlinkFollows);
|
|
479
484
|
return resolved;
|
|
480
485
|
}
|
|
481
486
|
const paths = FS_PATH_ARGUMENTS[name].map((_, index) => {
|
|
@@ -483,12 +488,12 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
483
488
|
resolved[index] = path;
|
|
484
489
|
return path;
|
|
485
490
|
});
|
|
486
|
-
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal);
|
|
491
|
+
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, paths, maxSymlinkFollows);
|
|
487
492
|
if (name === "mkdtemp") {
|
|
488
493
|
const prefix = args[0];
|
|
489
494
|
const absolutePrefix = isAbsolutePath(prefix) ? prefix : `${base}${sep}${prefix}`;
|
|
490
495
|
const parent = absolutePrefix.endsWith(sep) ? absolutePrefix : dirname(absolutePrefix);
|
|
491
|
-
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths);
|
|
496
|
+
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths, maxSymlinkFollows);
|
|
492
497
|
resolved[0] = absolutePrefix;
|
|
493
498
|
}
|
|
494
499
|
if (adapter !== void 0 && name === "mkdir") {
|
|
@@ -506,15 +511,15 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
506
511
|
}
|
|
507
512
|
return resolved;
|
|
508
513
|
}
|
|
509
|
-
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths) {
|
|
514
|
+
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths, maxSymlinkFollows = Infinity) {
|
|
510
515
|
for (const path of paths) {
|
|
511
|
-
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal)) {
|
|
516
|
+
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows)) {
|
|
512
517
|
throw createAccessDeniedError(name, reportedPaths[0], reportedPaths[1]);
|
|
513
518
|
}
|
|
514
519
|
}
|
|
515
520
|
}
|
|
516
|
-
async function escapesRoot(fs, canonicalRoot, path, adapter, signal) {
|
|
517
|
-
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path);
|
|
521
|
+
async function escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows = Infinity) {
|
|
522
|
+
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path, maxSymlinkFollows);
|
|
518
523
|
return !await (adapter === void 0 ? containsPath(readStat(fs), canonicalRoot, canonicalPath) : containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal));
|
|
519
524
|
}
|
|
520
525
|
async function containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal) {
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
parseFsConfig,
|
|
9
9
|
resolveFsConfig,
|
|
10
10
|
splitFrontmatter
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4KMUWNZD.js";
|
|
12
12
|
import {
|
|
13
13
|
parseMcpConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-6H5VC5W5.js";
|
|
15
15
|
import {
|
|
16
16
|
lint,
|
|
17
17
|
makeEnvModule,
|
|
@@ -291,12 +291,12 @@ async function assertHarnessFile(input) {
|
|
|
291
291
|
}
|
|
292
292
|
async function runScriptFile(filepath, parsed, options) {
|
|
293
293
|
const [{ run }, { restore }, { dump, dumpCurrent }, { createLintModulesFromRuntimeRegistry }, { makeFsModule }, { makeMcpModule }] = await Promise.all([
|
|
294
|
-
import("./run-
|
|
294
|
+
import("./run-M6N5KCPF.js"),
|
|
295
295
|
import("./restore-GDHBT5ZD.js"),
|
|
296
296
|
import("./dump-KUPBSXSL.js"),
|
|
297
297
|
import("./runtime-modules-MGSXY4BN.js"),
|
|
298
298
|
import("../modules/fs.js"),
|
|
299
|
-
import("./mcp-
|
|
299
|
+
import("./mcp-5TMFK3UE.js")
|
|
300
300
|
]);
|
|
301
301
|
const loaded = loadExecutableSource(filepath, await options.readFile(filepath, "utf8"));
|
|
302
302
|
const meta = {
|
package/dist/safe-js/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import path from "node:path";
|
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
async function runCli(argv, options = {}) {
|
|
15
15
|
if (!argv.includes("--help") && !argv.includes("-h")) {
|
|
16
|
-
const runtime = await import("./chunks/cli-runtime-
|
|
16
|
+
const runtime = await import("./chunks/cli-runtime-L4IABN2W.js");
|
|
17
17
|
return runtime.runCli(argv, options, createUsage());
|
|
18
18
|
}
|
|
19
19
|
const brokenPipe = createBrokenPipeState();
|
|
@@ -32,7 +32,7 @@ async function runCli(argv, options = {}) {
|
|
|
32
32
|
stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
33
33
|
`);
|
|
34
34
|
if (brokenPipe.closed) return 0;
|
|
35
|
-
const { exitCodeForError } = await import("./chunks/cli-runtime-
|
|
35
|
+
const { exitCodeForError } = await import("./chunks/cli-runtime-L4IABN2W.js");
|
|
36
36
|
return exitCodeForError(error);
|
|
37
37
|
}
|
|
38
38
|
}
|
package/dist/safe-js/core.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
FS_OPTION_SURFACE,
|
|
18
18
|
makeFsModule
|
|
19
|
-
} from "./chunks/chunk-
|
|
19
|
+
} from "./chunks/chunk-YCFOANSU.js";
|
|
20
20
|
import {
|
|
21
21
|
createRootedSourceResolver
|
|
22
22
|
} from "./chunks/chunk-3NFTBEZR.js";
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
createRealm,
|
|
25
25
|
createReplayableRandom,
|
|
26
26
|
run
|
|
27
|
-
} from "./chunks/chunk-
|
|
27
|
+
} from "./chunks/chunk-HFRBLE6Y.js";
|
|
28
28
|
import "./chunks/chunk-DHGJSEFX.js";
|
|
29
29
|
import "./chunks/chunk-DIG26TEI.js";
|
|
30
30
|
import "./chunks/chunk-ONWFPHUI.js";
|
package/dist/safe-js/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunks/chunk-7THYP46K.js";
|
|
9
9
|
import {
|
|
10
10
|
makeMcpModule
|
|
11
|
-
} from "./chunks/chunk-
|
|
11
|
+
} from "./chunks/chunk-IB6WAQAE.js";
|
|
12
12
|
import {
|
|
13
13
|
AgentSpawnError,
|
|
14
14
|
SPAWN_MODES,
|
|
@@ -24,10 +24,10 @@ import {
|
|
|
24
24
|
runWithSpawnUsageAccumulator,
|
|
25
25
|
splitFrontmatter,
|
|
26
26
|
supportsSpawnMode
|
|
27
|
-
} from "./chunks/chunk-
|
|
27
|
+
} from "./chunks/chunk-4KMUWNZD.js";
|
|
28
28
|
import {
|
|
29
29
|
parseMcpConfig
|
|
30
|
-
} from "./chunks/chunk-
|
|
30
|
+
} from "./chunks/chunk-6H5VC5W5.js";
|
|
31
31
|
import {
|
|
32
32
|
makeTimeModule
|
|
33
33
|
} from "./chunks/chunk-QRWRR6IA.js";
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
import "./chunks/chunk-X3YCE3ZH.js";
|
|
46
46
|
import {
|
|
47
47
|
makeFsModule
|
|
48
|
-
} from "./chunks/chunk-
|
|
48
|
+
} from "./chunks/chunk-YCFOANSU.js";
|
|
49
49
|
import {
|
|
50
50
|
createRootedSourceResolver
|
|
51
51
|
} from "./chunks/chunk-3NFTBEZR.js";
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
createRealm,
|
|
55
55
|
createReplayableRandom,
|
|
56
56
|
run
|
|
57
|
-
} from "./chunks/chunk-
|
|
57
|
+
} from "./chunks/chunk-HFRBLE6Y.js";
|
|
58
58
|
import "./chunks/chunk-DHGJSEFX.js";
|
|
59
59
|
import {
|
|
60
60
|
fsCodec
|
|
@@ -57798,11 +57798,14 @@ function describeValue2(value) {
|
|
|
57798
57798
|
// packages/safe-js/src/modules/canonical-path.ts
|
|
57799
57799
|
var MISSING_PATH_CODES = ["ENOENT", "ENOTDIR"];
|
|
57800
57800
|
var NOT_A_SYMLINK_CODES = [...MISSING_PATH_CODES, "EINVAL"];
|
|
57801
|
-
|
|
57802
|
-
|
|
57801
|
+
async function resolveCanonicalPath({ realpath, readlink }, path, maxSymlinkFollows = Infinity) {
|
|
57802
|
+
if (maxSymlinkFollows !== Infinity && (!Number.isSafeInteger(maxSymlinkFollows) || maxSymlinkFollows < 0)) {
|
|
57803
|
+
throw new RangeError("maxSymlinkFollows must be a nonnegative safe integer or Infinity");
|
|
57804
|
+
}
|
|
57803
57805
|
const missingSegments = [];
|
|
57804
57806
|
let current = path;
|
|
57805
57807
|
let follows = 0;
|
|
57808
|
+
const visited = /* @__PURE__ */ new Set();
|
|
57806
57809
|
while (true) {
|
|
57807
57810
|
try {
|
|
57808
57811
|
const canonicalCurrent = await realpath(current);
|
|
@@ -57813,9 +57816,10 @@ async function resolveCanonicalPath({ realpath, readlink }, path) {
|
|
|
57813
57816
|
}
|
|
57814
57817
|
const target = await readSymlinkTarget(readlink, current);
|
|
57815
57818
|
if (target !== void 0) {
|
|
57816
|
-
if (++follows >
|
|
57819
|
+
if (++follows > maxSymlinkFollows || visited.has(current)) {
|
|
57817
57820
|
throw createLoopError(path);
|
|
57818
57821
|
}
|
|
57822
|
+
visited.add(current);
|
|
57819
57823
|
current = isAbsolutePath(target) ? target : `${dirname(current)}${sep}${target}`;
|
|
57820
57824
|
continue;
|
|
57821
57825
|
}
|
|
@@ -58028,9 +58032,10 @@ var NULL_BYTE = "\0";
|
|
|
58028
58032
|
var [ACCESS_DENIED_ERRNO, ACCESS_DENIED_MESSAGE] = accessDeniedSystemError;
|
|
58029
58033
|
function makeFsModule(options = {}) {
|
|
58030
58034
|
assertSupportedPlatform();
|
|
58035
|
+
const maxSymlinkFollows = options.maxSymlinkFollows ?? Infinity;
|
|
58031
58036
|
const hostReadMemoryLimit = options.hostReadMemoryLimit ?? Infinity;
|
|
58032
58037
|
const readFileMaxBytes = options.readFileMaxBytes ?? Infinity;
|
|
58033
|
-
for (const limit of [hostReadMemoryLimit, readFileMaxBytes]) {
|
|
58038
|
+
for (const limit of [hostReadMemoryLimit, readFileMaxBytes, maxSymlinkFollows]) {
|
|
58034
58039
|
if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 0))
|
|
58035
58040
|
throw new TypeError("Filesystem read limits must be non-negative safe integers or Infinity.");
|
|
58036
58041
|
}
|
|
@@ -58052,7 +58057,7 @@ function makeFsModule(options = {}) {
|
|
|
58052
58057
|
cwd: options.root === void 0 ? options.cwd : void 0,
|
|
58053
58058
|
signal: options.signal
|
|
58054
58059
|
});
|
|
58055
|
-
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal);
|
|
58060
|
+
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
58056
58061
|
let readFile = bindStringResult(fs, "readFile");
|
|
58057
58062
|
if (options.adapter !== void 0) {
|
|
58058
58063
|
const boundedRead = async (args, budget) => {
|
|
@@ -58080,7 +58085,7 @@ function makeFsModule(options = {}) {
|
|
|
58080
58085
|
}
|
|
58081
58086
|
});
|
|
58082
58087
|
const portable = bridge;
|
|
58083
|
-
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal);
|
|
58088
|
+
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
58084
58089
|
return await invoke(boundedFs, "readFile", args);
|
|
58085
58090
|
};
|
|
58086
58091
|
const directRead = declare("readFile", "re-issue", (...args) => boundedRead(args));
|
|
@@ -58172,7 +58177,7 @@ function invoke(fs, name, args) {
|
|
|
58172
58177
|
return Reflect.apply(fs[name], fs, args);
|
|
58173
58178
|
}
|
|
58174
58179
|
var rootedFsOperations = /* @__PURE__ */ new WeakMap();
|
|
58175
|
-
function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
58180
|
+
function makeRootedFs(fs, root, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
58176
58181
|
if (root.trim().length === 0) {
|
|
58177
58182
|
throw new Error("fs module root must be a non-empty string.");
|
|
58178
58183
|
}
|
|
@@ -58193,7 +58198,7 @@ function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
|
58193
58198
|
return await invoke(
|
|
58194
58199
|
fs,
|
|
58195
58200
|
name,
|
|
58196
|
-
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal)
|
|
58201
|
+
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal, maxSymlinkFollows)
|
|
58197
58202
|
);
|
|
58198
58203
|
} finally {
|
|
58199
58204
|
release();
|
|
@@ -58214,8 +58219,8 @@ function assertRootCanConfineOptions(name, args) {
|
|
|
58214
58219
|
throw createUnsupportedOptionError("cp", "dereference", ROOT_REFUSED_DEREFERENCE_REASON);
|
|
58215
58220
|
}
|
|
58216
58221
|
}
|
|
58217
|
-
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal) {
|
|
58218
|
-
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root));
|
|
58222
|
+
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
58223
|
+
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root), maxSymlinkFollows);
|
|
58219
58224
|
const base = cwd ?? canonicalRoot;
|
|
58220
58225
|
const resolved = [...args];
|
|
58221
58226
|
if (name === "symlink") {
|
|
@@ -58239,7 +58244,7 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
58239
58244
|
await assertInsideRoot(fs, canonicalRoot, name, [checkedTarget, linkPath], adapter, signal, [
|
|
58240
58245
|
targetPath,
|
|
58241
58246
|
linkPath
|
|
58242
|
-
]);
|
|
58247
|
+
], maxSymlinkFollows);
|
|
58243
58248
|
return resolved;
|
|
58244
58249
|
}
|
|
58245
58250
|
const paths = FS_PATH_ARGUMENTS[name].map((_, index) => {
|
|
@@ -58247,12 +58252,12 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
58247
58252
|
resolved[index] = path;
|
|
58248
58253
|
return path;
|
|
58249
58254
|
});
|
|
58250
|
-
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal);
|
|
58255
|
+
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, paths, maxSymlinkFollows);
|
|
58251
58256
|
if (name === "mkdtemp") {
|
|
58252
58257
|
const prefix = args[0];
|
|
58253
58258
|
const absolutePrefix = isAbsolutePath(prefix) ? prefix : `${base}${sep}${prefix}`;
|
|
58254
58259
|
const parent = absolutePrefix.endsWith(sep) ? absolutePrefix : dirname(absolutePrefix);
|
|
58255
|
-
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths);
|
|
58260
|
+
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths, maxSymlinkFollows);
|
|
58256
58261
|
resolved[0] = absolutePrefix;
|
|
58257
58262
|
}
|
|
58258
58263
|
if (adapter !== void 0 && name === "mkdir") {
|
|
@@ -58270,15 +58275,15 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
58270
58275
|
}
|
|
58271
58276
|
return resolved;
|
|
58272
58277
|
}
|
|
58273
|
-
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths) {
|
|
58278
|
+
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths, maxSymlinkFollows = Infinity) {
|
|
58274
58279
|
for (const path of paths) {
|
|
58275
|
-
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal)) {
|
|
58280
|
+
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows)) {
|
|
58276
58281
|
throw createAccessDeniedError(name, reportedPaths[0], reportedPaths[1]);
|
|
58277
58282
|
}
|
|
58278
58283
|
}
|
|
58279
58284
|
}
|
|
58280
|
-
async function escapesRoot(fs, canonicalRoot, path, adapter, signal) {
|
|
58281
|
-
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path);
|
|
58285
|
+
async function escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows = Infinity) {
|
|
58286
|
+
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path, maxSymlinkFollows);
|
|
58282
58287
|
return !await (adapter === void 0 ? containsPath(readStat(fs), canonicalRoot, canonicalPath) : containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal));
|
|
58283
58288
|
}
|
|
58284
58289
|
async function containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal) {
|
|
@@ -119,7 +119,7 @@ import {
|
|
|
119
119
|
wrapCallerInjectedBindings,
|
|
120
120
|
wrapCancelableBindings,
|
|
121
121
|
wrapHostConstructor
|
|
122
|
-
} from "./chunks/chunk-
|
|
122
|
+
} from "./chunks/chunk-2FNMGWDK.js";
|
|
123
123
|
import {
|
|
124
124
|
createRootedSourceResolver
|
|
125
125
|
} from "./chunks/chunk-XCTU25SU.js";
|
|
@@ -12489,7 +12489,7 @@ var RealmState = class {
|
|
|
12489
12489
|
this.assertOpen();
|
|
12490
12490
|
const closure = readGuestCallback(callback, this);
|
|
12491
12491
|
this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
|
|
12492
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
12492
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.queuedCallbacks.has(callback);
|
|
12493
12493
|
const record = {
|
|
12494
12494
|
closure,
|
|
12495
12495
|
prefixComplete: false
|
|
@@ -12871,7 +12871,7 @@ var RealmState = class {
|
|
|
12871
12871
|
await this.dispose();
|
|
12872
12872
|
this.assertOpen();
|
|
12873
12873
|
if (this.active !== void 0) throw new SandboxError("reentry");
|
|
12874
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
12874
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0;
|
|
12875
12875
|
if (scheduled && (this.phase.getStore()?.active || [...this.pendingCallbacks].some((record) => !record.prefixComplete)))
|
|
12876
12876
|
throw new SandboxError("reentry");
|
|
12877
12877
|
const rejectionOwner = scheduled ? this.tracker.startOperation() : void 0;
|
|
@@ -12921,13 +12921,13 @@ var RealmState = class {
|
|
|
12921
12921
|
} finally {
|
|
12922
12922
|
this.tracker.finishOperation(rejectionOwner);
|
|
12923
12923
|
if (this.active === pending) this.active = void 0;
|
|
12924
|
-
if (scheduled) this.reconcileWhenIdle();
|
|
12924
|
+
if (scheduled || this.releaseReconciliation !== void 0) this.reconcileWhenIdle();
|
|
12925
12925
|
}
|
|
12926
12926
|
}
|
|
12927
12927
|
close = () => {
|
|
12928
12928
|
this.closed = true;
|
|
12929
12929
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
12930
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
12930
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
12931
12931
|
const disposal = this.dispose();
|
|
12932
12932
|
if (this.phase.getStore()?.active) {
|
|
12933
12933
|
void disposal.catch(() => void 0);
|
|
@@ -12946,7 +12946,7 @@ var RealmState = class {
|
|
|
12946
12946
|
this.closed = true;
|
|
12947
12947
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
12948
12948
|
this.options.signal?.removeEventListener("abort", this.abort);
|
|
12949
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
12949
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
12950
12950
|
this.disposal = Promise.resolve().then(async () => {
|
|
12951
12951
|
while (this.pendingWork.size > 0) await Promise.allSettled([...this.pendingWork]);
|
|
12952
12952
|
await this.sourceGraph?.settle();
|
|
@@ -13393,16 +13393,24 @@ import { createFsBridge } from "@poe-platform/safe-fs/core";
|
|
|
13393
13393
|
var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
|
|
13394
13394
|
var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
|
|
13395
13395
|
var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
13396
|
-
var
|
|
13396
|
+
var adapterOperations = /* @__PURE__ */ new WeakMap();
|
|
13397
13397
|
var FileSnapshotBackend = class {
|
|
13398
13398
|
constructor(path, options = {}) {
|
|
13399
13399
|
this.path = path;
|
|
13400
|
+
const adapter = options.adapter ?? hostFs;
|
|
13401
|
+
let pending = adapterOperations.get(adapter);
|
|
13402
|
+
if (pending === void 0) {
|
|
13403
|
+
pending = /* @__PURE__ */ new Map();
|
|
13404
|
+
adapterOperations.set(adapter, pending);
|
|
13405
|
+
}
|
|
13406
|
+
this.#pendingOperations = pending;
|
|
13400
13407
|
this.#io = options.adapter === void 0 ? hostFs : createFsBridge(options.adapter, { codec: fsCodec });
|
|
13401
13408
|
this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
|
|
13402
13409
|
this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
|
|
13403
13410
|
}
|
|
13404
13411
|
path;
|
|
13405
13412
|
#io;
|
|
13413
|
+
#pendingOperations;
|
|
13406
13414
|
#writeMaxAttempts;
|
|
13407
13415
|
#writeRetryDelayMs;
|
|
13408
13416
|
async read() {
|
|
@@ -13420,6 +13428,7 @@ var FileSnapshotBackend = class {
|
|
|
13420
13428
|
}
|
|
13421
13429
|
async write(snapshot) {
|
|
13422
13430
|
await enqueueOperation(
|
|
13431
|
+
this.#pendingOperations,
|
|
13423
13432
|
this.path,
|
|
13424
13433
|
() => writeSnapshotAtomically(this.#io, this.path, snapshot, {
|
|
13425
13434
|
maxAttempts: this.#writeMaxAttempts,
|
|
@@ -13428,7 +13437,7 @@ var FileSnapshotBackend = class {
|
|
|
13428
13437
|
);
|
|
13429
13438
|
}
|
|
13430
13439
|
async remove() {
|
|
13431
|
-
await enqueueOperation(this.path, async () => {
|
|
13440
|
+
await enqueueOperation(this.#pendingOperations, this.path, async () => {
|
|
13432
13441
|
try {
|
|
13433
13442
|
await this.#io.unlink(this.path);
|
|
13434
13443
|
} catch (error) {
|
|
@@ -13516,7 +13525,7 @@ async function writeSnapshotOnce(io, temporaryPath, snapshotPath, contents) {
|
|
|
13516
13525
|
}
|
|
13517
13526
|
}
|
|
13518
13527
|
}
|
|
13519
|
-
async function enqueueOperation(path, operation) {
|
|
13528
|
+
async function enqueueOperation(pendingOperations, path, operation) {
|
|
13520
13529
|
const previous = pendingOperations.get(path) ?? Promise.resolve();
|
|
13521
13530
|
const pending = previous.catch(() => void 0).then(operation);
|
|
13522
13531
|
const queued = pending.catch(() => void 0);
|
|
@@ -14108,10 +14117,9 @@ function run(source, options = {}) {
|
|
|
14108
14117
|
migration: restoredSnapshot?.migration,
|
|
14109
14118
|
bindings: executionScope.snapshot().bindings,
|
|
14110
14119
|
clock: options.clock,
|
|
14111
|
-
hostCalls
|
|
14112
|
-
replay: hostCalls.snapshotReplay(),
|
|
14120
|
+
hostCalls,
|
|
14113
14121
|
initialInputs: initialInputs.snapshot,
|
|
14114
|
-
promiseReplay
|
|
14122
|
+
promiseReplay,
|
|
14115
14123
|
random,
|
|
14116
14124
|
sourceHash
|
|
14117
14125
|
});
|
|
@@ -14138,12 +14146,11 @@ function run(source, options = {}) {
|
|
|
14138
14146
|
migration: restoredSnapshot?.migration,
|
|
14139
14147
|
bindings: interpreterSnapshot2.bindings,
|
|
14140
14148
|
clock: options.clock,
|
|
14141
|
-
hostCalls
|
|
14149
|
+
hostCalls,
|
|
14142
14150
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
14143
14151
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
14144
|
-
replay: hostCalls.snapshotReplay(),
|
|
14145
14152
|
initialInputs: initialInputs.snapshot,
|
|
14146
|
-
promiseReplay
|
|
14153
|
+
promiseReplay,
|
|
14147
14154
|
random,
|
|
14148
14155
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
14149
14156
|
sourceHash
|
|
@@ -14183,12 +14190,11 @@ function run(source, options = {}) {
|
|
|
14183
14190
|
migration: restoredSnapshot?.migration,
|
|
14184
14191
|
bindings: interpreterSnapshot2.bindings,
|
|
14185
14192
|
clock: options.clock,
|
|
14186
|
-
hostCalls
|
|
14193
|
+
hostCalls,
|
|
14187
14194
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
14188
14195
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
14189
|
-
replay: hostCalls.snapshotReplay(),
|
|
14190
14196
|
initialInputs: initialInputs.snapshot,
|
|
14191
|
-
promiseReplay
|
|
14197
|
+
promiseReplay,
|
|
14192
14198
|
random,
|
|
14193
14199
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
14194
14200
|
sourceHash
|
|
@@ -14205,27 +14211,17 @@ function run(source, options = {}) {
|
|
|
14205
14211
|
await throwIfReturnedPromiseRejected(result2);
|
|
14206
14212
|
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
14207
14213
|
await activeSnapshotScheduler.finish();
|
|
14208
|
-
let replay;
|
|
14209
|
-
let replayError;
|
|
14210
|
-
try {
|
|
14211
|
-
replay = hostCalls.snapshotReplay();
|
|
14212
|
-
} catch (error) {
|
|
14213
|
-
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
14214
|
-
replayError = error.message;
|
|
14215
|
-
}
|
|
14216
14214
|
const snapshot = createRunSnapshot({
|
|
14217
14215
|
executionSemantics,
|
|
14218
14216
|
migration: restoredSnapshot?.migration,
|
|
14219
14217
|
bindings: executionScope.snapshot().bindings,
|
|
14220
14218
|
clock: options.clock,
|
|
14221
|
-
hostCalls
|
|
14222
|
-
replay,
|
|
14219
|
+
hostCalls,
|
|
14223
14220
|
initialInputs: initialInputs.snapshot,
|
|
14224
|
-
promiseReplay
|
|
14221
|
+
promiseReplay,
|
|
14225
14222
|
random,
|
|
14226
14223
|
sourceHash
|
|
14227
14224
|
});
|
|
14228
|
-
if (replayError !== void 0) snapshot.replayError = replayError;
|
|
14229
14225
|
dumpController.finalize(snapshot);
|
|
14230
14226
|
completedSnapshot = snapshot;
|
|
14231
14227
|
reconcileCompiledValues(
|
|
@@ -14402,6 +14398,15 @@ function createExecutableNode(module) {
|
|
|
14402
14398
|
};
|
|
14403
14399
|
}
|
|
14404
14400
|
function createRunSnapshot(input) {
|
|
14401
|
+
let replay;
|
|
14402
|
+
let replayError;
|
|
14403
|
+
try {
|
|
14404
|
+
replay = input.hostCalls.snapshotReplay();
|
|
14405
|
+
} catch (error) {
|
|
14406
|
+
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
14407
|
+
replayError = error.message;
|
|
14408
|
+
}
|
|
14409
|
+
const hostCalls = input.hostCalls.snapshot();
|
|
14405
14410
|
const snapshot = {
|
|
14406
14411
|
version: DUMP_FORMAT_VERSION,
|
|
14407
14412
|
executionSemantics: input.executionSemantics,
|
|
@@ -14409,11 +14414,12 @@ function createRunSnapshot(input) {
|
|
|
14409
14414
|
...input.migration === void 0 ? {} : { migration: structuredClone(input.migration) },
|
|
14410
14415
|
bindings: input.bindings,
|
|
14411
14416
|
clock: input.clock?.snapshot(),
|
|
14412
|
-
...
|
|
14417
|
+
...hostCalls.length === 0 ? {} : { hostCalls },
|
|
14413
14418
|
...input.loopIterations === void 0 ? {} : { loopIterations: input.loopIterations },
|
|
14414
|
-
...
|
|
14419
|
+
...replay === void 0 ? {} : { replay },
|
|
14420
|
+
...replayError === void 0 ? {} : { replayError },
|
|
14415
14421
|
...input.initialInputs === void 0 ? {} : { initialInputs: structuredClone(input.initialInputs) },
|
|
14416
|
-
|
|
14422
|
+
promiseReplay: input.promiseReplay.snapshot(),
|
|
14417
14423
|
...input.pendingAwaits === void 0 || input.pendingAwaits.length === 0 ? {} : { pendingAwaits: input.pendingAwaits },
|
|
14418
14424
|
random: input.random === void 0 ? void 0 : {
|
|
14419
14425
|
seed: input.random.seed,
|
package/dist/safe-js/workerd.js
CHANGED
|
@@ -71259,7 +71259,7 @@ var RealmState = class {
|
|
|
71259
71259
|
this.assertOpen();
|
|
71260
71260
|
const closure = readGuestCallback(callback, this);
|
|
71261
71261
|
this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
|
|
71262
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
71262
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.queuedCallbacks.has(callback);
|
|
71263
71263
|
const record5 = {
|
|
71264
71264
|
closure,
|
|
71265
71265
|
prefixComplete: false
|
|
@@ -71641,7 +71641,7 @@ var RealmState = class {
|
|
|
71641
71641
|
await this.dispose();
|
|
71642
71642
|
this.assertOpen();
|
|
71643
71643
|
if (this.active !== void 0) throw new SandboxError("reentry");
|
|
71644
|
-
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
71644
|
+
const scheduled = this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0;
|
|
71645
71645
|
if (scheduled && (this.phase.getStore()?.active || [...this.pendingCallbacks].some((record5) => !record5.prefixComplete)))
|
|
71646
71646
|
throw new SandboxError("reentry");
|
|
71647
71647
|
const rejectionOwner = scheduled ? this.tracker.startOperation() : void 0;
|
|
@@ -71691,13 +71691,13 @@ var RealmState = class {
|
|
|
71691
71691
|
} finally {
|
|
71692
71692
|
this.tracker.finishOperation(rejectionOwner);
|
|
71693
71693
|
if (this.active === pending) this.active = void 0;
|
|
71694
|
-
if (scheduled) this.reconcileWhenIdle();
|
|
71694
|
+
if (scheduled || this.releaseReconciliation !== void 0) this.reconcileWhenIdle();
|
|
71695
71695
|
}
|
|
71696
71696
|
}
|
|
71697
71697
|
close = () => {
|
|
71698
71698
|
this.closed = true;
|
|
71699
71699
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
71700
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
71700
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
71701
71701
|
const disposal = this.dispose();
|
|
71702
71702
|
if (this.phase.getStore()?.active) {
|
|
71703
71703
|
void disposal.catch(() => void 0);
|
|
@@ -71716,7 +71716,7 @@ var RealmState = class {
|
|
|
71716
71716
|
this.closed = true;
|
|
71717
71717
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
71718
71718
|
this.options.signal?.removeEventListener("abort", this.abort);
|
|
71719
|
-
if (this.options.callbackScheduling === "after-prefix") {
|
|
71719
|
+
if (this.options.callbackScheduling === "after-prefix" || this.releaseReconciliation !== void 0 || this.pendingWork.size > 0) {
|
|
71720
71720
|
this.disposal = Promise.resolve().then(async () => {
|
|
71721
71721
|
while (this.pendingWork.size > 0) await Promise.allSettled([...this.pendingWork]);
|
|
71722
71722
|
await this.sourceGraph?.settle();
|
|
@@ -72264,16 +72264,24 @@ function hasOwnErrorCode(error, code) {
|
|
|
72264
72264
|
var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
|
|
72265
72265
|
var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
|
|
72266
72266
|
var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
72267
|
-
var
|
|
72267
|
+
var adapterOperations = /* @__PURE__ */ new WeakMap();
|
|
72268
72268
|
var FileSnapshotBackend = class {
|
|
72269
72269
|
constructor(path, options = {}) {
|
|
72270
72270
|
this.path = path;
|
|
72271
|
+
const adapter = options.adapter ?? hostFs;
|
|
72272
|
+
let pending = adapterOperations.get(adapter);
|
|
72273
|
+
if (pending === void 0) {
|
|
72274
|
+
pending = /* @__PURE__ */ new Map();
|
|
72275
|
+
adapterOperations.set(adapter, pending);
|
|
72276
|
+
}
|
|
72277
|
+
this.#pendingOperations = pending;
|
|
72271
72278
|
this.#io = options.adapter === void 0 ? hostFs : createFsBridge(options.adapter, { codec: fsCodec });
|
|
72272
72279
|
this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
|
|
72273
72280
|
this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
|
|
72274
72281
|
}
|
|
72275
72282
|
path;
|
|
72276
72283
|
#io;
|
|
72284
|
+
#pendingOperations;
|
|
72277
72285
|
#writeMaxAttempts;
|
|
72278
72286
|
#writeRetryDelayMs;
|
|
72279
72287
|
async read() {
|
|
@@ -72291,6 +72299,7 @@ var FileSnapshotBackend = class {
|
|
|
72291
72299
|
}
|
|
72292
72300
|
async write(snapshot) {
|
|
72293
72301
|
await enqueueOperation(
|
|
72302
|
+
this.#pendingOperations,
|
|
72294
72303
|
this.path,
|
|
72295
72304
|
() => writeSnapshotAtomically(this.#io, this.path, snapshot, {
|
|
72296
72305
|
maxAttempts: this.#writeMaxAttempts,
|
|
@@ -72299,7 +72308,7 @@ var FileSnapshotBackend = class {
|
|
|
72299
72308
|
);
|
|
72300
72309
|
}
|
|
72301
72310
|
async remove() {
|
|
72302
|
-
await enqueueOperation(this.path, async () => {
|
|
72311
|
+
await enqueueOperation(this.#pendingOperations, this.path, async () => {
|
|
72303
72312
|
try {
|
|
72304
72313
|
await this.#io.unlink(this.path);
|
|
72305
72314
|
} catch (error) {
|
|
@@ -72387,7 +72396,7 @@ async function writeSnapshotOnce(io, temporaryPath, snapshotPath, contents) {
|
|
|
72387
72396
|
}
|
|
72388
72397
|
}
|
|
72389
72398
|
}
|
|
72390
|
-
async function enqueueOperation(path, operation) {
|
|
72399
|
+
async function enqueueOperation(pendingOperations, path, operation) {
|
|
72391
72400
|
const previous = pendingOperations.get(path) ?? Promise.resolve();
|
|
72392
72401
|
const pending = previous.catch(() => void 0).then(operation);
|
|
72393
72402
|
const queued = pending.catch(() => void 0);
|
|
@@ -72980,10 +72989,9 @@ function run(source, options = {}) {
|
|
|
72980
72989
|
migration: restoredSnapshot?.migration,
|
|
72981
72990
|
bindings: executionScope.snapshot().bindings,
|
|
72982
72991
|
clock: options.clock,
|
|
72983
|
-
hostCalls
|
|
72984
|
-
replay: hostCalls.snapshotReplay(),
|
|
72992
|
+
hostCalls,
|
|
72985
72993
|
initialInputs: initialInputs.snapshot,
|
|
72986
|
-
promiseReplay
|
|
72994
|
+
promiseReplay,
|
|
72987
72995
|
random,
|
|
72988
72996
|
sourceHash
|
|
72989
72997
|
});
|
|
@@ -73010,12 +73018,11 @@ function run(source, options = {}) {
|
|
|
73010
73018
|
migration: restoredSnapshot?.migration,
|
|
73011
73019
|
bindings: interpreterSnapshot2.bindings,
|
|
73012
73020
|
clock: options.clock,
|
|
73013
|
-
hostCalls
|
|
73021
|
+
hostCalls,
|
|
73014
73022
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
73015
73023
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
73016
|
-
replay: hostCalls.snapshotReplay(),
|
|
73017
73024
|
initialInputs: initialInputs.snapshot,
|
|
73018
|
-
promiseReplay
|
|
73025
|
+
promiseReplay,
|
|
73019
73026
|
random,
|
|
73020
73027
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
73021
73028
|
sourceHash
|
|
@@ -73055,12 +73062,11 @@ function run(source, options = {}) {
|
|
|
73055
73062
|
migration: restoredSnapshot?.migration,
|
|
73056
73063
|
bindings: interpreterSnapshot2.bindings,
|
|
73057
73064
|
clock: options.clock,
|
|
73058
|
-
hostCalls
|
|
73065
|
+
hostCalls,
|
|
73059
73066
|
loopIterations: interpreterSnapshot2.loopIterations,
|
|
73060
73067
|
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
73061
|
-
replay: hostCalls.snapshotReplay(),
|
|
73062
73068
|
initialInputs: initialInputs.snapshot,
|
|
73063
|
-
promiseReplay
|
|
73069
|
+
promiseReplay,
|
|
73064
73070
|
random,
|
|
73065
73071
|
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : void 0,
|
|
73066
73072
|
sourceHash
|
|
@@ -73077,27 +73083,17 @@ function run(source, options = {}) {
|
|
|
73077
73083
|
await throwIfReturnedPromiseRejected(result2);
|
|
73078
73084
|
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
73079
73085
|
await activeSnapshotScheduler.finish();
|
|
73080
|
-
let replay;
|
|
73081
|
-
let replayError;
|
|
73082
|
-
try {
|
|
73083
|
-
replay = hostCalls.snapshotReplay();
|
|
73084
|
-
} catch (error) {
|
|
73085
|
-
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
73086
|
-
replayError = error.message;
|
|
73087
|
-
}
|
|
73088
73086
|
const snapshot = createRunSnapshot({
|
|
73089
73087
|
executionSemantics,
|
|
73090
73088
|
migration: restoredSnapshot?.migration,
|
|
73091
73089
|
bindings: executionScope.snapshot().bindings,
|
|
73092
73090
|
clock: options.clock,
|
|
73093
|
-
hostCalls
|
|
73094
|
-
replay,
|
|
73091
|
+
hostCalls,
|
|
73095
73092
|
initialInputs: initialInputs.snapshot,
|
|
73096
|
-
promiseReplay
|
|
73093
|
+
promiseReplay,
|
|
73097
73094
|
random,
|
|
73098
73095
|
sourceHash
|
|
73099
73096
|
});
|
|
73100
|
-
if (replayError !== void 0) snapshot.replayError = replayError;
|
|
73101
73097
|
dumpController.finalize(snapshot);
|
|
73102
73098
|
completedSnapshot = snapshot;
|
|
73103
73099
|
reconcileCompiledValues(
|
|
@@ -73274,6 +73270,15 @@ function createExecutableNode(module) {
|
|
|
73274
73270
|
};
|
|
73275
73271
|
}
|
|
73276
73272
|
function createRunSnapshot(input) {
|
|
73273
|
+
let replay;
|
|
73274
|
+
let replayError;
|
|
73275
|
+
try {
|
|
73276
|
+
replay = input.hostCalls.snapshotReplay();
|
|
73277
|
+
} catch (error) {
|
|
73278
|
+
if (!(error instanceof MissingReplayCapabilityError)) throw error;
|
|
73279
|
+
replayError = error.message;
|
|
73280
|
+
}
|
|
73281
|
+
const hostCalls = input.hostCalls.snapshot();
|
|
73277
73282
|
const snapshot = {
|
|
73278
73283
|
version: DUMP_FORMAT_VERSION,
|
|
73279
73284
|
executionSemantics: input.executionSemantics,
|
|
@@ -73281,11 +73286,12 @@ function createRunSnapshot(input) {
|
|
|
73281
73286
|
...input.migration === void 0 ? {} : { migration: structuredClone(input.migration) },
|
|
73282
73287
|
bindings: input.bindings,
|
|
73283
73288
|
clock: input.clock?.snapshot(),
|
|
73284
|
-
...
|
|
73289
|
+
...hostCalls.length === 0 ? {} : { hostCalls },
|
|
73285
73290
|
...input.loopIterations === void 0 ? {} : { loopIterations: input.loopIterations },
|
|
73286
|
-
...
|
|
73291
|
+
...replay === void 0 ? {} : { replay },
|
|
73292
|
+
...replayError === void 0 ? {} : { replayError },
|
|
73287
73293
|
...input.initialInputs === void 0 ? {} : { initialInputs: structuredClone(input.initialInputs) },
|
|
73288
|
-
|
|
73294
|
+
promiseReplay: input.promiseReplay.snapshot(),
|
|
73289
73295
|
...input.pendingAwaits === void 0 || input.pendingAwaits.length === 0 ? {} : { pendingAwaits: input.pendingAwaits },
|
|
73290
73296
|
random: input.random === void 0 ? void 0 : {
|
|
73291
73297
|
seed: input.random.seed,
|
|
@@ -73472,11 +73478,14 @@ import {
|
|
|
73472
73478
|
init_paths();
|
|
73473
73479
|
var MISSING_PATH_CODES = ["ENOENT", "ENOTDIR"];
|
|
73474
73480
|
var NOT_A_SYMLINK_CODES = [...MISSING_PATH_CODES, "EINVAL"];
|
|
73475
|
-
|
|
73476
|
-
|
|
73481
|
+
async function resolveCanonicalPath({ realpath, readlink }, path, maxSymlinkFollows = Infinity) {
|
|
73482
|
+
if (maxSymlinkFollows !== Infinity && (!Number.isSafeInteger(maxSymlinkFollows) || maxSymlinkFollows < 0)) {
|
|
73483
|
+
throw new RangeError("maxSymlinkFollows must be a nonnegative safe integer or Infinity");
|
|
73484
|
+
}
|
|
73477
73485
|
const missingSegments = [];
|
|
73478
73486
|
let current = path;
|
|
73479
73487
|
let follows = 0;
|
|
73488
|
+
const visited = /* @__PURE__ */ new Set();
|
|
73480
73489
|
while (true) {
|
|
73481
73490
|
try {
|
|
73482
73491
|
const canonicalCurrent = await realpath(current);
|
|
@@ -73487,9 +73496,10 @@ async function resolveCanonicalPath({ realpath, readlink }, path) {
|
|
|
73487
73496
|
}
|
|
73488
73497
|
const target = await readSymlinkTarget(readlink, current);
|
|
73489
73498
|
if (target !== void 0) {
|
|
73490
|
-
if (++follows >
|
|
73499
|
+
if (++follows > maxSymlinkFollows || visited.has(current)) {
|
|
73491
73500
|
throw createLoopError(path);
|
|
73492
73501
|
}
|
|
73502
|
+
visited.add(current);
|
|
73493
73503
|
current = isAbsolutePath(target) ? target : `${dirname(current)}${sep}${target}`;
|
|
73494
73504
|
continue;
|
|
73495
73505
|
}
|
|
@@ -73702,9 +73712,10 @@ var NULL_BYTE = "\0";
|
|
|
73702
73712
|
var [ACCESS_DENIED_ERRNO, ACCESS_DENIED_MESSAGE] = accessDeniedSystemError;
|
|
73703
73713
|
function makeFsModule(options = {}) {
|
|
73704
73714
|
assertSupportedPlatform();
|
|
73715
|
+
const maxSymlinkFollows = options.maxSymlinkFollows ?? Infinity;
|
|
73705
73716
|
const hostReadMemoryLimit = options.hostReadMemoryLimit ?? Infinity;
|
|
73706
73717
|
const readFileMaxBytes = options.readFileMaxBytes ?? Infinity;
|
|
73707
|
-
for (const limit of [hostReadMemoryLimit, readFileMaxBytes]) {
|
|
73718
|
+
for (const limit of [hostReadMemoryLimit, readFileMaxBytes, maxSymlinkFollows]) {
|
|
73708
73719
|
if (limit !== Infinity && (!Number.isSafeInteger(limit) || limit < 0))
|
|
73709
73720
|
throw new TypeError("Filesystem read limits must be non-negative safe integers or Infinity.");
|
|
73710
73721
|
}
|
|
@@ -73726,7 +73737,7 @@ function makeFsModule(options = {}) {
|
|
|
73726
73737
|
cwd: options.root === void 0 ? options.cwd : void 0,
|
|
73727
73738
|
signal: options.signal
|
|
73728
73739
|
});
|
|
73729
|
-
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal);
|
|
73740
|
+
const fs = options.root === void 0 ? implementation : makeRootedFs(implementation, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
73730
73741
|
let readFile = bindStringResult(fs, "readFile");
|
|
73731
73742
|
if (options.adapter !== void 0) {
|
|
73732
73743
|
const boundedRead = async (args, budget) => {
|
|
@@ -73754,7 +73765,7 @@ function makeFsModule(options = {}) {
|
|
|
73754
73765
|
}
|
|
73755
73766
|
});
|
|
73756
73767
|
const portable = bridge;
|
|
73757
|
-
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal);
|
|
73768
|
+
const boundedFs = options.root === void 0 ? portable : makeRootedFs(portable, options.root, options.adapter, options.cwd, options.signal, maxSymlinkFollows);
|
|
73758
73769
|
return await invoke(boundedFs, "readFile", args);
|
|
73759
73770
|
};
|
|
73760
73771
|
const directRead = declare("readFile", "re-issue", (...args) => boundedRead(args));
|
|
@@ -73846,7 +73857,7 @@ function invoke(fs, name, args) {
|
|
|
73846
73857
|
return Reflect.apply(fs[name], fs, args);
|
|
73847
73858
|
}
|
|
73848
73859
|
var rootedFsOperations = /* @__PURE__ */ new WeakMap();
|
|
73849
|
-
function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
73860
|
+
function makeRootedFs(fs, root, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
73850
73861
|
if (root.trim().length === 0) {
|
|
73851
73862
|
throw new Error("fs module root must be a non-empty string.");
|
|
73852
73863
|
}
|
|
@@ -73867,7 +73878,7 @@ function makeRootedFs(fs, root, adapter, cwd, signal) {
|
|
|
73867
73878
|
return await invoke(
|
|
73868
73879
|
fs,
|
|
73869
73880
|
name,
|
|
73870
|
-
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal)
|
|
73881
|
+
await resolvePathArguments(fs, resolvedRoot, name, args, adapter, cwd, signal, maxSymlinkFollows)
|
|
73871
73882
|
);
|
|
73872
73883
|
} finally {
|
|
73873
73884
|
release();
|
|
@@ -73888,8 +73899,8 @@ function assertRootCanConfineOptions(name, args) {
|
|
|
73888
73899
|
throw createUnsupportedOptionError("cp", "dereference", ROOT_REFUSED_DEREFERENCE_REASON);
|
|
73889
73900
|
}
|
|
73890
73901
|
}
|
|
73891
|
-
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal) {
|
|
73892
|
-
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root));
|
|
73902
|
+
async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal, maxSymlinkFollows = Infinity) {
|
|
73903
|
+
const canonicalRoot = await resolveCanonicalPath(readCanonicalPathFs(fs), resolve(root), maxSymlinkFollows);
|
|
73893
73904
|
const base = cwd ?? canonicalRoot;
|
|
73894
73905
|
const resolved = [...args];
|
|
73895
73906
|
if (name === "symlink") {
|
|
@@ -73913,7 +73924,7 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
73913
73924
|
await assertInsideRoot(fs, canonicalRoot, name, [checkedTarget, linkPath], adapter, signal, [
|
|
73914
73925
|
targetPath,
|
|
73915
73926
|
linkPath
|
|
73916
|
-
]);
|
|
73927
|
+
], maxSymlinkFollows);
|
|
73917
73928
|
return resolved;
|
|
73918
73929
|
}
|
|
73919
73930
|
const paths = FS_PATH_ARGUMENTS[name].map((_, index) => {
|
|
@@ -73921,12 +73932,12 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
73921
73932
|
resolved[index] = path;
|
|
73922
73933
|
return path;
|
|
73923
73934
|
});
|
|
73924
|
-
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal);
|
|
73935
|
+
await assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, paths, maxSymlinkFollows);
|
|
73925
73936
|
if (name === "mkdtemp") {
|
|
73926
73937
|
const prefix = args[0];
|
|
73927
73938
|
const absolutePrefix = isAbsolutePath(prefix) ? prefix : `${base}${sep}${prefix}`;
|
|
73928
73939
|
const parent = absolutePrefix.endsWith(sep) ? absolutePrefix : dirname(absolutePrefix);
|
|
73929
|
-
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths);
|
|
73940
|
+
await assertInsideRoot(fs, canonicalRoot, name, [parent], adapter, signal, paths, maxSymlinkFollows);
|
|
73930
73941
|
resolved[0] = absolutePrefix;
|
|
73931
73942
|
}
|
|
73932
73943
|
if (adapter !== void 0 && name === "mkdir") {
|
|
@@ -73944,15 +73955,15 @@ async function resolvePathArguments(fs, root, name, args, adapter, cwd, signal)
|
|
|
73944
73955
|
}
|
|
73945
73956
|
return resolved;
|
|
73946
73957
|
}
|
|
73947
|
-
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths) {
|
|
73958
|
+
async function assertInsideRoot(fs, canonicalRoot, name, paths, adapter, signal, reportedPaths = paths, maxSymlinkFollows = Infinity) {
|
|
73948
73959
|
for (const path of paths) {
|
|
73949
|
-
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal)) {
|
|
73960
|
+
if (await escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows)) {
|
|
73950
73961
|
throw createAccessDeniedError(name, reportedPaths[0], reportedPaths[1]);
|
|
73951
73962
|
}
|
|
73952
73963
|
}
|
|
73953
73964
|
}
|
|
73954
|
-
async function escapesRoot(fs, canonicalRoot, path, adapter, signal) {
|
|
73955
|
-
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path);
|
|
73965
|
+
async function escapesRoot(fs, canonicalRoot, path, adapter, signal, maxSymlinkFollows = Infinity) {
|
|
73966
|
+
const canonicalPath = await resolveCanonicalPath(readCanonicalPathFs(fs), path, maxSymlinkFollows);
|
|
73956
73967
|
return !await (adapter === void 0 ? containsPath(readStat(fs), canonicalRoot, canonicalPath) : containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal));
|
|
73957
73968
|
}
|
|
73958
73969
|
async function containsAdapterPath(adapter, canonicalRoot, canonicalPath, signal) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poe-platform/safe-js",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.802",
|
|
4
4
|
"description": "Budgeted JavaScript interpreter with explicit host capabilities and resumable execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"access": "public"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@poe-platform/safe-fs": "0.1.
|
|
85
|
+
"@poe-platform/safe-fs": "0.1.802",
|
|
86
86
|
"@petamoriken/float16": "^3.9.3",
|
|
87
87
|
"@noble/hashes": "2.4.0",
|
|
88
88
|
"@formatjs/intl-localematcher": "0.8.13",
|