1const RUNTIME_STUB: &str = r#"(() => {
2 "use strict";
3
4 const MANIFEST_ELEMENT_ID = "presolve-template-manifest";
5 const COMPUTED_ARTIFACT_ELEMENT_ID = "presolve-computed-runtime";
6 const EFFECT_ARTIFACT_ELEMENT_ID = "presolve-effect-runtime";
7 const CONTEXT_ARTIFACT_ELEMENT_ID = "presolve-context-runtime";
8 const COMPONENT_ARTIFACT_ELEMENT_ID = "presolve-component-runtime";
9 const FORMS_ARTIFACT_ELEMENT_ID = "presolve-forms-runtime";
10 const RESOURCES_ARTIFACT_ELEMENT_ID = "presolve-resources-runtime";
11 const OPAQUE_ARTIFACT_ELEMENT_ID = "presolve-opaque-runtime";
12 const PACKAGE_INVOCATIONS_ARTIFACT_ELEMENT_ID = "presolve-package-invocations-runtime";
13 const RESUME_MANIFEST_ELEMENT_ID = "presolve-resume-runtime";
14 const RESUME_SNAPSHOT_ELEMENT_ID = "presolve-resume-snapshot";
15 const PRODUCTION_RUNTIME_ELEMENT_ID = "presolve-production-runtime";
16 const RUNTIME_VERSION = "0.0.0";
17 const SUPPORTED_SCHEMA_VERSION = 5;
18 const ACTION_MANIFEST_SCHEMA_VERSION = 2;
19 const FORMS_MANIFEST_SCHEMA_VERSION = 3;
20 const LEGACY_MANIFEST_SCHEMA_VERSION = 1;
21 const SUPPORTED_COMPUTED_ARTIFACT_SCHEMA_VERSION = 12;
22 const SUPPORTED_EFFECT_ARTIFACT_SCHEMA_VERSION = __EZ_EFFECT_SCHEMA_VERSION__;
23 const SUPPORTED_CONTEXT_ARTIFACT_SCHEMA_VERSION = 2;
24 const SUPPORTED_COMPONENT_ARTIFACT_SCHEMA_VERSION = __EZ_COMPONENT_SCHEMA_VERSION__;
25 const LEGACY_COMPONENT_ARTIFACT_SCHEMA_VERSION = 2;
26 const SUPPORTED_FORMS_ARTIFACT_SCHEMA_VERSION = 6;
27 const SUPPORTED_RESOURCES_ARTIFACT_SCHEMA_VERSION = 3;
28 const SUPPORTED_OPAQUE_ARTIFACT_SCHEMA_VERSION = 1;
29 const SUPPORTED_PACKAGE_INVOCATIONS_ARTIFACT_SCHEMA_VERSION = 2;
30 const SUPPORTED_RESUME_MANIFEST_SCHEMA_VERSION = 7;
31 const SUPPORTED_RESUME_SNAPSHOT_SCHEMA_VERSION = 2;
32 const SUPPORTED_RESUME_RUNTIME_PROTOCOL_VERSION = 1;
33 const RESUME_REGISTRY_CONTRACT_VERSION = 1;
34
35 class PresolveBootError extends Error {
36 constructor(code) {
37 super(code);
38 this.name = "PresolveBootError";
39 this.code = code;
40 }
41 }
42
43 function createDiagnostic(code, message, detail, fatal = false) {
44 return {
45 code,
46 message,
47 detail,
48 fatal
49 };
50 }
51
52 function reportDiagnostic(diagnostics, code, message, detail, fatal = false) {
53 const diagnostic = createDiagnostic(code, message, detail, fatal);
54 diagnostics.push(diagnostic);
55 console.error(`[Presolve] ${code}`, diagnostic);
56 return diagnostic;
57 }
58
59 class ResumeBootError extends Error {
60 constructor(failure, detail = {}) {
61 super(failure);
62 this.name = "ResumeBootError";
63 this.failure = failure;
64 this.detail = detail;
65 }
66 }
67
68 const resumeBootstrapState = {
69 phase: "idle",
70 manifest: null,
71 registry: null,
72 result: null,
73 debug: []
74 };
75 let standardSchemaValidators = new Map();
76 let formSubmissionCapabilities = new Map();
77 let packageInvocationRegistry = new Map();
78
79 function exactObjectKeys(value, expected) {
80 if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
81 const actual = Object.keys(value).sort();
82 const canonical = [...expected].sort();
83 return actual.length === canonical.length
84 && actual.every((key, index) => key === canonical[index]);
85 }
86
87 function readResumeManifest(diagnostics) {
88 const element = document.getElementById(RESUME_MANIFEST_ELEMENT_ID);
89 if (!(element instanceof HTMLScriptElement)) {
90 reportDiagnostic(diagnostics, "PSR_RESUME_MANIFEST_MISSING", "Resume manifest v7 is missing", { artifactElementId: RESUME_MANIFEST_ELEMENT_ID });
91 throw new ResumeBootError("ManifestVersionMismatch");
92 }
93 try {
94 return JSON.parse(element.textContent ?? "");
95 } catch (error) {
96 reportDiagnostic(diagnostics, "PSR_RESUME_MANIFEST_PARSE", "Resume manifest v7 could not be parsed", { message: error instanceof Error ? error.message : String(error) });
97 throw new ResumeBootError("ManifestVersionMismatch");
98 }
99 }
100
101 function readProductionRuntimeArtifact() {
102 const element = document.getElementById(PRODUCTION_RUNTIME_ELEMENT_ID);
103 if (element === null) return null;
104 if (!(element instanceof HTMLScriptElement)) throw new ResumeBootError("ProductionArtifactMismatch");
105 let artifact;
106 try { artifact = JSON.parse(element.textContent ?? ""); } catch (_) { throw new ResumeBootError("ProductionArtifactMismatch"); }
107 if (artifact === null || typeof artifact !== "object"
108 || artifact.schemaVersion !== 1 || artifact.runtimeProtocolVersion !== 1
109 || !Array.isArray(artifact.tables?.tables) || !Array.isArray(artifact.chunks)) {
110 throw new ResumeBootError("ProductionArtifactMismatch");
111 }
112 return artifact;
113 }
114
115 function productionOrdinalIndexes(artifact) {
116 if (artifact === null) return null;
117 const indexes = new Map();
118 for (const table of artifact.tables.tables) {
119 if (typeof table.table_kind !== "string" || !Array.isArray(table.mappings)) {
120 throw new ResumeBootError("ProductionArtifactMismatch");
121 }
122 const values = new Map();
123 for (const mapping of table.mappings) {
124 if (typeof mapping.canonical_id !== "string" || !Number.isInteger(mapping.ordinal)
125 || mapping.ordinal < 0 || values.has(mapping.canonical_id)) {
126 throw new ResumeBootError("ProductionArtifactMismatch");
127 }
128 values.set(mapping.canonical_id, mapping.ordinal);
129 }
130 indexes.set(table.table_kind, values);
131 }
132 for (const required of ["anchors", "events", "activations", "activation_roots"]) {
133 if (!indexes.has(required)) throw new ResumeBootError("ProductionArtifactMismatch");
134 }
135 return indexes;
136 }
137
138 function readOptionalResumeSnapshot(diagnostics, explicitSnapshot) {
139 if (explicitSnapshot !== undefined) return explicitSnapshot;
140 if (window.__PRESOLVE_RESUME_SNAPSHOT__ !== undefined) {
141 return window.__PRESOLVE_RESUME_SNAPSHOT__;
142 }
143 const element = document.getElementById(RESUME_SNAPSHOT_ELEMENT_ID);
144 if (element === null) return null;
145 if (!(element instanceof HTMLScriptElement)) {
146 reportDiagnostic(diagnostics, "PSR_RESUME_SNAPSHOT_PARSE", "Resume snapshot was not stored in a JSON script element", { artifactElementId: RESUME_SNAPSHOT_ELEMENT_ID });
147 throw new ResumeBootError("SnapshotParseFailure");
148 }
149 try {
150 return JSON.parse(element.textContent ?? "");
151 } catch (error) {
152 reportDiagnostic(diagnostics, "PSR_RESUME_SNAPSHOT_PARSE", "Resume snapshot v2 could not be parsed", { message: error instanceof Error ? error.message : String(error) });
153 throw new ResumeBootError("SnapshotParseFailure");
154 }
155 }
156
157 function uniqueRecordIndex(records, key, failure = "DuplicateIdentity") {
158 if (!Array.isArray(records)) throw new ResumeBootError("ResumeArtifactMismatch");
159 const index = new Map();
160 for (const record of records) {
161 const id = record?.[key];
162 if (typeof id !== "string" || index.has(id)) throw new ResumeBootError(failure, { id });
163 index.set(id, record);
164 }
165 return index;
166 }
167
168 function validateResumeManifest(manifest) {
169 const topLevelKeys = [
170 "schema_version", "build_id", "snapshot_schema_version", "runtime_protocol_version",
171 "application_root_boundary_id", "boundaries", "slot_schemas", "capture_programs",
172 "restore_programs", "chunks", "activations", "anchors", "events",
173 "phase_i_component_resume_records", "phase_i_form_resume_records"
174 ];
175 if (!exactObjectKeys(manifest, topLevelKeys)) throw new ResumeBootError("ResumeArtifactMismatch");
176 if (manifest.schema_version !== SUPPORTED_RESUME_MANIFEST_SCHEMA_VERSION) {
177 throw new ResumeBootError("ManifestVersionMismatch");
178 }
179 if (manifest.snapshot_schema_version !== SUPPORTED_RESUME_SNAPSHOT_SCHEMA_VERSION) {
180 throw new ResumeBootError("SnapshotSchemaMismatch");
181 }
182 if (manifest.runtime_protocol_version !== SUPPORTED_RESUME_RUNTIME_PROTOCOL_VERSION) {
183 throw new ResumeBootError("RuntimeProtocolMismatch");
184 }
185 if (typeof manifest.build_id !== "string" || !/^resume-build:[0-9a-f]{64}$/.test(manifest.build_id)) {
186 throw new ResumeBootError("ResumeArtifactMismatch");
187 }
188 const boundaries = uniqueRecordIndex(manifest.boundaries, "boundary_id");
189 const slots = uniqueRecordIndex(manifest.slot_schemas, "slot_id");
190 const capturePrograms = uniqueRecordIndex(manifest.capture_programs, "program_id");
191 const restorePrograms = uniqueRecordIndex(manifest.restore_programs, "program_id");
192 const chunks = uniqueRecordIndex(manifest.chunks, "chunk_id");
193 const activations = uniqueRecordIndex(manifest.activations, "activation_id");
194 const anchors = uniqueRecordIndex(manifest.anchors, "anchor_id");
195 const events = uniqueRecordIndex(manifest.events, "resume_event_id");
196 if (!boundaries.has(manifest.application_root_boundary_id)) {
197 throw new ResumeBootError("UnknownBoundary");
198 }
199 for (const boundary of boundaries.values()) {
200 if (!capturePrograms.has(boundary.capture_program_id)
201 || !restorePrograms.has(boundary.restore_program_id)
202 || (boundary.parent_boundary_id !== undefined && !boundaries.has(boundary.parent_boundary_id))
203 || !boundary.child_boundary_ids.every((id) => boundaries.has(id))
204 || !boundary.anchor_ids.every((id) => anchors.has(id))
205 || !boundary.event_ids.every((id) => events.has(id))) {
206 throw new ResumeBootError("ResumeArtifactMismatch", { boundary: boundary.boundary_id });
207 }
208 }
209 for (const slot of slots.values()) {
210 if (!boundaries.has(slot.owner_boundary_id)) throw new ResumeBootError("UnknownBoundary");
211 }
212 for (const activation of activations.values()) {
213 if (!boundaries.has(activation.boundary_id)
214 || !chunks.has(activation.chunk_id)
215 || !activation.prerequisite_boundary_ids.every((id) => boundaries.has(id))
216 || (activation.event_id !== undefined && !events.has(activation.event_id))) {
217 throw new ResumeBootError("ResumeArtifactMismatch", { activation: activation.activation_id });
218 }
219 }
220 for (const anchor of anchors.values()) {
221 if (!boundaries.has(anchor.boundary_id)) throw new ResumeBootError("UnknownBoundary");
222 }
223 for (const event of events.values()) {
224 if (!anchors.has(event.exact_target_anchor_id)
225 || !boundaries.has(event.owner_boundary_id)
226 || !chunks.has(event.chunk_id)) {
227 throw new ResumeBootError("ResumeArtifactMismatch", { event: event.resume_event_id });
228 }
229 }
230 return { boundaries, slots, capturePrograms, restorePrograms, chunks, activations, anchors, events };
231 }
232
233 function validateResumeSnapshot(snapshot, manifest, definitions) {
234 if (!exactObjectKeys(snapshot, ["schemaVersion", "buildId", "snapshotId", "manifestVersion", "capturedAt", "boundaries", "structuralOccurrences"])) {
235 throw new ResumeBootError("SnapshotSchemaMismatch");
236 }
237 if (snapshot.schemaVersion !== SUPPORTED_RESUME_SNAPSHOT_SCHEMA_VERSION
238 || snapshot.manifestVersion !== SUPPORTED_RESUME_MANIFEST_SCHEMA_VERSION
239 || snapshot.capturedAt !== null
240 || typeof snapshot.snapshotId !== "string") {
241 throw new ResumeBootError("SnapshotSchemaMismatch");
242 }
243 if (snapshot.buildId !== manifest.build_id) throw new ResumeBootError("BuildIdMismatch");
244 const seenBoundaries = new Set();
245 const seenSlots = new Set();
246 if (!Array.isArray(snapshot.boundaries) || !Array.isArray(snapshot.structuralOccurrences)) {
247 throw new ResumeBootError("SnapshotSchemaMismatch");
248 }
249 for (const boundary of snapshot.boundaries) {
250 if (!exactObjectKeys(boundary, ["boundaryId", "schemaId", "values"])) {
251 throw new ResumeBootError("SnapshotSchemaMismatch");
252 }
253 const definition = definitions.boundaries.get(boundary.boundaryId);
254 if (definition === undefined) throw new ResumeBootError("UnknownBoundary");
255 if (seenBoundaries.has(boundary.boundaryId)) throw new ResumeBootError("DuplicateIdentity");
256 if (boundary.schemaId !== definition.schema_id || !Array.isArray(boundary.values)) {
257 throw new ResumeBootError("ResumeArtifactMismatch");
258 }
259 seenBoundaries.add(boundary.boundaryId);
260 for (const value of boundary.values) {
261 if (!exactObjectKeys(value, ["valueRecordId", "slotId", "value"])) {
262 throw new ResumeBootError("SnapshotSchemaMismatch");
263 }
264 const slot = definitions.slots.get(value.slotId);
265 if (slot === undefined) throw new ResumeBootError("UnknownSlot");
266 if (slot.owner_boundary_id !== boundary.boundaryId || seenSlots.has(value.slotId)) {
267 throw new ResumeBootError("DuplicateIdentity");
268 }
269 seenSlots.add(value.slotId);
270 }
271 }
272 const structuralOccurrences = new Map();
273 for (const occurrence of snapshot.structuralOccurrences) {
274 if (!exactObjectKeys(occurrence, ["occurrenceIdentity", "templateInstance", "parentScope", "structuralRegion", "localOccurrence", "state"])
275 || typeof occurrence.occurrenceIdentity !== "string"
276 || typeof occurrence.templateInstance !== "string"
277 || typeof occurrence.parentScope !== "string"
278 || typeof occurrence.structuralRegion !== "string"
279 || typeof occurrence.localOccurrence !== "string"
280 || !Array.isArray(occurrence.state)
281 || structuralOccurrences.has(occurrence.occurrenceIdentity)) {
282 throw new ResumeBootError("SnapshotSchemaMismatch");
283 }
284 const stateSlots = new Set();
285 for (const state of occurrence.state) {
286 if (!exactObjectKeys(state, ["slotId", "value"])
287 || typeof state.slotId !== "string"
288 || stateSlots.has(state.slotId)) {
289 throw new ResumeBootError("SnapshotSchemaMismatch");
290 }
291 stateSlots.add(state.slotId);
292 }
293 structuralOccurrences.set(occurrence.occurrenceIdentity, occurrence);
294 }
295 return { seenBoundaries, seenSlots, structuralOccurrences };
296 }
297
298 function allocateResumeRegistry(manifest, definitions) {
299 return {
300 contract_version: RESUME_REGISTRY_CONTRACT_VERSION,
301 build_id: manifest.build_id,
302 definitions,
303 boundary_records: new Map(),
304 slot_values: new Map(),
305 context_bindings: new Map(),
306 component_records: new Map(),
307 form_records: new Map(),
308 structural_records: new Map(),
309 structural_occurrences: new Map(),
310 effect_subscriptions: new Map(),
311 activation_states: new Map(),
312 debug: []
313 };
314 }
315
316 function resumeDebugEvidence(result) {
317 return {
318 contract_version: RESUME_REGISTRY_CONTRACT_VERSION,
319 mode: result.mode,
320 failure: result.failure ?? null,
321 build_id: resumeBootstrapState.manifest?.build_id ?? null,
322 boundary_ids: resumeBootstrapState.registry === null
323 ? []
324 : [...resumeBootstrapState.registry.definitions.boundaries.keys()],
325 slot_ids: resumeBootstrapState.registry === null
326 ? []
327 : [...resumeBootstrapState.registry.definitions.slots.keys()]
328 };
329 }
330
331 async function bootstrapResume(input = {}) {
332 if (resumeBootstrapState.phase !== "idle") {
333 throw new ResumeBootError("DoubleBootstrap");
334 }
335 resumeBootstrapState.phase = "booting";
336 const diagnostics = input.diagnostics ?? [];
337 let snapshot = null;
338 let coldAttempted = false;
339 try {
340 const manifest = input.resumeManifest ?? readResumeManifest(diagnostics);
341 const definitions = validateResumeManifest(manifest);
342 snapshot = readOptionalResumeSnapshot(diagnostics, input.snapshot);
343 resumeBootstrapState.manifest = manifest;
344 if (snapshot === null) {
345 coldAttempted = true;
346 const cold = await input.coldBoot?.("NoSnapshot");
347 const result = { mode: "cold", failure: null, cold };
348 resumeBootstrapState.phase = "ready";
349 resumeBootstrapState.result = result;
350 resumeBootstrapState.debug = [resumeDebugEvidence(result)];
351 return result;
352 }
353 validateResumeSnapshot(snapshot, manifest, definitions);
354 resumeBootstrapState.registry = allocateResumeRegistry(manifest, definitions);
355 const resume = await input.resumeBoot?.({
356 manifest,
357 snapshot,
358 registry: resumeBootstrapState.registry
359 });
360 const result = {
361 mode: "resume",
362 failure: null,
363 registry: resumeBootstrapState.registry,
364 resume
365 };
366 resumeBootstrapState.phase = "ready";
367 resumeBootstrapState.result = result;
368 resumeBootstrapState.debug = [resumeDebugEvidence(result)];
369 return result;
370 } catch (error) {
371 if (coldAttempted) {
372 resumeBootstrapState.phase = "failed";
373 throw error;
374 }
375 const failure = error instanceof ResumeBootError ? error.failure : "RestoreInstructionFailure";
376 resumeBootstrapState.registry = null;
377 resumeBootstrapState.debug = [{ contract_version: RESUME_REGISTRY_CONTRACT_VERSION, mode: "cold", failure }];
378 try {
379 coldAttempted = true;
380 const cold = await input.coldBoot?.(failure);
381 const result = { mode: "cold", failure, cold };
382 resumeBootstrapState.phase = "ready";
383 resumeBootstrapState.result = result;
384 return result;
385 } catch (coldError) {
386 resumeBootstrapState.phase = "failed";
387 throw coldError;
388 }
389 }
390 }
391
392 function captureSnapshot() {
393 if (resumeBootstrapState.phase !== "ready" || resumeBootstrapState.manifest === null) {
394 return { ok: false, failure: "NotQuiescent" };
395 }
396 return { ok: false, failure: "NotQuiescent" };
397 }
398
399 async function activateBoundary(boundaryId) {
400 const registry = resumeBootstrapState.registry;
401 if (registry === null || !registry.definitions.boundaries.has(boundaryId)) {
402 throw new ResumeBootError("UnknownBoundary", { boundaryId });
403 }
404 const activation = [...registry.definitions.activations.values()]
405 .find((record) => record.boundary_id === boundaryId);
406 if (activation === undefined) throw new ResumeBootError("ActivationFailure", { boundaryId });
407 const prior = registry.activation_states.get(activation.activation_id);
408 if (prior?.status === "active") return prior.result;
409 if (prior?.status === "failed") throw new ResumeBootError("ActivationFailure", { boundaryId });
410 if (prior?.promise !== undefined) return prior.promise;
411 const chunk = registry.definitions.chunks.get(activation.chunk_id);
412 if (chunk === undefined || typeof chunk.module_path !== "string") {
413 throw new ResumeBootError("ActivationFailure", { boundaryId });
414 }
415 const promise = import(new URL(chunk.module_path, document.baseURI).href)
416 .then(() => {
417 const result = { boundary_id: boundaryId, activation_id: activation.activation_id, chunk_id: activation.chunk_id, status: "active" };
418 registry.activation_states.set(activation.activation_id, { status: "active", result });
419 return result;
420 })
421 .catch(() => {
422 registry.activation_states.set(activation.activation_id, { status: "failed" });
423 throw new ResumeBootError("ActivationFailure", { boundaryId });
424 });
425 registry.activation_states.set(activation.activation_id, { status: "loading", promise });
426 return promise;
427 }
428
429 async function activateByEvent(resumeEventId) {
430 const registry = resumeBootstrapState.registry;
431 if (registry === null || !registry.definitions.events.has(resumeEventId)) {
432 throw new ResumeBootError("ActivationFailure", { resumeEventId });
433 }
434 const activation = [...registry.definitions.activations.values()]
435 .find((record) => record.event_id === resumeEventId);
436 if (activation === undefined) throw new ResumeBootError("ActivationFailure", { resumeEventId });
437 return activateBoundary(activation.boundary_id);
438 }
439
440 function resumeEventMarker(target) {
441 let current = target instanceof Element ? target : target?.parentElement;
442 while (current !== null && current !== undefined) {
443 const marker = current.getAttribute("data-presolve-e");
444 if (marker !== null) return marker;
445 current = current.parentElement;
446 }
447 return null;
448 }
449
450 function installResumeActivationListeners(registry, store) {
451 const events = new Map([...registry.definitions.events.values()].map((event) => [event.resume_event_id, event]));
452 const eventTypes = new Set([...events.values()].map((event) => event.event_type));
453 for (const eventType of eventTypes) {
454 document.addEventListener(eventType, async (event) => {
455 const target = event.target instanceof Element ? event.target : event.target?.parentElement;
456 const type = event.type;
457 const marker = resumeEventMarker(target);
458 if (marker === null) return;
459 const record = events.get(marker);
460 if (record === undefined || record.event_type !== type) return;
461 try {
462 await activateByEvent(marker);
463 dispatchOrdinaryInstanceEvent(store, { target, type });
464 } catch (error) {
465 registry.debug.push({ event_id: marker, failure: error instanceof ResumeBootError ? error.failure : "ActivationFailure" });
466 }
467 });
468 }
469 }
470
471 function readManifest(diagnostics) {
472 const element = document.getElementById(MANIFEST_ELEMENT_ID);
473
474 if (!(element instanceof HTMLScriptElement)) {
475 reportDiagnostic(
476 diagnostics,
477 "PSR_MISSING_MANIFEST",
478 `Missing template manifest script #${MANIFEST_ELEMENT_ID}`,
479 { manifestElementId: MANIFEST_ELEMENT_ID },
480 true
481 );
482 throw new PresolveBootError("PSR_MISSING_MANIFEST");
483 }
484
485 try {
486 return JSON.parse(element.textContent ?? "");
487 } catch (error) {
488 reportDiagnostic(
489 diagnostics,
490 "PSR_INVALID_MANIFEST_JSON",
491 "Template manifest JSON could not be parsed",
492 { message: error instanceof Error ? error.message : String(error) },
493 true
494 );
495 throw new PresolveBootError("PSR_INVALID_MANIFEST_JSON");
496 }
497 }
498
499 function effectArtifactHasActionPlans(effectArtifact) {
500 return (effectArtifact?.effects ?? []).some((effect) =>
501 Array.isArray(effect.action_batch_triggers) && effect.action_batch_triggers.length > 0
502 );
503 }
504
505 function legacyActionBinding(action) {
506 return action?.method_id === undefined
507 && action?.action_batch_id === undefined
508 && typeof action?.method === "string"
509 && action.method.length > 0;
510 }
511
512 function legacyEventBinding(event) {
513 return event?.kind === undefined
514 && event?.method_id === undefined
515 && event?.action_batch_id === undefined
516 && /^this\.[A-Za-z_$][\w$]*$/.test(String(event?.handler ?? ""));
517 }
518
519 function legacyHandlerMethod(reference) {
520 return String(reference ?? "").replace(/^this\./, "");
521 }
522
523 function legacyComponentMethodKey(componentName, method) {
524 return `${componentName}:${method}`;
525 }
526
527 function validateManifestActionBindings(manifest, opaqueArtifact, packageInvocationsArtifact, diagnostics) {
528 const opaqueMethods = new Set((opaqueArtifact?.activations ?? []).map((activation) => activation.method));
529 const packageInvocationMethods = new Set(
530 (packageInvocationsArtifact?.invocations ?? []).map((invocation) => invocation.method)
531 );
532 for (const component of manifest.components ?? []) {
533 const actionsByMethod = new Map();
534 const legacyMethods = new Set();
535
536 for (const action of component.actions ?? []) {
537 if (legacyActionBinding(action)) {
538 legacyMethods.add(action.method);
539 continue;
540 }
541 if (typeof action.method_id !== "string"
542 || typeof action.action_batch_id !== "string"
543 || (manifest.schema_version === SUPPORTED_SCHEMA_VERSION && typeof action.storage_id !== "string")) {
544 reportDiagnostic(
545 diagnostics,
546 "PSR_INVALID_ACTION_BINDING",
547 "Schema-v2 template action was missing compiler action identities",
548 { component: component.name, action },
549 true
550 );
551 throw new PresolveBootError("PSR_INVALID_ACTION_BINDING");
552 }
553 actionsByMethod.set(action.method_id, action.action_batch_id);
554 }
555
556 for (const event of component.template?.events ?? []) {
557 if (legacyEventBinding(event)) {
558 const method = legacyHandlerMethod(event.handler);
559 if (legacyMethods.has(method)) continue;
560 reportDiagnostic(
561 diagnostics,
562 "PSR_INVALID_ACTION_BINDING",
563 "Legacy template action binding did not match its compiler action implementation",
564 { component: component.name, event },
565 true
566 );
567 throw new PresolveBootError("PSR_INVALID_ACTION_BINDING");
568 }
569 if (event.kind !== "action") {
570 reportDiagnostic(
571 diagnostics,
572 "PSR_INVALID_ACTION_BINDING",
573 "Schema-v2 template event was not an explicit action binding",
574 { component: component.name, event },
575 true
576 );
577 throw new PresolveBootError("PSR_INVALID_ACTION_BINDING");
578 }
579 if (typeof event.method_id !== "string" || typeof event.action_batch_id !== "string") {
580 reportDiagnostic(
581 diagnostics,
582 "PSR_INVALID_ACTION_BINDING",
583 "Schema-v2 template action binding was missing an action batch identity",
584 { component: component.name, event },
585 true
586 );
587 throw new PresolveBootError("PSR_INVALID_ACTION_BINDING");
588 }
589 if (actionsByMethod.get(event.method_id) !== event.action_batch_id
590 && !opaqueMethods.has(event.method_id)
591 && !packageInvocationMethods.has(event.method_id)) {
592 reportDiagnostic(
593 diagnostics,
594 "PSR_INVALID_ACTION_BINDING",
595 "Template action binding did not match its compiler action implementation",
596 { component: component.name, event },
597 true
598 );
599 throw new PresolveBootError("PSR_INVALID_ACTION_BINDING");
600 }
601 }
602 }
603 }
604
605 function validateManifestSchema(manifest, effectArtifact, componentArtifact, opaqueArtifact, packageInvocationsArtifact, diagnostics) {
606 if (
607 manifest?.schema_version !== SUPPORTED_SCHEMA_VERSION &&
608 manifest?.schema_version !== FORMS_MANIFEST_SCHEMA_VERSION &&
609 manifest?.schema_version !== ACTION_MANIFEST_SCHEMA_VERSION &&
610 manifest?.schema_version !== LEGACY_MANIFEST_SCHEMA_VERSION
611 ) {
612 reportDiagnostic(
613 diagnostics,
614 "PSR_UNSUPPORTED_SCHEMA",
615 `Unsupported template manifest schema version ${String(manifest?.schema_version)}`,
616 {
617 schema_version: manifest?.schema_version,
618 supported_schema_version: SUPPORTED_SCHEMA_VERSION
619 },
620 true
621 );
622 throw new PresolveBootError("PSR_UNSUPPORTED_SCHEMA");
623 }
624
625 const isOrdinaryInstancePair = manifest.schema_version === SUPPORTED_SCHEMA_VERSION
626 && componentArtifact?.schema_version === SUPPORTED_COMPONENT_ARTIFACT_SCHEMA_VERSION;
627 const isLegacyColdPair = manifest.schema_version === FORMS_MANIFEST_SCHEMA_VERSION
628 && componentArtifact?.schema_version === LEGACY_COMPONENT_ARTIFACT_SCHEMA_VERSION;
629 if (!isOrdinaryInstancePair && !isLegacyColdPair) {
630 reportDiagnostic(
631 diagnostics,
632 "PSR_UNSUPPORTED_SCHEMA",
633 "Template manifest and component artifact are not an exact runtime contract pair",
634 { manifest_schema_version: manifest.schema_version, component_schema_version: componentArtifact?.schema_version },
635 true
636 );
637 throw new PresolveBootError("PSR_UNSUPPORTED_SCHEMA");
638 }
639
640 if (isOrdinaryInstancePair) {
641 for (const program of componentArtifact.structural_programs ?? []) {
642 const component = (manifest.components ?? []).find(
643 (candidate) => candidate.component_id === program.host_component
644 );
645 const host = component?.template?.nodes?.find((node) => node.id === program.host_node);
646 if (component === undefined || host === undefined
647 || (host.kind !== "conditional" && host.kind !== "list")) {
648 reportDiagnostic(
649 diagnostics,
650 "PSR_INVALID_COMPONENT_ARTIFACT",
651 "Structural component metadata did not resolve to an emitted conditional or keyed-list host",
652 { region: program.region, host_component: program.host_component, host_node: program.host_node },
653 true
654 );
655 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
656 }
657 if (host.kind === "list" && program.conditional_host_fragments.length !== 0) {
658 reportDiagnostic(
659 diagnostics,
660 "PSR_INVALID_COMPONENT_ARTIFACT",
661 "Conditional host fragments were attached to a keyed-list host",
662 { region: program.region, host_component: program.host_component, host_node: program.host_node },
663 true
664 );
665 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
666 }
667 if (host.kind === "conditional" && program.keyed_host_fragments.length !== 0) {
668 reportDiagnostic(
669 diagnostics,
670 "PSR_INVALID_COMPONENT_ARTIFACT",
671 "Keyed host fragments were attached to a conditional host",
672 { region: program.region, host_component: program.host_component, host_node: program.host_node },
673 true
674 );
675 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
676 }
677 }
678 }
679
680 if (
681 manifest.schema_version === LEGACY_MANIFEST_SCHEMA_VERSION &&
682 effectArtifactHasActionPlans(effectArtifact)
683 ) {
684 reportDiagnostic(
685 diagnostics,
686 "PSR_LEGACY_MANIFEST_EFFECT_ACTIONS",
687 "A legacy template manifest cannot activate compiler-generated effect action batches",
688 { schema_version: manifest.schema_version },
689 true
690 );
691 throw new PresolveBootError("PSR_LEGACY_MANIFEST_EFFECT_ACTIONS");
692 }
693
694 if (manifest.schema_version >= ACTION_MANIFEST_SCHEMA_VERSION) {
695 validateManifestActionBindings(
696 manifest,
697 opaqueArtifact,
698 packageInvocationsArtifact,
699 diagnostics
700 );
701 }
702 }
703
704 function readFormsArtifact(diagnostics) {
705 const element = document.getElementById(FORMS_ARTIFACT_ELEMENT_ID);
706 if (element === null) return null;
707 if (!(element instanceof HTMLScriptElement)) {
708 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Forms runtime metadata was not stored in a script element", { artifactElementId: FORMS_ARTIFACT_ELEMENT_ID }, true);
709 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
710 }
711 try { return JSON.parse(element.textContent ?? ""); } catch (error) {
712 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Forms runtime metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
713 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
714 }
715 }
716
717 function readResourcesArtifact(diagnostics) {
718 const element = document.getElementById(RESOURCES_ARTIFACT_ELEMENT_ID);
719 if (element === null) return null;
720 if (!(element instanceof HTMLScriptElement)) {
721 reportDiagnostic(diagnostics, "PSR_INVALID_RESOURCES_ARTIFACT", "Resource runtime metadata was not stored in a script element", { artifactElementId: RESOURCES_ARTIFACT_ELEMENT_ID }, true);
722 throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
723 }
724 try { return JSON.parse(element.textContent ?? ""); } catch (error) {
725 reportDiagnostic(diagnostics, "PSR_INVALID_RESOURCES_ARTIFACT", "Resource runtime metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
726 throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
727 }
728 }
729
730 function readOpaqueArtifact(diagnostics) {
731 const element = document.getElementById(OPAQUE_ARTIFACT_ELEMENT_ID);
732 if (element === null) return null;
733 if (!(element instanceof HTMLScriptElement)) {
734 reportDiagnostic(diagnostics, "PSR_INVALID_OPAQUE_ARTIFACT", "Opaque terminal metadata was not stored in a script element", { artifactElementId: OPAQUE_ARTIFACT_ELEMENT_ID }, true);
735 throw new PresolveBootError("PSR_INVALID_OPAQUE_ARTIFACT");
736 }
737 try { return JSON.parse(element.textContent ?? ""); } catch (error) {
738 reportDiagnostic(diagnostics, "PSR_INVALID_OPAQUE_ARTIFACT", "Opaque terminal metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
739 throw new PresolveBootError("PSR_INVALID_OPAQUE_ARTIFACT");
740 }
741 }
742
743 function validateOpaqueArtifact(opaqueArtifact, diagnostics) {
744 if (opaqueArtifact === null) return;
745 if (opaqueArtifact.schema_version !== SUPPORTED_OPAQUE_ARTIFACT_SCHEMA_VERSION
746 || !Array.isArray(opaqueArtifact.activations)) {
747 reportDiagnostic(diagnostics, "PSR_UNSUPPORTED_OPAQUE_ARTIFACT_SCHEMA", "Opaque terminal metadata did not match the compiler artifact contract", { schema_version: opaqueArtifact.schema_version }, true);
748 throw new PresolveBootError("PSR_UNSUPPORTED_OPAQUE_ARTIFACT_SCHEMA");
749 }
750 const ids = new Set();
751 const methods = new Set();
752 for (const activation of opaqueArtifact.activations) {
753 if (typeof activation?.id !== "string" || ids.has(activation.id)
754 || typeof activation?.method !== "string" || methods.has(activation.method)
755 || typeof activation?.owner_component !== "string"
756 || typeof activation?.package !== "string" || typeof activation?.version !== "string"
757 || typeof activation?.integrity !== "string" || typeof activation?.export !== "string"
758 || typeof activation?.runtime_module !== "string" || typeof activation?.runtime_location !== "string"
759 || activation?.type_signature !== "() -> void"
760 || activation?.execution_boundary !== "client" || activation?.resume_policy !== "cold_fallback") {
761 reportDiagnostic(diagnostics, "PSR_INVALID_OPAQUE_ARTIFACT", "Opaque terminal activation did not retain one exact callable client boundary", { activation }, true);
762 throw new PresolveBootError("PSR_INVALID_OPAQUE_ARTIFACT");
763 }
764 ids.add(activation.id);
765 methods.add(activation.method);
766 }
767 }
768
769 function readPackageInvocationsArtifact(diagnostics) {
770 const element = document.getElementById(PACKAGE_INVOCATIONS_ARTIFACT_ELEMENT_ID);
771 if (element === null) return null;
772 if (!(element instanceof HTMLScriptElement)) {
773 reportDiagnostic(diagnostics, "PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT", "Package invocation metadata was not stored in a script element", { artifactElementId: PACKAGE_INVOCATIONS_ARTIFACT_ELEMENT_ID }, true);
774 throw new PresolveBootError("PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT");
775 }
776 try { return JSON.parse(element.textContent ?? ""); } catch (error) {
777 reportDiagnostic(diagnostics, "PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT", "Package invocation metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
778 throw new PresolveBootError("PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT");
779 }
780 }
781
782 function validatePackageInvocationsArtifact(artifact, diagnostics) {
783 if (artifact === null) return;
784 if (artifact.schema_version !== SUPPORTED_PACKAGE_INVOCATIONS_ARTIFACT_SCHEMA_VERSION
785 || typeof artifact.registry_path !== "string"
786 || !Array.isArray(artifact.invocations)) {
787 reportDiagnostic(diagnostics, "PSR_UNSUPPORTED_PACKAGE_INVOCATIONS_ARTIFACT_SCHEMA", "Package invocation metadata did not match the compiler artifact contract", { schema_version: artifact.schema_version }, true);
788 throw new PresolveBootError("PSR_UNSUPPORTED_PACKAGE_INVOCATIONS_ARTIFACT_SCHEMA");
789 }
790 const ids = new Set();
791 const methods = new Set();
792 for (const invocation of artifact.invocations) {
793 if (typeof invocation?.id !== "string" || ids.has(invocation.id)
794 || typeof invocation?.method !== "string" || methods.has(invocation.method)
795 || typeof invocation?.owner_component !== "string"
796 || typeof invocation?.module_specifier !== "string"
797 || typeof invocation?.export !== "string"
798 || typeof invocation?.owner_source !== "string"
799 || !Array.isArray(invocation?.declaration_modules)
800 || invocation.declaration_modules.length === 0
801 || !Array.isArray(invocation.arguments)
802 || !invocation.arguments.every((argument, index) =>
803 argument?.event_argument_index === index
804 && ["string", "number", "boolean", "null"].includes(argument?.codec))
805 || !["synchronous", "promise"].includes(invocation.completion)
806 || typeof invocation.inject_abort_signal !== "boolean"
807 || (invocation.completion === "synchronous"
808 ? invocation.inject_abort_signal
809 || invocation.concurrency !== "none"
810 || invocation.cancellation !== "none"
811 : !invocation.inject_abort_signal
812 || invocation.concurrency !== "replace_previous_per_component_instance"
813 || invocation.cancellation !== "abort_on_replacement_teardown_or_pagehide")
814 || invocation.execution_boundary !== "client"
815 || invocation.resume_policy !== "restore_event_without_replay") {
816 reportDiagnostic(diagnostics, "PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT", "Package invocation metadata did not retain one exact compiler-authorized call boundary", { invocation }, true);
817 throw new PresolveBootError("PSR_INVALID_PACKAGE_INVOCATIONS_ARTIFACT");
818 }
819 ids.add(invocation.id);
820 methods.add(invocation.method);
821 }
822 }
823
824 async function loadPackageInvocationRegistry(artifact, diagnostics) {
825 if (artifact === null) return new Map();
826 let imported;
827 try {
828 imported = await import(new URL(artifact.registry_path, document.baseURI).href);
829 } catch (error) {
830 reportDiagnostic(diagnostics, "PSR_PACKAGE_INVOCATION_MODULE_FAILED", "The compiler-published package invocation module could not be loaded", {
831 path: artifact.registry_path,
832 message: error instanceof Error ? error.message : String(error)
833 }, true);
834 throw new PresolveBootError("PSR_PACKAGE_INVOCATION_MODULE_FAILED");
835 }
836 const registry = imported?.presolvePackageInvocations;
837 if (registry === null || typeof registry !== "object" || Array.isArray(registry)) {
838 reportDiagnostic(diagnostics, "PSR_PACKAGE_INVOCATION_MODULE_MISMATCH", "The package invocation module did not expose the compiler-issued registry", {}, true);
839 throw new PresolveBootError("PSR_PACKAGE_INVOCATION_MODULE_MISMATCH");
840 }
841 const callables = new Map();
842 for (const invocation of artifact.invocations) {
843 const callable = registry[invocation.id];
844 if (typeof callable !== "function") {
845 reportDiagnostic(diagnostics, "PSR_PACKAGE_INVOCATION_MODULE_MISMATCH", "A bundled package invocation was not callable", { invocation: invocation.id }, true);
846 throw new PresolveBootError("PSR_PACKAGE_INVOCATION_MODULE_MISMATCH");
847 }
848 callables.set(invocation.id, callable);
849 }
850 return callables;
851 }
852
853 function validateResourcesArtifact(resourcesArtifact, diagnostics) {
854 if (resourcesArtifact === null) return;
855 if (resourcesArtifact.schema_version !== SUPPORTED_RESOURCES_ARTIFACT_SCHEMA_VERSION
856 || !Array.isArray(resourcesArtifact.declarations)
857 || !Array.isArray(resourcesArtifact.activations)) {
858 reportDiagnostic(diagnostics, "PSR_UNSUPPORTED_RESOURCES_ARTIFACT_SCHEMA", "Resource runtime metadata did not match the compiler artifact contract", { schema_version: resourcesArtifact.schema_version }, true);
859 throw new PresolveBootError("PSR_UNSUPPORTED_RESOURCES_ARTIFACT_SCHEMA");
860 }
861 const declarations = new Set();
862 for (const declaration of resourcesArtifact.declarations) {
863 const endpoint = declaration?.endpoint;
864 if (typeof declaration?.id !== "string" || declarations.has(declaration.id)
865 || typeof endpoint?.package !== "string" || typeof endpoint?.version !== "string"
866 || typeof endpoint?.integrity !== "string" || typeof endpoint?.export !== "string"
867 || typeof endpoint?.runtime_module !== "string" || typeof endpoint?.runtime_location !== "string"
868 || !isValidResourceValueCodec(declaration?.data_codec)
869 || !isValidResourceValueCodec(declaration?.error_codec)) {
870 reportDiagnostic(diagnostics, "PSR_INVALID_RESOURCES_ARTIFACT", "Resource declaration did not retain one exact executable endpoint", { declaration }, true);
871 throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
872 }
873 declarations.add(declaration.id);
874 }
875 const activations = new Set();
876 for (const activation of resourcesArtifact.activations) {
877 const generationRequired = ["pending", "ready", "failed", "cancelled"].includes(activation?.state);
878 if (typeof activation?.id !== "string" || activations.has(activation.id)
879 || !declarations.has(activation?.declaration)
880 || generationRequired !== Number.isInteger(activation?.generation)
881 || !hasExactResourceResumeSlots(activation)) {
882 reportDiagnostic(diagnostics, "PSR_INVALID_RESOURCES_ARTIFACT", "Resource activation did not retain canonical lifecycle linkage", { activation }, true);
883 throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
884 }
885 activations.add(activation.id);
886 }
887 }
888
889 function hasExactResourceResumeSlots(activation) {
890 if (typeof activation?.id !== "string"
891 || typeof activation?.state_slot !== "string"
892 || typeof activation?.data_slot !== "string"
893 || typeof activation?.error_slot !== "string") return false;
894 const prefix = `${activation.id}/resource-slot:`;
895 return activation.state_slot === `${prefix}state`
896 && activation.data_slot === `${prefix}data`
897 && activation.error_slot === `${prefix}error`;
898 }
899
900 function isValidResourceValueCodec(codec, depth = 0) {
901 if (depth > 32 || codec === null || typeof codec !== "object" || Array.isArray(codec)) return false;
902 switch (codec.kind) {
903 case "null_codec":
904 case "boolean_codec":
905 case "number_codec":
906 case "string_codec":
907 return exactObjectKeys(codec, ["kind"]);
908 case "array_codec":
909 case "nullable_codec":
910 return exactObjectKeys(codec, ["kind", "value"])
911 && isValidResourceValueCodec(codec.value, depth + 1);
912 case "object_codec": {
913 if (!exactObjectKeys(codec, ["kind", "value"]) || !Array.isArray(codec.value)) return false;
914 const names = new Set();
915 return codec.value.every((property) => property !== null
916 && typeof property === "object" && !Array.isArray(property)
917 && exactObjectKeys(property, ["name", "codec"])
918 && typeof property.name === "string" && property.name.length > 0
919 && !names.has(property.name) && names.add(property.name)
920 && isValidResourceValueCodec(property.codec, depth + 1));
921 }
922 default:
923 return false;
924 }
925 }
926
927 function validateFormsArtifact(formsArtifact, manifest, diagnostics) {
928 if (formsArtifact === null) {
929 if (manifest.schema_version >= 3) {
930 reportDiagnostic(diagnostics, "PSR_MISSING_FORMS_ARTIFACT", "A schema-v3 template manifest requires Forms runtime metadata", {}, true);
931 throw new PresolveBootError("PSR_MISSING_FORMS_ARTIFACT");
932 }
933 return;
934 }
935 if (formsArtifact.schema_version !== SUPPORTED_FORMS_ARTIFACT_SCHEMA_VERSION || !Array.isArray(formsArtifact.forms) || !Array.isArray(formsArtifact.instances) || !Array.isArray(formsArtifact.hosts)) {
936 reportDiagnostic(diagnostics, "PSR_UNSUPPORTED_FORMS_ARTIFACT_SCHEMA", "Forms runtime metadata did not match the compiler artifact contract", { schema_version: formsArtifact.schema_version }, true);
937 throw new PresolveBootError("PSR_UNSUPPORTED_FORMS_ARTIFACT_SCHEMA");
938 }
939 for (const form of formsArtifact.forms) {
940 const paths = new Set();
941 const fieldIds = new Set((form?.fields ?? []).map((field) => field.id));
942 for (const field of form?.fields ?? []) {
943 if (!Array.isArray(field?.path) || field.path.length === 0 || field.path.length > 16
944 || !field.path.every((segment) => typeof segment === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(segment))) {
945 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Form Field path was not compiler-canonical", { field }, true);
946 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
947 }
948 const path = field.path.join(".");
949 if ([...paths].some((other) => path === other || path.startsWith(`${other}.`) || other.startsWith(`${path}.`))) {
950 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Form Field paths conflicted", { form: form.id, path }, true);
951 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
952 }
953 paths.add(path);
954 }
955 const ruleIds = new Set();
956 for (const rule of form?.validation_rules ?? []) {
957 if (typeof rule?.id !== "string" || !rule.id || ruleIds.has(rule.id)
958 || !fieldIds.has(rule.target_field)
959 || !isValidFormRuleArtifact(rule, fieldIds)) {
960 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Form validation rule was not compiler-canonical", { form: form.id, rule }, true);
961 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
962 }
963 ruleIds.add(rule.id);
964 }
965 }
966 const standardSchemaValidators = [...new Set(formsArtifact.forms
967 .flatMap((form) => form.validation_rules ?? [])
968 .filter((rule) => rule.kind === "StandardSchema")
969 .map((rule) => rule.argument.validator))].sort();
970 const standardSchemaModule = formsArtifact.standard_schema_module;
971 if (standardSchemaValidators.length === 0) {
972 if (standardSchemaModule !== undefined) {
973 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Unused Standard Schema runtime module was published", {}, true);
974 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
975 }
976 } else if (!exactObjectKeys(standardSchemaModule, ["path", "validators"])
977 || standardSchemaModule.path !== "/presolve.validators.js"
978 || !Array.isArray(standardSchemaModule.validators)
979 || JSON.stringify([...standardSchemaModule.validators].sort()) !== JSON.stringify(standardSchemaValidators)) {
980 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Standard Schema runtime module did not match validation rules", {}, true);
981 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
982 }
983 const submissionCapabilityIds = [...new Set(formsArtifact.forms
984 .map((form) => form?.submission?.capability)
985 .filter((capability) => typeof capability === "string"))].sort();
986 const submissionCapabilityModule = formsArtifact.submission_capability_module;
987 if (submissionCapabilityIds.length === 0) {
988 if (submissionCapabilityModule !== undefined) {
989 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Unused Form submission capability module was published", {}, true);
990 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
991 }
992 } else if (!exactObjectKeys(submissionCapabilityModule, ["path", "capabilities"])
993 || submissionCapabilityModule.path !== "/presolve.form-submissions.js"
994 || !Array.isArray(submissionCapabilityModule.capabilities)
995 || JSON.stringify(submissionCapabilityModule.capabilities.map((capability) => capability?.id).sort()) !== JSON.stringify(submissionCapabilityIds)
996 || !submissionCapabilityModule.capabilities.every((capability) =>
997 exactObjectKeys(capability, ["id", "module_specifier", "package", "version", "integrity", "export", "runtime_module", "resume_policy"])
998 && typeof capability.id === "string" && capability.id.length > 0
999 && typeof capability.module_specifier === "string" && capability.module_specifier.length > 0
1000 && typeof capability.package === "string" && capability.package.length > 0
1001 && typeof capability.version === "string" && capability.version.length > 0
1002 && typeof capability.integrity === "string" && /^sha256:[0-9a-fA-F]{64}$/.test(capability.integrity)
1003 && typeof capability.export === "string" && capability.export.length > 0
1004 && typeof capability.runtime_module === "string" && capability.runtime_module.length > 0
1005 && capability.resume_policy === "cold_fallback")) {
1006 reportDiagnostic(diagnostics, "PSR_INVALID_FORMS_ARTIFACT", "Form submission capability module did not match submission plans", {}, true);
1007 throw new PresolveBootError("PSR_INVALID_FORMS_ARTIFACT");
1008 }
1009 const hasForms = formsArtifact.forms.length > 0 || formsArtifact.instances.length > 0;
1010 if (hasForms && manifest.schema_version < 3) {
1011 reportDiagnostic(diagnostics, "PSR_FORMS_MANIFEST_MISMATCH", "Forms runtime metadata requires a schema-v3 template manifest", { schema_version: manifest.schema_version }, true);
1012 throw new PresolveBootError("PSR_FORMS_MANIFEST_MISMATCH");
1013 }
1014 const instances = new Set(formsArtifact.instances.map((instance) => instance.id));
1015 for (const binding of manifest.form_bindings ?? []) {
1016 if (!instances.has(binding.form_instance_id)) {
1017 reportDiagnostic(diagnostics, "PSR_FORMS_MANIFEST_MISMATCH", "Forms manifest bridge referenced an unknown Form instance", { binding }, true);
1018 throw new PresolveBootError("PSR_FORMS_MANIFEST_MISMATCH");
1019 }
1020 }
1021 const artifactHosts = new Map(formsArtifact.hosts.map((host) => [`${host.host_anchor}|${host.form_instance}`, host]));
1022 for (const host of manifest.form_hosts ?? []) {
1023 const artifact = artifactHosts.get(`${host.host_anchor}|${host.form_instance_id}`);
1024 if (artifact === undefined || artifact.id !== host.submission_host_id || artifact.event !== host.event || artifact.submit_action !== host.submit_action || artifact.action_batch !== host.action_batch || artifact.serialization_plan !== host.serialization_plan || artifact.prevent_default !== host.prevent_default) {
1025 reportDiagnostic(diagnostics, "PSR_FORMS_MANIFEST_MISMATCH", "Forms manifest host bridge did not match an exact compiler host record", { host }, true);
1026 throw new PresolveBootError("PSR_FORMS_MANIFEST_MISMATCH");
1027 }
1028 }
1029 }
1030
1031 function isValidFormRuleArtifact(rule, fieldIds) {
1032 const argument = rule?.argument;
1033 if (argument === null || typeof argument !== "object" || Array.isArray(argument)
1034 || typeof rule.kind !== "string") return false;
1035 if (rule.kind === "Required" || rule.kind === "Email") {
1036 return exactObjectKeys(argument, ["kind"]) && argument.kind === "none"
1037 && rule.dependency === undefined;
1038 }
1039 if (rule.kind === "Min" || rule.kind === "Max") {
1040 return exactObjectKeys(argument, ["kind", "value"]) && argument.kind === "number"
1041 && typeof argument.value === "string" && Number.isFinite(Number(argument.value))
1042 && rule.dependency === undefined;
1043 }
1044 if (rule.kind === "MinLength" || rule.kind === "MaxLength") {
1045 return exactObjectKeys(argument, ["kind", "value"]) && argument.kind === "length"
1046 && Number.isSafeInteger(argument.value) && argument.value >= 0
1047 && rule.dependency === undefined;
1048 }
1049 if (rule.kind === "Pattern") {
1050 if (!exactObjectKeys(argument, ["kind", "value"]) || argument.kind !== "pattern"
1051 || typeof argument.value !== "string" || rule.dependency !== undefined) return false;
1052 try { new RegExp(argument.value); } catch (_) { return false; }
1053 return true;
1054 }
1055 if (rule.kind === "Equals" || rule.kind === "NotEquals") {
1056 return exactObjectKeys(argument, ["kind", "field"]) && argument.kind === "field"
1057 && typeof argument.field === "string" && fieldIds.has(argument.field)
1058 && rule.dependency === argument.field;
1059 }
1060 if (rule.kind === "StandardSchema") {
1061 return exactObjectKeys(argument, ["kind", "validator"])
1062 && argument.kind === "standard_schema"
1063 && typeof argument.validator === "string" && argument.validator.length > 0
1064 && rule.dependency === undefined;
1065 }
1066 return false;
1067 }
1068
1069 async function loadStandardSchemaValidators(formsArtifact, diagnostics) {
1070 const runtimeModule = formsArtifact?.standard_schema_module;
1071 if (runtimeModule === undefined) return new Map();
1072 let imported;
1073 try {
1074 imported = await import(runtimeModule.path);
1075 } catch (error) {
1076 reportDiagnostic(diagnostics, "PSR_STANDARD_SCHEMA_MODULE_FAILED", "The compiler-published Standard Schema module could not be loaded", {
1077 path: runtimeModule.path,
1078 message: error instanceof Error ? error.message : String(error)
1079 }, true);
1080 throw new PresolveBootError("PSR_STANDARD_SCHEMA_MODULE_FAILED");
1081 }
1082 const registry = imported?.presolveStandardSchemaValidators;
1083 const expected = [...runtimeModule.validators].sort();
1084 if (registry === null || typeof registry !== "object" || Array.isArray(registry)
1085 || !expected.every((id) => Object.prototype.hasOwnProperty.call(registry, id))) {
1086 reportDiagnostic(diagnostics, "PSR_STANDARD_SCHEMA_MODULE_MISMATCH", "The Standard Schema module did not expose the compiler-issued validator registry", {}, true);
1087 throw new PresolveBootError("PSR_STANDARD_SCHEMA_MODULE_MISMATCH");
1088 }
1089 const validators = new Map();
1090 for (const id of expected) {
1091 const schema = registry[id];
1092 const protocol = schema?.["~standard"];
1093 if (protocol?.version !== 1 || typeof protocol.vendor !== "string"
1094 || typeof protocol.validate !== "function") {
1095 reportDiagnostic(diagnostics, "PSR_STANDARD_SCHEMA_MODULE_MISMATCH", "A bundled validator did not implement Standard Schema v1", { validator: id }, true);
1096 throw new PresolveBootError("PSR_STANDARD_SCHEMA_MODULE_MISMATCH");
1097 }
1098 validators.set(id, schema);
1099 }
1100 return validators;
1101 }
1102
1103 async function loadFormSubmissionCapabilities(formsArtifact, diagnostics) {
1104 const runtimeModule = formsArtifact?.submission_capability_module;
1105 if (runtimeModule === undefined) return new Map();
1106 let imported;
1107 try {
1108 imported = await import(runtimeModule.path);
1109 } catch (error) {
1110 reportDiagnostic(diagnostics, "PSR_FORM_SUBMISSION_MODULE_FAILED", "The compiler-published Form submission module could not be loaded", {
1111 path: runtimeModule.path,
1112 message: error instanceof Error ? error.message : String(error)
1113 }, true);
1114 throw new PresolveBootError("PSR_FORM_SUBMISSION_MODULE_FAILED");
1115 }
1116 const registry = imported?.presolveFormSubmissionCapabilities;
1117 const expected = runtimeModule.capabilities.map((capability) => capability.id).sort();
1118 if (registry === null || typeof registry !== "object" || Array.isArray(registry)
1119 || !expected.every((id) => Object.prototype.hasOwnProperty.call(registry, id))) {
1120 reportDiagnostic(diagnostics, "PSR_FORM_SUBMISSION_MODULE_MISMATCH", "The Form submission module did not expose the compiler-issued capability registry", {}, true);
1121 throw new PresolveBootError("PSR_FORM_SUBMISSION_MODULE_MISMATCH");
1122 }
1123 const capabilities = new Map();
1124 for (const id of expected) {
1125 if (typeof registry[id] !== "function") {
1126 reportDiagnostic(diagnostics, "PSR_FORM_SUBMISSION_MODULE_MISMATCH", "A bundled Form submission capability was not callable", { capability: id }, true);
1127 throw new PresolveBootError("PSR_FORM_SUBMISSION_MODULE_MISMATCH");
1128 }
1129 capabilities.set(id, registry[id]);
1130 }
1131 return capabilities;
1132 }
1133
1134 function readComputedArtifact(diagnostics) {
1135 const element = document.getElementById(COMPUTED_ARTIFACT_ELEMENT_ID);
1136
1137 if (element === null) {
1138 return null;
1139 }
1140
1141 if (!(element instanceof HTMLScriptElement)) {
1142 reportDiagnostic(
1143 diagnostics,
1144 "PSR_INVALID_COMPUTED_ARTIFACT",
1145 "Computed runtime metadata was not stored in a script element",
1146 { artifactElementId: COMPUTED_ARTIFACT_ELEMENT_ID },
1147 true
1148 );
1149 throw new PresolveBootError("PSR_INVALID_COMPUTED_ARTIFACT");
1150 }
1151
1152 try {
1153 return JSON.parse(element.textContent ?? "");
1154 } catch (error) {
1155 reportDiagnostic(
1156 diagnostics,
1157 "PSR_INVALID_COMPUTED_ARTIFACT",
1158 "Computed runtime metadata JSON could not be parsed",
1159 { message: error instanceof Error ? error.message : String(error) },
1160 true
1161 );
1162 throw new PresolveBootError("PSR_INVALID_COMPUTED_ARTIFACT");
1163 }
1164 }
1165
1166 function validateComputedArtifactSchema(artifact, diagnostics) {
1167 if (artifact === null) {
1168 return;
1169 }
1170
1171 if (artifact.schema_version !== SUPPORTED_COMPUTED_ARTIFACT_SCHEMA_VERSION) {
1172 reportDiagnostic(
1173 diagnostics,
1174 "PSR_UNSUPPORTED_COMPUTED_ARTIFACT_SCHEMA",
1175 `Unsupported computed runtime metadata schema version ${String(artifact.schema_version)}`,
1176 {
1177 schema_version: artifact.schema_version,
1178 supported_schema_version: SUPPORTED_COMPUTED_ARTIFACT_SCHEMA_VERSION
1179 },
1180 true
1181 );
1182 throw new PresolveBootError("PSR_UNSUPPORTED_COMPUTED_ARTIFACT_SCHEMA");
1183 }
1184 }
1185
1186 function readEffectArtifact(diagnostics) {
1187 const element = document.getElementById(EFFECT_ARTIFACT_ELEMENT_ID);
1188
1189 if (element === null) {
1190 return null;
1191 }
1192
1193 if (!(element instanceof HTMLScriptElement)) {
1194 reportDiagnostic(
1195 diagnostics,
1196 "PSR_INVALID_EFFECT_ARTIFACT",
1197 "Effect runtime metadata was not stored in a script element",
1198 { artifactElementId: EFFECT_ARTIFACT_ELEMENT_ID },
1199 true
1200 );
1201 throw new PresolveBootError("PSR_INVALID_EFFECT_ARTIFACT");
1202 }
1203
1204 try {
1205 return JSON.parse(element.textContent ?? "");
1206 } catch (error) {
1207 reportDiagnostic(
1208 diagnostics,
1209 "PSR_INVALID_EFFECT_ARTIFACT",
1210 "Effect runtime metadata JSON could not be parsed",
1211 { message: error instanceof Error ? error.message : String(error) },
1212 true
1213 );
1214 throw new PresolveBootError("PSR_INVALID_EFFECT_ARTIFACT");
1215 }
1216 }
1217
1218 function validateEffectArtifactSchema(artifact, diagnostics) {
1219 if (artifact === null) {
1220 return;
1221 }
1222
1223 if (artifact.schema_version !== SUPPORTED_EFFECT_ARTIFACT_SCHEMA_VERSION) {
1224 reportDiagnostic(
1225 diagnostics,
1226 "PSR_UNSUPPORTED_EFFECT_ARTIFACT_SCHEMA",
1227 `Unsupported effect runtime metadata schema version ${String(artifact.schema_version)}`,
1228 {
1229 schema_version: artifact.schema_version,
1230 supported_schema_version: SUPPORTED_EFFECT_ARTIFACT_SCHEMA_VERSION
1231 },
1232 true
1233 );
1234 throw new PresolveBootError("PSR_UNSUPPORTED_EFFECT_ARTIFACT_SCHEMA");
1235 }
1236 }
1237
1238 function validateEffectArtifactInstances(effectArtifact, componentArtifact, diagnostics) {
1239 if (effectArtifact === null) return;
1240 if (!Array.isArray(effectArtifact.instances) || !Array.isArray(effectArtifact.structural_templates)) {
1241 reportDiagnostic(diagnostics, "PSR_INVALID_EFFECT_INSTANCE_ARTIFACT", "Effect runtime metadata omitted instance ownership records", {}, true);
1242 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
1243 }
1244 if (effectArtifact.instances.length === 0 && effectArtifact.structural_templates.length === 0) return;
1245 if (componentArtifact === null) {
1246 reportDiagnostic(diagnostics, "PSR_INVALID_EFFECT_INSTANCE_ARTIFACT", "Instance-owned effects require a component runtime artifact", {}, true);
1247 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
1248 }
1249 const declarations = new Set((effectArtifact.effects ?? []).map((effect) => effect.effect));
1250 const instances = new Map((componentArtifact.instances ?? []).map((instance) => [instance.instance, instance]));
1251 const identities = new Set();
1252 for (const record of effectArtifact.instances) {
1253 const component = instances.get(record.component_instance);
1254 if (typeof record.effect_instance !== "string" || identities.has(record.effect_instance)
1255 || !declarations.has(record.effect) || component === undefined
1256 || record.parent_instance !== component.parent || record.depth !== component.depth
1257 || !Number.isInteger(record.declaration_order) || record.declaration_order < 0) {
1258 reportDiagnostic(diagnostics, "PSR_INVALID_EFFECT_INSTANCE_ARTIFACT", "Effect instance ownership did not match compiler component metadata", { effect_instance: record.effect_instance }, true);
1259 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
1260 }
1261 identities.add(record.effect_instance);
1262 }
1263 const regions = new Map((componentArtifact.structural_programs ?? []).map((program) => [program.region, program]));
1264 const occurrences = new Map();
1265 for (const program of regions.values()) {
1266 for (const occurrence of program.template_occurrences ?? []) {
1267 if (occurrences.has(occurrence.template_instance)) {
1268 reportDiagnostic(diagnostics, "PSR_INVALID_EFFECT_INSTANCE_ARTIFACT", "Structural effect templates did not have unique compiler occurrence ownership", { template_instance: occurrence.template_instance }, true);
1269 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
1270 }
1271 occurrences.set(occurrence.template_instance, { region: program.region, component: occurrence.component });
1272 }
1273 }
1274 const templateIdentities = new Set();
1275 for (const record of effectArtifact.structural_templates) {
1276 const occurrence = occurrences.get(record.template_instance);
1277 const expectedEffectInstance = `${String(record.template_instance ?? "")}/effect-instance:${String(record.effect ?? "")}`;
1278 if (typeof record.effect_instance !== "string" || templateIdentities.has(record.effect_instance)
1279 || record.effect_instance !== expectedEffectInstance
1280 || occurrence === undefined || record.structural_region !== occurrence.region
1281 || record.component !== occurrence.component || !declarations.has(record.effect)
1282 || !Number.isInteger(record.depth) || record.depth < 0
1283 || !Number.isInteger(record.declaration_order) || record.declaration_order < 0) {
1284 reportDiagnostic(diagnostics, "PSR_INVALID_EFFECT_INSTANCE_ARTIFACT", "Structural effect template metadata did not match compiler component metadata", { effect_instance: record.effect_instance }, true);
1285 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
1286 }
1287 templateIdentities.add(record.effect_instance);
1288 }
1289 }
1290
1291 function readComponentArtifact(diagnostics) {
1292 const element = document.getElementById(COMPONENT_ARTIFACT_ELEMENT_ID);
1293 if (element === null) return null;
1294 if (!(element instanceof HTMLScriptElement)) {
1295 reportDiagnostic(diagnostics, "PSR_INVALID_COMPONENT_ARTIFACT", "Component runtime metadata was not stored in a script element", { artifactElementId: COMPONENT_ARTIFACT_ELEMENT_ID }, true);
1296 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1297 }
1298 try { return JSON.parse(element.textContent ?? ""); } catch (error) {
1299 reportDiagnostic(diagnostics, "PSR_INVALID_COMPONENT_ARTIFACT", "Component runtime metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
1300 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1301 }
1302 }
1303
1304 function canonicalStateSlotId(componentInstanceId, storageId) {
1305 const encoded = [...new TextEncoder().encode(storageId)].map((byte) => {
1306 const unreserved = (byte >= 65 && byte <= 90)
1307 || (byte >= 97 && byte <= 122)
1308 || (byte >= 48 && byte <= 57)
1309 || byte === 45 || byte === 46 || byte === 95 || byte === 126;
1310 return unreserved ? String.fromCharCode(byte) : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
1311 }).join("");
1312 return `${componentInstanceId}/state-slot:${encoded}`;
1313 }
1314
1315 function validateComponentArtifactSchema(artifact, diagnostics) {
1316 if (artifact === null) return;
1317 if ((artifact.schema_version !== SUPPORTED_COMPONENT_ARTIFACT_SCHEMA_VERSION && artifact.schema_version !== LEGACY_COMPONENT_ARTIFACT_SCHEMA_VERSION) || !Array.isArray(artifact.instances) || !Array.isArray(artifact.initialization_batches)) {
1318 reportDiagnostic(diagnostics, "PSR_INVALID_COMPONENT_ARTIFACT", "Component runtime metadata did not match the compiler artifact contract", { schema_version: artifact.schema_version }, true);
1319 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1320 }
1321 const instances = new Set(artifact.instances.map((instance) => instance.instance));
1322 const instancesById = new Map(artifact.instances.map((instance) => [instance.instance, instance]));
1323 const structuralTemplates = new Set(
1324 (artifact.structural_programs ?? [])
1325 .flatMap((program) => program.template_instances ?? [])
1326 );
1327 const structuralTemplateComponents = new Map(
1328 (artifact.structural_programs ?? [])
1329 .flatMap((program) => (program.template_occurrences ?? []).map((occurrence) => [
1330 occurrence.template_instance,
1331 occurrence.component
1332 ]))
1333 );
1334 const stateSlots = new Set();
1335 const statePairs = new Set();
1336 const structuralStateSlots = new Set();
1337 const structuralStatePairs = new Set();
1338 const structuralComputedCacheSlots = new Set();
1339 const structuralComputedDirtySlots = new Set();
1340 const structuralComputedPairs = new Set();
1341 for (const instance of artifact.instances) if (
1342 instance.parent !== null
1343 && instance.parent !== undefined
1344 && !instances.has(instance.parent)
1345 && !structuralTemplates.has(instance.parent)
1346 ) {
1347 reportDiagnostic(diagnostics, "PSR_INVALID_COMPONENT_ARTIFACT", "Component runtime metadata referenced an unknown parent instance", { instance: instance.instance, parent: instance.parent }, true);
1348 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1349 }
1350 if (artifact.schema_version === SUPPORTED_COMPONENT_ARTIFACT_SCHEMA_VERSION) {
1351 if (!Array.isArray(artifact.structural_programs)) {
1352 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1353 }
1354 if (!Array.isArray(artifact.ordinary_template_targets)
1355 || !Array.isArray(artifact.ordinary_template_bindings)
1356 || !Array.isArray(artifact.ordinary_template_events)) {
1357 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1358 }
1359 const structuralRegions = new Set();
1360 const structuralHosts = new Set();
1361 const slotBindingCallees = new Map((artifact.slot_binding_programs ?? []).map((binding) => [binding.binding, binding.callee_instance]));
1362 for (const program of artifact.structural_programs) {
1363 const host = `${String(program.host_component)}\u001f${String(program.host_node)}`;
1364 if (typeof program.region !== "string" || program.region.length === 0
1365 || typeof program.host_component !== "string" || program.host_component.length === 0
1366 || typeof program.host_node !== "string" || program.host_node.length === 0
1367 || typeof program.host_template_entity !== "string" || program.host_template_entity.length === 0
1368 || structuralRegions.has(program.region) || structuralHosts.has(host)
1369 || !Array.isArray(program.conditional_host_fragments)
1370 || !Array.isArray(program.keyed_host_fragments)
1371 || !Array.isArray(program.template_instances)
1372 || !Array.isArray(program.template_occurrences)
1373 || program.template_occurrences.length !== program.template_instances.length
1374 || new Set(program.conditional_host_fragments.map((fragments) => fragments?.host_instance)).size !== program.conditional_host_fragments.length
1375 || program.conditional_host_fragments.some((fragments) => typeof fragments?.host_instance !== "string"
1376 || typeof fragments.host_scope !== "string"
1377 || (fragments.host_scope === "static-instance"
1378 ? instancesById.get(fragments.host_instance)?.component !== program.host_component
1379 : fragments.host_scope === "structural-occurrence"
1380 ? structuralTemplateComponents.get(fragments.host_instance) !== program.host_component
1381 : true)
1382 || typeof fragments.when_true_html !== "string" || fragments.when_true_html.length === 0
1383 || typeof fragments.when_false_html !== "string" || fragments.when_false_html.length === 0
1384 || !Array.isArray(fragments.when_true_invocations)
1385 || !Array.isArray(fragments.when_false_invocations)
1386 || !Array.isArray(fragments.slot_projection_bindings)
1387 || !Array.isArray(fragments.slot_projection_programs)
1388 || fragments.slot_projection_programs.length !== fragments.slot_projection_bindings.length
1389 || new Set(fragments.slot_projection_bindings).size !== fragments.slot_projection_bindings.length
1390 || fragments.slot_projection_bindings.some((binding) => slotBindingCallees.get(binding) !== fragments.host_instance)
1391 || fragments.slot_projection_programs.some((projection) => typeof projection?.binding !== "string"
1392 || !fragments.slot_projection_bindings.includes(projection.binding)
1393 || typeof projection.caller_instance !== "string" || typeof projection.content_owner_instance !== "string"
1394 || !Array.isArray(projection.target_ids) || !Array.isArray(projection.binding_ids)
1395 || !Array.isArray(projection.event_ids) || !Array.isArray(projection.nested_invocations))
1396 || new Set(fragments.when_true_invocations).size !== fragments.when_true_invocations.length
1397 || new Set(fragments.when_false_invocations).size !== fragments.when_false_invocations.length
1398 || [...fragments.when_true_invocations, ...fragments.when_false_invocations].some((invocation) =>
1399 !program.template_occurrences.some((occurrence) => occurrence.invocation === invocation)
1400 ))
1401 || new Set(program.keyed_host_fragments.map((fragments) => fragments?.host_instance)).size !== program.keyed_host_fragments.length
1402 || program.keyed_host_fragments.some((fragments) => typeof fragments?.host_instance !== "string"
1403 || typeof fragments.host_scope !== "string"
1404 || (fragments.host_scope === "static-instance"
1405 ? instancesById.get(fragments.host_instance)?.component !== program.host_component
1406 : fragments.host_scope === "structural-occurrence"
1407 ? structuralTemplateComponents.get(fragments.host_instance) !== program.host_component
1408 : true)
1409 || typeof fragments.item_template_html !== "string" || fragments.item_template_html.length === 0
1410 || !Array.isArray(fragments.item_invocations)
1411 || !Array.isArray(fragments.slot_projection_bindings)
1412 || !Array.isArray(fragments.slot_projection_programs)
1413 || fragments.slot_projection_programs.length !== fragments.slot_projection_bindings.length
1414 || new Set(fragments.slot_projection_bindings).size !== fragments.slot_projection_bindings.length
1415 || fragments.slot_projection_bindings.some((binding) => slotBindingCallees.get(binding) !== fragments.host_instance)
1416 || fragments.slot_projection_programs.some((projection) => typeof projection?.binding !== "string"
1417 || !fragments.slot_projection_bindings.includes(projection.binding)
1418 || typeof projection.caller_instance !== "string" || typeof projection.content_owner_instance !== "string"
1419 || !Array.isArray(projection.target_ids) || !Array.isArray(projection.binding_ids)
1420 || !Array.isArray(projection.event_ids) || !Array.isArray(projection.nested_invocations))
1421 || new Set(fragments.item_invocations).size !== fragments.item_invocations.length
1422 || fragments.item_invocations.some((invocation) =>
1423 !program.template_occurrences.some((occurrence) => occurrence.invocation === invocation)
1424 ))
1425 || program.template_occurrences.some((occurrence, index) => typeof occurrence?.template_instance !== "string"
1426 || occurrence.template_instance !== program.template_instances[index]
1427 || typeof occurrence.invocation !== "string" || typeof occurrence.invocation_template_entity !== "string"
1428 || occurrence.invocation_template_entity.length === 0 || typeof occurrence.component !== "string"
1429 || typeof occurrence.template_html !== "string" || occurrence.template_html.length === 0
1430 || !Array.isArray(occurrence.nested_invocations)
1431 || new Set(occurrence.nested_invocations).size !== occurrence.nested_invocations.length
1432 || occurrence.nested_invocations.some((invocation) => !program.template_occurrences.some((candidate) => candidate.invocation === invocation))
1433 || !Array.isArray(occurrence.state_slots)
1434 || !Array.isArray(occurrence.computed_slots)
1435 || !Array.isArray(occurrence.ordinary_template_targets)
1436 || !Array.isArray(occurrence.ordinary_template_bindings)
1437 || !Array.isArray(occurrence.ordinary_template_events)
1438 || occurrence.state_slots.some((slot) => {
1439 const pair = `${occurrence.template_instance}|${slot?.storage_id}`;
1440 return typeof slot?.slot_id !== "string"
1441 || slot.slot_id !== canonicalStateSlotId(occurrence.template_instance, slot.storage_id)
1442 || typeof slot.state_id !== "string"
1443 || slot.state_id.length === 0
1444 || typeof slot.storage_id !== "string"
1445 || slot.storage_id !== `storage:${slot.state_id}`
1446 || typeof slot.semantic_type !== "string"
1447 || slot.semantic_type.length === 0
1448 || typeof slot.serializable !== "boolean"
1449 || structuralStateSlots.has(slot.slot_id)
1450 || structuralStatePairs.has(pair)
1451 || !structuralStateSlots.add(slot.slot_id)
1452 || !structuralStatePairs.add(pair);
1453 })
1454 || occurrence.computed_slots.some((slot) => {
1455 const pair = `${occurrence.template_instance}|${slot?.computed_id}`;
1456 return typeof slot?.computed_id !== "string"
1457 || slot.computed_id.length === 0
1458 || typeof slot?.cache_slot_id !== "string"
1459 || typeof slot?.dirty_slot_id !== "string"
1460 || !slot.cache_slot_id.startsWith(`${occurrence.template_instance}/computed-cache:`)
1461 || !slot.dirty_slot_id.startsWith(`${occurrence.template_instance}/computed-dirty:`)
1462 || typeof slot.dirty_initial_value !== "boolean"
1463 || structuralComputedCacheSlots.has(slot.cache_slot_id)
1464 || structuralComputedDirtySlots.has(slot.dirty_slot_id)
1465 || structuralComputedPairs.has(pair)
1466 || !structuralComputedCacheSlots.add(slot.cache_slot_id)
1467 || !structuralComputedDirtySlots.add(slot.dirty_slot_id)
1468 || !structuralComputedPairs.add(pair);
1469 })
1470 || JSON.stringify(occurrence.ordinary_template_targets) !== JSON.stringify(
1471 artifact.ordinary_template_targets
1472 .filter((target) => target.component_instance_id === occurrence.template_instance)
1473 .map((target) => target.id)
1474 )
1475 || JSON.stringify(occurrence.ordinary_template_bindings) !== JSON.stringify(
1476 artifact.ordinary_template_bindings
1477 .filter((binding) => binding.component_instance_id === occurrence.template_instance)
1478 .map((binding) => binding.id)
1479 )
1480 || JSON.stringify(occurrence.ordinary_template_events) !== JSON.stringify(
1481 artifact.ordinary_template_events
1482 .filter((event) => event.component_instance_id === occurrence.template_instance)
1483 .map((event) => event.declaration_event_id)
1484 ))
1485 || JSON.stringify(program.create_order) !== JSON.stringify(program.template_instances)
1486 || JSON.stringify([...(program.destroy_order ?? [])].reverse()) !== JSON.stringify(program.template_instances)) {
1487 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1488 }
1489 structuralRegions.add(program.region);
1490 structuralHosts.add(host);
1491 }
1492 for (const instance of artifact.instances) {
1493 if (!Array.isArray(instance.state_slots)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1494 for (const slot of instance.state_slots) {
1495 const pair = `${instance.instance}|${slot.storage_id}`;
1496 if (
1497 typeof slot.slot_id !== "string"
1498 || slot.slot_id !== canonicalStateSlotId(instance.instance, slot.storage_id)
1499 || typeof slot.state_id !== "string"
1500 || typeof slot.storage_id !== "string"
1501 || slot.storage_id !== `storage:${slot.state_id}`
1502 || stateSlots.has(slot.slot_id)
1503 || statePairs.has(pair)
1504 ) {
1505 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1506 }
1507 stateSlots.add(slot.slot_id);
1508 statePairs.add(pair);
1509 }
1510 }
1511 }
1512 }
1513
1514 function readContextArtifact(diagnostics) {
1515 const element = document.getElementById(CONTEXT_ARTIFACT_ELEMENT_ID);
1516 if (!(element instanceof HTMLScriptElement)) {
1517 reportDiagnostic(diagnostics, "PSR_INVALID_CONTEXT_ARTIFACT", "Context runtime metadata was not stored in a script element", { artifactElementId: CONTEXT_ARTIFACT_ELEMENT_ID }, true);
1518 throw new PresolveBootError("PSR_INVALID_CONTEXT_ARTIFACT");
1519 }
1520 try { return JSON.parse(element.textContent ?? ""); }
1521 catch (error) {
1522 reportDiagnostic(diagnostics, "PSR_INVALID_CONTEXT_ARTIFACT", "Context runtime metadata JSON could not be parsed", { message: error instanceof Error ? error.message : String(error) }, true);
1523 throw new PresolveBootError("PSR_INVALID_CONTEXT_ARTIFACT");
1524 }
1525 }
1526
1527 function validateContextArtifactSchema(artifact, diagnostics) {
1528 if (artifact.schema_version !== SUPPORTED_CONTEXT_ARTIFACT_SCHEMA_VERSION) {
1529 reportDiagnostic(diagnostics, "PSR_UNSUPPORTED_CONTEXT_ARTIFACT_SCHEMA", `Unsupported Context runtime metadata schema version ${String(artifact.schema_version)}`, { schema_version: artifact.schema_version, supported_schema_version: SUPPORTED_CONTEXT_ARTIFACT_SCHEMA_VERSION }, true);
1530 throw new PresolveBootError("PSR_UNSUPPORTED_CONTEXT_ARTIFACT_SCHEMA");
1531 }
1532 }
1533
1534 function fieldNameFromThisMember(expression) {
1535 const match = /^this\.([A-Za-z_$][\w$]*)$/.exec(String(expression ?? ""));
1536 return match === null ? null : match[1];
1537 }
1538
1539 function collectBindingAnchors() {
1540 const anchors = new Map();
1541 const walker = document.createTreeWalker(
1542 document.body,
1543 NodeFilter.SHOW_COMMENT
1544 );
1545
1546 while (walker.nextNode()) {
1547 const value = (walker.currentNode.nodeValue ?? "").trim();
1548 const match = /^presolve-binding:([^:]+):(.*)$/.exec(value);
1549
1550 if (match !== null) {
1551 anchors.set(match[1], {
1552 id: match[1],
1553 expression: match[2],
1554 marker: walker.currentNode
1555 });
1556 }
1557 }
1558
1559 return anchors;
1560 }
1561
1562 function collectConditionalAnchors() {
1563 const starts = new Map();
1564 const ends = new Map();
1565 const walker = document.createTreeWalker(
1566 document.body,
1567 NodeFilter.SHOW_COMMENT
1568 );
1569
1570 while (walker.nextNode()) {
1571 const value = (walker.currentNode.nodeValue ?? "").trim();
1572 const startMatch = /^presolve-conditional-start:([^:]+):(.*)$/.exec(value);
1573
1574 if (startMatch !== null) {
1575 starts.set(startMatch[1], {
1576 id: startMatch[1],
1577 condition: startMatch[2],
1578 marker: walker.currentNode
1579 });
1580 continue;
1581 }
1582
1583 const endMatch = /^presolve-conditional-end:([^:]+)$/.exec(value);
1584
1585 if (endMatch !== null) {
1586 ends.set(endMatch[1], {
1587 id: endMatch[1],
1588 marker: walker.currentNode
1589 });
1590 }
1591 }
1592
1593 return {
1594 starts,
1595 ends
1596 };
1597 }
1598
1599 function collectListAnchors() {
1600 const starts = new Map();
1601 const ends = new Map();
1602 const walker = document.createTreeWalker(
1603 document.body,
1604 NodeFilter.SHOW_COMMENT
1605 );
1606
1607 while (walker.nextNode()) {
1608 const value = (walker.currentNode.nodeValue ?? "").trim();
1609 const startMatch = /^presolve-list-start:([^:]+):(.*)$/.exec(value);
1610
1611 if (startMatch !== null) {
1612 starts.set(startMatch[1], {
1613 id: startMatch[1],
1614 iterable: startMatch[2],
1615 marker: walker.currentNode
1616 });
1617 continue;
1618 }
1619
1620 const endMatch = /^presolve-list-end:([^:]+)$/.exec(value);
1621
1622 if (endMatch !== null) {
1623 ends.set(endMatch[1], {
1624 id: endMatch[1],
1625 marker: walker.currentNode
1626 });
1627 }
1628 }
1629
1630 return {
1631 starts,
1632 ends
1633 };
1634 }
1635
1636 function collectElementAnchors() {
1637 const elementsByNode = new Map();
1638
1639 for (const element of document.querySelectorAll("[data-presolve-node]")) {
1640 elementsByNode.set(element.dataset.presolveNode, element);
1641 }
1642
1643 return elementsByNode;
1644 }
1645
1646 function collectMissingAnchors(
1647 manifest,
1648 bindingAnchors,
1649 conditionalAnchors,
1650 listAnchors,
1651 elementsByNode
1652 ) {
1653 const missing = [];
1654
1655 for (const component of manifest.components ?? []) {
1656 for (const node of component.template?.nodes ?? []) {
1657 if (node.kind === "element") {
1658 if (!elementsByNode.has(node.id)) {
1659 missing.push({
1660 component: component.name,
1661 id: node.id,
1662 kind: node.kind,
1663 code: "PSR_MISSING_ELEMENT_ANCHOR"
1664 });
1665 }
1666 }
1667
1668 if (
1669 node.kind === "binding" &&
1670 node.target !== "attribute" &&
1671 !bindingAnchors.has(node.id)
1672 ) {
1673 missing.push({
1674 component: component.name,
1675 id: node.id,
1676 kind: node.kind,
1677 code: "PSR_MISSING_BINDING_ANCHOR"
1678 });
1679 }
1680
1681 if (node.kind === "conditional") {
1682 if (!conditionalAnchors.starts.has(node.start)) {
1683 missing.push({
1684 component: component.name,
1685 id: node.start,
1686 kind: node.kind,
1687 code: "PSR_MISSING_CONDITIONAL_ANCHOR"
1688 });
1689 }
1690
1691 if (!conditionalAnchors.ends.has(node.end)) {
1692 missing.push({
1693 component: component.name,
1694 id: node.end,
1695 kind: node.kind,
1696 code: "PSR_MISSING_CONDITIONAL_ANCHOR"
1697 });
1698 }
1699 }
1700
1701 if (node.kind === "list") {
1702 if (!listAnchors.starts.has(node.start)) {
1703 missing.push({
1704 component: component.name,
1705 id: node.start,
1706 kind: node.kind,
1707 code: "PSR_MISSING_LIST_ANCHOR"
1708 });
1709 }
1710
1711 if (!listAnchors.ends.has(node.end)) {
1712 missing.push({
1713 component: component.name,
1714 id: node.end,
1715 kind: node.kind,
1716 code: "PSR_MISSING_LIST_ANCHOR"
1717 });
1718 }
1719 }
1720 }
1721 }
1722
1723 return missing;
1724 }
1725
1726 function buildActionsByMethod(component) {
1727 const actionsByMethod = new Map();
1728 const legacyActionsByMethod = new Map();
1729
1730 for (const action of component.actions ?? []) {
1731 if (legacyActionBinding(action)) {
1732 const actions = legacyActionsByMethod.get(action.method) ?? [];
1733 actions.push(action);
1734 legacyActionsByMethod.set(action.method, actions);
1735 continue;
1736 }
1737 const record = actionsByMethod.get(action.method_id) ?? {
1738 action_batch_id: action.action_batch_id,
1739 actions: []
1740 };
1741 record.actions.push(action);
1742 actionsByMethod.set(action.method_id, record);
1743 }
1744
1745 return { actionsByMethod, legacyActionsByMethod };
1746 }
1747
1748 function componentFieldKey(componentName, field) {
1749 return `${componentName}:${field}`;
1750 }
1751
1752 function formatBindingValue(value) {
1753 return value === null ? "" : String(value);
1754 }
1755
1756 function isBooleanAttribute(attribute) {
1757 return new Set([
1758 "allowfullscreen",
1759 "async",
1760 "autofocus",
1761 "autoplay",
1762 "checked",
1763 "controls",
1764 "default",
1765 "defer",
1766 "disabled",
1767 "formnovalidate",
1768 "hidden",
1769 "inert",
1770 "loop",
1771 "multiple",
1772 "muted",
1773 "nomodule",
1774 "novalidate",
1775 "open",
1776 "readonly",
1777 "required",
1778 "reversed",
1779 "selected"
1780 ]).has(String(attribute).toLowerCase());
1781 }
1782
1783 function isPropertyAttribute(attribute) {
1784 return new Set([
1785 "checked",
1786 "disabled",
1787 "selected",
1788 "value"
1789 ]).has(String(attribute).toLowerCase());
1790 }
1791
1792 function updateAttributeBinding(element, attribute, value) {
1793 const normalizedAttribute = String(attribute);
1794
1795 if (isBooleanAttribute(normalizedAttribute)) {
1796 const enabled = Boolean(value);
1797 element.toggleAttribute(normalizedAttribute, enabled);
1798
1799 if (isPropertyAttribute(normalizedAttribute) && normalizedAttribute in element) {
1800 element[normalizedAttribute] = enabled;
1801 }
1802
1803 return;
1804 }
1805
1806 if (value === null || value === undefined) {
1807 element.removeAttribute(normalizedAttribute);
1808
1809 if (isPropertyAttribute(normalizedAttribute) && normalizedAttribute in element) {
1810 element[normalizedAttribute] = "";
1811 }
1812
1813 return;
1814 }
1815
1816 const text = formatBindingValue(value);
1817 element.setAttribute(normalizedAttribute, text);
1818
1819 if (isPropertyAttribute(normalizedAttribute) && normalizedAttribute in element) {
1820 element[normalizedAttribute] = text;
1821 }
1822 }
1823
1824 function replaceConditionalBranch(store, startMarker, endMarker, html) {
1825 if (
1826 startMarker.parentNode === null ||
1827 endMarker.parentNode === null ||
1828 startMarker.parentNode !== endMarker.parentNode
1829 ) {
1830 reportDiagnostic(
1831 store.diagnostics,
1832 "PSR_MISSING_CONDITIONAL_ANCHOR",
1833 "Conditional anchor range was not contiguous in one parent",
1834 {}
1835 );
1836 return;
1837 }
1838
1839 let current = startMarker.nextSibling;
1840
1841 while (current !== null && current !== endMarker) {
1842 const next = current.nextSibling;
1843 current.remove();
1844 current = next;
1845 }
1846
1847 const template = document.createElement("template");
1848 template.innerHTML = String(html ?? "");
1849 endMarker.parentNode.insertBefore(template.content, endMarker);
1850 store.elementsByNode = collectElementAnchors();
1851 }
1852
1853 function listItems(value) {
1854 return Array.isArray(value) ? value : [];
1855 }
1856
1857 function normalizeListKey(value) {
1858 return String(value).replaceAll("--", "—");
1859 }
1860
1861 function listItemMemberPath(node, expression) {
1862 const prefix = `${String(node.item_variable ?? "")}.`;
1863 const value = String(expression ?? "");
1864
1865 if (!value.startsWith(prefix)) {
1866 return null;
1867 }
1868
1869 const path = value.slice(prefix.length).split(".");
1870 return path.length === 0 || path.some((member) => member === "") ? null : path;
1871 }
1872
1873 function listItemMemberValue(node, item, expression) {
1874 const path = listItemMemberPath(node, expression);
1875
1876 if (path === null) {
1877 return undefined;
1878 }
1879
1880 let value = item;
1881
1882 for (const member of path) {
1883 if (
1884 value === null ||
1885 typeof value !== "object" ||
1886 Array.isArray(value) ||
1887 !Object.prototype.hasOwnProperty.call(value, member)
1888 ) {
1889 return undefined;
1890 }
1891
1892 value = value[member];
1893 }
1894
1895 return value;
1896 }
1897
1898 function listItemBindingValue(node, item, index, expression) {
1899 if (expression === node.item_variable) {
1900 return item;
1901 }
1902
1903 if (expression === node.index_variable) {
1904 return index;
1905 }
1906
1907 if (listItemMemberPath(node, expression) !== null) {
1908 return listItemMemberValue(node, item, expression);
1909 }
1910
1911 return undefined;
1912 }
1913
1914 function isListKeyPrimitive(value) {
1915 return value === null || (typeof value !== "object" && typeof value !== "undefined");
1916 }
1917
1918 function listItemKey(node, item, index) {
1919 if (node.key_expression === node.item_variable) {
1920 return isListKeyPrimitive(item) ? normalizeListKey(item) : String(index);
1921 }
1922
1923 if (listItemMemberPath(node, node.key_expression) !== null) {
1924 const value = listItemMemberValue(node, item, node.key_expression);
1925 return isListKeyPrimitive(value) ? normalizeListKey(value) : String(index);
1926 }
1927
1928 if (node.index_variable === node.key_expression) {
1929 return String(index);
1930 }
1931
1932 return String(index);
1933 }
1934
1935 const STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX = "presolve-structural-occurrence:v1:";
1936
1937 function structuralOccurrenceHex(value) {
1938 if (typeof value !== "string" || value.length === 0) {
1939 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1940 }
1941 return [...new TextEncoder().encode(value)]
1942 .map((byte) => byte.toString(16).toUpperCase().padStart(2, "0"))
1943 .join("");
1944 }
1945
1946 function structuralOccurrenceIdentity(parentScope, region, templateInstance, localOccurrence) {
1947 return `${STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX}${structuralOccurrenceHex(parentScope)}.${structuralOccurrenceHex(region)}.${structuralOccurrenceHex(templateInstance)}.${structuralOccurrenceHex(localOccurrence)}`;
1948 }
1949
1950 function decodeStructuralOccurrenceIdentity(value) {
1951 if (typeof value !== "string" || !value.startsWith(STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX)) {
1952 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1953 }
1954 const fields = value.slice(STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX.length).split(".");
1955 if (fields.length !== 4 || fields.some((field) => field.length === 0 || field.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(field))) {
1956 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1957 }
1958 let decoded;
1959 try {
1960 decoded = fields.map((field) => new TextDecoder("utf-8", { fatal: true }).decode(Uint8Array.from(
1961 field.match(/../g).map((pair) => Number.parseInt(pair, 16))
1962 )));
1963 } catch (_) {
1964 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1965 }
1966 if (decoded.some((field) => field.length === 0)) {
1967 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1968 }
1969 return Object.freeze({
1970 parent_scope: decoded[0],
1971 region: decoded[1],
1972 template_instance: decoded[2],
1973 local_occurrence: decoded[3]
1974 });
1975 }
1976
1977 function instantiateStructuralTemplateSlots(occurrence, occurrenceIdentity) {
1978 decodeStructuralOccurrenceIdentity(occurrenceIdentity);
1979 const templateInstance = String(occurrence?.template_instance ?? "");
1980 const prefix = `${templateInstance}/`;
1981 if (templateInstance.length === 0
1982 || !Array.isArray(occurrence?.state_slots)
1983 || !Array.isArray(occurrence?.computed_slots)) {
1984 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1985 }
1986 const ids = new Set();
1987 const stateSlots = occurrence.state_slots.map((slot) => {
1988 if (typeof slot?.slot_id !== "string" || !slot.slot_id.startsWith(`${prefix}state-slot:`)
1989 || typeof slot.storage_id !== "string" || !slot.storage_id.startsWith("storage:")) {
1990 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1991 }
1992 const slotId = `${occurrenceIdentity}/${slot.slot_id.slice(prefix.length)}`;
1993 if (ids.has(slotId)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
1994 ids.add(slotId);
1995 return Object.freeze({ ...slot, slot_id: slotId });
1996 });
1997 const computedSlots = occurrence.computed_slots.map((slot) => {
1998 if (typeof slot?.cache_slot_id !== "string" || !slot.cache_slot_id.startsWith(`${prefix}computed-cache:`)
1999 || typeof slot.dirty_slot_id !== "string" || !slot.dirty_slot_id.startsWith(`${prefix}computed-dirty:`)) {
2000 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2001 }
2002 const cacheSlotId = `${occurrenceIdentity}/${slot.cache_slot_id.slice(prefix.length)}`;
2003 const dirtySlotId = `${occurrenceIdentity}/${slot.dirty_slot_id.slice(prefix.length)}`;
2004 if (ids.has(cacheSlotId) || ids.has(dirtySlotId)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2005 ids.add(cacheSlotId);
2006 ids.add(dirtySlotId);
2007 return Object.freeze({ ...slot, cache_slot_id: cacheSlotId, dirty_slot_id: dirtySlotId });
2008 });
2009 return Object.freeze({ state_slots: stateSlots, computed_slots: computedSlots });
2010 }
2011
2012 function rewriteStructuralTemplateIdentity(templateInstance, occurrenceIdentity, value) {
2013 if (typeof templateInstance !== "string" || templateInstance.length === 0
2014 || typeof occurrenceIdentity !== "string" || typeof value !== "string") {
2015 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2016 }
2017 const prefix = `${templateInstance}/`;
2018 if (!value.startsWith(prefix)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2019 return `${occurrenceIdentity}/${value.slice(prefix.length)}`;
2020 }
2021
2022 function deriveStructuralOccurrenceRecords(templateRecord, occurrenceIdentity) {
2023 const decoded = decodeStructuralOccurrenceIdentity(occurrenceIdentity);
2024 const occurrence = templateRecord?.occurrence;
2025 const templateInstance = String(occurrence?.template_instance ?? "");
2026 if (templateInstance.length === 0
2027 || decoded.template_instance !== templateInstance
2028 || typeof templateRecord?.structural_region !== "string"
2029 || decoded.region !== templateRecord.structural_region
2030 || !Array.isArray(templateRecord?.targets)
2031 || !Array.isArray(templateRecord?.bindings)
2032 || !Array.isArray(templateRecord?.events)) {
2033 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2034 }
2035 const slots = instantiateStructuralTemplateSlots(occurrence, occurrenceIdentity);
2036 const targetIds = new Set();
2037 const bindingIds = new Set();
2038 const eventKeys = new Set();
2039 const targets = templateRecord.targets.map((pair) => {
2040 const artifact = pair?.artifact;
2041 const manifest = pair?.manifest;
2042 const id = rewriteStructuralTemplateIdentity(templateInstance, occurrenceIdentity, artifact?.id);
2043 if (manifest?.id !== artifact?.id || targetIds.has(id)) {
2044 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2045 }
2046 targetIds.add(id);
2047 return Object.freeze({
2048 artifact: Object.freeze({ ...artifact, id, component_instance_id: occurrenceIdentity }),
2049 manifest: Object.freeze({ ...manifest, id, component_instance_id: occurrenceIdentity })
2050 });
2051 });
2052 const bindings = templateRecord.bindings.map((pair) => {
2053 const artifact = pair?.artifact;
2054 const manifest = pair?.manifest;
2055 const id = rewriteStructuralTemplateIdentity(templateInstance, occurrenceIdentity, artifact?.id);
2056 const targetId = rewriteStructuralTemplateIdentity(templateInstance, occurrenceIdentity, artifact?.target_id);
2057 if (manifest?.instance_binding_id !== artifact?.id
2058 || manifest?.instance_target_id !== artifact?.target_id
2059 || !targetIds.has(targetId)
2060 || bindingIds.has(id)) {
2061 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2062 }
2063 bindingIds.add(id);
2064 return Object.freeze({
2065 artifact: Object.freeze({ ...artifact, id, target_id: targetId, component_instance_id: occurrenceIdentity }),
2066 manifest: Object.freeze({ ...manifest, instance_binding_id: id, instance_target_id: targetId, component_instance_id: occurrenceIdentity })
2067 });
2068 });
2069 const events = templateRecord.events.map((pair) => {
2070 const artifact = pair?.artifact;
2071 const manifest = pair?.manifest;
2072 const targetId = rewriteStructuralTemplateIdentity(templateInstance, occurrenceIdentity, artifact?.target_id);
2073 const key = ordinaryEventKey(targetId, artifact?.event_type);
2074 if (manifest?.instance_target_id !== artifact?.target_id
2075 || !targetIds.has(targetId)
2076 || eventKeys.has(key)) {
2077 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2078 }
2079 eventKeys.add(key);
2080 return Object.freeze({
2081 artifact: Object.freeze({ ...artifact, target_id: targetId, component_instance_id: occurrenceIdentity }),
2082 manifest: Object.freeze({ ...manifest, instance_target_id: targetId, component_instance_id: occurrenceIdentity })
2083 });
2084 });
2085 return Object.freeze({
2086 occurrence_identity: occurrenceIdentity,
2087 parent_scope: decoded.parent_scope,
2088 structural_region: templateRecord.structural_region,
2089 template_instance: templateInstance,
2090 occurrence,
2091 component: occurrence.component,
2092 definition: templateRecord.definition,
2093 state_slots: slots.state_slots,
2094 computed_slots: slots.computed_slots,
2095 targets: Object.freeze(targets),
2096 bindings: Object.freeze(bindings),
2097 events: Object.freeze(events)
2098 });
2099 }
2100
2101 function stageStructuralOccurrenceRecords(store, records) {
2102 const instanceId = String(records?.occurrence_identity ?? "");
2103 const componentId = String(records?.component ?? "");
2104 const definition = records?.definition;
2105 if (instanceId.length === 0 || componentId.length === 0 || definition === undefined
2106 || store.components.has(instanceId) || store.componentInstances.has(instanceId)) {
2107 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2108 }
2109 const statePairs = [];
2110 const computedPairs = [];
2111 let component = null;
2112 let staged = false;
2113 const rollback = () => {
2114 if (!staged) return;
2115 for (const [pair, slot] of statePairs) {
2116 store.stateSlotsByInstanceStorage.delete(pair);
2117 store.storageValues.delete(slot.slot_id);
2118 store.bindingsByStateSlot.delete(slot.slot_id);
2119 }
2120 for (const [pair, slot] of computedPairs) {
2121 store.computedSlotsByInstanceComputed.delete(pair);
2122 store.computedDirtySlots.delete(slot.dirty_slot_id);
2123 store.computedCaches.delete(slot.cache_slot_id);
2124 store.bindingsByInstanceComputed.delete(pair);
2125 }
2126 store.components.delete(instanceId);
2127 store.componentInstances.delete(instanceId);
2128 staged = false;
2129 };
2130 try {
2131 for (const slot of records.state_slots ?? []) {
2132 const pair = `${instanceId}|${slot.storage_id}`;
2133 if (store.stateSlotsByInstanceStorage.has(pair) || store.storageValues.has(slot.slot_id)) {
2134 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2135 }
2136 store.stateSlotsByInstanceStorage.set(pair, slot);
2137 store.storageValues.set(slot.slot_id, initialStateSlotValue(slot));
2138 statePairs.push([pair, slot]);
2139 }
2140 for (const slot of records.computed_slots ?? []) {
2141 const pair = `${instanceId}|${slot.computed_id}`;
2142 if (store.computedSlotsByInstanceComputed.has(pair)
2143 || store.computedDirtySlots.has(slot.dirty_slot_id)
2144 || store.computedCaches.has(slot.cache_slot_id)) {
2145 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2146 }
2147 store.computedSlotsByInstanceComputed.set(pair, slot);
2148 store.computedDirtySlots.set(slot.dirty_slot_id, slot.dirty_initial_value === true);
2149 computedPairs.push([pair, slot]);
2150 }
2151 component = { instance_id: instanceId, name: definition.name, manifest: definition, state: {} };
2152 for (const state of store.computedArtifact?.state ?? []) {
2153 if (state.component !== definition.name) continue;
2154 const slot = store.stateSlotsByInstanceStorage.get(`${instanceId}|${state.storage}`);
2155 if (slot === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2156 component.state[state.field] = store.storageValues.get(slot.slot_id);
2157 }
2158 store.components.set(instanceId, component);
2159 store.componentInstances.set(instanceId, {
2160 instance: instanceId,
2161 component: componentId,
2162 parent: records.parent_scope,
2163 structural_region: records.structural_region,
2164 status: "staged"
2165 });
2166 registerActions(store, component, definition);
2167 staged = true;
2168 } catch (error) {
2169 staged = true;
2170 rollback();
2171 throw error;
2172 }
2173 return Object.freeze({ ...records, rollback });
2174 }
2175
2176 function renderStructuralOccurrenceTemplate(records) {
2177 const occurrenceIdentity = String(records?.occurrence_identity ?? "");
2178 const templateHtml = records?.occurrence?.template_html;
2179 decodeStructuralOccurrenceIdentity(occurrenceIdentity);
2180 if (typeof templateHtml !== "string" || templateHtml.length === 0) {
2181 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2182 }
2183 const html = templateHtml.replaceAll("__PRESOLVE_STRUCTURAL_OCCURRENCE__", occurrenceIdentity);
2184 if (html.includes("__PRESOLVE_STRUCTURAL_OCCURRENCE__")) {
2185 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2186 }
2187 const template = document.createElement("template");
2188 template.innerHTML = html;
2189 if (!template.content.hasChildNodes()) {
2190 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2191 }
2192 return template.content;
2193 }
2194
2195 function attachStructuralOccurrenceFragment(marker, invocation, fragment) {
2196 if (!(marker instanceof Element)
2197 || marker.getAttribute("data-presolve-structural-invocation") !== invocation
2198 || marker.parentNode === null
2199 || !(fragment instanceof DocumentFragment)
2200 || !fragment.hasChildNodes()) {
2201 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2202 }
2203 const parent = marker.parentNode;
2204 const nextSibling = marker.nextSibling;
2205 const nodes = [...fragment.childNodes];
2206 marker.replaceWith(fragment);
2207 let attached = true;
2208 const rollback = () => {
2209 if (!attached) return;
2210 for (const node of nodes) {
2211 if (node.parentNode !== null) node.remove();
2212 }
2213 if (nextSibling !== null && nextSibling.parentNode === parent) {
2214 parent.insertBefore(marker, nextSibling);
2215 } else {
2216 parent.appendChild(marker);
2217 }
2218 attached = false;
2219 };
2220 return Object.freeze({ nodes: Object.freeze(nodes), rollback });
2221 }
2222
2223 function registerStructuralOccurrenceRecords(store, staged) {
2224 if (!(store.templateTargetsById instanceof Map)
2225 || !(store.ordinaryBindingsById instanceof Map)
2226 || !(store.ordinaryEventsByTargetAndType instanceof Map)) {
2227 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2228 }
2229 const anchors = collectOrdinaryTargetAnchors();
2230 for (const pair of staged.bindings) {
2231 const binding = pair.manifest;
2232 if (binding.kind !== "text" || anchors.targets.has(binding.instance_target_id)) continue;
2233 const text = ordinaryTextBindingNode(binding.instance_binding_id);
2234 if (text !== null) anchors.targets.set(binding.instance_target_id, text);
2235 }
2236 const targetIds = [];
2237 const bindingIds = [];
2238 const eventKeys = [];
2239 const unsubscribes = [];
2240 let registered = false;
2241 const rollback = () => {
2242 if (!registered) return;
2243 for (const unsubscribe of unsubscribes.reverse()) unsubscribe();
2244 for (const key of eventKeys) store.ordinaryEventsByTargetAndType.delete(key);
2245 for (const id of bindingIds) store.ordinaryBindingsById.delete(id);
2246 for (const id of targetIds) store.templateTargetsById.delete(id);
2247 registered = false;
2248 };
2249 try {
2250 for (const pair of staged.targets) {
2251 const target = pair.manifest;
2252 if (anchors.duplicates.has(target.id) || !anchors.targets.has(target.id)
2253 || store.templateTargetsById.has(target.id)) {
2254 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2255 }
2256 store.templateTargetsById.set(target.id, anchors.targets.get(target.id));
2257 targetIds.push(target.id);
2258 }
2259 for (const pair of staged.bindings) {
2260 const binding = pair.manifest;
2261 if (store.ordinaryBindingsById.has(binding.instance_binding_id)) {
2262 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2263 }
2264 store.ordinaryBindingsById.set(binding.instance_binding_id, {
2265 ...binding,
2266 execution_context: { component_instance_id: binding.component_instance_id }
2267 });
2268 bindingIds.push(binding.instance_binding_id);
2269 unsubscribes.push(registerOrdinaryBinding(store, binding, pair.artifact));
2270 }
2271 for (const pair of staged.events) {
2272 const event = pair.manifest;
2273 const key = ordinaryEventKey(event.instance_target_id, event.event_type);
2274 if (store.ordinaryEventsByTargetAndType.has(key)) {
2275 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2276 }
2277 store.ordinaryEventsByTargetAndType.set(key, event);
2278 eventKeys.push(key);
2279 }
2280 executeComputedPlan(store, staged.occurrence_identity);
2281 installOrdinaryInstanceEventListeners(store);
2282 registered = true;
2283 } catch (error) {
2284 registered = true;
2285 rollback();
2286 throw error;
2287 }
2288 return Object.freeze({ rollback });
2289 }
2290
2291 function structuralEffectInstances(store, records) {
2292 const templateInstance = String(records?.template_instance ?? "");
2293 const occurrenceIdentity = String(records?.occurrence_identity ?? "");
2294 const structuralRegion = String(records?.structural_region ?? "");
2295 const component = String(records?.component ?? "");
2296 if (templateInstance.length === 0 || occurrenceIdentity.length === 0
2297 || structuralRegion.length === 0 || component.length === 0) {
2298 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
2299 }
2300 const effects = new Set((store.effectArtifact?.effects ?? []).map((effect) => effect.effect));
2301 const identities = new Set();
2302 const instances = (store.effectArtifact?.structural_templates ?? [])
2303 .filter((record) => record.template_instance === templateInstance)
2304 .map((record) => {
2305 if (record.structural_region !== structuralRegion || record.component !== component
2306 || !effects.has(record.effect)) {
2307 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
2308 }
2309 const effectInstance = rewriteStructuralTemplateIdentity(
2310 templateInstance,
2311 occurrenceIdentity,
2312 record.effect_instance
2313 );
2314 if (identities.has(effectInstance) || store.activeEffectInstances.has(effectInstance)) {
2315 throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
2316 }
2317 identities.add(effectInstance);
2318 return Object.freeze({
2319 effect_instance: effectInstance,
2320 effect: record.effect,
2321 component_instance: occurrenceIdentity,
2322 parent_instance: records.parent_scope,
2323 depth: record.depth,
2324 declaration_order: record.declaration_order,
2325 structural: true
2326 });
2327 })
2328 .sort((left, right) => left.declaration_order - right.declaration_order
2329 || left.effect_instance.localeCompare(right.effect_instance));
2330 return Object.freeze(instances);
2331 }
2332
2333 function activateStructuralEffectInstances(store, records, resumeOnly = false) {
2334 const instances = structuralEffectInstances(store, records);
2335 const effects = new Map((store.effectArtifact?.effects ?? []).map((effect) => [effect.effect, effect]));
2336 const activated = [];
2337 try {
2338 for (const instance of instances) {
2339 const effect = effects.get(instance.effect);
2340 if (effect === undefined) throw new PresolveBootError("PSR_INVALID_EFFECT_INSTANCE_ARTIFACT");
2341 if (resumeOnly && effect.run_on_resume !== true) continue;
2342 store.activeEffectInstances.set(instance.effect_instance, instance);
2343 activated.push(instance);
2344 const evidence = {
2345 effect: effect.effect,
2346 effect_instance: instance.effect_instance,
2347 structural_region: records.structural_region,
2348 occurrence_identity: records.occurrence_identity,
2349 capability_operations: []
2350 };
2351 runEffect(store, effect, evidence, instance);
2352 store.structuralEffectRuns.push(evidence);
2353 }
2354 return Object.freeze({ instances, dispose: () => disposeEffectInstances(store, instances) });
2355 } catch (error) {
2356 disposeEffectInstances(store, activated);
2357 throw error;
2358 }
2359 }
2360
2361 function materializeStructuralOccurrence(store, marker, parentScope, localOccurrence) {
2362 let materializationPhase = "invocation";
2363 const invocation = marker?.getAttribute?.("data-presolve-structural-invocation");
2364 const template = store.structuralOccurrenceTemplatesByInvocation?.get(invocation);
2365 if (typeof invocation !== "string" || template === undefined
2366 || typeof parentScope !== "string" || parentScope.length === 0
2367 || typeof localOccurrence !== "string" || localOccurrence.length === 0) {
2368 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2369 }
2370 const identity = structuralOccurrenceIdentity(
2371 parentScope,
2372 template.structural_region,
2373 template.occurrence.template_instance,
2374 localOccurrence
2375 );
2376 materializationPhase = "record-derivation";
2377 const records = deriveStructuralOccurrenceRecords(template, identity);
2378 let staged = null;
2379 let attachment = null;
2380 let registration = null;
2381 let effects = null;
2382 const children = [];
2383 try {
2384 materializationPhase = "record-staging";
2385 staged = stageStructuralOccurrenceRecords(store, records);
2386 materializationPhase = "fragment-rendering";
2387 const program = store.componentRegions?.get(records.structural_region);
2388 const fragment = renderStructuralOccurrenceTemplate(records);
2389 materializationPhase = "nested-anchor-validation";
2390 const anchors = compilerFragmentInvocationAnchors(
2391 fragment,
2392 program,
2393 records.occurrence.nested_invocations
2394 );
2395 attachment = attachStructuralOccurrenceFragment(
2396 marker,
2397 invocation,
2398 fragment
2399 );
2400 materializationPhase = "ordinary-record-registration";
2401 registration = registerStructuralOccurrenceRecords(store, staged);
2402 materializationPhase = "effect-activation";
2403 effects = activateStructuralEffectInstances(store, staged);
2404 materializationPhase = "nested-materialization";
2405 for (const anchor of anchors) {
2406 children.push(materializeStructuralOccurrence(store, anchor.marker, identity, localOccurrence));
2407 }
2408 return Object.freeze({ ...staged, attachment, registration, dispose: () => {
2409 for (const child of [...children].reverse()) child.dispose();
2410 cancelFormSubmissionsForComponent(store, identity);
2411 cancelPackageInvocationsForComponent(store, identity);
2412 effects?.dispose();
2413 registration.rollback();
2414 attachment.rollback();
2415 staged.rollback();
2416 }});
2417 } catch (error) {
2418 for (const child of [...children].reverse()) child.dispose();
2419 effects?.dispose();
2420 registration?.rollback();
2421 attachment?.rollback();
2422 staged?.rollback();
2423 reportDiagnostic(
2424 store.diagnostics,
2425 error instanceof PresolveBootError ? error.code : "PSR_RUNTIME_BOOT_FAILED",
2426 "Structural occurrence materialization failed",
2427 { invocation, structural_region: template?.structural_region ?? null, phase: materializationPhase, message: error instanceof Error ? error.message : String(error) },
2428 true
2429 );
2430 throw error;
2431 }
2432 }
2433
2434 function structuralConditionalHostFragment(store, component, node) {
2435 const programs = [...(store.componentRegions?.values() ?? [])].filter((program) =>
2436 program.host_component === component?.manifest?.component_id
2437 && program.host_node === node?.id
2438 );
2439 if (programs.length === 0) return null;
2440 if (programs.length !== 1 || typeof component?.instance_id !== "string") {
2441 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2442 }
2443 const fragments = programs[0].conditional_host_fragments.filter((fragment) =>
2444 structuralHostScopeMatches(fragment, component)
2445 );
2446 if (fragments.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2447 return fragments[0];
2448 }
2449
2450 function structuralKeyedHostFragment(store, component, node) {
2451 const programs = [...(store.componentRegions?.values() ?? [])].filter((program) =>
2452 program.host_component === component?.manifest?.component_id
2453 && program.host_node === node?.id
2454 );
2455 if (programs.length === 0) return null;
2456 if (programs.length !== 1 || typeof component?.instance_id !== "string") {
2457 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2458 }
2459 const fragments = programs[0].keyed_host_fragments.filter((fragment) =>
2460 structuralHostScopeMatches(fragment, component)
2461 );
2462 if (fragments.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2463 return fragments[0];
2464 }
2465
2466 function structuralHostScopeMatches(fragment, component) {
2467 if (typeof component?.instance_id !== "string" || typeof fragment?.host_instance !== "string") {
2468 return false;
2469 }
2470 if (fragment.host_scope === "static-instance") {
2471 return fragment.host_instance === component.instance_id;
2472 }
2473 if (fragment.host_scope === "structural-occurrence") {
2474 return decodeStructuralOccurrenceIdentity(component.instance_id).template_instance === fragment.host_instance;
2475 }
2476 return false;
2477 }
2478
2479 function compilerFragmentInvocationAnchors(fragment, program, expectedInvocations) {
2480 if (!(fragment instanceof DocumentFragment)
2481 || !Array.isArray(program?.template_occurrences)
2482 || !Array.isArray(program?.create_order)
2483 || !Array.isArray(expectedInvocations)
2484 || program.create_order.length !== program.template_occurrences.length) {
2485 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2486 }
2487 const occurrencesByInvocation = new Map();
2488 const occurrencesByTemplate = new Map();
2489 for (const occurrence of program.template_occurrences) {
2490 if (typeof occurrence?.invocation !== "string" || typeof occurrence?.template_instance !== "string"
2491 || occurrencesByInvocation.has(occurrence.invocation)
2492 || occurrencesByTemplate.has(occurrence.template_instance)) {
2493 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2494 }
2495 occurrencesByInvocation.set(occurrence.invocation, occurrence);
2496 occurrencesByTemplate.set(occurrence.template_instance, occurrence);
2497 }
2498 if (new Set(program.create_order).size !== program.create_order.length
2499 || program.create_order.some((templateInstance) => !occurrencesByTemplate.has(templateInstance))) {
2500 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2501 }
2502 if (new Set(expectedInvocations).size !== expectedInvocations.length
2503 || expectedInvocations.some((invocation) => !occurrencesByInvocation.has(invocation))) {
2504 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2505 }
2506 const anchorsByInvocation = new Map();
2507 const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_ELEMENT);
2508 while (walker.nextNode()) {
2509 const marker = walker.currentNode;
2510 const invocation = marker.getAttribute("data-presolve-structural-invocation");
2511 if (invocation === null) continue;
2512 if (!occurrencesByInvocation.has(invocation) || anchorsByInvocation.has(invocation)) {
2513 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2514 }
2515 anchorsByInvocation.set(invocation, marker);
2516 }
2517 if (anchorsByInvocation.size !== expectedInvocations.length
2518 || expectedInvocations.some((invocation) => !anchorsByInvocation.has(invocation))) {
2519 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2520 }
2521 return Object.freeze(program.create_order
2522 .map((templateInstance) => occurrencesByTemplate.get(templateInstance))
2523 .filter((occurrence) => expectedInvocations.includes(occurrence.invocation))
2524 .map((occurrence) => Object.freeze({
2525 invocation: occurrence.invocation,
2526 marker: anchorsByInvocation.get(occurrence.invocation)
2527 })));
2528 }
2529
2530 function replaceStructuralConditionalBranch(store, target, component, node, fragmentRecord, value) {
2531 if (!structuralHostScopeMatches(fragmentRecord, component)
2532 || target?.start?.parentNode === null
2533 || target?.end?.parentNode === null
2534 || target.start.parentNode !== target.end.parentNode) {
2535 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2536 }
2537 const program = [...(store.componentRegions?.values() ?? [])].filter((candidate) =>
2538 candidate.host_component === component.manifest?.component_id && candidate.host_node === node?.id
2539 );
2540 if (program.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2541 const branch = value === true ? "true" : "false";
2542 const html = branch === "true" ? fragmentRecord.when_true_html : fragmentRecord.when_false_html;
2543 if (typeof html !== "string" || html.length === 0) {
2544 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2545 }
2546 const template = document.createElement("template");
2547 template.innerHTML = html;
2548 if (!template.content.hasChildNodes()) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2549 const expectedInvocations = branch === "true"
2550 ? fragmentRecord.when_true_invocations
2551 : fragmentRecord.when_false_invocations;
2552 const anchors = compilerFragmentInvocationAnchors(template.content, program[0], expectedInvocations);
2553 const previous = document.createDocumentFragment();
2554 let current = target.start.nextSibling;
2555 while (current !== null && current !== target.end) {
2556 const next = current.nextSibling;
2557 previous.appendChild(current);
2558 current = next;
2559 }
2560 const prior = target.structural_occurrences ?? [];
2561 const priorProjection = target.structural_projection_registration ?? null;
2562 const priorBranch = target.structural_branch ?? null;
2563 const priorHtml = priorBranch === "true" ? fragmentRecord.when_true_html
2564 : priorBranch === "false" ? fragmentRecord.when_false_html
2565 : null;
2566 priorProjection?.rollback();
2567 const created = [];
2568 let projectionRegistration = null;
2569 try {
2570 target.end.parentNode.insertBefore(template.content, target.end);
2571 const projection = structuralHostProjectionRecords(store, fragmentRecord, component, html);
2572 projectionRegistration = registerStructuralOccurrenceRecords(store, {
2573 ...projection,
2574 occurrence_identity: component.instance_id
2575 });
2576 for (const anchor of anchors) {
2577 created.push(materializeStructuralOccurrence(
2578 store,
2579 anchor.marker,
2580 component.instance_id,
2581 `conditional:${branch}`
2582 ));
2583 }
2584 for (const occurrence of [...prior].reverse()) occurrence.dispose();
2585 target.structural_occurrences = Object.freeze(created);
2586 target.structural_projection_registration = projectionRegistration;
2587 target.structural_branch = branch;
2588 store.elementsByNode = collectElementAnchors();
2589 } catch (error) {
2590 for (const occurrence of [...created].reverse()) occurrence.dispose();
2591 projectionRegistration?.rollback();
2592 current = target.start.nextSibling;
2593 while (current !== null && current !== target.end) {
2594 const next = current.nextSibling;
2595 current.remove();
2596 current = next;
2597 }
2598 target.end.parentNode.insertBefore(previous, target.end);
2599 if (priorProjection !== null) {
2600 if (typeof priorHtml !== "string") throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2601 const projection = structuralHostProjectionRecords(store, fragmentRecord, component, priorHtml);
2602 target.structural_projection_registration = registerStructuralOccurrenceRecords(store, {
2603 ...projection,
2604 occurrence_identity: component.instance_id
2605 });
2606 }
2607 throw error;
2608 }
2609 }
2610
2611 function structuralOccurrenceTemplateRegistry(manifest, componentArtifact, computedArtifact) {
2612 const components = new Map((manifest.components ?? []).map((component) => [component.component_id, component]));
2613 if (components.size !== (manifest.components ?? []).length) {
2614 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2615 }
2616 const targetRecords = new Map((componentArtifact.ordinary_template_targets ?? []).map((record) => [record.id, record]));
2617 const bindingRecords = new Map((componentArtifact.ordinary_template_bindings ?? []).map((record) => [record.id, record]));
2618 const manifestTargets = new Map((manifest.ordinary_targets ?? []).map((record) => [record.id, record]));
2619 const manifestBindings = new Map((manifest.ordinary_bindings ?? []).map((record) => [record.instance_binding_id, record]));
2620 if (targetRecords.size !== (componentArtifact.ordinary_template_targets ?? []).length
2621 || bindingRecords.size !== (componentArtifact.ordinary_template_bindings ?? []).length
2622 || manifestTargets.size !== (manifest.ordinary_targets ?? []).length
2623 || manifestBindings.size !== (manifest.ordinary_bindings ?? []).length) {
2624 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2625 }
2626 const recordsFor = (ids, table, templateInstance) => {
2627 if (!Array.isArray(ids)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2628 const records = ids.map((id) => table.get(id));
2629 if (new Set(ids).size !== ids.length || records.some((record) => record === undefined
2630 || record.component_instance_id !== templateInstance)) {
2631 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2632 }
2633 return records;
2634 };
2635 const registry = new Map();
2636 for (const program of componentArtifact.structural_programs ?? []) {
2637 for (const occurrence of program.template_occurrences ?? []) {
2638 if (registry.has(occurrence.invocation)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2639 const definition = components.get(occurrence.component);
2640 if (definition === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2641 const targets = recordsFor(occurrence.ordinary_template_targets, targetRecords, occurrence.template_instance);
2642 const bindings = recordsFor(occurrence.ordinary_template_bindings, bindingRecords, occurrence.template_instance);
2643 const events = (occurrence.ordinary_template_events ?? []).map((declarationEventId) => {
2644 const matching = (componentArtifact.ordinary_template_events ?? []).filter((record) =>
2645 record.component_instance_id === occurrence.template_instance
2646 && record.declaration_event_id === declarationEventId
2647 );
2648 if (matching.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2649 return matching[0];
2650 });
2651 if (new Set(occurrence.ordinary_template_events ?? []).size !== events.length) {
2652 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2653 }
2654 const targetPairs = targets.map((record) => {
2655 const manifestRecord = manifestTargets.get(record.id);
2656 if (manifestRecord === undefined
2657 || manifestRecord.component_instance_id !== occurrence.template_instance
2658 || manifestRecord.template_entity_id !== record.template_entity_id
2659 || manifestRecord.kind !== record.kind) {
2660 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2661 }
2662 return Object.freeze({ artifact: record, manifest: manifestRecord });
2663 });
2664 const bindingPairs = bindings.map((record) => {
2665 const manifestRecord = manifestBindings.get(record.id);
2666 if (manifestRecord === undefined
2667 || manifestRecord.component_instance_id !== occurrence.template_instance
2668 || manifestRecord.instance_target_id !== record.target_id
2669 || manifestRecord.declaration_binding_id !== record.declaration_binding_id
2670 || manifestRecord.kind !== record.kind
2671 || manifestRecord.program_id !== record.program_id
2672 || manifestRecord.expression !== record.expression
2673 || manifestRecord.attribute_name !== record.attribute_name) {
2674 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2675 }
2676 return Object.freeze({ artifact: record, manifest: manifestRecord });
2677 });
2678 const eventPairs = events.map((record) => {
2679 const matching = (manifest.ordinary_events ?? []).filter((manifestRecord) =>
2680 manifestRecord.component_instance_id === occurrence.template_instance
2681 && manifestRecord.declaration_event_id === record.declaration_event_id
2682 );
2683 if (matching.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2684 const manifestRecord = matching[0];
2685 if (manifestRecord.component_id !== record.component_id
2686 || manifestRecord.instance_target_id !== record.target_id
2687 || manifestRecord.event_type !== record.event_type
2688 || manifestRecord.handler_method_id !== record.handler_method_id
2689 || manifestRecord.action_batch_id !== record.action_batch_id
2690 || JSON.stringify(manifestRecord.arguments ?? []) !== JSON.stringify(record.arguments ?? [])
2691 || manifestRecord.program_id !== record.program_id) {
2692 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2693 }
2694 return Object.freeze({ artifact: record, manifest: manifestRecord });
2695 });
2696 const expectedStateStorage = (computedArtifact?.state ?? [])
2697 .filter((state) => state.component === definition.name)
2698 .map((state) => state.storage);
2699 const expectedComputed = (computedArtifact?.evaluations ?? [])
2700 .filter((evaluation) => evaluation.component === definition.name)
2701 .map((evaluation) => evaluation.computed);
2702 if (JSON.stringify(occurrence.state_slots.map((slot) => slot.storage_id)) !== JSON.stringify(expectedStateStorage)
2703 || JSON.stringify(occurrence.computed_slots.map((slot) => slot.computed_id)) !== JSON.stringify(expectedComputed)) {
2704 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2705 }
2706 registry.set(occurrence.invocation, Object.freeze({
2707 structural_region: program.region,
2708 occurrence,
2709 definition,
2710 targets: Object.freeze(targetPairs),
2711 bindings: Object.freeze(bindingPairs),
2712 events: Object.freeze(eventPairs)
2713 }));
2714 }
2715 }
2716 return registry;
2717 }
2718
2719 function structuralSlotProjectionRegistry(manifest, componentArtifact) {
2720 const targets = new Map((componentArtifact?.ordinary_template_targets ?? []).map((record) => [record.id, record]));
2721 const bindings = new Map((componentArtifact?.ordinary_template_bindings ?? []).map((record) => [record.id, record]));
2722 const manifestTargets = new Map((manifest?.ordinary_targets ?? []).map((record) => [record.id, record]));
2723 const manifestBindings = new Map((manifest?.ordinary_bindings ?? []).map((record) => [record.instance_binding_id, record]));
2724 const slotBindings = new Map((componentArtifact?.slot_binding_programs ?? []).map((record) => [record.binding, record]));
2725 if (targets.size !== (componentArtifact?.ordinary_template_targets ?? []).length
2726 || bindings.size !== (componentArtifact?.ordinary_template_bindings ?? []).length
2727 || manifestTargets.size !== (manifest?.ordinary_targets ?? []).length
2728 || manifestBindings.size !== (manifest?.ordinary_bindings ?? []).length
2729 || slotBindings.size !== (componentArtifact?.slot_binding_programs ?? []).length) {
2730 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2731 }
2732 const registry = new Map();
2733 for (const program of componentArtifact?.structural_programs ?? []) {
2734 for (const fragment of [...(program.conditional_host_fragments ?? []), ...(program.keyed_host_fragments ?? [])]) {
2735 const programs = fragment?.slot_projection_programs;
2736 if (!Array.isArray(programs) || !Array.isArray(fragment.slot_projection_bindings)
2737 || programs.length !== fragment.slot_projection_bindings.length) {
2738 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2739 }
2740 for (const projection of programs) {
2741 const slotBinding = slotBindings.get(projection?.binding);
2742 if (slotBinding === undefined || slotBinding.binding !== projection.binding
2743 || slotBinding.callee_instance !== fragment.host_instance
2744 || slotBinding.caller_instance !== projection.caller_instance
2745 || slotBinding.content_owner_instance !== projection.content_owner_instance
2746 || !fragment.slot_projection_bindings.includes(projection.binding)
2747 || !Array.isArray(projection.target_ids) || !Array.isArray(projection.binding_ids)
2748 || !Array.isArray(projection.event_ids) || !Array.isArray(projection.nested_invocations)
2749 || new Set(projection.target_ids).size !== projection.target_ids.length
2750 || new Set(projection.binding_ids).size !== projection.binding_ids.length
2751 || new Set(projection.event_ids).size !== projection.event_ids.length
2752 || new Set(projection.nested_invocations).size !== projection.nested_invocations.length
2753 // This amendment activates ordinary caller-owned projection
2754 // members. Projected component invocation cloning needs its own
2755 // State/Effect identity contract and therefore remains fail-closed.
2756 || projection.nested_invocations.length !== 0) {
2757 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2758 }
2759 const targetPairs = projection.target_ids.map((id) => {
2760 const artifact = targets.get(id); const manifestRecord = manifestTargets.get(id);
2761 if (artifact === undefined || manifestRecord === undefined
2762 || artifact.component_instance_id !== projection.caller_instance
2763 || manifestRecord.component_instance_id !== projection.caller_instance) {
2764 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2765 }
2766 return Object.freeze({ artifact, manifest: manifestRecord });
2767 });
2768 const targetIds = new Set(projection.target_ids);
2769 const bindingPairs = projection.binding_ids.map((id) => {
2770 const artifact = bindings.get(id); const manifestRecord = manifestBindings.get(id);
2771 if (artifact === undefined || manifestRecord === undefined
2772 || artifact.component_instance_id !== projection.caller_instance
2773 || !targetIds.has(artifact.target_id) || manifestRecord.instance_target_id !== artifact.target_id) {
2774 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2775 }
2776 return Object.freeze({ artifact, manifest: manifestRecord });
2777 });
2778 const eventPairs = projection.event_ids.map((id) => {
2779 const matches = (componentArtifact?.ordinary_template_events ?? []).filter((event) =>
2780 event.component_instance_id === projection.caller_instance && event.declaration_event_id === id
2781 );
2782 const manifestMatches = (manifest?.ordinary_events ?? []).filter((event) =>
2783 event.component_instance_id === projection.caller_instance && event.declaration_event_id === id
2784 );
2785 if (matches.length !== 1 || manifestMatches.length !== 1 || !targetIds.has(matches[0].target_id)
2786 || manifestMatches[0].instance_target_id !== matches[0].target_id) {
2787 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2788 }
2789 return Object.freeze({ artifact: matches[0], manifest: manifestMatches[0] });
2790 });
2791 const record = Object.freeze({
2792 binding: projection.binding,
2793 caller_instance: projection.caller_instance,
2794 targets: Object.freeze(targetPairs), bindings: Object.freeze(bindingPairs), events: Object.freeze(eventPairs),
2795 nested_invocations: Object.freeze([...projection.nested_invocations])
2796 });
2797 // A binding may be listed by more than one host fragment while only
2798 // one exact outlet is emitted by a given conditional branch or keyed
2799 // item template. Key the preflight result by the compiler program
2800 // object, preserving fragment-local membership without merging it.
2801 registry.set(projection, record);
2802 }
2803 }
2804 }
2805 return registry;
2806 }
2807
2808 function structuralSlotProjectionTargetIds(componentArtifact) {
2809 const ids = new Set();
2810 for (const program of componentArtifact?.structural_programs ?? []) {
2811 for (const fragment of [...(program.conditional_host_fragments ?? []), ...(program.keyed_host_fragments ?? [])]) {
2812 for (const projection of fragment?.slot_projection_programs ?? []) {
2813 for (const id of projection?.target_ids ?? []) {
2814 if (typeof id !== "string" || id.length === 0) {
2815 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2816 }
2817 ids.add(id);
2818 }
2819 }
2820 }
2821 }
2822 return ids;
2823 }
2824
2825 function structuralProjectionOwnerScope(store, component, callerInstance) {
2826 const parent = store.componentInstances?.get(component?.instance_id)?.parent;
2827 if (typeof parent !== "string" || parent.length === 0 || typeof callerInstance !== "string") {
2828 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2829 }
2830 if (callerInstance === parent) return parent;
2831 if (parent.startsWith(STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX)
2832 && decodeStructuralOccurrenceIdentity(parent).template_instance === callerInstance) return parent;
2833 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2834 }
2835
2836 function structuralHostProjectionRecords(store, fragment, component, compilerHtml, itemKey = null) {
2837 if (typeof compilerHtml !== "string") throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2838 const records = [];
2839 const ids = new Set();
2840 for (const projection of fragment?.slot_projection_programs ?? []) {
2841 const source = store.structuralSlotProjectionPrograms?.get(projection);
2842 if (source === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2843 const emitted = [...source.targets, ...source.bindings].some((pair) => compilerHtml.includes(pair.artifact.id));
2844 if (!emitted) continue;
2845 const owner = structuralProjectionOwnerScope(store, component, source.caller_instance);
2846 const rewrite = (value) => {
2847 const base = owner === source.caller_instance ? value
2848 : rewriteStructuralTemplateIdentity(source.caller_instance, owner, value);
2849 return itemKey === null ? base : `${base}:${itemKey}`;
2850 };
2851 const targets = source.targets.map((pair) => Object.freeze({
2852 artifact: Object.freeze({ ...pair.artifact, id: rewrite(pair.artifact.id), component_instance_id: owner }),
2853 manifest: Object.freeze({ ...pair.manifest, id: rewrite(pair.manifest.id), component_instance_id: owner })
2854 }));
2855 const targetIds = new Set(targets.map((pair) => pair.manifest.id));
2856 const bindings = source.bindings.map((pair) => Object.freeze({
2857 artifact: Object.freeze({ ...pair.artifact, id: rewrite(pair.artifact.id), target_id: rewrite(pair.artifact.target_id), component_instance_id: owner }),
2858 manifest: Object.freeze({ ...pair.manifest, instance_binding_id: rewrite(pair.manifest.instance_binding_id), instance_target_id: rewrite(pair.manifest.instance_target_id), component_instance_id: owner })
2859 }));
2860 const events = source.events.map((pair) => Object.freeze({
2861 artifact: Object.freeze({ ...pair.artifact, target_id: rewrite(pair.artifact.target_id), component_instance_id: owner }),
2862 manifest: Object.freeze({ ...pair.manifest, instance_target_id: rewrite(pair.manifest.instance_target_id), component_instance_id: owner })
2863 }));
2864 for (const target of targets) if (ids.has(target.manifest.id) || !ids.add(target.manifest.id)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2865 if (bindings.some((pair) => !targetIds.has(pair.manifest.instance_target_id))) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2866 records.push(...targets, ...bindings, ...events);
2867 }
2868 const targets = records.filter((pair) => pair.artifact?.template_entity_id !== undefined);
2869 const bindings = records.filter((pair) => pair.artifact?.declaration_binding_id !== undefined);
2870 const events = records.filter((pair) => pair.artifact?.declaration_event_id !== undefined);
2871 return Object.freeze({ targets, bindings, events });
2872 }
2873
2874 function escapeHtmlText(value) {
2875 return String(value)
2876 .replaceAll("&", "&")
2877 .replaceAll("<", "<")
2878 .replaceAll(">", ">");
2879 }
2880
2881 function escapeHtmlAttribute(value) {
2882 return escapeHtmlText(value).replaceAll('"', """);
2883 }
2884
2885 function renderListItemHtml(node, item, index, key) {
2886 return String(node.item_template_html ?? "")
2887 .replaceAll("__ez_list_key__", escapeHtmlAttribute(key))
2888 .replaceAll("__ez_list_item__", escapeHtmlText(formatBindingValue(item)))
2889 .replaceAll("__ez_list_index__", String(index));
2890 }
2891
2892 function qualifyStructuralSlotProjectionItemHtml(fragment, html, key) {
2893 let qualified = html;
2894 for (const projection of fragment?.slot_projection_programs ?? []) {
2895 for (const id of [...(projection.target_ids ?? []), ...(projection.binding_ids ?? [])]) {
2896 if (typeof id !== "string" || id.length === 0) {
2897 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
2898 }
2899 qualified = qualified.replaceAll(id, `${id}:${escapeHtmlAttribute(key)}`);
2900 }
2901 }
2902 return qualified;
2903 }
2904
2905 function populateListItemMemberBindings(node, item, fragment) {
2906 const walker = document.createTreeWalker(fragment, NodeFilter.SHOW_COMMENT);
2907 const markers = [];
2908
2909 while (walker.nextNode()) {
2910 markers.push(walker.currentNode);
2911 }
2912
2913 const memberPrefix = `:${String(node.item_variable ?? "")}.`;
2914
2915 for (const marker of markers) {
2916 const comment = String(marker.nodeValue ?? "");
2917 const expressionStart = comment.lastIndexOf(memberPrefix);
2918
2919 if (expressionStart < 0) {
2920 continue;
2921 }
2922
2923 const expression = comment.slice(expressionStart + 1);
2924 const value = listItemMemberValue(node, item, expression);
2925 marker.after(document.createTextNode(value === undefined ? "" : formatBindingValue(value)));
2926 }
2927 }
2928
2929 function listItemBindingExpression(node, comment) {
2930 const value = String(comment ?? "");
2931 const memberPrefix = `:${String(node.item_variable ?? "")}.`;
2932 const memberStart = value.lastIndexOf(memberPrefix);
2933
2934 if (memberStart >= 0) {
2935 return value.slice(memberStart + 1);
2936 }
2937
2938 const itemSuffix = `:${String(node.item_variable ?? "")}`;
2939 if (value.endsWith(itemSuffix)) {
2940 return String(node.item_variable ?? "");
2941 }
2942
2943 const indexSuffix = `:${String(node.index_variable ?? "")}`;
2944 if (node.index_variable !== null && node.index_variable !== undefined && value.endsWith(indexSuffix)) {
2945 return String(node.index_variable);
2946 }
2947
2948 return null;
2949 }
2950
2951 function updateListItemTextBindings(node, instance) {
2952 const walker = document.createTreeWalker(instance.element, NodeFilter.SHOW_COMMENT);
2953
2954 while (walker.nextNode()) {
2955 const marker = walker.currentNode;
2956 const expression = listItemBindingExpression(node, marker.nodeValue);
2957
2958 if (expression === null) {
2959 continue;
2960 }
2961
2962 const textNode = marker.nextSibling;
2963 const value = listItemBindingValue(node, instance.item, instance.index, expression);
2964 const text = value === undefined ? "" : formatBindingValue(value);
2965
2966 if (textNode instanceof Text) {
2967 textNode.textContent = text;
2968 } else if (
2969 textNode instanceof Comment &&
2970 String(textNode.nodeValue ?? "").startsWith("presolve-list-binding-end:")
2971 ) {
2972 textNode.before(document.createTextNode(text));
2973 }
2974 }
2975 }
2976
2977 function listItemElements(root) {
2978 return [root, ...root.querySelectorAll("[data-presolve-list-bindings]")];
2979 }
2980
2981 function updateListItemAttributes(node, instance) {
2982 for (const element of listItemElements(instance.element)) {
2983 const bindings = String(element.dataset.presolveListBindings ?? "");
2984
2985 for (const binding of bindings.split(";")) {
2986 const separator = binding.indexOf("=");
2987
2988 if (separator < 1) {
2989 continue;
2990 }
2991
2992 const attribute = binding.slice(0, separator);
2993 const expression = binding.slice(separator + 1);
2994 const value = listItemBindingValue(node, instance.item, instance.index, expression);
2995 updateAttributeBinding(element, attribute, value);
2996 }
2997 }
2998 }
2999
3000 function listItemEventElements(root) {
3001 return [root, ...root.querySelectorAll("[data-presolve-on-click]")];
3002 }
3003
3004 function registerListItemEvents(store, component, instance) {
3005 for (const element of listItemEventElements(instance.element)) {
3006 const node = element.dataset.presolveNode;
3007 const handler = element.dataset.presolveOnClick;
3008
3009 if (node !== undefined && handler !== undefined) {
3010 registerEvent(store, component, { node, event: "click", handler });
3011 }
3012 }
3013 }
3014
3015 function unregisterListItemEvents(store, instance) {
3016 const eventsByNode = store.eventsByType.get("click");
3017
3018 if (eventsByNode === undefined) {
3019 return;
3020 }
3021
3022 for (const element of listItemEventElements(instance.element)) {
3023 const node = element.dataset.presolveNode;
3024
3025 if (node !== undefined) {
3026 eventsByNode.delete(node);
3027 }
3028 }
3029 }
3030
3031 function renderListItemElement(node, item, index, key) {
3032 const template = document.createElement("template");
3033 template.innerHTML = renderListItemHtml(node, item, index, key);
3034 populateListItemMemberBindings(node, item, template.content);
3035 return template.content.firstElementChild;
3036 }
3037
3038 function renderStructuralKeyedListItem(store, component, node, fragmentRecord, item, index, key) {
3039 if (!structuralHostScopeMatches(fragmentRecord, component)
3040 || typeof fragmentRecord.item_template_html !== "string") {
3041 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3042 }
3043 const programs = [...(store.componentRegions?.values() ?? [])].filter((program) =>
3044 program.host_component === component.manifest?.component_id && program.host_node === node?.id
3045 );
3046 if (programs.length !== 1) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3047 const template = document.createElement("template");
3048 template.innerHTML = qualifyStructuralSlotProjectionItemHtml(
3049 fragmentRecord,
3050 renderListItemHtml({ item_template_html: fragmentRecord.item_template_html }, item, index, key),
3051 key
3052 );
3053 populateListItemMemberBindings(node, item, template.content);
3054 const anchors = compilerFragmentInvocationAnchors(template.content, programs[0], fragmentRecord.item_invocations);
3055 const element = template.content.firstElementChild;
3056 if (element === null || template.content.childElementCount !== 1
3057 || [...template.content.childNodes].some((child) => child !== element)) {
3058 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3059 }
3060 return Object.freeze({ element, anchors });
3061 }
3062
3063 function disposeStructuralKeyedListItem(store, instance) {
3064 for (const occurrence of [...(instance.structural_occurrences ?? [])].reverse()) occurrence.dispose();
3065 instance.structural_projection_registration?.rollback();
3066 unregisterListItemEvents(store, instance);
3067 instance.element.remove();
3068 }
3069
3070 function reconcileStructuralKeyedList(store, component, node, fragmentRecord, startMarker, endMarker, instances, value) {
3071 if (startMarker.parentNode === null || endMarker.parentNode === null || startMarker.parentNode !== endMarker.parentNode) {
3072 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3073 }
3074 const parent = startMarker.parentNode;
3075 const nextInstances = new Map();
3076 const ordered = [];
3077 for (const [index, item] of listItems(value).entries()) {
3078 const key = listItemKey(node, item, index);
3079 if (nextInstances.has(key)) {
3080 reportDiagnostic(store.diagnostics, "PSR_DUPLICATE_LIST_KEY", "List update produced a duplicate key", { id: node.id, key });
3081 continue;
3082 }
3083 let instance = instances.get(key);
3084 if (instance === undefined || !Array.isArray(instance.structural_occurrences)) {
3085 const prior = instance;
3086 const rendered = renderStructuralKeyedListItem(store, component, node, fragmentRecord, item, index, key);
3087 const created = [];
3088 let projectionRegistration = null;
3089 try {
3090 parent.insertBefore(rendered.element, endMarker);
3091 const projection = structuralHostProjectionRecords(store, fragmentRecord, component, fragmentRecord.item_template_html, key);
3092 projectionRegistration = registerStructuralOccurrenceRecords(store, {
3093 ...projection,
3094 occurrence_identity: component.instance_id
3095 });
3096 for (const anchor of rendered.anchors) {
3097 created.push(materializeStructuralOccurrence(store, anchor.marker, component.instance_id, `keyed:${key}`));
3098 }
3099 instance = { element: rendered.element, item, index, key, structural_occurrences: Object.freeze(created), structural_projection_registration: projectionRegistration };
3100 registerListItemEvents(store, component, instance);
3101 if (prior !== undefined) {
3102 unregisterListItemEvents(store, prior);
3103 prior.element.remove();
3104 }
3105 } catch (error) {
3106 for (const occurrence of [...created].reverse()) occurrence.dispose();
3107 projectionRegistration?.rollback();
3108 rendered.element.remove();
3109 throw error;
3110 }
3111 }
3112 instance.item = item;
3113 instance.index = index;
3114 updateListItemTextBindings(node, instance);
3115 updateListItemAttributes(node, instance);
3116 nextInstances.set(key, instance);
3117 ordered.push(instance);
3118 }
3119 for (const [key, instance] of instances) {
3120 if (!nextInstances.has(key)) disposeStructuralKeyedListItem(store, instance);
3121 }
3122 let cursor = startMarker.nextSibling;
3123 for (const instance of ordered) {
3124 if (instance.element !== cursor) parent.insertBefore(instance.element, cursor);
3125 cursor = instance.element.nextSibling;
3126 }
3127 store.elementsByNode = collectElementAnchors();
3128 return nextInstances;
3129 }
3130
3131 function initialListInstances(store, component, node, items) {
3132 const instances = new Map();
3133
3134 for (const [index, item] of items.entries()) {
3135 const key = listItemKey(node, item, index);
3136 const element = store.elementsByNode.get(`${node.item_root}:${key}`);
3137
3138 if (element !== undefined) {
3139 const restored = store.restoredStructuralOccurrencesByParentLocal?.get(
3140 `${component?.instance_id ?? ""}\u001fkeyed:${key}`
3141 );
3142 const instance = { element, item, index, key };
3143 if (restored !== undefined) instance.structural_occurrences = Object.freeze(restored);
3144 instances.set(key, instance);
3145 }
3146 }
3147
3148 return instances;
3149 }
3150
3151 function reconcileKeyedList(store, component, node, startMarker, endMarker, instances, value) {
3152 if (
3153 startMarker.parentNode === null ||
3154 endMarker.parentNode === null ||
3155 startMarker.parentNode !== endMarker.parentNode
3156 ) {
3157 reportDiagnostic(
3158 store.diagnostics,
3159 "PSR_MISSING_LIST_ANCHOR",
3160 "List anchor range was not contiguous in one parent",
3161 {}
3162 );
3163 return instances;
3164 }
3165
3166 const parent = startMarker.parentNode;
3167 const nextInstances = new Map();
3168 const ordered = [];
3169
3170 for (const [index, item] of listItems(value).entries()) {
3171 const key = listItemKey(node, item, index);
3172
3173 if (nextInstances.has(key)) {
3174 reportDiagnostic(
3175 store.diagnostics,
3176 "PSR_DUPLICATE_LIST_KEY",
3177 "List update produced a duplicate key",
3178 { id: node.id, key }
3179 );
3180 continue;
3181 }
3182
3183 let instance = instances.get(key);
3184
3185 if (instance === undefined) {
3186 const element = renderListItemElement(node, item, index, key);
3187
3188 if (element === null) {
3189 reportDiagnostic(
3190 store.diagnostics,
3191 "PSR_INVALID_LIST_TEMPLATE",
3192 "List item template did not produce a root element",
3193 node
3194 );
3195 continue;
3196 }
3197
3198 parent.insertBefore(element, endMarker);
3199 instance = { element, item, index, key };
3200 registerListItemEvents(store, component, instance);
3201 }
3202
3203 instance.item = item;
3204 instance.index = index;
3205 updateListItemTextBindings(node, instance);
3206 updateListItemAttributes(node, instance);
3207 nextInstances.set(key, instance);
3208 ordered.push(instance);
3209 }
3210
3211 for (const [key, instance] of instances) {
3212 if (!nextInstances.has(key)) {
3213 unregisterListItemEvents(store, instance);
3214 instance.element.remove();
3215 }
3216 }
3217
3218 let cursor = startMarker.nextSibling;
3219
3220 for (const instance of ordered) {
3221 if (instance.element !== cursor) {
3222 parent.insertBefore(instance.element, cursor);
3223 }
3224 cursor = instance.element.nextSibling;
3225 }
3226
3227 store.elementsByNode = collectElementAnchors();
3228 return nextInstances;
3229 }
3230
3231 function createRuntimeStore(elementsByNode, diagnostics, computedArtifact, contextArtifact, effectArtifact, componentArtifact, opaqueArtifact, packageInvocationsArtifact) {
3232 const computedEvaluations = new Map();
3233 const storageValues = new Map();
3234 const storageByComponentField = new Map();
3235 const instanceQualifiedState = componentArtifact?.schema_version === SUPPORTED_COMPONENT_ARTIFACT_SCHEMA_VERSION;
3236 const invalidationsByStorage = new Map();
3237 const resourceInvalidationsByDeclaration = new Map();
3238 const computedDirty = new Map();
3239
3240 if (!instanceQualifiedState) {
3241 for (const state of computedArtifact?.state ?? []) {
3242 storageValues.set(state.storage, state.initial_value);
3243 storageByComponentField.set(
3244 componentFieldKey(state.component, state.field),
3245 state.storage
3246 );
3247 }
3248 }
3249
3250 for (const invalidation of computedArtifact?.invalidations ?? []) {
3251 invalidationsByStorage.set(invalidation.storage, invalidation.dependents ?? []);
3252 }
3253
3254 for (const invalidation of computedArtifact?.resource_invalidations ?? []) {
3255 resourceInvalidationsByDeclaration.set(invalidation.declaration, invalidation.dependents ?? []);
3256 }
3257
3258 for (const evaluation of computedArtifact?.evaluations ?? []) {
3259 computedEvaluations.set(evaluation.computed, evaluation);
3260 computedDirty.set(evaluation.computed, evaluation.dirty_flag?.initial_value === true);
3261 }
3262
3263 return {
3264 components: new Map(),
3265 bindingsByField: new Map(),
3266 bindingsByStateSlot: new Map(),
3267 bindingsByInstanceComputed: new Map(),
3268 ordinaryEventListenerTypes: new Set(),
3269 actionsByMethod: new Map(),
3270 legacyActionsByComponentMethod: new Map(),
3271 opaqueTerminalsByMethod: new Map((opaqueArtifact?.activations ?? []).map((activation) => [activation.method, activation])),
3272 opaqueActivations: [],
3273 packageInvocationsByMethod: new Map(
3274 (packageInvocationsArtifact?.invocations ?? []).map((invocation) => [invocation.method, invocation])
3275 ),
3276 packageInvocationRuns: [],
3277 pendingPackageInvocations: new Map(),
3278 packageInvocationGenerations: new Map(),
3279 eventsByType: new Map(),
3280 elementsByNode,
3281 diagnostics,
3282 computedArtifact,
3283 contextArtifact,
3284 effectArtifact,
3285 contextSlots: new Map(),
3286 contextConsumerBindings: new Map(),
3287 contextInitialSourceRuns: [],
3288 contextUpdateSourceRuns: [],
3289 contextFailures: [],
3290 computedEvaluations,
3291 computedDirty,
3292 computedValues: new Map(),
3293 computedCaches: new Map(),
3294 computedSlotsByInstanceComputed: new Map(),
3295 computedDirtySlots: new Map(),
3296 storageValues,
3297 storageByComponentField,
3298 stateSlotsByInstanceStorage: new Map(),
3299 instanceQualifiedState,
3300 invalidationsByStorage,
3301 resourceInvalidationsByDeclaration,
3302 computedUpdateRuns: 0,
3303 initialEffectRuns: [],
3304 completedActionEffectRuns: [],
3305 structuralEffectRuns: [],
3306 effectCleanupRuns: [],
3307 effectSubscriptions: new Map(),
3308 effectCleanups: new Map(),
3309 activeEffectInstances: new Map((effectArtifact?.instances ?? []).map((record) => [
3310 record.effect_instance,
3311 Object.freeze({ ...record, structural: false })
3312 ])),
3313 resources: new Map(),
3314 resourceActivationsByInstanceDeclaration: new Map(),
3315 resourceSlots: new Map(),
3316 activeActionBatch: null
3317 };
3318 }
3319
3320 function computedSlotForExecution(store, computed) {
3321 const componentInstanceId = store.activeExecutionContext?.component_instance_id;
3322 if (componentInstanceId === undefined) return undefined;
3323 const slot = store.computedSlotsByInstanceComputed.get(`${componentInstanceId}|${computed}`);
3324 if (slot === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3325 return slot;
3326 }
3327
3328 function stateSlotForInstanceStorage(store, componentInstanceId, storage) {
3329 const slot = store.stateSlotsByInstanceStorage.get(`${componentInstanceId}|${storage}`);
3330 if (slot === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3331 return slot;
3332 }
3333
3334 function stateValueForStorage(store, storage) {
3335 if (!store.instanceQualifiedState) return store.storageValues.get(storage);
3336 const componentInstanceId = store.activeExecutionContext?.component_instance_id;
3337 if (componentInstanceId === undefined) throw new PresolveBootError("PSR_MISSING_EXECUTION_CONTEXT");
3338 return store.storageValues.get(
3339 stateSlotForInstanceStorage(store, componentInstanceId, storage).slot_id
3340 );
3341 }
3342
3343 function isComputedDirty(store, computed) {
3344 const slot = computedSlotForExecution(store, computed);
3345 return slot === undefined
3346 ? store.computedDirty.get(computed) === true
3347 : store.computedDirtySlots.get(slot.dirty_slot_id) === true;
3348 }
3349
3350 function setComputedDirty(store, computed, value) {
3351 const slot = computedSlotForExecution(store, computed);
3352 if (slot === undefined) store.computedDirty.set(computed, value);
3353 else store.computedDirtySlots.set(slot.dirty_slot_id, value);
3354 }
3355
3356 function computedValue(store, computed) {
3357 const slot = computedSlotForExecution(store, computed);
3358 return slot === undefined
3359 ? store.computedValues.get(computed)
3360 : store.computedCaches.get(slot.cache_slot_id);
3361 }
3362
3363 function computedValueForInstance(store, componentInstanceId, computed) {
3364 const slot = store.computedSlotsByInstanceComputed.get(`${componentInstanceId}|${computed}`);
3365 if (slot === undefined) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3366 return store.computedCaches.get(slot.cache_slot_id);
3367 }
3368
3369 function notifyComputed(store, computed, value) {
3370 const componentInstanceId = store.activeExecutionContext?.component_instance_id;
3371 if (componentInstanceId === undefined) return;
3372 for (const updateBinding of store.bindingsByInstanceComputed.get(`${componentInstanceId}|${computed}`) ?? []) {
3373 updateBinding(value);
3374 }
3375 }
3376
3377 function registerComputedBinding(store, componentInstanceId, computed, updateBinding) {
3378 const key = `${componentInstanceId}|${computed}`;
3379 const bindings = store.bindingsByInstanceComputed.get(key) ?? [];
3380 bindings.push(updateBinding);
3381 store.bindingsByInstanceComputed.set(key, bindings);
3382 return () => {
3383 const active = store.bindingsByInstanceComputed.get(key);
3384 if (active === undefined) return;
3385 const index = active.indexOf(updateBinding);
3386 if (index < 0) return;
3387 active.splice(index, 1);
3388 if (active.length === 0) store.bindingsByInstanceComputed.delete(key);
3389 };
3390 }
3391
3392 function storeComputedValue(store, evaluation, value) {
3393 const slot = computedSlotForExecution(store, evaluation.computed);
3394 if (slot === undefined) {
3395 store.computedValues.set(evaluation.computed, value);
3396 store.computedCaches.set(evaluation.cache_slot, value);
3397 } else {
3398 store.computedCaches.set(slot.cache_slot_id, value);
3399 }
3400 notifyComputed(store, evaluation.computed, value);
3401 }
3402
3403 function computedOperandValue(store, values, operand) {
3404 if (operand?.kind === "value") {
3405 return values.get(operand.value);
3406 }
3407
3408 if (operand?.kind === "constant") {
3409 return operand.value;
3410 }
3411
3412 if (operand?.kind === "storage") {
3413 return stateValueForStorage(store, operand.storage);
3414 }
3415
3416 return undefined;
3417 }
3418
3419 function computedBinary(operation, left, right) {
3420 switch (operation) {
3421 case "add": return left + right;
3422 case "subtract": return left - right;
3423 case "multiply": return left * right;
3424 case "divide": return left / right;
3425 case "remainder": return left % right;
3426 case "equal": return left === right;
3427 case "not-equal": return left !== right;
3428 case "less-than": return left < right;
3429 case "less-than-or-equal": return left <= right;
3430 case "greater-than": return left > right;
3431 case "greater-than-or-equal": return left >= right;
3432 case "and": return left && right;
3433 case "or": return left || right;
3434 case "nullish-coalesce": return left ?? right;
3435 case "min": return typeof left === "number" && typeof right === "number" ? Math.min(left, right) : undefined;
3436 case "max": return typeof left === "number" && typeof right === "number" ? Math.max(left, right) : undefined;
3437 default: return undefined;
3438 }
3439 }
3440
3441 function computedUnary(operation, value) {
3442 switch (operation) {
3443 case "not": return !value;
3444 case "identity": return +value;
3445 case "negate": return -value;
3446 case "abs": return typeof value === "number" ? Math.abs(value) : undefined;
3447 case "floor": return typeof value === "number" ? Math.floor(value) : undefined;
3448 case "ceil": return typeof value === "number" ? Math.ceil(value) : undefined;
3449 case "round": return typeof value === "number" ? Math.round(value) : undefined;
3450 default: return undefined;
3451 }
3452 }
3453
3454 function executePureProgramInstruction(store, values, instruction, subject) {
3455 if (instruction.kind === "constant") {
3456 values.set(instruction.result, instruction.value);
3457 return true;
3458 }
3459
3460 if (instruction.kind === "load-state") {
3461 values.set(instruction.result, stateValueForStorage(store, instruction.storage));
3462 return true;
3463 }
3464
3465 if (instruction.kind === "load-computed") {
3466 if (isComputedDirty(store, instruction.computed)) {
3467 reportDiagnostic(
3468 store.diagnostics,
3469 "PSR_UNPLANNED_COMPUTED_DEPENDENCY",
3470 "Compiler program depended on a value not yet evaluated by the compiler plan",
3471 { subject, dependency: instruction.computed }
3472 );
3473 values.set(instruction.result, undefined);
3474 } else {
3475 values.set(instruction.result, computedValue(store, instruction.computed));
3476 }
3477 return true;
3478 }
3479
3480 if (instruction.kind === "load-resource") {
3481 const componentInstanceId = store.activeExecutionContext?.component_instance_id;
3482 const activationId = typeof componentInstanceId === "string"
3483 ? store.resourceActivationsByInstanceDeclaration.get(`${componentInstanceId}\u001f${instruction.declaration}`)
3484 : undefined;
3485 const resource = activationId === undefined ? undefined : store.resources.get(activationId);
3486 if (resource === undefined) {
3487 reportDiagnostic(
3488 store.diagnostics,
3489 "PSR_RESOURCE_ACTIVATION_MISSING",
3490 "Computed Resource projection lacked exactly one compiler-selected activation",
3491 { subject, component_instance_id: componentInstanceId, declaration: instruction.declaration },
3492 true
3493 );
3494 throw new PresolveBootError("PSR_RESOURCE_ACTIVATION_MISSING");
3495 }
3496 values.set(instruction.result, { data: resource.data, error: resource.error, state: resource.state });
3497 return true;
3498 }
3499
3500 if (instruction.kind === "get-member") {
3501 const object = computedOperandValue(store, values, instruction.object);
3502 const value = object !== null && typeof object === "object"
3503 && Object.prototype.hasOwnProperty.call(object, instruction.property)
3504 ? object[instruction.property]
3505 : undefined;
3506 values.set(instruction.result, value);
3507 return true;
3508 }
3509
3510 if (instruction.kind === "get-index") {
3511 const object = computedOperandValue(store, values, instruction.object);
3512 const index = computedOperandValue(store, values, instruction.index);
3513 const key = typeof index === "string" || (typeof index === "number" && Number.isInteger(index) && index >= 0)
3514 ? String(index)
3515 : null;
3516 const value = key !== null && object !== null && typeof object === "object"
3517 && Object.prototype.hasOwnProperty.call(object, key)
3518 ? object[key]
3519 : undefined;
3520 values.set(instruction.result, value);
3521 return true;
3522 }
3523
3524 if (instruction.kind === "select") {
3525 const condition = computedOperandValue(store, values, instruction.condition);
3526 const value = condition === true
3527 ? computedOperandValue(store, values, instruction.when_true)
3528 : computedOperandValue(store, values, instruction.when_false);
3529 values.set(instruction.result, value);
3530 return true;
3531 }
3532
3533 if (instruction.kind === "template") {
3534 const quasis = instruction.quasis ?? [];
3535 const expressions = instruction.expressions ?? [];
3536 if (quasis.length !== expressions.length + 1) {
3537 reportDiagnostic(
3538 store.diagnostics,
3539 "PSR_INVALID_TEMPLATE_PROGRAM",
3540 "Compiler artifact contained an invalid template interpolation program",
3541 { subject }
3542 );
3543 values.set(instruction.result, undefined);
3544 } else {
3545 let value = quasis[0];
3546 for (let index = 0; index < expressions.length; index += 1) {
3547 value += String(values.get(expressions[index]));
3548 value += quasis[index + 1];
3549 }
3550 values.set(instruction.result, value);
3551 }
3552 return true;
3553 }
3554
3555 if (instruction.kind === "binary") {
3556 values.set(
3557 instruction.result,
3558 computedBinary(
3559 instruction.operation,
3560 computedOperandValue(store, values, instruction.left),
3561 computedOperandValue(store, values, instruction.right)
3562 )
3563 );
3564 return true;
3565 }
3566
3567 if (instruction.kind === "unary") {
3568 values.set(
3569 instruction.result,
3570 computedUnary(
3571 instruction.operation,
3572 computedOperandValue(store, values, instruction.operand)
3573 )
3574 );
3575 return true;
3576 }
3577
3578 if (instruction.kind === "pure-package-call") {
3579 if (instruction.operation === "identity" && instruction.arguments?.length === 1) {
3580 values.set(instruction.result, values.get(instruction.arguments[0]));
3581 } else {
3582 reportDiagnostic(
3583 store.diagnostics,
3584 "PSR_INVALID_PURE_PACKAGE_OPERATION",
3585 "Compiler artifact contained an unsupported pure package operation",
3586 { subject, package: instruction.package, export: instruction.export, operation: instruction.operation }
3587 );
3588 values.set(instruction.result, undefined);
3589 }
3590 return true;
3591 }
3592
3593 return false;
3594 }
3595
3596 function executeComputedProgram(store, evaluation) {
3597 const values = new Map();
3598
3599 for (const instruction of evaluation.program?.instructions ?? []) {
3600 executePureProgramInstruction(store, values, instruction, evaluation.computed);
3601 }
3602
3603 return values.get(evaluation.program?.result);
3604 }
3605
3606 function initialEffectBatches(effectArtifact) {
3607 const batches = new Map();
3608
3609 for (const effect of effectArtifact?.effects ?? []) {
3610 const trigger = effect.initial_trigger;
3611
3612 if (trigger === null || trigger === undefined) {
3613 continue;
3614 }
3615
3616 const effects = batches.get(trigger.effect_batch_index) ?? [];
3617 effects.push(effect);
3618 batches.set(trigger.effect_batch_index, effects);
3619 }
3620
3621 return [...batches.entries()]
3622 .sort(([left], [right]) => left - right)
3623 .map(([batchIndex, effects]) => [
3624 batchIndex,
3625 effects.sort((left, right) =>
3626 (left.declaration_order ?? Number.MAX_SAFE_INTEGER)
3627 - (right.declaration_order ?? Number.MAX_SAFE_INTEGER)
3628 || left.effect.localeCompare(right.effect)
3629 )
3630 ]);
3631 }
3632
3633 function dispatchEffectCapability(store, effect, instruction, values, evidence) {
3634 const runtimeLowering = instruction.runtime_lowering;
3635 const capabilityArguments = (instruction.arguments ?? []).map((operand) =>
3636 computedOperandValue(store, values, operand)
3637 );
3638 const value = computedOperandValue(store, values, instruction.value);
3639
3640 switch (runtimeLowering) {
3641 case "builtin.browser.document.title.assign":
3642 document.title = value;
3643 break;
3644 case "builtin.browser.console.log":
3645 console.log(...capabilityArguments);
3646 break;
3647 case "builtin.browser.console.info":
3648 console.info(...capabilityArguments);
3649 break;
3650 case "builtin.browser.console.warn":
3651 console.warn(...capabilityArguments);
3652 break;
3653 case "builtin.browser.console.error":
3654 console.error(...capabilityArguments);
3655 break;
3656 case "builtin.browser.local_storage.set_item":
3657 localStorage.setItem(...capabilityArguments);
3658 break;
3659 case "builtin.browser.local_storage.remove_item":
3660 localStorage.removeItem(...capabilityArguments);
3661 break;
3662 case "builtin.browser.session_storage.set_item":
3663 sessionStorage.setItem(...capabilityArguments);
3664 break;
3665 case "builtin.browser.session_storage.remove_item":
3666 sessionStorage.removeItem(...capabilityArguments);
3667 break;
3668 default:
3669 reportDiagnostic(
3670 store.diagnostics,
3671 "PSR_UNSUPPORTED_EFFECT_CAPABILITY",
3672 "Effect program referenced an unsupported compiler runtime lowering",
3673 { effect: effect.effect, runtime_lowering: runtimeLowering }
3674 );
3675 return;
3676 }
3677
3678 evidence.capability_operations.push({
3679 operation: instruction.operation,
3680 runtime_lowering: runtimeLowering
3681 });
3682 }
3683
3684 function effectInstanceTargets(store, effect, actionInstanceId = null) {
3685 const records = [...store.activeEffectInstances.values()]
3686 .filter((record) => record.effect === effect.effect)
3687 .filter((record) => actionInstanceId === null || record.component_instance === actionInstanceId)
3688 .sort((left, right) => left.depth - right.depth
3689 || left.declaration_order - right.declaration_order
3690 || left.effect_instance.localeCompare(right.effect_instance));
3691 const hasOwnership = (store.effectArtifact?.instances ?? []).some(
3692 (record) => record.effect === effect.effect
3693 ) || (store.effectArtifact?.structural_templates ?? []).some(
3694 (record) => record.effect === effect.effect
3695 );
3696 return records.length === 0 && !hasOwnership ? [null] : records;
3697 }
3698
3699 function initialEffectInstanceTargets(store, effect) {
3700 const records = [...store.activeEffectInstances.values()]
3701 .filter((record) => record.structural !== true && record.effect === effect.effect)
3702 .sort((left, right) => left.depth - right.depth
3703 || left.declaration_order - right.declaration_order
3704 || left.effect_instance.localeCompare(right.effect_instance));
3705 const hasOwnership = (store.effectArtifact?.instances ?? []).some(
3706 (record) => record.effect === effect.effect
3707 ) || (store.effectArtifact?.structural_templates ?? []).some(
3708 (record) => record.effect === effect.effect
3709 );
3710 return records.length === 0 && !hasOwnership ? [null] : records;
3711 }
3712
3713 function executeEffectProgram(store, effect, evidence, program = effect.program) {
3714 const values = new Map();
3715
3716 for (const instruction of program?.instructions ?? []) {
3717 if (executePureProgramInstruction(store, values, instruction, effect.effect)) {
3718 continue;
3719 }
3720
3721 if (instruction.kind === "capability-call" || instruction.kind === "capability-assign") {
3722 dispatchEffectCapability(store, effect, instruction, values, evidence);
3723 continue;
3724 }
3725
3726 reportDiagnostic(
3727 store.diagnostics,
3728 "PSR_UNSUPPORTED_EFFECT_INSTRUCTION",
3729 "Effect program contained an unsupported compiler instruction",
3730 { effect: effect.effect, kind: instruction.kind }
3731 );
3732 }
3733 }
3734
3735 function runEffect(store, effect, evidence, instance = null) {
3736 const key = instance?.effect_instance ?? effect.effect;
3737 const priorExecutionContext = store.activeExecutionContext;
3738 if (instance !== null) store.activeExecutionContext = { component_instance_id: instance.component_instance };
3739 try {
3740 const cleanup = store.effectCleanups.get(key);
3741 if (cleanup !== undefined) {
3742 const cleanupEvidence = { capability_operations: [] };
3743 executeEffectProgram(store, effect, cleanupEvidence, cleanup);
3744 evidence.cleanup_capability_operations = cleanupEvidence.capability_operations;
3745 store.effectCleanups.delete(key);
3746 }
3747 executeEffectProgram(store, effect, evidence);
3748 if (effect.cleanup_program !== null && effect.cleanup_program !== undefined) {
3749 store.effectCleanups.set(key, effect.cleanup_program);
3750 }
3751 } finally {
3752 store.activeExecutionContext = priorExecutionContext;
3753 }
3754 }
3755
3756 function disposeEffectInstances(store, selected = null) {
3757 const effects = new Map((store.effectArtifact?.effects ?? []).map((effect) => [effect.effect, effect]));
3758 const instances = [...(selected ?? store.activeEffectInstances.values())]
3759 .sort((left, right) => right.depth - left.depth
3760 || right.declaration_order - left.declaration_order
3761 || right.effect_instance.localeCompare(left.effect_instance));
3762 for (const instance of instances) {
3763 const cleanup = store.effectCleanups.get(instance.effect_instance);
3764 const effect = effects.get(instance.effect);
3765 if (cleanup === undefined || effect === undefined) {
3766 store.effectCleanups.delete(instance.effect_instance);
3767 store.activeEffectInstances.delete(instance.effect_instance);
3768 continue;
3769 }
3770 const priorExecutionContext = store.activeExecutionContext;
3771 store.activeExecutionContext = { component_instance_id: instance.component_instance };
3772 try {
3773 const evidence = {
3774 effect: effect.effect,
3775 effect_instance: instance.effect_instance,
3776 capability_operations: []
3777 };
3778 executeEffectProgram(store, effect, evidence, cleanup);
3779 store.effectCleanupRuns.push(evidence);
3780 store.effectCleanups.delete(instance.effect_instance);
3781 } finally {
3782 store.activeExecutionContext = priorExecutionContext;
3783 }
3784 store.activeEffectInstances.delete(instance.effect_instance);
3785 }
3786 }
3787
3788 function installEffectDisposal(store) {
3789 window.addEventListener("pagehide", () => disposeEffectInstances(store), { once: true });
3790 }
3791
3792 function executeInitialEffects(store) {
3793 for (const [effectBatchIndex, effects] of initialEffectBatches(store.effectArtifact)) {
3794 for (const effect of effects) {
3795 for (const instance of initialEffectInstanceTargets(store, effect)) {
3796 const evidence = {
3797 effect: effect.effect,
3798 effect_instance: instance?.effect_instance,
3799 effect_batch_index: effectBatchIndex,
3800 capability_operations: []
3801 };
3802 runEffect(store, effect, evidence, instance);
3803 store.initialEffectRuns.push(evidence);
3804 }
3805 }
3806 }
3807 }
3808
3809 // Resume is an explicit V2 lifecycle phase. It intentionally excludes the
3810 // legacy decorator effects whose restore boundary is frozen by the existing
3811 // resumability contract.
3812 function executeResumeEffects(store) {
3813 for (const [effectBatchIndex, effects] of initialEffectBatches(store.effectArtifact)) {
3814 for (const effect of effects) {
3815 if (effect.run_on_resume !== true) continue;
3816 for (const instance of initialEffectInstanceTargets(store, effect)) {
3817 const evidence = {
3818 effect: effect.effect,
3819 effect_instance: instance?.effect_instance,
3820 effect_batch_index: effectBatchIndex,
3821 capability_operations: []
3822 };
3823 runEffect(store, effect, evidence, instance);
3824 store.initialEffectRuns.push(evidence);
3825 }
3826 }
3827 }
3828 }
3829
3830 function actionEffectBatches(effectArtifact, actionBatchId) {
3831 const batches = new Map();
3832
3833 for (const effect of effectArtifact?.effects ?? []) {
3834 const trigger = (effect.action_batch_triggers ?? []).find(
3835 (candidate) => candidate.action_batch === actionBatchId
3836 );
3837
3838 if (trigger === undefined) {
3839 continue;
3840 }
3841
3842 const effects = batches.get(trigger.effect_batch_index) ?? [];
3843 effects.push(effect);
3844 batches.set(trigger.effect_batch_index, effects);
3845 }
3846
3847 return [...batches.entries()]
3848 .sort(([left], [right]) => left - right)
3849 .map(([batchIndex, effects]) => [
3850 batchIndex,
3851 effects.sort((left, right) =>
3852 (left.declaration_order ?? Number.MAX_SAFE_INTEGER)
3853 - (right.declaration_order ?? Number.MAX_SAFE_INTEGER)
3854 || left.effect.localeCompare(right.effect)
3855 )
3856 ]);
3857 }
3858
3859 function executeCompletedActionEffects(store, actionBatchId) {
3860 for (const [effectBatchIndex, effects] of actionEffectBatches(
3861 store.effectArtifact,
3862 actionBatchId
3863 )) {
3864 for (const effect of effects) {
3865 const actionInstanceId = store.activeExecutionContext?.component_instance_id ?? null;
3866 for (const instance of effectInstanceTargets(store, effect, actionInstanceId)) {
3867 const evidence = {
3868 action_batch_id: actionBatchId,
3869 effect: effect.effect,
3870 effect_instance: instance?.effect_instance,
3871 effect_batch_index: effectBatchIndex,
3872 capability_operations: []
3873 };
3874 runEffect(store, effect, evidence, instance);
3875 store.completedActionEffectRuns.push(evidence);
3876 }
3877 }
3878 }
3879 }
3880
3881 function executeComputedPlan(store, componentInstanceId = null) {
3882 if (store.computedArtifact === null) {
3883 return;
3884 }
3885
3886 const priorExecutionContext = store.activeExecutionContext;
3887 const component = componentInstanceId === null
3888 ? null
3889 : store.components.get(componentInstanceId);
3890 if (componentInstanceId !== null && component === undefined) {
3891 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
3892 }
3893 if (componentInstanceId !== null) {
3894 store.activeExecutionContext = { component_instance_id: componentInstanceId };
3895 }
3896
3897 try {
3898 for (const computed of store.computedArtifact.evaluation_order ?? []) {
3899 const evaluation = store.computedEvaluations.get(computed);
3900
3901 if (evaluation === undefined) {
3902 reportDiagnostic(
3903 store.diagnostics,
3904 "PSR_UNPLANNED_COMPUTED_DEPENDENCY",
3905 "Compiler plan referenced a missing computed evaluation",
3906 { computed }
3907 );
3908 continue;
3909 }
3910
3911 if (component !== null && evaluation.component !== component.name) continue;
3912 if (!isComputedDirty(store, computed)) continue;
3913
3914 storeComputedValue(store, evaluation, executeComputedProgram(store, evaluation));
3915 setComputedDirty(store, computed, false);
3916 }
3917 } finally {
3918 store.activeExecutionContext = priorExecutionContext;
3919 }
3920 }
3921
3922 function executeInitialContext(store) {
3923 const sources = new Map((store.contextArtifact?.sources ?? []).map((source) => [source.source, source]));
3924 for (const batch of store.contextArtifact?.initial_batches ?? []) {
3925 for (const sourceId of batch.sources ?? []) {
3926 const source = sources.get(sourceId);
3927 if (source === undefined) { continue; }
3928 const unavailable = (source.required_computed ?? []).some((computed) => store.computedDirty.get(computed) === true);
3929 if (unavailable) {
3930 store.contextFailures.push({ source: source.source, failure: "unavailable-computed-prerequisite" });
3931 continue;
3932 }
3933 const values = new Map();
3934 let initialized = false;
3935 for (const instruction of source.program?.instructions ?? []) {
3936 if (executePureProgramInstruction(store, values, instruction, source.source)) { continue; }
3937 if (instruction.kind === "initialize_context_slot") {
3938 store.contextSlots.set(instruction.slot, computedOperandValue(store, values, instruction.value));
3939 initialized = true;
3940 continue;
3941 }
3942 store.contextFailures.push({ source: source.source, failure: `unsupported-instruction:${String(instruction.kind)}` });
3943 break;
3944 }
3945 if (initialized) { store.contextInitialSourceRuns.push(source.source); }
3946 }
3947 }
3948 for (const consumer of store.contextArtifact?.consumers ?? []) {
3949 store.contextConsumerBindings.set(consumer.consumer, consumer.slot);
3950 if (!store.contextSlots.has(consumer.slot)) {
3951 store.contextFailures.push({ consumer: consumer.consumer, failure: "source-slot-unavailable" });
3952 }
3953 }
3954 }
3955
3956 function executeContextUpdates(store, actionBatchId) {
3957 const update = (store.contextArtifact?.action_updates ?? []).find(
3958 (candidate) => candidate.action_batch === actionBatchId
3959 );
3960 if (update === undefined || update.invalidated_sources.length === 0) { return; }
3961 const sources = new Map((store.contextArtifact?.sources ?? []).map((source) => [source.source, source]));
3962 for (const sourceId of update.invalidated_sources) {
3963 const source = sources.get(sourceId);
3964 if (source === undefined) { continue; }
3965 const values = new Map();
3966 let initialized = false;
3967 for (const instruction of source.program?.instructions ?? []) {
3968 if (executePureProgramInstruction(store, values, instruction, source.source)) { continue; }
3969 if (instruction.kind === "initialize_context_slot") {
3970 store.contextSlots.set(instruction.slot, computedOperandValue(store, values, instruction.value));
3971 initialized = true;
3972 continue;
3973 }
3974 store.contextFailures.push({ action_batch: actionBatchId, source: source.source, failure: `unsupported-update-instruction:${String(instruction.kind)}` });
3975 break;
3976 }
3977 if (initialized) { store.contextUpdateSourceRuns.push({ action_batch: actionBatchId, source: source.source }); }
3978 }
3979 }
3980
3981 function executeComputedUpdateBatches(store) {
3982 if (store.computedArtifact === null) {
3983 return;
3984 }
3985
3986 let executed = false;
3987
3988 for (const batch of store.computedArtifact.update_batches ?? []) {
3989 for (const computed of batch) {
3990 if (!isComputedDirty(store, computed)) {
3991 continue;
3992 }
3993
3994 const evaluation = store.computedEvaluations.get(computed);
3995
3996 if (evaluation === undefined) {
3997 reportDiagnostic(
3998 store.diagnostics,
3999 "PSR_UNPLANNED_COMPUTED_DEPENDENCY",
4000 "Compiler update batch referenced a missing computed evaluation",
4001 { computed }
4002 );
4003 continue;
4004 }
4005
4006 storeComputedValue(store, evaluation, executeComputedProgram(store, evaluation));
4007 setComputedDirty(store, computed, false);
4008 executed = true;
4009 }
4010 }
4011
4012 if (executed) {
4013 store.computedUpdateRuns += 1;
4014 }
4015 }
4016
4017 function invalidateResourceComputeds(store, activation) {
4018 const priorExecutionContext = store.activeExecutionContext;
4019 store.activeExecutionContext = { component_instance_id: activation.component_instance };
4020 try {
4021 for (const computed of store.resourceInvalidationsByDeclaration.get(activation.declaration) ?? []) {
4022 setComputedDirty(store, computed, true);
4023 }
4024 executeComputedUpdateBatches(store);
4025 } finally {
4026 store.activeExecutionContext = priorExecutionContext;
4027 }
4028 }
4029
4030 function readField(store, component, field, storageId = null) {
4031 if (store.instanceQualifiedState) {
4032 if (typeof component.instance_id !== "string" || typeof storageId !== "string") {
4033 throw new PresolveBootError("PSR_INVALID_STATE_OPERATION");
4034 }
4035 return store.storageValues.get(
4036 stateSlotForInstanceStorage(store, component.instance_id, storageId).slot_id
4037 );
4038 }
4039 if (!(field in component.state)) {
4040 reportDiagnostic(
4041 store.diagnostics,
4042 "PSR_INVALID_STATE_OPERATION",
4043 "Action referenced a missing state field",
4044 { component: component.name, field }
4045 );
4046 return undefined;
4047 }
4048
4049 return component.state[field];
4050 }
4051
4052 function writeField(store, component, field, value, storageId = null) {
4053 if (store.instanceQualifiedState) {
4054 if (typeof component.instance_id !== "string" || typeof storageId !== "string") {
4055 throw new PresolveBootError("PSR_INVALID_STATE_OPERATION");
4056 }
4057 const slot = stateSlotForInstanceStorage(store, component.instance_id, storageId);
4058 store.storageValues.set(slot.slot_id, value);
4059 component.state[field] = value;
4060 for (const computed of store.invalidationsByStorage.get(storageId) ?? []) {
4061 setComputedDirty(store, computed, true);
4062 }
4063 notifyField(store, component, field, slot.slot_id);
4064 return;
4065 }
4066 if (!(field in component.state)) {
4067 reportDiagnostic(
4068 store.diagnostics,
4069 "PSR_INVALID_STATE_OPERATION",
4070 "Action referenced a missing state field",
4071 { component: component.name, field }
4072 );
4073 return;
4074 }
4075
4076 component.state[field] = value;
4077 const storage = store.storageByComponentField.get(
4078 componentFieldKey(component.name, field)
4079 );
4080
4081 if (storage !== undefined) {
4082 store.storageValues.set(storage, value);
4083 for (const computed of store.invalidationsByStorage.get(storage) ?? []) {
4084 setComputedDirty(store, computed, true);
4085 }
4086 }
4087 notifyField(store, component, field, null);
4088 }
4089
4090 function notifyField(store, component, field, stateSlotId) {
4091 const bindings = stateSlotId === null
4092 ? store.bindingsByField.get(componentFieldKey(component.name, field))
4093 : store.bindingsByStateSlot.get(stateSlotId);
4094
4095 if (bindings === undefined) {
4096 reportDiagnostic(
4097 store.diagnostics,
4098 "PSR_MISSING_BINDING_ANCHOR",
4099 "State field has no registered binding anchor",
4100 { component: component.name, field }
4101 );
4102 return;
4103 }
4104
4105 for (const updateBinding of bindings) {
4106 updateBinding(stateSlotId === null ? component.state[field] : store.storageValues.get(stateSlotId));
4107 }
4108 }
4109
4110 function registerBinding(store, component, field, updateBinding, storageId = null) {
4111 if (store.instanceQualifiedState) {
4112 if (typeof component.instance_id !== "string" || typeof storageId !== "string") {
4113 throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4114 }
4115 const slot = stateSlotForInstanceStorage(store, component.instance_id, storageId);
4116 const bindings = store.bindingsByStateSlot.get(slot.slot_id) ?? [];
4117 bindings.push(updateBinding);
4118 store.bindingsByStateSlot.set(slot.slot_id, bindings);
4119 return () => {
4120 const active = store.bindingsByStateSlot.get(slot.slot_id);
4121 if (active === undefined) return;
4122 const index = active.indexOf(updateBinding);
4123 if (index < 0) return;
4124 active.splice(index, 1);
4125 if (active.length === 0) store.bindingsByStateSlot.delete(slot.slot_id);
4126 };
4127 }
4128 const key = componentFieldKey(component.name, field);
4129 const bindings = store.bindingsByField.get(key) ?? [];
4130 bindings.push(updateBinding);
4131 store.bindingsByField.set(key, bindings);
4132 return () => {
4133 const active = store.bindingsByField.get(key);
4134 if (active === undefined) return;
4135 const index = active.indexOf(updateBinding);
4136 if (index < 0) return;
4137 active.splice(index, 1);
4138 if (active.length === 0) store.bindingsByField.delete(key);
4139 };
4140 }
4141
4142 function registerActions(store, component, manifestComponent) {
4143 const { actionsByMethod, legacyActionsByMethod } = buildActionsByMethod(manifestComponent);
4144
4145 for (const [methodId, actionRecord] of actionsByMethod) {
4146 store.actionsByMethod.set(methodId, actionRecord);
4147 }
4148 for (const [method, actions] of legacyActionsByMethod) {
4149 store.legacyActionsByComponentMethod.set(
4150 legacyComponentMethodKey(component.name, method),
4151 actions
4152 );
4153 }
4154 }
4155
4156 function registerEvent(store, component, event) {
4157 if (event.event !== "click") {
4158 reportDiagnostic(
4159 store.diagnostics,
4160 "PSR_UNRESOLVED_EVENT",
4161 "Unsupported event type in template manifest",
4162 event
4163 );
4164 return;
4165 }
4166
4167 if (legacyEventBinding(event)) {
4168 const method = legacyHandlerMethod(event.handler);
4169 const actions = store.legacyActionsByComponentMethod.get(
4170 legacyComponentMethodKey(component.name, method)
4171 );
4172
4173 if (actions === undefined) {
4174 reportDiagnostic(
4175 store.diagnostics,
4176 "PSR_UNRESOLVED_ACTION",
4177 "Legacy event handler did not resolve to a compiler action",
4178 event
4179 );
4180 return;
4181 }
4182
4183 const eventsByNode = store.eventsByType.get(event.event) ?? new Map();
4184 if (eventsByNode.has(event.node)) {
4185 reportDiagnostic(
4186 store.diagnostics,
4187 "PSR_UNRESOLVED_EVENT",
4188 "Duplicate event registration for template node",
4189 event
4190 );
4191 return;
4192 }
4193
4194 eventsByNode.set(event.node, {
4195 component,
4196 method_id: null,
4197 action_batch_id: null,
4198 actions,
4199 arguments: Array.isArray(event.arguments) ? event.arguments : []
4200 });
4201 store.eventsByType.set(event.event, eventsByNode);
4202 return;
4203 }
4204
4205 const actionRecord = store.actionsByMethod.get(event.method_id)
4206 ?? (store.opaqueTerminalsByMethod.has(event.method_id)
4207 || store.packageInvocationsByMethod.has(event.method_id)
4208 ? { action_batch_id: event.action_batch_id, actions: [] }
4209 : undefined);
4210
4211 if (
4212 actionRecord === undefined ||
4213 actionRecord.action_batch_id !== event.action_batch_id
4214 ) {
4215 reportDiagnostic(
4216 store.diagnostics,
4217 "PSR_UNRESOLVED_ACTION",
4218 "Event handler did not resolve to a compiler action",
4219 event
4220 );
4221 return;
4222 }
4223
4224 const eventsByNode = store.eventsByType.get(event.event) ?? new Map();
4225
4226 if (eventsByNode.has(event.node)) {
4227 reportDiagnostic(
4228 store.diagnostics,
4229 "PSR_UNRESOLVED_EVENT",
4230 "Duplicate event registration for template node",
4231 event
4232 );
4233 return;
4234 }
4235
4236 eventsByNode.set(event.node, {
4237 component,
4238 method_id: event.method_id,
4239 action_batch_id: event.action_batch_id,
4240 actions: actionRecord.actions,
4241 arguments: Array.isArray(event.arguments) ? event.arguments : []
4242 });
4243 store.eventsByType.set(event.event, eventsByNode);
4244 }
4245
4246 function initializeComponentRuntime(
4247 store,
4248 manifestComponent,
4249 bindingAnchors,
4250 conditionalAnchors,
4251 listAnchors
4252 ) {
4253 const component = {
4254 name: manifestComponent.name,
4255 manifest: manifestComponent,
4256 state: {}
4257 };
4258
4259 store.components.set(component.name, component);
4260 registerActions(store, component, manifestComponent);
4261
4262 for (const node of manifestComponent.template?.nodes ?? []) {
4263 if (node.kind === "list") {
4264 const field = fieldNameFromThisMember(node.iterable);
4265
4266 if (field === null) {
4267 continue;
4268 }
4269
4270 if (component.state[field] === undefined) {
4271 component.state[field] = node.initial_value;
4272 }
4273
4274 const start = listAnchors.starts.get(node.start);
4275 const end = listAnchors.ends.get(node.end);
4276
4277 if (start === undefined || end === undefined) {
4278 continue;
4279 }
4280
4281 let instances = initialListInstances(
4282 store,
4283 component,
4284 node,
4285 listItems(component.state[field])
4286 );
4287 for (const instance of instances.values()) {
4288 registerListItemEvents(store, component, instance);
4289 }
4290 registerBinding(store, component, field, (value) => {
4291 instances = reconcileKeyedList(
4292 store,
4293 component,
4294 node,
4295 start.marker,
4296 end.marker,
4297 instances,
4298 value
4299 );
4300 });
4301 continue;
4302 }
4303
4304 if (node.kind === "conditional") {
4305 const field = fieldNameFromThisMember(node.condition);
4306
4307 if (field === null) {
4308 continue;
4309 }
4310
4311 if (component.state[field] === undefined) {
4312 component.state[field] = node.initial_value;
4313 }
4314
4315 const start = conditionalAnchors.starts.get(node.start);
4316 const end = conditionalAnchors.ends.get(node.end);
4317
4318 if (start === undefined || end === undefined) {
4319 continue;
4320 }
4321
4322 registerBinding(store, component, field, (value) => {
4323 replaceConditionalBranch(
4324 store,
4325 start.marker,
4326 end.marker,
4327 value === true ? node.when_true_html : node.when_false_html
4328 );
4329 });
4330 continue;
4331 }
4332
4333 if (node.kind !== "binding") {
4334 continue;
4335 }
4336
4337 const field = fieldNameFromThisMember(node.expression);
4338
4339 if (field === null) {
4340 continue;
4341 }
4342
4343 if (component.state[field] === undefined) {
4344 component.state[field] = node.initial_value;
4345 }
4346
4347 if (node.target === "attribute") {
4348 const element = store.elementsByNode.get(node.element);
4349
4350 if (element === undefined) {
4351 continue;
4352 }
4353
4354 updateAttributeBinding(element, node.attribute, component.state[field]);
4355 registerBinding(store, component, field, (value) => {
4356 updateAttributeBinding(element, node.attribute, value);
4357 });
4358 continue;
4359 }
4360
4361 const anchor = bindingAnchors.get(node.id);
4362
4363 if (anchor === undefined) {
4364 continue;
4365 }
4366
4367 const textNode = anchor.marker.nextSibling;
4368
4369 if (!(textNode instanceof Text)) {
4370 reportDiagnostic(
4371 store.diagnostics,
4372 "PSR_MISSING_BINDING_ANCHOR",
4373 "Binding anchor was not followed by a text node",
4374 node
4375 );
4376 continue;
4377 }
4378
4379 registerBinding(store, component, field, (value) => {
4380 textNode.textContent = formatBindingValue(value);
4381 });
4382 }
4383
4384 return component;
4385 }
4386
4387 function actionDelta(store, action) {
4388 if (action.operation === "increment") {
4389 return 1;
4390 }
4391
4392 if (action.operation === "decrement") {
4393 return -1;
4394 }
4395
4396 if (action.operation === "add_assign" || action.operation === "subtract_assign") {
4397 const operand = Number(action.operand);
4398
4399 if (Number.isNaN(operand)) {
4400 reportDiagnostic(
4401 store.diagnostics,
4402 "PSR_INVALID_STATE_OPERATION",
4403 "Numeric state operation had a non-numeric operand",
4404 action
4405 );
4406 return null;
4407 }
4408
4409 return action.operation === "add_assign" ? operand : -operand;
4410 }
4411
4412 return null;
4413 }
4414
4415 function executeAction(store, component, action, executionContext = null) {
4416 if (
4417 action.operation !== "increment" &&
4418 action.operation !== "decrement" &&
4419 action.operation !== "add_assign" &&
4420 action.operation !== "subtract_assign" &&
4421 action.operation !== "assign" &&
4422 action.operation !== "assign_parameter" &&
4423 action.operation !== "toggle"
4424 ) {
4425 reportDiagnostic(
4426 store.diagnostics,
4427 "PSR_INVALID_STATE_OPERATION",
4428 "Action used an unsupported state operation",
4429 action
4430 );
4431 return;
4432 }
4433
4434 if (action.operation === "toggle") {
4435 const current = readField(store, component, action.field, action.storage_id);
4436
4437 if (typeof current !== "boolean") {
4438 reportDiagnostic(
4439 store.diagnostics,
4440 "PSR_INVALID_STATE_OPERATION",
4441 "Toggle action requires a boolean state field",
4442 action
4443 );
4444 return;
4445 }
4446
4447 writeField(store, component, action.field, !current, action.storage_id);
4448 return;
4449 }
4450
4451 if (action.operation === "assign") {
4452 writeField(store, component, action.field, action.operand, action.storage_id);
4453 return;
4454 }
4455
4456 if (action.operation === "assign_parameter") {
4457 const parameterIndex = Number(action.operand);
4458 const value = executionContext?.arguments?.[parameterIndex];
4459 if (value === undefined || !Number.isInteger(parameterIndex)) {
4460 reportDiagnostic(store.diagnostics, "PSR_INVALID_STATE_OPERATION", "Action parameter assignment had no compiler-projected argument", action);
4461 return;
4462 }
4463 writeField(store, component, action.field, value, action.storage_id);
4464 return;
4465 }
4466
4467 const current = Number(readField(store, component, action.field, action.storage_id));
4468
4469 if (Number.isNaN(current)) {
4470 reportDiagnostic(
4471 store.diagnostics,
4472 "PSR_INVALID_STATE_OPERATION",
4473 "Numeric state operation requires a numeric state field",
4474 action
4475 );
4476 return;
4477 }
4478
4479 const delta = actionDelta(store, action);
4480
4481 if (delta === null) {
4482 return;
4483 }
4484
4485 writeField(store, component, action.field, current + delta, action.storage_id);
4486 }
4487
4488 function executeActions(store, component, actionBatchId, actions, executionContext = null) {
4489 store.activeActionBatch = actionBatchId;
4490 store.activeExecutionContext = executionContext;
4491
4492 try {
4493 for (const action of actions) {
4494 executeAction(store, component, action, executionContext);
4495 }
4496
4497 executeComputedUpdateBatches(store);
4498 executeContextUpdates(store, actionBatchId);
4499 executeCompletedActionEffects(store, actionBatchId);
4500 const methodId = executionContext?.method_id;
4501 if (typeof methodId === "string") {
4502 executeOpaqueTerminal(store, methodId);
4503 executePackageInvocation(store, component, methodId, executionContext);
4504 }
4505 } finally {
4506 store.activeActionBatch = null;
4507 store.activeExecutionContext = null;
4508 refreshComputedDebugState(store);
4509 }
4510 }
4511
4512 function executeOpaqueTerminal(store, methodId) {
4513 const terminal = store.opaqueTerminalsByMethod.get(methodId);
4514 if (terminal === undefined) return;
4515 const evidence = { activation: terminal.id, method: methodId, status: "loading" };
4516 store.opaqueActivations.push(evidence);
4517 import(new URL(terminal.runtime_location, document.baseURI).href)
4518 .then((module) => {
4519 const callable = module?.[terminal.export];
4520 if (typeof callable !== "function") throw new Error("declared export is not callable");
4521 return callable();
4522 })
4523 .then(() => { evidence.status = "complete"; })
4524 .catch((error) => {
4525 evidence.status = "failed";
4526 reportDiagnostic(store.diagnostics, "PSR_OPAQUE_TERMINAL_FAILURE", "A compiler-authorized opaque terminal failed", { activation: terminal.id, message: error instanceof Error ? error.message : String(error) });
4527 });
4528 }
4529
4530 function packageInvocationArgument(value, codec) {
4531 if (codec === "null") {
4532 if (value !== null) throw new Error("package argument did not match compiler codec null");
4533 return value;
4534 }
4535 if (typeof value !== codec) {
4536 throw new Error(`package argument did not match compiler codec ${codec}`);
4537 }
4538 return value;
4539 }
4540
4541 function packageInvocationInstanceKey(component, executionContext, invocation) {
4542 const componentInstanceId = executionContext?.component_instance_id ?? component?.instance_id;
4543 if (typeof componentInstanceId !== "string" || componentInstanceId.length === 0) {
4544 throw new Error("package invocation has no compiler-issued component instance");
4545 }
4546 return `${componentInstanceId}\u001f${invocation.id}`;
4547 }
4548
4549 function cancelPackageInvocationsForComponent(store, componentInstanceId) {
4550 for (const [key, pending] of [...store.pendingPackageInvocations]) {
4551 if (componentInstanceId !== null && pending.component_instance_id !== componentInstanceId) continue;
4552 pending.evidence.status = "cancelled";
4553 pending.controller.abort();
4554 store.pendingPackageInvocations.delete(key);
4555 }
4556 }
4557
4558 function executePackageInvocation(store, component, methodId, executionContext) {
4559 const invocation = store.packageInvocationsByMethod.get(methodId);
4560 if (invocation === undefined) return;
4561 const evidence = { invocation: invocation.id, method: methodId, status: "running" };
4562 store.packageInvocationRuns.push(evidence);
4563 try {
4564 const callable = packageInvocationRegistry.get(invocation.id);
4565 if (typeof callable !== "function") {
4566 throw new Error("compiler-issued registry callable is missing");
4567 }
4568 const runtimeArguments = invocation.arguments.map((argument) =>
4569 packageInvocationArgument(
4570 executionContext?.arguments?.[argument.event_argument_index],
4571 argument.codec
4572 )
4573 );
4574 if (invocation.completion === "synchronous") {
4575 const result = callable(...runtimeArguments);
4576 if (result !== null && (typeof result === "object" || typeof result === "function")
4577 && typeof result.then === "function") {
4578 throw new Error("synchronous package invocation returned a Promise");
4579 }
4580 evidence.status = "complete";
4581 return;
4582 }
4583 const key = packageInvocationInstanceKey(component, executionContext, invocation);
4584 const previous = store.pendingPackageInvocations.get(key);
4585 if (previous !== undefined) {
4586 previous.evidence.status = "cancelled";
4587 previous.controller.abort();
4588 }
4589 const controller = new AbortController();
4590 const generation = (store.packageInvocationGenerations.get(key) ?? 0) + 1;
4591 store.packageInvocationGenerations.set(key, generation);
4592 const pending = {
4593 component_instance_id: executionContext?.component_instance_id ?? component?.instance_id,
4594 controller,
4595 evidence,
4596 generation
4597 };
4598 store.pendingPackageInvocations.set(key, pending);
4599 Promise.resolve()
4600 .then(() => callable(...runtimeArguments, controller.signal))
4601 .then(() => {
4602 if (controller.signal.aborted
4603 || store.packageInvocationGenerations.get(key) !== generation) {
4604 evidence.status = "cancelled";
4605 return;
4606 }
4607 evidence.status = "complete";
4608 })
4609 .catch((error) => {
4610 if (controller.signal.aborted) {
4611 evidence.status = "cancelled";
4612 return;
4613 }
4614 evidence.status = "failed";
4615 reportDiagnostic(store.diagnostics, "PSR_PACKAGE_INVOCATION_FAILURE", "A compiler-authorized package invocation failed", { invocation: invocation.id, message: error instanceof Error ? error.message : String(error) });
4616 })
4617 .finally(() => {
4618 const current = store.pendingPackageInvocations.get(key);
4619 if (current?.generation === generation) {
4620 store.pendingPackageInvocations.delete(key);
4621 }
4622 });
4623 } catch (error) {
4624 evidence.status = "failed";
4625 reportDiagnostic(store.diagnostics, "PSR_PACKAGE_INVOCATION_FAILURE", "A compiler-authorized package invocation failed", { invocation: invocation.id, message: error instanceof Error ? error.message : String(error) });
4626 }
4627 }
4628
4629 function registerComponentEvents(store, component) {
4630 for (const event of component.manifest.template?.events ?? []) {
4631 registerEvent(store, component, event);
4632 }
4633 }
4634
4635 function registerLegacyComponentEvents(store, component) {
4636 for (const event of component.manifest.template?.events ?? []) {
4637 if (legacyEventBinding(event)) registerEvent(store, component, event);
4638 }
4639 }
4640
4641 function delegatedEventRecord(store, eventType, target) {
4642 const eventsByNode = store.eventsByType.get(eventType);
4643
4644 if (eventsByNode === undefined) {
4645 return null;
4646 }
4647
4648 let current = target instanceof Element ? target : target?.parentElement;
4649
4650 while (current !== null && current !== undefined) {
4651 const nodeId = current.dataset?.presolveNode;
4652
4653 if (nodeId !== undefined) {
4654 const record = eventsByNode.get(nodeId);
4655
4656 if (record !== undefined) {
4657 return record;
4658 }
4659 }
4660
4661 current = current.parentElement;
4662 }
4663
4664 return null;
4665 }
4666
4667 function dispatchDelegatedEvent(store, event) {
4668 const record = delegatedEventRecord(store, event.type, event.target);
4669
4670 if (record === null) {
4671 return;
4672 }
4673
4674 executeActions(store, record.component, record.action_batch_id, record.actions, { arguments: record.arguments, method_id: record.method_id });
4675 }
4676
4677 function installDelegatedEventListeners(store) {
4678 for (const eventType of store.eventsByType.keys()) {
4679 document.addEventListener(eventType, (event) => {
4680 dispatchDelegatedEvent(store, event);
4681 });
4682 }
4683 }
4684
4685 function collectOrdinaryTargetAnchors() {
4686 const targets = new Map();
4687 const duplicates = new Set();
4688 const register = (id, target) => {
4689 if (targets.has(id)) duplicates.add(id);
4690 targets.set(id, target);
4691 };
4692 for (const element of document.querySelectorAll("[data-presolve-ti]")) {
4693 const id = element.getAttribute("data-presolve-ti");
4694 if (id === null) continue;
4695 register(id, element);
4696 }
4697 const conditionalStarts = new Map();
4698 const listStarts = new Map();
4699 const walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT);
4700 while (walker.nextNode()) {
4701 const marker = walker.currentNode;
4702 const value = String(marker.nodeValue ?? "");
4703 const conditionalStart = /^presolve-conditional-start:[^:]+:ti:(.+)$/.exec(value);
4704 if (conditionalStart !== null) {
4705 conditionalStarts.set(conditionalStart[1], marker);
4706 continue;
4707 }
4708 const conditionalEnd = /^presolve-conditional-end:[^:]+:ti:(.+)$/.exec(value);
4709 if (conditionalEnd !== null) {
4710 const start = conditionalStarts.get(conditionalEnd[1]);
4711 if (start !== undefined) {
4712 register(conditionalEnd[1], { kind: "conditional", start, end: marker });
4713 conditionalStarts.delete(conditionalEnd[1]);
4714 }
4715 continue;
4716 }
4717 const listStart = /^presolve-ti-target-start:(.+)$/.exec(value);
4718 if (listStart !== null) {
4719 listStarts.set(listStart[1], marker);
4720 continue;
4721 }
4722 const listEnd = /^presolve-ti-target-end:(.+)$/.exec(value);
4723 if (listEnd !== null) {
4724 const start = listStarts.get(listEnd[1]);
4725 if (start !== undefined) {
4726 register(listEnd[1], { kind: "list", start, end: marker });
4727 listStarts.delete(listEnd[1]);
4728 }
4729 }
4730 }
4731 return { targets, duplicates };
4732 }
4733
4734 function ordinaryEventKey(targetId, eventType) {
4735 return `${targetId}\u001f${eventType}`;
4736 }
4737
4738 function ordinaryTextBindingNode(bindingId) {
4739 const walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT);
4740 const start = `presolve-ti-binding-start:${bindingId}`;
4741 const end = `presolve-ti-binding-end:${bindingId}`;
4742 let startMarker = null;
4743 while (walker.nextNode()) {
4744 if (walker.currentNode.data === start) { startMarker = walker.currentNode; continue; }
4745 if (startMarker !== null && walker.currentNode.data === end) {
4746 const text = startMarker.nextSibling;
4747 if (text instanceof Text) return text;
4748 if (text === walker.currentNode && startMarker.parentNode !== null) {
4749 const empty = document.createTextNode("");
4750 startMarker.parentNode.insertBefore(empty, walker.currentNode);
4751 return empty;
4752 }
4753 return null;
4754 }
4755 }
4756 return null;
4757 }
4758
4759 function registerOrdinaryBinding(store, binding, artifactBinding) {
4760 const component = store.components.get(binding.component_instance_id);
4761 const field = fieldNameFromThisMember(binding.expression);
4762 const storageId = artifactBinding.state_storage_ids?.length === 1
4763 ? artifactBinding.state_storage_ids[0]
4764 : null;
4765 const computedId = artifactBinding.computed_ids?.length === 1
4766 ? artifactBinding.computed_ids[0]
4767 : null;
4768 if (component === undefined || field === null || (storageId === null) === (computedId === null)) {
4769 throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4770 }
4771 const target = store.templateTargetsById.get(binding.instance_target_id);
4772 const slot = storageId === null
4773 ? null
4774 : stateSlotForInstanceStorage(store, binding.component_instance_id, storageId);
4775 let update = null;
4776 if (binding.kind === "text") {
4777 const text = ordinaryTextBindingNode(binding.instance_binding_id);
4778 if (text !== null) update = (value) => { text.data = formatBindingValue(value); };
4779 } else if ((binding.kind === "attribute" || binding.kind === "property") && target instanceof Element && typeof binding.attribute_name === "string") {
4780 update = (value) => { updateAttributeBinding(target, binding.attribute_name, value); };
4781 } else if (binding.kind === "conditional" && target?.kind === "conditional") {
4782 const nodes = (component.manifest.template?.nodes ?? []).filter(
4783 (node) => node.kind === "conditional" && node.condition === binding.expression
4784 );
4785 if (nodes.length === 1) {
4786 const node = nodes[0];
4787 const fragment = structuralConditionalHostFragment(store, component, node);
4788 if (fragment === null) {
4789 update = (value) => {
4790 replaceConditionalBranch(
4791 store,
4792 target.start,
4793 target.end,
4794 value === true ? node.when_true_html : node.when_false_html
4795 );
4796 };
4797 } else {
4798 update = (value) => {
4799 const branch = value === true ? "true" : "false";
4800 if (target.structural_branch === branch) return;
4801 replaceStructuralConditionalBranch(store, target, component, node, fragment, value);
4802 };
4803 }
4804 }
4805 } else if (binding.kind === "list" && target?.kind === "list") {
4806 if (slot === null) throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4807 const nodes = (component.manifest.template?.nodes ?? []).filter(
4808 (node) => node.kind === "list" && node.iterable === binding.expression
4809 );
4810 if (nodes.length === 1) {
4811 const node = nodes[0];
4812 const fragment = structuralKeyedHostFragment(store, component, node);
4813 let instances = initialListInstances(
4814 store,
4815 component,
4816 node,
4817 listItems(store.storageValues.get(slot.slot_id))
4818 );
4819 if (fragment === null) for (const instance of instances.values()) registerListItemEvents(store, component, instance);
4820 update = (value) => {
4821 instances = fragment === null
4822 ? reconcileKeyedList(store, component, node, target.start, target.end, instances, value)
4823 : reconcileStructuralKeyedList(store, component, node, fragment, target.start, target.end, instances, value);
4824 };
4825 }
4826 }
4827 if (update === null) throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4828 if (slot !== null) {
4829 update(store.storageValues.get(slot.slot_id));
4830 return registerBinding(store, component, field, update, storageId);
4831 } else {
4832 update(computedValueForInstance(store, binding.component_instance_id, computedId));
4833 return registerComputedBinding(store, binding.component_instance_id, computedId, update);
4834 }
4835 }
4836
4837 function initializeOrdinaryInstanceRuntime(store, manifest, componentArtifact) {
4838 if (manifest.schema_version !== SUPPORTED_SCHEMA_VERSION) return;
4839 const activeInstances = new Set((componentArtifact.instances ?? []).map((instance) => instance.instance));
4840 // Caller-owned Slot records selected by a structural host are absent until
4841 // that compiler-issued fragment materializes. Registering them during
4842 // ordinary boot would require anchors that the selected branch/list item
4843 // has not attached yet; structuralHostProjectionRecords owns that staging.
4844 const structuralSlotTargets = structuralSlotProjectionTargetIds(componentArtifact);
4845 // Canonical Form bindings deliberately remain in the template/component
4846 // membership artifacts, but the Forms runtime owns their value channels.
4847 // Registering the same bind:* expression as ordinary component state would
4848 // create a second authority path and reject valid `Field` member chains.
4849 const formBindingTargets = new Set(
4850 (manifest.form_bindings ?? []).map((binding) => binding.instance_target_id)
4851 );
4852 const targets = (manifest.ordinary_targets ?? []).filter((target) =>
4853 activeInstances.has(target.component_instance_id) && !structuralSlotTargets.has(target.id)
4854 );
4855 const bindings = (manifest.ordinary_bindings ?? []).filter((binding) =>
4856 activeInstances.has(binding.component_instance_id)
4857 && !structuralSlotTargets.has(binding.instance_target_id)
4858 && !formBindingTargets.has(binding.instance_target_id)
4859 );
4860 const events = (manifest.ordinary_events ?? []).filter((event) =>
4861 activeInstances.has(event.component_instance_id) && !structuralSlotTargets.has(event.instance_target_id)
4862 );
4863 const anchors = collectOrdinaryTargetAnchors();
4864 for (const binding of bindings) {
4865 if (binding.kind !== "text" || anchors.targets.has(binding.instance_target_id)) continue;
4866 const text = ordinaryTextBindingNode(binding.instance_binding_id);
4867 if (text !== null) anchors.targets.set(binding.instance_target_id, text);
4868 }
4869 const artifactTargets = new Map((componentArtifact.ordinary_template_targets ?? []).map((target) => [target.id, target]));
4870 const artifactBindings = new Map((componentArtifact.ordinary_template_bindings ?? []).map((binding) => [binding.id, binding]));
4871 const artifactEvents = new Map((componentArtifact.ordinary_template_events ?? []).map((event) => [ordinaryEventKey(event.target_id, event.event_type), event]));
4872 const preserveStructuralRegistry = store.resumeStructuralRegistryPrepared === true;
4873 store.templateTargetsById = anchors.targets;
4874 if (!preserveStructuralRegistry) {
4875 store.ordinaryBindingsById = new Map();
4876 store.ordinaryEventsByTargetAndType = new Map();
4877 }
4878 for (const target of targets) {
4879 const artifactTarget = artifactTargets.get(target.id);
4880 if (artifactTarget === undefined || artifactTarget.component_instance_id !== target.component_instance_id || anchors.duplicates.has(target.id) || !anchors.targets.has(target.id)) {
4881 throw new PresolveBootError("PSR_INVALID_ORDINARY_TARGET");
4882 }
4883 }
4884 for (const binding of bindings) {
4885 const artifactBinding = artifactBindings.get(binding.instance_binding_id);
4886 if (artifactBinding === undefined || artifactBinding.component_instance_id !== binding.component_instance_id || artifactBinding.target_id !== binding.instance_target_id) {
4887 throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4888 }
4889 if (store.ordinaryBindingsById.has(binding.instance_binding_id)) {
4890 throw new PresolveBootError("PSR_INVALID_ORDINARY_BINDING");
4891 }
4892 store.ordinaryBindingsById.set(binding.instance_binding_id, {
4893 ...binding,
4894 execution_context: { component_instance_id: binding.component_instance_id }
4895 });
4896 registerOrdinaryBinding(store, binding, artifactBinding);
4897 }
4898 for (const event of events) {
4899 const key = ordinaryEventKey(event.instance_target_id, event.event_type);
4900 const artifactEvent = artifactEvents.get(key);
4901 if (
4902 artifactEvent === undefined
4903 || artifactEvent.component_instance_id !== event.component_instance_id
4904 || JSON.stringify(artifactEvent.arguments ?? []) !== JSON.stringify(event.arguments ?? [])
4905 || store.ordinaryEventsByTargetAndType.has(key)
4906 ) {
4907 throw new PresolveBootError("PSR_INVALID_ORDINARY_EVENT");
4908 }
4909 store.ordinaryEventsByTargetAndType.set(key, event);
4910 }
4911 }
4912
4913 function installResumeDomBindings(store, manifest, componentArtifact) {
4914 const stateBindingIds = new Set(
4915 (componentArtifact.ordinary_template_bindings ?? [])
4916 .filter((binding) => binding.state_storage_ids?.length === 1)
4917 .map((binding) => binding.id)
4918 );
4919 const bindings = (manifest.ordinary_bindings ?? []).filter((binding) =>
4920 stateBindingIds.has(binding.instance_binding_id)
4921 && (binding.kind === "text" || binding.kind === "attribute" || binding.kind === "property"
4922 || (store.structuralOccurrenceResumeActive === true
4923 && (binding.kind === "conditional" || binding.kind === "list")))
4924 );
4925 const targetIds = new Set(bindings.map((binding) => binding.instance_target_id));
4926 for (const event of manifest.ordinary_events ?? []) targetIds.add(event.instance_target_id);
4927 const targets = (manifest.ordinary_targets ?? []).filter((target) => targetIds.has(target.id));
4928 initializeOrdinaryInstanceRuntime(
4929 store,
4930 { ...manifest, ordinary_targets: targets, ordinary_bindings: bindings },
4931 componentArtifact
4932 );
4933 }
4934
4935 function establishResumeEffects(registry, store, effectArtifact) {
4936 for (const effect of effectArtifact?.effects ?? []) {
4937 if (store.effectSubscriptions.has(effect.effect) || registry.effect_subscriptions.has(effect.effect)) {
4938 throw new ResumeBootError("DuplicateIdentity");
4939 }
4940 const subscription = {
4941 effect_instance_id: effect.effect,
4942 scheduler_order: effect.initial_trigger?.effect_batch_index ?? null,
4943 active_after_restore: true,
4944 run_on_restore: effect.run_on_resume === true
4945 };
4946 store.effectSubscriptions.set(effect.effect, subscription);
4947 registry.effect_subscriptions.set(effect.effect, subscription);
4948 }
4949 executeResumeEffects(store);
4950 }
4951
4952 function ordinaryTargetFromEvent(target) {
4953 let current = target instanceof Element ? target : target?.parentElement;
4954 while (current !== null && current !== undefined) {
4955 const targetId = current.getAttribute("data-presolve-ti");
4956 if (targetId !== null) return targetId;
4957 current = current.parentElement;
4958 }
4959 return null;
4960 }
4961
4962 function dispatchOrdinaryInstanceEvent(store, event) {
4963 const targetId = ordinaryTargetFromEvent(event.target);
4964 if (targetId === null) return;
4965 const record = store.ordinaryEventsByTargetAndType.get(ordinaryEventKey(targetId, event.type));
4966 if (record === undefined) return;
4967 const actionRecord = store.actionsByMethod.get(record.handler_method_id)
4968 ?? (store.opaqueTerminalsByMethod.has(record.handler_method_id)
4969 || store.packageInvocationsByMethod.has(record.handler_method_id)
4970 ? { action_batch_id: record.action_batch_id, actions: [] }
4971 : undefined);
4972 const component = store.components.get(record.component_instance_id);
4973 if (actionRecord === undefined || component === undefined || actionRecord.action_batch_id !== record.action_batch_id) {
4974 throw new PresolveBootError("PSR_INVALID_ORDINARY_EVENT");
4975 }
4976 const context = {
4977 component_instance_id: record.component_instance_id,
4978 trigger_target_id: record.instance_target_id,
4979 declaration_event_id: record.declaration_event_id,
4980 action_batch_id: record.action_batch_id,
4981 method_id: record.handler_method_id,
4982 arguments: Array.isArray(record.arguments) ? record.arguments : []
4983 };
4984 executeActions(store, component, record.action_batch_id, actionRecord.actions, context);
4985 }
4986
4987 function installOrdinaryInstanceEventListeners(store) {
4988 for (const key of store.ordinaryEventsByTargetAndType.keys()) {
4989 const eventType = key.slice(key.lastIndexOf("\u001f") + 1);
4990 if (store.ordinaryEventListenerTypes.has(eventType)) continue;
4991 store.ordinaryEventListenerTypes.add(eventType);
4992 document.addEventListener(eventType, (event) => dispatchOrdinaryInstanceEvent(store, event));
4993 }
4994 }
4995
4996 // Forms are initialized exclusively from the compiler artifact and manifest
4997 // bridge. The DOM contributes only the user event value for a known anchor.
4998 async function initializeFormsRuntime(store, formsArtifact, manifest, elementsByNode, diagnostics) {
4999 store.forms = new Map();
5000 store.formInstances = new Map();
5001 store.formBindingsByAnchor = new Map();
5002 store.formBindingsByField = new Map();
5003 store.formHostsByAnchor = new Map();
5004 store.composingFormControls = new WeakSet();
5005 if (formsArtifact === null) return;
5006
5007 const definitions = new Map(formsArtifact.forms.map((form) => [form.id, form]));
5008 for (const instance of formsArtifact.instances) {
5009 const definition = definitions.get(instance.form);
5010 if (definition === undefined) {
5011 reportDiagnostic(diagnostics, "PSR_UNKNOWN_FORM_INSTANCE", "Forms artifact referenced an unknown Form definition", { instance: instance.id, form: instance.form }, true);
5012 continue;
5013 }
5014 const fields = new Map(definition.fields.map((field) => [field.id, {
5015 value: field.initial_value,
5016 initial: field.initial_value,
5017 dirty: false,
5018 touched: false,
5019 validation: [],
5020 validation_issues: [],
5021 validation_pending: false,
5022 validation_generation: 0
5023 }]));
5024 store.forms.set(definition.id, definition);
5025 store.formInstances.set(instance.id, {
5026 definition,
5027 instance,
5028 fields,
5029 aggregate_valid: true,
5030 submission: "Idle",
5031 submission_generation: 0,
5032 submission_controller: null,
5033 diagnostics
5034 });
5035 }
5036
5037 for (const bridge of manifest.form_bindings ?? []) {
5038 const element = manifest.schema_version === SUPPORTED_SCHEMA_VERSION
5039 ? store.templateTargetsById.get(bridge.instance_target_id)
5040 : elementsByNode.get(bridge.control_anchor);
5041 const formInstance = store.formInstances.get(bridge.form_instance_id);
5042 if (element === undefined || formInstance === undefined) {
5043 reportDiagnostic(diagnostics, "PSR_FORMS_MANIFEST_MISMATCH", "Forms manifest bridge did not resolve an exact compiler anchor and instance", { bridge }, true);
5044 continue;
5045 }
5046 const binding = formInstance.definition.bindings.find((item) => item.id === bridge.field_binding_id);
5047 if (binding === undefined || binding.field === undefined || binding.channel !== bridge.channel) {
5048 reportDiagnostic(diagnostics, "PSR_UNKNOWN_FORM_BINDING", "Forms manifest bridge did not match an artifact binding", { bridge }, true);
5049 continue;
5050 }
5051 const record = { bridge, binding, element, formInstance };
5052 store.formBindingsByAnchor.set(manifest.schema_version === SUPPORTED_SCHEMA_VERSION ? bridge.instance_target_id : bridge.control_anchor, record);
5053 const key = `${bridge.form_instance_id}|${binding.field}`;
5054 const bindings = store.formBindingsByField.get(key) ?? [];
5055 bindings.push(record);
5056 store.formBindingsByField.set(key, bindings);
5057 writeFormControl(record, formInstance.fields.get(binding.field)?.value, true);
5058 }
5059
5060 for (const bridge of manifest.form_hosts ?? []) {
5061 const element = manifest.schema_version === SUPPORTED_SCHEMA_VERSION
5062 ? store.templateTargetsById.get(bridge.instance_target_id)
5063 : elementsByNode.get(bridge.host_anchor);
5064 const formInstance = store.formInstances.get(bridge.form_instance_id);
5065 const host = (formsArtifact.hosts ?? []).find((candidate) => candidate.host_anchor === bridge.host_anchor && candidate.form_instance === bridge.form_instance_id);
5066 if (!(element instanceof HTMLFormElement) || formInstance === undefined || host === undefined || host.event !== "submit") {
5067 reportDiagnostic(diagnostics, "PSR_FORMS_MANIFEST_MISMATCH", "Forms host bridge did not resolve an exact compiler-owned form anchor", { bridge }, true);
5068 continue;
5069 }
5070 const anchor = manifest.schema_version === SUPPORTED_SCHEMA_VERSION ? bridge.instance_target_id : bridge.host_anchor;
5071 store.formHostsByAnchor.set(anchor, { bridge, host, element, formInstance });
5072 element.addEventListener(host.event, (event) => dispatchFormSubmit(store, event, anchor));
5073 }
5074
5075 const initialValidations = [];
5076 for (const formInstance of store.formInstances.values()) {
5077 if ((formInstance.definition.validation_rules ?? []).some((rule) => rule.kind === "StandardSchema")) {
5078 for (const fieldId of formInstance.fields.keys()) {
5079 initialValidations.push(validateFormField(formInstance, fieldId));
5080 }
5081 }
5082 }
5083 await Promise.all(initialValidations);
5084 installFormControlListeners(store);
5085 installFormSubmissionDisposal(store);
5086 window.__PRESOLVE_FORMS__ = {
5087 resetForm: (instanceId) => resetForm(store, instanceId),
5088 resetField: (instanceId, fieldId) => resetField(store, instanceId, fieldId)
5089 };
5090 }
5091
5092 function installFormControlListeners(store) {
5093 document.addEventListener("input", (event) => dispatchFormEvent(store, event, false));
5094 document.addEventListener("change", (event) => dispatchFormEvent(store, event, false));
5095 document.addEventListener("focusout", (event) => dispatchFormEvent(store, event, true));
5096 document.addEventListener("compositionstart", (event) => {
5097 if (event.target instanceof HTMLElement) store.composingFormControls.add(event.target);
5098 });
5099 document.addEventListener("compositionend", (event) => {
5100 if (event.target instanceof HTMLElement) store.composingFormControls.delete(event.target);
5101 });
5102 }
5103
5104 function installFormSubmissionDisposal(store) {
5105 window.addEventListener("pagehide", () => {
5106 cancelFormSubmissionsForComponent(store, null);
5107 }, { once: true });
5108 }
5109
5110 function cancelFormSubmissionsForComponent(store, componentInstanceId) {
5111 for (const formInstance of store.formInstances?.values() ?? []) {
5112 if (componentInstanceId !== null
5113 && formInstance.instance.component_instance !== componentInstanceId) continue;
5114 if (formInstance.submission_controller === null) continue;
5115 formInstance.submission_generation += 1;
5116 formInstance.submission = "Cancelled";
5117 formInstance.submission_controller.abort();
5118 formInstance.submission_controller = null;
5119 }
5120 }
5121
5122 async function dispatchFormSubmit(store, event, anchor) {
5123 const record = store.formHostsByAnchor.get(anchor);
5124 if (record === undefined || event.type !== record.host.event) return;
5125 if (record.host.prevent_default === true) event.preventDefault();
5126 if (record.formInstance.submission === "Submitting") return;
5127 record.formInstance.submission = "Submitting";
5128 const generation = ++record.formInstance.submission_generation;
5129 await Promise.all([...record.formInstance.fields.keys()]
5130 .map((fieldId) => validateFormField(record.formInstance, fieldId)));
5131 if (generation !== record.formInstance.submission_generation) return;
5132 if (!record.formInstance.aggregate_valid) { record.formInstance.submission = "Invalid"; return; }
5133 const capabilityId = record.formInstance.definition.submission?.capability;
5134 if (capabilityId !== undefined) {
5135 const capability = formSubmissionCapabilities.get(capabilityId);
5136 if (capability === undefined) {
5137 reportDiagnostic(store.diagnostics, "PSR_UNRESOLVED_FORM_SUBMISSION_CAPABILITY", "Submission plan did not resolve its exact compiler capability", { capability: capabilityId }, true);
5138 record.formInstance.submission = "Failed";
5139 return;
5140 }
5141 const controller = new AbortController();
5142 record.formInstance.submission_controller = controller;
5143 record.formInstance.serialized = serializeFormInstance(record.formInstance);
5144 try {
5145 await capability(canonicalFormValue(record.formInstance), controller.signal);
5146 if (generation === record.formInstance.submission_generation) {
5147 record.formInstance.submission = controller.signal.aborted ? "Cancelled" : "Completed";
5148 }
5149 } catch (error) {
5150 if (generation === record.formInstance.submission_generation) {
5151 record.formInstance.submission = controller.signal.aborted ? "Cancelled" : "Failed";
5152 if (!controller.signal.aborted) {
5153 reportDiagnostic(store.diagnostics, "PSR_FORM_SUBMISSION_CAPABILITY_REJECTED", "Form submission capability rejected", {
5154 capability: capabilityId,
5155 message: error instanceof Error ? error.message : String(error)
5156 });
5157 }
5158 }
5159 } finally {
5160 if (generation === record.formInstance.submission_generation) {
5161 record.formInstance.submission_controller = null;
5162 }
5163 }
5164 return;
5165 }
5166 const action = store.actionsByMethod.get(record.host.submit_action);
5167 const component = store.components.get(record.bridge.component_instance_id) ?? action?.component;
5168 if (action === undefined || action.action_batch_id !== record.host.action_batch || component === undefined) {
5169 reportDiagnostic(store.diagnostics, "PSR_UNRESOLVED_FORM_SUBMIT_ACTION", "Submission host did not resolve its exact compiler action", { host: record.host }, true);
5170 record.formInstance.submission = "Failed";
5171 return;
5172 }
5173 // Serialization is deliberately compiler-record driven: field values and
5174 // path shape come from the compiler artifact, never DOM scanning.
5175 record.formInstance.serialized = serializeFormInstance(record.formInstance);
5176 executeActions(store, component, record.host.action_batch, action.actions, {
5177 component_instance_id: record.bridge.component_instance_id,
5178 trigger_target_id: record.bridge.instance_target_id,
5179 declaration_event_id: record.host.submit_action,
5180 action_batch_id: record.host.action_batch
5181 });
5182 record.formInstance.submission = "Completed";
5183 }
5184
5185 function serializeFormInstance(formInstance) {
5186 const definition = formInstance.definition;
5187 const fields = new Map((definition.fields ?? []).map((field) => [field.id, field]));
5188 if (definition.serialization?.format === "Json") {
5189 return canonicalFormValue(formInstance);
5190 }
5191 return [...formInstance.fields.entries()].map(([field, state]) => ({
5192 key: fields.get(field)?.path?.join(".") ?? field,
5193 value: state.value
5194 }));
5195 }
5196
5197 function canonicalFormValue(formInstance) {
5198 const fields = new Map((formInstance.definition.fields ?? []).map((field) => [field.id, field]));
5199 const result = {};
5200 for (const [fieldId, state] of formInstance.fields.entries()) {
5201 const path = fields.get(fieldId)?.path;
5202 if (!Array.isArray(path) || path.length === 0) continue;
5203 let target = result;
5204 for (const segment of path.slice(0, -1)) target = target[segment] ??= {};
5205 target[path[path.length - 1]] = state.value;
5206 }
5207 return result;
5208 }
5209
5210 function dispatchFormEvent(store, event, blur) {
5211 const element = event.target;
5212 if (!(element instanceof HTMLElement)) return;
5213 const anchor = store.templateTargetsById instanceof Map
5214 ? ordinaryTargetFromEvent(element)
5215 : element.getAttribute("data-presolve-node");
5216 const record = anchor === null ? undefined : store.formBindingsByAnchor.get(anchor);
5217 if (record === undefined) return;
5218 if (blur) {
5219 const state = record.formInstance.fields.get(record.binding.field);
5220 state.touched = true;
5221 validateFormField(record.formInstance, record.binding.field);
5222 return;
5223 }
5224 if (event.isComposing === true || store.composingFormControls.has(element)) return;
5225 const expected = record.binding.channel === "Checked"
5226 || record.binding.channel === "RadioValue"
5227 || record.binding.channel === "Files"
5228 ? "change"
5229 : "input";
5230 if (event.type !== expected) return;
5231 const value = readFormControl(record);
5232 if (value === undefined) return;
5233 writeFormField(store, record.formInstance, record.binding.field, value);
5234 }
5235
5236 function readFormControl(record) {
5237 const { element, binding } = record;
5238 if (binding.channel === "Checked") return element.checked === true;
5239 if (binding.channel === "Files") return Array.from(element.files ?? []);
5240 if (binding.channel === "NumericValue") {
5241 if (element.value === "") return binding.normalization === "NullableNumber" ? null : undefined;
5242 const value = Number(element.value);
5243 return Number.isFinite(value) ? value : undefined;
5244 }
5245 if (binding.channel === "SelectedValues") return [...element.selectedOptions].map((option) => option.value);
5246 return element.value;
5247 }
5248
5249 function writeFormControl(record, value, resetFile = false) {
5250 const { element, binding } = record;
5251 if (binding.channel === "Checked") element.checked = value === true;
5252 else if (binding.channel === "Files") {
5253 if (resetFile) element.value = "";
5254 }
5255 else if (binding.channel === "SelectedValues") {
5256 for (const option of element.options ?? []) option.selected = Array.isArray(value) && value.includes(option.value);
5257 } else element.value = value === null ? "" : String(value ?? "");
5258 }
5259
5260 function writeFormField(store, formInstance, fieldId, value) {
5261 const state = formInstance.fields.get(fieldId);
5262 if (state === undefined) return;
5263 state.value = value;
5264 state.dirty = JSON.stringify(value) !== JSON.stringify(state.initial);
5265 void validateFormField(formInstance, fieldId);
5266 for (const dependency of formInstance.definition.validation_dependencies ?? []) {
5267 if (dependency.source_field === fieldId) {
5268 void validateFormField(formInstance, dependency.target_field);
5269 }
5270 }
5271 for (const record of store.formBindingsByField.get(`${formInstance.instance.id}|${fieldId}`) ?? []) writeFormControl(record, value);
5272 }
5273
5274 function validateFormField(formInstance, fieldId) {
5275 const state = formInstance.fields.get(fieldId);
5276 if (state === undefined) return Promise.resolve(false);
5277 const generation = state.validation_generation + 1;
5278 state.validation_generation = generation;
5279 const rules = (formInstance.definition.validation_rules ?? []).filter((rule) => rule.target_field === fieldId);
5280 const failures = [];
5281 const pending = [];
5282 for (const rule of rules) {
5283 if (rule.kind !== "StandardSchema") {
5284 if (!validateFormRule(formInstance, state.value, rule)) {
5285 failures.push({
5286 rule: rule.id,
5287 issues: [{ message: "Built-in validation failed", path: [] }]
5288 });
5289 }
5290 continue;
5291 }
5292 const schema = standardSchemaValidators.get(rule.argument.validator);
5293 if (schema === undefined) {
5294 failures.push({
5295 rule: rule.id,
5296 issues: [{ message: "Standard Schema validator was unavailable", path: [] }]
5297 });
5298 continue;
5299 }
5300 try {
5301 const result = schema["~standard"].validate(state.value);
5302 if (result !== null && typeof result === "object" && typeof result.then === "function") {
5303 pending.push(Promise.resolve(result)
5304 .then((value) => ({ rule: rule.id, outcome: normalizeStandardSchemaResult(value) }))
5305 .catch((error) => ({
5306 rule: rule.id,
5307 outcome: {
5308 valid: false,
5309 issues: [{
5310 message: error instanceof Error ? error.message : String(error),
5311 path: []
5312 }]
5313 }
5314 })));
5315 } else {
5316 const outcome = normalizeStandardSchemaResult(result);
5317 if (!outcome.valid) failures.push({ rule: rule.id, issues: outcome.issues });
5318 }
5319 } catch (error) {
5320 failures.push({
5321 rule: rule.id,
5322 issues: [{
5323 message: error instanceof Error ? error.message : String(error),
5324 path: []
5325 }]
5326 });
5327 }
5328 }
5329 applyFormValidationState(formInstance, state, failures, pending.length > 0);
5330 if (pending.length === 0) return Promise.resolve(true);
5331 return Promise.all(pending).then((outcomes) => {
5332 if (state.validation_generation !== generation) return false;
5333 for (const { rule, outcome } of outcomes) {
5334 if (!outcome.valid) failures.push({ rule, issues: outcome.issues });
5335 }
5336 applyFormValidationState(formInstance, state, failures, false);
5337 return true;
5338 });
5339 }
5340
5341 function normalizeStandardSchemaResult(result) {
5342 if (result === null || typeof result !== "object" || Array.isArray(result)) {
5343 return { valid: false, issues: [{ message: "Validator returned a malformed result", path: [] }] };
5344 }
5345 if (Array.isArray(result.issues)) {
5346 if (result.issues.length === 0 || !result.issues.every((issue) =>
5347 issue !== null && typeof issue === "object" && typeof issue.message === "string")) {
5348 return { valid: false, issues: [{ message: "Validator returned malformed issues", path: [] }] };
5349 }
5350 return {
5351 valid: false,
5352 issues: result.issues.map((issue) => ({
5353 message: issue.message,
5354 path: Array.isArray(issue.path)
5355 ? issue.path.map((segment) => {
5356 const key = segment !== null && typeof segment === "object" ? segment.key : segment;
5357 return typeof key === "string" || typeof key === "number" ? key : String(key);
5358 })
5359 : []
5360 }))
5361 };
5362 }
5363 if (Object.prototype.hasOwnProperty.call(result, "value")) {
5364 return { valid: true, issues: [] };
5365 }
5366 return { valid: false, issues: [{ message: "Validator returned a malformed result", path: [] }] };
5367 }
5368
5369 function applyFormValidationState(formInstance, state, failures, pending) {
5370 state.validation = failures.map((failure) => failure.rule);
5371 state.validation_issues = failures.flatMap((failure) =>
5372 failure.issues.map((issue) => ({ rule: failure.rule, ...issue }))
5373 );
5374 state.validation_pending = pending;
5375 formInstance.aggregate_valid = [...formInstance.fields.values()].every((field) =>
5376 field.validation.length === 0 && field.validation_pending !== true
5377 );
5378 }
5379
5380 function validateFormRule(formInstance, value, rule) {
5381 const dependency = rule.dependency === undefined ? undefined : formInstance.fields.get(rule.dependency)?.value;
5382 if (rule.kind === "Required") return !(value === null || value === undefined || value === "" || (Array.isArray(value) && value.length === 0));
5383 if (value === null || value === undefined || value === "" || (Array.isArray(value) && value.length === 0)) return true;
5384 if (rule.kind === "Min") return typeof value === "number" && Number.isFinite(value) && value >= Number(rule.argument.value);
5385 if (rule.kind === "Max") return typeof value === "number" && Number.isFinite(value) && value <= Number(rule.argument.value);
5386 if (rule.kind === "MinLength") return (typeof value === "string" || Array.isArray(value)) && value.length >= rule.argument.value;
5387 if (rule.kind === "MaxLength") return (typeof value === "string" || Array.isArray(value)) && value.length <= rule.argument.value;
5388 if (rule.kind === "Pattern") return typeof value === "string" && new RegExp(rule.argument.value).test(value);
5389 if (rule.kind === "Email") return value === "" || /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(String(value));
5390 if (rule.kind === "Equals") return value === dependency;
5391 if (rule.kind === "NotEquals") return value !== dependency;
5392 return false;
5393 }
5394
5395 function resetField(store, instanceId, fieldId) {
5396 const formInstance = store.formInstances?.get(instanceId);
5397 const state = formInstance?.fields.get(fieldId);
5398 if (state === undefined) return false;
5399 state.validation_generation += 1;
5400 state.value = state.initial; state.dirty = false; state.touched = false;
5401 state.validation = []; state.validation_issues = []; state.validation_pending = false;
5402 for (const record of store.formBindingsByField.get(`${instanceId}|${fieldId}`) ?? []) writeFormControl(record, state.value, true);
5403 void validateFormField(formInstance, fieldId);
5404 return true;
5405 }
5406
5407 function resetForm(store, instanceId) {
5408 const formInstance = store.formInstances?.get(instanceId);
5409 if (formInstance === undefined) return false;
5410 formInstance.submission_controller?.abort();
5411 formInstance.submission_controller = null;
5412 formInstance.submission_generation += 1;
5413 for (const fieldId of formInstance.fields.keys()) resetField(store, instanceId, fieldId);
5414 formInstance.submission = "Idle";
5415 return true;
5416 }
5417
5418 function debugComponents(store) {
5419 return [...store.components.values()].map((component) => ({
5420 name: component.name,
5421 state: component.state
5422 }));
5423 }
5424
5425 function debugComputed(store) {
5426 if (store.instanceQualifiedState) {
5427 return [...store.computedSlotsByInstanceComputed.entries()].map(([key, slot]) => ({
5428 component_instance_id: key.slice(0, key.lastIndexOf("|")),
5429 computed: slot.computed_id,
5430 cache_slot: slot.cache_slot_id,
5431 dirty: store.computedDirtySlots.get(slot.dirty_slot_id) === true,
5432 value: store.computedCaches.get(slot.cache_slot_id)
5433 }));
5434 }
5435 return [...store.computedEvaluations.values()].map((evaluation) => ({
5436 computed: evaluation.computed,
5437 cache_slot: evaluation.cache_slot,
5438 dirty: store.computedDirty.get(evaluation.computed) === true,
5439 value: store.computedCaches.get(evaluation.cache_slot)
5440 }));
5441 }
5442
5443 function refreshComputedDebugState(store) {
5444 if (window.__PRESOLVE__?.store !== store) {
5445 return;
5446 }
5447
5448 window.__PRESOLVE__.computed = debugComputed(store);
5449 window.__PRESOLVE__.computed_update_runs = store.computedUpdateRuns;
5450 }
5451
5452 function initialStateSlotValue(slot) {
5453 if (slot.semantic_type !== "number") return slot.initial_value;
5454 const value = Number(slot.initial_value);
5455 if (!Number.isFinite(value)) throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
5456 return value;
5457 }
5458
5459 function decodeResumeValue(value, codec) {
5460 switch (codec?.kind) {
5461 case "null_codec":
5462 if (value !== null) throw new ResumeBootError("ValueTypeMismatch");
5463 return null;
5464 case "boolean_codec":
5465 if (typeof value !== "boolean") throw new ResumeBootError("ValueTypeMismatch");
5466 return value;
5467 case "number_codec":
5468 if (typeof value !== "number" || !Number.isFinite(value) || Object.is(value, -0)) {
5469 throw new ResumeBootError("ValueTypeMismatch");
5470 }
5471 return value;
5472 case "string_codec":
5473 if (typeof value !== "string") throw new ResumeBootError("ValueTypeMismatch");
5474 return value;
5475 case "array_codec":
5476 if (!Array.isArray(value)) throw new ResumeBootError("ValueTypeMismatch");
5477 return value.map((entry) => decodeResumeValue(entry, codec.value));
5478 case "object_codec": {
5479 if (value === null || typeof value !== "object" || Array.isArray(value)) {
5480 throw new ResumeBootError("ValueTypeMismatch");
5481 }
5482 const properties = codec.value ?? [];
5483 if (!exactObjectKeys(value, properties.map((property) => property.name))) {
5484 throw new ResumeBootError("ValueTypeMismatch");
5485 }
5486 return Object.fromEntries(properties.map((property) => [
5487 property.name,
5488 decodeResumeValue(value[property.name], property.codec)
5489 ]));
5490 }
5491 case "nullable_codec":
5492 return value === null ? null : decodeResumeValue(value, codec.value);
5493 default:
5494 throw new ResumeBootError("ValueCodecFailure");
5495 }
5496 }
5497
5498 function decodeResourceValue(value, codec) {
5499 try {
5500 return decodeResumeValue(value, codec);
5501 } catch (_) {
5502 throw new PresolveBootError("PSR_RESOURCE_VALUE_CODEC_FAILURE");
5503 }
5504 }
5505
5506 function snapshotValuesBySlot(snapshot) {
5507 const values = new Map();
5508 for (const boundary of snapshot.boundaries) {
5509 for (const record of boundary.values) values.set(record.slotId, record.value);
5510 }
5511 return values;
5512 }
5513
5514 function allocateResumeStateComputedStore(
5515 registry,
5516 manifest,
5517 templateManifest,
5518 computedArtifact,
5519 contextArtifact,
5520 effectArtifact,
5521 componentArtifact,
5522 packageInvocationsArtifact,
5523 diagnostics
5524 ) {
5525 const store = createRuntimeStore(
5526 collectElementAnchors(),
5527 diagnostics,
5528 computedArtifact,
5529 contextArtifact,
5530 effectArtifact,
5531 componentArtifact,
5532 null,
5533 packageInvocationsArtifact
5534 );
5535 window.addEventListener("pagehide", () => {
5536 cancelPackageInvocationsForComponent(store, null);
5537 }, { once: true });
5538 store.componentArtifact = componentArtifact;
5539 store.componentInstances = new Map();
5540 store.slotBindings = new Map();
5541 store.componentRegions = new Map((componentArtifact?.structural_programs ?? []).map(
5542 (program) => [program.region, program]
5543 ));
5544 store.structuralOccurrenceTemplatesByInvocation = structuralOccurrenceTemplateRegistry(
5545 templateManifest,
5546 componentArtifact,
5547 computedArtifact
5548 );
5549 store.structuralSlotProjectionPrograms = structuralSlotProjectionRegistry(templateManifest, componentArtifact);
5550 store.instanceContextBindings = new Map(
5551 (componentArtifact?.instance_context_bindings ?? [])
5552 .map((binding) => [binding.consumer_instance, binding])
5553 );
5554 const definitions = new Map(
5555 (templateManifest.components ?? []).map((component) => [component.component_id, component])
5556 );
5557 for (const boundary of manifest.boundaries) {
5558 registry.boundary_records.set(boundary.boundary_id, {
5559 boundary_id: boundary.boundary_id,
5560 kind: boundary.kind,
5561 status: "allocated"
5562 });
5563 }
5564 for (const instance of componentArtifact.instances ?? []) {
5565 const definition = definitions.get(instance.component);
5566 if (definition === undefined) throw new ResumeBootError("ResumeArtifactMismatch");
5567 for (const slot of instance.state_slots ?? []) {
5568 const key = `${instance.instance}|${slot.storage_id}`;
5569 if (store.stateSlotsByInstanceStorage.has(key)) {
5570 throw new ResumeBootError("DuplicateIdentity");
5571 }
5572 store.stateSlotsByInstanceStorage.set(key, slot);
5573 }
5574 for (const slot of instance.computed_slots ?? []) {
5575 const key = `${instance.instance}|${slot.computed_id}`;
5576 if (store.computedSlotsByInstanceComputed.has(key)) {
5577 throw new ResumeBootError("DuplicateIdentity");
5578 }
5579 store.computedSlotsByInstanceComputed.set(key, slot);
5580 store.computedDirtySlots.set(slot.dirty_slot_id, false);
5581 }
5582 const component = {
5583 instance_id: instance.instance,
5584 name: instance.component,
5585 manifest: definition,
5586 state: {}
5587 };
5588 store.components.set(instance.instance, component);
5589 registerActions(store, component, definition);
5590 }
5591 return store;
5592 }
5593
5594 function writeResumeSlot(store, registry, slotSchema, value) {
5595 registry.slot_values.set(slotSchema.slot_id, value);
5596 const existing = slotSchema.existing_storage_slot_id;
5597 const resourceSlot = store.resourceSlots.get(existing);
5598 if (resourceSlot !== undefined) {
5599 if (slotSchema.restore_phase !== "R3") throw new ResumeBootError("RestoreInstructionFailure");
5600 resourceSlot.resource.restoredValues[resourceSlot.kind] = value;
5601 return;
5602 }
5603 if (slotSchema.restore_phase === "R3") {
5604 store.storageValues.set(existing, value);
5605 return;
5606 }
5607 if (slotSchema.restore_phase === "R4") {
5608 const computedSlot = [...store.computedSlotsByInstanceComputed.values()]
5609 .find((slot) => slot.cache_slot_id === existing || slot.dirty_slot_id === existing);
5610 if (computedSlot === undefined) throw new ResumeBootError("UnknownSlot");
5611 if (computedSlot.cache_slot_id === existing) store.computedCaches.set(existing, value);
5612 else store.computedDirtySlots.set(existing, value);
5613 return;
5614 }
5615 if (slotSchema.restore_phase === "R6") {
5616 store.contextSlots.set(existing, value);
5617 return;
5618 }
5619 throw new ResumeBootError("RestoreInstructionFailure");
5620 }
5621
5622 function executeResumeDecodeAndWrites(store, registry, snapshot, phases) {
5623 const snapshotValues = snapshotValuesBySlot(snapshot);
5624 const decoded = new Map();
5625 for (const program of registry.definitions.restorePrograms.values()) {
5626 for (const record of program.instructions ?? []) {
5627 if (!phases.has(record.phase)) continue;
5628 const instruction = record.instruction;
5629 if (instruction.kind === "decode_value") {
5630 const schema = registry.definitions.slots.get(instruction.slot_id);
5631 if (schema === undefined || schema.restore_phase !== record.phase) {
5632 throw new ResumeBootError("RestoreInstructionFailure");
5633 }
5634 if (!snapshotValues.has(instruction.slot_id)) throw new ResumeBootError("UnknownSlot");
5635 decoded.set(
5636 instruction.slot_id,
5637 decodeResumeValue(snapshotValues.get(instruction.slot_id), instruction.codec)
5638 );
5639 } else if (instruction.kind === "write_slot") {
5640 const schema = registry.definitions.slots.get(instruction.slot_id);
5641 if (schema === undefined || !decoded.has(instruction.slot_id)) {
5642 throw new ResumeBootError("RestoreInstructionFailure");
5643 }
5644 writeResumeSlot(store, registry, schema, decoded.get(instruction.slot_id));
5645 } else {
5646 throw new ResumeBootError("RestoreInstructionFailure");
5647 }
5648 }
5649 }
5650 }
5651
5652 function synchronizeRestoredComponentState(store, computedArtifact, componentArtifact) {
5653 const fieldsByStorage = new Map(
5654 (computedArtifact?.state ?? []).map((state) => [state.storage, state.field])
5655 );
5656 for (const instance of componentArtifact.instances ?? []) {
5657 const component = store.components.get(instance.instance);
5658 if (component === undefined) throw new ResumeBootError("ResumeArtifactMismatch");
5659 for (const slot of instance.state_slots ?? []) {
5660 const field = fieldsByStorage.get(slot.storage_id);
5661 if (field === undefined || !store.storageValues.has(slot.slot_id)) {
5662 throw new ResumeBootError("UnknownSlot");
5663 }
5664 component.state[field] = store.storageValues.get(slot.slot_id);
5665 }
5666 }
5667 }
5668
5669 function executeResumeComputedRecomputation(store, registry) {
5670 for (const schema of registry.definitions.slots.values()) {
5671 if (schema.restore_phase !== "R5") continue;
5672 const computedSlot = [...store.computedSlotsByInstanceComputed.values()]
5673 .find((slot) =>
5674 slot.cache_slot_id === schema.existing_storage_slot_id
5675 || slot.dirty_slot_id === schema.existing_storage_slot_id
5676 );
5677 if (computedSlot === undefined) throw new ResumeBootError("UnknownSlot");
5678 if (computedSlot.dirty_slot_id === schema.existing_storage_slot_id) {
5679 store.computedDirtySlots.set(computedSlot.dirty_slot_id, true);
5680 }
5681 }
5682 const recomputed = new Set();
5683 for (const program of registry.definitions.restorePrograms.values()) {
5684 for (const record of program.instructions ?? []) {
5685 if (record.phase !== "R5") continue;
5686 const instruction = record.instruction;
5687 if (instruction.kind !== "recompute_computed") {
5688 throw new ResumeBootError("RestoreInstructionFailure");
5689 }
5690 const key = `${instruction.component_instance_id}|${instruction.computed_id}`;
5691 const slot = store.computedSlotsByInstanceComputed.get(key);
5692 const evaluation = store.computedEvaluations.get(instruction.computed_id);
5693 if (slot === undefined || evaluation === undefined || recomputed.has(key)) {
5694 throw new ResumeBootError("RestoreInstructionFailure");
5695 }
5696 const prior = store.activeExecutionContext;
5697 store.activeExecutionContext = {
5698 component_instance_id: instruction.component_instance_id
5699 };
5700 try {
5701 const value = executeComputedProgram(store, evaluation);
5702 storeComputedValue(store, evaluation, value);
5703 setComputedDirty(store, instruction.computed_id, false);
5704 const cacheSchema = [...registry.definitions.slots.values()]
5705 .find((schema) => schema.existing_storage_slot_id === slot.cache_slot_id);
5706 const dirtySchema = [...registry.definitions.slots.values()]
5707 .find((schema) => schema.existing_storage_slot_id === slot.dirty_slot_id);
5708 if (cacheSchema === undefined || dirtySchema === undefined) {
5709 throw new ResumeBootError("UnknownSlot");
5710 }
5711 registry.slot_values.set(cacheSchema.slot_id, value);
5712 registry.slot_values.set(dirtySchema.slot_id, false);
5713 recomputed.add(key);
5714 } finally {
5715 store.activeExecutionContext = prior;
5716 }
5717 }
5718 }
5719 return [...recomputed];
5720 }
5721
5722 function executeResumeContextBindings(store, registry, componentArtifact) {
5723 const expected = new Map(
5724 (componentArtifact?.instance_context_bindings ?? [])
5725 .map((binding) => [binding.consumer_instance, binding])
5726 );
5727 for (const program of registry.definitions.restorePrograms.values()) {
5728 for (const record of program.instructions ?? []) {
5729 if (record.phase !== "R7") continue;
5730 const instruction = record.instruction;
5731 if (instruction.kind !== "bind_context_consumer") {
5732 throw new ResumeBootError("RestoreInstructionFailure");
5733 }
5734 const binding = expected.get(instruction.consumer_instance_id);
5735 if (
5736 binding === undefined
5737 || binding.selected_source !== instruction.selected_source
5738 || (binding.provider_source ?? null) !== (instruction.provider_instance_id ?? null)
5739 || binding.runtime_slot !== instruction.value_slot_id
5740 || !store.contextSlots.has(instruction.value_slot_id)
5741 || store.contextConsumerBindings.has(instruction.consumer_instance_id)
5742 ) {
5743 throw new ResumeBootError("ResumeArtifactMismatch");
5744 }
5745 const installed = {
5746 consumer_instance_id: instruction.consumer_instance_id,
5747 selected_source: instruction.selected_source,
5748 provider_instance_id: instruction.provider_instance_id ?? null,
5749 value_slot_id: instruction.value_slot_id
5750 };
5751 store.contextConsumerBindings.set(
5752 instruction.consumer_instance_id,
5753 instruction.value_slot_id
5754 );
5755 registry.context_bindings.set(instruction.consumer_instance_id, installed);
5756 }
5757 }
5758 if (store.contextConsumerBindings.size !== expected.size) {
5759 throw new ResumeBootError("ResumeArtifactMismatch");
5760 }
5761 }
5762
5763 function collectExactResumeAnchors(manifest) {
5764 const elements = new Map();
5765 for (const element of document.querySelectorAll("[data-presolve-r]")) {
5766 const id = element.getAttribute("data-presolve-r");
5767 if (elements.has(id)) throw new ResumeBootError("DuplicateIdentity");
5768 elements.set(id, element);
5769 }
5770 const comments = new Map();
5771 const walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT);
5772 for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
5773 const value = node.nodeValue ?? "";
5774 if (!value.startsWith("presolve-r-start:") && !value.startsWith("presolve-r-end:")) continue;
5775 const id = value.slice(value.indexOf(":") + 1);
5776 if (comments.has(id)) throw new ResumeBootError("DuplicateIdentity");
5777 comments.set(id, node);
5778 }
5779 const anchors = new Map();
5780 for (const anchor of manifest.anchors) {
5781 const node = anchor.kind === "structural_start" || anchor.kind === "structural_end"
5782 ? comments.get(anchor.anchor_id)
5783 : elements.get(anchor.anchor_id);
5784 if (anchor.required && node === undefined) throw new ResumeBootError("MissingAnchor");
5785 if (node !== undefined) anchors.set(anchor.anchor_id, node);
5786 }
5787 return anchors;
5788 }
5789
5790 function canonicalResumeValueEqual(left, right) {
5791 return JSON.stringify(left) === JSON.stringify(right);
5792 }
5793
5794 function restoreResumeComponentsSlotsAndStructure(
5795 manifest,
5796 registry,
5797 store,
5798 componentArtifact
5799 ) {
5800 const componentRecords = new Map();
5801 const slotRecords = new Map();
5802 const structuralRecords = new Map();
5803 for (const item of manifest.phase_i_component_resume_records ?? []) {
5804 if (item.record_kind === "component_instance") {
5805 const record = item.component_instance;
5806 if (componentRecords.has(record.instance)) throw new ResumeBootError("DuplicateIdentity");
5807 componentRecords.set(record.instance, record);
5808 } else if (item.record_kind === "slot_binding") {
5809 const record = item.slot_binding;
5810 if (slotRecords.has(record.binding)) throw new ResumeBootError("DuplicateIdentity");
5811 slotRecords.set(record.binding, record);
5812 } else if (item.record_kind === "structural_region") {
5813 const record = item.structural_region;
5814 if (structuralRecords.has(record.region)) throw new ResumeBootError("DuplicateIdentity");
5815 structuralRecords.set(record.region, record);
5816 }
5817 }
5818
5819 const planned = new Map(
5820 (componentArtifact.instances ?? []).map((instance) => [instance.instance, instance])
5821 );
5822 const templateInstances = new Set(
5823 (componentArtifact.structural_programs ?? [])
5824 .flatMap((program) => program.template_instances ?? [])
5825 );
5826 if (componentRecords.size !== planned.size + templateInstances.size) {
5827 throw new ResumeBootError("ResumeArtifactMismatch");
5828 }
5829 for (const record of componentRecords.values()) {
5830 const instance = planned.get(record.instance);
5831 if (instance !== undefined) {
5832 if (
5833 record.component !== instance.component
5834 || (record.parent_instance ?? null) !== (instance.parent ?? null)
5835 || (record.structural_region ?? null) !== (instance.structural_region ?? null)
5836 || record.active_status !== "active"
5837 ) {
5838 throw new ResumeBootError("ResumeArtifactMismatch");
5839 }
5840 } else if (!templateInstances.has(record.instance) || record.active_status !== "inactive") {
5841 throw new ResumeBootError("ResumeArtifactMismatch");
5842 }
5843 const runtimeRecord = { ...record, status: record.active_status };
5844 registry.component_records.set(record.instance, runtimeRecord);
5845 store.componentInstances.set(record.instance, runtimeRecord);
5846 }
5847
5848 const expectedSlots = new Map(
5849 (componentArtifact.slot_binding_programs ?? []).map((binding) => [binding.binding, binding])
5850 );
5851 if (slotRecords.size !== expectedSlots.size) throw new ResumeBootError("ResumeArtifactMismatch");
5852 for (const record of slotRecords.values()) {
5853 const binding = expectedSlots.get(record.binding);
5854 if (
5855 binding === undefined
5856 || record.caller_instance !== binding.caller_instance
5857 || record.callee_instance !== binding.callee_instance
5858 ) {
5859 throw new ResumeBootError("ResumeArtifactMismatch");
5860 }
5861 store.slotBindings.set(record.binding, binding);
5862 }
5863
5864 const expectedRegions = new Map(
5865 (componentArtifact.structural_programs ?? []).map((program) => [program.region, program])
5866 );
5867 if (structuralRecords.size !== expectedRegions.size) {
5868 throw new ResumeBootError("ResumeArtifactMismatch");
5869 }
5870 for (const record of structuralRecords.values()) {
5871 const program = expectedRegions.get(record.region);
5872 if (program === undefined || record.active_status !== "inactive") {
5873 throw new ResumeBootError("ResumeArtifactMismatch");
5874 }
5875 const runtimeRecord = { ...record, program, selection_value: undefined };
5876 registry.structural_records.set(record.region, runtimeRecord);
5877 }
5878
5879 const restoredRegions = new Map();
5880 for (const program of registry.definitions.restorePrograms.values()) {
5881 for (const record of program.instructions ?? []) {
5882 if (record.phase !== "R9") continue;
5883 const instruction = record.instruction;
5884 if (
5885 instruction.kind !== "restore_structural_selection"
5886 || (restoredRegions.has(instruction.region_id)
5887 && restoredRegions.get(instruction.region_id) !== instruction.slot_id)
5888 ) {
5889 throw new ResumeBootError("RestoreInstructionFailure");
5890 }
5891 if (restoredRegions.has(instruction.region_id)) continue;
5892 const runtimeRecord = registry.structural_records.get(instruction.region_id);
5893 const schema = registry.definitions.slots.get(instruction.slot_id);
5894 const value = registry.slot_values.get(instruction.slot_id);
5895 if (runtimeRecord === undefined || schema === undefined || value === undefined) {
5896 throw new ResumeBootError("ResumeArtifactMismatch");
5897 }
5898 const stateSlot = (componentArtifact.instances ?? [])
5899 .flatMap((instance) => instance.state_slots ?? [])
5900 .find((slot) => slot.slot_id === schema.existing_storage_slot_id);
5901 if (stateSlot === undefined || !canonicalResumeValueEqual(value, stateSlot.initial_value)) {
5902 throw new ResumeBootError("StructuralStateMismatch");
5903 }
5904 runtimeRecord.selection_value = value;
5905 restoredRegions.set(instruction.region_id, instruction.slot_id);
5906 }
5907 }
5908 if (restoredRegions.size !== expectedRegions.size) {
5909 throw new ResumeBootError("ResumeArtifactMismatch");
5910 }
5911 store.resumeAnchors = collectExactResumeAnchors(manifest);
5912 }
5913
5914 function restoreResumeStructuralOccurrences(snapshot, registry, store, templateManifest, computedArtifact, componentArtifact) {
5915 if (!(store.structuralOccurrenceTemplatesByInvocation instanceof Map)
5916 || !(store.componentRegions instanceof Map)) {
5917 throw new ResumeBootError("ResumeArtifactMismatch");
5918 }
5919 const templatesByInstance = new Map();
5920 for (const template of store.structuralOccurrenceTemplatesByInvocation.values()) {
5921 const templateInstance = template?.occurrence?.template_instance;
5922 if (typeof templateInstance !== "string" || templatesByInstance.has(templateInstance)) {
5923 throw new ResumeBootError("ResumeArtifactMismatch");
5924 }
5925 templatesByInstance.set(templateInstance, template);
5926 }
5927 const staticInstances = new Set((componentArtifact.instances ?? []).map((instance) => instance.instance));
5928 const snapshotOccurrences = snapshot.structuralOccurrences ?? [];
5929 store.structuralOccurrenceResumeActive = snapshotOccurrences.length > 0;
5930 const snapshotIdentities = new Set(snapshotOccurrences.map((record) => record.occurrenceIdentity));
5931 const domIdentities = new Set();
5932 const addDomIdentity = (identity) => {
5933 if (typeof identity !== "string" || !identity.startsWith(STRUCTURAL_OCCURRENCE_IDENTITY_PREFIX)
5934 || domIdentities.has(identity)) return;
5935 domIdentities.add(identity);
5936 addDomIdentity(decodeStructuralOccurrenceIdentity(identity).parent_scope);
5937 };
5938 for (const target of document.querySelectorAll("[data-presolve-ti]")) {
5939 const value = target.getAttribute("data-presolve-ti") ?? "";
5940 const marker = "/template-target:";
5941 const index = value.indexOf(marker);
5942 if (index !== -1) addDomIdentity(value.slice(0, index));
5943 }
5944 if (domIdentities.size !== snapshotIdentities.size
5945 || [...domIdentities].some((identity) => !snapshotIdentities.has(identity))) {
5946 throw new ResumeBootError("StructuralOccurrenceAnchorMismatch");
5947 }
5948 const restored = new Map();
5949 const byParentLocal = new Map();
5950 store.restoredStructuralOccurrencesByParentLocal = new Map();
5951 const fieldsByComponentStorage = new Map();
5952 for (const state of computedArtifact?.state ?? []) {
5953 fieldsByComponentStorage.set(`${state.component}\u001f${state.storage}`, state.field);
5954 }
5955 store.templateTargetsById = new Map();
5956 store.ordinaryBindingsById = new Map();
5957 store.ordinaryEventsByTargetAndType = new Map();
5958 store.resumeStructuralRegistryPrepared = true;
5959 for (const record of snapshotOccurrences) {
5960 const decoded = decodeStructuralOccurrenceIdentity(record.occurrenceIdentity);
5961 if (decoded.template_instance !== record.templateInstance
5962 || decoded.parent_scope !== record.parentScope
5963 || decoded.region !== record.structuralRegion
5964 || decoded.local_occurrence !== record.localOccurrence) {
5965 throw new ResumeBootError("StructuralOccurrenceIdentityMismatch");
5966 }
5967 const template = templatesByInstance.get(record.templateInstance);
5968 if (template === undefined || template.structural_region !== record.structuralRegion) {
5969 throw new ResumeBootError("StructuralOccurrenceIdentityMismatch");
5970 }
5971 const parentIsStatic = staticInstances.has(record.parentScope);
5972 const parent = restored.get(record.parentScope);
5973 if (!parentIsStatic && parent === undefined) {
5974 throw new ResumeBootError("StructuralOccurrenceParentMismatch");
5975 }
5976 if (parent !== undefined && template.occurrence.parent_template_instance !== parent.template_instance) {
5977 throw new ResumeBootError("StructuralOccurrenceIdentityMismatch");
5978 }
5979 if (parentIsStatic && template.occurrence.parent_template_instance !== record.parentScope) {
5980 throw new ResumeBootError("StructuralOccurrenceIdentityMismatch");
5981 }
5982 const records = deriveStructuralOccurrenceRecords(template, record.occurrenceIdentity);
5983 const expectedState = new Map();
5984 for (const slot of records.state_slots) {
5985 if (slot.serializable !== true || slot.resume_codec === undefined) {
5986 throw new ResumeBootError("StructuralStateUnsupported");
5987 }
5988 expectedState.set(slot.slot_id, slot);
5989 }
5990 if (expectedState.size !== record.state.length) throw new ResumeBootError("StructuralStateMismatch");
5991 const staged = stageStructuralOccurrenceRecords(store, records);
5992 let registration = null;
5993 let effects = null;
5994 try {
5995 for (const state of record.state) {
5996 const slot = expectedState.get(state.slotId);
5997 if (slot === undefined) throw new ResumeBootError("StructuralStateMismatch");
5998 const value = decodeResumeValue(state.value, slot.resume_codec);
5999 store.storageValues.set(slot.slot_id, value);
6000 const field = fieldsByComponentStorage.get(`${records.definition.name}\u001f${slot.storage_id}`);
6001 const component = store.components.get(record.occurrenceIdentity);
6002 if (field === undefined || component === undefined) throw new ResumeBootError("StructuralStateMismatch");
6003 component.state[field] = value;
6004 }
6005 registration = registerStructuralOccurrenceRecords(store, staged);
6006 effects = activateStructuralEffectInstances(store, staged, true);
6007 const transaction = Object.freeze({ ...staged, registration, effects, dispose: () => {
6008 for (const child of [...(transaction.children ?? [])].reverse()) child.dispose();
6009 effects?.dispose();
6010 registration?.rollback();
6011 staged.rollback();
6012 }, children: [] });
6013 restored.set(record.occurrenceIdentity, transaction);
6014 registry.structural_occurrences.set(record.occurrenceIdentity, transaction);
6015 const key = `${record.parentScope}\u001f${record.localOccurrence}`;
6016 const siblings = byParentLocal.get(key) ?? [];
6017 siblings.push(transaction);
6018 byParentLocal.set(key, siblings);
6019 if (parent !== undefined) parent.children.push(transaction);
6020 } catch (error) {
6021 effects?.dispose();
6022 registration?.rollback();
6023 staged.rollback();
6024 throw error;
6025 }
6026 }
6027 for (const [key, transactions] of byParentLocal) {
6028 store.restoredStructuralOccurrencesByParentLocal.set(key, Object.freeze(transactions));
6029 }
6030 const anchors = collectOrdinaryTargetAnchors();
6031 for (const target of templateManifest.ordinary_targets ?? []) {
6032 const artifact = (componentArtifact.ordinary_template_targets ?? []).find((candidate) => candidate.id === target.id);
6033 if (artifact === undefined || artifact.template_entity_id !== target.template_entity_id) continue;
6034 const host = anchors.targets.get(target.id);
6035 if (host?.kind !== "conditional") continue;
6036 const program = [...store.componentRegions.values()].find((candidate) =>
6037 candidate.host_template_entity === artifact.template_entity_id
6038 && candidate.host_component === artifact.component_id
6039 );
6040 const component = store.components.get(target.component_instance_id);
6041 const binding = (templateManifest.ordinary_bindings ?? []).find((candidate) =>
6042 candidate.instance_target_id === target.id && candidate.kind === "conditional"
6043 );
6044 const field = fieldNameFromThisMember(binding?.expression);
6045 if (program === undefined || component === undefined || field === null) {
6046 throw new ResumeBootError("ResumeArtifactMismatch");
6047 }
6048 host.structural_branch = component.state[field] === true ? "true" : "false";
6049 host.structural_occurrences = store.restoredStructuralOccurrencesByParentLocal.get(
6050 `${target.component_instance_id}\u001fconditional:${host.structural_branch}`
6051 ) ?? Object.freeze([]);
6052 }
6053 }
6054
6055 async function restoreResumeForms(templateManifest, snapshot, registry, store, formsArtifact) {
6056 const restoreRecords = [...registry.definitions.restorePrograms.values()]
6057 .flatMap((program) => program.instructions ?? [])
6058 .filter((record) => ["R11", "R12", "R13", "R14", "R15"].includes(record.phase));
6059 if (formsArtifact === null) {
6060 if (restoreRecords.length !== 0) throw new ResumeBootError("ResumeArtifactMismatch");
6061 return;
6062 }
6063 const targets = collectOrdinaryTargetAnchors();
6064 const definitions = new Map((formsArtifact.forms ?? []).map((form) => [form.id, form]));
6065 const instances = new Map((formsArtifact.instances ?? []).map((instance) => [instance.id, instance]));
6066 if (definitions.size !== (formsArtifact.forms ?? []).length || instances.size !== (formsArtifact.instances ?? []).length) {
6067 throw new ResumeBootError("DuplicateIdentity");
6068 }
6069 store.forms = new Map();
6070 store.formInstances = new Map();
6071 store.formBindingsByAnchor = new Map();
6072 store.formBindingsByField = new Map();
6073 store.formHostsByAnchor = new Map();
6074 store.composingFormControls = new WeakSet();
6075 const slotOwners = new Map();
6076 for (const instance of instances.values()) {
6077 const definition = definitions.get(instance.form);
6078 if (definition === undefined || store.formInstances.has(instance.id)) {
6079 throw new ResumeBootError("ResumeArtifactMismatch");
6080 }
6081 const fields = new Map((definition.fields ?? []).map((field) => [field.id, {
6082 value: field.initial_value,
6083 initial: field.initial_value,
6084 dirty: false,
6085 touched: false,
6086 validation: [],
6087 validation_issues: [],
6088 validation_pending: false,
6089 validation_generation: 0
6090 }]));
6091 if (fields.size !== (definition.fields ?? []).length) throw new ResumeBootError("DuplicateIdentity");
6092 const runtime = {
6093 definition,
6094 instance,
6095 fields,
6096 aggregate_valid: true,
6097 submission: "Idle",
6098 submission_generation: 0,
6099 submission_controller: null,
6100 diagnostics: store.diagnostics
6101 };
6102 store.forms.set(definition.id, definition);
6103 store.formInstances.set(instance.id, runtime);
6104 registry.form_records.set(instance.id, runtime);
6105 for (const slots of instance.field_slots ?? []) {
6106 if (!fields.has(slots.field)) throw new ResumeBootError("ResumeArtifactMismatch");
6107 for (const [kind, slot] of [["value", slots.value], ["dirty", slots.dirty], ["touched", slots.touched], ["validation", slots.validation]]) {
6108 if (slotOwners.has(slot)) throw new ResumeBootError("DuplicateIdentity");
6109 slotOwners.set(slot, { instance: runtime, field: slots.field, kind });
6110 }
6111 }
6112 if (slotOwners.has(instance.aggregate_validation_slot) || slotOwners.has(instance.submission_slot)) {
6113 throw new ResumeBootError("DuplicateIdentity");
6114 }
6115 slotOwners.set(instance.aggregate_validation_slot, { instance: runtime, field: null, kind: "aggregate" });
6116 slotOwners.set(instance.submission_slot, { instance: runtime, field: null, kind: "submission" });
6117 }
6118
6119 const snapshotValues = snapshotValuesBySlot(snapshot);
6120 const restored = new Set();
6121 for (const record of restoreRecords) {
6122 if (record.phase === "R15") continue;
6123 const instruction = record.instruction;
6124 if (instruction.kind !== "decode_value") continue;
6125 const schema = registry.definitions.slots.get(instruction.slot_id);
6126 if (schema === undefined || schema.restore_phase !== record.phase || !snapshotValues.has(instruction.slot_id)) {
6127 throw new ResumeBootError("RestoreInstructionFailure");
6128 }
6129 const owner = slotOwners.get(schema.existing_storage_slot_id);
6130 if (owner === undefined || restored.has(instruction.slot_id)) throw new ResumeBootError("ResumeArtifactMismatch");
6131 const value = decodeResumeValue(snapshotValues.get(instruction.slot_id), instruction.codec);
6132 const field = owner.field === null ? undefined : owner.instance.fields.get(owner.field);
6133 if (owner.kind === "value" && field !== undefined) field.value = value;
6134 else if (owner.kind === "dirty" && field !== undefined && typeof value === "boolean") field.dirty = value;
6135 else if (owner.kind === "touched" && field !== undefined && typeof value === "boolean") field.touched = value;
6136 else if (owner.kind === "validation" && field !== undefined && Array.isArray(value) && value.every((item) => typeof item === "string")) field.validation = value;
6137 else if (owner.kind === "aggregate" && typeof value === "boolean") owner.instance.aggregate_valid = value;
6138 else if (owner.kind === "submission" && ["Idle", "Completed", "Failed", "Invalid"].includes(value)) owner.instance.submission = value;
6139 else throw new ResumeBootError(owner.kind === "submission" ? "UnstableFormSubmission" : "ValueTypeMismatch");
6140 registry.slot_values.set(instruction.slot_id, value);
6141 restored.add(instruction.slot_id);
6142 }
6143 const expectedSlots = [...registry.definitions.slots.values()]
6144 .filter((schema) => ["R11", "R12", "R13", "R14"].includes(schema.restore_phase));
6145 if (restored.size !== expectedSlots.length) throw new ResumeBootError("RestoreInstructionFailure");
6146
6147 for (const bridge of templateManifest.form_bindings ?? []) {
6148 const target = targets.targets.get(bridge.instance_target_id);
6149 const formInstance = store.formInstances.get(bridge.form_instance_id);
6150 if (!(target instanceof Element) || targets.duplicates.has(bridge.instance_target_id) || formInstance === undefined) {
6151 throw new ResumeBootError("MissingAnchor");
6152 }
6153 const binding = formInstance.definition.bindings.find((item) => item.id === bridge.field_binding_id);
6154 if (binding === undefined || binding.field === undefined || binding.channel !== bridge.channel || store.formBindingsByAnchor.has(bridge.instance_target_id)) {
6155 throw new ResumeBootError("ResumeArtifactMismatch");
6156 }
6157 const runtimeBinding = { bridge, binding, element: target, formInstance };
6158 store.formBindingsByAnchor.set(bridge.instance_target_id, runtimeBinding);
6159 const key = `${bridge.form_instance_id}|${binding.field}`;
6160 const bindings = store.formBindingsByField.get(key) ?? [];
6161 bindings.push(runtimeBinding);
6162 store.formBindingsByField.set(key, bindings);
6163 writeFormControl(runtimeBinding, formInstance.fields.get(binding.field)?.value, true);
6164 }
6165 const expectedBindings = [...instances.values()].reduce((count, instance) => count + (definitions.get(instance.form)?.bindings?.length ?? 0), 0);
6166 if (store.formBindingsByAnchor.size !== expectedBindings) throw new ResumeBootError("ResumeArtifactMismatch");
6167 for (const bridge of templateManifest.form_hosts ?? []) {
6168 const target = targets.targets.get(bridge.instance_target_id);
6169 const formInstance = store.formInstances.get(bridge.form_instance_id);
6170 const host = (formsArtifact.hosts ?? []).find((candidate) =>
6171 candidate.host_anchor === bridge.host_anchor
6172 && candidate.form_instance === bridge.form_instance_id
6173 );
6174 if (!(target instanceof HTMLFormElement) || targets.duplicates.has(bridge.instance_target_id)
6175 || formInstance === undefined || host === undefined || host.event !== "submit"
6176 || store.formHostsByAnchor.has(bridge.instance_target_id)) {
6177 throw new ResumeBootError("ResumeArtifactMismatch");
6178 }
6179 store.formHostsByAnchor.set(bridge.instance_target_id, {
6180 bridge,
6181 host,
6182 element: target,
6183 formInstance
6184 });
6185 target.addEventListener(host.event, (event) =>
6186 dispatchFormSubmit(store, event, bridge.instance_target_id)
6187 );
6188 }
6189 if (store.formHostsByAnchor.size !== (templateManifest.form_hosts ?? []).length) {
6190 throw new ResumeBootError("ResumeArtifactMismatch");
6191 }
6192 const resumedValidations = [];
6193 for (const formInstance of store.formInstances.values()) {
6194 if ((formInstance.definition.fields ?? []).some((field) => field.semantic_type === "File[]")
6195 || (formInstance.definition.validation_rules ?? []).some((rule) => rule.kind === "StandardSchema")) {
6196 for (const fieldId of formInstance.fields.keys()) {
6197 resumedValidations.push(validateFormField(formInstance, fieldId));
6198 }
6199 }
6200 }
6201 await Promise.all(resumedValidations);
6202 installFormControlListeners(store);
6203 installFormSubmissionDisposal(store);
6204 window.__PRESOLVE_FORMS__ = {
6205 resetForm: (instanceId) => resetForm(store, instanceId),
6206 resetField: (instanceId, fieldId) => resetField(store, instanceId, fieldId)
6207 };
6208 }
6209
6210 function allocateResumeResources(store, registry, resourcesArtifact) {
6211 if (resourcesArtifact === null) return;
6212 const declarations = new Map((resourcesArtifact.declarations ?? []).map((declaration) => [declaration.id, declaration]));
6213 if (declarations.size !== (resourcesArtifact.declarations ?? []).length) {
6214 throw new ResumeBootError("ResourceArtifactMismatch");
6215 }
6216 const staged = [];
6217 for (const activation of resourcesArtifact.activations ?? []) {
6218 const declaration = declarations.get(activation.declaration);
6219 if (declaration === undefined) {
6220 throw new ResumeBootError("ResourceArtifactMismatch");
6221 }
6222 if (declaration.endpoint?.resume_policy === "reload") {
6223 continue;
6224 }
6225 if (declaration.endpoint?.resume_policy !== "snapshot") {
6226 throw new ResumeBootError("ResourceResumeUnsupported");
6227 }
6228 const slotIds = [activation.state_slot, activation.data_slot, activation.error_slot];
6229 const schemasByExisting = new Map(
6230 [...registry.definitions.slots.values()].map((schema) => [schema.existing_storage_slot_id, schema])
6231 );
6232 const stateSchema = schemasByExisting.get(activation.state_slot);
6233 const dataSchema = schemasByExisting.get(activation.data_slot);
6234 const errorSchema = schemasByExisting.get(activation.error_slot);
6235 if (stateSchema === undefined || dataSchema === undefined || errorSchema === undefined
6236 || stateSchema.restore_phase !== "R3" || dataSchema.restore_phase !== "R3" || errorSchema.restore_phase !== "R3"
6237 || store.resources.has(activation.id)
6238 || store.resourceActivationsByInstanceDeclaration.has(`${activation.component_instance}\u001f${activation.declaration}`)
6239 || slotIds.some((slot) => store.resourceSlots.has(slot))) {
6240 throw new ResumeBootError("ResourceArtifactMismatch");
6241 }
6242 staged.push({ activation, declaration, schemas: [stateSchema, dataSchema, errorSchema] });
6243 }
6244 for (const record of staged) {
6245 const resource = {
6246 activation: record.activation,
6247 declaration: record.declaration,
6248 controller: new AbortController(),
6249 state: "restoring",
6250 generation: null,
6251 data: null,
6252 error: null,
6253 restoredValues: {}
6254 };
6255 store.resources.set(record.activation.id, resource);
6256 store.resourceActivationsByInstanceDeclaration.set(
6257 `${record.activation.component_instance}\u001f${record.activation.declaration}`,
6258 record.activation.id
6259 );
6260 for (const [kind, schema] of [["state", record.schemas[0]], ["data", record.schemas[1]], ["error", record.schemas[2]]]) {
6261 store.resourceSlots.set(schema.existing_storage_slot_id, { resource, kind });
6262 resource.restoredValues[kind] = undefined;
6263 }
6264 }
6265 }
6266
6267 function finalizeRestoredResources(store) {
6268 for (const resource of store.resources.values()) {
6269 const values = resource.restoredValues;
6270 const lifecycle = values.state;
6271 if (lifecycle === null || typeof lifecycle !== "object" || Array.isArray(lifecycle)
6272 || !exactObjectKeys(lifecycle, ["state", "generation"])
6273 || !["ready", "failed"].includes(lifecycle.state)
6274 || !Number.isInteger(lifecycle.generation) || lifecycle.generation < 1
6275 || values.data === undefined || values.error === undefined
6276 || (lifecycle.state === "ready" && values.error !== null)
6277 || (lifecycle.state === "failed" && values.data !== null)) {
6278 throw new ResumeBootError("ResourceSnapshotMismatch");
6279 }
6280 resource.state = lifecycle.state;
6281 resource.generation = lifecycle.generation;
6282 resource.data = values.data;
6283 resource.error = values.error;
6284 delete resource.restoredValues;
6285 }
6286 }
6287
6288 async function restoreResumeRuntimeThroughForms(
6289 manifest,
6290 snapshot,
6291 registry,
6292 templateManifest,
6293 computedArtifact,
6294 contextArtifact,
6295 effectArtifact,
6296 componentArtifact,
6297 formsArtifact,
6298 resourcesArtifact,
6299 packageInvocationsArtifact,
6300 diagnostics
6301 ) {
6302 const store = allocateResumeStateComputedStore(
6303 registry,
6304 manifest,
6305 templateManifest,
6306 computedArtifact,
6307 contextArtifact,
6308 effectArtifact,
6309 componentArtifact,
6310 packageInvocationsArtifact,
6311 diagnostics
6312 );
6313 allocateResumeResources(store, registry, resourcesArtifact);
6314 executeResumeDecodeAndWrites(store, registry, snapshot, new Set(["R3", "R4"]));
6315 finalizeRestoredResources(store);
6316 synchronizeRestoredComponentState(store, computedArtifact, componentArtifact);
6317 const recomputationRuns = executeResumeComputedRecomputation(store, registry);
6318 executeResumeDecodeAndWrites(store, registry, snapshot, new Set(["R6"]));
6319 executeResumeContextBindings(store, registry, componentArtifact);
6320 restoreResumeComponentsSlotsAndStructure(manifest, registry, store, componentArtifact);
6321 restoreResumeStructuralOccurrences(
6322 snapshot,
6323 registry,
6324 store,
6325 templateManifest,
6326 computedArtifact,
6327 componentArtifact
6328 );
6329 await restoreResumeForms(templateManifest, snapshot, registry, store, formsArtifact);
6330 installResumeDomBindings(store, templateManifest, componentArtifact);
6331 await initializeResourcesRuntime(store, resourcesArtifact, diagnostics, "reload");
6332 establishResumeEffects(registry, store, effectArtifact);
6333 installEffectDisposal(store);
6334 installResumeActivationListeners(registry, store);
6335 const state = runtimeState({
6336 manifest: templateManifest,
6337 diagnostics,
6338 store,
6339 components: debugComponents(store),
6340 computed: debugComputed(store),
6341 computed_update_runs: 0,
6342 context_initial_source_runs: store.contextInitialSourceRuns,
6343 context_slots: [...store.contextSlots.entries()],
6344 context_consumer_bindings: [...store.contextConsumerBindings.entries()],
6345 context_failures: store.contextFailures,
6346 context_update_source_runs: store.contextUpdateSourceRuns,
6347 component_initialization_runs: [],
6348 component_instance_tree: [...store.componentInstances.values()],
6349 forms: [...store.formInstances.values()].map((instance) => ({
6350 id: instance.instance.id,
6351 form: instance.definition.id,
6352 aggregate_valid: instance.aggregate_valid,
6353 submission: instance.submission
6354 })),
6355 resources: [...store.resources.entries()].map(([id, resource]) => ({
6356 id,
6357 state: resource.state,
6358 generation: resource.generation
6359 })),
6360 package_invocations: store.packageInvocationRuns,
6361 slot_binding_runs: [],
6362 component_failures: []
6363 });
6364 state.resume_recomputation_runs = recomputationRuns;
6365 return state;
6366 }
6367
6368 function runtimeState({
6369 manifest = null,
6370 missingAnchors = [],
6371 store = null,
6372 components = [],
6373 computed = [],
6374 computed_update_runs = 0,
6375 initial_effect_runs = [],
6376 completed_action_effect_runs = [],
6377 structural_effect_runs = [],
6378 context_initial_source_runs = [],
6379 context_slots = [],
6380 context_consumer_bindings = [],
6381 context_failures = [],
6382 context_update_source_runs = [],
6383 component_initialization_runs = [],
6384 component_instance_tree = [],
6385 forms = [],
6386 resources = [],
6387 opaque_terminals = [],
6388 package_invocations = [],
6389 slot_binding_runs = [],
6390 component_failures = [],
6391 diagnostics
6392 }) {
6393 return {
6394 runtime_version: RUNTIME_VERSION,
6395 supported_schema_version: SUPPORTED_SCHEMA_VERSION,
6396 manifest,
6397 missingAnchors,
6398 diagnostics,
6399 store,
6400 components,
6401 computed,
6402 computed_update_runs,
6403 initial_effect_runs,
6404 completed_action_effect_runs,
6405 structural_effect_runs,
6406 context_initial_source_runs,
6407 context_slots,
6408 context_consumer_bindings,
6409 context_failures,
6410 context_update_source_runs,
6411 component_initialization_runs,
6412 component_instance_tree,
6413 forms,
6414 resources,
6415 opaque_terminals,
6416 package_invocations,
6417 slot_binding_runs,
6418 component_failures
6419 };
6420 }
6421
6422 async function initializeResourcesRuntime(store, resourcesArtifact, diagnostics, resumePolicy = null) {
6423 if (resourcesArtifact === null) return;
6424 window.addEventListener("pagehide", () => {
6425 for (const resource of store.resources.values()) resource.controller.abort();
6426 }, { once: true });
6427 const declarations = new Map(resourcesArtifact.declarations.map((declaration) => [declaration.id, declaration]));
6428 const records = [];
6429 for (const activation of resourcesArtifact.activations) {
6430 const declaration = declarations.get(activation.declaration);
6431 if (declaration === undefined) throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
6432 if (resumePolicy !== null && declaration.endpoint.resume_policy !== resumePolicy) continue;
6433 if (!["Client", "Shared"].includes(declaration.execution_boundary)) {
6434 reportDiagnostic(diagnostics, "PSR_RESOURCE_SERVER_UNAVAILABLE", "A server-only Resource cannot activate in the browser runtime", { activation, declaration }, true);
6435 throw new PresolveBootError("PSR_RESOURCE_SERVER_UNAVAILABLE");
6436 }
6437 const controller = new AbortController();
6438 const record = { activation, declaration, controller, state: "pending", generation: 1, data: null, error: null };
6439 const activationKey = `${activation.component_instance}\u001f${activation.declaration}`;
6440 if (store.resources.has(activation.id) || store.resourceActivationsByInstanceDeclaration.has(activationKey)) {
6441 throw new PresolveBootError("PSR_INVALID_RESOURCES_ARTIFACT");
6442 }
6443 store.resources.set(activation.id, record);
6444 store.resourceActivationsByInstanceDeclaration.set(activationKey, activation.id);
6445 records.push(record);
6446 }
6447 await Promise.all(records.map(async (record) => {
6448 try {
6449 const module = await import(record.declaration.endpoint.runtime_location);
6450 const endpoint = module[record.declaration.endpoint.export];
6451 if (typeof endpoint !== "function") throw new Error("endpoint-export-missing");
6452 const result = await endpoint({ signal: record.controller.signal, inputs: Object.freeze({}) });
6453 if (record.controller.signal.aborted) {
6454 record.state = "cancelled";
6455 } else {
6456 try {
6457 record.data = decodeResourceValue(result, record.declaration.data_codec);
6458 record.state = "ready";
6459 } catch (_) {
6460 record.state = "failed";
6461 record.data = null;
6462 record.error = null;
6463 reportDiagnostic(diagnostics, "PSR_RESOURCE_VALUE_CODEC_FAILURE", "A Resource endpoint result did not match its compiler-issued data codec", { activation: record.activation.id });
6464 }
6465 }
6466 } catch (error) {
6467 if (record.controller.signal.aborted) {
6468 record.state = "cancelled";
6469 } else {
6470 const endpointError = error instanceof Error ? error.message : error;
6471 try {
6472 record.error = decodeResourceValue(endpointError, record.declaration.error_codec);
6473 record.state = "failed";
6474 reportDiagnostic(diagnostics, "PSR_RESOURCE_ENDPOINT_FAILURE", "A compiler-authorized Resource endpoint failed", { activation: record.activation.id, error: record.error });
6475 } catch (_) {
6476 record.state = "failed";
6477 record.data = null;
6478 record.error = null;
6479 reportDiagnostic(diagnostics, "PSR_RESOURCE_VALUE_CODEC_FAILURE", "A Resource endpoint error did not match its compiler-issued error codec", { activation: record.activation.id });
6480 }
6481 }
6482 }
6483 invalidateResourceComputeds(store, record.activation);
6484 }));
6485 }
6486
6487 async function initializeRuntime(manifest, computedArtifact, contextArtifact, effectArtifact, componentArtifact, formsArtifact, resourcesArtifact, opaqueArtifact, packageInvocationsArtifact, diagnostics) {
6488 const bindingAnchors = collectBindingAnchors();
6489 const conditionalAnchors = collectConditionalAnchors();
6490 const listAnchors = collectListAnchors();
6491 const elementsByNode = collectElementAnchors();
6492 const store = createRuntimeStore(elementsByNode, diagnostics, computedArtifact, contextArtifact, effectArtifact, componentArtifact, opaqueArtifact, packageInvocationsArtifact);
6493 window.addEventListener("pagehide", () => {
6494 cancelPackageInvocationsForComponent(store, null);
6495 }, { once: true });
6496 store.componentArtifact = componentArtifact;
6497 store.componentInstances = new Map((componentArtifact?.instances ?? []).map((instance) => [instance.instance, { ...instance, status: "created" }]));
6498 store.slotBindings = new Map((componentArtifact?.slot_binding_programs ?? []).map((binding) => [binding.binding, binding]));
6499 store.instanceContextBindings = new Map((componentArtifact?.instance_context_bindings ?? []).map((binding) => [binding.consumer_instance, binding]));
6500 store.componentRegions = new Map((componentArtifact?.structural_programs ?? []).map((program) => [program.region, program]));
6501 // Inactive compiler-issued occurrence templates. Dynamic materialization
6502 // must consume this table; it must not rediscover component structure from
6503 // DOM nodes or selectors.
6504 store.structuralOccurrences = new Map((componentArtifact?.structural_programs ?? []).map(
6505 (program) => [program.region, program.template_occurrences]
6506 ));
6507 store.structuralOccurrenceTemplatesByInvocation = structuralOccurrenceTemplateRegistry(
6508 manifest,
6509 componentArtifact,
6510 computedArtifact
6511 );
6512 store.structuralSlotProjectionPrograms = structuralSlotProjectionRegistry(manifest, componentArtifact);
6513 store.structuralOccurrencesByInvocation = new Map(
6514 [...store.structuralOccurrenceTemplatesByInvocation].map(([invocation, record]) => [
6515 invocation,
6516 Object.freeze({
6517 ...record.occurrence,
6518 structural_region: record.structural_region
6519 })
6520 ])
6521 );
6522 const missingAnchors = manifest.schema_version === SUPPORTED_SCHEMA_VERSION
6523 ? []
6524 : collectMissingAnchors(
6525 manifest,
6526 bindingAnchors,
6527 conditionalAnchors,
6528 listAnchors,
6529 elementsByNode
6530 );
6531
6532 for (const anchor of missingAnchors) {
6533 reportDiagnostic(
6534 diagnostics,
6535 anchor.code,
6536 anchor.kind === "element"
6537 ? "Manifest element anchor was not found in the rendered DOM"
6538 : anchor.kind === "conditional"
6539 ? "Manifest conditional anchor was not found in the rendered DOM"
6540 : anchor.kind === "list"
6541 ? "Manifest list anchor was not found in the rendered DOM"
6542 : "Manifest binding anchor was not found in the rendered DOM",
6543 anchor
6544 );
6545 }
6546
6547 const resourceInitialization = initializeResourcesRuntime(store, resourcesArtifact, diagnostics);
6548
6549 if (manifest.schema_version === SUPPORTED_SCHEMA_VERSION) {
6550 const definitions = new Map((manifest.components ?? []).map((component) => [component.component_id, component]));
6551 for (const instance of componentArtifact.instances ?? []) {
6552 const definition = definitions.get(instance.component);
6553 if (definition === undefined) throw new PresolveBootError("PSR_INVALID_ORDINARY_COMPONENT");
6554 const definitionStates = (computedArtifact?.state ?? []).filter(
6555 (state) => state.component === definition.name
6556 );
6557 if ((instance.state_slots ?? []).length !== definitionStates.length) {
6558 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
6559 }
6560 for (const slot of instance.state_slots ?? []) {
6561 const pair = `${instance.instance}|${slot.storage_id}`;
6562 if (
6563 store.stateSlotsByInstanceStorage.has(pair)
6564 || store.storageValues.has(slot.slot_id)
6565 ) {
6566 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
6567 }
6568 store.stateSlotsByInstanceStorage.set(pair, slot);
6569 store.storageValues.set(slot.slot_id, initialStateSlotValue(slot));
6570 }
6571 for (const state of definitionStates) {
6572 if (!store.stateSlotsByInstanceStorage.has(`${instance.instance}|${state.storage}`)) {
6573 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
6574 }
6575 }
6576 for (const slot of instance.computed_slots ?? []) {
6577 const pair = `${instance.instance}|${slot.computed_id}`;
6578 if (!slot.cache_slot_id.startsWith(`${instance.instance}/computed-cache:`)
6579 || !slot.dirty_slot_id.startsWith(`${instance.instance}/computed-dirty:`)
6580 || store.computedSlotsByInstanceComputed.has(pair)
6581 || store.computedDirtySlots.has(slot.dirty_slot_id)) {
6582 throw new PresolveBootError("PSR_INVALID_COMPONENT_ARTIFACT");
6583 }
6584 store.computedSlotsByInstanceComputed.set(pair, slot);
6585 store.computedDirtySlots.set(slot.dirty_slot_id, slot.dirty_initial_value === true);
6586 }
6587 const component = { instance_id: instance.instance, name: instance.component, manifest: definition, state: {} };
6588 for (const state of computedArtifact?.state ?? []) {
6589 if (state.component !== definition.name) continue;
6590 const slot = store.stateSlotsByInstanceStorage.get(`${instance.instance}|${state.storage}`);
6591 if (slot !== undefined) component.state[state.field] = store.storageValues.get(slot.slot_id);
6592 }
6593 store.components.set(instance.instance, component);
6594 registerActions(store, component, definition);
6595 registerLegacyComponentEvents(store, component);
6596 }
6597 initializeOrdinaryInstanceRuntime(store, manifest, componentArtifact);
6598 } else {
6599 for (const manifestComponent of manifest.components ?? []) {
6600 const component = initializeComponentRuntime(
6601 store,
6602 manifestComponent,
6603 bindingAnchors,
6604 conditionalAnchors,
6605 listAnchors
6606 );
6607 registerComponentEvents(store, component);
6608 }
6609 }
6610
6611 if (manifest.schema_version === SUPPORTED_SCHEMA_VERSION) {
6612 for (const instance of componentArtifact.instances ?? []) {
6613 executeComputedPlan(store, instance.instance);
6614 }
6615 } else {
6616 executeComputedPlan(store);
6617 }
6618
6619 executeInitialContext(store);
6620
6621 await initializeFormsRuntime(store, formsArtifact, manifest, elementsByNode, diagnostics);
6622
6623 await resourceInitialization;
6624
6625 executeInitialEffects(store);
6626 installEffectDisposal(store);
6627
6628 if (manifest.schema_version === SUPPORTED_SCHEMA_VERSION) {
6629 installOrdinaryInstanceEventListeners(store);
6630 // Schema-v5 component instances can still host the frozen implicit
6631 // decorator-action shape. Those bindings have no ordinary-event record
6632 // because they intentionally predate canonical action batches.
6633 installDelegatedEventListeners(store);
6634 } else {
6635 installDelegatedEventListeners(store);
6636 }
6637
6638 return runtimeState({
6639 manifest,
6640 missingAnchors,
6641 diagnostics,
6642 store,
6643 components: debugComponents(store),
6644 computed: debugComputed(store),
6645 computed_update_runs: store.computedUpdateRuns,
6646 initial_effect_runs: store.initialEffectRuns,
6647 completed_action_effect_runs: store.completedActionEffectRuns,
6648 structural_effect_runs: store.structuralEffectRuns,
6649 context_initial_source_runs: store.contextInitialSourceRuns,
6650 context_slots: [...store.contextSlots.entries()],
6651 context_consumer_bindings: [...store.contextConsumerBindings.entries()],
6652 context_failures: store.contextFailures,
6653 context_update_source_runs: store.contextUpdateSourceRuns,
6654 component_initialization_runs: (componentArtifact?.initialization_batches ?? []).map((batch) => batch.index),
6655 component_instance_tree: [...store.componentInstances.values()],
6656 forms: [...store.formInstances.values()].map((instance) => ({
6657 id: instance.instance.id,
6658 form: instance.definition.id,
6659 aggregate_valid: instance.aggregate_valid,
6660 submission: instance.submission
6661 })),
6662 resources: [...store.resources.entries()].map(([id, resource]) => ({ id, state: resource.state, generation: resource.generation })),
6663 opaque_terminals: [...store.opaqueActivations],
6664 package_invocations: store.packageInvocationRuns,
6665 slot_binding_runs: [...store.slotBindings.keys()],
6666 component_failures: []
6667 });
6668 }
6669
6670 async function boot() {
6671 const diagnostics = [];
6672
6673 try {
6674 const productionArtifact = readProductionRuntimeArtifact();
6675 const productionIndexes = productionOrdinalIndexes(productionArtifact);
6676 const manifest = readManifest(diagnostics);
6677 const computedArtifact = readComputedArtifact(diagnostics);
6678 validateComputedArtifactSchema(computedArtifact, diagnostics);
6679 const contextArtifact = readContextArtifact(diagnostics);
6680 validateContextArtifactSchema(contextArtifact, diagnostics);
6681 const effectArtifact = readEffectArtifact(diagnostics);
6682 validateEffectArtifactSchema(effectArtifact, diagnostics);
6683 const componentArtifact = readComponentArtifact(diagnostics);
6684 validateComponentArtifactSchema(componentArtifact, diagnostics);
6685 validateEffectArtifactInstances(effectArtifact, componentArtifact, diagnostics);
6686 const opaqueArtifact = readOpaqueArtifact(diagnostics);
6687 validateOpaqueArtifact(opaqueArtifact, diagnostics);
6688 const packageInvocationsArtifact = readPackageInvocationsArtifact(diagnostics);
6689 validatePackageInvocationsArtifact(packageInvocationsArtifact, diagnostics);
6690 packageInvocationRegistry = await loadPackageInvocationRegistry(
6691 packageInvocationsArtifact,
6692 diagnostics
6693 );
6694 validateManifestSchema(
6695 manifest,
6696 effectArtifact,
6697 componentArtifact,
6698 opaqueArtifact,
6699 packageInvocationsArtifact,
6700 diagnostics
6701 );
6702 const formsArtifact = readFormsArtifact(diagnostics);
6703 validateFormsArtifact(formsArtifact, manifest, diagnostics);
6704 standardSchemaValidators = await loadStandardSchemaValidators(formsArtifact, diagnostics);
6705 formSubmissionCapabilities = await loadFormSubmissionCapabilities(formsArtifact, diagnostics);
6706 const resourcesArtifact = readResourcesArtifact(diagnostics);
6707 validateResourcesArtifact(resourcesArtifact, diagnostics);
6708
6709 const result = await bootstrapResume({
6710 diagnostics,
6711 resumeBoot: ({ manifest: resumeManifest, snapshot, registry }) => {
6712 if ((opaqueArtifact?.activations ?? []).length > 0) {
6713 throw new ResumeBootError("OpaqueTerminalColdFallback");
6714 }
6715 return restoreResumeRuntimeThroughForms(
6716 resumeManifest,
6717 snapshot,
6718 registry,
6719 manifest,
6720 computedArtifact,
6721 contextArtifact,
6722 effectArtifact,
6723 componentArtifact,
6724 formsArtifact,
6725 resourcesArtifact,
6726 packageInvocationsArtifact,
6727 diagnostics
6728 );
6729 },
6730 coldBoot: () => initializeRuntime(
6731 manifest,
6732 computedArtifact,
6733 contextArtifact,
6734 effectArtifact,
6735 componentArtifact,
6736 formsArtifact,
6737 resourcesArtifact,
6738 opaqueArtifact,
6739 packageInvocationsArtifact,
6740 diagnostics
6741 )
6742 });
6743 const state = result.mode === "cold"
6744 ? result.cold
6745 : result.resume;
6746 state.resume = {
6747 mode: result.mode,
6748 failure: result.failure,
6749 contract_version: RESUME_REGISTRY_CONTRACT_VERSION
6750 };
6751 state.disposeEffects = () => disposeEffectInstances(state.store);
6752 state.resume_registry = result.mode === "resume" ? result.registry : null;
6753 state.resume_debug = [...resumeBootstrapState.debug];
6754 state.production = productionIndexes === null ? null : {
6755 artifact_checksum: productionArtifact.integrity?.artifact_checksum ?? null,
6756 table_kinds: [...productionIndexes.keys()]
6757 };
6758 const status = state.diagnostics.some((diagnostic) => diagnostic.fatal)
6759 || state.missingAnchors.length > 0
6760 ? "error"
6761 : "ready";
6762
6763 document.documentElement.dataset.presolveRuntime = status;
6764 window.__PRESOLVE__ = state;
6765
6766 document.dispatchEvent(
6767 new CustomEvent("presolve:ready", {
6768 detail: state
6769 })
6770 );
6771 } catch (error) {
6772 document.documentElement.dataset.presolveRuntime = "error";
6773 if (error instanceof PresolveBootError) {
6774 reportDiagnostic(
6775 diagnostics,
6776 error.code,
6777 "Runtime boot failed at a closed compiler contract boundary",
6778 { code: error.code },
6779 true
6780 );
6781 } else {
6782 reportDiagnostic(
6783 diagnostics,
6784 "PSR_RUNTIME_BOOT_FAILED",
6785 "Runtime boot failed",
6786 { message: error instanceof Error ? error.message : String(error) },
6787 true
6788 );
6789 }
6790
6791 window.__PRESOLVE__ = runtimeState({
6792 diagnostics
6793 });
6794
6795 document.dispatchEvent(
6796 new CustomEvent("presolve:ready", {
6797 detail: window.__PRESOLVE__
6798 })
6799 );
6800 }
6801 }
6802
6803 window.__PRESOLVE_RESUME__ = Object.freeze({
6804 bootstrapResume,
6805 captureSnapshot,
6806 activateByEvent,
6807 activateBoundary,
6808 debugEvidence: () => [...resumeBootstrapState.debug]
6809 });
6810
6811 if (document.readyState === "loading") {
6812 document.addEventListener("DOMContentLoaded", boot, {
6813 once: true
6814 });
6815 } else {
6816 boot();
6817 }
6818})();
6819"#;
6820
6821#[must_use]
6822pub fn generate_runtime_stub() -> String {
6823 RUNTIME_STUB
6824 .replace(
6825 "__EZ_COMPONENT_SCHEMA_VERSION__",
6826 &crate::RUNTIME_COMPONENT_ARTIFACT_SCHEMA_VERSION.to_string(),
6827 )
6828 .replace(
6829 "__EZ_EFFECT_SCHEMA_VERSION__",
6830 &crate::RUNTIME_EFFECT_ARTIFACT_SCHEMA_VERSION.to_string(),
6831 )
6832}
6833
6834#[cfg(test)]
6835mod tests {
6836 use super::generate_runtime_stub;
6837
6838 #[test]
6839 fn emits_runtime_manifest_bootstrap() {
6840 let runtime = generate_runtime_stub();
6841
6842 assert!(runtime.contains("presolve-template-manifest"));
6843 assert!(runtime.contains("presolve-effect-runtime"));
6844 assert!(runtime.contains("presolve-context-runtime"));
6845 assert!(runtime.contains("executeInitialContext(store)"));
6846 assert!(runtime.contains("executeContextUpdates(store, actionBatchId)"));
6847 assert!(runtime.contains("contextSlots: new Map()"));
6848 assert!(runtime.contains("RUNTIME_VERSION = \"0.0.0\""));
6849 assert!(runtime.contains("SUPPORTED_SCHEMA_VERSION = 5"));
6850 assert!(runtime.contains("SUPPORTED_COMPUTED_ARTIFACT_SCHEMA_VERSION = 12"));
6851 assert!(runtime.contains("instruction.kind === \"load-resource\""));
6852 assert!(runtime.contains("resourceInvalidationsByDeclaration"));
6853 assert!(runtime.contains("case \"abs\""));
6854 assert!(runtime.contains("instruction.kind === \"select\""));
6855 assert!(runtime.contains("instruction.kind === \"get-index\""));
6856 assert!(runtime.contains("presolve-forms-runtime"));
6857 assert!(runtime.contains("presolve-resources-runtime"));
6858 assert!(runtime.contains("presolve-opaque-runtime"));
6859 assert!(runtime.contains("validateOpaqueArtifact"));
6860 assert!(runtime.contains("executeOpaqueTerminal"));
6861 assert!(runtime.contains("PSR_OPAQUE_TERMINAL_FAILURE"));
6862 assert!(runtime.contains("OpaqueTerminalColdFallback"));
6863 assert!(runtime.contains("validateResourcesArtifact"));
6864 assert!(runtime.contains("initializeResourcesRuntime"));
6865 assert!(runtime.contains("AbortController"));
6866 assert!(runtime.contains("pagehide"));
6867 assert!(runtime.contains("initializeFormsRuntime"));
6868 assert!(runtime.contains("dispatchFormSubmit"));
6869 assert!(runtime.contains("form_hosts"));
6870 assert!(runtime.contains("structuralOccurrences = new Map"));
6871 assert!(runtime.contains("structuralOccurrencesByInvocation"));
6872 assert!(runtime.contains("function structuralOccurrenceIdentity"));
6873 assert!(runtime.contains("function decodeStructuralOccurrenceIdentity"));
6874 assert!(runtime.contains("function instantiateStructuralTemplateSlots"));
6875 assert!(runtime.contains("function rewriteStructuralTemplateIdentity"));
6876 assert!(runtime.contains("function deriveStructuralOccurrenceRecords"));
6877 assert!(runtime.contains("function stageStructuralOccurrenceRecords"));
6878 assert!(runtime.contains("function renderStructuralOccurrenceTemplate"));
6879 assert!(runtime.contains("function attachStructuralOccurrenceFragment"));
6880 assert!(runtime.contains("function registerStructuralOccurrenceRecords"));
6881 assert!(runtime.contains("function materializeStructuralOccurrence"));
6882 assert!(runtime.contains("function structuralConditionalHostFragment"));
6883 assert!(runtime.contains("function structuralKeyedHostFragment"));
6884 assert!(runtime.contains("function renderStructuralKeyedListItem"));
6885 assert!(runtime.contains("function reconcileStructuralKeyedList"));
6886 assert!(runtime.contains("function compilerFragmentInvocationAnchors"));
6887 assert!(runtime.contains("function replaceStructuralConditionalBranch"));
6888 assert!(runtime.contains("active.indexOf(updateBinding)"));
6889 assert!(runtime.contains("function structuralOccurrenceTemplateRegistry"));
6890 assert!(runtime.contains("structuralOccurrenceTemplatesByInvocation"));
6891 assert!(runtime.contains("structuralStateSlots = new Set()"));
6892 assert!(runtime.contains("structuralComputedCacheSlots = new Set()"));
6893 assert!(runtime.contains("Conditional host fragments were attached to a keyed-list host"));
6894 assert!(runtime.contains("occurrence.ordinary_template_targets"));
6895 assert!(runtime.contains("occurrence.ordinary_template_bindings"));
6896 assert!(runtime.contains("occurrence.ordinary_template_events"));
6897 assert!(!runtime.contains("FormData(formElement)"));
6898 assert!(runtime.contains("PSR_MISSING_MANIFEST"));
6899 assert!(runtime.contains("PSR_INVALID_MANIFEST_JSON"));
6900 assert!(runtime.contains("PSR_UNSUPPORTED_SCHEMA"));
6901 assert!(runtime.contains("data-presolve-node"));
6902 assert!(runtime.contains("ordinaryEventsByTargetAndType"));
6903 assert!(runtime.contains("ordinaryEventListenerTypes: new Set()"));
6904 assert!(runtime.contains("component_instance_id: record.component_instance_id"));
6905 assert!(runtime.contains("computedSlotsByInstanceComputed: new Map()"));
6906 assert!(runtime.contains("computedDirtySlots: new Map()"));
6907 assert!(runtime.contains("function computedSlotForExecution"));
6908 assert!(runtime.contains(
6909 "if (component !== null && evaluation.component !== component.name) continue;"
6910 ));
6911 assert!(runtime.contains("/computed-cache:"));
6912 assert!(runtime.contains("/computed-dirty:"));
6913 assert!(runtime.contains("LEGACY_COMPONENT_ARTIFACT_SCHEMA_VERSION = 2"));
6914 assert!(runtime.contains("RESUME_REGISTRY_CONTRACT_VERSION = 1"));
6915 assert!(runtime.contains("function validateResumeManifest"));
6916 assert!(runtime.contains("function validateResumeSnapshot"));
6917 assert!(runtime.contains("async function bootstrapResume"));
6918 assert!(runtime.contains("function captureSnapshot"));
6919 assert!(runtime.contains("async function activateByEvent"));
6920 assert!(runtime.contains("async function activateBoundary"));
6921 assert!(runtime.contains("function decodeResumeValue"));
6922 assert!(runtime.contains("async function restoreResumeRuntimeThroughForms"));
6923 assert!(runtime.contains("function allocateResumeResources"));
6924 assert!(runtime.contains("function finalizeRestoredResources"));
6925 assert!(runtime.contains("ResourceResumeUnsupported"));
6926 assert!(runtime.contains("executeResumeComputedRecomputation"));
6927 assert!(runtime.contains("function executeResumeContextBindings"));
6928 assert!(runtime.contains("function restoreResumeComponentsSlotsAndStructure"));
6929 assert!(runtime.contains("function restoreResumeForms"));
6930 assert!(runtime.contains("function installResumeDomBindings"));
6931 assert!(runtime.contains("function establishResumeEffects"));
6932 assert!(runtime.contains("function collectExactResumeAnchors"));
6933 assert!(runtime.contains("window.__PRESOLVE_RESUME__ = Object.freeze"));
6934 assert!(runtime.contains("throw new ResumeBootError(\"DoubleBootstrap\")"));
6935 assert!(runtime.contains("presolve-binding:"));
6936 assert!(runtime.contains("reportDiagnostic"));
6937 assert!(runtime.contains("validateManifestSchema"));
6938 assert!(runtime.contains("validateEffectArtifactSchema"));
6939 assert!(runtime.contains("createRuntimeStore"));
6940 assert!(runtime.contains("readField"));
6941 assert!(runtime.contains("writeField"));
6942 assert!(runtime.contains("notifyField"));
6943 assert!(runtime.contains("actionDelta"));
6944 assert!(runtime.contains("isBooleanAttribute"));
6945 assert!(runtime.contains("isPropertyAttribute"));
6946 assert!(runtime.contains("updateAttributeBinding"));
6947 assert!(runtime.contains("function legacyActionBinding"));
6948 assert!(runtime.contains("function legacyEventBinding"));
6949 assert!(runtime.contains("function registerLegacyComponentEvents"));
6950 assert!(runtime.contains(
6951 "Legacy template action binding did not match its compiler action implementation"
6952 ));
6953 assert!(runtime.contains("actionsByMethod.set(action.method_id, action.action_batch_id)"));
6954 assert!(runtime.contains("const actionRecord = store.actionsByMethod.get(event.method_id)"));
6955 assert!(runtime.contains("actionRecord.action_batch_id !== event.action_batch_id"));
6956 assert!(runtime.contains("executeActions"));
6957 assert!(runtime.contains("function executePackageInvocation"));
6958 assert!(runtime.contains("presolvePackageInvocations"));
6959 assert!(runtime.contains("PSR_PACKAGE_INVOCATION_MODULE_MISMATCH"));
6960 assert!(runtime.contains("PSR_PACKAGE_INVOCATION_FAILURE"));
6961 assert!(runtime.contains("executeCompletedActionEffects"));
6962 assert!(runtime.contains("activeActionBatch"));
6963 assert!(runtime.contains("executeInitialEffects"));
6964 assert!(runtime.contains("function executeResumeEffects"));
6965 assert!(runtime.contains("function validateEffectArtifactInstances"));
6966 assert!(runtime.contains("effectArtifact.structural_templates"));
6967 assert!(runtime.contains("function disposeEffectInstances"));
6968 assert!(runtime.contains("effect.run_on_resume !== true"));
6969 assert!(runtime.contains("dispatchEffectCapability"));
6970 assert!(!runtime.contains("const arguments ="));
6971 assert!(runtime.contains("formatBindingValue"));
6972 assert!(runtime.contains("value === null ? \"\" : String(value)"));
6973 assert!(runtime.contains("listItemMemberPath"));
6974 assert!(runtime.contains("populateListItemMemberBindings"));
6975 assert!(runtime.contains("updateListItemTextBindings"));
6976 assert!(runtime.contains("updateListItemAttributes"));
6977 assert!(runtime.contains("registerListItemEvents"));
6978 assert!(runtime.contains("unregisterListItemEvents"));
6979 assert!(runtime.contains("presolve-list-binding-end:"));
6980 assert!(runtime.contains("renderListItemElement"));
6981 assert!(runtime.contains("component.state[field] = node.initial_value"));
6982 assert!(!runtime.contains("component.state[field] = Number(node.initial_value)"));
6983 assert!(runtime.contains("installDelegatedEventListeners"));
6984 assert!(runtime.contains("document.addEventListener(eventType"));
6985 assert!(!runtime.contains("element.addEventListener(\"click\""));
6986 assert!(runtime.contains("action.operation !== \"toggle\""));
6987 assert!(runtime.contains("action.operation === \"assign\""));
6988 assert!(runtime.contains("action.operation === \"toggle\""));
6989 assert!(runtime.contains("PSR_MISSING_ELEMENT_ANCHOR"));
6990 assert!(runtime.contains("PSR_MISSING_BINDING_ANCHOR"));
6991 assert!(runtime.contains("PSR_UNRESOLVED_EVENT"));
6992 assert!(runtime.contains("PSR_UNRESOLVED_ACTION"));
6993 assert!(runtime.contains("PSR_INVALID_STATE_OPERATION"));
6994 assert!(runtime.contains("current + delta"));
6995 assert!(runtime.contains("dataset.presolveRuntime"));
6996 assert!(runtime.contains("presolve:ready"));
6997 assert!(runtime.contains("runtime_version"));
6998 assert!(runtime.contains("diagnostics"));
6999 assert!(runtime.contains("window.__PRESOLVE__"));
7000 }
7001}