@askrjs/askr 0.0.35 → 0.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/README.md +17 -9
  2. package/dist/bench/components/benchmark-row.js.map +1 -1
  3. package/dist/bench/components/benchmark-table.js +1 -1
  4. package/dist/bench/components/benchmark-table.js.map +1 -1
  5. package/dist/benchmark.js +3 -3
  6. package/dist/benchmark.js.map +1 -1
  7. package/dist/bin/askr-ssg.js.map +1 -1
  8. package/dist/boot/index.d.ts +1 -7
  9. package/dist/boot/index.d.ts.map +1 -1
  10. package/dist/boot/index.js +31 -42
  11. package/dist/boot/index.js.map +1 -1
  12. package/dist/common/control.js.map +1 -1
  13. package/dist/common/env.js.map +1 -1
  14. package/dist/common/ssr-errors.js.map +1 -1
  15. package/dist/common/vnode.js.map +1 -1
  16. package/dist/components/error-boundary.js.map +1 -1
  17. package/dist/components/index.d.ts +2 -0
  18. package/dist/components/index.js +2 -0
  19. package/dist/components/link.d.ts +4 -5
  20. package/dist/components/link.d.ts.map +1 -1
  21. package/dist/components/link.js +2 -1
  22. package/dist/components/link.js.map +1 -1
  23. package/dist/control/case.js.map +1 -1
  24. package/dist/control/for.js.map +1 -1
  25. package/dist/control/shared.js.map +1 -1
  26. package/dist/control/show.js.map +1 -1
  27. package/dist/data/index.d.ts.map +1 -1
  28. package/dist/data/index.js +165 -23
  29. package/dist/data/index.js.map +1 -1
  30. package/dist/dev/invariant.js.map +1 -1
  31. package/dist/dev/logger.js.map +1 -1
  32. package/dist/foundations/icon/icon.d.ts.map +1 -1
  33. package/dist/foundations/icon/icon.js.map +1 -1
  34. package/dist/foundations/icon/icon.types.d.ts +2 -1
  35. package/dist/foundations/icon/icon.types.d.ts.map +1 -1
  36. package/dist/foundations/icon/index.d.ts +3 -0
  37. package/dist/foundations/icon/index.js +2 -0
  38. package/dist/foundations/index.d.ts +1 -18
  39. package/dist/foundations/index.js +2 -18
  40. package/dist/foundations/interactions/dismissable.js.map +1 -1
  41. package/dist/foundations/interactions/focusable.js.map +1 -1
  42. package/dist/foundations/interactions/hoverable.js.map +1 -1
  43. package/dist/foundations/interactions/index.d.ts +7 -0
  44. package/dist/foundations/interactions/index.js +7 -0
  45. package/dist/foundations/interactions/interaction-policy.js +2 -2
  46. package/dist/foundations/interactions/interaction-policy.js.map +1 -1
  47. package/dist/foundations/interactions/pressable.js.map +1 -1
  48. package/dist/foundations/interactions/roving-focus.js.map +1 -1
  49. package/dist/foundations/state/controllable.js.map +1 -1
  50. package/dist/foundations/state/index.d.ts +2 -0
  51. package/dist/foundations/state/index.js +2 -0
  52. package/dist/foundations/structures/collection.js.map +1 -1
  53. package/dist/foundations/structures/index.d.ts +8 -0
  54. package/dist/foundations/structures/index.js +7 -0
  55. package/dist/foundations/structures/layer.js.map +1 -1
  56. package/dist/foundations/structures/layout.js.map +1 -1
  57. package/dist/foundations/structures/portal.js.map +1 -1
  58. package/dist/foundations/structures/presence.js.map +1 -1
  59. package/dist/foundations/structures/slot.js.map +1 -1
  60. package/dist/foundations/utilities/aria.js.map +1 -1
  61. package/dist/foundations/utilities/compose-handlers.js.map +1 -1
  62. package/dist/foundations/utilities/compose-ref.js.map +1 -1
  63. package/dist/foundations/utilities/index.d.ts +7 -0
  64. package/dist/foundations/utilities/index.js +6 -0
  65. package/dist/foundations/utilities/merge-props.js.map +1 -1
  66. package/dist/foundations/utilities/use-id.js.map +1 -1
  67. package/dist/fx/fx.js.map +1 -1
  68. package/dist/fx/timing.js.map +1 -1
  69. package/dist/index.d.ts +2 -16
  70. package/dist/index.js +1 -17
  71. package/dist/index.js.map +1 -1
  72. package/dist/jsx/utils.js.map +1 -1
  73. package/dist/jsx-dev-runtime.d.ts +1 -1
  74. package/dist/jsx-dev-runtime.js.map +1 -1
  75. package/dist/jsx-runtime.d.ts +1 -1
  76. package/dist/jsx-runtime.js.map +1 -1
  77. package/dist/renderer/children.js.map +1 -1
  78. package/dist/renderer/cleanup.js.map +1 -1
  79. package/dist/renderer/dom.js +92 -357
  80. package/dist/renderer/dom.js.map +1 -1
  81. package/dist/renderer/evaluate.js +7 -0
  82. package/dist/renderer/evaluate.js.map +1 -1
  83. package/dist/renderer/fastpath.js +20 -18
  84. package/dist/renderer/fastpath.js.map +1 -1
  85. package/dist/renderer/for-commit.js +486 -0
  86. package/dist/renderer/for-commit.js.map +1 -0
  87. package/dist/renderer/index.js.map +1 -1
  88. package/dist/renderer/keyed.js +84 -23
  89. package/dist/renderer/keyed.js.map +1 -1
  90. package/dist/renderer/reconcile.js +11 -18
  91. package/dist/renderer/reconcile.js.map +1 -1
  92. package/dist/renderer/utils.js +5 -1
  93. package/dist/renderer/utils.js.map +1 -1
  94. package/dist/resources/index.d.ts +1 -2
  95. package/dist/resources/index.js +1 -2
  96. package/dist/router/index.d.ts +2 -2
  97. package/dist/router/index.js +2 -2
  98. package/dist/router/match.js.map +1 -1
  99. package/dist/router/navigate.d.ts.map +1 -1
  100. package/dist/router/navigate.js +4 -2
  101. package/dist/router/navigate.js.map +1 -1
  102. package/dist/router/policy.js.map +1 -1
  103. package/dist/router/route-context.js.map +1 -1
  104. package/dist/router/route.d.ts +1 -1
  105. package/dist/router/route.d.ts.map +1 -1
  106. package/dist/router/route.js +2 -33
  107. package/dist/router/route.js.map +1 -1
  108. package/dist/runtime/child-scope.d.ts +1 -0
  109. package/dist/runtime/child-scope.d.ts.map +1 -1
  110. package/dist/runtime/child-scope.js +2 -0
  111. package/dist/runtime/child-scope.js.map +1 -1
  112. package/dist/runtime/component.js +1 -1
  113. package/dist/runtime/component.js.map +1 -1
  114. package/dist/runtime/context.js.map +1 -1
  115. package/dist/runtime/control.js.map +1 -1
  116. package/dist/runtime/derive.d.ts +2 -1
  117. package/dist/runtime/derive.d.ts.map +1 -1
  118. package/dist/runtime/derive.js +15 -10
  119. package/dist/runtime/derive.js.map +1 -1
  120. package/dist/runtime/dev-namespace.js.map +1 -1
  121. package/dist/runtime/effect.d.ts.map +1 -1
  122. package/dist/runtime/effect.js +34 -9
  123. package/dist/runtime/effect.js.map +1 -1
  124. package/dist/runtime/events.js.map +1 -1
  125. package/dist/runtime/execution-model.js.map +1 -1
  126. package/dist/runtime/fastlane.js.map +1 -1
  127. package/dist/runtime/for-bench.d.ts +1 -1
  128. package/dist/runtime/for-bench.d.ts.map +1 -1
  129. package/dist/runtime/for-bench.js +15 -14
  130. package/dist/runtime/for-bench.js.map +1 -1
  131. package/dist/runtime/for.d.ts +1 -0
  132. package/dist/runtime/for.d.ts.map +1 -1
  133. package/dist/runtime/for.js +90 -31
  134. package/dist/runtime/for.js.map +1 -1
  135. package/dist/runtime/operations.d.ts.map +1 -1
  136. package/dist/runtime/operations.js +10 -8
  137. package/dist/runtime/operations.js.map +1 -1
  138. package/dist/runtime/perf-metrics.js +8 -2
  139. package/dist/runtime/perf-metrics.js.map +1 -1
  140. package/dist/runtime/readable.js.map +1 -1
  141. package/dist/runtime/resource-cell.js +3 -2
  142. package/dist/runtime/resource-cell.js.map +1 -1
  143. package/dist/runtime/scheduler.d.ts +0 -1
  144. package/dist/runtime/scheduler.d.ts.map +1 -1
  145. package/dist/runtime/scheduler.js +6 -19
  146. package/dist/runtime/scheduler.js.map +1 -1
  147. package/dist/runtime/selector.d.ts.map +1 -1
  148. package/dist/runtime/selector.js +182 -103
  149. package/dist/runtime/selector.js.map +1 -1
  150. package/dist/runtime/snapshot-source.d.ts +10 -0
  151. package/dist/runtime/snapshot-source.d.ts.map +1 -0
  152. package/dist/runtime/snapshot-source.js +17 -0
  153. package/dist/runtime/snapshot-source.js.map +1 -0
  154. package/dist/runtime/ssr-bridge.js.map +1 -1
  155. package/dist/runtime/state.d.ts.map +1 -1
  156. package/dist/runtime/state.js +1 -5
  157. package/dist/runtime/state.js.map +1 -1
  158. package/dist/ssg/batch-render.js.map +1 -1
  159. package/dist/ssg/create-static-gen.js.map +1 -1
  160. package/dist/ssg/generate-metadata.js.map +1 -1
  161. package/dist/ssg/incremental-manifest.js.map +1 -1
  162. package/dist/ssg/index.d.ts +1 -6
  163. package/dist/ssg/index.js +1 -6
  164. package/dist/ssg/resolve-ssg-data.js.map +1 -1
  165. package/dist/ssg/route-utils.js.map +1 -1
  166. package/dist/ssg/write-static-files.js.map +1 -1
  167. package/dist/ssr/attrs.js.map +1 -1
  168. package/dist/ssr/context.d.ts +3 -1
  169. package/dist/ssr/context.d.ts.map +1 -1
  170. package/dist/ssr/context.js +31 -11
  171. package/dist/ssr/context.js.map +1 -1
  172. package/dist/ssr/escape.js +56 -16
  173. package/dist/ssr/escape.js.map +1 -1
  174. package/dist/ssr/index.d.ts +2 -31
  175. package/dist/ssr/index.d.ts.map +1 -1
  176. package/dist/ssr/index.js +19 -49
  177. package/dist/ssr/index.js.map +1 -1
  178. package/dist/ssr/render-keys.js +1 -12
  179. package/dist/ssr/render-keys.js.map +1 -1
  180. package/dist/ssr/sink.js.map +1 -1
  181. package/dist/ssr/verify-hydration.js +25 -0
  182. package/dist/ssr/verify-hydration.js.map +1 -0
  183. package/package.json +44 -19
  184. package/dist/_virtual/_rolldown/runtime.js +0 -7
  185. package/dist/foundations/core.d.ts +0 -15
  186. package/dist/foundations/core.js +0 -13
  187. package/dist/foundations/structures.d.ts +0 -7
  188. package/dist/foundations/structures.js +0 -6
  189. package/dist/ssg/batch-render.d.ts +0 -16
  190. package/dist/ssg/batch-render.d.ts.map +0 -1
  191. package/dist/ssg/generate-metadata.d.ts +0 -24
  192. package/dist/ssg/generate-metadata.d.ts.map +0 -1
  193. package/dist/ssg/resolve-ssg-data.d.ts +0 -23
  194. package/dist/ssg/resolve-ssg-data.d.ts.map +0 -1
  195. package/dist/ssg/route-utils.d.ts +0 -16
  196. package/dist/ssg/route-utils.d.ts.map +0 -1
  197. package/dist/ssg/write-static-files.d.ts +0 -15
  198. package/dist/ssg/write-static-files.d.ts.map +0 -1
  199. package/dist/ssr/render-keys.d.ts +0 -37
  200. package/dist/ssr/render-keys.d.ts.map +0 -1
  201. package/dist/ssr/stream-render.js +0 -76
  202. package/dist/ssr/stream-render.js.map +0 -1
