poe-code 14.0.6 → 14.0.8
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 +944 -143
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-2M6MNQBY.js → chunk-MO3YD4ID.js} +888 -133
- package/packages/safe-js/dist/chunks/chunk-MO3YD4ID.js.map +7 -0
- package/packages/safe-js/dist/chunks/{chunk-QSSQJNKE.js → chunk-RXLDJ6LQ.js} +2 -2
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.d.ts +1 -1
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/extensions.d.ts +2 -0
- package/packages/safe-js/dist/index.d.ts +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/index.js.map +1 -1
- package/packages/safe-js/dist/interp/async.js +1 -0
- package/packages/safe-js/dist/interp/date.d.ts +19 -0
- package/packages/safe-js/dist/interp/date.js +129 -0
- package/packages/safe-js/dist/interp/globals/console-json.js +5 -1
- package/packages/safe-js/dist/interp/globals/date.d.ts +10 -0
- package/packages/safe-js/dist/interp/globals/date.js +95 -0
- package/packages/safe-js/dist/interp/globals/object-array.d.ts +4 -3
- package/packages/safe-js/dist/interp/globals/object-array.js +42 -5
- package/packages/safe-js/dist/interp/globals/object.d.ts +4 -0
- package/packages/safe-js/dist/interp/globals/object.js +153 -0
- package/packages/safe-js/dist/interp/globals.d.ts +4 -1
- package/packages/safe-js/dist/interp/globals.js +2 -0
- package/packages/safe-js/dist/interp/host-bridge.d.ts +4 -0
- package/packages/safe-js/dist/interp/host-bridge.js +21 -2
- package/packages/safe-js/dist/interp/host-call.js +4 -0
- package/packages/safe-js/dist/interp/host-capabilities.d.ts +28 -1
- package/packages/safe-js/dist/interp/host-capabilities.js +220 -5
- package/packages/safe-js/dist/interp/interpreter.js +46 -11
- package/packages/safe-js/dist/interp/iteration.js +3 -0
- package/packages/safe-js/dist/interp/object-model.d.ts +3 -1
- package/packages/safe-js/dist/interp/object-model.js +39 -9
- package/packages/safe-js/dist/interp/string-coercion.js +3 -0
- package/packages/safe-js/dist/interp/values.d.ts +3 -1
- package/packages/safe-js/dist/interp/values.js +34 -6
- package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
- package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
- package/packages/safe-js/dist/parse/parser.js +4 -2
- package/packages/safe-js/dist/realm.d.ts +4 -1
- package/packages/safe-js/dist/realm.js +89 -10
- package/packages/safe-js/dist/run.d.ts +2 -0
- package/packages/safe-js/dist/run.js +3 -1
- package/packages/safe-js/dist/snapshot/dump-format.js +8 -3
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +4 -1
- package/packages/safe-js/dist/snapshot/replay-data.js +11 -0
- package/packages/safe-js/dist/snapshot/restore.js +6 -0
- package/packages/safe-js/dist/snapshot/serialize.d.ts +5 -2
- package/packages/safe-js/dist/snapshot/serialize.js +8 -2
- package/packages/safe-js/dist/snapshot/validation.js +18 -1
- package/packages/safe-js/dist/chunks/chunk-2M6MNQBY.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-QSSQJNKE.js.map → chunk-RXLDJ6LQ.js.map} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
2
|
-
import { getHostObjectKeys, getHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
|
|
2
|
+
import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
|
|
3
|
+
import { sandboxString } from "./string-coercion.js";
|
|
3
4
|
import { assertPromiseExecutionAllowed } from "./promise-tracker.js";
|
|
4
5
|
import { SandboxJobQueue, runAsyncPrefix, suspendJob } from "./jobs.js";
|
|
5
6
|
import { withCancellationSignal } from "./cancel.js";
|
|
@@ -11,7 +12,7 @@ import { CompileScope, RegexCompileGuard } from "./regex/compile-guard.js";
|
|
|
11
12
|
import { coerceThrownValue, createCapturedException, evaluateThrowStatement as evaluateThrowStatementResult, evaluateTryStatement as evaluateTryStatementResult, isCapturedException, surfaceThrownValue } from "./exceptions.js";
|
|
12
13
|
import { callArrayMethod, getArrayMember, isArrayMethodName } from "./methods/array.js";
|
|
13
14
|
import { getFunctionMember } from "./methods/function.js";
|
|
14
|
-
import { getGuestFunctionProperty, getSandboxPrototype, isGuestClosure, materializeFunctionProperties } from "./object-model.js";
|
|
15
|
+
import { getGuestFunctionProperty, getSandboxPrototype, isGuestClosure, materializeFunctionProperties, setSandboxPrototype } from "./object-model.js";
|
|
15
16
|
import { assertSandboxDataDepth } from "../graph-depth.js";
|
|
16
17
|
import { callMapMethod, getMapMember, isMapMethodName } from "./methods/map.js";
|
|
17
18
|
import { callNumberMethod, getNumberMember, isNumberMethodName } from "./methods/number.js";
|
|
@@ -27,6 +28,8 @@ import { isSandboxErrorConstructorInstance } from "./globals/error.js";
|
|
|
27
28
|
import { isSandboxMapConstructor, isSandboxSetConstructor } from "./globals/collections.js";
|
|
28
29
|
import { getFloat32Member, isFloat32ArrayConstructor, setFloat32Member } from "./globals/float32array.js";
|
|
29
30
|
import { isFloat32Array } from "./float32.js";
|
|
31
|
+
import { dateString, dateTime, isSandboxDate } from "./date.js";
|
|
32
|
+
import { getDateMember, getDatePrototype, isDateConstructor } from "./globals/date.js";
|
|
30
33
|
import { createSandboxRegex, allocateProducedSandboxValue, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, reconcileCompiledValues } from "./values.js";
|
|
31
34
|
import { Scope } from "./scope.js";
|
|
32
35
|
import { hoistVarDeclarations } from "./var-hoist.js";
|
|
@@ -323,6 +326,9 @@ async function evaluateObjectExpression(node, context) {
|
|
|
323
326
|
return value;
|
|
324
327
|
}
|
|
325
328
|
if (isObjectPrototypeSetterProperty(property, key.value)) {
|
|
329
|
+
if (value.value === null || typeof value.value === "object") {
|
|
330
|
+
setSandboxPrototype(object, value.value, context.budget);
|
|
331
|
+
}
|
|
326
332
|
continue;
|
|
327
333
|
}
|
|
328
334
|
defineSandboxProperty(object, String(key.value), value.value);
|
|
@@ -431,7 +437,13 @@ async function evaluateBinaryExpression(node, context) {
|
|
|
431
437
|
if (right.kind !== "normal") {
|
|
432
438
|
return right;
|
|
433
439
|
}
|
|
434
|
-
const value =
|
|
440
|
+
const value = node.operator === "in" && isGuestHostObject(right.value)
|
|
441
|
+
? hasHostObjectMember(right.value, await sandboxString(left.value, context.budget, {
|
|
442
|
+
stack: context.callStack,
|
|
443
|
+
thisValue: undefined,
|
|
444
|
+
invokeClosure: (closure, args, thisValue) => invokeSandboxClosure(closure, args, context, context.callStack, undefined, thisValue)
|
|
445
|
+
}))
|
|
446
|
+
: applyBinaryOperator(node, left.value, right.value, context);
|
|
435
447
|
return {
|
|
436
448
|
kind: "normal",
|
|
437
449
|
hasValue: true,
|
|
@@ -1128,7 +1140,7 @@ function forInKeys(object, budget) {
|
|
|
1128
1140
|
const keys = [];
|
|
1129
1141
|
const seen = new Set();
|
|
1130
1142
|
let depth = 0;
|
|
1131
|
-
for (let current = object; current !== null; current = getSandboxPrototype(current)) {
|
|
1143
|
+
for (let current = object; current !== null; current = getSandboxPrototype(current, budget)) {
|
|
1132
1144
|
if (depth > 0)
|
|
1133
1145
|
budget.visitNode();
|
|
1134
1146
|
assertSandboxDataDepth(depth++);
|
|
@@ -1147,9 +1159,9 @@ function forInKeys(object, budget) {
|
|
|
1147
1159
|
}
|
|
1148
1160
|
function hasForInProperty(object, key, budget) {
|
|
1149
1161
|
if (isGuestHostObject(object))
|
|
1150
|
-
return
|
|
1162
|
+
return hasHostObjectMember(object, key, true);
|
|
1151
1163
|
let depth = 0;
|
|
1152
|
-
for (let current = object; current !== null; current = getSandboxPrototype(current)) {
|
|
1164
|
+
for (let current = object; current !== null; current = getSandboxPrototype(current, budget)) {
|
|
1153
1165
|
if (depth > 0)
|
|
1154
1166
|
budget.visitNode();
|
|
1155
1167
|
assertSandboxDataDepth(depth++);
|
|
@@ -1648,6 +1660,8 @@ function getPropertyValue(target, property, context) {
|
|
|
1648
1660
|
return undefined;
|
|
1649
1661
|
if (isFloat32Array(target))
|
|
1650
1662
|
return getFloat32Member(target, property, context.budget);
|
|
1663
|
+
if (isSandboxDate(target))
|
|
1664
|
+
return getDateMember(property, context.budget, context.compilation?.owner);
|
|
1651
1665
|
if (isSandboxMap(target))
|
|
1652
1666
|
return getMapMember(target, property, createMapMethodOptions(context));
|
|
1653
1667
|
if (isSandboxSet(target))
|
|
@@ -1864,6 +1878,9 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
1864
1878
|
if (isSandboxMap(member.object)) {
|
|
1865
1879
|
return evaluatePrimitiveMemberCall(node, "Map", member.property, getMapMember(member.object, member.property, createMapMethodOptions(context)), context);
|
|
1866
1880
|
}
|
|
1881
|
+
if (isSandboxDate(member.object)) {
|
|
1882
|
+
return evaluateResolvedCallExpression(node, getDateMember(member.property, context.budget, context.compilation?.owner), context, member.object);
|
|
1883
|
+
}
|
|
1867
1884
|
if (isFloat32Array(member.object)) {
|
|
1868
1885
|
return evaluateResolvedCallExpression(node, getFloat32Member(member.object, member.property, context.budget), context, member.object);
|
|
1869
1886
|
}
|
|
@@ -2076,6 +2093,8 @@ function applyBinaryOperator(node, left, right, context) {
|
|
|
2076
2093
|
}
|
|
2077
2094
|
if (isFloat32ArrayConstructor(right))
|
|
2078
2095
|
return isFloat32Array(left);
|
|
2096
|
+
if (isDateConstructor(right))
|
|
2097
|
+
return isSandboxDate(left) && getDatePrototype(left, context.budget, context.compilation?.owner) !== null;
|
|
2079
2098
|
if (isSandboxSetConstructor(right) && isSandboxSet(left)) {
|
|
2080
2099
|
return true;
|
|
2081
2100
|
}
|
|
@@ -2090,7 +2109,7 @@ function applyBinaryOperator(node, left, right, context) {
|
|
|
2090
2109
|
throw new TypeError("Function has a non-object prototype in instanceof check.");
|
|
2091
2110
|
}
|
|
2092
2111
|
let depth = 0;
|
|
2093
|
-
for (let current = getSandboxPrototype(left); current !== null; current = getSandboxPrototype(current)) {
|
|
2112
|
+
for (let current = getSandboxPrototype(left, context.budget); current !== null; current = getSandboxPrototype(current, context.budget)) {
|
|
2094
2113
|
context.budget.visitNode();
|
|
2095
2114
|
assertSandboxDataDepth(depth++);
|
|
2096
2115
|
if (current === prototype)
|
|
@@ -2141,8 +2160,8 @@ function applyAdditionOperator(left, right, context) {
|
|
|
2141
2160
|
return toNumber(leftPrimitive) + toNumber(rightPrimitive);
|
|
2142
2161
|
}
|
|
2143
2162
|
function compareRelational(left, right, operator) {
|
|
2144
|
-
const leftPrimitive = toPrimitive(left);
|
|
2145
|
-
const rightPrimitive = toPrimitive(right);
|
|
2163
|
+
const leftPrimitive = isSandboxDate(left) ? dateTime(left) : toPrimitive(left);
|
|
2164
|
+
const rightPrimitive = isSandboxDate(right) ? dateTime(right) : toPrimitive(right);
|
|
2146
2165
|
if (typeof leftPrimitive === "string" && typeof rightPrimitive === "string") {
|
|
2147
2166
|
switch (operator) {
|
|
2148
2167
|
case "<":
|
|
@@ -2225,6 +2244,8 @@ function toPrimitive(value) {
|
|
|
2225
2244
|
return toString(value);
|
|
2226
2245
|
}
|
|
2227
2246
|
async function toNumericPrimitive(value, context) {
|
|
2247
|
+
if (isSandboxDate(value))
|
|
2248
|
+
return dateTime(value);
|
|
2228
2249
|
if (isPrimitiveCoercionType(getCoercionType(value))) {
|
|
2229
2250
|
return value;
|
|
2230
2251
|
}
|
|
@@ -2247,6 +2268,8 @@ async function toNumericPrimitive(value, context) {
|
|
|
2247
2268
|
return toString(value);
|
|
2248
2269
|
}
|
|
2249
2270
|
function toNumber(value) {
|
|
2271
|
+
if (isSandboxDate(value))
|
|
2272
|
+
return dateTime(value);
|
|
2250
2273
|
if (typeof value === "number") {
|
|
2251
2274
|
return value;
|
|
2252
2275
|
}
|
|
@@ -2265,6 +2288,8 @@ function toNumber(value) {
|
|
|
2265
2288
|
return toNumber(toPrimitive(value));
|
|
2266
2289
|
}
|
|
2267
2290
|
function toString(value) {
|
|
2291
|
+
if (isSandboxDate(value))
|
|
2292
|
+
return dateString(value);
|
|
2268
2293
|
if (Array.isArray(value)) {
|
|
2269
2294
|
return value
|
|
2270
2295
|
.map((entry) => (entry === null || entry === undefined ? "" : toString(entry)))
|
|
@@ -2308,7 +2333,7 @@ function getMemberValue(target, property, context) {
|
|
|
2308
2333
|
}
|
|
2309
2334
|
if (Object.hasOwn(current, String(property)))
|
|
2310
2335
|
return current[String(property)];
|
|
2311
|
-
current = getSandboxPrototype(current);
|
|
2336
|
+
current = getSandboxPrototype(current, context.budget);
|
|
2312
2337
|
if (current !== null) {
|
|
2313
2338
|
context.budget.visitNode();
|
|
2314
2339
|
assertSandboxDataDepth(++depth);
|
|
@@ -2323,6 +2348,8 @@ function getArrayMemberValue(target, property, context) {
|
|
|
2323
2348
|
return getArrayMember(target, property, createArrayMethodOptions(context));
|
|
2324
2349
|
}
|
|
2325
2350
|
export function setSandboxProperty(target, property, value, budget) {
|
|
2351
|
+
if (isSandboxDate(target))
|
|
2352
|
+
throw new TypeError("Date own properties are not supported.");
|
|
2326
2353
|
if (isGuestHostObject(target)) {
|
|
2327
2354
|
setHostObjectMember(target, String(property), value);
|
|
2328
2355
|
return;
|
|
@@ -2359,7 +2386,7 @@ export function setSandboxProperty(target, property, value, budget) {
|
|
|
2359
2386
|
else {
|
|
2360
2387
|
if (typeof prototypeOwner === "object" && prototypeOwner !== null) {
|
|
2361
2388
|
let depth = 0;
|
|
2362
|
-
for (let prototype = getSandboxPrototype(prototypeOwner); prototype !== null; prototype = getSandboxPrototype(prototype)) {
|
|
2389
|
+
for (let prototype = getSandboxPrototype(prototypeOwner, budget); prototype !== null; prototype = getSandboxPrototype(prototype, budget)) {
|
|
2363
2390
|
budget.visitNode();
|
|
2364
2391
|
assertSandboxDataDepth(depth++);
|
|
2365
2392
|
const properties = isSandboxClosure(prototype) ? prototype.properties : prototype;
|
|
@@ -2553,6 +2580,14 @@ async function evaluateObjectSpread(node, context) {
|
|
|
2553
2580
|
value: []
|
|
2554
2581
|
};
|
|
2555
2582
|
}
|
|
2583
|
+
if (isGuestHostObject(value.value)) {
|
|
2584
|
+
const entries = [];
|
|
2585
|
+
for (const key of getHostObjectKeys(value.value)) {
|
|
2586
|
+
if (hasHostObjectMember(value.value, key, true))
|
|
2587
|
+
entries.push([key, getHostObjectMember(value.value, key)]);
|
|
2588
|
+
}
|
|
2589
|
+
return { ok: true, value: entries };
|
|
2590
|
+
}
|
|
2556
2591
|
if ((isSandboxClosure(value.value) && !isGuestClosure(value.value)) || isSandboxPromise(value.value)) {
|
|
2557
2592
|
throw new TypeError(`Cannot spread ${describeObjectSpreadValue(value.value)} into object literal.`);
|
|
2558
2593
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { isSandboxGenerator, isSandboxMap, isSandboxSet } from "./values.js";
|
|
2
2
|
import { enterRunningState } from "./running-state.js";
|
|
3
3
|
import { isFloat32Array } from "./float32.js";
|
|
4
|
+
import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
|
|
4
5
|
export function getSandboxIterator(value) {
|
|
6
|
+
if (isGuestHostObject(value))
|
|
7
|
+
return getHostObjectIterator(value);
|
|
5
8
|
if (isFloat32Array(value)) {
|
|
6
9
|
return syncIterator(Float32Array.prototype.values.call(value));
|
|
7
10
|
}
|
|
@@ -5,7 +5,9 @@ export declare function isGuestClosure(value: unknown): value is SandboxClosure;
|
|
|
5
5
|
export declare function getGuestFunctionProperties(closure: SandboxClosure): SandboxObject | undefined;
|
|
6
6
|
export declare function materializeFunctionProperties(closure: SandboxClosure): SandboxObject;
|
|
7
7
|
export declare function getGuestFunctionProperty(closure: SandboxClosure, key: string): SandboxValue;
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function installObjectPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
|
|
9
|
+
export declare function releaseObjectPrototype(budget: Budget): void;
|
|
10
|
+
export declare function getSandboxPrototype(value: object, budget?: Budget): object | null;
|
|
9
11
|
export declare function getSandboxDataProperty(value: SandboxValue, key: string | number, budget?: Budget): SandboxValue;
|
|
10
12
|
export declare function setSandboxPrototype(value: object, prototype: object | null, budget?: Budget): void;
|
|
11
13
|
export declare function markDescriptorObject(value: object): void;
|
|
@@ -4,6 +4,8 @@ import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, i
|
|
|
4
4
|
const guestClosures = new WeakSet();
|
|
5
5
|
const functionProperties = new WeakMap();
|
|
6
6
|
const prototypes = new WeakMap();
|
|
7
|
+
const intrinsicPrototypes = new WeakMap();
|
|
8
|
+
const intrinsicConstructors = new WeakMap();
|
|
7
9
|
const descriptorObjects = new WeakSet();
|
|
8
10
|
export function registerGuestClosure(closure) {
|
|
9
11
|
guestClosures.add(closure);
|
|
@@ -56,8 +58,33 @@ export function getGuestFunctionProperty(closure, key) {
|
|
|
56
58
|
? undefined
|
|
57
59
|
: Object.getOwnPropertyDescriptor(properties, key)?.value;
|
|
58
60
|
}
|
|
59
|
-
export function
|
|
60
|
-
|
|
61
|
+
export function installObjectPrototype(budget, prototype, constructor) {
|
|
62
|
+
prototypes.set(prototype, null);
|
|
63
|
+
intrinsicPrototypes.set(budget, prototype);
|
|
64
|
+
const records = [prototype, materializeFunctionProperties(constructor)].map(value => ({
|
|
65
|
+
value, descriptors: new Map(Object.entries(Object.getOwnPropertyDescriptors(value)))
|
|
66
|
+
}));
|
|
67
|
+
const unchanged = (before, after) => before !== undefined && after !== undefined && before.value === after.value &&
|
|
68
|
+
before.writable === after.writable && before.configurable === after.configurable && before.enumerable === after.enumerable;
|
|
69
|
+
intrinsicConstructors.set(constructor, () => records.every(({ value, descriptors }) => {
|
|
70
|
+
const current = Object.getOwnPropertyDescriptors(value);
|
|
71
|
+
return Object.keys(current).length === descriptors.size &&
|
|
72
|
+
Object.keys(current).every(key => unchanged(descriptors.get(key), current[key]));
|
|
73
|
+
}));
|
|
74
|
+
budget.setRetainedValues(prototype, () => records.flatMap(({ value, descriptors }) => Object.entries(Object.getOwnPropertyDescriptors(value)).flatMap(([key, descriptor]) => unchanged(descriptors.get(key), descriptor) ? [] : [key, descriptor.value])));
|
|
75
|
+
}
|
|
76
|
+
export function releaseObjectPrototype(budget) {
|
|
77
|
+
const prototype = intrinsicPrototypes.get(budget);
|
|
78
|
+
if (prototype !== undefined)
|
|
79
|
+
budget.setRetainedValues(prototype, undefined);
|
|
80
|
+
intrinsicPrototypes.delete(budget);
|
|
81
|
+
}
|
|
82
|
+
export function getSandboxPrototype(value, budget) {
|
|
83
|
+
if (prototypes.has(value))
|
|
84
|
+
return prototypes.get(value) ?? null;
|
|
85
|
+
return budget !== undefined && isPrototypeRecord(value)
|
|
86
|
+
? intrinsicPrototypes.get(budget) ?? null
|
|
87
|
+
: null;
|
|
61
88
|
}
|
|
62
89
|
export function getSandboxDataProperty(value, key, budget) {
|
|
63
90
|
let current = value;
|
|
@@ -81,7 +108,7 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
81
108
|
return undefined;
|
|
82
109
|
if (Object.hasOwn(current, String(key)))
|
|
83
110
|
return current[String(key)];
|
|
84
|
-
current = getSandboxPrototype(current);
|
|
111
|
+
current = getSandboxPrototype(current, budget);
|
|
85
112
|
if (current !== null) {
|
|
86
113
|
budget?.visitNode();
|
|
87
114
|
assertSandboxDataDepth(++depth);
|
|
@@ -90,25 +117,25 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
90
117
|
return undefined;
|
|
91
118
|
}
|
|
92
119
|
export function setSandboxPrototype(value, prototype, budget) {
|
|
120
|
+
if (budget !== undefined && intrinsicPrototypes.get(budget) === value && prototype !== null) {
|
|
121
|
+
throw new TypeError("Object.prototype has an immutable null prototype.");
|
|
122
|
+
}
|
|
93
123
|
if (!isPrototypeRecord(value) || (prototype !== null && !isPrototypeRecord(prototype))) {
|
|
94
124
|
throw new TypeError("Prototype links require ordinary sandbox objects; callable and exotic prototype chains are not supported.");
|
|
95
125
|
}
|
|
96
|
-
if (getSandboxPrototype(value) === prototype)
|
|
126
|
+
if (prototypes.has(value) && getSandboxPrototype(value, budget) === prototype)
|
|
97
127
|
return;
|
|
98
128
|
if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : value)) {
|
|
99
129
|
throw new TypeError("Cannot change the prototype of a non-extensible object.");
|
|
100
130
|
}
|
|
101
131
|
let depth = 0;
|
|
102
|
-
for (let current = prototype; current !== null; current = getSandboxPrototype(current)) {
|
|
132
|
+
for (let current = prototype; current !== null; current = getSandboxPrototype(current, budget)) {
|
|
103
133
|
budget?.visitNode();
|
|
104
134
|
assertSandboxDataDepth(depth++);
|
|
105
135
|
if (current === value)
|
|
106
136
|
throw new TypeError("Cyclic prototype value.");
|
|
107
137
|
}
|
|
108
|
-
|
|
109
|
-
prototypes.delete(value);
|
|
110
|
-
else
|
|
111
|
-
prototypes.set(value, prototype);
|
|
138
|
+
prototypes.set(value, prototype);
|
|
112
139
|
}
|
|
113
140
|
function isPrototypeRecord(value) {
|
|
114
141
|
if (isGuestHostObject(value))
|
|
@@ -130,6 +157,9 @@ export function hasManagedDescriptors(value) {
|
|
|
130
157
|
return descriptorObjects.has(value);
|
|
131
158
|
}
|
|
132
159
|
export function hasGuestObjectState(value) {
|
|
160
|
+
const intrinsicUnchanged = intrinsicConstructors.get(value);
|
|
161
|
+
if (intrinsicUnchanged !== undefined)
|
|
162
|
+
return !intrinsicUnchanged();
|
|
133
163
|
if (isLiveCapability(value))
|
|
134
164
|
return true;
|
|
135
165
|
if (functionProperties.has(value) || prototypes.has(value))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sandboxErrorTypes } from "../error/shape.js";
|
|
2
|
+
import { dateString, isSandboxDate } from "./date.js";
|
|
2
3
|
import { float32Storage, isFloat32Array } from "./float32.js";
|
|
3
4
|
import { isSandboxClosure, isSandboxPromise } from "./values.js";
|
|
4
5
|
export function sandboxString(value, budget, context, joining = new Set()) {
|
|
@@ -41,6 +42,8 @@ async function stringifyObject(value, budget, context, joining) {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
async function defaultToString(value, budget, context, joining) {
|
|
45
|
+
if (isSandboxDate(value))
|
|
46
|
+
return budget.allocateString(dateString(value));
|
|
44
47
|
if (Array.isArray(value) || isFloat32Array(value)) {
|
|
45
48
|
if (Object.hasOwn(value, "join")) {
|
|
46
49
|
const join = ownDataValue(value, "join");
|
|
@@ -12,7 +12,7 @@ declare const sandboxRegexPattern: unique symbol;
|
|
|
12
12
|
declare const sandboxSetBrand: unique symbol;
|
|
13
13
|
declare const sandboxRetainedValues: unique symbol;
|
|
14
14
|
export type SandboxPrimitive = string | number | boolean | null | undefined;
|
|
15
|
-
export type SandboxValue = SandboxPrimitive | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
|
|
15
|
+
export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
|
|
16
16
|
export type SandboxObject = {
|
|
17
17
|
[key: string]: SandboxValue;
|
|
18
18
|
};
|
|
@@ -55,6 +55,7 @@ export type SandboxCallContext = {
|
|
|
55
55
|
};
|
|
56
56
|
export type SandboxClosure = {
|
|
57
57
|
readonly async?: true;
|
|
58
|
+
readonly generator?: true;
|
|
58
59
|
readonly sandbox?: true;
|
|
59
60
|
readonly boundTarget?: SandboxClosure;
|
|
60
61
|
readonly cancellationSignal?: AbortSignal;
|
|
@@ -92,6 +93,7 @@ type CopyFromSandboxOptions = {
|
|
|
92
93
|
export declare function createSandboxClosure(input: {
|
|
93
94
|
guest?: boolean;
|
|
94
95
|
async?: boolean;
|
|
96
|
+
generator?: boolean;
|
|
95
97
|
sandbox?: boolean;
|
|
96
98
|
boundTarget?: SandboxClosure;
|
|
97
99
|
cancellationSignal?: AbortSignal;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
2
|
-
import {
|
|
2
|
+
import { copyNativeDate, exportDate, isSandboxDate } from "./date.js";
|
|
3
|
+
import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
3
4
|
import { types as nodeTypes } from "node:util";
|
|
4
5
|
import { CompileScope, RegexCompileGuard, regexCompiledData } from "./regex/compile-guard.js";
|
|
5
6
|
import { copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
@@ -40,6 +41,8 @@ export function createSandboxClosure(input) {
|
|
|
40
41
|
if (input.sandbox === true) {
|
|
41
42
|
Object.defineProperty(closure, "sandbox", { value: true });
|
|
42
43
|
}
|
|
44
|
+
if (input.generator === true)
|
|
45
|
+
Object.defineProperty(closure, "generator", { value: true });
|
|
43
46
|
if (input.length !== undefined) {
|
|
44
47
|
Object.defineProperty(closure, "length", { value: input.length });
|
|
45
48
|
}
|
|
@@ -71,8 +74,14 @@ export function createSandboxClosure(input) {
|
|
|
71
74
|
return Object.freeze(closure);
|
|
72
75
|
}
|
|
73
76
|
export function ownEnumerableSandboxEntries(value) {
|
|
74
|
-
if (isGuestHostObject(value))
|
|
75
|
-
|
|
77
|
+
if (isGuestHostObject(value)) {
|
|
78
|
+
const entries = [];
|
|
79
|
+
for (const key of getHostObjectKeys(value)) {
|
|
80
|
+
if (hasHostObjectMember(value, key, true))
|
|
81
|
+
entries.push([key, getHostObjectMember(value, key)]);
|
|
82
|
+
}
|
|
83
|
+
return entries;
|
|
84
|
+
}
|
|
76
85
|
if (value === null || value === undefined)
|
|
77
86
|
throw new TypeError("Cannot convert undefined or null to object.");
|
|
78
87
|
if (isGuestClosure(value))
|
|
@@ -225,9 +234,12 @@ export function measureSandboxData(values, options = {}) {
|
|
|
225
234
|
assertSandboxDataDepth(depth);
|
|
226
235
|
seen.add(value);
|
|
227
236
|
usage += 1;
|
|
237
|
+
if (isSandboxDate(value)) {
|
|
238
|
+
usage += 8;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
228
241
|
if (isGuestHostObject(value)) {
|
|
229
|
-
|
|
230
|
-
usage += key.length + 1;
|
|
242
|
+
usage += measureHostObjectData(value);
|
|
231
243
|
return;
|
|
232
244
|
}
|
|
233
245
|
const prototype = getSandboxPrototype(value);
|
|
@@ -341,7 +353,7 @@ export function reconcileCompiledValues(budget, values, compilation, parent, esc
|
|
|
341
353
|
while (parent?.closed)
|
|
342
354
|
parent = parent.parent;
|
|
343
355
|
const included = new Set();
|
|
344
|
-
const usage = measureSandboxData(values, { compileTickets: included });
|
|
356
|
+
const usage = measureSandboxData([...values, ...budget.retainedValues()], { compileTickets: included });
|
|
345
357
|
const kept = new Set();
|
|
346
358
|
if (parent !== undefined)
|
|
347
359
|
measureSandboxData(escaping, { compileTickets: kept });
|
|
@@ -435,6 +447,14 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
435
447
|
}
|
|
436
448
|
return sandboxPromise;
|
|
437
449
|
}
|
|
450
|
+
if (nodeTypes.isDate(value)) {
|
|
451
|
+
const existing = state.seen.get(value);
|
|
452
|
+
if (existing !== undefined)
|
|
453
|
+
return existing;
|
|
454
|
+
const copy = copyNativeDate(value);
|
|
455
|
+
state.seen.set(value, copy);
|
|
456
|
+
return copy;
|
|
457
|
+
}
|
|
438
458
|
if (isFloat32Array(value)) {
|
|
439
459
|
const existing = state.seen.get(value);
|
|
440
460
|
if (existing !== undefined)
|
|
@@ -567,6 +587,14 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
567
587
|
Object.preventExtensions(copy);
|
|
568
588
|
return copy;
|
|
569
589
|
}
|
|
590
|
+
if (isSandboxDate(value)) {
|
|
591
|
+
const existing = state.seen.get(value);
|
|
592
|
+
if (existing !== undefined)
|
|
593
|
+
return existing;
|
|
594
|
+
const copy = exportDate(value);
|
|
595
|
+
state.seen.set(value, copy);
|
|
596
|
+
return copy;
|
|
597
|
+
}
|
|
570
598
|
if (isSandboxClosure(value)) {
|
|
571
599
|
if (options.wrapClosure === undefined) {
|
|
572
600
|
throw new TypeError("Sandbox closures cannot cross into host values without an explicit wrapper.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "structuredClone", "SyntaxError", "TypeError", "console"];
|
|
1
|
+
export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "Date", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "structuredClone", "SyntaxError", "TypeError", "console"];
|
|
@@ -1832,8 +1832,10 @@ class Parser {
|
|
|
1832
1832
|
}
|
|
1833
1833
|
break;
|
|
1834
1834
|
}
|
|
1835
|
-
this.
|
|
1836
|
-
|
|
1835
|
+
const optional = this.consumePunctuator("?.");
|
|
1836
|
+
if (optional !== undefined)
|
|
1837
|
+
throw new DisallowedSyntaxError("new optional chain", optional.start);
|
|
1838
|
+
const args = this.consumePunctuator("(") === undefined ? [] : this.parseArguments();
|
|
1837
1839
|
const end = this.previousToken();
|
|
1838
1840
|
return {
|
|
1839
1841
|
node: {
|
|
@@ -4,15 +4,17 @@ import { type CallerInjectedBinding } from "./interp/host-bridge.js";
|
|
|
4
4
|
import { type CallbackOptions, type SafeJSExtension } from "./extensions.js";
|
|
5
5
|
import { type ModuleRegistry } from "./modules/registry.js";
|
|
6
6
|
import type { ConsoleSink } from "./interp/globals/console-json.js";
|
|
7
|
-
import type { RunOptions, RunResult } from "./run.js";
|
|
7
|
+
import type { RunClock, RunOptions, RunResult } from "./run.js";
|
|
8
8
|
export type RealmLimits = {
|
|
9
9
|
extensions?: number;
|
|
10
10
|
hostObjects?: number;
|
|
11
11
|
callbacks?: number;
|
|
12
|
+
guestReferences?: number;
|
|
12
13
|
cleanups?: number;
|
|
13
14
|
nestedEvaluations?: number;
|
|
14
15
|
};
|
|
15
16
|
export type RealmOptions = {
|
|
17
|
+
clock?: RunClock;
|
|
16
18
|
bindings?: Record<string, CallerInjectedBinding>;
|
|
17
19
|
modules?: ModuleRegistry;
|
|
18
20
|
extensions?: readonly SafeJSExtension[];
|
|
@@ -37,6 +39,7 @@ export type SafeJSRealm = {
|
|
|
37
39
|
}): Promise<RealmResult>;
|
|
38
40
|
invokeCallback(callback: unknown, options?: CallbackOptions): Promise<unknown>;
|
|
39
41
|
releaseCallback(callback: unknown): void;
|
|
42
|
+
releaseGuestReference(reference: unknown): void;
|
|
40
43
|
close(): Promise<void>;
|
|
41
44
|
};
|
|
42
45
|
export declare function createRealm(options?: RealmOptions): SafeJSRealm;
|