poe-code 14.0.81 → 14.0.82

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.
Files changed (29) hide show
  1. package/dist/index.js +360 -167
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-2LNBLFJ3.js → chunk-7LGBDF56.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-ZSYBRZU6.js → chunk-V6LQP64H.js} +308 -134
  7. package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/interp/error-prototypes.d.ts +3 -0
  12. package/packages/safe-js/dist/interp/error-prototypes.js +1 -0
  13. package/packages/safe-js/dist/interp/exceptions.d.ts +1 -0
  14. package/packages/safe-js/dist/interp/exceptions.js +39 -15
  15. package/packages/safe-js/dist/interp/globals/error.d.ts +2 -0
  16. package/packages/safe-js/dist/interp/globals/error.js +104 -4
  17. package/packages/safe-js/dist/interp/globals.d.ts +1 -0
  18. package/packages/safe-js/dist/interp/globals.js +4 -2
  19. package/packages/safe-js/dist/interp/host-bridge.js +4 -2
  20. package/packages/safe-js/dist/interp/instanceof.js +3 -2
  21. package/packages/safe-js/dist/interp/object-model.js +11 -0
  22. package/packages/safe-js/dist/interp/values.js +47 -2
  23. package/packages/safe-js/dist/snapshot/guest-heap-validation.js +4 -1
  24. package/packages/safe-js/dist/snapshot/guest-heap.d.ts +2 -0
  25. package/packages/safe-js/dist/snapshot/guest-heap.js +6 -2
  26. package/packages/safe-js/dist/snapshot/restore.js +17 -2
  27. package/packages/safe-js/dist/snapshot/validation.js +1 -1
  28. package/packages/safe-js/dist/chunks/chunk-ZSYBRZU6.js.map +0 -7
  29. /package/packages/safe-js/dist/chunks/{chunk-2LNBLFJ3.js.map → chunk-7LGBDF56.js.map} +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  resolveFsConfig,
23
23
  splitFrontmatter,
24
24
  withBrokenPipeGuard
25
- } from "./chunks/chunk-2LNBLFJ3.js";
25
+ } from "./chunks/chunk-7LGBDF56.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-ZSYBRZU6.js";
37
+ } from "./chunks/chunk-V6LQP64H.js";
38
38
  import "./chunks/chunk-M2DLCGEF.js";
39
39
  import "./chunks/chunk-Q7USUEL7.js";
40
40
  import "./chunks/chunk-4YIDX44G.js";
@@ -5,7 +5,7 @@ import {
5
5
  defineExtension,
6
6
  lint,
7
7
  run
8
- } from "./chunks/chunk-ZSYBRZU6.js";
8
+ } from "./chunks/chunk-V6LQP64H.js";
9
9
  import "./chunks/chunk-4YIDX44G.js";
10
10
  export {
11
11
  Budget,
@@ -26,7 +26,7 @@ import {
26
26
  runWithSpawnUsageAccumulator,
27
27
  splitFrontmatter,
28
28
  supportsSpawnMode
29
- } from "./chunks/chunk-2LNBLFJ3.js";
29
+ } from "./chunks/chunk-7LGBDF56.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-ZSYBRZU6.js";
53
+ } from "./chunks/chunk-V6LQP64H.js";
54
54
  import "./chunks/chunk-M2DLCGEF.js";
55
55
  import "./chunks/chunk-Q7USUEL7.js";
56
56
  import "./chunks/chunk-4YIDX44G.js";
@@ -0,0 +1,3 @@
1
+ import type { Budget } from "./budget.js";
2
+ import type { SandboxObject } from "./values.js";
3
+ export declare const errorPrototypes: WeakMap<Budget, Map<"Error" | "TypeError" | "RangeError" | "ReferenceError" | "SyntaxError" | "URIError" | "EvalError" | "AbortError" | "AggregateError" | "HarnessFailure", SandboxObject>>;
@@ -0,0 +1 @@
1
+ export const errorPrototypes = new WeakMap();
@@ -55,5 +55,6 @@ export declare function createSubsetErrorValue(name: string, message: SandboxVal
55
55
  cause?: unknown;
56
56
  chargeBudget?: boolean;
57
57
  span?: ErrorSourceSpan;
58
+ transport?: boolean;
58
59
  }): SandboxObject;
59
60
  export declare function isSandboxErrorConstructorInstance(value: SandboxValue, name: SandboxErrorName): boolean;
@@ -5,7 +5,8 @@ import { withFatalPromiseCleanup } from "./promise-tracker.js";
5
5
  import { deepCopyToSandbox, ownEnumerableSandboxKeys } from "./values.js";
6
6
  import { hasOwnSandboxProperty } from "./globals/object.js";
7
7
  import { retainValues } from "./resources.js";