@@ -1,10 +1,11 @@
1
- import { incrementPerfMetric } from "./perf-metrics.js";
1
+ import { getPerfMetricsStore, incrementPerfMetric } from "./perf-metrics.js";
2
2
  import { globalScheduler } from "./scheduler.js";
3
3
  import { clearDerivedDependencySubscriptions, markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, markReadableUsage, notifyReadableReaders, recordReadableRead, syncDerivedDependencySubscriptions, withDerivedReadTracking } from "./readable.js";
4
4
  import { claimHookIndex, getCurrentInstance } from "./component.js";
5
5
  //#region src/runtime/selector.ts
6
6
  const selectorCells = /* @__PURE__ */ new WeakMap();
7
- const dirtySelectorCells = /* @__PURE__ */ new Set();
7
+ const selectorRecords = /* @__PURE__ */ new WeakMap();
8
+ const dirtySelectorRecords = /* @__PURE__ */ new Set();
8
9
  let hasPendingSelectorFlush = false;
9
10
  function getSelectorStore(instance) {
10
11
  let store = selectorCells.get(instance);
@@ -17,24 +18,24 @@ function getSelectorStore(instance) {
17
18
  function scheduleSelectorFlush() {
18
19
  if (hasPendingSelectorFlush) return;
19
20
  hasPendingSelectorFlush = true;
20
- globalScheduler.enqueueInLane("derived", flushDirtySelectorCells);
21
+ globalScheduler.enqueueInLane("derived", flushDirtySelectorRecords);
21
22
  }
22
- function markSelectorCellDirty(cell) {
23
- cell._dirty = true;
24
- if (cell._scheduled) return;
25
- cell._scheduled = true;
26
- dirtySelectorCells.add(cell);
23
+ function markSelectorRecordDirty(record) {
24
+ record._dirty = true;
25
+ if (record._scheduled) return;
26
+ record._scheduled = true;
27
+ dirtySelectorRecords.add(record);
27
28
  scheduleSelectorFlush();
28
29
  }
29
- function flushDirtySelectorCells() {
30
+ function flushDirtySelectorRecords() {
30
31
  hasPendingSelectorFlush = false;
31
- if (dirtySelectorCells.size === 0) return;
32
- const pending = Array.from(dirtySelectorCells);
33
- dirtySelectorCells.clear();
34
- for (const cell of pending) {
35
- cell._scheduled = false;
36
- if (!cell._dirty) continue;
37
- recomputeSelectorCell(cell, true);
32
+ if (dirtySelectorRecords.size === 0) return;
33
+ const pending = Array.from(dirtySelectorRecords);
34
+ dirtySelectorRecords.clear();
35
+ for (const record of pending) {
36
+ record._scheduled = false;
37
+ if (!record._dirty) continue;
38
+ recomputeSelectorSourceRecord(record, true);
38
39
  }
39
40
  }
40
41
  function isObjectCandidate(value) {
@@ -48,129 +49,206 @@ function createCandidateSource(candidate) {
48
49
  source._candidate = candidate;
49
50
  return source;
50
51
  }
51
- function getCandidateSource(cell, candidate) {
52
+ function getCandidateSource(lane, candidate) {
52
53
  if (isObjectCandidate(candidate)) {
53
- const cached = cell._objectCandidates.get(candidate);
54
+ const cached = lane._objectCandidates.get(candidate);
54
55
  if (cached) return cached;
55
56
  const created = createCandidateSource(candidate);
56
- created._candidate = candidate;
57
- cell._objectCandidates.set(candidate, created);
58
- cell._objectCandidateSources.add(created);
57
+ lane._objectCandidates.set(candidate, created);
58
+ lane._objectCandidateSources.add(created);
59
59
  return created;
60
60
  }
61
61
  const key = candidate;
62
- const cached = cell._primitiveCandidates.get(key);
62
+ const cached = lane._primitiveCandidates.get(key);
63
63
  if (cached) return cached;
64
64
  const created = createCandidateSource(candidate);
65
- created._candidate = candidate;
66
- cell._primitiveCandidates.set(key, created);
65
+ lane._primitiveCandidates.set(key, created);
67
66
  return created;
68
67
  }
68
+ function getSelectorSourceRecord(source) {
69
+ const cached = selectorRecords.get(source);
70
+ if (cached) return cached;
71
+ const record = createSelectorSourceRecord(source);
72
+ selectorRecords.set(source, record);
73
+ return record;
74
+ }
75
+ function createSelectorSourceRecord(source) {
76
+ let record;
77
+ record = {
78
+ _source: source,
79
+ _value: void 0,
80
+ _hasValue: false,
81
+ _dirty: true,
82
+ _scheduled: false,
83
+ _evaluating: false,
84
+ _sources: /* @__PURE__ */ new Set(),
85
+ _lanes: /* @__PURE__ */ new Map(),
86
+ _markDirty: () => {
87
+ markSelectorRecordDirty(record);
88
+ },
89
+ _cleanup: () => {
90
+ record._scheduled = false;
91
+ record._dirty = false;
92
+ record._hasValue = false;
93
+ record._evaluating = false;
94
+ record._pendingDependencySources = void 0;
95
+ clearDerivedDependencySubscriptions(record, record._sources);
96
+ record._lanes.clear();
97
+ selectorRecords.delete(source);
98
+ }
99
+ };
100
+ return record;
101
+ }
102
+ function getSelectorLane(record, equals) {
103
+ const cached = record._lanes.get(equals);
104
+ if (cached) return cached;
105
+ const lane = createSelectorLane(record, equals);
106
+ record._lanes.set(equals, lane);
107
+ return lane;
108
+ }
109
+ function createSelectorLane(record, equals) {
110
+ const lane = {
111
+ _record: record,
112
+ _equals: equals,
113
+ _bindingCount: 0,
114
+ _primitiveCandidates: /* @__PURE__ */ new Map(),
115
+ _objectCandidates: /* @__PURE__ */ new WeakMap(),
116
+ _objectCandidateSources: /* @__PURE__ */ new Set(),
117
+ _cleanup: () => {
118
+ for (const sourceRef of lane._primitiveCandidates.values()) {
119
+ sourceRef._readers?.clear();
120
+ sourceRef._derivedSubscribers?.clear();
121
+ }
122
+ for (const sourceRef of lane._objectCandidateSources) {
123
+ sourceRef._readers?.clear();
124
+ sourceRef._derivedSubscribers?.clear();
125
+ }
126
+ lane._primitiveCandidates.clear();
127
+ lane._objectCandidates = /* @__PURE__ */ new WeakMap();
128
+ lane._objectCandidateSources.clear();
129
+ }
130
+ };
131
+ return lane;
132
+ }
69
133
  function notifySelectorSource(source) {
70
134
  incrementPerfMetric("selectorInvalidations");
71
135
  markReadableDerivedSubscribersDirty(source);
72
136
  markReactivePropsDirtySource(source);
73
137
  notifyReadableReaders(source);
74
138
  }
75
- function notifyAllSelectorSources(cell) {
76
- for (const source of cell._primitiveCandidates.values()) notifySelectorSource(source);
77
- for (const source of cell._objectCandidateSources) notifySelectorSource(source);
139
+ function notifyAllSelectorSources(lane) {
140
+ for (const source of lane._primitiveCandidates.values()) notifySelectorSource(source);
141
+ for (const source of lane._objectCandidateSources) notifySelectorSource(source);
78
142
  }
79
- function notifySelectorValueChange(cell, prevValue, nextValue) {
80
- if (!isDefaultSelectorEquals(cell._equals)) {
81
- notifyAllSelectorSources(cell);
143
+ function notifySelectorLaneValueChange(lane, prevValue, nextValue) {
144
+ if (!lane._bindingCount) return;
145
+ if (!isDefaultSelectorEquals(lane._equals)) {
146
+ if (lane._equals(prevValue, nextValue)) return;
147
+ notifyAllSelectorSources(lane);
82
148
  return;
83
149
  }
84
150
  if (!Object.is(prevValue, nextValue)) {
85
- notifySelectorSource(getCandidateSource(cell, prevValue));
86
- notifySelectorSource(getCandidateSource(cell, nextValue));
151
+ notifySelectorSource(getCandidateSource(lane, prevValue));
152
+ notifySelectorSource(getCandidateSource(lane, nextValue));
87
153
  }
88
154
  }
89
- function recomputeSelectorCell(cell, notifyDownstream) {
90
- if (!cell._dirty && cell._hasValue) return cell._value;
91
- if (cell._evaluating) throw new Error("selector() cannot read itself recursively");
92
- cell._evaluating = true;
93
- cell._dirty = false;
94
- cell._pendingDependencySources = /* @__PURE__ */ new Set();
95
- const prevSources = cell._sources;
96
- const hadValue = cell._hasValue;
97
- const prevValue = cell._value;
155
+ function recomputeSelectorSourceRecord(record, notifyDownstream) {
156
+ if (!record._dirty && record._hasValue) return record._value;
157
+ if (record._evaluating) throw new Error("selector() cannot read itself recursively");
158
+ record._evaluating = true;
159
+ record._dirty = false;
160
+ record._pendingDependencySources = /* @__PURE__ */ new Set();
161
+ const prevSources = record._sources;
162
+ const hadValue = record._hasValue;
163
+ const prevValue = record._value;
98
164
  let nextValue;
99
165
  try {
100
- nextValue = withDerivedReadTracking(cell, cell._source);
166
+ nextValue = withDerivedReadTracking(record, record._source);
101
167
  } catch (error) {
102
- cell._dirty = true;
103
- cell._pendingDependencySources = void 0;
168
+ record._dirty = true;
169
+ record._pendingDependencySources = void 0;
104
170
  throw error;
105
171
  } finally {
106
- cell._evaluating = false;
172
+ record._evaluating = false;
107
173
  }
108
- const nextSources = cell._pendingDependencySources ?? /* @__PURE__ */ new Set();
109
- cell._pendingDependencySources = void 0;
110
- syncDerivedDependencySubscriptions(cell, prevSources, nextSources);
111
- cell._sources = nextSources;
112
- const valueChanged = !cell._hasValue || !cell._equals(prevValue, nextValue);
113
- cell._hasValue = true;
114
- cell._value = nextValue;
115
- if (valueChanged && notifyDownstream && hadValue) notifySelectorValueChange(cell, prevValue, nextValue);
116
- return cell._value;
117
- }
118
- function createSelectorCell(instance, hookIndex, source, equals) {
119
- const cell = function selectorPredicate(candidate) {
120
- recordReadableRead(getCandidateSource(cell, candidate));
121
- incrementPerfMetric("selectorCandidateReads");
122
- const current = recomputeSelectorCell(cell, cell._scheduled);
123
- return cell._equals(current, candidate);
124
- };
125
- cell._owner = instance;
126
- cell._hookIndex = hookIndex;
127
- cell._source = source;
128
- cell._equals = equals;
129
- cell._value = void 0;
130
- cell._hasValue = false;
131
- cell._dirty = true;
132
- cell._scheduled = false;
133
- cell._evaluating = false;
134
- cell._sources = /* @__PURE__ */ new Set();
135
- cell._primitiveCandidates = /* @__PURE__ */ new Map();
136
- cell._objectCandidates = /* @__PURE__ */ new WeakMap();
137
- cell._objectCandidateSources = /* @__PURE__ */ new Set();
138
- cell._markDirty = () => {
139
- markSelectorCellDirty(cell);
174
+ const nextSources = record._pendingDependencySources ?? /* @__PURE__ */ new Set();
175
+ record._pendingDependencySources = void 0;
176
+ syncDerivedDependencySubscriptions(record, prevSources, nextSources);
177
+ record._sources = nextSources;
178
+ const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);
179
+ record._hasValue = true;
180
+ record._value = nextValue;
181
+ if (valueChanged && notifyDownstream && hadValue) for (const lane of Array.from(record._lanes.values())) notifySelectorLaneValueChange(lane, prevValue, nextValue);
182
+ return record._value;
183
+ }
184
+ function attachSelectorHookBinding(hook, source, equals) {
185
+ const record = getSelectorSourceRecord(source);
186
+ const lane = getSelectorLane(record, equals);
187
+ hook._source = source;
188
+ hook._equals = equals;
189
+ hook._record = record;
190
+ hook._lane = lane;
191
+ lane._bindingCount += 1;
192
+ }
193
+ function detachSelectorHookBinding(hook) {
194
+ const record = hook._record;
195
+ const lane = hook._lane;
196
+ hook._record = null;
197
+ hook._lane = null;
198
+ if (!record || !lane) return;
199
+ if (lane._bindingCount > 0) lane._bindingCount -= 1;
200
+ if (lane._bindingCount > 0) return;
201
+ lane._cleanup();
202
+ record._lanes.delete(lane._equals);
203
+ if (record._lanes.size === 0) record._cleanup();
204
+ }
205
+ function ensureSelectorHookBinding(hook) {
206
+ const record = hook._record;
207
+ const lane = hook._lane;
208
+ if (record && lane && lane._bindingCount > 0 && record._lanes.get(hook._equals) === lane && record._source === hook._source) return record;
209
+ if (hook._record || hook._lane) detachSelectorHookBinding(hook);
210
+ attachSelectorHookBinding(hook, hook._source, hook._equals);
211
+ return hook._record;
212
+ }
213
+ function createSelectorHook(instance, hookIndex, source, equals) {
214
+ const hook = function selectorPredicate(candidate) {
215
+ const selectorHook = hook;
216
+ const record = ensureSelectorHookBinding(selectorHook);
217
+ const lane = selectorHook._lane;
218
+ if (!lane) throw new Error("selector() binding could not be established.");
219
+ recordReadableRead(getCandidateSource(lane, candidate));
220
+ const perfMetricsStore = getPerfMetricsStore();
221
+ if (perfMetricsStore) perfMetricsStore.selectorCandidateReads += 1;
222
+ const current = record._dirty || !record._hasValue ? recomputeSelectorSourceRecord(record, record._scheduled) : record._value;
223
+ return lane._equals(current, candidate);
140
224
  };
141
- cell._cleanup = () => {
142
- cell._scheduled = false;
143
- cell._dirty = false;
144
- cell._hasValue = false;
145
- dirtySelectorCells.delete(cell);
146
- clearDerivedDependencySubscriptions(cell, cell._sources);
147
- for (const sourceRef of cell._primitiveCandidates.values()) {
148
- sourceRef._readers?.clear();
149
- sourceRef._derivedSubscribers?.clear();
150
- }
151
- for (const sourceRef of cell._objectCandidateSources) {
152
- sourceRef._readers?.clear();
153
- sourceRef._derivedSubscribers?.clear();
154
- }
155
- cell._primitiveCandidates.clear();
156
- cell._objectCandidateSources.clear();
225
+ hook._owner = instance;
226
+ hook._hookIndex = hookIndex;
227
+ hook._source = source;
228
+ hook._equals = equals;
229
+ hook._record = null;
230
+ hook._lane = null;
231
+ hook._cleanup = () => {
232
+ detachSelectorHookBinding(hook);
157
233
  };
234
+ attachSelectorHookBinding(hook, source, equals);
158
235
  (instance.cleanupFns ??= []).push(() => {
159
- cell._cleanup();
236
+ hook._cleanup();
160
237
  selectorCells.get(instance)?.delete(hookIndex);
161
238
  });
162
- return cell;
239
+ return hook;
163
240
  }
164
- function getOrCreateSelectorCell(instance, hookIndex, source, equals) {
241
+ function getOrCreateSelectorHook(instance, hookIndex, source, equals) {
165
242
  const store = getSelectorStore(instance);
166
243
  const existing = store.get(hookIndex);
167
244
  if (existing) {
168
- existing._source = source;
169
- existing._equals = equals;
170
- existing._dirty = true;
245
+ if (existing._source !== source || existing._equals !== equals) {
246
+ detachSelectorHookBinding(existing);
247
+ attachSelectorHookBinding(existing, source, equals);
248
+ } else ensureSelectorHookBinding(existing);
171
249
  return existing;
172
250
  }
173
- const created = createSelectorCell(instance, hookIndex, source, equals);
251
+ const created = createSelectorHook(instance, hookIndex, source, equals);
174
252
  store.set(hookIndex, created);
175
253
  return created;
176
254
  }
@@ -178,9 +256,10 @@ function selector(source, equals = Object.is) {
178
256
  markReadableUsage(source);
179
257
  const instance = getCurrentInstance();
180
258
  if (!instance) throw new Error("selector() can only be called during component render execution. Move selector() calls to the top level of your component function.");
181
- const cell = getOrCreateSelectorCell(instance, claimHookIndex(instance, "selector"), source, equals);
182
- recomputeSelectorCell(cell, false);
183
- return cell;
259
+ const hook = getOrCreateSelectorHook(instance, claimHookIndex(instance, "selector"), source, equals);
260
+ if (!hook._record) throw new Error("selector() record binding was not established.");
261
+ if (!hook._record._hasValue) recomputeSelectorSourceRecord(hook._record, false);
262
+ return hook;
184
263
  }
185
264
  //#endregion
186
265
  export { selector };
@@ -1 +1 @@
1
- {"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { globalScheduler } from './scheduler';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { incrementPerfMetric } from './perf-metrics';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorCell<T> extends Selector<T>, DerivedSubscriber {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorCell<unknown>>\n>();\nconst dirtySelectorCells = new Set<SelectorCell<unknown>>();\nlet hasPendingSelectorFlush = false;\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorCell<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction scheduleSelectorFlush(): void {\n if (hasPendingSelectorFlush) {\n return;\n }\n hasPendingSelectorFlush = true;\n globalScheduler.enqueueInLane('derived', flushDirtySelectorCells);\n}\n\nfunction markSelectorCellDirty(cell: SelectorCell<unknown>): void {\n cell._dirty = true;\n if (cell._scheduled) {\n return;\n }\n\n cell._scheduled = true;\n dirtySelectorCells.add(cell);\n scheduleSelectorFlush();\n}\n\nfunction flushDirtySelectorCells(): void {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorCells.size === 0) {\n return;\n }\n\n const pending = Array.from(dirtySelectorCells);\n dirtySelectorCells.clear();\n\n for (const cell of pending) {\n cell._scheduled = false;\n if (!cell._dirty) {\n continue;\n }\n recomputeSelectorCell(cell, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n cell: SelectorCell<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = cell._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n created._candidate = candidate;\n cell._objectCandidates.set(candidate, created);\n cell._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = cell._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n created._candidate = candidate;\n cell._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(cell: SelectorCell<T>): void {\n for (const source of cell._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of cell._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorValueChange<T>(\n cell: SelectorCell<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!isDefaultSelectorEquals(cell._equals)) {\n notifyAllSelectorSources(cell);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n notifySelectorSource(getCandidateSource(cell, prevValue));\n notifySelectorSource(getCandidateSource(cell, nextValue));\n }\n}\n\nfunction recomputeSelectorCell<T>(\n cell: SelectorCell<T>,\n notifyDownstream: boolean\n): T {\n if (!cell._dirty && cell._hasValue) {\n return cell._value;\n }\n\n if (cell._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n cell._evaluating = true;\n cell._dirty = false;\n cell._pendingDependencySources = new Set();\n\n const prevSources = cell._sources;\n const hadValue = cell._hasValue;\n const prevValue = cell._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(cell, cell._source);\n } catch (error) {\n cell._dirty = true;\n cell._pendingDependencySources = undefined;\n throw error;\n } finally {\n cell._evaluating = false;\n }\n\n const nextSources = cell._pendingDependencySources ?? new Set();\n cell._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(cell, prevSources, nextSources);\n cell._sources = nextSources;\n\n const valueChanged = !cell._hasValue || !cell._equals(prevValue, nextValue);\n cell._hasValue = true;\n cell._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n notifySelectorValueChange(cell, prevValue, nextValue);\n }\n\n return cell._value;\n}\n\nfunction createSelectorCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorCell<T> {\n const cell = function selectorPredicate(candidate: T): boolean {\n const sourceRef = getCandidateSource(cell as SelectorCell<T>, candidate);\n recordReadableRead(sourceRef);\n incrementPerfMetric('selectorCandidateReads');\n const current = recomputeSelectorCell(\n cell as SelectorCell<T>,\n (cell as SelectorCell<T>)._scheduled\n );\n return (cell as SelectorCell<T>)._equals(current, candidate);\n } as SelectorCell<T>;\n\n cell._owner = instance;\n cell._hookIndex = hookIndex;\n cell._source = source;\n cell._equals = equals;\n cell._value = undefined as T;\n cell._hasValue = false;\n cell._dirty = true;\n cell._scheduled = false;\n cell._evaluating = false;\n cell._sources = new Set();\n cell._primitiveCandidates = new Map();\n cell._objectCandidates = new WeakMap();\n cell._objectCandidateSources = new Set();\n cell._markDirty = () => {\n markSelectorCellDirty(cell as unknown as SelectorCell<unknown>);\n };\n cell._cleanup = () => {\n cell._scheduled = false;\n cell._dirty = false;\n cell._hasValue = false;\n dirtySelectorCells.delete(cell as unknown as SelectorCell<unknown>);\n clearDerivedDependencySubscriptions(cell, cell._sources);\n for (const sourceRef of cell._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of cell._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n cell._primitiveCandidates.clear();\n cell._objectCandidateSources.clear();\n };\n\n (instance.cleanupFns ??= []).push(() => {\n cell._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return cell;\n}\n\nfunction getOrCreateSelectorCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorCell<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorCell<T> | undefined;\n if (existing) {\n existing._source = source;\n existing._equals = equals;\n existing._dirty = true;\n return existing;\n }\n\n const created = createSelectorCell(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorCell<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const cell = getOrCreateSelectorCell(instance, hookIndex, source, equals);\n recomputeSelectorCell(cell, false);\n return cell;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { globalScheduler } from './scheduler';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { getPerfMetricsStore, incrementPerfMetric } from './perf-metrics';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorLane<T> {\n _record: SelectorSourceRecord<T>;\n _equals: SelectorEquals<T>;\n _bindingCount: number;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorSourceRecord<T> extends DerivedSubscriber {\n _source: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _lanes: Map<SelectorEquals<T>, SelectorLane<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorHook<T> extends Selector<T> {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _record: SelectorSourceRecord<T> | null;\n _lane: SelectorLane<T> | null;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorHook<unknown>>\n>();\nconst selectorRecords = new WeakMap<\n ReadableSource<unknown>,\n SelectorSourceRecord<unknown>\n>();\nconst dirtySelectorRecords = new Set<SelectorSourceRecord<unknown>>();\nlet hasPendingSelectorFlush = false;\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorHook<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction scheduleSelectorFlush(): void {\n if (hasPendingSelectorFlush) {\n return;\n }\n\n hasPendingSelectorFlush = true;\n globalScheduler.enqueueInLane('derived', flushDirtySelectorRecords);\n}\n\nfunction markSelectorRecordDirty(record: SelectorSourceRecord<unknown>): void {\n record._dirty = true;\n if (record._scheduled) {\n return;\n }\n\n record._scheduled = true;\n dirtySelectorRecords.add(record);\n scheduleSelectorFlush();\n}\n\nfunction flushDirtySelectorRecords(): void {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorRecords.size === 0) {\n return;\n }\n\n const pending = Array.from(dirtySelectorRecords);\n dirtySelectorRecords.clear();\n\n for (const record of pending) {\n record._scheduled = false;\n if (!record._dirty) {\n continue;\n }\n recomputeSelectorSourceRecord(record, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = lane._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._objectCandidates.set(candidate, created);\n lane._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = lane._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction getSelectorSourceRecord<T>(source: () => T): SelectorSourceRecord<T> {\n const cached = selectorRecords.get(source);\n if (cached) {\n return cached as SelectorSourceRecord<T>;\n }\n\n const record = createSelectorSourceRecord(source);\n selectorRecords.set(source, record as SelectorSourceRecord<unknown>);\n return record;\n}\n\nfunction createSelectorSourceRecord<T>(\n source: () => T\n): SelectorSourceRecord<T> {\n let record!: SelectorSourceRecord<T>;\n\n record = {\n _source: source,\n _value: undefined as T,\n _hasValue: false,\n _dirty: true,\n _scheduled: false,\n _evaluating: false,\n _sources: new Set(),\n _lanes: new Map(),\n _markDirty: () => {\n markSelectorRecordDirty(record as SelectorSourceRecord<unknown>);\n },\n _cleanup: () => {\n record._scheduled = false;\n record._dirty = false;\n record._hasValue = false;\n record._evaluating = false;\n record._pendingDependencySources = undefined;\n clearDerivedDependencySubscriptions(record, record._sources);\n record._lanes.clear();\n selectorRecords.delete(source as ReadableSource<unknown>);\n },\n };\n\n return record;\n}\n\nfunction getSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const cached = record._lanes.get(equals);\n if (cached) {\n return cached;\n }\n\n const lane = createSelectorLane(record, equals);\n record._lanes.set(equals, lane);\n return lane;\n}\n\nfunction createSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const lane: SelectorLane<T> = {\n _record: record,\n _equals: equals,\n _bindingCount: 0,\n _primitiveCandidates: new Map(),\n _objectCandidates: new WeakMap(),\n _objectCandidateSources: new Set(),\n _cleanup: () => {\n for (const sourceRef of lane._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of lane._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n lane._primitiveCandidates.clear();\n lane._objectCandidates = new WeakMap();\n lane._objectCandidateSources.clear();\n },\n };\n\n return lane;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(lane: SelectorLane<T>): void {\n for (const source of lane._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of lane._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorLaneValueChange<T>(\n lane: SelectorLane<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!lane._bindingCount) {\n return;\n }\n\n if (!isDefaultSelectorEquals(lane._equals)) {\n if (lane._equals(prevValue, nextValue)) {\n return;\n }\n notifyAllSelectorSources(lane);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n notifySelectorSource(getCandidateSource(lane, prevValue));\n notifySelectorSource(getCandidateSource(lane, nextValue));\n }\n}\n\nfunction recomputeSelectorSourceRecord<T>(\n record: SelectorSourceRecord<T>,\n notifyDownstream: boolean\n): T {\n if (!record._dirty && record._hasValue) {\n return record._value;\n }\n\n if (record._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n record._evaluating = true;\n record._dirty = false;\n record._pendingDependencySources = new Set();\n\n const prevSources = record._sources;\n const hadValue = record._hasValue;\n const prevValue = record._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(record, record._source);\n } catch (error) {\n record._dirty = true;\n record._pendingDependencySources = undefined;\n throw error;\n } finally {\n record._evaluating = false;\n }\n\n const nextSources = record._pendingDependencySources ?? new Set();\n record._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(record, prevSources, nextSources);\n record._sources = nextSources;\n\n const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);\n record._hasValue = true;\n record._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n for (const lane of Array.from(record._lanes.values())) {\n notifySelectorLaneValueChange(lane, prevValue, nextValue);\n }\n }\n\n return record._value;\n}\n\nfunction attachSelectorHookBinding<T>(\n hook: SelectorHook<T>,\n source: () => T,\n equals: SelectorEquals<T>\n): void {\n const record = getSelectorSourceRecord(source);\n const lane = getSelectorLane(record, equals);\n\n hook._source = source;\n hook._equals = equals;\n hook._record = record;\n hook._lane = lane;\n lane._bindingCount += 1;\n}\n\nfunction detachSelectorHookBinding<T>(hook: SelectorHook<T>): void {\n const record = hook._record;\n const lane = hook._lane;\n\n hook._record = null;\n hook._lane = null;\n\n if (!record || !lane) {\n return;\n }\n\n if (lane._bindingCount > 0) {\n lane._bindingCount -= 1;\n }\n\n if (lane._bindingCount > 0) {\n return;\n }\n\n lane._cleanup();\n record._lanes.delete(lane._equals);\n\n if (record._lanes.size === 0) {\n record._cleanup();\n }\n}\n\nfunction ensureSelectorHookBinding<T>(\n hook: SelectorHook<T>\n): SelectorSourceRecord<T> {\n const record = hook._record;\n const lane = hook._lane;\n\n if (\n record &&\n lane &&\n lane._bindingCount > 0 &&\n record._lanes.get(hook._equals) === lane &&\n record._source === hook._source\n ) {\n return record;\n }\n\n if (hook._record || hook._lane) {\n detachSelectorHookBinding(hook);\n }\n\n attachSelectorHookBinding(hook, hook._source, hook._equals);\n return hook._record!;\n}\n\nfunction createSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const hook = function selectorPredicate(candidate: T): boolean {\n const selectorHook = hook as SelectorHook<T>;\n const record = ensureSelectorHookBinding(selectorHook);\n const lane = selectorHook._lane;\n if (!lane) {\n throw new Error('selector() binding could not be established.');\n }\n\n const sourceRef = getCandidateSource(lane, candidate);\n recordReadableRead(sourceRef);\n\n const perfMetricsStore = getPerfMetricsStore();\n if (perfMetricsStore) {\n perfMetricsStore.selectorCandidateReads += 1;\n }\n\n const current =\n record._dirty || !record._hasValue\n ? recomputeSelectorSourceRecord(record, record._scheduled)\n : record._value;\n\n return lane._equals(current, candidate);\n } as SelectorHook<T>;\n\n hook._owner = instance;\n hook._hookIndex = hookIndex;\n hook._source = source;\n hook._equals = equals;\n hook._record = null;\n hook._lane = null;\n hook._cleanup = () => {\n detachSelectorHookBinding(hook);\n };\n\n attachSelectorHookBinding(hook, source, equals);\n\n (instance.cleanupFns ??= []).push(() => {\n hook._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return hook;\n}\n\nfunction getOrCreateSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorHook<T> | undefined;\n if (existing) {\n if (existing._source !== source || existing._equals !== equals) {\n detachSelectorHookBinding(existing);\n attachSelectorHookBinding(existing, source, equals);\n } else {\n ensureSelectorHookBinding(existing);\n }\n return existing;\n }\n\n const created = createSelectorHook(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorHook<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const hook = getOrCreateSelectorHook(instance, hookIndex, source, equals);\n if (!hook._record) {\n throw new Error('selector() record binding was not established.');\n }\n\n if (!hook._record._hasValue) {\n // Initialize the shared source once so downstream selectors can subscribe,\n // but do not consume a pending dirty state on later renders.\n recomputeSelectorSourceRecord(hook._record, false);\n }\n return hook;\n}\n"],"mappings":";;;;;AA0EA,MAAM,gCAAgB,IAAI,SAGvB;AACH,MAAM,kCAAkB,IAAI,SAGzB;AACH,MAAM,uCAAuB,IAAI,KAAoC;AACrE,IAAI,0BAA0B;AAE9B,SAAS,iBACP,UACoC;CACpC,IAAI,QAAQ,cAAc,IAAI,SAAS;CACvC,IAAI,CAAC,OAAO;EACV,wBAAQ,IAAI,KAAK;EACjB,cAAc,IAAI,UAAU,MAAM;;CAEpC,OAAO;;AAGT,SAAS,wBAA8B;CACrC,IAAI,yBACF;CAGF,0BAA0B;CAC1B,gBAAgB,cAAc,WAAW,0BAA0B;;AAGrE,SAAS,wBAAwB,QAA6C;CAC5E,OAAO,SAAS;CAChB,IAAI,OAAO,YACT;CAGF,OAAO,aAAa;CACpB,qBAAqB,IAAI,OAAO;CAChC,uBAAuB;;AAGzB,SAAS,4BAAkC;CACzC,0BAA0B;CAE1B,IAAI,qBAAqB,SAAS,GAChC;CAGF,MAAM,UAAU,MAAM,KAAK,qBAAqB;CAChD,qBAAqB,OAAO;CAE5B,KAAK,MAAM,UAAU,SAAS;EAC5B,OAAO,aAAa;EACpB,IAAI,CAAC,OAAO,QACV;EAEF,8BAA8B,QAAQ,KAAK;;;AAI/C,SAAS,kBAAkB,OAAiC;CAC1D,OACG,OAAO,UAAU,YAAY,UAAU,QAAS,OAAO,UAAU;;AAItE,SAAS,wBAA2B,QAAoC;CACtE,OAAO,WAAW,OAAO;;AAG3B,SAAS,sBAAyB,WAA0C;CAC1E,MAAM,gBAAgB;CACtB,OAAO,aAAa;CACpB,OAAO;;AAGT,SAAS,mBACP,MACA,WAC4B;CAC5B,IAAI,kBAAkB,UAAU,EAAE;EAChC,MAAM,SAAS,KAAK,kBAAkB,IAAI,UAAU;EACpD,IAAI,QACF,OAAO;EAGT,MAAM,UAAU,sBAAsB,UAAU;EAChD,KAAK,kBAAkB,IAAI,WAAW,QAAQ;EAC9C,KAAK,wBAAwB,IAAI,QAAQ;EACzC,OAAO;;CAGT,MAAM,MAAM;CACZ,MAAM,SAAS,KAAK,qBAAqB,IAAI,IAAI;CACjD,IAAI,QACF,OAAO;CAGT,MAAM,UAAU,sBAAsB,UAAU;CAChD,KAAK,qBAAqB,IAAI,KAAK,QAAQ;CAC3C,OAAO;;AAGT,SAAS,wBAA2B,QAA0C;CAC5E,MAAM,SAAS,gBAAgB,IAAI,OAAO;CAC1C,IAAI,QACF,OAAO;CAGT,MAAM,SAAS,2BAA2B,OAAO;CACjD,gBAAgB,IAAI,QAAQ,OAAwC;CACpE,OAAO;;AAGT,SAAS,2BACP,QACyB;CACzB,IAAI;CAEJ,SAAS;EACP,SAAS;EACT,QAAQ;EACR,WAAW;EACX,QAAQ;EACR,YAAY;EACZ,aAAa;EACb,0BAAU,IAAI,KAAK;EACnB,wBAAQ,IAAI,KAAK;EACjB,kBAAkB;GAChB,wBAAwB,OAAwC;;EAElE,gBAAgB;GACd,OAAO,aAAa;GACpB,OAAO,SAAS;GAChB,OAAO,YAAY;GACnB,OAAO,cAAc;GACrB,OAAO,4BAA4B;GACnC,oCAAoC,QAAQ,OAAO,SAAS;GAC5D,OAAO,OAAO,OAAO;GACrB,gBAAgB,OAAO,OAAkC;;EAE5D;CAED,OAAO;;AAGT,SAAS,gBACP,QACA,QACiB;CACjB,MAAM,SAAS,OAAO,OAAO,IAAI,OAAO;CACxC,IAAI,QACF,OAAO;CAGT,MAAM,OAAO,mBAAmB,QAAQ,OAAO;CAC/C,OAAO,OAAO,IAAI,QAAQ,KAAK;CAC/B,OAAO;;AAGT,SAAS,mBACP,QACA,QACiB;CACjB,MAAM,OAAwB;EAC5B,SAAS;EACT,SAAS;EACT,eAAe;EACf,sCAAsB,IAAI,KAAK;EAC/B,mCAAmB,IAAI,SAAS;EAChC,yCAAyB,IAAI,KAAK;EAClC,gBAAgB;GACd,KAAK,MAAM,aAAa,KAAK,qBAAqB,QAAQ,EAAE;IAC1D,UAAU,UAAU,OAAO;IAC3B,UAAU,qBAAqB,OAAO;;GAExC,KAAK,MAAM,aAAa,KAAK,yBAAyB;IACpD,UAAU,UAAU,OAAO;IAC3B,UAAU,qBAAqB,OAAO;;GAExC,KAAK,qBAAqB,OAAO;GACjC,KAAK,oCAAoB,IAAI,SAAS;GACtC,KAAK,wBAAwB,OAAO;;EAEvC;CAED,OAAO;;AAGT,SAAS,qBAAqB,QAAgD;CAC5E,oBAAoB,wBAAwB;CAC5C,oCAAoC,OAAO;CAC3C,6BAA6B,OAAO;CACpC,sBAAsB,OAAO;;AAG/B,SAAS,yBAA4B,MAA6B;CAChE,KAAK,MAAM,UAAU,KAAK,qBAAqB,QAAQ,EACrD,qBAAqB,OAAO;CAE9B,KAAK,MAAM,UAAU,KAAK,yBACxB,qBAAqB,OAAO;;AAIhC,SAAS,8BACP,MACA,WACA,WACM;CACN,IAAI,CAAC,KAAK,eACR;CAGF,IAAI,CAAC,wBAAwB,KAAK,QAAQ,EAAE;EAC1C,IAAI,KAAK,QAAQ,WAAW,UAAU,EACpC;EAEF,yBAAyB,KAAK;EAC9B;;CAGF,IAAI,CAAC,OAAO,GAAG,WAAW,UAAU,EAAE;EACpC,qBAAqB,mBAAmB,MAAM,UAAU,CAAC;EACzD,qBAAqB,mBAAmB,MAAM,UAAU,CAAC;;;AAI7D,SAAS,8BACP,QACA,kBACG;CACH,IAAI,CAAC,OAAO,UAAU,OAAO,WAC3B,OAAO,OAAO;CAGhB,IAAI,OAAO,aACT,MAAM,IAAI,MAAM,4CAA4C;CAG9D,OAAO,cAAc;CACrB,OAAO,SAAS;CAChB,OAAO,4CAA4B,IAAI,KAAK;CAE5C,MAAM,cAAc,OAAO;CAC3B,MAAM,WAAW,OAAO;CACxB,MAAM,YAAY,OAAO;CACzB,IAAI;CAEJ,IAAI;EACF,YAAY,wBAAwB,QAAQ,OAAO,QAAQ;UACpD,OAAO;EACd,OAAO,SAAS;EAChB,OAAO,4BAA4B;EACnC,MAAM;WACE;EACR,OAAO,cAAc;;CAGvB,MAAM,cAAc,OAAO,6CAA6B,IAAI,KAAK;CACjE,OAAO,4BAA4B;CACnC,mCAAmC,QAAQ,aAAa,YAAY;CACpE,OAAO,WAAW;CAElB,MAAM,eAAe,CAAC,OAAO,aAAa,CAAC,OAAO,GAAG,WAAW,UAAU;CAC1E,OAAO,YAAY;CACnB,OAAO,SAAS;CAEhB,IAAI,gBAAgB,oBAAoB,UACtC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,OAAO,QAAQ,CAAC,EACnD,8BAA8B,MAAM,WAAW,UAAU;CAI7D,OAAO,OAAO;;AAGhB,SAAS,0BACP,MACA,QACA,QACM;CACN,MAAM,SAAS,wBAAwB,OAAO;CAC9C,MAAM,OAAO,gBAAgB,QAAQ,OAAO;CAE5C,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,QAAQ;CACb,KAAK,iBAAiB;;AAGxB,SAAS,0BAA6B,MAA6B;CACjE,MAAM,SAAS,KAAK;CACpB,MAAM,OAAO,KAAK;CAElB,KAAK,UAAU;CACf,KAAK,QAAQ;CAEb,IAAI,CAAC,UAAU,CAAC,MACd;CAGF,IAAI,KAAK,gBAAgB,GACvB,KAAK,iBAAiB;CAGxB,IAAI,KAAK,gBAAgB,GACvB;CAGF,KAAK,UAAU;CACf,OAAO,OAAO,OAAO,KAAK,QAAQ;CAElC,IAAI,OAAO,OAAO,SAAS,GACzB,OAAO,UAAU;;AAIrB,SAAS,0BACP,MACyB;CACzB,MAAM,SAAS,KAAK;CACpB,MAAM,OAAO,KAAK;CAElB,IACE,UACA,QACA,KAAK,gBAAgB,KACrB,OAAO,OAAO,IAAI,KAAK,QAAQ,KAAK,QACpC,OAAO,YAAY,KAAK,SAExB,OAAO;CAGT,IAAI,KAAK,WAAW,KAAK,OACvB,0BAA0B,KAAK;CAGjC,0BAA0B,MAAM,KAAK,SAAS,KAAK,QAAQ;CAC3D,OAAO,KAAK;;AAGd,SAAS,mBACP,UACA,WACA,QACA,QACiB;CACjB,MAAM,OAAO,SAAS,kBAAkB,WAAuB;EAC7D,MAAM,eAAe;EACrB,MAAM,SAAS,0BAA0B,aAAa;EACtD,MAAM,OAAO,aAAa;EAC1B,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,+CAA+C;EAIjE,mBADkB,mBAAmB,MAAM,UACxB,CAAU;EAE7B,MAAM,mBAAmB,qBAAqB;EAC9C,IAAI,kBACF,iBAAiB,0BAA0B;EAG7C,MAAM,UACJ,OAAO,UAAU,CAAC,OAAO,YACrB,8BAA8B,QAAQ,OAAO,WAAW,GACxD,OAAO;EAEb,OAAO,KAAK,QAAQ,SAAS,UAAU;;CAGzC,KAAK,SAAS;CACd,KAAK,aAAa;CAClB,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,QAAQ;CACb,KAAK,iBAAiB;EACpB,0BAA0B,KAAK;;CAGjC,0BAA0B,MAAM,QAAQ,OAAO;CAE/C,CAAC,SAAS,eAAe,EAAE,EAAE,WAAW;EACtC,KAAK,UAAU;EACf,cAAc,IAAI,SAAS,EAAE,OAAO,UAAU;GAC9C;CAEF,OAAO;;AAGT,SAAS,wBACP,UACA,WACA,QACA,QACiB;CACjB,MAAM,QAAQ,iBAAiB,SAAS;CACxC,MAAM,WAAW,MAAM,IAAI,UAAU;CACrC,IAAI,UAAU;EACZ,IAAI,SAAS,YAAY,UAAU,SAAS,YAAY,QAAQ;GAC9D,0BAA0B,SAAS;GACnC,0BAA0B,UAAU,QAAQ,OAAO;SAEnD,0BAA0B,SAAS;EAErC,OAAO;;CAGT,MAAM,UAAU,mBAAmB,UAAU,WAAW,QAAQ,OAAO;CACvE,MAAM,IAAI,WAAW,QAA4C;CACjE,OAAO;;AAGT,SAAgB,SACd,QACA,SAA4B,OAAO,IACtB;CACb,kBAAkB,OAAO;CAEzB,MAAM,WAAW,oBAAoB;CACrC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,sIAED;CAIH,MAAM,OAAO,wBAAwB,UADnB,eAAe,UAAU,WACI,EAAW,QAAQ,OAAO;CACzE,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MAAM,iDAAiD;CAGnE,IAAI,CAAC,KAAK,QAAQ,WAGhB,8BAA8B,KAAK,SAAS,MAAM;CAEpD,OAAO"}
@@ -0,0 +1,10 @@
1
+ //#region src/runtime/snapshot-source.d.ts
2
+ declare const SNAPSHOT_SOURCE_BRAND: unique symbol;
3
+ type SnapshotSourceBrand = {
4
+ readonly [SNAPSHOT_SOURCE_BRAND]: true;
5
+ };
6
+ declare function brandSnapshotSource<T extends object>(value: T): T & SnapshotSourceBrand;
7
+ declare function isSnapshotSource(value: unknown): value is SnapshotSourceBrand;
8
+ //#endregion
9
+ export { SnapshotSourceBrand };
10
+ //# sourceMappingURL=snapshot-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-source.d.ts","names":[],"sources":["../../src/runtime/snapshot-source.ts"],"mappings":";cAAa,qBAAA;AAAA,KAED,mBAAA;EAAA,UACA,qBAAA;AAAA;AAAA,iBAGI,mBAAA,kBAAA,CACd,KAAA,EAAO,CAAA,GACN,CAAA,GAAI,mBAAA;AAAA,iBASS,gBAAA,CAAiB,KAAA,YAAiB,KAAA,IAAS,mBAAA"}
@@ -0,0 +1,17 @@
1
+ //#region src/runtime/snapshot-source.ts
2
+ const SNAPSHOT_SOURCE_BRAND = Symbol.for("__ASKR_SNAPSHOT_SOURCE__");
3
+ function brandSnapshotSource(value) {
4
+ Object.defineProperty(value, SNAPSHOT_SOURCE_BRAND, {
5
+ value: true,
6
+ enumerable: false,
7
+ configurable: false
8
+ });
9
+ return value;
10
+ }
11
+ function isSnapshotSource(value) {
12
+ return !!value && typeof value === "object" && value[SNAPSHOT_SOURCE_BRAND] === true;
13
+ }
14
+ //#endregion
15
+ export { brandSnapshotSource, isSnapshotSource };
16
+
17
+ //# sourceMappingURL=snapshot-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-source.js","names":[],"sources":["../../src/runtime/snapshot-source.ts"],"sourcesContent":["export const SNAPSHOT_SOURCE_BRAND = Symbol.for('__ASKR_SNAPSHOT_SOURCE__');\n\nexport type SnapshotSourceBrand = {\n readonly [SNAPSHOT_SOURCE_BRAND]: true;\n};\n\nexport function brandSnapshotSource<T extends object>(\n value: T\n): T & SnapshotSourceBrand {\n Object.defineProperty(value, SNAPSHOT_SOURCE_BRAND, {\n value: true,\n enumerable: false,\n configurable: false,\n });\n return value as T & SnapshotSourceBrand;\n}\n\nexport function isSnapshotSource(value: unknown): value is SnapshotSourceBrand {\n return (\n !!value &&\n typeof value === 'object' &&\n (value as Record<PropertyKey, unknown>)[SNAPSHOT_SOURCE_BRAND] === true\n );\n}\n"],"mappings":";AAAA,MAAa,wBAAwB,OAAO,IAAI,2BAA2B;AAM3E,SAAgB,oBACd,OACyB;CACzB,OAAO,eAAe,OAAO,uBAAuB;EAClD,OAAO;EACP,YAAY;EACZ,cAAc;EACf,CAAC;CACF,OAAO;;AAGT,SAAgB,iBAAiB,OAA8C;CAC7E,OACE,CAAC,CAAC,SACF,OAAO,UAAU,YAChB,MAAuC,2BAA2B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-bridge.js","names":[],"sources":["../../src/runtime/ssr-bridge.ts"],"sourcesContent":["import type { RenderContext } from '../common/ssr';\n\nexport type SSRBridge = {\n getCurrentSSRContext(): RenderContext | null;\n throwSSRDataMissing(): never;\n\n // Deterministic SSR render-phase data lookup\n getCurrentRenderData(): Record<string, unknown> | null;\n getNextKey(): string;\n};\n\nconst defaultBridge: SSRBridge = {\n getCurrentSSRContext() {\n return null;\n },\n throwSSRDataMissing() {\n throw new Error(\n '[Askr] SSR data missing (SSR bridge not installed). ' +\n 'If you are rendering on the server, ensure you are using the askr SSR entrypoints.'\n );\n },\n getCurrentRenderData() {\n return null;\n },\n getNextKey() {\n throw new Error(\n '[Askr] getNextKey() called outside SSR render phase (SSR bridge not installed).'\n );\n },\n};\n\nlet bridge: SSRBridge = defaultBridge;\n\nexport function installSSRBridge(next: SSRBridge): void {\n bridge = next;\n}\n\nexport function getSSRBridge(): SSRBridge {\n return bridge;\n}\n"],"mappings":"AA+BA,IAAI,SAAoB;CAnBtB,uBAAuB;AACrB,SAAO;;CAET,sBAAsB;AACpB,QAAM,IAAI,MACR,yIAED;;CAEH,uBAAuB;AACrB,SAAO;;CAET,aAAa;AACX,QAAM,IAAI,MACR,kFACD;;CAImB;AAExB,SAAgB,iBAAiB,MAAuB;AACtD,UAAS;;AAGX,SAAgB,eAA0B;AACxC,QAAO"}
1
+ {"version":3,"file":"ssr-bridge.js","names":[],"sources":["../../src/runtime/ssr-bridge.ts"],"sourcesContent":["import type { RenderContext } from '../common/ssr';\n\nexport type SSRBridge = {\n getCurrentSSRContext(): RenderContext | null;\n throwSSRDataMissing(): never;\n\n // Deterministic SSR render-phase data lookup\n getCurrentRenderData(): Record<string, unknown> | null;\n getNextKey(): string;\n};\n\nconst defaultBridge: SSRBridge = {\n getCurrentSSRContext() {\n return null;\n },\n throwSSRDataMissing() {\n throw new Error(\n '[Askr] SSR data missing (SSR bridge not installed). ' +\n 'If you are rendering on the server, ensure you are using the askr SSR entrypoints.'\n );\n },\n getCurrentRenderData() {\n return null;\n },\n getNextKey() {\n throw new Error(\n '[Askr] getNextKey() called outside SSR render phase (SSR bridge not installed).'\n );\n },\n};\n\nlet bridge: SSRBridge = defaultBridge;\n\nexport function installSSRBridge(next: SSRBridge): void {\n bridge = next;\n}\n\nexport function getSSRBridge(): SSRBridge {\n return bridge;\n}\n"],"mappings":"AA+BA,IAAI,SAAoB;CAnBtB,uBAAuB;EACrB,OAAO;;CAET,sBAAsB;EACpB,MAAM,IAAI,MACR,yIAED;;CAEH,uBAAuB;EACrB,OAAO;;CAET,aAAa;EACX,MAAM,IAAI,MACR,kFACD;;CAImB;AAExB,SAAgB,iBAAiB,MAAuB;CACtD,SAAS;;AAGX,SAAgB,eAA0B;CACxC,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","names":[],"sources":["../../src/runtime/state.ts"],"mappings":";;;;;;;;;;UAmCiB,KAAA,YAAiB,cAAA,CAAe,CAAA;EAAA,IAC3C,CAAA;EACJ,GAAA,CAAI,KAAA,EAAO,CAAA;EACX,GAAA,CAAI,OAAA,GAAU,IAAA,EAAM,CAAA,KAAM,CAAA;EAAA,CACzB,MAAA,CAAO,QAAP,KAAoB,QAAA,CAAS,KAAA,CAAM,CAAA,IAAK,KAAA,CAAM,CAAA;AAAA;;;;;;;;;;;;;;;;AA6BjD;;;;;;;;;;;iBAAgB,KAAA,GAAA,CAAS,YAAA,EAAc,CAAA,GAAI,KAAA,CAAM,CAAA"}
1
+ {"version":3,"file":"state.d.ts","names":[],"sources":["../../src/runtime/state.ts"],"mappings":";;;;;;;;;;UAkCiB,KAAA,YAAiB,cAAA,CAAe,CAAA;EAAA,IAC3C,CAAA;EACJ,GAAA,CAAI,KAAA,EAAO,CAAA;EACX,GAAA,CAAI,OAAA,GAAU,IAAA,EAAM,CAAA,KAAM,CAAA;EAAA,CACzB,MAAA,CAAO,QAAP,KAAoB,QAAA,CAAS,KAAA,CAAM,CAAA,IAAK,KAAA,CAAM,CAAA;AAAA;;;;;;;;;;;;;;;;AA6BjD;;;;;;;;;;;iBAAgB,KAAA,GAAA,CAAS,YAAA,EAAc,CAAA,GAAI,KAAA,CAAM,CAAA"}
@@ -1,4 +1,3 @@
1
- import { globalScheduler } from "./scheduler.js";
2
1
  import { markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, notifyReadableReaders, recordReadableRead } from "./readable.js";
3
2
  import { isBulkCommitActive } from "./fastlane.js";
4
3
  import { claimHookIndex, getCurrentInstance } from "./component.js";
@@ -61,7 +60,6 @@ function state(initialValue) {
61
60
  */
62
61
  function createStateCell(initialValue, instance) {
63
62
  let value = initialValue;
64
- let pendingNotifyFlushVersion = -1;
65
63
  const readers = /* @__PURE__ */ new Map();
66
64
  function read() {
67
65
  read._hasBeenRead = true;
@@ -83,9 +81,7 @@ function createStateCell(initialValue, instance) {
83
81
  value = newValue;
84
82
  markReadableDerivedSubscribersDirty(read);
85
83
  markReactivePropsDirtySource(read);
86
- const flushVersion = globalScheduler.getFlushVersion();
87
- if (pendingNotifyFlushVersion === flushVersion && !globalScheduler.isExecuting()) return;
88
- pendingNotifyFlushVersion = notifyReadableReaders(read) && !globalScheduler.isExecuting() ? flushVersion : -1;
84
+ notifyReadableReaders(read);
89
85
  };
90
86
  read[Symbol.iterator] = function* () {
91
87
  yield read;
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","names":[],"sources":["../../src/runtime/state.ts"],"sourcesContent":["/**\n * State primitive for Askr components\n * Optimized for minimal overhead and fast updates\n *\n * INVARIANTS ENFORCED:\n * - state() only callable during component render (currentInstance exists)\n * - state() called at top-level only (indices must be monotonically increasing)\n * - state values persist across re-renders (stored in stateValues array)\n * - state.set() cannot be called during render (causes infinite loops)\n * - state.set() always enqueues through scheduler (never direct mutation)\n * - state.set() callback (notifyUpdate) always available\n */\n\nimport { globalScheduler } from './scheduler';\nimport {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { isBulkCommitActive } from './fastlane';\nimport {\n recordReadableRead,\n type ReadableSource,\n markReadableDerivedSubscribersDirty,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n} from './readable';\n\n/**\n * State value holder - callable to read, has set method to update\n * @example\n * const count = state(0);\n * count(); // read: 0\n * count.set(1); // write: triggers re-render\n */\nexport interface State<T> extends ReadableSource<T> {\n (): T;\n set(value: T): void;\n set(updater: (prev: T) => T): void;\n [Symbol.iterator](): Iterator<State<T> | State<T>['set']>; // Allows destructuring: const [get, set] = state(0)\n}\n\n/**\n * Creates a local state value for a component\n * Optimized for:\n * - O(1) read performance\n * - Minimal allocation per state\n * - Fast scheduler integration\n *\n * IMPORTANT: state() must be called during component render execution.\n * It captures the current component instance from context.\n * Calling outside a component function will throw an error.\n *\n * @example\n * ```ts\n * // ✅ Correct: called during render\n * export function Counter() {\n * const count = state(0);\n * return { type: 'button', children: [count()] };\n * }\n *\n * // ❌ Wrong: called outside component\n * const count = state(0);\n * export function BadComponent() {\n * return { type: 'div' };\n * }\n * ```\n */\nexport function state<T>(initialValue: T): State<T> {\n // INVARIANT: state() must be called during component render\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'state() can only be called during component render execution. ' +\n 'Move state() calls to the top level of your component function.'\n );\n }\n\n const index = claimHookIndex(instance, 'state');\n const stateValues = instance.stateValues;\n\n // INVARIANT: Reuse existing state if it exists (fast path on re-renders)\n // This ensures state identity and persistence and enforces ownership stability\n if (stateValues[index]) {\n const existing = stateValues[index] as State<T> & {\n _owner?: ComponentInstance;\n };\n // Ownership must be stable: the state cell belongs to the instance that\n // created it and must never change. This checks for accidental reuse.\n if (existing._owner !== instance) {\n throw new Error(\n `State ownership violation: state() called at index ${index} is owned by a different component instance. ` +\n `State ownership is positional and immutable.`\n );\n }\n return existing as State<T>;\n }\n\n // Create new state (slow path, only on first render) — delegated to helper\n const cell = createStateCell(initialValue, instance);\n\n // INVARIANT: Store state in instance for persistence across renders\n stateValues[index] = cell;\n\n return cell;\n}\n\n/**\n * Internal helper: create the backing state cell (value + readers + set semantics)\n * This extraction makes it easier to later split hook wiring from storage.\n */\nfunction createStateCell<T>(\n initialValue: T,\n instance: ComponentInstance\n): State<T> {\n let value = initialValue;\n let pendingNotifyFlushVersion = -1;\n\n // Per-state reader map: component -> last-committed render token\n const readers = new Map<ComponentInstance, number>();\n\n // Use a function as the state object (callable directly)\n function read(): T {\n (read as State<T>)._hasBeenRead = true;\n recordReadableRead(read as State<T>);\n\n return value;\n }\n\n // Attach the readers map to the callable so other runtime parts can access it\n (read as State<T>)._readers = readers;\n\n // Record explicit ownership of this state cell. Ownership is the component\n // instance that created the state cell and must never change for the life\n // of the cell. We expose this for runtime invariant checks/tests.\n (read as State<T> & { _owner?: ComponentInstance })._owner = instance;\n\n // Attach set method directly to function\n read.set = (newValueOrUpdater: T | ((prev: T) => T)): void => {\n // INVARIANT: State cannot be mutated during component render\n // (when currentInstance is non-null). It must be scheduled for consistency.\n const currentInst = getCurrentInstance();\n if (currentInst !== null) {\n throw new Error(\n `[Askr] state.set() cannot be called during component render. ` +\n `State mutations during render break the actor model and cause infinite loops. ` +\n `Move state updates to event handlers or use conditional rendering instead.`\n );\n }\n\n // Compute new value if an updater was provided\n let newValue: T;\n if (typeof newValueOrUpdater === 'function') {\n // Note: function-valued state cannot be set directly via a function argument;\n // such an argument is treated as a functional updater (this follows the common\n // convention from other libraries). If you need to store a function as state,\n // wrap it in an object.\n const updater = newValueOrUpdater as (prev: T) => T;\n newValue = updater(value);\n } else {\n newValue = newValueOrUpdater as T;\n }\n\n // Skip work if value didn't change\n if (Object.is(value, newValue)) return;\n\n // If a bulk commit is active, update backing value only and DO NOT notify or enqueue.\n // Bulk commits must be side-effect silent with respect to runtime notifications.\n if (isBulkCommitActive()) {\n // In bulk commit mode we must be side-effect free: update backing\n // value only and do not notify, enqueue, or log.\n value = newValue;\n return;\n }\n\n // INVARIANT: Update the value\n value = newValue;\n\n markReadableDerivedSubscribersDirty(read as State<T>);\n markReactivePropsDirtySource(read as State<T>);\n\n // notifyUpdate may be temporarily unavailable (e.g. during hydration).\n // We intentionally avoid logging here to keep the state mutation path\n // side-effect free. The scheduler will process updates when the system\n // is stable.\n const flushVersion = globalScheduler.getFlushVersion();\n const canSkipNotifyPass =\n pendingNotifyFlushVersion === flushVersion &&\n !globalScheduler.isExecuting();\n\n if (canSkipNotifyPass) {\n return;\n }\n\n // After value change, notify only components that *read* this state in their last committed render.\n const didScheduleUpdate = notifyReadableReaders(read as State<T>);\n\n pendingNotifyFlushVersion =\n didScheduleUpdate && !globalScheduler.isExecuting() ? flushVersion : -1;\n };\n\n // Allow destructuring assignment: const [get, set] = state(0);\n // The state function is iterable and yields the getter then the setter\n (\n read as unknown as {\n [Symbol.iterator]?: () => Iterator<State<T> | State<T>['set']>;\n }\n )[Symbol.iterator] = function* (): Generator<\n State<T> | State<T>['set'],\n void,\n unknown\n > {\n yield read;\n yield read.set;\n };\n\n return read as State<T>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,SAAgB,MAAS,cAA2B;CAElD,MAAM,WAAW,oBAAoB;AACrC,KAAI,CAAC,SACH,OAAM,IAAI,MACR,gIAED;CAGH,MAAM,QAAQ,eAAe,UAAU,QAAQ;CAC/C,MAAM,cAAc,SAAS;AAI7B,KAAI,YAAY,QAAQ;EACtB,MAAM,WAAW,YAAY;AAK7B,MAAI,SAAS,WAAW,SACtB,OAAM,IAAI,MACR,sDAAsD,MAAM,2FAE7D;AAEH,SAAO;;CAIT,MAAM,OAAO,gBAAgB,cAAc,SAAS;AAGpD,aAAY,SAAS;AAErB,QAAO;;;;;;AAOT,SAAS,gBACP,cACA,UACU;CACV,IAAI,QAAQ;CACZ,IAAI,4BAA4B;CAGhC,MAAM,0BAAU,IAAI,KAAgC;CAGpD,SAAS,OAAU;AAChB,OAAkB,eAAe;AAClC,qBAAmB,KAAiB;AAEpC,SAAO;;AAIR,MAAkB,WAAW;AAK7B,MAAmD,SAAS;AAG7D,MAAK,OAAO,sBAAkD;AAI5D,MADoB,oBAChB,KAAgB,KAClB,OAAM,IAAI,MACR,wNAGD;EAIH,IAAI;AACJ,MAAI,OAAO,sBAAsB,WAM/B,YAAW,kBAAQ,MAAM;MAEzB,YAAW;AAIb,MAAI,OAAO,GAAG,OAAO,SAAS,CAAE;AAIhC,MAAI,oBAAoB,EAAE;AAGxB,WAAQ;AACR;;AAIF,UAAQ;AAER,sCAAoC,KAAiB;AACrD,+BAA6B,KAAiB;EAM9C,MAAM,eAAe,gBAAgB,iBAAiB;AAKtD,MAHE,8BAA8B,gBAC9B,CAAC,gBAAgB,aAAa,CAG9B;AAMF,8BAF0B,sBAAsB,KAG9C,IAAqB,CAAC,gBAAgB,aAAa,GAAG,eAAe;;AAMvE,MAGA,OAAO,YAAY,aAInB;AACA,QAAM;AACN,QAAM,KAAK;;AAGb,QAAO"}
1
+ {"version":3,"file":"state.js","names":[],"sources":["../../src/runtime/state.ts"],"sourcesContent":["/**\n * State primitive for Askr components\n * Optimized for minimal overhead and fast updates\n *\n * INVARIANTS ENFORCED:\n * - state() only callable during component render (currentInstance exists)\n * - state() called at top-level only (indices must be monotonically increasing)\n * - state values persist across re-renders (stored in stateValues array)\n * - state.set() cannot be called during render (causes infinite loops)\n * - state.set() always enqueues through scheduler (never direct mutation)\n * - state.set() callback (notifyUpdate) always available\n */\n\nimport {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { isBulkCommitActive } from './fastlane';\nimport {\n recordReadableRead,\n type ReadableSource,\n markReadableDerivedSubscribersDirty,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n} from './readable';\n\n/**\n * State value holder - callable to read, has set method to update\n * @example\n * const count = state(0);\n * count(); // read: 0\n * count.set(1); // write: triggers re-render\n */\nexport interface State<T> extends ReadableSource<T> {\n (): T;\n set(value: T): void;\n set(updater: (prev: T) => T): void;\n [Symbol.iterator](): Iterator<State<T> | State<T>['set']>; // Allows destructuring: const [get, set] = state(0)\n}\n\n/**\n * Creates a local state value for a component\n * Optimized for:\n * - O(1) read performance\n * - Minimal allocation per state\n * - Fast scheduler integration\n *\n * IMPORTANT: state() must be called during component render execution.\n * It captures the current component instance from context.\n * Calling outside a component function will throw an error.\n *\n * @example\n * ```ts\n * // ✅ Correct: called during render\n * export function Counter() {\n * const count = state(0);\n * return { type: 'button', children: [count()] };\n * }\n *\n * // ❌ Wrong: called outside component\n * const count = state(0);\n * export function BadComponent() {\n * return { type: 'div' };\n * }\n * ```\n */\nexport function state<T>(initialValue: T): State<T> {\n // INVARIANT: state() must be called during component render\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'state() can only be called during component render execution. ' +\n 'Move state() calls to the top level of your component function.'\n );\n }\n\n const index = claimHookIndex(instance, 'state');\n const stateValues = instance.stateValues;\n\n // INVARIANT: Reuse existing state if it exists (fast path on re-renders)\n // This ensures state identity and persistence and enforces ownership stability\n if (stateValues[index]) {\n const existing = stateValues[index] as State<T> & {\n _owner?: ComponentInstance;\n };\n // Ownership must be stable: the state cell belongs to the instance that\n // created it and must never change. This checks for accidental reuse.\n if (existing._owner !== instance) {\n throw new Error(\n `State ownership violation: state() called at index ${index} is owned by a different component instance. ` +\n `State ownership is positional and immutable.`\n );\n }\n return existing as State<T>;\n }\n\n // Create new state (slow path, only on first render) — delegated to helper\n const cell = createStateCell(initialValue, instance);\n\n // INVARIANT: Store state in instance for persistence across renders\n stateValues[index] = cell;\n\n return cell;\n}\n\n/**\n * Internal helper: create the backing state cell (value + readers + set semantics)\n * This extraction makes it easier to later split hook wiring from storage.\n */\nfunction createStateCell<T>(\n initialValue: T,\n instance: ComponentInstance\n): State<T> {\n let value = initialValue;\n\n // Per-state reader map: component -> last-committed render token\n const readers = new Map<ComponentInstance, number>();\n\n // Use a function as the state object (callable directly)\n function read(): T {\n (read as State<T>)._hasBeenRead = true;\n recordReadableRead(read as State<T>);\n\n return value;\n }\n\n // Attach the readers map to the callable so other runtime parts can access it\n (read as State<T>)._readers = readers;\n\n // Record explicit ownership of this state cell. Ownership is the component\n // instance that created the state cell and must never change for the life\n // of the cell. We expose this for runtime invariant checks/tests.\n (read as State<T> & { _owner?: ComponentInstance })._owner = instance;\n\n // Attach set method directly to function\n read.set = (newValueOrUpdater: T | ((prev: T) => T)): void => {\n // INVARIANT: State cannot be mutated during component render\n // (when currentInstance is non-null). It must be scheduled for consistency.\n const currentInst = getCurrentInstance();\n if (currentInst !== null) {\n throw new Error(\n `[Askr] state.set() cannot be called during component render. ` +\n `State mutations during render break the actor model and cause infinite loops. ` +\n `Move state updates to event handlers or use conditional rendering instead.`\n );\n }\n\n // Compute new value if an updater was provided\n let newValue: T;\n if (typeof newValueOrUpdater === 'function') {\n // Note: function-valued state cannot be set directly via a function argument;\n // such an argument is treated as a functional updater (this follows the common\n // convention from other libraries). If you need to store a function as state,\n // wrap it in an object.\n const updater = newValueOrUpdater as (prev: T) => T;\n newValue = updater(value);\n } else {\n newValue = newValueOrUpdater as T;\n }\n\n // Skip work if value didn't change\n if (Object.is(value, newValue)) return;\n\n // If a bulk commit is active, update backing value only and DO NOT notify or enqueue.\n // Bulk commits must be side-effect silent with respect to runtime notifications.\n if (isBulkCommitActive()) {\n // In bulk commit mode we must be side-effect free: update backing\n // value only and do not notify, enqueue, or log.\n value = newValue;\n return;\n }\n\n // INVARIANT: Update the value\n value = newValue;\n\n markReadableDerivedSubscribersDirty(read as State<T>);\n markReactivePropsDirtySource(read as State<T>);\n\n // notifyUpdate may be temporarily unavailable (e.g. during hydration).\n // We intentionally avoid logging here to keep the state mutation path\n // side-effect free. The scheduler will process updates when the system\n // is stable.\n // After value change, notify only components that *read* this state in their last committed render.\n void notifyReadableReaders(read as State<T>);\n };\n\n // Allow destructuring assignment: const [get, set] = state(0);\n // The state function is iterable and yields the getter then the setter\n (\n read as unknown as {\n [Symbol.iterator]?: () => Iterator<State<T> | State<T>['set']>;\n }\n )[Symbol.iterator] = function* (): Generator<\n State<T> | State<T>['set'],\n void,\n unknown\n > {\n yield read;\n yield read.set;\n };\n\n return read as State<T>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEA,SAAgB,MAAS,cAA2B;CAElD,MAAM,WAAW,oBAAoB;CACrC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,gIAED;CAGH,MAAM,QAAQ,eAAe,UAAU,QAAQ;CAC/C,MAAM,cAAc,SAAS;CAI7B,IAAI,YAAY,QAAQ;EACtB,MAAM,WAAW,YAAY;EAK7B,IAAI,SAAS,WAAW,UACtB,MAAM,IAAI,MACR,sDAAsD,MAAM,2FAE7D;EAEH,OAAO;;CAIT,MAAM,OAAO,gBAAgB,cAAc,SAAS;CAGpD,YAAY,SAAS;CAErB,OAAO;;;;;;AAOT,SAAS,gBACP,cACA,UACU;CACV,IAAI,QAAQ;CAGZ,MAAM,0BAAU,IAAI,KAAgC;CAGpD,SAAS,OAAU;EACjB,KAAmB,eAAe;EAClC,mBAAmB,KAAiB;EAEpC,OAAO;;CAIT,KAAmB,WAAW;CAK9B,KAAoD,SAAS;CAG7D,KAAK,OAAO,sBAAkD;EAI5D,IADoB,oBAChB,KAAgB,MAClB,MAAM,IAAI,MACR,wNAGD;EAIH,IAAI;EACJ,IAAI,OAAO,sBAAsB,YAM/B,WAAW,kBAAQ,MAAM;OAEzB,WAAW;EAIb,IAAI,OAAO,GAAG,OAAO,SAAS,EAAE;EAIhC,IAAI,oBAAoB,EAAE;GAGxB,QAAQ;GACR;;EAIF,QAAQ;EAER,oCAAoC,KAAiB;EACrD,6BAA6B,KAAiB;EAO9C,AAAK,sBAAsB,KAAiB;;CAK9C,KAIE,OAAO,YAAY,aAInB;EACA,MAAM;EACN,MAAM,KAAK;;CAGb,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"batch-render.js","names":[],"sources":["../../src/ssg/batch-render.ts"],"sourcesContent":["/**\n * Batch rendering of multiple routes for SSG\n */\n\nimport { renderResolvedToStringSync } from '../ssr';\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RouteHandler } from '../common/router';\nimport type { ComponentFunction } from '../common/component';\nimport type { SSRData } from '../common/ssr';\nimport { getOutputFilePath, interpolateRoutePath } from './route-utils';\n\ninterface BatchRenderOptions {\n seed?: number;\n dataMap?: Record<string, SSRData>;\n concurrency?: number;\n}\n\n/**\n * Render multiple routes in parallel with error handling\n */\nexport async function batchRenderRoutes(\n routes: RouteConfig[],\n options: BatchRenderOptions = {}\n): Promise<RouteRenderResult[]> {\n const { seed = 12345, dataMap = {}, concurrency = 1 } = options;\n\n const workerCount = Math.max(1, Math.min(concurrency, routes.length || 1));\n const results: RouteRenderResult[] = [];\n results.length = routes.length;\n let nextIndex = 0;\n\n const renderOne = async (route: RouteConfig): Promise<RouteRenderResult> => {\n const startTime = performance.now();\n const url = interpolateRoutePath(route.path, route.params);\n const baseData = dataMap[route.path] ?? dataMap[url] ?? {};\n\n const mergedHandler: RouteHandler = route.handler\n ? route.handler\n : (params, ctx?: unknown) => {\n const component = route.component as ComponentFunction;\n return component(\n { ...route.props, ...params },\n ctx as { signal: AbortSignal; ssr?: unknown }\n );\n };\n\n try {\n const routeEntry = {\n path: route.path,\n handler: mergedHandler,\n namespace: route.namespace,\n };\n\n const html = renderResolvedToStringSync({\n url,\n routes: [routeEntry],\n handler: mergedHandler,\n params: route.params,\n options: {\n seed,\n data: baseData,\n },\n });\n\n const duration = performance.now() - startTime;\n return {\n path: url,\n filePath: getOutputFilePath(url),\n html,\n fileSize: Buffer.byteLength(html, 'utf8'),\n renderDuration: Math.round(duration),\n resourceCount: Object.keys(baseData).length,\n status: 'success',\n reason: 'full',\n written: false,\n };\n } catch (error) {\n const duration = performance.now() - startTime;\n return {\n path: url,\n filePath: getOutputFilePath(url),\n html: '',\n fileSize: 0,\n renderDuration: Math.round(duration),\n resourceCount: Object.keys(baseData).length,\n status: 'error',\n reason: 'full',\n written: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n };\n\n const worker = async () => {\n while (true) {\n const current = nextIndex;\n nextIndex += 1;\n if (current >= routes.length) return;\n results[current] = await renderOne(routes[current]);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n return results;\n}\n"],"mappings":";;;;;;;;;AAoBA,eAAsB,kBACpB,QACA,UAA8B,EAAE,EACF;CAC9B,MAAM,EAAE,OAAO,OAAO,UAAU,EAAE,EAAE,cAAc,MAAM;CAExD,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,aAAa,OAAO,UAAU,EAAE,CAAC;CAC1E,MAAM,UAA+B,EAAE;AACvC,SAAQ,SAAS,OAAO;CACxB,IAAI,YAAY;CAEhB,MAAM,YAAY,OAAO,UAAmD;EAC1E,MAAM,YAAY,YAAY,KAAK;EACnC,MAAM,MAAM,qBAAqB,MAAM,MAAM,MAAM,OAAO;EAC1D,MAAM,WAAW,QAAQ,MAAM,SAAS,QAAQ,QAAQ,EAAE;EAE1D,MAAM,gBAA8B,MAAM,UACtC,MAAM,WACL,QAAQ,QAAkB;GACzB,MAAM,YAAY,MAAM;AACxB,UAAO,UACL;IAAE,GAAG,MAAM;IAAO,GAAG;IAAQ,EAC7B,IACD;;AAGP,MAAI;GAOF,MAAM,OAAO,2BAA2B;IACtC;IACA,QAAQ,CAAC;KAPT,MAAM,MAAM;KACZ,SAAS;KACT,WAAW,MAAM;KAKR,CAAW;IACpB,SAAS;IACT,QAAQ,MAAM;IACd,SAAS;KACP;KACA,MAAM;KACP;IACF,CAAC;GAEF,MAAM,WAAW,YAAY,KAAK,GAAG;AACrC,UAAO;IACL,MAAM;IACN,UAAU,kBAAkB,IAAI;IAChC;IACA,UAAU,OAAO,WAAW,MAAM,OAAO;IACzC,gBAAgB,KAAK,MAAM,SAAS;IACpC,eAAe,OAAO,KAAK,SAAS,CAAC;IACrC,QAAQ;IACR,QAAQ;IACR,SAAS;IACV;WACM,OAAO;GACd,MAAM,WAAW,YAAY,KAAK,GAAG;AACrC,UAAO;IACL,MAAM;IACN,UAAU,kBAAkB,IAAI;IAChC,MAAM;IACN,UAAU;IACV,gBAAgB,KAAK,MAAM,SAAS;IACpC,eAAe,OAAO,KAAK,SAAS,CAAC;IACrC,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D;;;CAIL,MAAM,SAAS,YAAY;AACzB,SAAO,MAAM;GACX,MAAM,UAAU;AAChB,gBAAa;AACb,OAAI,WAAW,OAAO,OAAQ;AAC9B,WAAQ,WAAW,MAAM,UAAU,OAAO,SAAS;;;AAIvD,OAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,aAAa,QAAQ,QAAQ,CAAC,CAAC;AACtE,QAAO"}
1
+ {"version":3,"file":"batch-render.js","names":[],"sources":["../../src/ssg/batch-render.ts"],"sourcesContent":["/**\n * Batch rendering of multiple routes for SSG\n */\n\nimport { renderResolvedToStringSync } from '../ssr';\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RouteHandler } from '../common/router';\nimport type { ComponentFunction } from '../common/component';\nimport type { SSRData } from '../common/ssr';\nimport { getOutputFilePath, interpolateRoutePath } from './route-utils';\n\ninterface BatchRenderOptions {\n seed?: number;\n dataMap?: Record<string, SSRData>;\n concurrency?: number;\n}\n\n/**\n * Render multiple routes in parallel with error handling\n */\nexport async function batchRenderRoutes(\n routes: RouteConfig[],\n options: BatchRenderOptions = {}\n): Promise<RouteRenderResult[]> {\n const { seed = 12345, dataMap = {}, concurrency = 1 } = options;\n\n const workerCount = Math.max(1, Math.min(concurrency, routes.length || 1));\n const results: RouteRenderResult[] = [];\n results.length = routes.length;\n let nextIndex = 0;\n\n const renderOne = async (route: RouteConfig): Promise<RouteRenderResult> => {\n const startTime = performance.now();\n const url = interpolateRoutePath(route.path, route.params);\n const baseData = dataMap[route.path] ?? dataMap[url] ?? {};\n\n const mergedHandler: RouteHandler = route.handler\n ? route.handler\n : (params, ctx?: unknown) => {\n const component = route.component as ComponentFunction;\n return component(\n { ...route.props, ...params },\n ctx as { signal: AbortSignal; ssr?: unknown }\n );\n };\n\n try {\n const routeEntry = {\n path: route.path,\n handler: mergedHandler,\n namespace: route.namespace,\n };\n\n const html = renderResolvedToStringSync({\n url,\n routes: [routeEntry],\n handler: mergedHandler,\n params: route.params,\n options: {\n seed,\n data: baseData,\n },\n });\n\n const duration = performance.now() - startTime;\n return {\n path: url,\n filePath: getOutputFilePath(url),\n html,\n fileSize: Buffer.byteLength(html, 'utf8'),\n renderDuration: Math.round(duration),\n resourceCount: Object.keys(baseData).length,\n status: 'success',\n reason: 'full',\n written: false,\n };\n } catch (error) {\n const duration = performance.now() - startTime;\n return {\n path: url,\n filePath: getOutputFilePath(url),\n html: '',\n fileSize: 0,\n renderDuration: Math.round(duration),\n resourceCount: Object.keys(baseData).length,\n status: 'error',\n reason: 'full',\n written: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n };\n\n const worker = async () => {\n while (true) {\n const current = nextIndex;\n nextIndex += 1;\n if (current >= routes.length) return;\n results[current] = await renderOne(routes[current]);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n return results;\n}\n"],"mappings":";;;;;;;;;AAoBA,eAAsB,kBACpB,QACA,UAA8B,EAAE,EACF;CAC9B,MAAM,EAAE,OAAO,OAAO,UAAU,EAAE,EAAE,cAAc,MAAM;CAExD,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,aAAa,OAAO,UAAU,EAAE,CAAC;CAC1E,MAAM,UAA+B,EAAE;CACvC,QAAQ,SAAS,OAAO;CACxB,IAAI,YAAY;CAEhB,MAAM,YAAY,OAAO,UAAmD;EAC1E,MAAM,YAAY,YAAY,KAAK;EACnC,MAAM,MAAM,qBAAqB,MAAM,MAAM,MAAM,OAAO;EAC1D,MAAM,WAAW,QAAQ,MAAM,SAAS,QAAQ,QAAQ,EAAE;EAE1D,MAAM,gBAA8B,MAAM,UACtC,MAAM,WACL,QAAQ,QAAkB;GACzB,MAAM,YAAY,MAAM;GACxB,OAAO,UACL;IAAE,GAAG,MAAM;IAAO,GAAG;IAAQ,EAC7B,IACD;;EAGP,IAAI;GAOF,MAAM,OAAO,2BAA2B;IACtC;IACA,QAAQ,CAAC;KAPT,MAAM,MAAM;KACZ,SAAS;KACT,WAAW,MAAM;KAKR,CAAW;IACpB,SAAS;IACT,QAAQ,MAAM;IACd,SAAS;KACP;KACA,MAAM;KACP;IACF,CAAC;GAEF,MAAM,WAAW,YAAY,KAAK,GAAG;GACrC,OAAO;IACL,MAAM;IACN,UAAU,kBAAkB,IAAI;IAChC;IACA,UAAU,OAAO,WAAW,MAAM,OAAO;IACzC,gBAAgB,KAAK,MAAM,SAAS;IACpC,eAAe,OAAO,KAAK,SAAS,CAAC;IACrC,QAAQ;IACR,QAAQ;IACR,SAAS;IACV;WACM,OAAO;GACd,MAAM,WAAW,YAAY,KAAK,GAAG;GACrC,OAAO;IACL,MAAM;IACN,UAAU,kBAAkB,IAAI;IAChC,MAAM;IACN,UAAU;IACV,gBAAgB,KAAK,MAAM,SAAS;IACpC,eAAe,OAAO,KAAK,SAAS,CAAC;IACrC,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D;;;CAIL,MAAM,SAAS,YAAY;EACzB,OAAO,MAAM;GACX,MAAM,UAAU;GAChB,aAAa;GACb,IAAI,WAAW,OAAO,QAAQ;GAC9B,QAAQ,WAAW,MAAM,UAAU,OAAO,SAAS;;;CAIvD,MAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,aAAa,QAAQ,QAAQ,CAAC,CAAC;CACtE,OAAO"}