@poe-platform/safe-js 0.1.729 → 0.1.731
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 +5 -5
- package/dist/safe-js/chunks/{chunk-SJZWSPWD.js → chunk-2GVBG23M.js} +1 -1
- package/dist/safe-js/chunks/{chunk-SJZWSPWD.js.map → chunk-2GVBG23M.js.map} +1 -1
- package/dist/safe-js/chunks/{chunk-VIMROAQA.js → chunk-E4XLBT7R.js} +2 -2
- package/dist/safe-js/chunks/chunk-F6CV74HU.js +114 -0
- package/dist/safe-js/chunks/chunk-F6CV74HU.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-OZLTLIHX.js → chunk-G6WTEIJJ.js} +2 -2
- package/dist/safe-js/chunks/{chunk-XX57YCGZ.js → chunk-GNEORAQI.js} +55 -50
- package/dist/safe-js/chunks/chunk-GNEORAQI.js.map +7 -0
- package/dist/safe-js/chunks/chunk-GVKXZW53.js +76 -0
- package/dist/safe-js/chunks/chunk-GVKXZW53.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-2S4YRXI6.js → chunk-IRDQDZ5R.js} +4 -4
- package/dist/safe-js/chunks/{chunk-MRULOD5J.js → chunk-K4T4EBED.js} +59 -38
- package/dist/safe-js/chunks/chunk-K4T4EBED.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-MFCEBCGV.js → chunk-KETIFEA7.js} +17 -8
- package/dist/safe-js/chunks/chunk-KETIFEA7.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-S5YDMMM3.js → chunk-MDIWQFYU.js} +95 -169
- package/dist/safe-js/chunks/{chunk-S5YDMMM3.js.map → chunk-MDIWQFYU.js.map} +4 -4
- package/dist/safe-js/chunks/{chunk-BRBOVGNC.js → chunk-MGHE7ZFI.js} +78 -67
- package/dist/safe-js/chunks/chunk-MGHE7ZFI.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-EN724VH3.js → chunk-O4IDRXW7.js} +4 -4
- package/dist/safe-js/chunks/{chunk-EA7AHM2X.js → chunk-PSVV3IG2.js} +3 -3
- package/dist/safe-js/chunks/{chunk-Y5EZYHU6.js → chunk-QKO4FATZ.js} +33 -5
- package/dist/safe-js/chunks/chunk-QKO4FATZ.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-EG3QWREA.js → chunk-RULU2F5J.js} +2 -2
- package/dist/safe-js/chunks/chunk-UQPYTZOZ.js +72 -0
- package/dist/safe-js/chunks/chunk-UQPYTZOZ.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-LRSWTDIV.js → chunk-W4SWUHCQ.js} +58 -23
- package/dist/safe-js/chunks/chunk-W4SWUHCQ.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-W3IY6FKO.js → chunk-WS2FJBH6.js} +2 -2
- package/dist/safe-js/chunks/{chunk-MVLDRXWS.js → chunk-X3CKAZQ4.js} +3 -3
- package/dist/safe-js/chunks/chunk-YUQFFRUF.js +26 -0
- package/dist/safe-js/chunks/chunk-YUQFFRUF.js.map +7 -0
- package/dist/safe-js/chunks/{cli-runtime-6VVBO2SS.js → cli-runtime-NUEFUM64.js} +51 -30
- package/dist/safe-js/chunks/cli-runtime-NUEFUM64.js.map +7 -0
- package/dist/safe-js/chunks/{dump-UNYK24YS.js → dump-RGRC3CG3.js} +5 -4
- package/dist/safe-js/chunks/harness-UMOMFXDT.js +11 -0
- package/dist/safe-js/chunks/mcp-S672263Q.js +12 -0
- package/dist/safe-js/chunks/migration-file-KRXQYI3Q.js +15 -0
- package/dist/safe-js/chunks/restore-GEO7VN2R.js +14 -0
- package/dist/safe-js/chunks/run-ZSFX66RN.js +20 -0
- package/dist/safe-js/chunks/runtime-modules-A3U2DKFL.js +11 -0
- package/dist/safe-js/chunks/source-files-L3SGK63Z.js +10 -0
- package/dist/safe-js/cli-runtime.d.ts +2 -0
- package/dist/safe-js/cli.js +4 -4
- package/dist/safe-js/core.d.ts +1 -0
- package/dist/safe-js/core.js +15 -8
- package/dist/safe-js/error/shape.js +170 -0
- package/dist/safe-js/index.js +42 -33
- package/dist/safe-js/index.js.map +2 -2
- package/dist/safe-js/interp/budget.js +600 -0
- package/dist/safe-js/interp/internal-symbols.js +1 -0
- package/dist/safe-js/interp/promise-replay.d.ts +1 -1
- package/dist/safe-js/interp/template-cache.js +7 -0
- package/dist/safe-js/migration-file.d.ts +2 -0
- package/dist/safe-js/modules/fs-config.d.ts +3 -1
- package/dist/safe-js/modules/fs.d.ts +8 -4
- package/dist/safe-js/modules/fs.js +16 -0
- package/dist/safe-js/modules/source-files.d.ts +3 -2
- package/dist/safe-js/platform/context.js +58 -0
- package/dist/safe-js/platform/node.js +64 -0
- package/dist/safe-js/platform/types.js +63 -0
- package/dist/safe-js/platform/workerd.js +39 -0
- package/dist/safe-js/runner/run-harness.d.ts +2 -0
- package/dist/safe-js/snapshot/backend.d.ts +2 -0
- package/package.json +9 -2
- package/dist/safe-js/chunks/chunk-BRBOVGNC.js.map +0 -7
- package/dist/safe-js/chunks/chunk-FCCA27RC.js +0 -69
- package/dist/safe-js/chunks/chunk-FCCA27RC.js.map +0 -7
- package/dist/safe-js/chunks/chunk-LRSWTDIV.js.map +0 -7
- package/dist/safe-js/chunks/chunk-MFCEBCGV.js.map +0 -7
- package/dist/safe-js/chunks/chunk-MRULOD5J.js.map +0 -7
- package/dist/safe-js/chunks/chunk-XX57YCGZ.js.map +0 -7
- package/dist/safe-js/chunks/chunk-Y5EZYHU6.js.map +0 -7
- package/dist/safe-js/chunks/cli-runtime-6VVBO2SS.js.map +0 -7
- package/dist/safe-js/chunks/fs-AOV77RQC.js +0 -13
- package/dist/safe-js/chunks/harness-ZIEO7NAV.js +0 -10
- package/dist/safe-js/chunks/mcp-WBM7ZOAN.js +0 -11
- package/dist/safe-js/chunks/migration-file-3SWGNDS2.js +0 -12
- package/dist/safe-js/chunks/restore-FCTWPLU3.js +0 -13
- package/dist/safe-js/chunks/run-ESJHEXCE.js +0 -17
- package/dist/safe-js/chunks/runtime-modules-7V6BWCRK.js +0 -10
- package/dist/safe-js/chunks/source-files-73OHLNGH.js +0 -8
- /package/dist/safe-js/chunks/{chunk-VIMROAQA.js.map → chunk-E4XLBT7R.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-OZLTLIHX.js.map → chunk-G6WTEIJJ.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-2S4YRXI6.js.map → chunk-IRDQDZ5R.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-EN724VH3.js.map → chunk-O4IDRXW7.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-EA7AHM2X.js.map → chunk-PSVV3IG2.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-EG3QWREA.js.map → chunk-RULU2F5J.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-W3IY6FKO.js.map → chunk-WS2FJBH6.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-MVLDRXWS.js.map → chunk-X3CKAZQ4.js.map} +0 -0
- /package/dist/safe-js/chunks/{dump-UNYK24YS.js.map → dump-RGRC3CG3.js.map} +0 -0
- /package/dist/safe-js/chunks/{fs-AOV77RQC.js.map → harness-UMOMFXDT.js.map} +0 -0
- /package/dist/safe-js/chunks/{harness-ZIEO7NAV.js.map → mcp-S672263Q.js.map} +0 -0
- /package/dist/safe-js/chunks/{mcp-WBM7ZOAN.js.map → migration-file-KRXQYI3Q.js.map} +0 -0
- /package/dist/safe-js/chunks/{migration-file-3SWGNDS2.js.map → restore-GEO7VN2R.js.map} +0 -0
- /package/dist/safe-js/chunks/{restore-FCTWPLU3.js.map → run-ZSFX66RN.js.map} +0 -0
- /package/dist/safe-js/chunks/{run-ESJHEXCE.js.map → runtime-modules-A3U2DKFL.js.map} +0 -0
- /package/dist/safe-js/chunks/{runtime-modules-7V6BWCRK.js.map → source-files-L3SGK63Z.js.map} +0 -0
- /package/dist/safe-js/{chunks/source-files-73OHLNGH.js.map → modules/fs.js.map} +0 -0
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ console.log(result.returnValue);
|
|
|
36
36
|
|
|
37
37
|
`run()` takes source text, not a file path. Success returns `ok`, `returnValue`, `snapshot`, and `stats`. Handle both an `ok: false` result and a rejected promise: parsing, budget exhaustion, cancellation, and some execution failures can reject. Top-level `await` in this example lets rejections reach Node.
|
|
38
38
|
|
|
39
|
-
`@poe-platform/safe-js/core` exposes `run`, `createRealm`, `defineExtension`, `lint`, `Budget`, and replayable-random helpers. The shared filesystem lives in `@poe-platform/safe-fs`, with a portable `/core` entry. Existing `@poe-platform/safe-js/fs`, `/fs/core`, and `/fs/node` imports re-export it. Legacy `poe-code/safe-js` imports remain available through the CLI package but use a separate runtime; keep factories and errors within one import family.
|
|
39
|
+
`@poe-platform/safe-js/core` exposes `run`, `createRealm`, `defineExtension`, `lint`, `Budget`, and replayable-random helpers. The `/core`, `/workerd`, and `/modules/fs` workspace entries bundle with the `workerd` or `browser` condition without Node built-ins. Supply a `@poe-code/safe-fs` adapter for filesystem capabilities; `createRootedSourceResolver(root, adapter)` grants portable source imports. File snapshots, migrations, harnesses, and file-running helpers also accept an `adapter`. The shared filesystem lives in `@poe-platform/safe-fs`, with a portable `/core` entry. Existing `@poe-platform/safe-js/fs`, `/fs/core`, and `/fs/node` imports re-export it. Legacy `poe-code/safe-js` imports remain available through the CLI package but use a separate runtime; keep factories and errors within one import family.
|
|
40
40
|
|
|
41
41
|
## Supported features
|
|
42
42
|
|
|
@@ -237,7 +237,7 @@ Execution gives host timers and cancellation turns between guest nodes after ela
|
|
|
237
237
|
| `extensions` | Explicit `defineExtension(...)` registrations; `[]`. Setup runs once, on first evaluation, not on construction or unused close. |
|
|
238
238
|
| `grants` | Granted capability names; `[]`. Every requested capability must be granted before any extension setup runs. |
|
|
239
239
|
| `builtinOverrides` | Optional `{ console: "extension-name" }` authorizes that registered extension to replace only the builtin console. It must declare `console` and export a host object created in the realm. No overrides by default. |
|
|
240
|
-
| `limits` |
|
|
240
|
+
| `limits` | Optional positive integer caps for `extensions`, `hostObjects`, `callbacks`, `guestReferences`, `cleanups`, and `nestedEvaluations`. Every cap defaults to `Infinity` and accepts explicit `Infinity`. Collection budgets also apply. |
|
|
241
241
|
| `stringCompilation` | Optional `"allow"` (default) or `"deny"`. Denial raises a catchable guest EvalError for string eval and Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction compilation, including retained callbacks. Host source evaluation remains available. This is separate from WebAssembly compilation policy. |
|
|
242
242
|
| `classicScripts` | Optional boolean, default `false`. Evaluations use classic Script grammar with persistent globals: top-level `this` is the intrinsic global object, `var` and functions create global properties, and `let`/`const` remain lexical. Injected capabilities stay immutable lexical bindings. Explicit source modules retain module semantics. |
|
|
243
243
|
| `classicScriptErrors` | Optional `"fatal"` (default) or `"report"`; reporting requires `classicScripts: true`. Ordinary escaped Script exceptions return `ok: false` with `recoverable: true` while preserving realm state. Syntax, budget, cancellation, module, callback and unhandled rejection failures remain fatal. |
|
|
@@ -445,7 +445,7 @@ For one-shot use, `run(source, { extensions, grants, ... })` accepts the same re
|
|
|
445
445
|
| `snapshotIntervalMs` | Periodic checkpoint interval when persistence is configured: 30,000 ms; `0` disables periodic writes. Capture happens at interpreter yield points. |
|
|
446
446
|
| `hostCallResumeProvider` | Reconciles pending external operations on restore; returns a matching `HostCallResumeProof`. |
|
|
447
447
|
|
|
448
|
-
`new Budget(options?)` accepts optional limits.
|
|
448
|
+
`new Budget(options?)` accepts optional limits, each unlimited by default. Explicit `Infinity` also disables a limit. Set `maxCallDepth` to opt into a recursion guard in `run()` or `createRealm()`.
|
|
449
449
|
|
|
450
450
|
| Option | Limit |
|
|
451
451
|
| --- | --- |
|
|
@@ -536,7 +536,7 @@ Factories return exports to register in `modules`; calling a factory alone does
|
|
|
536
536
|
| --- | --- |
|
|
537
537
|
| `makeAgentModule(spawnAgent, options?)` | Inject the agent runner. Options: `defaultRetry`, `onEvent`, `otelSink`. Exposes `spawn`, `spawn.retry`, and `spawn.parallel`; call options follow this table. |
|
|
538
538
|
| `makeMcpModule(options)` | Required `servers` map: stdio `{ command, args?, cwd?, env? }` or HTTP `{ url, headers? }`. Options: `requestTimeoutMs` (30,000), `closeTimeoutMs` (1,000), `maxToolPages` (100), `signal`, and injected `fetch`/`spawn`. Named clients expose `tools`, `tool`, `toolBatch`, and `close`; close managed clients when finished. A custom connector function is also accepted. |
|
|
539
|
-
| `makeFsModule(options?)` | Node-backed `{ root?, fs? }`, or shared-filesystem `{ adapter, root?, cwd?, signal? }`; do not combine `fs` and `adapter`. Node access without `root` is unconfined. Rooted calls sharing the same adapter or Node implementation are serialized through path checks and backend completion to prevent guest namespace races. External host mutations or distinct adapters over the same storage require independent backend confinement. With an adapter, `root` confines access and `cwd` selects the virtual relative-path base; without `root`, explicit `cwd` also confines access. Omitting both uses virtual `/`. Adapter text reads pass a byte cap derived conservatively from the guest string and remaining data limits to the backend before decoding.
|
|
539
|
+
| `makeFsModule(options?)` | Node-backed `{ root?, fs? }`, or shared-filesystem `{ adapter, root?, cwd?, signal? }`; do not combine `fs` and `adapter`. Node access without `root` is unconfined. Rooted calls sharing the same adapter or Node implementation are serialized through path checks and backend completion to prevent guest namespace races. External host mutations or distinct adapters over the same storage require independent backend confinement. With an adapter, `root` confines access and `cwd` selects the virtual relative-path base; without `root`, explicit `cwd` also confines access. Omitting both uses virtual `/`. Adapter text reads pass a byte cap derived conservatively from the guest string and remaining data limits to the backend before decoding. Optional `readFileMaxBytes` and `hostReadMemoryLimit` default to `Infinity` and accept explicit `Infinity`. A finite host allowance reserves ten bytes per input byte for collection, copies, encoding expansion and admission across concurrent reads from that module; reservations release after the underlying read settles and decoding finishes, including when cancellation rejects the caller earlier. Native Node/injected `fs` implementations retain their own read behavior. Read text with `readFile(path, "utf8")`; see the [module methods](src/modules/fs.ts) and [filesystem package](../safe-fs/README.md). |
|
|
540
540
|
| `makeEnvModule(namesOrOptions)` | Allowed-name array or `{ allow, values? }`; exposes `get(name)`. `parseEnvConfig(json)` accepts the object form. |
|
|
541
541
|
| `makeTimeModule(options?)` | `now`, `random`, `seed`, `signal`; exposes `now`, `random`, `sleep`, `uuid`. Defaults to host time/randomness; `seed` makes the random generator deterministic, and explicit `random` takes precedence. |
|
|
542
542
|
| `makeLogModule(sink)` | Sends timestamped `info`, `error`, and `event` entries to your callback. |
|
|
@@ -548,7 +548,7 @@ Factories return exports to register in `modules`; calling a factory alone does
|
|
|
548
548
|
|
|
549
549
|
`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)`.
|
|
550
550
|
|
|
551
|
-
**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? }`; `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.
|
|
551
|
+
**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.
|
|
552
552
|
|
|
553
553
|
</details>
|
|
554
554
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/error-codes.ts"],
|
|
4
|
-
"sourcesContent": ["export function getOwnErrorCode(error: unknown): string | undefined {\n if (\n typeof error !== \"object\" ||\n error === null ||\n !Object.prototype.hasOwnProperty.call(error, \"code\")\n ) {\n return undefined;\n }\n\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nexport function hasOwnErrorCode(error: unknown, code: string): error is NodeJS.ErrnoException {\n return getOwnErrorCode(error) === code;\n}\n"],
|
|
4
|
+
"sourcesContent": ["export function getOwnErrorCode(error: unknown): string | undefined {\n if (\n typeof error !== \"object\" ||\n error === null ||\n !Object.prototype.hasOwnProperty.call(error, \"code\")\n ) {\n return undefined;\n }\n\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nexport function hasOwnErrorCode(error: unknown, code: string): error is NodeJS.ErrnoException {\n return getOwnErrorCode(error) === code;\n}\n\nexport type SystemError = Error & { code?: string; errno?: number; syscall?: string; path?: string; dest?: string };\n"],
|
|
5
5
|
"mappings": ";AAAO,SAAS,gBAAgB,OAAoC;AAClE,MACE,OAAO,UAAU,YACjB,UAAU,QACV,CAAC,OAAO,UAAU,eAAe,KAAK,OAAO,MAAM,GACnD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAQ,MAA6B;AAC3C,SAAO,OAAO,SAAS,WAAW,OAAO;AAC3C;AAEO,SAAS,gBAAgB,OAAgB,MAA8C;AAC5F,SAAO,gBAAgB,KAAK,MAAM;AACpC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isSandboxClosure
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MDIWQFYU.js";
|
|
4
4
|
|
|
5
5
|
// packages/safe-js/src/lint/runtime-modules.ts
|
|
6
6
|
var AsyncFunction = (async () => void 0).constructor;
|
|
@@ -34,4 +34,4 @@ function isAsyncRuntimeExport(value) {
|
|
|
34
34
|
export {
|
|
35
35
|
createLintModulesFromRuntimeRegistry
|
|
36
36
|
};
|
|
37
|
-
//# sourceMappingURL=chunk-
|
|
37
|
+
//# sourceMappingURL=chunk-E4XLBT7R.js.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
paths_default
|
|
3
|
+
} from "./chunk-YUQFFRUF.js";
|
|
4
|
+
import {
|
|
5
|
+
constants,
|
|
6
|
+
hostFs
|
|
7
|
+
} from "./chunk-UQPYTZOZ.js";
|
|
8
|
+
|
|
9
|
+
// packages/safe-js/src/modules/source-files.ts
|
|
10
|
+
import { resolvePath } from "@poe-platform/safe-fs/core";
|
|
11
|
+
async function createRootedSourceResolver(root, adapter) {
|
|
12
|
+
const realpath = (filename) => adapter ? adapter.realpath(filename) : hostFs.realpath(filename);
|
|
13
|
+
const stat = async (filename) => adapter ? sourceStat(await adapter.stat(filename)) : await hostFs.stat(filename);
|
|
14
|
+
const granted = adapter ? resolvePath("/", root) : paths_default.resolve(root);
|
|
15
|
+
const directory = await realpath(granted);
|
|
16
|
+
if (!(await stat(directory)).isDirectory()) throw new TypeError("Source module root must be a directory.");
|
|
17
|
+
const contains = (filename) => {
|
|
18
|
+
const relative = paths_default.relative(directory, filename);
|
|
19
|
+
return relative !== ".." && !relative.startsWith(`..${paths_default.sep}`) && !paths_default.isAbsolute(relative);
|
|
20
|
+
};
|
|
21
|
+
const resolver = async (specifier, referrer, { signal }) => {
|
|
22
|
+
signal?.throwIfAborted();
|
|
23
|
+
if (!specifier.startsWith("./") && !specifier.startsWith("../") || !paths_default.isAbsolute(referrer)) return void 0;
|
|
24
|
+
const relative = paths_default.relative(granted, referrer);
|
|
25
|
+
const canonicalReferrer = relative !== ".." && !relative.startsWith(`..${paths_default.sep}`) && !paths_default.isAbsolute(relative) ? paths_default.resolve(directory, relative) : referrer;
|
|
26
|
+
if (!contains(canonicalReferrer)) return void 0;
|
|
27
|
+
const candidate = paths_default.resolve(paths_default.dirname(canonicalReferrer), specifier);
|
|
28
|
+
if (!contains(candidate)) return void 0;
|
|
29
|
+
try {
|
|
30
|
+
const id = await realpath(candidate);
|
|
31
|
+
signal?.throwIfAborted();
|
|
32
|
+
if (!contains(id)) return void 0;
|
|
33
|
+
const expected = await stat(id);
|
|
34
|
+
signal?.throwIfAborted();
|
|
35
|
+
if (!expected.isFile()) return void 0;
|
|
36
|
+
const handle = adapter ? await openSourceFile(adapter, id, signal) : await hostFs.open(id, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
37
|
+
try {
|
|
38
|
+
signal?.throwIfAborted();
|
|
39
|
+
const actual = await handle.stat();
|
|
40
|
+
signal?.throwIfAborted();
|
|
41
|
+
if (!actual.isFile() || ("identity" in actual && "identity" in expected ? !sameSourceIdentity(actual.identity, expected.identity) : actual.dev !== expected.dev || actual.ino !== expected.ino)) return void 0;
|
|
42
|
+
const currentId = await realpath(id);
|
|
43
|
+
signal?.throwIfAborted();
|
|
44
|
+
if (currentId !== id) return void 0;
|
|
45
|
+
const source = await handle.readFile({ encoding: "utf8", signal });
|
|
46
|
+
signal?.throwIfAborted();
|
|
47
|
+
return { id, source };
|
|
48
|
+
} finally {
|
|
49
|
+
await handle.close();
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
signal?.throwIfAborted();
|
|
53
|
+
if (error !== null && typeof error === "object" && "code" in error && ["ENOENT", "ENOTDIR", "ELOOP"].includes(String(error.code))) return void 0;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
return Object.assign(resolver, { async entryId(filename) {
|
|
58
|
+
if (filename === void 0) return paths_default.join(directory, "<entry>");
|
|
59
|
+
const supplied = paths_default.resolve(granted, filename);
|
|
60
|
+
const relative = paths_default.relative(granted, supplied);
|
|
61
|
+
const candidate = relative !== ".." && !relative.startsWith(`..${paths_default.sep}`) && !paths_default.isAbsolute(relative) ? paths_default.resolve(directory, relative) : supplied;
|
|
62
|
+
if (!contains(candidate)) throw new TypeError("Source entry must be inside its granted root.");
|
|
63
|
+
try {
|
|
64
|
+
const id = await realpath(candidate);
|
|
65
|
+
if (!contains(id)) throw new TypeError("Source entry must be inside its granted root.");
|
|
66
|
+
return id;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if (error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT") return candidate;
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
} });
|
|
72
|
+
}
|
|
73
|
+
function sourceStat(value) {
|
|
74
|
+
return {
|
|
75
|
+
identity: value,
|
|
76
|
+
dev: value.dev,
|
|
77
|
+
ino: value.ino,
|
|
78
|
+
isFile: () => value.type === "file",
|
|
79
|
+
isDirectory: () => value.type === "directory"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function sameSourceIdentity(actual, expected) {
|
|
83
|
+
if (expected.identityScope !== void 0 && expected.opaqueIdentity !== void 0) {
|
|
84
|
+
return actual.identityScope === expected.identityScope && actual.opaqueIdentity === expected.opaqueIdentity && (expected.opaqueVersion === void 0 || actual.opaqueVersion === expected.opaqueVersion);
|
|
85
|
+
}
|
|
86
|
+
return expected.dev !== void 0 && expected.ino !== void 0 && actual.dev === expected.dev && actual.ino === expected.ino;
|
|
87
|
+
}
|
|
88
|
+
async function openSourceFile(adapter, id, signal) {
|
|
89
|
+
if (!adapter.openReadFile) throw new TypeError("Source filesystem must support retained reads.");
|
|
90
|
+
const handle = await adapter.openReadFile(id, signal ? { signal } : {});
|
|
91
|
+
return {
|
|
92
|
+
stat: async () => sourceStat(await handle.stat(signal ? { signal } : {})),
|
|
93
|
+
close: handle.close.bind(handle),
|
|
94
|
+
async readFile(_options) {
|
|
95
|
+
const decoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
96
|
+
const chunks = [];
|
|
97
|
+
let position = 0;
|
|
98
|
+
for (; ; ) {
|
|
99
|
+
signal?.throwIfAborted();
|
|
100
|
+
const chunk = await handle.read(position, 64 * 1024, signal ? { signal } : {});
|
|
101
|
+
if (chunk.byteLength === 0) break;
|
|
102
|
+
chunks.push(decoder.decode(chunk, { stream: true }));
|
|
103
|
+
position += chunk.byteLength;
|
|
104
|
+
}
|
|
105
|
+
chunks.push(decoder.decode());
|
|
106
|
+
return chunks.join("");
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
createRootedSourceResolver
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=chunk-F6CV74HU.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/modules/source-files.ts"],
|
|
4
|
+
"sourcesContent": ["import {hostFs, fsConstants as constants} from \"#safe-js-platform\";\nimport {resolvePath, type FileSystem, type FileStat} from \"@poe-code/safe-fs/core\";\n\nimport path from \"./paths.js\";\nimport type {SourceResolver} from \"./source-graph.js\";\n\n/** Explicit filesystem grant. No package lookup, extension search, or URL loading. */\nexport async function createRootedSourceResolver(root: string, adapter?: FileSystem): Promise<SourceResolver & {\n entryId(filename?: string): Promise<string>;\n}> {\n const realpath = (filename: string) => adapter ? adapter.realpath(filename) : hostFs.realpath(filename);\n const stat = async (filename: string) => adapter ? sourceStat(await adapter.stat(filename)) : await hostFs.stat(filename);\n const granted = adapter ? resolvePath(\"/\", root) : path.resolve(root);\n const directory = await realpath(granted);\n if (!(await stat(directory)).isDirectory()) throw new TypeError(\"Source module root must be a directory.\");\n const contains = (filename: string) => {\n const relative = path.relative(directory,filename);\n return relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n };\n const resolver: SourceResolver = async (specifier,referrer,{signal}) => {\n signal?.throwIfAborted();\n if ((!specifier.startsWith(\"./\") && !specifier.startsWith(\"../\")) || !path.isAbsolute(referrer)) return undefined;\n const relative = path.relative(granted,referrer);\n const canonicalReferrer = relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)\n ? path.resolve(directory,relative) : referrer;\n if (!contains(canonicalReferrer)) return undefined;\n const candidate = path.resolve(path.dirname(canonicalReferrer),specifier);\n if (!contains(candidate)) return undefined;\n try {\n const id = await realpath(candidate);\n signal?.throwIfAborted();\n if (!contains(id)) return undefined;\n const expected = await stat(id);\n signal?.throwIfAborted();\n if (!expected.isFile()) return undefined;\n const handle = adapter\n ? await openSourceFile(adapter, id, signal)\n : await hostFs.open(id,constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n try {\n signal?.throwIfAborted();\n const actual = await handle.stat();\n signal?.throwIfAborted();\n // Read the checked inode, never reopen its pathname. These checks deny\n // observed replacements; Node's path APIs do not provide atomic ancestor\n // confinement against an adversary repeatedly swapping directories.\n if (!actual.isFile() || (\"identity\" in actual && \"identity\" in expected\n ? !sameSourceIdentity(actual.identity, expected.identity)\n : actual.dev !== expected.dev || actual.ino !== expected.ino)) return undefined;\n const currentId = await realpath(id);\n signal?.throwIfAborted();\n if (currentId !== id) return undefined;\n const source = await handle.readFile({encoding:\"utf8\",signal});\n signal?.throwIfAborted();\n return {id,source};\n } finally {await handle.close();}\n } catch (error) {\n signal?.throwIfAborted();\n if (error !== null && typeof error === \"object\" && \"code\" in error &&\n [\"ENOENT\",\"ENOTDIR\",\"ELOOP\"].includes(String(error.code))) return undefined;\n throw error;\n }\n };\n return Object.assign(resolver, {async entryId(filename?: string): Promise<string> {\n if (filename === undefined) return path.join(directory,\"<entry>\");\n const supplied = path.resolve(granted,filename);\n const relative = path.relative(granted,supplied);\n const candidate = relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)\n ? path.resolve(directory,relative) : supplied;\n if (!contains(candidate)) throw new TypeError(\"Source entry must be inside its granted root.\");\n try {\n const id = await realpath(candidate);\n if (!contains(id)) throw new TypeError(\"Source entry must be inside its granted root.\");\n return id;\n } catch (error) {\n if (error !== null && typeof error === \"object\" && \"code\" in error && error.code === \"ENOENT\") return candidate;\n throw error;\n }\n }});\n}\n\nfunction sourceStat(value: FileStat) {\n return {identity: value, dev: value.dev, ino: value.ino,\n isFile: () => value.type === \"file\", isDirectory: () => value.type === \"directory\"};\n}\n\nfunction sameSourceIdentity(actual: FileStat, expected: FileStat): boolean {\n if (expected.identityScope !== undefined && expected.opaqueIdentity !== undefined) {\n return actual.identityScope === expected.identityScope && actual.opaqueIdentity === expected.opaqueIdentity &&\n (expected.opaqueVersion === undefined || actual.opaqueVersion === expected.opaqueVersion);\n }\n return expected.dev !== undefined && expected.ino !== undefined && actual.dev === expected.dev && actual.ino === expected.ino;\n}\n\nasync function openSourceFile(adapter: FileSystem, id: string, signal?: AbortSignal) {\n if (!adapter.openReadFile) throw new TypeError(\"Source filesystem must support retained reads.\");\n const handle = await adapter.openReadFile(id, signal ? {signal} : {});\n return {\n stat: async () => sourceStat(await handle.stat(signal ? {signal} : {})),\n close: handle.close.bind(handle),\n async readFile(_options: {encoding: \"utf8\"; signal?: AbortSignal}) {\n const decoder = new TextDecoder(\"utf-8\", {ignoreBOM: true});\n const chunks: string[] = [];\n let position = 0;\n for (;;) {\n signal?.throwIfAborted();\n const chunk = await handle.read(position, 64 * 1024, signal ? {signal} : {});\n if (chunk.byteLength === 0) break;\n chunks.push(decoder.decode(chunk, {stream: true}));\n position += chunk.byteLength;\n }\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hasOwnErrorCode
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2GVBG23M.js";
|
|
4
4
|
|
|
5
5
|
// packages/safe-js/src/output-stream.ts
|
|
6
6
|
function createBrokenPipeState() {
|
|
@@ -57,4 +57,4 @@ export {
|
|
|
57
57
|
withBrokenPipeGuard,
|
|
58
58
|
addBrokenPipeListener
|
|
59
59
|
};
|
|
60
|
-
//# sourceMappingURL=chunk-
|
|
60
|
+
//# sourceMappingURL=chunk-G6WTEIJJ.js.map
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import {
|
|
5
|
-
attachDumpController,
|
|
6
|
-
createDumpController
|
|
7
|
-
} from "./chunk-MVLDRXWS.js";
|
|
2
|
+
fsCodec
|
|
3
|
+
} from "./chunk-GVKXZW53.js";
|
|
8
4
|
import {
|
|
9
5
|
getOwnErrorCode,
|
|
10
6
|
hasOwnErrorCode
|
|
11
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2GVBG23M.js";
|
|
8
|
+
import {
|
|
9
|
+
restore
|
|
10
|
+
} from "./chunk-O4IDRXW7.js";
|
|
12
11
|
import {
|
|
13
12
|
hashParsedAst,
|
|
14
13
|
hashSource
|
|
15
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PSVV3IG2.js";
|
|
15
|
+
import {
|
|
16
|
+
attachDumpController,
|
|
17
|
+
createDumpController
|
|
18
|
+
} from "./chunk-X3CKAZQ4.js";
|
|
16
19
|
import {
|
|
17
20
|
DUMP_FORMAT_VERSION,
|
|
18
21
|
EXECUTION_SEMANTICS,
|
|
@@ -35,7 +38,6 @@ import {
|
|
|
35
38
|
createBuiltinBindings,
|
|
36
39
|
createEvalSource,
|
|
37
40
|
createGuestReference,
|
|
38
|
-
createHostCallbackContext,
|
|
39
41
|
createImmutableEmptyModuleEnvironment,
|
|
40
42
|
createLiveHostObject,
|
|
41
43
|
createModuleEnvironment,
|
|
@@ -100,7 +102,7 @@ import {
|
|
|
100
102
|
withSandboxPromiseRejectionTracker,
|
|
101
103
|
wrapCallerInjectedBindings,
|
|
102
104
|
wrapCancelableBindings
|
|
103
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-MDIWQFYU.js";
|
|
104
106
|
import {
|
|
105
107
|
Budget,
|
|
106
108
|
CompileScope,
|
|
@@ -115,14 +117,18 @@ import {
|
|
|
115
117
|
parseSourceModule,
|
|
116
118
|
replaceErrorStack,
|
|
117
119
|
safeAddEvent
|
|
118
|
-
} from "./chunk-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
import {
|
|
120
|
+
} from "./chunk-QKO4FATZ.js";
|
|
121
|
+
import {
|
|
122
|
+
dirname
|
|
123
|
+
} from "./chunk-YUQFFRUF.js";
|
|
124
|
+
import {
|
|
125
|
+
AsyncLocalStorage,
|
|
126
|
+
createHostCallbackContext,
|
|
127
|
+
hostFs,
|
|
128
|
+
types
|
|
129
|
+
} from "./chunk-UQPYTZOZ.js";
|
|
123
130
|
|
|
124
131
|
// packages/safe-js/src/modules/source-graph.ts
|
|
125
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
126
132
|
var ambiguous = /* @__PURE__ */ Symbol("ambiguous module export");
|
|
127
133
|
var sourceRecords = /* @__PURE__ */ new WeakSet();
|
|
128
134
|
var SourceModuleGraph = class {
|
|
@@ -612,17 +618,17 @@ var RealmState = class {
|
|
|
612
618
|
this.queue = queue;
|
|
613
619
|
const limitInput = readDataRecord(options.limits ?? {}, "Realm limits");
|
|
614
620
|
this.limits = {
|
|
615
|
-
extensions:
|
|
616
|
-
hostObjects:
|
|
617
|
-
callbacks:
|
|
618
|
-
guestReferences:
|
|
619
|
-
cleanups:
|
|
620
|
-
nestedEvaluations:
|
|
621
|
+
extensions: Infinity,
|
|
622
|
+
hostObjects: Infinity,
|
|
623
|
+
callbacks: Infinity,
|
|
624
|
+
guestReferences: Infinity,
|
|
625
|
+
cleanups: Infinity,
|
|
626
|
+
nestedEvaluations: Infinity
|
|
621
627
|
};
|
|
622
628
|
for (const [name, value] of Object.entries(limitInput)) {
|
|
623
|
-
if (!Object.hasOwn(this.limits, name) || !Number.isSafeInteger(value) || Number(value) < 1)
|
|
624
|
-
throw new TypeError("Realm limits must be positive safe integers with supported names.");
|
|
625
|
-
this.limits[name] = Number(value);
|
|
629
|
+
if (!Object.hasOwn(this.limits, name) || value !== void 0 && value !== Infinity && (!Number.isSafeInteger(value) || Number(value) < 1))
|
|
630
|
+
throw new TypeError("Realm limits must be positive safe integers or Infinity with supported names.");
|
|
631
|
+
if (value !== void 0) this.limits[name] = Number(value);
|
|
626
632
|
}
|
|
627
633
|
if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types.isProxy(options.extensions)))
|
|
628
634
|
throw new TypeError("Extensions must be a registration array.");
|
|
@@ -655,7 +661,7 @@ var RealmState = class {
|
|
|
655
661
|
throw new TypeError("Console override requires a registered extension declaring console.");
|
|
656
662
|
this.consoleExtension = extensionName;
|
|
657
663
|
}
|
|
658
|
-
this.budget = options.budget ?? new Budget(
|
|
664
|
+
this.budget = options.budget ?? new Budget();
|
|
659
665
|
this.lease = this.budget.acquireRealmOwner();
|
|
660
666
|
this.compilation = new CompileScope(this.lease.owner);
|
|
661
667
|
this.bridge = {
|
|
@@ -731,7 +737,7 @@ var RealmState = class {
|
|
|
731
737
|
lease;
|
|
732
738
|
compilation;
|
|
733
739
|
controller = new AbortController();
|
|
734
|
-
phase = new
|
|
740
|
+
phase = new AsyncLocalStorage();
|
|
735
741
|
queue;
|
|
736
742
|
tracker = createSandboxPromiseRejectionTracker();
|
|
737
743
|
bridge;
|
|
@@ -1733,9 +1739,7 @@ function readRealmOptions(value, oneShot = false) {
|
|
|
1733
1739
|
}
|
|
1734
1740
|
|
|
1735
1741
|
// packages/safe-js/src/snapshot/backend.ts
|
|
1736
|
-
import {
|
|
1737
|
-
import { readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
1738
|
-
import { dirname } from "node:path";
|
|
1742
|
+
import { createFsBridge } from "@poe-platform/safe-fs/core";
|
|
1739
1743
|
var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
|
|
1740
1744
|
var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
|
|
1741
1745
|
var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
@@ -1743,15 +1747,17 @@ var pendingOperations = /* @__PURE__ */ new Map();
|
|
|
1743
1747
|
var FileSnapshotBackend = class {
|
|
1744
1748
|
constructor(path, options = {}) {
|
|
1745
1749
|
this.path = path;
|
|
1750
|
+
this.#io = options.adapter === void 0 ? hostFs : createFsBridge(options.adapter, { codec: fsCodec });
|
|
1746
1751
|
this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
|
|
1747
1752
|
this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
|
|
1748
1753
|
}
|
|
1749
1754
|
path;
|
|
1755
|
+
#io;
|
|
1750
1756
|
#writeMaxAttempts;
|
|
1751
1757
|
#writeRetryDelayMs;
|
|
1752
1758
|
async read() {
|
|
1753
1759
|
try {
|
|
1754
|
-
return JSON.parse(await readFile(this.path, "utf8"));
|
|
1760
|
+
return JSON.parse(await this.#io.readFile(this.path, "utf8"));
|
|
1755
1761
|
} catch (error) {
|
|
1756
1762
|
if (hasErrorCode(error, "ENOENT")) {
|
|
1757
1763
|
return void 0;
|
|
@@ -1765,7 +1771,7 @@ var FileSnapshotBackend = class {
|
|
|
1765
1771
|
async write(snapshot) {
|
|
1766
1772
|
await enqueueOperation(
|
|
1767
1773
|
this.path,
|
|
1768
|
-
() => writeSnapshotAtomically(this.path, snapshot, {
|
|
1774
|
+
() => writeSnapshotAtomically(this.#io, this.path, snapshot, {
|
|
1769
1775
|
maxAttempts: this.#writeMaxAttempts,
|
|
1770
1776
|
retryDelayMs: this.#writeRetryDelayMs
|
|
1771
1777
|
})
|
|
@@ -1774,7 +1780,7 @@ var FileSnapshotBackend = class {
|
|
|
1774
1780
|
async remove() {
|
|
1775
1781
|
await enqueueOperation(this.path, async () => {
|
|
1776
1782
|
try {
|
|
1777
|
-
await unlink(this.path);
|
|
1783
|
+
await this.#io.unlink(this.path);
|
|
1778
1784
|
} catch (error) {
|
|
1779
1785
|
if (!hasErrorCode(error, "ENOENT")) {
|
|
1780
1786
|
throw error;
|
|
@@ -1783,14 +1789,14 @@ var FileSnapshotBackend = class {
|
|
|
1783
1789
|
});
|
|
1784
1790
|
}
|
|
1785
1791
|
};
|
|
1786
|
-
async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
|
|
1792
|
+
async function writeSnapshotAtomically(io, snapshotPath, snapshot, options) {
|
|
1787
1793
|
const parentPath = dirname(snapshotPath);
|
|
1788
1794
|
const contents = serializeSafeJSSnapshot(snapshot);
|
|
1789
|
-
await assertParentDirectoryExists(snapshotPath, parentPath);
|
|
1795
|
+
await assertParentDirectoryExists(io, snapshotPath, parentPath);
|
|
1790
1796
|
for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
|
|
1791
1797
|
try {
|
|
1792
|
-
const temporaryPath = `${snapshotPath}.${randomUUID()}.tmp`;
|
|
1793
|
-
await writeSnapshotOnce(temporaryPath, snapshotPath, contents);
|
|
1798
|
+
const temporaryPath = `${snapshotPath}.${globalThis.crypto.randomUUID()}.tmp`;
|
|
1799
|
+
await writeSnapshotOnce(io, temporaryPath, snapshotPath, contents);
|
|
1794
1800
|
return;
|
|
1795
1801
|
} catch (error) {
|
|
1796
1802
|
if (hasErrorCode(error, "EEXIST")) {
|
|
@@ -1819,9 +1825,9 @@ async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
|
|
|
1819
1825
|
}
|
|
1820
1826
|
}
|
|
1821
1827
|
}
|
|
1822
|
-
async function assertParentDirectoryExists(snapshotPath, parentPath) {
|
|
1828
|
+
async function assertParentDirectoryExists(io, snapshotPath, parentPath) {
|
|
1823
1829
|
try {
|
|
1824
|
-
const parent = await stat(parentPath);
|
|
1830
|
+
const parent = await io.stat(parentPath);
|
|
1825
1831
|
if (!parent.isDirectory()) {
|
|
1826
1832
|
throw new Error(
|
|
1827
1833
|
`Cannot write snapshot at ${snapshotPath}: parent path ${parentPath} is not a directory`
|
|
@@ -1839,24 +1845,24 @@ async function assertParentDirectoryExists(snapshotPath, parentPath) {
|
|
|
1839
1845
|
throw error;
|
|
1840
1846
|
}
|
|
1841
1847
|
}
|
|
1842
|
-
async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
|
|
1848
|
+
async function writeSnapshotOnce(io, temporaryPath, snapshotPath, contents) {
|
|
1843
1849
|
let temporaryCreated = false;
|
|
1844
1850
|
let renamed = false;
|
|
1845
1851
|
try {
|
|
1846
1852
|
try {
|
|
1847
|
-
await writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
|
|
1853
|
+
await io.writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
|
|
1848
1854
|
temporaryCreated = true;
|
|
1849
1855
|
} catch (error) {
|
|
1850
1856
|
if (!hasErrorCode(error, "EEXIST")) {
|
|
1851
|
-
await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
|
|
1857
|
+
await removeTemporarySnapshot(io, temporaryPath).catch(() => void 0);
|
|
1852
1858
|
}
|
|
1853
1859
|
throw error;
|
|
1854
1860
|
}
|
|
1855
|
-
await rename(temporaryPath, snapshotPath);
|
|
1861
|
+
await io.rename(temporaryPath, snapshotPath);
|
|
1856
1862
|
renamed = true;
|
|
1857
1863
|
} finally {
|
|
1858
1864
|
if (temporaryCreated && !renamed) {
|
|
1859
|
-
await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
|
|
1865
|
+
await removeTemporarySnapshot(io, temporaryPath).catch(() => void 0);
|
|
1860
1866
|
}
|
|
1861
1867
|
}
|
|
1862
1868
|
}
|
|
@@ -1873,9 +1879,9 @@ async function enqueueOperation(path, operation) {
|
|
|
1873
1879
|
}
|
|
1874
1880
|
}
|
|
1875
1881
|
}
|
|
1876
|
-
async function removeTemporarySnapshot(temporaryPath) {
|
|
1882
|
+
async function removeTemporarySnapshot(io, temporaryPath) {
|
|
1877
1883
|
try {
|
|
1878
|
-
await unlink(temporaryPath);
|
|
1884
|
+
await io.unlink(temporaryPath);
|
|
1879
1885
|
} catch (error) {
|
|
1880
1886
|
if (!hasErrorCode(error, "ENOENT")) {
|
|
1881
1887
|
throw error;
|
|
@@ -2212,7 +2218,6 @@ var UnhandledRejectionError = class extends Error {
|
|
|
2212
2218
|
replaceErrorStack(this);
|
|
2213
2219
|
}
|
|
2214
2220
|
};
|
|
2215
|
-
var DEFAULT_MAX_CALL_DEPTH = 1e3;
|
|
2216
2221
|
function run(source, options = {}) {
|
|
2217
2222
|
const jobs = new SandboxJobQueue();
|
|
2218
2223
|
if (options.extensions !== void 0 || options.builtinOverrides !== void 0 || options.sourceType !== void 0 || options.sourceResolver !== void 0 || options.sourceRoot !== void 0) {
|
|
@@ -2221,7 +2226,7 @@ function run(source, options = {}) {
|
|
|
2221
2226
|
throw new TypeError("Source resolution requires sourceType: 'module'.");
|
|
2222
2227
|
if (options.sourceRoot !== void 0) {
|
|
2223
2228
|
if (options.sourceResolver !== void 0) throw new TypeError("Specify sourceRoot or sourceResolver, not both.");
|
|
2224
|
-
const { createRootedSourceResolver } = await import("./source-files-
|
|
2229
|
+
const { createRootedSourceResolver } = await import("./source-files-L3SGK63Z.js");
|
|
2225
2230
|
const { sourceRoot, ...resolved } = options;
|
|
2226
2231
|
const sourceResolver = await createRootedSourceResolver(sourceRoot);
|
|
2227
2232
|
return runWithExtensions(source, { ...resolved, filename: await sourceResolver.entryId(options.filename), sourceResolver }, jobs);
|
|
@@ -2245,7 +2250,7 @@ function run(source, options = {}) {
|
|
|
2245
2250
|
const detachExecutionFailure = promiseTracker.onFatalRejection((error) => jobs.interrupt(error));
|
|
2246
2251
|
let completedSnapshot;
|
|
2247
2252
|
const execute = async () => {
|
|
2248
|
-
const budget = options.budget ?? new Budget(
|
|
2253
|
+
const budget = options.budget ?? new Budget();
|
|
2249
2254
|
const operation = budget.acquireCompileOwner(true);
|
|
2250
2255
|
const compilation = new CompileScope(operation.owner);
|
|
2251
2256
|
try {
|
|
@@ -2824,4 +2829,4 @@ export {
|
|
|
2824
2829
|
UnhandledRejectionError,
|
|
2825
2830
|
run
|
|
2826
2831
|
};
|
|
2827
|
-
//# sourceMappingURL=chunk-
|
|
2832
|
+
//# sourceMappingURL=chunk-GNEORAQI.js.map
|