8
- import { getSandboxDataProperty } from "./object-model.js";
8
+ import { getSandboxDataProperty, setSandboxPrototype } from "./object-model.js";
9
+ import { errorPrototypes } from "./error-prototypes.js";
9
10
  import { toPropertyKey } from "./property-key.js";
10
11
  import { internalSymbols } from "./internal-symbols.js";
11
12
  import { containsResumeTarget } from "./resume-target.js";
@@ -162,8 +163,7 @@ export function surfaceThrownValue(reason, budget, stackFrames = [], span) {
162
163
  throw reason;
163
164
  }
164
165
  if (isSubsetErrorValue(reason)) {
165
- normalizeSurfacedSubsetError(reason, budget, stackFrames, span);
166
- return reason;
166
+ return normalizeSurfacedSubsetError(reason, budget, stackFrames, span);
167
167
  }
168
168
  if (reason instanceof Error) {
169
169
  const error = createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
@@ -171,8 +171,7 @@ export function surfaceThrownValue(reason, budget, stackFrames = [], span) {
171
171
  chargeBudget: false,
172
172
  span
173
173
  });
174
- normalizeSurfacedSubsetError(error, budget, stackFrames, span);
175
- return error;
174
+ return normalizeSurfacedSubsetError(error, budget, stackFrames, span);
176
175
  }
177
176
  if (isErrorLikeValue(reason)) {
178
177
  const error = createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
@@ -180,13 +179,13 @@ export function surfaceThrownValue(reason, budget, stackFrames = [], span) {
180
179
  chargeBudget: false,
181
180
  span
182
181
  });
183
- normalizeSurfacedSubsetError(error, budget, stackFrames, span);
184
- return error;
182
+ return normalizeSurfacedSubsetError(error, budget, stackFrames, span);
185
183
  }
