@sema-agent/mods-kernel 7.55.0 → 7.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/events.js CHANGED
@@ -1,8 +1,11 @@
1
- export const KERNEL_CONTRACT_VERSION = 2;
1
+ export const KERNEL_CONTRACT_VERSION = 3;
2
2
  export const MOD_TIERS = Object.freeze(["prepend", "user", "append", "builtin", "core"]);
3
3
  export const MOD_SEATS = Object.freeze(["deployment", "task"]);
4
4
  export const MOD_EVENT_SIDES = Object.freeze(["engine", "surface", "both"]);
5
- export const MOD_FAILURE_ANSWERS = Object.freeze(["refuse", "skip"]);
5
+ export const MOD_FAILURE_ANSWERS = Object.freeze(["refuse", "skip", "refuse_until_run"]);
6
+ export function failureRefuses(failure) {
7
+ return failure !== "skip";
8
+ }
6
9
  export const MOD_ABORT_POSTURES = Object.freeze(["immediate", "grace", "caller"]);
7
10
  export const NEXT_TO_TABLE = Object.freeze({
8
11
  prepend: Object.freeze(["append", "builtin", "core"]),
@@ -27,10 +30,19 @@ export const SEAT_TIER_TABLE = Object.freeze({
27
30
  deployment: Object.freeze({ declared: "required", tiers: Object.freeze(["prepend", "user", "append"]) }),
28
31
  task: Object.freeze({ declared: "optional", tiers: Object.freeze(["user"]) }),
29
32
  });
30
- const station = (failure, abort, pinned = []) => Object.freeze({ failure, abort, pinned: Object.freeze([...pinned]) });
33
+ const station = (failure, abort, pinned = [], more = {}) => Object.freeze({
34
+ failure,
35
+ abort,
36
+ pinned: Object.freeze([...pinned]),
37
+ ...(more.call === true ? { call: Object.freeze({ pausesCallerBudget: true }) } : {}),
38
+ ...(more.budgetMs !== undefined ? { budgetMs: more.budgetMs } : {}),
39
+ });
31
40
  const method = (pausesCallerBudget) => Object.freeze({ failure: "skip", abort: "caller", pinned: Object.freeze([]), method: Object.freeze({ pausesCallerBudget }) });
32
41
  const engine = (s) => Object.freeze(s === undefined ? { side: "engine" } : { side: "engine", station: s });
33
- const surface = Object.freeze({ side: "surface" });
42
+ const surface = (s) => Object.freeze(s === undefined ? { side: "surface" } : { side: "surface", station: s });
43
+ const RENDER_PINNED = ["surface", "component", "requestId", "viewport"];
44
+ const ELEMENT_PINNED = ["plugin", "element", "component", "requestId", "surface"];
45
+ const PROMPT_EDIT_BUDGET_MS = 50;
34
46
  export const MOD_EVENT_TABLE = Object.freeze({
35
47
  "classic.PreToolUse": engine(station("refuse", "immediate", ["tool", "tool_use_id", "agentId", "input"])),
36
48
  "classic.PostToolUse": engine(station("skip", "grace")),
@@ -65,34 +77,34 @@ export const MOD_EVENT_TABLE = Object.freeze({
65
77
  "classic.FileChanged": engine(),
66
78
  "classic.DirectoryAdded": engine(),
67
79
  "classic.MessageDisplay": engine(),
68
- "tool.call": engine(),
80
+ "tool.call": engine(station("refuse_until_run", "immediate", ["tool", "tool_use_id", "agentId", "input"], { call: true })),
69
81
  "tool.check": engine(station("refuse", "immediate", ["tool", "input", "tool_use_id", "agentId", "ceiling"])),
70
- "ui.render": surface,
71
- "ui.resolve": surface,
72
- "ui.press": surface,
73
- "ui.input": surface,
74
- "ui.select": surface,
75
- "ui.message": surface,
76
- "ui.fault": surface,
77
- "ui.scroll": surface,
78
- "ui.focus": surface,
82
+ "ui.render": surface(station("skip", "grace", RENDER_PINNED)),
83
+ "ui.resolve": surface(station("skip", "grace", ["surface", "component"])),
84
+ "ui.press": surface(station("skip", "grace", ELEMENT_PINNED)),
85
+ "ui.input": surface(station("skip", "grace", ELEMENT_PINNED)),
86
+ "ui.select": surface(station("skip", "grace", ELEMENT_PINNED)),
87
+ "ui.message": surface(),
88
+ "ui.fault": surface(),
89
+ "ui.scroll": surface(station("skip", "grace", ["component", "requestId", "by", "bodyRows", "contentRows", "origin", "pointer"], { call: true })),
90
+ "ui.focus": surface(station("skip", "grace", ["component", "requestId", "plugin", "origin", "element"], { call: true })),
79
91
  "agent.offer": engine(),
80
92
  "agent.spawn": engine(),
81
93
  "prompt.submit": engine(),
82
- "prompt.fill": surface,
83
- "prompt.suggest": surface,
84
- "prompt.edit": surface,
85
- "prompt.autocomplete": surface,
94
+ "prompt.fill": surface(station("skip", "grace", ["origin", "mode"], { call: true })),
95
+ "prompt.suggest": surface(station("skip", "grace", ["origin"], { call: true })),
96
+ "prompt.edit": surface(station("skip", "grace", ["origin", "key"], { budgetMs: PROMPT_EDIT_BUDGET_MS })),
97
+ "prompt.autocomplete": surface(),
86
98
  "prompt.section": engine(station("skip", "grace", ["name", "key", "mountedTools"])),
87
99
  "prompt.context": engine(),
88
100
  "prompt.attachment": engine(),
89
- "prompt.mention": surface,
101
+ "prompt.mention": engine(station("refuse", "immediate", ["mention", "agentId"])),
90
102
  "prompt.compose": engine(station("skip", "grace", ["model", "catalog", "selectors"])),
91
103
  "tool.describe": engine(),
92
- "command.run": surface,
93
- "command.describe": surface,
94
- "config.set": surface,
95
- "config.describe": surface,
104
+ "command.run": surface(station("skip", "grace", ["command", "presentation", "origin"], { call: true })),
105
+ "command.describe": surface(station("skip", "grace", ["command", "immediate", "provider"])),
106
+ "config.set": surface(station("refuse", "immediate", ["key", "previous", "provider", "origin"], { call: true })),
107
+ "config.describe": surface(station("skip", "grace", ["key", "provider"])),
96
108
  "telemetry.log": engine(),
97
109
  "telemetry.mark": engine(),
98
110
  "skill.prompt": engine(),
@@ -106,7 +118,7 @@ export const MOD_EVENT_TABLE = Object.freeze({
106
118
  "session.detach": engine(),
107
119
  "session.measure": engine(),
108
120
  "session.end": engine(),
109
- "plugin.register": Object.freeze({ side: "both", station: station("skip", "immediate", ["name", "seat", "tier", "uses"]) }),
121
+ "plugin.register": Object.freeze({ side: "both", station: station("refuse", "immediate", ["name", "seat", "tier", "uses"]) }),
110
122
  "turn.start": engine(),
111
123
  "turn.step": engine(),
112
124
  "turn.complete": engine(),
@@ -114,8 +126,8 @@ export const MOD_EVENT_TABLE = Object.freeze({
114
126
  "model.complete": engine(method(true)),
115
127
  "model.classify": engine(),
116
128
  "model.fork": engine(),
117
- "audio.play": surface,
118
- "audio.speak": surface,
129
+ "audio.play": surface(),
130
+ "audio.speak": surface(),
119
131
  "mcp.call": engine(),
120
132
  "mcp.connect": engine(),
121
133
  "session.cwd": engine(method(true)),
@@ -131,27 +143,27 @@ export const MOD_EVENT_TABLE = Object.freeze({
131
143
  "session.usage": engine(),
132
144
  "session.version": engine(),
133
145
  "turn.abort": engine(),
134
- "prompt.read": surface,
146
+ "prompt.read": surface(method(true)),
135
147
  "flag.value": engine(),
136
148
  "tool.list": engine(method(true)),
137
149
  "tool.register": engine(),
138
- "command.list": surface,
139
- "command.register": surface,
140
- "config.list": surface,
150
+ "command.list": surface(method(true)),
151
+ "command.register": surface(method(true)),
152
+ "config.list": surface(method(true)),
141
153
  "agent.list": engine(method(true)),
142
154
  "agent.register": engine(),
143
- "ui.toast": surface,
144
- "ui.status": surface,
145
- "ui.log": surface,
146
- "ui.notice": surface,
147
- "ui.invalidate": surface,
148
- "ui.open": surface,
149
- "ui.close": surface,
150
- "ui.panes": surface,
151
- "ui.selection": surface,
152
- "ui.copy": surface,
153
- "ui.notify": surface,
154
- "ui.blit": surface,
155
+ "ui.toast": surface(method(true)),
156
+ "ui.status": surface(),
157
+ "ui.log": surface(method(true)),
158
+ "ui.notice": surface(method(true)),
159
+ "ui.invalidate": surface(method(true)),
160
+ "ui.open": surface(),
161
+ "ui.close": surface(),
162
+ "ui.panes": surface(),
163
+ "ui.selection": surface(method(true)),
164
+ "ui.copy": surface(method(true)),
165
+ "ui.notify": surface(),
166
+ "ui.blit": surface(),
155
167
  "fs.read": engine(),
156
168
  "fs.write": engine(),
157
169
  "fs.list": engine(),
@@ -199,6 +211,18 @@ export function expandModPattern(pattern) {
199
211
  }
200
212
  return isModEventName(pattern) ? { names: [pattern] } : { refusal: `"${pattern}" is not an event` };
201
213
  }
214
+ export function expandOnSide(pattern, side) {
215
+ const expanded = expandModPattern(pattern);
216
+ if ("refusal" in expanded)
217
+ return expanded;
218
+ const own = expanded.names.filter((n) => readOnSide(n, side));
219
+ if (own.length > 0)
220
+ return { names: own };
221
+ const named = String(pattern);
222
+ return named.endsWith(".*")
223
+ ? { refusal: `"${named}" selects no event the ${side} bus reads (${expanded.names.length === 1 ? "its one name is" : "its names are"} the ${MOD_EVENT_TABLE[expanded.names[0]].side} side's)` }
224
+ : { refusal: `"${named}" is a ${MOD_EVENT_TABLE[expanded.names[0]].side} event, read on that side's bus only — never on the ${side} bus` };
225
+ }
202
226
  export function describe(value) {
203
227
  if (typeof value === "string")
204
228
  return `"${value}"`;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { KERNEL_CONTRACT_VERSION, MOD_TIERS, MOD_SEATS, MOD_EVENT_SIDES, MOD_FAILURE_ANSWERS, MOD_ABORT_POSTURES, NEXT_TO_TABLE, SEAT_TIER_TABLE, MOD_EVENT_TABLE, nextToRefusal, expandModPattern, isModEventName, stationOn, readOnSide, type ModTier, type ModRegistrationTier, type ModSeat, type ModEventSide, type ModBusSide, type ModFailureAnswer, type ModAbortPosture, type ModStation, type ModEventRow, type ModEventName, } from "./events.js";
1
+ export { KERNEL_CONTRACT_VERSION, MOD_TIERS, MOD_SEATS, MOD_EVENT_SIDES, MOD_FAILURE_ANSWERS, MOD_ABORT_POSTURES, NEXT_TO_TABLE, SEAT_TIER_TABLE, MOD_EVENT_TABLE, nextToRefusal, expandModPattern, expandOnSide, failureRefuses, isModEventName, stationOn, readOnSide, type ModTier, type ModRegistrationTier, type ModSeat, type ModEventSide, type ModBusSide, type ModFailureAnswer, type ModAbortPosture, type ModStation, type ModEventRow, type ModEventName, } from "./events.js";
2
2
  export { DEFAULT_MOD_BUDGET_MS, CATCH_BUDGET_MS, RUNAWAY_AFTER_MS, POST_ABORT_GRACE_MS, MAX_TIMER_MS, resolveModBudgetMs, type ModBudgetReading, } from "./budget.js";
3
- export { MOD_FAILURE_CAUSES, type ModFailureCause, type ModEventPayload, type ModAnswerCheck, type ModAnswerer, type ModMatcher, type ModSkip } from "./site-rules.js";
4
- export { ENGINE_ORIGIN, MODS_INVALID_CODE, MODS_REGISTRATION_REFUSED_CODE, MOD_TRACE_OUTCOMES, type ModTraceOutcome, type ModUses, type ModOrigin, type ModPluginFacts, type ModDollarBase, type ModTraceEntry, type ModCaughtError, type ModNext, type ModHandler, type ModHandlerOptions, type On, type ModRegistration, type ModAdmissionRecord, type ModSeats, } from "./registration.js";
5
- export { admitMods, type ModFrame, type ModBottomContext, type ModMethodBottom, type ModMethodSeat, type ModMethodBottoms, type ModDispatchOutcome, type ModDispatchOptions, type ModBus, type ModMountedHandler, type ModBusInput, } from "./dispatch.js";
3
+ export { MOD_FAILURE_CAUSES, type ModFailureCause, type ModEventPayload, type ModAnswerCheck, type ModAnswerRanks, type ModDispatchRun, type ModAnswerer, type ModMatcher, type ModSkip, } from "./site-rules.js";
4
+ export { ENGINE_ORIGIN, MODS_INVALID_CODE, MODS_REGISTRATION_REFUSED_CODE, MOD_TRACE_OUTCOMES, type ModTraceOutcome, type ModUses, type ModOrigin, type ModPluginFacts, type ModDollarBase, type ModTraceEntry, type ModCaughtError, type ModNext, type ModHandler, type ModHandlerOptions, type ModEventPair, type ModEventMap, type ModTypedNext, type ModTypedHandler, type On, type MappedOn, type ModRegistration, type ModAdmissionRecord, type ModSeats, } from "./registration.js";
5
+ export { admitMods, type ModFrame, type ModBottomContext, type ModMethodBottom, type ModMethodSeat, type ModMethodBottoms, type ModCallEntry, type ModCallEntries, type ModDispatchOutcome, type ModDispatchOptions, type ModBus, type ModMountedHandler, type ModBusInput, } from "./dispatch.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { KERNEL_CONTRACT_VERSION, MOD_TIERS, MOD_SEATS, MOD_EVENT_SIDES, MOD_FAILURE_ANSWERS, MOD_ABORT_POSTURES, NEXT_TO_TABLE, SEAT_TIER_TABLE, MOD_EVENT_TABLE, nextToRefusal, expandModPattern, isModEventName, stationOn, readOnSide, } from "./events.js";
1
+ export { KERNEL_CONTRACT_VERSION, MOD_TIERS, MOD_SEATS, MOD_EVENT_SIDES, MOD_FAILURE_ANSWERS, MOD_ABORT_POSTURES, NEXT_TO_TABLE, SEAT_TIER_TABLE, MOD_EVENT_TABLE, nextToRefusal, expandModPattern, expandOnSide, failureRefuses, isModEventName, stationOn, readOnSide, } from "./events.js";
2
2
  export { DEFAULT_MOD_BUDGET_MS, CATCH_BUDGET_MS, RUNAWAY_AFTER_MS, POST_ABORT_GRACE_MS, MAX_TIMER_MS, resolveModBudgetMs, } from "./budget.js";
3
- export { MOD_FAILURE_CAUSES } from "./site-rules.js";
3
+ export { MOD_FAILURE_CAUSES, } from "./site-rules.js";
4
4
  export { ENGINE_ORIGIN, MODS_INVALID_CODE, MODS_REGISTRATION_REFUSED_CODE, MOD_TRACE_OUTCOMES, } from "./registration.js";
5
5
  export { admitMods, } from "./dispatch.js";
package/dist/receive.d.ts CHANGED
@@ -5,6 +5,8 @@ export interface ReceiptMode {
5
5
  readonly past?: "refuse";
6
6
  readonly contain?: true;
7
7
  readonly freeze?: boolean;
8
+ readonly wire?: true;
9
+ readonly leaves?: "cloned";
8
10
  readonly isProxy?: (value: object) => boolean;
9
11
  }
10
12
  export declare const RECEIPT_FAULTS: readonly ["proxy", "accessor", "hidden", "getter-threw", "prototype-moved", "not-data", "cycle", "too-deep", "uncopyable"];
@@ -22,6 +24,11 @@ export type Receipt = {
22
24
  readonly fault: ReceiptFault;
23
25
  };
24
26
  export declare function isPlainRecord(v: unknown): v is Record<string, unknown>;
25
- export declare function receive(value: unknown, mode: ReceiptMode, held?: ReadonlySet<object>): Receipt;
27
+ export declare function dataMember(value: unknown): PropertyDescriptor;
28
+ export declare function appendOwn<T>(list: T[], value: T): void;
29
+ export declare function receive(value: unknown, mode: ReceiptMode, held?: {
30
+ has(value: object): boolean;
31
+ }): Receipt;
26
32
  export declare const MODS_PAYLOAD_MODE: ReceiptMode;
27
33
  export declare function describeFault(fault: ReceiptFault): string;
34
+ export declare function sealedObjects(roots: readonly unknown[]): ReadonlySet<object>;
package/dist/receive.js CHANGED
@@ -5,25 +5,134 @@ export function isPlainRecord(v) {
5
5
  const proto = Object.getPrototypeOf(v);
6
6
  return proto === Object.prototype || proto === null;
7
7
  }
8
+ function isIndexName(k) {
9
+ const n = Number(k);
10
+ return String(n >>> 0) === k && n !== 4_294_967_295;
11
+ }
8
12
  function isOrdinaryArray(v) {
9
13
  return Array.isArray(v) && Object.getPrototypeOf(v) === Array.prototype;
10
14
  }
15
+ const DATE_TO_JSON = Date.prototype.toJSON;
16
+ const DATE_TIME = Date.prototype.getTime;
17
+ const DATE_ISO = Date.prototype.toISOString;
18
+ const TYPED_ARRAY_PROTO = Object.getPrototypeOf(Uint8Array.prototype);
19
+ const TYPED_ARRAY_NAME = Object.getOwnPropertyDescriptor(TYPED_ARRAY_PROTO, Symbol.toStringTag).get;
20
+ const TYPED_ARRAY_LENGTH = Object.getOwnPropertyDescriptor(TYPED_ARRAY_PROTO, "length").get;
21
+ const TYPED_ARRAY_SET = TYPED_ARRAY_PROTO.set;
22
+ const FLOAT64_ARRAY = Float64Array;
23
+ const ARRAY = Array;
24
+ const ARRAY_PROTOTYPE = Array.prototype;
25
+ const ARRAY_SLICE = Array.prototype.slice;
26
+ const OBJECT_PROTOTYPE = Object.prototype;
27
+ const HAS_OWN = Object.hasOwn;
28
+ const OWN_KEYS_ENUMERABLE = Object.keys;
29
+ const SET_PROTOTYPE = Object.setPrototypeOf;
30
+ const DEFINE = Reflect.defineProperty;
31
+ export function dataMember(value) {
32
+ const d = Object.create(null);
33
+ d.value = value;
34
+ d.writable = true;
35
+ d.enumerable = true;
36
+ d.configurable = true;
37
+ return d;
38
+ }
39
+ export function appendOwn(list, value) {
40
+ DEFINE(list, list.length, dataMember(value));
41
+ }
42
+ function listOnNoPrototype(list = []) {
43
+ return SET_PROTOTYPE(list, null);
44
+ }
45
+ const recordOnNoPrototype = () => Object.create(null);
46
+ function typedArrayIndices(v, name, length) {
47
+ const out = recordOnNoPrototype();
48
+ if (name === "BigInt64Array" || name === "BigUint64Array")
49
+ return out;
50
+ const copy = new FLOAT64_ARRAY(length);
51
+ Reflect.apply(TYPED_ARRAY_SET, copy, [v]);
52
+ for (let i = 0; i < length; i++)
53
+ out[i] = copy[i];
54
+ return out;
55
+ }
56
+ function readOwnMember(v, key, cell) {
57
+ try {
58
+ cell.value = v[key];
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ const NO_MEMBERS = Object.freeze(Object.create(null));
66
+ const NO_KEYS = Object.freeze([]);
67
+ function denseList(v, length) {
68
+ let holes = 0;
69
+ for (let i = 0; i < length; i++)
70
+ if (!HAS_OWN(v, i) && ++holes > 64 && holes * 2 > i + 1)
71
+ return false;
72
+ return true;
73
+ }
11
74
  export function receive(value, mode, held) {
12
75
  const seen = new Map();
13
- const path = [];
76
+ const path = listOnNoPrototype();
77
+ const pathTo = (below) => {
78
+ const names = Reflect.apply(ARRAY_SLICE, path, []);
79
+ if (below !== undefined)
80
+ appendOwn(names, below);
81
+ return Object.freeze(names);
82
+ };
14
83
  const open = new Set();
15
84
  const heights = new Map();
16
85
  const faults = [];
17
86
  const refusedAt = new Map();
18
- const stack = [];
87
+ const stack = listOnNoPrototype();
19
88
  const refusals = new Set();
20
89
  const refuse = (kind) => {
21
- const fault = Object.freeze({ kind, path: Object.freeze([...path]) });
90
+ const fault = Object.freeze({ kind, path: pathTo() });
22
91
  refusals.add(fault);
23
92
  throw fault;
24
93
  };
25
- const faultOf = (err) => typeof err === "object" && err !== null && refusals.has(err) ? err : Object.freeze({ kind: "uncopyable", path: Object.freeze([...path]) });
26
- const other = (v, kind) => (mode.others === "as-is" ? v : refuse(kind));
94
+ const faultOf = (err) => typeof err === "object" && err !== null && refusals.has(err) ? err : Object.freeze({ kind: "uncopyable", path: pathTo() });
95
+ const clones = new Map();
96
+ const leafOf = (v) => {
97
+ if (!clones.has(v)) {
98
+ let own = v;
99
+ try {
100
+ if (typeof v !== "function")
101
+ own = structuredClone(v);
102
+ }
103
+ catch {
104
+ }
105
+ clones.set(v, own);
106
+ }
107
+ return clones.get(v);
108
+ };
109
+ const other = (v, kind) => {
110
+ if (mode.others !== "as-is")
111
+ return refuse(kind);
112
+ return mode.leaves !== undefined && kind === "not-data" && v !== null && (typeof v === "object" || typeof v === "function") ? leafOf(v) : v;
113
+ };
114
+ const wireForm = (v) => {
115
+ for (let o = v; o !== null; o = Object.getPrototypeOf(o)) {
116
+ if (o !== v && mode.isProxy?.(o) === true)
117
+ return refuse("proxy");
118
+ const d = Object.getOwnPropertyDescriptor(o, "toJSON");
119
+ if (d === undefined)
120
+ continue;
121
+ if (!Object.hasOwn(d, "value"))
122
+ return refuse("not-data");
123
+ if (typeof d.value !== "function")
124
+ return v;
125
+ if (d.value !== DATE_TO_JSON)
126
+ return refuse("not-data");
127
+ try {
128
+ return Number.isFinite(Reflect.apply(DATE_TIME, v, [])) ? Reflect.apply(DATE_ISO, v, []) : null;
129
+ }
130
+ catch {
131
+ return refuse("not-data");
132
+ }
133
+ }
134
+ return v;
135
+ };
27
136
  const refuseContainer = (v, kind) => {
28
137
  if (mode.contain === true) {
29
138
  refusedAt.set(v, kind);
@@ -74,12 +183,44 @@ export function receive(value, mode, held) {
74
183
  return other(v, "too-deep");
75
184
  if (mode.isProxy?.(v) === true)
76
185
  return refuse("proxy");
186
+ if (mode.wire === true) {
187
+ const form = wireForm(v);
188
+ if (form !== v)
189
+ return form;
190
+ const name = Reflect.apply(TYPED_ARRAY_NAME, v, []);
191
+ if (typeof name === "string") {
192
+ const length = Reflect.apply(TYPED_ARRAY_LENGTH, v, []);
193
+ let out;
194
+ try {
195
+ out = typedArrayIndices(v, name, length);
196
+ }
197
+ catch {
198
+ out = recordOnNoPrototype();
199
+ }
200
+ const captured = Object.create(null);
201
+ const names = Object.keys(v);
202
+ let first = names.length;
203
+ while (first > 0 && !isIndexName(names[first - 1]))
204
+ first--;
205
+ for (const k of names.slice(first)) {
206
+ const d = Object.getOwnPropertyDescriptor(v, k);
207
+ if (d !== undefined)
208
+ captured[k] = d;
209
+ }
210
+ seen.set(v, out);
211
+ open.add(v);
212
+ stack[stack.length] = { v, out, list: false, proto: Object.getPrototypeOf(v), captured, keys: Object.keys(captured), level, next: 0, height: 1, key: "", member: undefined };
213
+ return out;
214
+ }
215
+ }
77
216
  const list = isOrdinaryArray(v) || (mode.others === "copy" && Array.isArray(v));
78
217
  if (!list && !isPlainRecord(v) && mode.others !== "copy")
79
218
  return other(v, "not-data");
219
+ if (mode.wire === true && (!list || denseList(v, v.length)))
220
+ return readInOnePass(v, list, level);
80
221
  const proto = Object.getPrototypeOf(v);
81
222
  const captured = Object.getOwnPropertyDescriptors(v);
82
- const out = list ? [] : {};
223
+ const out = list ? listOnNoPrototype() : recordOnNoPrototype();
83
224
  seen.set(v, out);
84
225
  open.add(v);
85
226
  if (mode.accessors === "refuse") {
@@ -87,15 +228,64 @@ export function receive(value, mode, held) {
87
228
  if (symbols.length > 0 && mode.contain !== true)
88
229
  refuseContainer(v, "hidden");
89
230
  for (const s of symbols)
90
- faults.push(Object.freeze({ kind: "hidden", path: Object.freeze([...path, String(s)]) }));
231
+ appendOwn(faults, Object.freeze({ kind: "hidden", path: pathTo(String(s)) }));
91
232
  }
92
- stack.push({ v, out, list, proto, captured, keys: Object.getOwnPropertyNames(captured), level, next: 0, height: 1, key: "", member: undefined });
233
+ const names = Object.getOwnPropertyNames(captured);
234
+ const keys = mode.wire !== true ? names : names.filter((k) => (list ? isIndexName(k) : captured[k].enumerable === true));
235
+ stack[stack.length] = { v, out, list, proto, captured, keys, level, next: 0, height: 1, key: "", member: undefined };
93
236
  return out;
94
237
  };
238
+ const readInOnePass = (v, list, level) => {
239
+ const names = list ? undefined : OWN_KEYS_ENUMERABLE(v);
240
+ const count = list ? v.length : names.length;
241
+ const out = (list ? listOnNoPrototype(new ARRAY(count)) : recordOnNoPrototype());
242
+ seen.set(v, out);
243
+ open.add(v);
244
+ const f = { v, out, list, proto: Object.getPrototypeOf(v), captured: NO_MEMBERS, keys: NO_KEYS, live: { names, count, pending: undefined }, level, next: 0, height: 1, key: "", member: undefined };
245
+ f.live.pending = primitivesUpToAnObject(f);
246
+ if (f.live.pending === undefined)
247
+ return finish(f);
248
+ stack[stack.length] = f;
249
+ return out;
250
+ };
251
+ const read = { value: undefined };
252
+ const primitivesUpToAnObject = (f) => {
253
+ const { names, count } = f.live;
254
+ const v = f.v;
255
+ const into = f.out;
256
+ while (f.next < count) {
257
+ const key = names === undefined ? f.next : names[f.next];
258
+ f.next++;
259
+ if (!HAS_OWN(v, key))
260
+ continue;
261
+ if (!readOwnMember(v, key, read)) {
262
+ memberLeftOut(String(key), "getter-threw");
263
+ continue;
264
+ }
265
+ const member = read.value;
266
+ read.value = undefined;
267
+ if (member === null || member === undefined || typeof member === "string" || typeof member === "number" || typeof member === "boolean")
268
+ into[key] = member;
269
+ else if (typeof member === "object") {
270
+ into[key] = undefined;
271
+ return { key: String(key), member };
272
+ }
273
+ else
274
+ memberLeftOut(String(key), "not-data");
275
+ }
276
+ return undefined;
277
+ };
278
+ const memberLeftOut = (key, kind) => {
279
+ if (mode.contain !== true) {
280
+ path[path.length] = key;
281
+ refuse(kind);
282
+ }
283
+ appendOwn(faults, Object.freeze({ kind, path: pathTo(key) }));
284
+ };
95
285
  const land = (f, key, copy, member) => {
96
286
  if (measured && typeof member === "object" && member !== null)
97
287
  f.height = Math.max(f.height, heightOf(member) + 1);
98
- Object.defineProperty(f.out, key, { value: copy, enumerable: true, writable: true, configurable: true });
288
+ f.out[key] = copy;
99
289
  path.length = f.level;
100
290
  };
101
291
  const finish = (f) => {
@@ -107,6 +297,7 @@ export function receive(value, mode, held) {
107
297
  if (typeof length === "number")
108
298
  f.out.length = length;
109
299
  }
300
+ SET_PROTOTYPE(f.out, Array.isArray(f.out) ? ARRAY_PROTOTYPE : OBJECT_PROTOTYPE);
110
301
  if (mode.freeze === true)
111
302
  Object.freeze(f.out);
112
303
  open.delete(f.v);
@@ -123,13 +314,34 @@ export function receive(value, mode, held) {
123
314
  }
124
315
  for (;;) {
125
316
  const f = stack[stack.length - 1];
126
- if (f.next < f.keys.length) {
127
- const key = f.keys[f.next++];
317
+ let key;
318
+ let captured;
319
+ let member;
320
+ if (f.live !== undefined) {
321
+ let next = f.live.pending;
322
+ f.live.pending = undefined;
323
+ if (next === undefined) {
324
+ try {
325
+ next = primitivesUpToAnObject(f);
326
+ }
327
+ catch (err) {
328
+ return { ok: false, fault: faultOf(err) };
329
+ }
330
+ }
331
+ if (next !== undefined)
332
+ ({ key, member } = next);
333
+ }
334
+ else if (f.next < f.keys.length) {
335
+ key = f.keys[f.next++];
128
336
  if (f.list && key === "length")
129
337
  continue;
130
- path.push(key);
338
+ captured = f.captured[key];
339
+ }
340
+ if (key !== undefined) {
341
+ path[path.length] = key;
131
342
  try {
132
- const member = memberOf(f.v, f.captured[key]);
343
+ if (captured !== undefined)
344
+ member = memberOf(f.v, captured);
133
345
  const frames = stack.length;
134
346
  const copy = meet(member, f.level + 1);
135
347
  if (stack.length > frames) {
@@ -142,7 +354,8 @@ export function receive(value, mode, held) {
142
354
  catch (err) {
143
355
  if (mode.contain !== true)
144
356
  return { ok: false, fault: faultOf(err) };
145
- faults.push(faultOf(err));
357
+ appendOwn(faults, faultOf(err));
358
+ delete f.out[key];
146
359
  path.length = f.level;
147
360
  }
148
361
  continue;
@@ -152,15 +365,16 @@ export function receive(value, mode, held) {
152
365
  copy = finish(f);
153
366
  }
154
367
  catch (err) {
155
- stack.pop();
368
+ stack.length -= 1;
156
369
  const holder = stack[stack.length - 1];
157
370
  if (mode.contain !== true || holder === undefined)
158
371
  return { ok: false, fault: faultOf(err) };
159
- faults.push(faultOf(err));
372
+ appendOwn(faults, faultOf(err));
373
+ delete holder.out[holder.key];
160
374
  path.length = holder.level;
161
375
  continue;
162
376
  }
163
- stack.pop();
377
+ stack.length -= 1;
164
378
  const holder = stack[stack.length - 1];
165
379
  if (holder === undefined)
166
380
  return received(copy);
@@ -191,3 +405,62 @@ export function describeFault(fault) {
191
405
  return `a value that could not be copied whole${at}`;
192
406
  }
193
407
  }
408
+ export function sealedObjects(roots) {
409
+ const holders = new WeakMap();
410
+ const met = new Set();
411
+ const unsealed = [];
412
+ const stack = [...roots];
413
+ while (stack.length > 0) {
414
+ const v = stack.pop();
415
+ if (typeof v !== "object" || v === null || met.has(v))
416
+ continue;
417
+ met.add(v);
418
+ const container = isPlainRecord(v) || (Array.isArray(v) && Object.getPrototypeOf(v) === Array.prototype);
419
+ if (!container) {
420
+ unsealed.push(v);
421
+ continue;
422
+ }
423
+ if (!Object.isFrozen(v))
424
+ unsealed.push(v);
425
+ const descriptors = Object.getOwnPropertyDescriptors(v);
426
+ if (Object.getOwnPropertySymbols(descriptors).length > 0)
427
+ unsealed.push(v);
428
+ for (const k of Object.getOwnPropertyNames(descriptors)) {
429
+ if (Array.isArray(v) && k === "length")
430
+ continue;
431
+ const d = descriptors[k];
432
+ if (!Object.hasOwn(d, "value") || d.enumerable !== true) {
433
+ unsealed.push(v);
434
+ continue;
435
+ }
436
+ const m = d.value;
437
+ if (typeof m === "bigint" || typeof m === "symbol" || typeof m === "function")
438
+ unsealed.push(v);
439
+ else if (typeof m === "object" && m !== null) {
440
+ const by = holders.get(m);
441
+ if (by === undefined)
442
+ holders.set(m, [v]);
443
+ else
444
+ by.push(v);
445
+ stack.push(m);
446
+ }
447
+ }
448
+ }
449
+ return withoutUnsealed(met, unsealed, holders);
450
+ }
451
+ function withoutUnsealed(objects, unsealed, holders) {
452
+ const bad = new Set();
453
+ while (unsealed.length > 0) {
454
+ const v = unsealed.pop();
455
+ if (bad.has(v))
456
+ continue;
457
+ bad.add(v);
458
+ for (const h of holders.get(v) ?? [])
459
+ unsealed.push(h);
460
+ }
461
+ const sealed = new Set();
462
+ for (const v of objects)
463
+ if (!bad.has(v))
464
+ sealed.add(v);
465
+ return sealed;
466
+ }
@@ -47,10 +47,34 @@ export interface ModHandlerOptions<D extends ModDollarBase = ModDollarBase> {
47
47
  readonly catch?: ModHandler<D>;
48
48
  readonly observe?: boolean;
49
49
  }
50
+ export interface ModEventPair {
51
+ readonly e: object;
52
+ readonly answer: unknown;
53
+ }
54
+ export type ModEventMap = {
55
+ readonly [name: string]: ModEventPair;
56
+ };
57
+ export interface ModTypedNext<P extends ModEventPair> {
58
+ (e: P["e"]): Promise<P["answer"]>;
59
+ to(e: P["e"], tier: ModTier): Promise<P["answer"]>;
60
+ readonly origin: ModOrigin;
61
+ readonly signal: AbortSignal;
62
+ readonly trace: readonly ModTraceEntry[];
63
+ readonly budget: ModBudgetReading;
64
+ readonly error?: ModCaughtError;
65
+ readonly called?: boolean;
66
+ }
67
+ export type ModTypedHandler<D extends ModDollarBase, P extends ModEventPair> = ($: D, e: P["e"], next: ModTypedNext<P>) => P["answer"] | Promise<P["answer"]>;
50
68
  export interface On<D extends ModDollarBase = ModDollarBase> {
51
69
  (pattern: string, handler: ModHandler<D>, options?: ModHandlerOptions<D>): void;
52
70
  (pattern: string, matcher: ModMatcher, handler: ModHandler<D>, options?: ModHandlerOptions<D>): void;
53
71
  }
72
+ export interface MappedOn<D extends ModDollarBase, M extends ModEventMap> {
73
+ <K extends keyof M & string>(pattern: K, handler: ModTypedHandler<D, M[K]>, options?: ModHandlerOptions<D>): void;
74
+ <K extends keyof M & string>(pattern: K, matcher: ModMatcher, handler: ModTypedHandler<D, M[K]>, options?: ModHandlerOptions<D>): void;
75
+ (pattern: string, handler: ModHandler<D>, options?: ModHandlerOptions<D>): void;
76
+ (pattern: string, matcher: ModMatcher, handler: ModHandler<D>, options?: ModHandlerOptions<D>): void;
77
+ }
54
78
  export interface ModRegistration<D extends ModDollarBase = ModDollarBase> {
55
79
  readonly name: string;
56
80
  readonly tier?: ModRegistrationTier;