poe-code 5.0.4 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3181 -2636
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safejs/dist/interp/async.js +31 -9
- package/packages/safejs/dist/interp/cancel.d.ts +7 -2
- package/packages/safejs/dist/interp/cancel.js +128 -92
- package/packages/safejs/dist/interp/exceptions.js +7 -3
- package/packages/safejs/dist/interp/globals/collections.js +2 -0
- package/packages/safejs/dist/interp/globals/console-json.js +4 -0
- package/packages/safejs/dist/interp/globals/error.js +1 -5
- package/packages/safejs/dist/interp/globals/math.js +2 -4
- package/packages/safejs/dist/interp/globals/misc.js +5 -0
- package/packages/safejs/dist/interp/globals/object-array.js +25 -0
- package/packages/safejs/dist/interp/globals/regex.js +1 -1
- package/packages/safejs/dist/interp/host-bridge.js +8 -5
- package/packages/safejs/dist/interp/interpreter.js +26 -32
- package/packages/safejs/dist/interp/iteration.d.ts +3 -3
- package/packages/safejs/dist/interp/iteration.js +20 -9
- package/packages/safejs/dist/interp/methods/array.js +1 -0
- package/packages/safejs/dist/interp/methods/function.d.ts +1 -1
- package/packages/safejs/dist/interp/methods/function.js +17 -1
- package/packages/safejs/dist/interp/methods/generator.js +1 -0
- package/packages/safejs/dist/interp/methods/map.js +1 -0
- package/packages/safejs/dist/interp/methods/number.js +1 -0
- package/packages/safejs/dist/interp/methods/regex.js +1 -0
- package/packages/safejs/dist/interp/methods/set.js +1 -0
- package/packages/safejs/dist/interp/methods/string.js +1 -0
- package/packages/safejs/dist/interp/promise-tracker.d.ts +12 -2
- package/packages/safejs/dist/interp/promise-tracker.js +65 -7
- package/packages/safejs/dist/interp/promise.d.ts +7 -5
- package/packages/safejs/dist/interp/promise.js +531 -148
- package/packages/safejs/dist/interp/values.d.ts +6 -0
- package/packages/safejs/dist/interp/values.js +25 -5
- package/packages/safejs/dist/lint/rules/AS001.js +0 -5
- package/packages/safejs/dist/snapshot/dump-format.d.ts +1 -1
- package/packages/safejs/dist/snapshot/dump-format.js +1 -1
- package/packages/safejs/dist/snapshot/replay-data.js +3 -0
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@ import { getThenable, resolveSandboxValue } from "./promise.js";
|
|
|
5
5
|
import { runAsyncPrefix, suspendJob } from "./jobs.js";
|
|
6
6
|
import { awaitSandboxValue } from "./cancel.js";
|
|
7
7
|
import { hoistVarDeclarations } from "./var-hoist.js";
|
|
8
|
-
import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxPromise, isSandboxPromise } from "./values.js";
|
|
8
|
+
import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxPromise, allocateProducedSandboxValue, isSandboxPromise } from "./values.js";
|
|
9
9
|
export function emitResumeBreakpoint(context, breakpoint) {
|
|
10
10
|
context.onYield?.({
|
|
11
11
|
...breakpoint,
|
|
@@ -53,6 +53,7 @@ export function createInterpretedClosure(node, context, evaluateNode) {
|
|
|
53
53
|
}
|
|
54
54
|
: undefined;
|
|
55
55
|
return createSandboxClosure({
|
|
56
|
+
sandbox: true,
|
|
56
57
|
...(node.async ? { async: true } : {}),
|
|
57
58
|
...(node.type === "FunctionDeclaration" || node.type === "FunctionExpression"
|
|
58
59
|
? node.id === undefined
|
|
@@ -72,16 +73,34 @@ export function createInterpretedClosure(node, context, evaluateNode) {
|
|
|
72
73
|
const synchronousPrefix = new Promise((resolve) => {
|
|
73
74
|
completePrefix = resolve;
|
|
74
75
|
});
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
const promise = new Promise((resolve, reject) => {
|
|
77
|
+
runAsyncPrefix(async () => {
|
|
78
|
+
try {
|
|
79
|
+
const value = await executeClosure(node, args, callContext?.thisValue, { ...invocationContext, onSuspend: completePrefix }, evaluateNode);
|
|
80
|
+
resolve(isSandboxPromise(value) || getThenable(value) !== undefined
|
|
81
|
+
? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget: context.budget }), {
|
|
82
|
+
trackReplay: false
|
|
83
|
+
}), context.signal, context.budget)
|
|
84
|
+
: allocateProducedSandboxValue(value, context.budget));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
reject(error);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
completePrefix();
|
|
91
|
+
}
|
|
92
|
+
}).catch((error) => {
|
|
93
|
+
reject(error);
|
|
94
|
+
completePrefix();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return createSandboxPromise(promise, { synchronousPrefix });
|
|
80
98
|
}
|
|
81
99
|
});
|
|
82
100
|
}
|
|
83
101
|
function createGeneratorClosure(node, context, evaluateNode) {
|
|
84
102
|
return createSandboxClosure({
|
|
103
|
+
sandbox: true,
|
|
85
104
|
...(node.id === undefined ? {} : { name: node.id.name }),
|
|
86
105
|
retainedValues: () => context.scope.retainedValues(),
|
|
87
106
|
call: async (args, callContext) => {
|
|
@@ -136,7 +155,7 @@ export async function evaluateAwaitExpression(node, context, evaluateNode) {
|
|
|
136
155
|
return {
|
|
137
156
|
kind: "normal",
|
|
138
157
|
hasValue: true,
|
|
139
|
-
value: await suspendJob(awaitSandboxValue(argument.value, context.signal))
|
|
158
|
+
value: await suspendJob(awaitSandboxValue(argument.value, context.signal, context.budget))
|
|
140
159
|
};
|
|
141
160
|
}
|
|
142
161
|
finally {
|
|
@@ -230,8 +249,11 @@ function getParameterBindingNames(pattern) {
|
|
|
230
249
|
}
|
|
231
250
|
}
|
|
232
251
|
export function normalizeClosureResult(result, budget) {
|
|
233
|
-
if (isSandboxPromise(result)
|
|
252
|
+
if (isSandboxPromise(result) &&
|
|
253
|
+
(result.synchronousPrefix !== undefined || result.hostCall !== undefined)) {
|
|
234
254
|
return result;
|
|
235
255
|
}
|
|
236
|
-
return createSandboxPromise(resolveSandboxValue(result, { budget })
|
|
256
|
+
return createSandboxPromise(resolveSandboxValue(result, { budget }), {
|
|
257
|
+
...(isSandboxPromise(result) ? { synchronousPrefix: Promise.resolve() } : {})
|
|
258
|
+
});
|
|
237
259
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import { type SandboxValue } from "./values.js";
|
|
1
|
+
import { type SandboxCallContext, type SandboxClosure, type SandboxPromise, type SandboxValue } from "./values.js";
|
|
2
|
+
import type { Budget } from "./budget.js";
|
|
3
|
+
export declare function withCancellationSignal<T>(signal: AbortSignal | undefined, task: () => T): T;
|
|
4
|
+
export declare function invokeCancelableClosure(closure: SandboxClosure, operation: SandboxClosure["call"], args: readonly SandboxValue[], context?: SandboxCallContext, construct?: boolean): SandboxValue | Promise<SandboxValue>;
|
|
2
5
|
export declare function wrapCancelableBindings(bindings: Record<string, SandboxValue>, signal?: AbortSignal): Record<string, SandboxValue>;
|
|
3
|
-
export declare function
|
|
6
|
+
export declare function registerPromiseCancellation(promise: SandboxPromise): void;
|
|
7
|
+
export declare function readPromiseCancellation(promise: SandboxPromise, original: Promise<SandboxValue>): Promise<SandboxValue>;
|
|
8
|
+
export declare function awaitSandboxValue(value: SandboxValue, signal?: AbortSignal, budget?: Budget): Promise<SandboxValue>;
|
|
@@ -1,90 +1,139 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { createSandboxPromise, isSandboxClosure, isSandboxMap, isSandboxPromise, isSandboxSet } from "./values.js";
|
|
3
|
+
import { assertPromiseExecutionAllowed, interruptOnFatalPromiseRejection, onFatalPromiseRejection, observeSandboxPromise, trackSandboxPromise } from "./promise-tracker.js";
|
|
3
4
|
import { replaceErrorStack } from "../error/shape.js";
|
|
4
|
-
import { resolveSandboxValue } from "./promise.js";
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
return wrapCancelableValue(bindings, signal, new WeakMap());
|
|
5
|
+
import { consumeSettledHostCall, resolveSandboxValue } from "./promise.js";
|
|
6
|
+
const activeCancellation = new AsyncLocalStorage();
|
|
7
|
+
const sandboxPromises = new WeakSet();
|
|
8
|
+
const cancelableOutcomes = new WeakMap();
|
|
9
|
+
export function withCancellationSignal(signal, task) {
|
|
10
|
+
return activeCancellation.run({ signal, host: false }, task);
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
export function invokeCancelableClosure(closure, operation, args, context, construct = false) {
|
|
13
|
+
assertPromiseExecutionAllowed();
|
|
14
|
+
const active = activeCancellation.getStore();
|
|
15
|
+
if (active === undefined)
|
|
16
|
+
return operation(args, context);
|
|
17
|
+
if (closure.sandbox === true) {
|
|
18
|
+
return activeCancellation.run({ signal: active.signal, host: false }, () => operation(args, context));
|
|
15
19
|
}
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
const signal = active.signal;
|
|
21
|
+
const managed = signal !== undefined && closure.cancellationSignal === signal;
|
|
22
|
+
if (signal?.aborted && !managed) {
|
|
23
|
+
if (!construct && closure.async === true)
|
|
24
|
+
return createRejectedSandboxPromise(readAbortReason(signal));
|
|
25
|
+
throw readAbortReason(signal);
|
|
19
26
|
}
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
return activeCancellation.run({ signal, host: true }, () => {
|
|
28
|
+
const result = operation(args, context);
|
|
29
|
+
if (signal === undefined || managed)
|
|
30
|
+
return result;
|
|
31
|
+
if (isPromiseLike(result))
|
|
32
|
+
return awaitWithSignal(result, signal).then((value) => {
|
|
33
|
+
registerCancelablePromises(value, signal);
|
|
34
|
+
return value;
|
|
35
|
+
});
|
|
36
|
+
registerCancelablePromises(result, signal);
|
|
37
|
+
return result;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export function wrapCancelableBindings(bindings, signal) {
|
|
41
|
+
if (signal !== undefined)
|
|
42
|
+
registerCancelablePromises(bindings, signal);
|
|
43
|
+
return bindings;
|
|
44
|
+
}
|
|
45
|
+
export function registerPromiseCancellation(promise) {
|
|
46
|
+
const active = activeCancellation.getStore();
|
|
47
|
+
if (active?.host === false)
|
|
48
|
+
sandboxPromises.add(promise);
|
|
49
|
+
else if (active?.signal !== undefined)
|
|
50
|
+
managePromiseCancellation(promise, active.signal);
|
|
51
|
+
}
|
|
52
|
+
export function readPromiseCancellation(promise, original) {
|
|
53
|
+
const signal = activeCancellation.getStore()?.signal;
|
|
54
|
+
return signal === undefined
|
|
55
|
+
? original
|
|
56
|
+
: (cancelableOutcomes.get(promise)?.get(signal) ?? original);
|
|
57
|
+
}
|
|
58
|
+
function managePromiseCancellation(promise, signal) {
|
|
59
|
+
let outcomes = cancelableOutcomes.get(promise);
|
|
60
|
+
if (outcomes?.has(signal))
|
|
61
|
+
return;
|
|
62
|
+
if (outcomes === undefined) {
|
|
63
|
+
outcomes = new WeakMap();
|
|
64
|
+
cancelableOutcomes.set(promise, outcomes);
|
|
65
|
+
}
|
|
66
|
+
const outcome = awaitWithSignal(promise.promise, signal);
|
|
67
|
+
outcomes.set(signal, outcome);
|
|
68
|
+
trackSandboxPromise(promise, outcome);
|
|
69
|
+
}
|
|
70
|
+
function registerCancelablePromises(value, signal) {
|
|
71
|
+
const seen = new WeakSet();
|
|
72
|
+
const pending = [value];
|
|
73
|
+
while (pending.length > 0) {
|
|
74
|
+
const current = pending.pop();
|
|
75
|
+
if (typeof current !== "object" || current === null || seen.has(current))
|
|
76
|
+
continue;
|
|
77
|
+
seen.add(current);
|
|
78
|
+
if (isSandboxPromise(current)) {
|
|
79
|
+
if (!sandboxPromises.has(current))
|
|
80
|
+
managePromiseCancellation(current, signal);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (isSandboxClosure(current)) {
|
|
84
|
+
if (current.properties !== undefined)
|
|
85
|
+
pending.push(current.properties);
|
|
86
|
+
}
|
|
87
|
+
else if (isSandboxMap(current)) {
|
|
88
|
+
for (const [key, entry] of current.entries)
|
|
89
|
+
pending.push(key, entry);
|
|
90
|
+
}
|
|
91
|
+
else if (isSandboxSet(current)) {
|
|
92
|
+
for (const entry of current.values)
|
|
93
|
+
pending.push(entry);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
for (const descriptor of Object.values(Object.getOwnPropertyDescriptors(current))) {
|
|
97
|
+
if ("value" in descriptor)
|
|
98
|
+
pending.push(descriptor.value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
36
101
|
}
|
|
102
|
+
}
|
|
103
|
+
export function awaitSandboxValue(value, signal, budget) {
|
|
104
|
+
let resolved;
|
|
37
105
|
if (isSandboxPromise(value)) {
|
|
38
|
-
// The wrapper delivers this promise's rejection to the sandbox in its place, so
|
|
39
|
-
// the sandbox never awaits the original and it would otherwise read as unhandled.
|
|
40
106
|
observeSandboxPromise(value);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
107
|
+
const outcome = signal === undefined
|
|
108
|
+
? value.promise
|
|
109
|
+
: (cancelableOutcomes.get(value)?.get(signal) ?? value.promise);
|
|
110
|
+
resolved = new Promise((resolve, reject) => {
|
|
111
|
+
const detach = onFatalPromiseRejection(reject);
|
|
112
|
+
const complete = (state, result) => {
|
|
113
|
+
detach?.();
|
|
114
|
+
try {
|
|
115
|
+
consumeSettledHostCall(value);
|
|
116
|
+
if (state === "fulfilled")
|
|
117
|
+
resolve(result);
|
|
118
|
+
else
|
|
119
|
+
reject(result);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
reject(error);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
outcome.then((result) => complete("fulfilled", result), (reason) => complete("rejected", reason));
|
|
49
126
|
});
|
|
50
|
-
seen.set(value, wrapped);
|
|
51
|
-
cancellationSignals.set(wrapped, signal);
|
|
52
|
-
return wrapped;
|
|
53
|
-
}
|
|
54
|
-
if (Array.isArray(value)) {
|
|
55
|
-
const wrapped = new Array(value.length);
|
|
56
|
-
seen.set(value, wrapped);
|
|
57
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
58
|
-
wrapped[index] = wrapCancelableValue(value[index], signal, seen);
|
|
59
|
-
}
|
|
60
|
-
return wrapped;
|
|
61
127
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
65
|
-
wrapped[key] = wrapCancelableValue(entry, signal, seen);
|
|
128
|
+
else {
|
|
129
|
+
resolved = resolveSandboxValue(value, { budget });
|
|
66
130
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!isPromiseLike(result)) {
|
|
71
|
-
return wrapCancelableValue(result, signal, seen);
|
|
72
|
-
}
|
|
73
|
-
return wrapCancelablePromise(result, signal, seen);
|
|
74
|
-
}
|
|
75
|
-
function wrapCancelablePromise(promise, signal, seen) {
|
|
76
|
-
return awaitWithSignal(promise, signal).then((value) => wrapCancelableValue(value, signal, seen), (reason) => {
|
|
77
|
-
if (signal.aborted && reason === signal.reason)
|
|
78
|
-
throw reason;
|
|
79
|
-
throw wrapCancelableUnknown(reason, signal, seen);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
export function awaitSandboxValue(value, signal) {
|
|
83
|
-
const resolved = resolveSandboxValue(value);
|
|
84
|
-
return isSandboxPromise(value) &&
|
|
85
|
-
(value.synchronousPrefix !== undefined || cancellationSignals.get(value) === signal)
|
|
131
|
+
const pending = isSandboxPromise(value) &&
|
|
132
|
+
(value.synchronousPrefix !== undefined ||
|
|
133
|
+
(signal !== undefined && cancelableOutcomes.get(value)?.has(signal)))
|
|
86
134
|
? resolved
|
|
87
135
|
: awaitWithSignal(resolved, signal);
|
|
136
|
+
return isSandboxPromise(value) ? pending : interruptOnFatalPromiseRejection(pending);
|
|
88
137
|
}
|
|
89
138
|
function awaitWithSignal(promise, signal) {
|
|
90
139
|
if (signal === undefined)
|
|
@@ -125,22 +174,6 @@ function awaitWithSignal(promise, signal) {
|
|
|
125
174
|
});
|
|
126
175
|
});
|
|
127
176
|
}
|
|
128
|
-
function wrapCancelableUnknown(value, signal, seen) {
|
|
129
|
-
if (value === null ||
|
|
130
|
-
value === undefined ||
|
|
131
|
-
typeof value === "string" ||
|
|
132
|
-
typeof value === "number" ||
|
|
133
|
-
typeof value === "boolean") {
|
|
134
|
-
return value;
|
|
135
|
-
}
|
|
136
|
-
if (isSandboxClosure(value) ||
|
|
137
|
-
isSandboxPromise(value) ||
|
|
138
|
-
Array.isArray(value) ||
|
|
139
|
-
(typeof value === "object" && value !== null)) {
|
|
140
|
-
return wrapCancelableValue(value, signal, seen);
|
|
141
|
-
}
|
|
142
|
-
return value;
|
|
143
|
-
}
|
|
144
177
|
function readAbortReason(signal) {
|
|
145
178
|
return signal.reason ?? createAbortError();
|
|
146
179
|
}
|
|
@@ -161,5 +194,8 @@ function createRejectedSandboxPromise(reason) {
|
|
|
161
194
|
return createSandboxPromise(promise);
|
|
162
195
|
}
|
|
163
196
|
function isPromiseLike(value) {
|
|
164
|
-
return typeof value === "object" &&
|
|
197
|
+
return (typeof value === "object" &&
|
|
198
|
+
value !== null &&
|
|
199
|
+
"then" in value &&
|
|
200
|
+
typeof value.then === "function");
|
|
165
201
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { attachErrorSpan, attachWrappedErrorCause, describeThrownValue, formatErrorStack, readErrorCause, readErrorSpan } from "../error/shape.js";
|
|
2
2
|
import { SandboxError } from "./budget.js";
|
|
3
3
|
import { HostCallResumabilityError } from "./host-call.js";
|
|
4
|
+
import { withFatalPromiseCleanup } from "./promise-tracker.js";
|
|
4
5
|
import { deepCopyToSandbox } from "./values.js";
|
|
5
6
|
const capturedExceptionBrand = Symbol("CapturedException");
|
|
6
7
|
const sandboxErrorBrand = Symbol("SandboxError");
|
|
@@ -50,9 +51,12 @@ export async function evaluateTryStatement(node, context, evaluateNode) {
|
|
|
50
51
|
if (node.finalizer === undefined || tryOrCatchResult.kind === "error") {
|
|
51
52
|
return tryOrCatchResult;
|
|
52
53
|
}
|
|
53
|
-
const
|
|
54
|
-
?
|
|
55
|
-
:
|
|
54
|
+
const evaluateFinalizer = () => fatalBudgetError?.budget === "deadline"
|
|
55
|
+
? evaluateWithoutDeadlineChecks(context, () => evaluateBlockCompletion(node.finalizer, context, evaluateNode))
|
|
56
|
+
: evaluateBlockCompletion(node.finalizer, context, evaluateNode);
|
|
57
|
+
const finalizerResult = await (fatalBudgetError === undefined
|
|
58
|
+
? evaluateFinalizer()
|
|
59
|
+
: withFatalPromiseCleanup(evaluateFinalizer));
|
|
56
60
|
if (fatalBudgetError !== undefined) {
|
|
57
61
|
throw fatalBudgetError;
|
|
58
62
|
}
|
|
@@ -4,6 +4,7 @@ const mapConstructors = new WeakSet();
|
|
|
4
4
|
const setConstructors = new WeakSet();
|
|
5
5
|
export function createCollectionGlobals(options) {
|
|
6
6
|
const mapConstructor = createSandboxClosure({
|
|
7
|
+
sandbox: true,
|
|
7
8
|
call: () => {
|
|
8
9
|
throw new TypeError("Constructor Map requires 'new'.");
|
|
9
10
|
},
|
|
@@ -17,6 +18,7 @@ export function createCollectionGlobals(options) {
|
|
|
17
18
|
name: "Map"
|
|
18
19
|
});
|
|
19
20
|
const setConstructor = createSandboxClosure({
|
|
21
|
+
sandbox: true,
|
|
20
22
|
call: () => {
|
|
21
23
|
throw new TypeError("Constructor Set requires 'new'.");
|
|
22
24
|
},
|
|
@@ -5,10 +5,12 @@ export function createConsoleJsonGlobals(options) {
|
|
|
5
5
|
return {
|
|
6
6
|
JSON: {
|
|
7
7
|
parse: createSandboxClosure({
|
|
8
|
+
sandbox: true,
|
|
8
9
|
call: async ([text]) => parseJson(text, options.budget),
|
|
9
10
|
name: "parse"
|
|
10
11
|
}),
|
|
11
12
|
stringify: createSandboxClosure({
|
|
13
|
+
sandbox: true,
|
|
12
14
|
call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
|
|
13
15
|
name: "stringify"
|
|
14
16
|
})
|
|
@@ -16,6 +18,7 @@ export function createConsoleJsonGlobals(options) {
|
|
|
16
18
|
console: options.hostCalls === undefined
|
|
17
19
|
? {
|
|
18
20
|
error: createSandboxClosure({
|
|
21
|
+
sandbox: true,
|
|
19
22
|
call: async (args) => {
|
|
20
23
|
sink.error(...args.map((value) => deepCopyFromSandbox(value)));
|
|
21
24
|
return undefined;
|
|
@@ -23,6 +26,7 @@ export function createConsoleJsonGlobals(options) {
|
|
|
23
26
|
name: "error"
|
|
24
27
|
}),
|
|
25
28
|
log: createSandboxClosure({
|
|
29
|
+
sandbox: true,
|
|
26
30
|
call: async (args) => {
|
|
27
31
|
sink.log(...args.map((value) => deepCopyFromSandbox(value)));
|
|
28
32
|
return undefined;
|
|
@@ -27,11 +27,7 @@ export function isSandboxErrorConstructor(value) {
|
|
|
27
27
|
}
|
|
28
28
|
function createErrorConstructor(name, budget) {
|
|
29
29
|
const call = (args, context) => createSubsetError(name, args, context?.stack ?? [], budget);
|
|
30
|
-
const closure = createSandboxClosure({
|
|
31
|
-
call,
|
|
32
|
-
construct: call,
|
|
33
|
-
name
|
|
34
|
-
});
|
|
30
|
+
const closure = createSandboxClosure({ sandbox: true, call, construct: call, name });
|
|
35
31
|
errorConstructorNames.set(closure, name);
|
|
36
32
|
return closure;
|
|
37
33
|
}
|
|
@@ -46,13 +46,11 @@ export function createMathGlobals(options = {}) {
|
|
|
46
46
|
PI: Math.PI,
|
|
47
47
|
SQRT1_2: Math.SQRT1_2,
|
|
48
48
|
SQRT2: Math.SQRT2,
|
|
49
|
-
random: createSandboxClosure({
|
|
50
|
-
call: () => random(),
|
|
51
|
-
name: "random"
|
|
52
|
-
})
|
|
49
|
+
random: createSandboxClosure({ sandbox: true, call: () => random(), name: "random" })
|
|
53
50
|
};
|
|
54
51
|
for (const [name, method] of Object.entries(mathMethods)) {
|
|
55
52
|
mathObject[name] = createSandboxClosure({
|
|
53
|
+
sandbox: true,
|
|
56
54
|
call: (args) => Reflect.apply(method, Math, args),
|
|
57
55
|
name
|
|
58
56
|
});
|
|
@@ -3,22 +3,27 @@ import { allocateProducedSandboxValue, cloneSandboxValue, createSandboxClosure,
|
|
|
3
3
|
export function createMiscGlobals(options) {
|
|
4
4
|
return {
|
|
5
5
|
structuredClone: createSandboxClosure({
|
|
6
|
+
sandbox: true,
|
|
6
7
|
call: ([value]) => structuredCloneSandboxValue(value, options.budget),
|
|
7
8
|
name: "structuredClone"
|
|
8
9
|
}),
|
|
9
10
|
parseInt: createSandboxClosure({
|
|
11
|
+
sandbox: true,
|
|
10
12
|
call: (args) => Reflect.apply(globalThis.parseInt, globalThis, [...args]),
|
|
11
13
|
name: "parseInt"
|
|
12
14
|
}),
|
|
13
15
|
parseFloat: createSandboxClosure({
|
|
16
|
+
sandbox: true,
|
|
14
17
|
call: (args) => Reflect.apply(globalThis.parseFloat, globalThis, [...args]),
|
|
15
18
|
name: "parseFloat"
|
|
16
19
|
}),
|
|
17
20
|
isNaN: createSandboxClosure({
|
|
21
|
+
sandbox: true,
|
|
18
22
|
call: ([value]) => globalThis.isNaN(value),
|
|
19
23
|
name: "isNaN"
|
|
20
24
|
}),
|
|
21
25
|
isFinite: createSandboxClosure({
|
|
26
|
+
sandbox: true,
|
|
22
27
|
call: ([value]) => globalThis.isFinite(value),
|
|
23
28
|
name: "isFinite"
|
|
24
29
|
})
|
|
@@ -4,30 +4,37 @@ export function createObjectArrayGlobals(options) {
|
|
|
4
4
|
return {
|
|
5
5
|
Object: {
|
|
6
6
|
keys: createSandboxClosure({
|
|
7
|
+
sandbox: true,
|
|
7
8
|
call: ([value]) => budgetSandboxValue(getOwnEnumerableKeys(value), options.budget),
|
|
8
9
|
name: "keys"
|
|
9
10
|
}),
|
|
10
11
|
values: createSandboxClosure({
|
|
12
|
+
sandbox: true,
|
|
11
13
|
call: ([value]) => budgetSandboxValue(getOwnEnumerableValues(value), options.budget),
|
|
12
14
|
name: "values"
|
|
13
15
|
}),
|
|
14
16
|
entries: createSandboxClosure({
|
|
17
|
+
sandbox: true,
|
|
15
18
|
call: ([value]) => budgetSandboxValue(getOwnEnumerableEntries(value), options.budget),
|
|
16
19
|
name: "entries"
|
|
17
20
|
}),
|
|
18
21
|
hasOwn: createSandboxClosure({
|
|
22
|
+
sandbox: true,
|
|
19
23
|
call: ([value, key]) => Reflect.apply(Object.hasOwn, Object, [value, key]),
|
|
20
24
|
name: "hasOwn"
|
|
21
25
|
}),
|
|
22
26
|
is: createSandboxClosure({
|
|
27
|
+
sandbox: true,
|
|
23
28
|
call: ([left, right]) => Reflect.apply(Object.is, Object, [left, right]),
|
|
24
29
|
name: "is"
|
|
25
30
|
}),
|
|
26
31
|
fromEntries: createSandboxClosure({
|
|
32
|
+
sandbox: true,
|
|
27
33
|
call: ([value]) => budgetSandboxValue(Reflect.apply(Object.fromEntries, Object, [value]), options.budget),
|
|
28
34
|
name: "fromEntries"
|
|
29
35
|
}),
|
|
30
36
|
freeze: createSandboxClosure({
|
|
37
|
+
sandbox: true,
|
|
31
38
|
call: ([value]) => {
|
|
32
39
|
if (typeof value === "object" && value !== null) {
|
|
33
40
|
Object.freeze(value);
|
|
@@ -37,76 +44,93 @@ export function createObjectArrayGlobals(options) {
|
|
|
37
44
|
name: "freeze"
|
|
38
45
|
}),
|
|
39
46
|
isFrozen: createSandboxClosure({
|
|
47
|
+
sandbox: true,
|
|
40
48
|
call: ([value]) => Object.isFrozen(value),
|
|
41
49
|
name: "isFrozen"
|
|
42
50
|
}),
|
|
43
51
|
assign: createSandboxClosure({
|
|
52
|
+
sandbox: true,
|
|
44
53
|
call: ([target, ...sources]) => assignSandboxValues(target, sources),
|
|
45
54
|
name: "assign"
|
|
46
55
|
})
|
|
47
56
|
},
|
|
48
57
|
Array: createSandboxClosure({
|
|
58
|
+
sandbox: true,
|
|
49
59
|
call: (args) => createArrayFromConstructorArgs(args, options.budget),
|
|
50
60
|
construct: (args) => createArrayFromConstructorArgs(args, options.budget),
|
|
51
61
|
name: "Array",
|
|
52
62
|
properties: {
|
|
53
63
|
isArray: createSandboxClosure({
|
|
64
|
+
sandbox: true,
|
|
54
65
|
call: ([value]) => Array.isArray(value),
|
|
55
66
|
name: "isArray"
|
|
56
67
|
}),
|
|
57
68
|
from: createSandboxClosure({
|
|
69
|
+
sandbox: true,
|
|
58
70
|
call: (args) => arrayFromSandboxValues(args, options.budget),
|
|
59
71
|
name: "from"
|
|
60
72
|
}),
|
|
61
73
|
of: createSandboxClosure({
|
|
74
|
+
sandbox: true,
|
|
62
75
|
call: (args) => budgetSandboxValue(Reflect.apply(Array.of, Array, [...args]), options.budget),
|
|
63
76
|
name: "of"
|
|
64
77
|
})
|
|
65
78
|
}
|
|
66
79
|
}),
|
|
67
80
|
String: createSandboxClosure({
|
|
81
|
+
sandbox: true,
|
|
68
82
|
call: ([value]) => options.budget.allocateString(String(value)),
|
|
69
83
|
name: "String",
|
|
70
84
|
properties: {
|
|
71
85
|
raw: createSandboxClosure({
|
|
86
|
+
sandbox: true,
|
|
72
87
|
call: (args) => stringRaw(args, options.budget),
|
|
73
88
|
name: "raw"
|
|
74
89
|
}),
|
|
75
90
|
fromCharCode: createSandboxClosure({
|
|
91
|
+
sandbox: true,
|
|
76
92
|
call: (args) => options.budget.allocateString(Reflect.apply(String.fromCharCode, String, [...args])),
|
|
77
93
|
name: "fromCharCode"
|
|
78
94
|
}),
|
|
79
95
|
fromCodePoint: createSandboxClosure({
|
|
96
|
+
sandbox: true,
|
|
80
97
|
call: (args) => options.budget.allocateString(Reflect.apply(String.fromCodePoint, String, [...args])),
|
|
81
98
|
name: "fromCodePoint"
|
|
82
99
|
})
|
|
83
100
|
}
|
|
84
101
|
}),
|
|
85
102
|
Number: createSandboxClosure({
|
|
103
|
+
sandbox: true,
|
|
86
104
|
call: ([value]) => Number(value),
|
|
87
105
|
name: "Number",
|
|
88
106
|
properties: {
|
|
89
107
|
isFinite: createSandboxClosure({
|
|
108
|
+
sandbox: true,
|
|
90
109
|
call: ([value]) => typeof value === "number" && Number.isFinite(value),
|
|
91
110
|
name: "isFinite"
|
|
92
111
|
}),
|
|
93
112
|
isNaN: createSandboxClosure({
|
|
113
|
+
sandbox: true,
|
|
94
114
|
call: ([value]) => typeof value === "number" && Number.isNaN(value),
|
|
95
115
|
name: "isNaN"
|
|
96
116
|
}),
|
|
97
117
|
isInteger: createSandboxClosure({
|
|
118
|
+
sandbox: true,
|
|
98
119
|
call: ([value]) => typeof value === "number" && Number.isInteger(value),
|
|
99
120
|
name: "isInteger"
|
|
100
121
|
}),
|
|
101
122
|
parseInt: createSandboxClosure({
|
|
123
|
+
sandbox: true,
|
|
102
124
|
call: (args) => Reflect.apply(Number.parseInt, Number, [...args]),
|
|
103
125
|
name: "parseInt"
|
|
104
126
|
}),
|
|
105
127
|
parseFloat: createSandboxClosure({
|
|
128
|
+
sandbox: true,
|
|
106
129
|
call: (args) => Reflect.apply(Number.parseFloat, Number, [...args]),
|
|
107
130
|
name: "parseFloat"
|
|
108
131
|
}),
|
|
109
132
|
isSafeInteger: createSandboxClosure({
|
|
133
|
+
sandbox: true,
|
|
110
134
|
call: ([value]) => typeof value === "number" && Number.isSafeInteger(value),
|
|
111
135
|
name: "isSafeInteger"
|
|
112
136
|
}),
|
|
@@ -118,6 +142,7 @@ export function createObjectArrayGlobals(options) {
|
|
|
118
142
|
}
|
|
119
143
|
}),
|
|
120
144
|
Boolean: createSandboxClosure({
|
|
145
|
+
sandbox: true,
|
|
121
146
|
call: ([value]) => Boolean(value),
|
|
122
147
|
name: "Boolean"
|
|
123
148
|
})
|
|
@@ -2,6 +2,6 @@ import { createSandboxClosure, createSandboxRegex } from "../values.js";
|
|
|
2
2
|
export function createRegexGlobals() {
|
|
3
3
|
const construct = (args) => createSandboxRegex(String(args[0] ?? ""), String(args[1] ?? ""));
|
|
4
4
|
return {
|
|
5
|
-
RegExp: createSandboxClosure({ name: "RegExp", call: construct, construct })
|
|
5
|
+
RegExp: createSandboxClosure({ sandbox: true, name: "RegExp", call: construct, construct })
|
|
6
6
|
};
|
|
7
7
|
}
|