@markless/router 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { c as routeMountTarget, d as PREFETCH_ATTRIBUTE, f as REPLACE_ATTRIBUTE, i as HTML_ATTRIBUTES_SLOT, p as SCROLL_ATTRIBUTE, t as rememberRequestLocals, u as LINK_ATTRIBUTE } from "./request-locals-BPfJaoM_.js";
1
+ import { f as LINK_ATTRIBUTE, h as SCROLL_ATTRIBUTE, m as REPLACE_ATTRIBUTE, o as HTML_ATTRIBUTES_SLOT, p as PREFETCH_ATTRIBUTE, r as rememberRequestLocals, t as MARKLESS_NAV_PENDING_MIN_MS, u as routeMountTarget } from "./navigation-timing-CzH6VaBR.js";
2
2
  import { a as normalizeRequestPathname, c as parseRequestFile, i as matchRouteManifest, l as transformRequestFileSource, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId, s as normalizeRequestFileId } from "./route-manifest-DmoxXanW.js";
3
3
  import { createExternalDelegateStructureTokens, createExternalDelegateView } from "@markless/web/fns/external-delegate";
4
4
  import { render } from "@markless/web/render";
5
- import { MARKLESS_PENDING_MIN_VISIBLE_MS as MARKLESS_NAV_PENDING_MIN_MS, settleOrPendingDeadline } from "@markless/web/fns/pending-timing";
5
+ import { settleOrPendingDeadline } from "@markless/web/fns/pending-timing";
6
6
  //#region src/route-state.ts
7
7
  const MARKLESS_ROUTER_ROUTE_EVENT = "marklessrouternavigate";
8
8
  const MARKLESS_ROUTER_RENDERED_EVENT = "marklessrouterrendered";
@@ -1,4 +1,5 @@
1
1
  import { CONTAINER_ATTRIBUTE, PROTOCOL_CONTAINER_END_COMMENT, PROTOCOL_CONTAINER_START_COMMENT, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE } from "@markless/web/fns/container-region";
2
+ import { MARKLESS_PENDING_MIN_VISIBLE_MS as MARKLESS_NAV_PENDING_MIN_MS, MARKLESS_PENDING_SETTLE_DEADLINE_MS as MARKLESS_NAV_SETTLE_DEADLINE_MS } from "@markless/web/fns/pending-timing";
2
3
  //#region src/link-attributes.ts
3
4
  const LINK_ATTRIBUTE = "data-markless-router-link";
4
5
  const REPLACE_ATTRIBUTE = "data-markless-router-replace";
@@ -92,4 +93,4 @@ function takeMiddlewareHeaders(request) {
92
93
  return record.taken;
93
94
  }
94
95
  //#endregion