186
- return createSubsetErrorValue("Error", describeThrownValue(reason), stackFrames, budget, {
184
+ const error = createSubsetErrorValue("Error", describeThrownValue(reason), stackFrames, budget, {
187
185
  chargeBudget: false,
188
186
  span
189
187
  });
188
+ return normalizeSurfacedSubsetError(error, budget, stackFrames, span);
190
189
  }
191
190
  export function createSubsetErrorValue(name, message, stackFrames, budget, options = {}) {
192
191
  const resumeChecks = options.chargeBudget === false ? budget.suspendChecks() : undefined;
@@ -195,11 +194,16 @@ export function createSubsetErrorValue(name, message, stackFrames, budget, optio
195
194
  const errorMessage = budget.allocateString(coerceErrorMessage(message));
196
195
  const header = errorMessage === "" ? errorName : `${errorName}: ${errorMessage}`;
197
196
  const stack = budget.allocateString([header, ...[...stackFrames].reverse()].join("\n"));
198
- const error = {
199
- name: errorName,
200
- message: errorMessage,
201
- stack
202
- };
197
+ const prototype = options.transport ? undefined : errorPrototypes.get(budget)?.get(toSandboxErrorName(errorName));
198
+ const error = prototype === undefined ? { name: errorName, message: errorMessage, stack } : {};
199
+ if (prototype !== undefined) {
200
+ if (message !== undefined)
201
+ Object.defineProperty(error, "message", { value: errorMessage, writable: true, configurable: true });
202
+ if (!errorPrototypes.get(budget).has(errorName))
203
+ Object.defineProperty(error, "name", { value: errorName, writable: true, configurable: true });
204
+ Object.defineProperty(error, "stack", { value: stack, writable: true, configurable: true });
205
+ setSandboxPrototype(error, prototype, budget);
206
+ }
203
207
  sandboxErrorTypes.set(error, toSandboxErrorName(errorName));
204
208
  attachErrorSpan(error, options.span);
205
209
  attachWrappedErrorCause(error, options.cause);
@@ -224,6 +228,8 @@ function isSubsetErrorValue(value) {
224
228
  if (typeof value !== "object" || value === null) {
225
229
  return false;
226
230
  }
231
+ if (sandboxErrorTypes.has(value))
232
+ return true;
227
233
  const prototype = Object.getPrototypeOf(value);
228
234
  return ((prototype === Object.prototype || prototype === null) &&
229
235
  typeof value.name === "string" &&
@@ -236,20 +242,38 @@ function normalizeSurfacedSubsetError(error, budget, stackFrames, span) {
236
242
  const name = budget.allocateString(toSandboxErrorName(readErrorName(error)));
237
243
  const message = budget.allocateString(readSurfacedErrorMessage(error, name));
238
244
  const frames = readSandboxStackFrames(error.stack);
245
+ if (!Object.isExtensible(error) || ["name", "message", "stack"].some(key => {
246
+ const descriptor = Object.getOwnPropertyDescriptor(error, key);
247
+ return descriptor !== undefined && (!("value" in descriptor) || !descriptor.writable);
248
+ })) {
249
+ // Public diagnostics must not mutate frozen guest state or invoke setters.
250
+ const original = error;
251
+ const descriptors = Object.getOwnPropertyDescriptors(original);
252
+ delete descriptors.name;
253
+ delete descriptors.message;
254
+ delete descriptors.stack;
255
+ error = Object.defineProperties({}, descriptors);
256
+ const errorType = sandboxErrorTypes.get(original);
257
+ if (errorType !== undefined)
258
+ sandboxErrorTypes.set(error, errorType);
259
+ }
239
260
  error.name = name;
240
261
  error.message = message;
241
262
  error.stack = budget.allocateString(formatErrorStack(name, message, frames.length > 0 ? frames : [...stackFrames].reverse()));
242
263
  attachErrorSpan(error, readErrorSpan(error) ?? span);
264
+ return error;
243
265
  }
244
266
  finally {
245
267
  resumeChecks();
246
268
  }
247
269
  }
248
270
  function readErrorName(error) {
249
- return typeof error.name === "string" && error.name.length > 0 ? error.name : "Error";
271
+ const name = getSandboxDataProperty(error, "name");
272
+ return typeof name === "string" && name.length > 0 ? name : sandboxErrorTypes.get(error) ?? "Error";
250
273
  }
251
274
  function readSurfacedErrorMessage(error, name) {
252
- const message = typeof error.message === "string" ? error.message : "";
275
+ const value = getSandboxDataProperty(error, "message");
276
+ const message = typeof value === "string" ? value : "";
253
277
  if (message === "") {
254
278
  return `${name} thrown`;
255
279
  }
@@ -5,7 +5,9 @@ export type ErrorName = (typeof errorNames)[number];
5
5
  export type ErrorGlobals = Record<ErrorName, ReturnType<typeof createSandboxClosure>>;
6
6
  export declare function createErrorGlobals(options: {
7
7
  budget: Budget;
8
+ errorPrototypes?: boolean;
8
9
  }): ErrorGlobals;
9
10
  export declare function isSandboxErrorConstructorInstance(value: SandboxValue, constructor: SandboxValue): boolean;
10
11
  export declare function isSandboxErrorConstructor(value: SandboxValue): value is SandboxClosure;
12
+ export declare function createErrorPrototypes(budget: Budget, constructors: ErrorGlobals): void;
11
13
  export {};
@@ -1,3 +1,10 @@
1
+ import { errorPrototypes } from "../error-prototypes.js";
2
+ import { getSandboxPropertyDescriptor, getSandboxPrototype, materializeFunctionProperties, registerIntrinsicFunction, registerIntrinsicObject, setSandboxPrototype } from "../object-model.js";
3
+ import { registerBuiltinIdentities } from "../intrinsics.js";
4
+ import { sandboxString } from "../string-coercion.js";
5
+ import { retainValues } from "../resources.js";
6
+ import { readPropertyDescriptor } from "../accessors.js";
7
+ import { acquireSandboxIterator, getSandboxIterator, readIteratorResult } from "../iteration.js";
1
8
  import { createSubsetErrorValue, isSandboxErrorConstructorInstance as isNamedSandboxErrorConstructorInstance } from "../exceptions.js";
2
9
  import { createSandboxClosure, isSandboxClosure } from "../values.js";
3
10
  const errorConstructorNames = new WeakMap();
@@ -12,7 +19,7 @@ const errorNames = [
12
19
  "AggregateError"
13
20
  ];
14
21
  export function createErrorGlobals(options) {
15
- return Object.fromEntries(errorNames.map((name) => [name, createErrorConstructor(name, options.budget)]));
22
+ return Object.fromEntries(errorNames.map((name) => [name, createErrorConstructor(name, options.budget, options.errorPrototypes === true)]));
16
23
  }
17
24
  export function isSandboxErrorConstructorInstance(value, constructor) {
18
25
  if (!isSandboxClosure(constructor)) {
@@ -27,12 +34,105 @@ export function isSandboxErrorConstructorInstance(value, constructor) {
27
34
  export function isSandboxErrorConstructor(value) {
28
35
  return isSandboxClosure(value) && errorConstructorNames.has(value);
29
36
  }
30
- function createErrorConstructor(name, budget) {
31
- const call = (args, context) => createSubsetError(name, args, context?.stack ?? [], budget);
32
- const closure = createSandboxClosure({ sandbox: true, call, construct: call, name });
37
+ function createErrorConstructor(name, budget, guest) {
38
+ const call = (args, context) => errorPrototypes.has(budget) ? createNativeError(name, args, budget, context, closure)
39
+ : createSubsetError(name, args, context?.stack ?? [], budget);
40
+ const closure = createSandboxClosure({ guest, sandbox: true, call, construct: call, name, length: name === "AggregateError" ? 2 : 1 });
33
41
  errorConstructorNames.set(closure, name);
34
42
  return closure;
35
43
  }
44
+ export function createErrorPrototypes(budget, constructors) {
45
+ const prototypes = new Map();
46
+ for (const name of errorNames)
47
+ prototypes.set(name, Object.create(null));
48
+ errorPrototypes.set(budget, prototypes);
49
+ for (const name of errorNames) {
50
+ const constructor = constructors[name];
51
+ const prototype = prototypes.get(name);
52
+ Object.defineProperties(prototype, {
53
+ name: { value: name, writable: true, configurable: true },
54
+ message: { value: "", writable: true, configurable: true },
55
+ constructor: { value: constructor, writable: true, configurable: true }
56
+ });
57
+ Object.defineProperty(materializeFunctionProperties(constructor), "prototype", { value: prototype, writable: false });
58
+ setSandboxPrototype(prototype, name === "Error" ? getSandboxPrototype(Object.create(null), budget) : prototypes.get("Error"));
59
+ if (name !== "Error")
60
+ setSandboxPrototype(constructor, constructors.Error);
61
+ }
62
+ Object.defineProperty(prototypes.get("Error"), "toString", {
63
+ writable: true, configurable: true,
64
+ value: createSandboxClosure({ guest: true, sandbox: true, name: "toString", length: 0,
65
+ call: async (_args, context) => {
66
+ const receiver = context?.thisValue;
67
+ if (receiver === null || typeof receiver !== "object")
68
+ throw new TypeError("Error.prototype.toString requires an object.");
69
+ let name;
70
+ const release = retainValues(budget, () => [receiver, name]);
71
+ try {
72
+ const rawName = await readErrorProperty(receiver, "name", budget, context);
73
+ name = rawName === undefined ? "Error" : await sandboxString(rawName, budget, context);
74
+ const rawMessage = await readErrorProperty(receiver, "message", budget, context);
75
+ const message = rawMessage === undefined ? "" : await sandboxString(rawMessage, budget, context);
76
+ return budget.allocateString(name === "" ? message : message === "" ? name : `${name}: ${message}`);
77
+ }
78
+ finally {
79
+ release();
80
+ }
81
+ }
82
+ })
83
+ });
84
+ registerBuiltinIdentities(budget, Object.fromEntries(errorNames.map(name => [name, constructors[name]])));
85
+ for (const name of errorNames) {
86
+ registerIntrinsicFunction(budget, constructors[name]);
87
+ registerIntrinsicObject(budget, prototypes.get(name));
88
+ }
89
+ }
90
+ async function readErrorProperty(value, key, budget, context) {
91
+ if (context?.getProperty !== undefined)
92
+ return context.getProperty(value, key);
93
+ const descriptor = getSandboxPropertyDescriptor(value, key, budget);
94
+ return descriptor === undefined ? undefined : readPropertyDescriptor(descriptor, value, context);
95
+ }
96
+ async function createNativeError(name, args, budget, context, constructor) {
97
+ const newTarget = context?.newTarget ?? constructor;
98
+ const candidate = await readErrorProperty(newTarget, "prototype", budget, context);
99
+ const prototype = candidate !== null && typeof candidate === "object" ? candidate : errorPrototypes.get(budget).get(name);
100
+ let error;
101
+ let iterator;
102
+ const errors = [];
103
+ const release = retainValues(budget, () => [prototype, error, iterator?.retainedValue, ...errors, ...args]);
104
+ try {
105
+ const message = name === "AggregateError" ? args[1] : args[0];
106
+ const options = name === "AggregateError" ? args[2] : args[1];
107
+ const text = message === undefined ? undefined : await sandboxString(message, budget, context);
108
+ error = createSubsetErrorValue(name, text, context?.stack ?? [], budget);
109
+ setSandboxPrototype(error, prototype, budget);
110
+ if (options !== null && typeof options === "object" && getSandboxPropertyDescriptor(options, "cause", budget) !== undefined) {
111
+ const cause = await readErrorProperty(options, "cause", budget, context);
112
+ Object.defineProperty(error, "cause", { value: cause, writable: true, configurable: true });
113
+ }
114
+ if (name === "AggregateError") {
115
+ iterator = context === undefined ? getSandboxIterator(args[0], budget) : await acquireSandboxIterator(args[0], budget, context);
116
+ if (iterator === undefined)
117
+ throw new TypeError("AggregateError errors must be iterable.");
118
+ while (true) {
119
+ budget.visitNode();
120
+ const result = await iterator.next();
121
+ if (result === null || typeof result !== "object")
122
+ throw new TypeError("Iterator result must be an object.");
123
+ if ((await readIteratorResult(iterator, result, "done")).value)
124
+ break;
125
+ budget.allocateArrayLength(errors.length + 1);
126
+ errors.push((await readIteratorResult(iterator, result, "value")).value);
127
+ }
128
+ Object.defineProperty(error, "errors", { value: errors, writable: true, configurable: true });
129
+ }
130
+ return error;
131
+ }
132
+ finally {
133
+ release();
134
+ }
135
+ }
36
136
  function createSubsetError(name, args, stackFrames, budget) {
37
137
  const message = name === "AggregateError" ? args[1] : args[0];
38
138
  const options = name === "AggregateError" ? args[2] : args[1];
@@ -4,6 +4,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
4
4
  random?: () => number;
5
5
  clock?: RunClock;
6
6
  functionHasInstance?: boolean;
7
+ errorPrototypes?: boolean;
7
8
  }): {
8
9
  RegExp: import("./values.js").SandboxClosure;
9
10
  Promise: import("./values.js").SandboxClosure;
@@ -1,7 +1,7 @@
1
1
  import { createConsoleJsonGlobals } from "./globals/console-json.js";
2
2
  import { createCollectionGlobals } from "./globals/collections.js";
3
3
  import { createFloat32ArrayGlobal } from "./globals/float32array.js";
4
- import { createErrorGlobals } from "./globals/error.js";
4
+ import { createErrorGlobals, createErrorPrototypes } from "./globals/error.js";
5
5
  import { createMathGlobals } from "./globals/math.js";
6
6
  import { createRegexGlobals } from "./globals/regex.js";
7
7
  import { createMiscGlobals } from "./globals/misc.js";
@@ -22,7 +22,7 @@ export function createBuiltinBindings(options) {
22
22
  Date: createDateGlobal(options),
23
23
  Symbol: createSymbolGlobal(options.budget),
24
24
  BigInt: createBigIntGlobal(options.budget),
25
- ...createErrorGlobals(options),
25
+ ...createErrorGlobals({ ...options, errorPrototypes: options.errorPrototypes !== false }),
26
26
  ...createMathGlobals({ random: options.random, budget: options.budget }),
27
27
  ...createObjectArrayGlobals(options),
28
28
  ...createMiscGlobals(options),
@@ -31,6 +31,8 @@ export function createBuiltinBindings(options) {
31
31
  ...createRegexGlobals(options)
32
32
  };
33
33
  createFunctionPrototype(options.budget, options.functionHasInstance);
34
+ if (options.errorPrototypes !== false)
35
+ createErrorPrototypes(options.budget, bindings);
34
36
  createGeneratorPrototypes(options.budget);
35
37
  registerBuiltinIdentities(options.budget, bindings);
36
38
  return bindings;
@@ -408,10 +408,12 @@ function createHostErrorValue(reason, stackFrames, budget, span, state = { seen:
408
408
  const error = reason instanceof Error
409
409
  ? createSubsetErrorValue(reason.name, reason.message, stackFrames, budget, {
410
410
  cause: reason,
411
- chargeBudget
411
+ chargeBudget,
412
+ transport: true
412
413
  })
413
414
  : createSubsetErrorValue("Error", describeThrownReason(reason), stackFrames, budget, {
414
- chargeBudget: false
415
+ chargeBudget: false,
416
+ transport: true
415
417
  });
416
418
  if (reason instanceof Error) {
417
419
  state.seen.set(reason, error);
@@ -4,7 +4,7 @@ import { invokeBuiltinClosure } from "./builtin-call.js";
4
4
  import { isFloat32Array } from "./float32.js";
5
5
  import { isFloat32ArrayConstructor } from "./globals/float32array.js";
6
6
  import { isSandboxErrorConstructorInstance } from "./globals/error.js";
7
- import { getSandboxPropertyDescriptor, getSandboxPrototype, isGuestClosure } from "./object-model.js";
7
+ import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure } from "./object-model.js";
8
8
  import { isSandboxClosure } from "./values.js";
9
9
  export async function evaluateInstanceof(value, constructor, budget, context) {
10
10
  if (constructor === null || typeof constructor !== "object")
@@ -29,7 +29,8 @@ export async function ordinaryHasInstance(value, constructor, budget, context) {
29
29
  // These existing built-ins do not yet have ordinary prototype graphs.
30
30
  if (isFloat32ArrayConstructor(constructor))
31
31
  return isFloat32Array(value);
32
- if (isSandboxErrorConstructorInstance(value, constructor))
32
+ if ((!isGuestClosure(constructor) || (value !== null && typeof value === "object" && !hasExplicitSandboxPrototype(value))) &&
33
+ isSandboxErrorConstructorInstance(value, constructor))
33
34
  return true;
34
35
  if (!isGuestClosure(constructor) || typeof value !== "object" || value === null)
35
36
  return false;
@@ -7,6 +7,8 @@ import { releaseTemplateObjects } from "./template-objects.js";
7
7
  import { isSandboxDate } from "./date.js";
8
8
  import { retainedAccessorClosures } from "./accessors.js";
9
9
  import { getHostObjectMember, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
10
+ import { errorPrototypes } from "./error-prototypes.js";
11
+ import { sandboxErrorTypes } from "../error/shape.js";
10
12
  import { boxedValue, isSandboxBox } from "./boxed.js";
11
13
  import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, getPromiseProperties, isSandboxRegex, getRegexProperties, getCollectionProperties, isSandboxSet } from "./values.js";
12
14
  const guestClosures = new WeakSet();
@@ -273,12 +275,21 @@ export function releaseObjectPrototype(budget) {
273
275
  arrayPrototypes.delete(budget);
274
276
  functionPrototypes.delete(budget);
275
277
  generatorPrototypes.delete(budget);
278
+ errorPrototypes.delete(budget);
276
279
  initialRegexDescriptors.delete(budget);
277
280
  intrinsicPrototypes.delete(budget);
278
281
  }
279
282
  export function getSandboxPrototype(value, budget) {
280
283
  if (prototypes.has(value))
281
284
  return prototypes.get(value) ?? null;
285
+ // Host transport records are data-only. Resolve their default prototype in
286
+ // the receiving realm without persisting executable intrinsic graphs.
287
+ const errorType = sandboxErrorTypes.get(value);
288
+ if (budget !== undefined && errorType !== undefined) {
289
+ const prototype = errorPrototypes.get(budget)?.get(errorType);
290
+ if (prototype !== undefined)
291
+ return prototype;
292
+ }
282
293
  if (budget !== undefined && isGuestClosure(value) && runResources.getStore()?.functionSourceText !== false)
283
294
  return functionPrototypes.get(budget) ?? null;
284
295
  if (budget !== undefined && Array.isArray(value))
@@ -1,5 +1,6 @@
1
1
  import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
2
2
  import { internalSymbols } from "./internal-symbols.js";
3
+ import { getIntrinsicIdentity } from "./intrinsics.js";
3
4
  import { getGeneratorProperties } from "./generator-properties.js";
4
5
  import { getRegexProperties, regexGuestProperties } from "./regexp-properties.js";
5
6
  import { getCollectionProperties, collectionGuestProperties, copyCollectionProperties } from "./collection-properties.js";
@@ -24,7 +25,7 @@ import { invokeCancelableClosure, readPromiseCancellation, registerPromiseCancel
24
25
  import { parseRegex } from "./regex/parse.js";
25
26
  import { assertSandboxDataDepth } from "../graph-depth.js";
26
27
  import { sandboxErrorTypes } from "../error/shape.js";
27
- import { getGuestFunctionProperties, getSandboxPrototype, hasGuestObjectState, hasManagedDescriptors, hasNullObjectPrototype, isGuestClosure, isIntrinsicFunction, registerGuestClosure, setSandboxPrototype } from "./object-model.js";
28
+ import { getGuestFunctionProperties, getSandboxPrototype, hasExplicitSandboxPrototype, hasGuestObjectState, hasManagedDescriptors, hasNullObjectPrototype, isGuestClosure, isIntrinsicFunction, registerGuestClosure, setSandboxPrototype } from "./object-model.js";
28
29
  import { copySandboxArgumentProperties, createSandboxArguments, getSandboxArgumentEntries, isSandboxArguments } from "./arguments.js";
29
30
  export { createSandboxArguments, isSandboxArguments } from "./arguments.js";
30
31
  export { isSandboxMap, isSandboxSet } from "./collection-brands.js";
@@ -578,7 +579,7 @@ export function measureSandboxData(values, options = {}) {
578
579
  if (descriptor !== undefined)
579
580
  descriptors.push([key, descriptor]);
580
581
  }
581
- const includeNonEnumerable = isSandboxDate(value) || hasManagedDescriptors(value);
582
+ const includeNonEnumerable = isSandboxDate(value) || sandboxErrorTypes.has(value) || hasManagedDescriptors(value);
582
583
  for (const [key, descriptor] of descriptors) {
583
584
  if (!descriptor.enumerable && !includeNonEnumerable)
584
585
  continue;
@@ -908,6 +909,50 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
908
909
  }
909
910
  if (nodeTypes.isProxy(value))
910
911
  throw new TypeError("Unsupported proxy sandbox value.");
912
+ if (sandboxErrorTypes.has(value) && hasExplicitSandboxPrototype(value)) {
913
+ const prototype = getSandboxPrototype(value);
914
+ let nativePrototype = null;
915
+ if (prototype !== null) {
916
+ const identity = getIntrinsicIdentity(prototype);
917
+ const nativePrototypes = {
918
+ Error: Error.prototype, TypeError: TypeError.prototype, RangeError: RangeError.prototype,
919
+ ReferenceError: ReferenceError.prototype, SyntaxError: SyntaxError.prototype,
920
+ URIError: URIError.prototype, EvalError: EvalError.prototype, AggregateError: AggregateError.prototype
921
+ };
922
+ const path = identity === undefined ? [] : JSON.parse(identity);
923
+ if (path.length !== 2 || typeof path[0] !== "string" || path[1] !== "prototype" || !Object.hasOwn(nativePrototypes, path[0]))
924
+ throw new TypeError("Custom Error prototype links cannot be copied as data.");
925
+ nativePrototype = nativePrototypes[path[0]];
926
+ let current = prototype;
927
+ let prototypeDepth = 0;
928
+ while (current !== null) {
929
+ assertSandboxDataDepth(++prototypeDepth);
930
+ const objectPrototype = getIntrinsicIdentity(current) === '["Object","prototype"]';
931
+ const owner = objectPrototype ? Object.getOwnPropertyDescriptor(current, "constructor")?.value : current;
932
+ if (owner === null || typeof owner !== "object" ||
933
+ (objectPrototype && getIntrinsicIdentity(owner) !== '["Object"]') || hasGuestObjectState(owner))
934
+ throw new TypeError("Modified Error prototype links cannot be copied as data.");
935
+ current = getSandboxPrototype(current);
936
+ }
937
+ }
938
+ const existing = state.seen.get(value);
939
+ if (existing !== undefined)
940
+ return existing;
941
+ const descriptors = Reflect.ownKeys(value).filter(key => typeof key !== "symbol" || !internalSymbols.has(key))
942
+ .map(key => [key, Object.getOwnPropertyDescriptor(value, key)]);
943
+ if (descriptors.some(([, descriptor]) => !("value" in descriptor)))
944
+ throw new TypeError("Error accessor properties cannot be copied as data.");
945
+ const copy = new Error();
946
+ delete copy.stack;
947
+ Object.setPrototypeOf(copy, nativePrototype);
948
+ state.seen.set(value, copy);
949
+ for (const [key, descriptor] of descriptors)
950
+ Object.defineProperty(copy, key, { ...descriptor,
951
+ value: copyFromSandbox(descriptor.value, state, joinPath(path, key), options, depth + 1) });
952
+ if (!Object.isExtensible(value))
953
+ Object.preventExtensions(copy);
954
+ return copy;
955
+ }
911
956
  if (!isSandboxClosure(value) && hasGuestObjectState(value)) {
912
957
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
913
958
  }
@@ -1,4 +1,5 @@
1
1
  import { Budget } from "../interp/budget.js";
2
+ import { sandboxErrorNames } from "../error/shape.js";
2
3
  import { createRawJson } from "../interp/raw-json.js";
3
4
  import { createBuiltinBindings } from "../interp/globals.js";
4
5
  import { getIntrinsicIdentity, listIntrinsicIdentities, resolveIntrinsicIdentity } from "../interp/intrinsics.js";
@@ -146,7 +147,9 @@ export function validateGuestHeapNode(raw, heap, maxArrayLength = 0xffffffff) {
146
147
  state(node.state);
147
148
  }
148
149
  else if (node.kind === "guest-object" || node.kind === "guest-array") {
149
- fields(node, ["kind", "state"], node.kind === "guest-array" ? ["templateNodeId", "templateOwner"] : []);
150
+ fields(node, ["kind", "state"], node.kind === "guest-array" ? ["templateNodeId", "templateOwner"] : ["errorType"]);
151
+ if (Object.hasOwn(node, "errorType") && !sandboxErrorNames.includes(node.errorType))
152
+ throw new TypeError("Invalid guest error type.");
150
153
  if (Object.hasOwn(node, "templateOwner"))
151
154
  reference(node.templateOwner, ["guest-array"]);
152
155
  if (Object.hasOwn(node, "templateNodeId") && integer(node.templateNodeId) < 1)
@@ -1,3 +1,4 @@
1
+ import { type SandboxErrorName } from "../error/shape.js";
1
2
  import { type ScopeFrame } from "../interp/scope.js";
2
3
  import { type PropertyDescriptorData } from "./property-descriptors.js";
3
4
  import type { CompletionResult } from "../interp/exceptions.js";
@@ -73,6 +74,7 @@ export type GuestHeapNode<T> = {
73
74
  } | {
74
75
  kind: "guest-object";
75
76
  state: GuestObjectState<T>;
77
+ errorType?: SandboxErrorName;
76
78
  } | {
77
79
  kind: "guest-array";
78
80
  state: GuestObjectState<T>;
@@ -1,5 +1,6 @@
1
1
  import { getClosureOrigin, getGeneratorOrigin } from "../interp/closure-origin.js";
2
2
  import { boundFunctionStates } from "../interp/bound-function-state.js";
3
+ import { sandboxErrorTypes } from "../error/shape.js";
3
4
  import { getGeneratorProperties } from "../interp/generator-properties.js";
4
5
  import { getIntrinsicIdentity } from "../interp/intrinsics.js";
5
6
  import { getSandboxPrototype, hasExplicitSandboxPrototype, hasGuestObjectState, isGuestClosure, materializeFunctionProperties } from "../interp/object-model.js";
@@ -151,8 +152,11 @@ export function captureGuestHeapNode(value, encode) {
151
152
  isSandboxRegExpIterator(value))
152
153
  return undefined;
153
154
  const prototype = Object.getPrototypeOf(value);
154
- if ((prototype === null || prototype === Object.prototype) && hasGuestObjectState(value))
155
- return { kind: "guest-object", state: captureObjectState(value, encode) };
155
+ if ((prototype === null || prototype === Object.prototype) && hasGuestObjectState(value)) {
156
+ const errorType = sandboxErrorTypes.get(value);
157
+ return { kind: "guest-object", state: captureObjectState(value, encode),
158
+ ...(errorType === undefined ? {} : { errorType }) };
159
+ }
156
160
  return undefined;
157
161
  }
158
162
  if (origin.node.nodeId === undefined)
@@ -22,7 +22,7 @@ import { restoreDateTime } from "../interp/date.js";
22
22
  import { createRawJson } from "../interp/raw-json.js";
23
23
  import { createSandboxBox } from "../interp/boxed.js";
24
24
  import { restoreBoxedProperties } from "./boxed.js";
25
- import { sandboxErrorTypes } from "../error/shape.js";
25
+ import { sandboxErrorNames, sandboxErrorTypes } from "../error/shape.js";
26
26
  import { SnapshotMismatchError } from "../restore.js";
27
27
  import { evaluateNode, Scope, setSandboxProperty } from "../interp/interpreter.js";
28
28
  import { getGuestFunctionProperties, getGuestFunctionProperty, getSandboxDataProperty, isGuestClosure, materializeFunctionProperties, registerGuestClosure, setSandboxPrototype } from "../interp/object-model.js";
@@ -398,7 +398,20 @@ function initializeIntrinsicRealm(state) {
398
398
  const method = state.heap[String(value.id)];
399
399
  return method?.kind === "intrinsic" && method.id === '["%FunctionPrototype%",{"symbol":"hasInstance"}]';
400
400
  });
401
- createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance });
401
+ const errorConstructors = Object.values(state.heap).filter(node => node.kind === "intrinsic" && sandboxErrorNames.some(name => node.id === JSON.stringify([name])));
402
+ const errorPrototypes = errorConstructors.every(node => node.kind === "intrinsic" &&
403
+ node.state?.properties.properties.some(([key, descriptor]) => {
404
+ if (key !== "prototype" || descriptor.kind !== "data" || descriptor.writable ||
405
+ descriptor.enumerable || descriptor.configurable)
406
+ return false;
407
+ const value = descriptor.value;
408
+ if (value === null || typeof value !== "object" || !("kind" in value) || value.kind !== "ref")
409
+ return false;
410
+ const prototype = state.heap[String(value.id)];
411
+ return prototype?.kind === "intrinsic" &&
412
+ prototype.id === JSON.stringify([...JSON.parse(node.id), "prototype"]);
413
+ }));
414
+ createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes });
402
415
  state.intrinsicsInitialized = true;
403
416
  }
404
417
  function restoreHeapValue(id, state) {
@@ -653,6 +666,8 @@ function restoreHeapValue(id, state) {
653
666
  throw new TypeError(`Missing restored function properties for ${serialized.kind === "intrinsic" ? serialized.id : serialized.kind}.`);
654
667
  if (objectState.prototype !== undefined)
655
668
  setSandboxPrototype(value, deserializeValue(objectState.prototype, state), state.budget);
669
+ if (serialized.kind === "guest-object" && serialized.errorType !== undefined)
670
+ sandboxErrorTypes.set(value, serialized.errorType);
656
671
  restorePropertyDescriptors(target, objectState.properties, entry => deserializeValue(entry, state));
657
672
  if (serialized.kind === "guest-array" && serialized.templateNodeId !== undefined) {
658
673
  const node = state.nodeById.get(serialized.templateNodeId);
@@ -706,7 +706,7 @@ function validateArrayHeap(record, path, state) {
706
706
  function validateErrorType(record, path) {
707
707
  if (!Object.hasOwn(record, "errorType"))
708
708
  return;
709
- if (record.kind !== "object" ||
709
+ if ((record.kind !== "object" && record.kind !== "guest-object") ||
710
710
  !sandboxErrorNames.includes(record.errorType)) {
711
711
  fail("invalidValue", `${path}.errorType`, "invalid error metadata");
712
712
  }