poe-code 14.0.62 → 14.0.63
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 +929 -504
- 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-F7TJSPDZ.js → chunk-KMTTD3BL.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-VKGWGZBH.js → chunk-RU2BCN4G.js} +898 -521
- package/packages/safe-js/dist/chunks/chunk-RU2BCN4G.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/graph-depth.js +3 -0
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/boxed.d.ts +14 -0
- package/packages/safe-js/dist/interp/boxed.js +50 -0
- package/packages/safe-js/dist/interp/globals/collections.js +4 -4
- package/packages/safe-js/dist/interp/globals/console-json.js +15 -18
- package/packages/safe-js/dist/interp/globals/misc.js +1 -1
- package/packages/safe-js/dist/interp/globals/object-array.js +19 -14
- package/packages/safe-js/dist/interp/globals/object.js +10 -5
- package/packages/safe-js/dist/interp/globals/primitives.d.ts +8 -0
- package/packages/safe-js/dist/interp/globals/primitives.js +69 -0
- package/packages/safe-js/dist/interp/host-bridge.js +22 -0
- package/packages/safe-js/dist/interp/interpreter.js +172 -120
- package/packages/safe-js/dist/interp/iteration.d.ts +5 -3
- package/packages/safe-js/dist/interp/iteration.js +22 -1
- package/packages/safe-js/dist/interp/methods/array.js +6 -3
- package/packages/safe-js/dist/interp/methods/number.d.ts +1 -0
- package/packages/safe-js/dist/interp/methods/number.js +4 -1
- package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
- package/packages/safe-js/dist/interp/methods/string.js +2 -2
- package/packages/safe-js/dist/interp/object-model.d.ts +5 -0
- package/packages/safe-js/dist/interp/object-model.js +41 -3
- package/packages/safe-js/dist/interp/promise.js +68 -61
- package/packages/safe-js/dist/interp/string-coercion.js +4 -1
- package/packages/safe-js/dist/interp/values.d.ts +1 -0
- package/packages/safe-js/dist/interp/values.js +78 -3
- package/packages/safe-js/dist/migrate.d.ts +2 -2
- package/packages/safe-js/dist/migration-file.d.ts +4 -4
- package/packages/safe-js/dist/snapshot/boxed.d.ts +16 -0
- package/packages/safe-js/dist/snapshot/boxed.js +52 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +18 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +24 -0
- package/packages/safe-js/dist/snapshot/restore.js +8 -0
- package/packages/safe-js/dist/snapshot/serialize.d.ts +4 -2
- package/packages/safe-js/dist/snapshot/serialize.js +18 -10
- package/packages/safe-js/dist/snapshot/validation.js +22 -1
- package/packages/safe-js/dist/chunks/chunk-VKGWGZBH.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-F7TJSPDZ.js.map → chunk-KMTTD3BL.js.map} +0 -0
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveFsConfig,
|
|
23
23
|
splitFrontmatter,
|
|
24
24
|
withBrokenPipeGuard
|
|
25
|
-
} from "./chunks/chunk-
|
|
25
|
+
} from "./chunks/chunk-KMTTD3BL.js";
|
|
26
26
|
import {
|
|
27
27
|
Budget,
|
|
28
28
|
SandboxError,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
replaceErrorStack,
|
|
35
35
|
restore,
|
|
36
36
|
run
|
|
37
|
-
} from "./chunks/chunk-
|
|
37
|
+
} from "./chunks/chunk-RU2BCN4G.js";
|
|
38
38
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
39
39
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
40
40
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -3,6 +3,7 @@ import { SandboxError } from "./interp/budget.js";
|
|
|
3
3
|
import { getSandboxArgumentEntries, isSandboxArguments } from "./interp/arguments.js";
|
|
4
4
|
import { collectionIteratorState, isSandboxCollectionIterator } from "./interp/collection-iterator.js";
|
|
5
5
|
import { isSandboxMap, isSandboxSet } from "./interp/collection-brands.js";
|
|
6
|
+
import { boxedDataProperties, isSandboxBox } from "./interp/boxed.js";
|
|
6
7
|
export const MAX_DATA_DEPTH = 1_024;
|
|
7
8
|
export class SnapshotBudgetError extends Error {
|
|
8
9
|
code = "budgetExceeded";
|
|
@@ -63,6 +64,8 @@ function walkGraphDepth(root, rootPath, assertDepth) {
|
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
function graphEntries(value) {
|
|
67
|
+
if (isSandboxBox(value))
|
|
68
|
+
return boxedDataProperties(value).map(([key, descriptor]) => [`.${key}`, descriptor.value]);
|
|
66
69
|
if (isSandboxArguments(value)) {
|
|
67
70
|
return getSandboxArgumentEntries(value).map(([key, entry]) => [`.${key}`, entry]);
|
|
68
71
|
}
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
runWithSpawnUsageAccumulator,
|
|
27
27
|
splitFrontmatter,
|
|
28
28
|
supportsSpawnMode
|
|
29
|
-
} from "./chunks/chunk-
|
|
29
|
+
} from "./chunks/chunk-KMTTD3BL.js";
|
|
30
30
|
import {
|
|
31
31
|
Budget,
|
|
32
32
|
FileSnapshotBackend,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
registerPendingHostCallPolicy,
|
|
51
51
|
restore,
|
|
52
52
|
run
|
|
53
|
-
} from "./chunks/chunk-
|
|
53
|
+
} from "./chunks/chunk-RU2BCN4G.js";
|
|
54
54
|
import "./chunks/chunk-UXMKEUH3.js";
|
|
55
55
|
import "./chunks/chunk-5DYEOCT5.js";
|
|
56
56
|
import "./chunks/chunk-4YIDX44G.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SandboxObject } from "./values.js";
|
|
2
|
+
export type BoxedPrimitive = string | number | boolean;
|
|
3
|
+
export type BoxedKind = "string" | "number" | "boolean";
|
|
4
|
+
declare const boxedPrimitiveBrand: unique symbol;
|
|
5
|
+
export type SandboxBox = SandboxObject & {
|
|
6
|
+
readonly [boxedPrimitiveBrand]: true;
|
|
7
|
+
};
|
|
8
|
+
export declare function nativeBoxedValue(value: unknown): BoxedPrimitive | undefined;
|
|
9
|
+
export declare function createSandboxBox(value: unknown): SandboxBox;
|
|
10
|
+
export declare function isSandboxBox(value: unknown): value is SandboxBox;
|
|
11
|
+
export declare function boxedValue(value: object): BoxedPrimitive;
|
|
12
|
+
export declare function primitiveReceiver(value: unknown, kind: BoxedKind): BoxedPrimitive;
|
|
13
|
+
export declare function boxedDataProperties(value: object): Array<[string, PropertyDescriptor]>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { types } from "node:util";
|
|
2
|
+
const boxes = new WeakSet();
|
|
3
|
+
const numberValue = Number.prototype.valueOf;
|
|
4
|
+
const stringValue = String.prototype.valueOf;
|
|
5
|
+
const booleanValue = Boolean.prototype.valueOf;
|
|
6
|
+
export function nativeBoxedValue(value) {
|
|
7
|
+
if (types.isNumberObject(value))
|
|
8
|
+
return Reflect.apply(numberValue, value, []);
|
|
9
|
+
if (types.isStringObject(value))
|
|
10
|
+
return Reflect.apply(stringValue, value, []);
|
|
11
|
+
if (types.isBooleanObject(value))
|
|
12
|
+
return Reflect.apply(booleanValue, value, []);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
export function createSandboxBox(value) {
|
|
16
|
+
if (typeof value !== "number" && typeof value !== "string" && typeof value !== "boolean")
|
|
17
|
+
throw new TypeError("Invalid boxed primitive payload.");
|
|
18
|
+
const box = Object(value);
|
|
19
|
+
Object.setPrototypeOf(box, null);
|
|
20
|
+
boxes.add(box);
|
|
21
|
+
return box;
|
|
22
|
+
}
|
|
23
|
+
export function isSandboxBox(value) {
|
|
24
|
+
return typeof value === "object" && value !== null && boxes.has(value);
|
|
25
|
+
}
|
|
26
|
+
export function boxedValue(value) {
|
|
27
|
+
if (!boxes.has(value))
|
|
28
|
+
throw new TypeError("Expected a sandbox boxed primitive.");
|
|
29
|
+
return nativeBoxedValue(value);
|
|
30
|
+
}
|
|
31
|
+
export function primitiveReceiver(value, kind) {
|
|
32
|
+
const primitive = isSandboxBox(value) ? boxedValue(value) : value;
|
|
33
|
+
if (typeof primitive !== kind)
|
|
34
|
+
throw new TypeError(`${kind} method requires a ${kind} receiver.`);
|
|
35
|
+
return primitive;
|
|
36
|
+
}
|
|
37
|
+
export function boxedDataProperties(value) {
|
|
38
|
+
const primitive = nativeBoxedValue(value);
|
|
39
|
+
return Object.entries(Object.getOwnPropertyDescriptors(value)).filter(([key]) => {
|
|
40
|
+
if (typeof primitive !== "string")
|
|
41
|
+
return true;
|
|
42
|
+
if (key === "length")
|
|
43
|
+
return false;
|
|
44
|
+
const index = Number(key);
|
|
45
|
+
return !(Number.isInteger(index) &&
|
|
46
|
+
index >= 0 &&
|
|
47
|
+
index < primitive.length &&
|
|
48
|
+
String(index) === key);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -71,13 +71,13 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
71
71
|
budget.allocateCollectionEntries(0);
|
|
72
72
|
if (source === undefined || source === null)
|
|
73
73
|
return collection;
|
|
74
|
-
const iterator = getSandboxIterator(source, budget);
|
|
74
|
+
const iterator = getSandboxIterator(source, budget, context);
|
|
75
75
|
if (iterator === undefined)
|
|
76
76
|
throw new TypeError(`${name} constructor requires an iterable.`);
|
|
77
77
|
let entry;
|
|
78
78
|
let failure;
|
|
79
79
|
const retained = {};
|
|
80
|
-
budget.setRetainedValues(retained, () => [source, collection, entry, failure, ...(retainedValues?.() ?? [])]);
|
|
80
|
+
budget.setRetainedValues(retained, () => [source, iterator.retainedValue, collection, entry, failure, ...(retainedValues?.() ?? [])]);
|
|
81
81
|
const checkData = createDataCheckpoint(budget, context);
|
|
82
82
|
const closeOnThrow = (error) => {
|
|
83
83
|
failure = isCapturedException(error) ? error.reason : error;
|
|
@@ -88,7 +88,7 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
88
88
|
};
|
|
89
89
|
try {
|
|
90
90
|
const closing = iterator.return?.();
|
|
91
|
-
if (iterator.generator)
|
|
91
|
+
if (iterator.generator || iterator.asynchronous)
|
|
92
92
|
return Promise.resolve(closing).then(() => { throw error; }, rethrow);
|
|
93
93
|
}
|
|
94
94
|
catch (closeError) {
|
|
@@ -113,7 +113,7 @@ function populateCollection(source, collection, { name, budget, context, append,
|
|
|
113
113
|
}
|
|
114
114
|
return false;
|
|
115
115
|
};
|
|
116
|
-
if (iterator.generator) {
|
|
116
|
+
if (iterator.generator || iterator.asynchronous) {
|
|
117
117
|
return (async () => {
|
|
118
118
|
try {
|
|
119
119
|
checkData(collection, 0, true);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { dateMethods, isSandboxDate } from "../date.js";
|
|
2
|
+
import { boxedValue, isSandboxBox } from "../boxed.js";
|
|
3
|
+
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
2
4
|
import { CompileScope } from "../regex/compile-guard.js";
|
|
3
5
|
import { wrapCallerInjectedBindings } from "../host-bridge.js";
|
|
4
6
|
import { allocateProducedSandboxValue, createSandboxClosure, deepCopyFromSandbox, isSandboxClosure, isSandboxPromise } from "../values.js";
|
|
@@ -8,12 +10,15 @@ export function createConsoleJsonGlobals(options) {
|
|
|
8
10
|
JSON: {
|
|
9
11
|
parse: createSandboxClosure({
|
|
10
12
|
sandbox: true,
|
|
11
|
-
call: async ([text]) =>
|
|
13
|
+
call: async ([text], context) => {
|
|
14
|
+
const converted = sandboxString(text, options.budget, context);
|
|
15
|
+
return copyJsonToSandbox(JSON.parse(converted instanceof Promise ? await converted : converted), options.budget);
|
|
16
|
+
},
|
|
12
17
|
name: "parse"
|
|
13
18
|
}),
|
|
14
19
|
stringify: createSandboxClosure({
|
|
15
20
|
sandbox: true,
|
|
16
|
-
call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
|
|
21
|
+
call: async ([value, replacer, indent], context) => stringifyJson(value, replacer, indent, options.budget, context),
|
|
17
22
|
name: "stringify"
|
|
18
23
|
})
|
|
19
24
|
},
|
|
@@ -69,11 +74,7 @@ export function createConsoleJsonGlobals(options) {
|
|
|
69
74
|
})
|
|
70
75
|
};
|
|
71
76
|
}
|
|
72
|
-
function
|
|
73
|
-
const text = budget.allocateString(toJsonParseText(input));
|
|
74
|
-
return copyJsonToSandbox(JSON.parse(text), budget);
|
|
75
|
-
}
|
|
76
|
-
async function stringifyJson(value, replacer, indent, budget) {
|
|
77
|
+
async function stringifyJson(value, replacer, indent, budget, context) {
|
|
77
78
|
if (replacer !== undefined && replacer !== null && !isSandboxClosure(replacer)) {
|
|
78
79
|
throw new TypeError("JSON.stringify(value, replacer, indent) only supports function, null, or undefined replacers.");
|
|
79
80
|
}
|
|
@@ -84,6 +85,7 @@ async function stringifyJson(value, replacer, indent, budget) {
|
|
|
84
85
|
defineDataProperty(holder, "", value);
|
|
85
86
|
const output = await stringifyProperty("", holder, {
|
|
86
87
|
budget,
|
|
88
|
+
context,
|
|
87
89
|
gap: normalizeStringifyGap(indent),
|
|
88
90
|
replacer: isSandboxClosure(replacer) ? replacer : undefined,
|
|
89
91
|
stack: []
|
|
@@ -93,17 +95,6 @@ async function stringifyJson(value, replacer, indent, budget) {
|
|
|
93
95
|
}
|
|
94
96
|
return budget.allocateString(output);
|
|
95
97
|
}
|
|
96
|
-
function toJsonParseText(input) {
|
|
97
|
-
if (Array.isArray(input)) {
|
|
98
|
-
return input
|
|
99
|
-
.map((entry) => (entry === null || entry === undefined ? "" : toJsonParseText(entry)))
|
|
100
|
-
.join(",");
|
|
101
|
-
}
|
|
102
|
-
if (typeof input === "object" && input !== null) {
|
|
103
|
-
return "[object Object]";
|
|
104
|
-
}
|
|
105
|
-
return String(input);
|
|
106
|
-
}
|
|
107
98
|
async function stringifyProperty(key, holder, state, indent = "") {
|
|
108
99
|
let value = getOwnDataValue(holder, key);
|
|
109
100
|
if (isSandboxDate(value)) {
|
|
@@ -121,6 +112,12 @@ async function stringifyProperty(key, holder, state, indent = "") {
|
|
|
121
112
|
return stringifyValue(value, state, indent);
|
|
122
113
|
}
|
|
123
114
|
async function stringifyValue(value, state, indent) {
|
|
115
|
+
if (isSandboxBox(value)) {
|
|
116
|
+
const primitive = boxedValue(value);
|
|
117
|
+
value = typeof primitive === "number" ? await sandboxNumber(value, state.budget, state.context)
|
|
118
|
+
: typeof primitive === "string" ? await sandboxString(value, state.budget, state.context)
|
|
119
|
+
: primitive;
|
|
120
|
+
}
|
|
124
121
|
if (value === null) {
|
|
125
122
|
return "null";
|
|
126
123
|
}
|
|
@@ -34,7 +34,7 @@ function structuredCloneSandboxValue(value, budget, parent) {
|
|
|
34
34
|
const operation = budget.acquireCompileOwner(false, parent?.owner);
|
|
35
35
|
const compilation = parent?.owner === operation.owner ? parent : new CompileScope(operation.owner);
|
|
36
36
|
try {
|
|
37
|
-
const clone = cloneSandboxValue(value, { compilation, resetRegexLastIndex: true });
|
|
37
|
+
const clone = cloneSandboxValue(value, { compilation, resetRegexLastIndex: true, structuredClone: true });
|
|
38
38
|
assertSandboxGraphDepth(clone);
|
|
39
39
|
assertStructuredCloneable(clone, new WeakSet());
|
|
40
40
|
allocateProducedSandboxValue(clone, budget);
|
|
@@ -3,6 +3,7 @@ import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
|
3
3
|
import { createDataCheckpoint } from "../data-checkpoint.js";
|
|
4
4
|
import { isCapturedException } from "../exceptions.js";
|
|
5
5
|
import { isSandboxDate } from "../date.js";
|
|
6
|
+
import { createSandboxBox } from "../boxed.js";
|
|
6
7
|
import { getDatePrototype } from "./date.js";
|
|
7
8
|
import { createObjectGlobal, hasOwnSandboxProperty } from "./object.js";
|
|
8
9
|
import { getHostObjectKeys, isGuestHostObject } from "../host-capabilities.js";
|
|
@@ -11,6 +12,7 @@ import { setSandboxProperty } from "../interpreter.js";
|
|
|
11
12
|
import { getSandboxIterator } from "../iteration.js";
|
|
12
13
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
13
14
|
import { createNumericParsers } from "./numeric-parsers.js";
|
|
15
|
+
import { createPrimitiveConstructor } from "./primitives.js";
|
|
14
16
|
import { getSandboxDataProperty, getSandboxPrototype, isGuestClosure, markDescriptorObject, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
|
|
15
17
|
import { allocateProducedSandboxValue, createSandboxClosure, deepCopyToSandbox, defineOwnDataProperty, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, measureSandboxData, ownEnumerableSandboxEntries as getOwnEnumerableEntries } from "../values.js";
|
|
16
18
|
export function createObjectArrayGlobals(options) {
|
|
@@ -82,6 +84,8 @@ export function createObjectArrayGlobals(options) {
|
|
|
82
84
|
call: ([value]) => {
|
|
83
85
|
if (isSandboxDate(value))
|
|
84
86
|
return getDatePrototype(value, options.budget, options.compileOwner);
|
|
87
|
+
if (value !== null && value !== undefined && typeof value !== "object")
|
|
88
|
+
value = createSandboxBox(value);
|
|
85
89
|
objectProperties(value);
|
|
86
90
|
return getSandboxPrototype(value, options.budget);
|
|
87
91
|
},
|
|
@@ -123,11 +127,11 @@ export function createObjectArrayGlobals(options) {
|
|
|
123
127
|
fromEntries: createSandboxClosure({
|
|
124
128
|
sandbox: true,
|
|
125
129
|
call: ([value], context) => {
|
|
126
|
-
const iterator = getSandboxIterator(value, options.budget);
|
|
130
|
+
const iterator = getSandboxIterator(value, options.budget, context);
|
|
127
131
|
if (iterator === undefined) {
|
|
128
132
|
throw new TypeError("Object.fromEntries requires an iterable.");
|
|
129
133
|
}
|
|
130
|
-
if (context === undefined && !iterator.generator) {
|
|
134
|
+
if (context === undefined && !iterator.generator && !iterator.asynchronous) {
|
|
131
135
|
// The direct host adapter preserves synchronous results and native hooks.
|
|
132
136
|
return allocateProducedSandboxValue(Object.setPrototypeOf(Reflect.apply(Object.fromEntries, Object, [{ [Symbol.iterator]: () => iterator }]), null), options.budget);
|
|
133
137
|
}
|
|
@@ -181,8 +185,7 @@ export function createObjectArrayGlobals(options) {
|
|
|
181
185
|
})
|
|
182
186
|
}
|
|
183
187
|
}),
|
|
184
|
-
String:
|
|
185
|
-
sandbox: true,
|
|
188
|
+
String: createPrimitiveConstructor({
|
|
186
189
|
call: (args, context) => sandboxString(args.length === 0 ? "" : args[0], options.budget, context),
|
|
187
190
|
name: "String",
|
|
188
191
|
properties: {
|
|
@@ -202,9 +205,8 @@ export function createObjectArrayGlobals(options) {
|
|
|
202
205
|
name: "fromCodePoint"
|
|
203
206
|
})
|
|
204
207
|
}
|
|
205
|
-
}),
|
|
206
|
-
Number:
|
|
207
|
-
sandbox: true,
|
|
208
|
+
}, options.budget),
|
|
209
|
+
Number: createPrimitiveConstructor({
|
|
208
210
|
call: (args, context) => sandboxNumber(args.length === 0 ? 0 : args[0], options.budget, context),
|
|
209
211
|
name: "Number",
|
|
210
212
|
properties: {
|
|
@@ -238,12 +240,11 @@ export function createObjectArrayGlobals(options) {
|
|
|
238
240
|
NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
|
|
239
241
|
POSITIVE_INFINITY: Number.POSITIVE_INFINITY
|
|
240
242
|
}
|
|
241
|
-
}),
|
|
242
|
-
Boolean:
|
|
243
|
-
sandbox: true,
|
|
243
|
+
}, options.budget),
|
|
244
|
+
Boolean: createPrimitiveConstructor({
|
|
244
245
|
call: ([value]) => Boolean(value),
|
|
245
246
|
name: "Boolean"
|
|
246
|
-
})
|
|
247
|
+
}, options.budget)
|
|
247
248
|
};
|
|
248
249
|
}
|
|
249
250
|
async function objectFromSandboxEntries(items, iterator, budget, context) {
|
|
@@ -253,7 +254,7 @@ async function objectFromSandboxEntries(items, iterator, budget, context) {
|
|
|
253
254
|
let value;
|
|
254
255
|
let failure;
|
|
255
256
|
const retained = {};
|
|
256
|
-
budget.setRetainedValues(retained, () => [items, object, entry, key, value, failure]);
|
|
257
|
+
budget.setRetainedValues(retained, () => [items, iterator.retainedValue, object, entry, key, value, failure]);
|
|
257
258
|
const checkData = createDataCheckpoint(budget, context);
|
|
258
259
|
const closeOnThrow = async (error) => {
|
|
259
260
|
failure = isCapturedException(error) ? error.reason : error;
|
|
@@ -315,6 +316,10 @@ function assignSandboxValues(target, sources, budget) {
|
|
|
315
316
|
if (target === null || target === undefined) {
|
|
316
317
|
throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
|
|
317
318
|
}
|
|
319
|
+
if (typeof target !== "object") {
|
|
320
|
+
target = createSandboxBox(target);
|
|
321
|
+
budget.chargeDataUsage(measureSandboxData([target]));
|
|
322
|
+
}
|
|
318
323
|
if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
|
|
319
324
|
throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
|
|
320
325
|
}
|
|
@@ -403,13 +408,13 @@ async function arrayFromSandboxValues(args, budget, context) {
|
|
|
403
408
|
const read = (property) => context?.getProperty !== undefined
|
|
404
409
|
? context.getProperty(items, property)
|
|
405
410
|
: getSandboxDataProperty(items, property, budget);
|
|
406
|
-
const iterator = getSandboxIterator(items, budget);
|
|
411
|
+
const iterator = getSandboxIterator(items, budget, context);
|
|
407
412
|
const constructor = context?.thisValue;
|
|
408
413
|
let result;
|
|
409
414
|
let currentValue;
|
|
410
415
|
let failure;
|
|
411
416
|
const retained = {};
|
|
412
|
-
budget.setRetainedValues(retained, () => [items, mapFn, constructor, result, currentValue, failure]);
|
|
417
|
+
budget.setRetainedValues(retained, () => [items, iterator?.retainedValue, mapFn, constructor, result, currentValue, failure]);
|
|
413
418
|
const checkData = createDataCheckpoint(budget, context);
|
|
414
419
|
const closeOnThrow = async (error) => {
|
|
415
420
|
failure = isCapturedException(error) ? error.reason : error;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assertSandboxDataDepth } from "../../graph-depth.js";
|
|
2
2
|
import { isSandboxDate } from "../date.js";
|
|
3
|
+
import { boxedValue, createSandboxBox, isSandboxBox } from "../boxed.js";
|
|
3
4
|
import { isSandboxErrorConstructorInstance } from "../exceptions.js";
|
|
4
5
|
import { isFloat32Array } from "../float32.js";
|
|
5
6
|
import { hasHostObjectMember, isGuestHostObject } from "../host-capabilities.js";
|
|
@@ -7,14 +8,18 @@ import { collectionIteratorState, isSandboxCollectionIterator } from "../collect
|
|
|
7
8
|
import { getSandboxPrototype, installObjectPrototype, isGuestClosure, markDescriptorObject, materializeFunctionProperties } from "../object-model.js";
|
|
8
9
|
import { sandboxString } from "../string-coercion.js";
|
|
9
10
|
import { createSandboxClosure, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "../values.js";
|
|
11
|
+
import { measureSandboxData } from "../values.js";
|
|
10
12
|
export function createObjectGlobal(methods, budget) {
|
|
11
13
|
const construct = ([value]) => {
|
|
12
14
|
if (value === null || value === undefined) {
|
|
13
15
|
budget.chargeDataUsage(1);
|
|
14
16
|
return Object.create(null);
|
|
15
17
|
}
|
|
16
|
-
if (typeof value !== "object")
|
|
17
|
-
|
|
18
|
+
if (typeof value !== "object") {
|
|
19
|
+
const box = createSandboxBox(value);
|
|
20
|
+
budget.chargeDataUsage(measureSandboxData([box]));
|
|
21
|
+
return box;
|
|
22
|
+
}
|
|
18
23
|
return value;
|
|
19
24
|
};
|
|
20
25
|
const constructor = createSandboxClosure({
|
|
@@ -44,9 +49,7 @@ export function createObjectGlobal(methods, budget) {
|
|
|
44
49
|
length: 0,
|
|
45
50
|
call: (_args, context) => {
|
|
46
51
|
const value = requireReceiver(context?.thisValue);
|
|
47
|
-
|
|
48
|
-
throw new TypeError("Object primitive boxing is not supported.");
|
|
49
|
-
return value;
|
|
52
|
+
return construct([value]);
|
|
50
53
|
}
|
|
51
54
|
}),
|
|
52
55
|
hasOwnProperty: createSandboxClosure({
|
|
@@ -117,6 +120,8 @@ export function hasOwnSandboxProperty(value, key, enumerable) {
|
|
|
117
120
|
return descriptor !== undefined && (!enumerable || descriptor.enumerable === true);
|
|
118
121
|
}
|
|
119
122
|
function typeTag(value) {
|
|
123
|
+
if (isSandboxBox(value))
|
|
124
|
+
value = boxedValue(value);
|
|
120
125
|
if (value === undefined)
|
|
121
126
|
return "Undefined";
|
|
122
127
|
if (value === null)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Budget } from "../budget.js";
|
|
2
|
+
import { type BoxedPrimitive } from "../boxed.js";
|
|
3
|
+
import { type SandboxCallContext, type SandboxClosure, type SandboxObject, type SandboxValue } from "../values.js";
|
|
4
|
+
export declare function createPrimitiveConstructor(options: {
|
|
5
|
+
name: "Number" | "String" | "Boolean";
|
|
6
|
+
call(args: readonly SandboxValue[], context?: SandboxCallContext): BoxedPrimitive | Promise<BoxedPrimitive>;
|
|
7
|
+
properties?: SandboxObject;
|
|
8
|
+
}, budget: Budget): SandboxClosure;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createSandboxBox, primitiveReceiver } from "../boxed.js";
|
|
2
|
+
import { installBoxedPrototype, materializeFunctionProperties } from "../object-model.js";
|
|
3
|
+
import { getNumberMember, numberMethodNames } from "../methods/number.js";
|
|
4
|
+
import { getStringMember, stringMethodNames } from "../methods/string.js";
|
|
5
|
+
import { createSandboxClosure, isSandboxClosure, measureSandboxData } from "../values.js";
|
|
6
|
+
export function createPrimitiveConstructor(options, budget) {
|
|
7
|
+
const initial = { Number: 0, String: "", Boolean: false }[options.name];
|
|
8
|
+
const kind = typeof initial;
|
|
9
|
+
const prototype = createSandboxBox(initial);
|
|
10
|
+
const allocate = (value) => {
|
|
11
|
+
const box = createSandboxBox(value);
|
|
12
|
+
budget.chargeDataUsage(measureSandboxData([box]));
|
|
13
|
+
return box;
|
|
14
|
+
};
|
|
15
|
+
const constructor = createSandboxClosure({
|
|
16
|
+
guest: true,
|
|
17
|
+
sandbox: true,
|
|
18
|
+
name: options.name,
|
|
19
|
+
length: 1,
|
|
20
|
+
call: options.call,
|
|
21
|
+
construct: (args, context) => {
|
|
22
|
+
const value = options.call(args, context);
|
|
23
|
+
return value instanceof Promise ? value.then(allocate) : allocate(value);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
const properties = materializeFunctionProperties(constructor);
|
|
27
|
+
Object.defineProperty(properties, "prototype", { value: prototype, writable: false });
|
|
28
|
+
Object.defineProperty(prototype, "constructor", {
|
|
29
|
+
value: constructor,
|
|
30
|
+
writable: true,
|
|
31
|
+
configurable: true
|
|
32
|
+
});
|
|
33
|
+
for (const [name, value] of Object.entries(options.properties ?? {}))
|
|
34
|
+
Object.defineProperty(properties, name, {
|
|
35
|
+
value,
|
|
36
|
+
writable: isSandboxClosure(value),
|
|
37
|
+
configurable: isSandboxClosure(value)
|
|
38
|
+
});
|
|
39
|
+
const methods = new Map([
|
|
40
|
+
[
|
|
41
|
+
"valueOf",
|
|
42
|
+
createSandboxClosure({
|
|
43
|
+
sandbox: true,
|
|
44
|
+
name: "valueOf",
|
|
45
|
+
length: 0,
|
|
46
|
+
call: (_args, context) => primitiveReceiver(context?.thisValue, kind)
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
]);
|
|
50
|
+
if (kind === "number") {
|
|
51
|
+
for (const name of numberMethodNames)
|
|
52
|
+
methods.set(name, getNumberMember(name, budget));
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
methods.set("toString", createSandboxClosure({
|
|
56
|
+
sandbox: true,
|
|
57
|
+
name: "toString",
|
|
58
|
+
length: 0,
|
|
59
|
+
call: (_args, context) => budget.allocateString(String(primitiveReceiver(context?.thisValue, kind)))
|
|
60
|
+
}));
|
|
61
|
+
if (kind === "string")
|
|
62
|
+
for (const name of stringMethodNames)
|
|
63
|
+
methods.set(name, getStringMember("", name, budget));
|
|
64
|
+
}
|
|
65
|
+
for (const [name, value] of methods)
|
|
66
|
+
Object.defineProperty(prototype, name, { value, writable: true, configurable: true });
|
|
67
|
+
installBoxedPrototype(budget, prototype, constructor);
|
|
68
|
+
return constructor;
|
|
69
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeClosureResult } from "./async.js";
|
|
2
2
|
import { copyNativeDate } from "./date.js";
|
|
3
|
+
import { boxedDataProperties, createSandboxBox, nativeBoxedValue } from "./boxed.js";
|
|
3
4
|
import { exportHostCapability, importHostCapability, isLiveCapability } from "./host-capabilities.js";
|
|
4
5
|
import { attachErrorSpan, replaceErrorStack } from "../error/shape.js";
|
|
5
6
|
import { SandboxError } from "./budget.js";
|
|
@@ -670,6 +671,27 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
670
671
|
: path
|
|
671
672
|
}, state);
|
|
672
673
|
}
|
|
674
|
+
const primitive = nativeBoxedValue(value);
|
|
675
|
+
if (primitive !== undefined) {
|
|
676
|
+
if (typeof primitive === "string")
|
|
677
|
+
budget.allocateString(primitive);
|
|
678
|
+
const original = value;
|
|
679
|
+
const existing = state.seen.get(original);
|
|
680
|
+
if (existing !== undefined)
|
|
681
|
+
return existing;
|
|
682
|
+
const copy = createSandboxBox(primitive);
|
|
683
|
+
state.seen.set(original, copy);
|
|
684
|
+
budget.chargeDataUsage(measureSandboxData([copy]));
|
|
685
|
+
for (const [key, descriptor] of boxedDataProperties(original)) {
|
|
686
|
+
if (!("value" in descriptor))
|
|
687
|
+
throw new TypeError(`Unsupported sandbox value at ${joinPath(path, key)}: accessor property`);
|
|
688
|
+
Object.defineProperty(copy, budget.allocateString(key), {
|
|
689
|
+
...descriptor,
|
|
690
|
+
value: copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key))
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
return copy;
|
|
694
|
+
}
|
|
673
695
|
const date = copyNativeDate(value);
|
|
674
696
|
if (date !== undefined) {
|
|
675
697
|
const existing = state.seen.get(value);
|