95
- export { ROUTE_SCRIPT_TYPE as a, routeMountTarget as c, PREFETCH_ATTRIBUTE as d, REPLACE_ATTRIBUTE as f, HTML_ATTRIBUTES_SLOT as i, servedHtmlAttributesScript as l, requestLocals as n, SERVED_BODY_ATTRIBUTES_PROPERTY as o, SCROLL_ATTRIBUTE as p, takeMiddlewareHeaders as r, SERVED_HTML_ATTRIBUTES_PROPERTY as s, rememberRequestLocals as t, LINK_ATTRIBUTE as u };
96
+ export { takeMiddlewareHeaders as a, SERVED_BODY_ATTRIBUTES_PROPERTY as c, servedHtmlAttributesScript as d, LINK_ATTRIBUTE as f, SCROLL_ATTRIBUTE as h, requestLocals as i, SERVED_HTML_ATTRIBUTES_PROPERTY as l, REPLACE_ATTRIBUTE as m, MARKLESS_NAV_SETTLE_DEADLINE_MS as n, HTML_ATTRIBUTES_SLOT as o, PREFETCH_ATTRIBUTE as p, rememberRequestLocals as r, ROUTE_SCRIPT_TYPE as s, MARKLESS_NAV_PENDING_MIN_MS as t, routeMountTarget as u };
@@ -10,6 +10,7 @@ export interface ServerEntryOptions {
10
10
  readonly prerenderWakeEntryPath?: string;
11
11
  readonly routeModulePreloads?: Record<string, readonly ModulePreloadInput[]>;
12
12
  readonly routeSsrModulePreloads?: Record<string, readonly ModulePreloadInput[]>;
13
+ readonly routeResumeModules?: Readonly<Record<string, readonly string[]>>;
13
14
  readonly routeStylesheets?: Record<string, readonly string[]>;
14
15
  readonly documentStylesheets?: readonly string[];
15
16
  readonly importMap?: string;
@@ -1 +1 @@
1
- export { t as createServerEntry, n as routerLinkBridgeModules } from "../../create-server-entry-CVhSjR45.js";
1
+ export { t as createServerEntry, n as routerLinkBridgeModules } from "../../create-server-entry-BnaEfDHl.js";
@@ -5,6 +5,80 @@ declare const ASYNC_BOUNDARY_ARM: {
5
5
  readonly catch: 2;
6
6
  };
7
7
  //#endregion
8
+ //#region ../serializer/src/value.d.ts
9
+ type SerializedPrimitive = null | string | number | boolean | {
10
+ readonly $type: 'undefined';
11
+ } | {
12
+ readonly $type: 'bigint';
13
+ readonly value: string;
14
+ } | {
15
+ readonly $type: 'number';
16
+ readonly value: NonFiniteNumberName;
17
+ };
18
+ /** JSON has no form for these, so a bare number slot would print as `null`. */
19
+ type NonFiniteNumberName = 'Infinity' | '-Infinity' | 'NaN';
20
+ type SerializedSlot = SerializedPrimitive | {
21
+ readonly $ref: number;
22
+ } | {
23
+ readonly $type: 'date';
24
+ readonly value: string;
25
+ } | {
26
+ readonly $type: 'regexp';
27
+ readonly source: string;
28
+ readonly flags: string;
29
+ } | {
30
+ readonly $type: 'url';
31
+ readonly value: string;
32
+ };
33
+ type SerializedRecord = {
34
+ readonly id: number;
35
+ readonly type: 'object';
36
+ readonly fields: ReadonlyArray<readonly [string, SerializedSlot]>;
37
+ } | {
38
+ readonly id: number;
39
+ readonly type: 'array';
40
+ readonly items: ReadonlyArray<SerializedSlot>;
41
+ } | {
42
+ readonly id: number;
43
+ readonly type: 'map';
44
+ readonly entries: ReadonlyArray<readonly [SerializedSlot, SerializedSlot]>;
45
+ } | {
46
+ readonly id: number;
47
+ readonly type: 'set';
48
+ readonly values: ReadonlyArray<SerializedSlot>;
49
+ } | {
50
+ readonly id: number;
51
+ readonly type: 'date';
52
+ readonly value: string;
53
+ } | {
54
+ readonly id: number;
55
+ readonly type: 'regexp';
56
+ readonly source: string;
57
+ readonly flags: string;
58
+ } | {
59
+ readonly id: number;
60
+ readonly type: 'url';
61
+ readonly value: string;
62
+ } | {
63
+ readonly id: number;
64
+ readonly type: 'array-buffer';
65
+ readonly bytes: ReadonlyArray<number>;
66
+ } | {
67
+ readonly id: number;
68
+ readonly type: 'typed-array';
69
+ readonly arrayType: TypedArrayName;
70
+ readonly buffer: SerializedSlot;
71
+ readonly byteOffset: number;
72
+ readonly length: number;
73
+ } | {
74
+ readonly id: number;
75
+ readonly type: 'data-view';
76
+ readonly buffer: SerializedSlot;
77
+ readonly byteOffset: number;
78
+ readonly byteLength: number;
79
+ };
80
+ type TypedArrayName = 'Int8Array' | 'Uint8Array' | 'Uint8ClampedArray' | 'Int16Array' | 'Uint16Array' | 'Int32Array' | 'Uint32Array' | 'Float32Array' | 'Float64Array' | 'BigInt64Array' | 'BigUint64Array';
81
+ //#endregion
8
82
  //#region ../serializer/src/protocol-constants.d.ts
9
83
  declare const ASYNC_PROTOCOL_VERSION = 1;
10
84
  declare const STORAGE_PROTOCOL_VERSION = 2;
@@ -15,6 +89,15 @@ declare const PROTOCOL_EVENT_ACTION_KIND: {
15
89
  //#endregion
16
90
  //#region ../serializer/src/protocol.d.ts
17
91
  type ProtocolAsyncBoundaryArm = (typeof ASYNC_BOUNDARY_ARM)[keyof typeof ASYNC_BOUNDARY_ARM];
92
+ /**
93
+ * Where an element sits below the node an address starts from, one step per
94
+ * level. A step counts the parent's element children, and each @if, @switch or
95
+ * @try block as one (its start comment, content and end comment together). Text
96
+ * never counts, since adjacent text merges and an empty value renders no node,
97
+ * so the server's HTML and a client-built tree read the same. A negative step
98
+ * counts back from the end: -1 is the last.
99
+ */
100
+ type ProtocolElementAddress = ReadonlyArray<number>;
18
101
  type ProtocolSyncPolicyCondition = {
19
102
  readonly type: 'and';
20
103
  readonly conditions: ReadonlyArray<ProtocolSyncPolicyCondition>;
@@ -28,6 +111,8 @@ type ProtocolSyncPolicyCondition = {
28
111
  readonly type: 'graph-truthy';
29
112
  readonly graphNodeId: string;
30
113
  readonly path?: ReadonlyArray<string>;
114
+ /** When present, the read must equal this value rather than be truthy. */
115
+ readonly equals?: string | number | boolean | null;
31
116
  } | {
32
117
  readonly type: 'constant-truthy';
33
118
  readonly value: unknown;
@@ -133,6 +218,7 @@ type ProtocolStatePayload = {
133
218
  readonly graphNodeId: string;
134
219
  readonly key: string;
135
220
  }>;
221
+ readonly sharedRecords?: ReadonlyArray<SerializedRecord>;
136
222
  };
137
223
  type ProtocolBranchContentRead = {
138
224
  readonly graphNodeId: string;
@@ -198,6 +284,8 @@ type ProtocolArmRecordSet = {
198
284
  readonly elementHandles: ProtocolViewPayload['elementHandles'];
199
285
  readonly keyedRepeats?: ProtocolViewPayload['keyedRepeats'];
200
286
  readonly branches?: ReadonlyArray<ProtocolArmBranchRecord>;
287
+ /** Served beside `events` sent as templates: the names the stream boot listens for. */
288
+ readonly eventNames?: ReadonlyArray<string>;
201
289
  };
202
290
  /**
203
291
  * Where one row-template slot's value comes from: the repeated item, a graph
@@ -225,6 +313,23 @@ type ProtocolRowTemplateSlotValue = {
225
313
  readonly path: ReadonlyArray<string>;
226
314
  }>;
227
315
  };
316
+ /** One arm of a row's branch: its markup and slots, FRAGMENT-relative to the arm's first node. */
317
+ type ProtocolRowTemplateArm = {
318
+ readonly html: string;
319
+ readonly textSlots?: ReadonlyArray<{
320
+ readonly path: ReadonlyArray<number>;
321
+ } & ProtocolRowTemplateSlotValue>;
322
+ readonly attributeSlots?: ReadonlyArray<{
323
+ readonly path: ReadonlyArray<number>;
324
+ readonly name: string;
325
+ } & ProtocolRowTemplateSlotValue>;
326
+ };
327
+ type ProtocolRowTemplateBranchSlot = {
328
+ readonly path: ReadonlyArray<number>;
329
+ readonly branchId: string;
330
+ readonly armTests?: ReadonlyArray<unknown>;
331
+ readonly arms: ReadonlyArray<ProtocolRowTemplateArm>;
332
+ } & ProtocolRowTemplateSlotValue;
228
333
  type ProtocolViewPayload = {
229
334
  readonly version: typeof ASYNC_PROTOCOL_VERSION;
230
335
  readonly asyncRunners?: Readonly<Record<string, string>>;
@@ -341,7 +446,7 @@ type ProtocolViewPayload = {
341
446
  */
342
447
  readonly enclosingRow?: {
343
448
  readonly repeatId: string;
344
- readonly parentHostPath: ReadonlyArray<number>;
449
+ readonly parentHostPath: ProtocolElementAddress;
345
450
  readonly itemPath?: ReadonlyArray<string>;
346
451
  };
347
452
  readonly collectionGraphNodeId?: string;
@@ -364,6 +469,11 @@ type ProtocolViewPayload = {
364
469
  readonly arm: number;
365
470
  };
366
471
  readonly itemName: string;
472
+ /**
473
+ * The `index` name of the `@for`, which a row handler reading it is handed
474
+ * beside the item. Pay-per-use: present only when a row handler reads it.
475
+ */
476
+ readonly indexName?: string;
367
477
  readonly rowElementCount: number;
368
478
  /**
369
479
  * Element children of the parent that stand before the rows. Rows occupy
@@ -442,6 +552,18 @@ type ProtocolViewPayload = {
442
552
  readonly path: ReadonlyArray<number>;
443
553
  readonly name: string;
444
554
  } & ProtocolRowTemplateSlotValue>;
555
+ /**
556
+ * An `@if`/`@switch` written in the row, flipped per row. The slot value is
557
+ * the test (the discriminant for a `@switch`, matched against `armTests`),
558
+ * and `path` names the marker in `html` the shown arm's anchors and nodes
559
+ * replace. A branch that IS the row (`@for { @if { <tr> } }`) has the marker
560
+ * as the whole html: its arm is the row root, so a flip rebuilds the row.
561
+ * `branchId` is the branch site as the anchor comments spell it, before
562
+ * composition's prefix, like `branchArm.branchId`.
563
+ *
564
+ * Pay-per-use: a row with no such branch omits the field.
565
+ */
566
+ readonly branchSlots?: ReadonlyArray<ProtocolRowTemplateBranchSlot>;
445
567
  };
446
568
  /**
447
569
  * The parent graph node each prop a `rowTemplate` source slot reads follows,
@@ -494,16 +616,25 @@ type ProtocolViewPayload = {
494
616
  readonly rowChunkId?: string;
495
617
  };
496
618
  readonly rowElementHandles?: ReadonlyArray<{
497
- readonly hostPath: ReadonlyArray<number>;
619
+ readonly hostPath: ProtocolElementAddress;
498
620
  readonly handleId: string;
499
621
  readonly name: string;
500
622
  readonly plural?: boolean;
501
623
  }>;
502
624
  readonly rowEvents: ReadonlyArray<{
503
- readonly hostPath: ReadonlyArray<number>;
625
+ readonly hostPath: ProtocolElementAddress;
504
626
  readonly eventName: string;
505
627
  readonly symbolIds: ReadonlyArray<string>;
506
628
  readonly syncPolicy?: ProtocolSyncPolicy;
629
+ /**
630
+ * The event's host sits in arm `arm` of `rowTemplate.branchSlots[slot]`, so it
631
+ * exists only while that arm shows, and `hostPath` is ARM-relative: element
632
+ * index among the arm's nodes, then child-node indexes from there.
633
+ */
634
+ readonly arm?: {
635
+ readonly slot: number;
636
+ readonly arm: number;
637
+ };
507
638
  }>;
508
639
  }>;
509
640
  readonly branches?: ReadonlyArray<{
@@ -520,7 +651,7 @@ type ProtocolViewPayload = {
520
651
  readonly armTests?: ReadonlyArray<unknown>;
521
652
  readonly armRecords?: ReadonlyArray<{
522
653
  readonly events: ReadonlyArray<{
523
- readonly hostPath: ReadonlyArray<number>;
654
+ readonly hostPath: ProtocolElementAddress;
524
655
  readonly eventName: string;
525
656
  readonly symbolIds: ReadonlyArray<string>;
526
657
  readonly syncPolicy?: ProtocolSyncPolicy;
@@ -603,6 +734,9 @@ type ProtocolViewPayload = {
603
734
  readonly path: ReadonlyArray<string>;
604
735
  readonly runnerSymbolId?: string;
605
736
  }>;
737
+ /** As on a branch: the part instance that authored this boundary and where its live props now live, for the arm its own module re-renders on settle. */
738
+ readonly composedInstancePath?: string;
739
+ readonly composedGraphProps?: ReadonlyArray<ProtocolComposedGraphProp>;
606
740
  }>;
607
741
  };
608
742
  //#endregion
@@ -689,7 +823,27 @@ type RuntimeDemandMapClosurePlan = {
689
823
  }>;
690
824
  };
691
825
  //#endregion
826
+ //#region ../runtime/src/graph-reconcile.d.ts
827
+ /**
828
+ * One array inside a derived value that reconciles by key instead of by
829
+ * element identity. `path` names the array (`[]` is the derived value itself)
830
+ * and `keyPath` is read on each element to get its identity.
831
+ */
832
+ type RuntimeGraphReconcileKey = {
833
+ readonly path: ReadonlyArray<string>;
834
+ readonly keyPath: ReadonlyArray<string>;
835
+ };
836
+ /** Reconcile options carried by a computed or async computed graph node. */
837
+ type RuntimeGraphReconcileOptions = {
838
+ readonly keyed?: ReadonlyArray<RuntimeGraphReconcileKey>;
839
+ };
840
+ //#endregion
692
841
  //#region ../runtime/src/graph.d.ts
842
+ type RuntimeGraphRead = (graphNodeId: string, path?: ReadonlyArray<string>) => unknown;
843
+ type RuntimeGraphComputedDependency = {
844
+ readonly graphNodeId: string;
845
+ readonly path?: ReadonlyArray<string>;
846
+ };
693
847
  type RuntimeGraphAsyncSnapshot = {
694
848
  readonly status: 'idle';
695
849
  readonly version: 0;
@@ -709,6 +863,19 @@ type RuntimeGraphAsyncSnapshot = {
709
863
  readonly key: unknown;
710
864
  readonly error: unknown;
711
865
  };
866
+ type RuntimeGraphAsyncComputed = {
867
+ readonly graphNodeId: string;
868
+ readonly dependencies: ReadonlyArray<RuntimeGraphComputedDependency>;
869
+ readonly initialSnapshot?: RuntimeGraphAsyncSnapshot;
870
+ readonly key: (read: RuntimeGraphRead) => unknown;
871
+ /** How a fulfilled value reconciles against the previously published one. */
872
+ readonly reconcile?: RuntimeGraphReconcileOptions;
873
+ readonly run: (input: {
874
+ readonly key: unknown;
875
+ readonly signal: AbortSignal;
876
+ readonly read: RuntimeGraphRead;
877
+ }) => unknown | Promise<unknown>;
878
+ };
712
879
  type DomJournalEntry = {
713
880
  readonly type: 'setText';
714
881
  readonly locator: string;
@@ -778,6 +945,8 @@ type RuntimeGraphSubscription = {
778
945
  readonly graphNodeId: string;
779
946
  readonly path?: ReadonlyArray<string>;
780
947
  readonly run: (value: unknown) => DomJournalResult | RuntimeGraphCommit | void | Promise<DomJournalResult | RuntimeGraphCommit | void>;
948
+ /** False while `run` still has code to load; a write observer then leaves its DOM to the pass, so the task's writes land together. */
949
+ readonly ready?: () => boolean;
781
950
  };
782
951
  /**
783
952
  * Told about a write the moment it lands, before the flush that write schedules.
@@ -820,11 +989,14 @@ type RuntimeGraph = {
820
989
  readonly listSharedDefinitions: () => NonNullable<ProtocolStatePayload['sharedDefinitions']>;
821
990
  readonly takeSharedPatches: () => RuntimeGraphSharedPatch[];
822
991
  readonly applySharedPatch: (patch: RuntimeGraphSharedPatch) => boolean;
823
- readonly write: (write: RuntimeGraphWrite) => void;
992
+ /** Answers the value written, as the assignment it lowers from does. */
993
+ readonly write: (write: RuntimeGraphWrite) => unknown;
824
994
  readonly update: (update: RuntimeGraphUpdate) => unknown;
825
995
  readonly call: (call: RuntimeGraphCall) => unknown;
826
996
  readonly delete: (deletion: RuntimeGraphDelete) => boolean;
827
997
  readonly subscribe: (subscription: RuntimeGraphSubscription) => () => void;
998
+ /** Adds an async computed a component rendered after the graph was built; false when the node already exists. */
999
+ readonly defineAsyncComputed?: (asyncComputed: RuntimeGraphAsyncComputed) => boolean;
828
1000
  /**
829
1001
  * Optional so a facade over a subset of this contract stays a `RuntimeGraph`;
830
1002
  * a caller without it gets the flush-time answer it always had.
@@ -879,6 +1051,7 @@ type ResumeDomElement = ResumeDomNode & {
879
1051
  __marklessReleaseDispatch?: () => void;
880
1052
  __marklessEventOnlyGraph?: Map<string, unknown>;
881
1053
  __marklessCensus?: ResumeDomElement[];
1054
+ __marklessComments?: ResumeDomComment[];
882
1055
  __marklessBranchArms?: Map<string, ResumeBranchArmEntry>;
883
1056
  readonly ownerDocument?: ResumeDomOwnerDocument;
884
1057
  };
@@ -917,7 +1090,7 @@ type ResumeDomEvent = {
917
1090
  readonly preventDefault?: () => void;
918
1091
  readonly stopPropagation?: () => void;
919
1092
  readonly composedPath?: () => ReadonlyArray<ResumeDomElement>;
920
- __marklessPressHost?: ResumeDomElement;
1093
+ __marklessPressPath?: ReadonlyArray<ResumeDomElement>;
921
1094
  };
922
1095
  type ResumeSharedPatchEvent = {
923
1096
  readonly type: 'async:shared-patch';
@@ -937,6 +1110,8 @@ type ResumeAsyncBoundaryRecord = {
937
1110
  readonly endAnchor: ResumeDomComment;
938
1111
  readonly asyncReads: ProtocolViewPayload['asyncBoundaries'][number]['asyncReads'];
939
1112
  readonly armRecords?: ResumeArmRecordSet | ReadonlyArray<unknown>;
1113
+ readonly composedInstancePath?: string;
1114
+ readonly composedGraphProps?: ProtocolViewPayload['asyncBoundaries'][number]['composedGraphProps'];
940
1115
  };
941
1116
  type ResumeBranchArmRecordSet = NonNullable<NonNullable<ProtocolViewPayload['branches']>[number]['armRecords']>[number];
942
1117
  type ResumeBranchRecord = {
@@ -1007,6 +1182,13 @@ type ResumeArmRecordSet = {
1007
1182
  readonly elementHandles: ProtocolViewPayload['elementHandles'];
1008
1183
  readonly keyedRepeats?: NonNullable<ProtocolViewPayload['keyedRepeats']>;
1009
1184
  readonly branches?: ReadonlyArray<ResumeArmBranchRecord>;
1185
+ /** @try blocks the arm renders inside itself, anchor indexes counted from the arm start. */
1186
+ readonly asyncBoundaries?: ReadonlyArray<Omit<ResumeAsyncBoundaryPayload, 'armRecords'> & {
1187
+ readonly armRecords?: ResumeArmRecordSet;
1188
+ }>;
1189
+ };
1190
+ type ResumeAsyncBoundaryPayload = ProtocolViewPayload['asyncBoundaries'][number] & {
1191
+ readonly armRecords?: ResumeArmRecordSet | ReadonlyArray<unknown>;
1010
1192
  };
1011
1193
  type ResumeSymbolContext = {
1012
1194
  readonly graph?: RuntimeGraph;
@@ -17,34 +17,114 @@ const PROTOCOL_RECORD_KEYS = {
17
17
  //#endregion
18
18
  //#region ../serializer/src/protocol-templated-lists.ts
19
19
  /**
20
- * The record lists a payload script may serve as record templates instead of a plain array. The
21
- * inline resumer reads the others at page load, before any decoder has loaded, so they stay plain.
20
+ * The record lists a payload script may serve as record templates instead of a plain array. A
21
+ * reader that parses a payload script without decoding it may read only the other lists.
22
22
  */
23
23
  const PROTOCOL_TEMPLATED_LISTS = {
24
24
  "markless/state": [
25
+ "cells",
25
26
  "computed",
26
27
  "sharedSeeds",
27
- "sharedDefinitions"
28
+ "sharedDefinitions",
29
+ "sharedRecords"
28
30
  ],
29
31
  "markless/view": [
32
+ "locators",
33
+ "events",
30
34
  "domUpdates",
31
35
  "behaviors",
32
- "elementHandles"
36
+ "elementHandles",
37
+ "keyedRepeats"
33
38
  ]
34
39
  };
35
40
  //#endregion
41
+ //#region ../serializer/src/protocol-shared-records-decode.ts
42
+ const ref = (slot, copy) => typeof slot === "object" && slot !== null && "$ref" in slot ? { $ref: copy(slot.$ref) } : slot;
43
+ function renamed(record, copy) {
44
+ const map = (slot) => ref(slot, copy);
45
+ if (record.type === "object") return {
46
+ ...record,
47
+ fields: record.fields.map(([key, slot]) => [key, map(slot)])
48
+ };
49
+ if (record.type === "array") return {
50
+ ...record,
51
+ items: record.items.map(map)
52
+ };
53
+ if (record.type === "map") return {
54
+ ...record,
55
+ entries: record.entries.map(([key, value]) => [map(key), map(value)])
56
+ };
57
+ if (record.type === "set") return {
58
+ ...record,
59
+ values: record.values.map(map)
60
+ };
61
+ if (record.type === "typed-array" || record.type === "data-view") return {
62
+ ...record,
63
+ buffer: map(record.buffer)
64
+ };
65
+ return record;
66
+ }
67
+ /**
68
+ * Gives every envelope of a freshly parsed state payload, in place, a copy of each shared subtree
69
+ * it references, under ids of its own: two references to one shared record are two objects.
70
+ */
71
+ function expandSharedRecords(state) {
72
+ const payload = state;
73
+ const shared = payload?.sharedRecords;
74
+ if (!shared) return state;
75
+ const byId = new Map(shared.map((record) => [record.id, record]));
76
+ const expand = (envelope) => {
77
+ const records = envelope?.records;
78
+ if (!Array.isArray(records)) return;
79
+ let next = 0;
80
+ for (const record of records) next = Math.max(next, record.id + 1);
81
+ const copies = [];
82
+ const copy = (id) => {
83
+ const record = byId.get(id);
84
+ if (!record) return id;
85
+ const at = next++;
86
+ const slot = copies.push(record) - 1;
87
+ copies[slot] = {
88
+ ...renamed(record, copy),
89
+ id: at
90
+ };
91
+ return at;
92
+ };
93
+ const own = records.map((record) => renamed(record, copy));
94
+ if (copies.length) envelope.records = [...own, ...copies];
95
+ };
96
+ for (const cell of payload.cells ?? []) expand(cell?.value);
97
+ for (const computed of payload.computed ?? []) {
98
+ expand(computed?.value);
99
+ const snapshot = computed?.snapshot;
100
+ expand(snapshot?.key);
101
+ expand(snapshot?.value);
102
+ expand(snapshot?.error);
103
+ }
104
+ delete payload.sharedRecords;
105
+ return state;
106
+ }
107
+ //#endregion
36
108
  //#region ../serializer/src/protocol-record-templates.ts
37
- function expandRecordTemplates(list, keys = "") {
109
+ function expandRecordTemplates(list, keys = "", instancePaths = []) {
38
110
  if (Array.isArray(list)) return list;
39
111
  const { t, r } = list;
40
112
  const names = keys.split(" ");
41
- const parts = t.map((text) => text.replace(/~(\d+):/g, (_, at) => `"${names[+at]}":`).split(/\^(\d+)/));
113
+ const paths = [];
114
+ const path = (at) => {
115
+ const entry = instancePaths[at];
116
+ return paths[at] ??= typeof entry === "string" ? entry : path(entry[0]) + entry[1];
117
+ };
118
+ const parts = t.map((text) => text.replace(/~(\d+):/g, (_, at) => `"${names[+at]}":`).split(/([\^`])(\d+)/));
42
119
  return r.map((ref) => {
43
120
  if (typeof ref === "number") return JSON.parse(parts[ref][0]);
44
121
  if (!Array.isArray(ref)) return ref;
45
122
  const part = parts[ref[0]];
46
123
  let text = part[0];
47
- for (let at = 1; at < part.length; at += 2) text += ref[+part[at] + 1] + part[at + 1];
124
+ for (let at = 1; at < part.length; at += 3) {
125
+ const value = ref[+part[at + 1] + 1];
126
+ text += (part[at] === "`" ? path(value) : value) + part[at + 2];
127
+ }
48
128
  return JSON.parse(text);
49
129
  });
50
130
  }
@@ -52,11 +132,20 @@ function expandRecordTemplates(list, keys = "") {
52
132
  function decodeProtocolPayloadLists(type, payload) {
53
133
  const record = payload;
54
134
  const keys = PROTOCOL_RECORD_KEYS[type];
55
- if (record) for (const key of PROTOCOL_TEMPLATED_LISTS[type]) {
56
- const list = record[key];
57
- if (list && !Array.isArray(list)) record[key] = expandRecordTemplates(list, keys[key]);
135
+ if (record) {
136
+ const paths = record.instancePaths;
137
+ const inRows = record.inRows;
138
+ for (const key of PROTOCOL_TEMPLATED_LISTS[type]) {
139
+ const list = record[key];
140
+ if (list && !Array.isArray(list)) record[key] = expandRecordTemplates(list, keys[key], paths);
141
+ const rows = inRows?.[key] && expandRecordTemplates(inRows[key], keys[key], paths);
142
+ let at = 0;
143
+ if (rows) record[key] = list.map((item) => item ?? rows[at++]);
144
+ }
145
+ delete record.instancePaths;
146
+ delete record.inRows;
58
147
  }
59
- return payload;
148
+ return expandSharedRecords(payload);
60
149
  }
61
150
  //#endregion
62
151
  //#region ../serializer/src/storage-cookie.ts
@@ -742,7 +831,7 @@ async function runScalar(root, event, prepared, symbol) {
742
831
  },
743
832
  write(write) {
744
833
  check(write.graphNodeId, write.path);
745
- value = write.value;
834
+ return value = write.value;
746
835
  },
747
836
  update(update) {
748
837
  check(update.graphNodeId, update.path);
@@ -1330,6 +1419,9 @@ function islandScopedFamilyRecord(record, context) {
1330
1419
  index: context.commentOffset + Number(anchor.index)
1331
1420
  };
1332
1421
  }
1422
+ if (isFamilyRecord(record.rowTemplate)) mapped.rowTemplate = islandScopedRowTemplate(record.rowTemplate, island);
1423
+ if ((record.rowTemplate || record.rowComponent) && record.instancePath === void 0 && island.segment) mapped.instancePath = island.segment;
1424
+ if (Array.isArray(record.propRoutes)) mapped.propRoutes = record.propRoutes.map((route) => isFamilyRecord(route) ? islandScopedGraphRecord(route, island) : route);
1333
1425
  for (const key of MDX_NESTED_RECORD_KEYS) {
1334
1426
  const nested = record[key];
1335
1427
  if (Array.isArray(nested)) mapped[key] = nested.map((entry) => isFamilyRecord(entry) ? islandScopedFamilyRecord(entry, context) : entry);
@@ -1337,6 +1429,26 @@ function islandScopedFamilyRecord(record, context) {
1337
1429
  }
1338
1430
  return mapped;
1339
1431
  }
1432
+ function islandScopedRowTemplate(template, island) {
1433
+ const slot = (value) => {
1434
+ if (!isFamilyRecord(value)) return value;
1435
+ const scoped = { ...islandScopedGraphRecord(value, island) };
1436
+ if (Array.isArray(value.reads)) scoped.reads = value.reads.map((read) => isFamilyRecord(read) ? islandScopedGraphRecord(read, island) : read);
1437
+ if (Array.isArray(value.arms)) scoped.arms = value.arms.map(slots);
1438
+ return scoped;
1439
+ };
1440
+ const slots = (owner) => {
1441
+ if (!isFamilyRecord(owner)) return owner;
1442
+ const scoped = { ...owner };
1443
+ for (const key of [
1444
+ "textSlots",
1445
+ "attributeSlots",
1446
+ "branchSlots"
1447
+ ]) if (Array.isArray(owner[key])) scoped[key] = owner[key].map(slot);
1448
+ return scoped;
1449
+ };
1450
+ return slots(template);
1451
+ }
1340
1452
  function isFamilyRecord(value) {
1341
1453
  return typeof value === "object" && value !== null && !Array.isArray(value);
1342
1454
  }