@askrjs/askr 0.3.0 → 0.4.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +874 -0
  2. package/README.md +61 -29
  3. package/capabilities.json +19 -9
  4. package/dist/actions/index.js +56 -12
  5. package/dist/benchmark.js +10 -15
  6. package/dist/boot/index.d.ts +3 -2
  7. package/dist/boot/index.js +1 -1
  8. package/dist/boot-DaoTYoCw.js +3989 -0
  9. package/dist/browser-activity-CB8e-V4f.js +220 -0
  10. package/dist/components/index.d.ts +8 -1
  11. package/dist/components/index.js +1 -43
  12. package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
  13. package/dist/control/index.d.ts +2 -0
  14. package/dist/control/index.js +1 -1
  15. package/dist/control-nfpT2fbK.js +209 -0
  16. package/dist/core.d.ts +5 -9
  17. package/dist/csp-nonce-DwGw1A6Q.js +35 -0
  18. package/dist/data/index.js +3 -3
  19. package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
  20. package/dist/data-runtime-C1bFAlba.js +242 -0
  21. package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
  22. package/dist/domains/actions.d.ts +8 -3
  23. package/dist/domains/component.d.ts +1 -107
  24. package/dist/domains/context.d.ts +0 -15
  25. package/dist/domains/control.d.ts +36 -249
  26. package/dist/domains/data.d.ts +31 -13
  27. package/dist/domains/diagnostics.d.ts +1 -2
  28. package/dist/domains/lifecycle.d.ts +2 -5
  29. package/dist/domains/refs.d.ts +0 -2
  30. package/dist/domains/routing.d.ts +43 -8
  31. package/dist/domains/scheduler.d.ts +1 -76
  32. package/dist/domains/server.d.ts +5 -2
  33. package/dist/domains/state.d.ts +2 -5
  34. package/dist/domains/telemetry.d.ts +0 -2
  35. package/dist/elements.d.ts +214 -51
  36. package/dist/error-boundary-Bpwofwps.js +293 -0
  37. package/dist/foundations/icon/index.d.ts +0 -58
  38. package/dist/foundations/icon/index.js +2 -2
  39. package/dist/foundations/index.js +2 -1
  40. package/dist/foundations/interactions/index.js +1 -1
  41. package/dist/foundations/state/index.d.ts +3 -3
  42. package/dist/foundations/state/index.js +5 -3
  43. package/dist/foundations/structures/index.js +2 -1
  44. package/dist/foundations/utilities/index.d.ts +2 -0
  45. package/dist/foundations/utilities/index.js +1 -2
  46. package/dist/fx/index.d.ts +31 -58
  47. package/dist/fx/index.js +313 -195
  48. package/dist/hooks-BimKStr4.js +202 -0
  49. package/dist/index.d.ts +11 -74
  50. package/dist/index.js +8 -447
  51. package/dist/instance-BAnfmXOR.js +988 -0
  52. package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
  53. package/dist/jsx-dev-runtime.d.ts +41 -18
  54. package/dist/jsx-dev-runtime.js +1 -6
  55. package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
  56. package/dist/jsx-runtime.js +1 -1
  57. package/dist/jsx.d.ts +61 -37
  58. package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
  59. package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
  60. package/dist/navigation.d.ts +12 -3
  61. package/dist/peer-types.d.ts +8 -0
  62. package/dist/portal-DuOKfnLa.js +349 -0
  63. package/dist/promise-Dz8iIHAm.js +16 -0
  64. package/dist/query-registry-WMCN0BJL.js +320 -0
  65. package/dist/readable-DFWOsTac.js +21 -0
  66. package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
  67. package/dist/render-sync-IC5lMFpq.js +1240 -0
  68. package/dist/resolution-Cx82-xjW.js +1244 -0
  69. package/dist/resource-CLjB7RBQ.js +377 -0
  70. package/dist/resources/index.d.ts +21 -11
  71. package/dist/resources/index.js +45 -244
  72. package/dist/router/index.d.ts +14 -5
  73. package/dist/router/index.js +22 -53
  74. package/dist/scope-CwpVSHVf.js +55 -0
  75. package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
  76. package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
  77. package/dist/ssg/index.d.ts +1 -2
  78. package/dist/ssg/index.js +5 -13
  79. package/dist/ssr/index.d.ts +26 -28
  80. package/dist/ssr/index.js +4 -4
  81. package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
  82. package/dist/ssr-DoV-vJ-5.js +229 -0
  83. package/dist/state-DWO1KzkX.js +232 -0
  84. package/dist/structures-D4dDMqHX.js +231 -0
  85. package/dist/testing/index.d.ts +8 -4
  86. package/dist/testing/index.js +29 -34
  87. package/dist/url-CnbfpX0K.js +185 -0
  88. package/dist/utilities.d.ts +48 -2
  89. package/dist/verify-hydration-DpVaDnqz.js +152 -0
  90. package/package.json +19 -9
  91. package/dist/access-CEA2pOry.js +0 -1046
  92. package/dist/activity-oy2YFTFF.js +0 -201
  93. package/dist/boot-BMBMWUGI.js +0 -1084
  94. package/dist/capabilities-Bbf0mlp9.js +0 -42
  95. package/dist/compose-ref-v0qGlHoN.js +0 -26
  96. package/dist/control-BR_mrX__.js +0 -173
  97. package/dist/control-C-ApnFs1.js +0 -20
  98. package/dist/csp-nonce-BfFWcd0w.js +0 -173
  99. package/dist/data-runtime-CxoY98lX.js +0 -149
  100. package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
  101. package/dist/dom-renderer.d.ts +0 -77
  102. package/dist/domains/renderer.d.ts +0 -127
  103. package/dist/eager-control.d.ts +0 -8
  104. package/dist/effect-C3Zsc1k6.js +0 -292
  105. package/dist/for-state-BDykeOJL.js +0 -1753
  106. package/dist/instance-VAFYVJOa.js +0 -1027
  107. package/dist/notify-DxxuDPeY.js +0 -266
  108. package/dist/portal-w3oQ6oQU.js +0 -29
  109. package/dist/query-registry-LrYpQsDJ.js +0 -83
  110. package/dist/render-resolved-BC0W7_5b.js +0 -1123
  111. package/dist/renderer-CT0HeY58.js +0 -8623
  112. package/dist/resolution-3DskUkjG.js +0 -577
  113. package/dist/resource-18-sFRl9.js +0 -344
  114. package/dist/route-matching-CUzZ31gT.js +0 -551
  115. package/dist/router-internal-7nuNEHfG.js +0 -36
  116. package/dist/scope-Cq_iYbTR.js +0 -403
  117. package/dist/selector-BSPVkjKP.js +0 -311
  118. package/dist/ssr-EPjwJH5R.js +0 -29
  119. package/dist/state-BXJfudq1.js +0 -91
  120. package/dist/structures-CjEzfj4h.js +0 -654
  121. package/dist/timer-C7uqnJVt.js +0 -85
  122. package/dist/verify-hydration-ikaxotf7.js +0 -27
  123. package/dist/vnode-D24p6IW2.js +0 -7
@@ -1,311 +0,0 @@
1
- import { b as ScheduledWork, f as requestRuntimeWork } from "./access-CEA2pOry.js";
2
- import { O as ownCleanup, f as getCurrentComponentInstance, i as claimHookIndex } from "./scope-Cq_iYbTR.js";
3
- import { _ as markReadableUsage, b as syncDerivedDependencySubscriptions, h as clearDerivedDependencySubscriptions, t as notifyReadableSource, v as recordReadableRead, x as withDerivedReadTracking } from "./notify-DxxuDPeY.js";
4
- //#region src/runtime/reactivity/selector-store.ts
5
- const dirtySelectorRecords = /* @__PURE__ */ new Set();
6
- let selectorWork;
7
- function markDirtySelectorRecord(record, flush) {
8
- record._dirty = true;
9
- if (!record._pending) {
10
- record._pending = true;
11
- dirtySelectorRecords.add(record);
12
- }
13
- requestRuntimeWork("derived", selectorWork ??= new ScheduledWork(flush));
14
- }
15
- function takeDirtySelectorRecords() {
16
- if (dirtySelectorRecords.size === 0) return [];
17
- const pending = Array.from(dirtySelectorRecords);
18
- dirtySelectorRecords.clear();
19
- return pending;
20
- }
21
- //#endregion
22
- //#region src/runtime/reactivity/selector.ts
23
- const selectorCells = /* @__PURE__ */ new WeakMap();
24
- const selectorRecords = /* @__PURE__ */ new WeakMap();
25
- function getSelectorStore(instance) {
26
- const generation = instance.owner.identity;
27
- let store = selectorCells.get(generation);
28
- if (!store) {
29
- store = /* @__PURE__ */ new Map();
30
- selectorCells.set(generation, store);
31
- }
32
- return store;
33
- }
34
- function markSelectorRecordDirty(record) {
35
- markDirtySelectorRecord(record, flushDirtySelectorRecords);
36
- }
37
- function flushDirtySelectorRecords() {
38
- let failures = null;
39
- for (const record of takeDirtySelectorRecords()) {
40
- record._pending = false;
41
- if (!record._dirty) continue;
42
- try {
43
- recomputeSelectorSourceRecord(record, true);
44
- } catch (error) {
45
- (failures ??= []).push(error);
46
- }
47
- }
48
- if (failures?.length === 1) throw failures[0];
49
- if (failures && failures.length > 1) throw new AggregateError(failures, "selector() recompute failures");
50
- }
51
- function isObjectCandidate(value) {
52
- return typeof value === "object" && value !== null || typeof value === "function";
53
- }
54
- function isDefaultSelectorEquals(equals) {
55
- return equals === Object.is;
56
- }
57
- function createCandidateSource(candidate) {
58
- return { _candidate: candidate };
59
- }
60
- function getCandidateSource(lane, candidate) {
61
- if (isObjectCandidate(candidate)) {
62
- const cached = lane._objectCandidates.get(candidate);
63
- if (cached) return cached;
64
- const created = createCandidateSource(candidate);
65
- lane._objectCandidates.set(candidate, created);
66
- lane._objectCandidateSources.add(created);
67
- return created;
68
- }
69
- const key = candidate;
70
- const cached = lane._primitiveCandidates.get(key);
71
- if (cached) return cached;
72
- const created = createCandidateSource(candidate);
73
- lane._primitiveCandidates.set(key, created);
74
- return created;
75
- }
76
- function peekCandidateSource(lane, candidate) {
77
- if (isObjectCandidate(candidate)) return lane._objectCandidates.get(candidate);
78
- return lane._primitiveCandidates.get(candidate);
79
- }
80
- function getSelectorSourceRecord(source) {
81
- const cached = selectorRecords.get(source);
82
- if (cached) return cached;
83
- const record = createSelectorSourceRecord(source);
84
- selectorRecords.set(source, record);
85
- return record;
86
- }
87
- function createSelectorSourceRecord(source) {
88
- let record;
89
- record = {
90
- _source: source,
91
- _value: void 0,
92
- _hasValue: false,
93
- _dirty: true,
94
- _pending: false,
95
- _evaluating: false,
96
- _sources: /* @__PURE__ */ new Set(),
97
- _lanes: /* @__PURE__ */ new Map(),
98
- _markDirty: () => {
99
- markSelectorRecordDirty(record);
100
- },
101
- _cleanup: () => {
102
- record._pending = false;
103
- record._dirty = false;
104
- record._hasValue = false;
105
- record._evaluating = false;
106
- record._pendingDependencySources = void 0;
107
- clearDerivedDependencySubscriptions(record, record._sources);
108
- record._lanes.clear();
109
- selectorRecords.delete(source);
110
- }
111
- };
112
- return record;
113
- }
114
- function getSelectorLane(record, equals) {
115
- const cached = record._lanes.get(equals);
116
- if (cached) return cached;
117
- const lane = createSelectorLane(record, equals);
118
- record._lanes.set(equals, lane);
119
- return lane;
120
- }
121
- function createSelectorLane(record, equals) {
122
- const lane = {
123
- _record: record,
124
- _equals: equals,
125
- _bindingCount: 0,
126
- _primitiveCandidates: /* @__PURE__ */ new Map(),
127
- _objectCandidates: /* @__PURE__ */ new WeakMap(),
128
- _objectCandidateSources: /* @__PURE__ */ new Set(),
129
- _cleanup: () => {
130
- for (const sourceRef of lane._primitiveCandidates.values()) {
131
- sourceRef._readers?.size;
132
- sourceRef._readers?.clear();
133
- sourceRef._derivedSubscribers?.clear();
134
- }
135
- for (const sourceRef of lane._objectCandidateSources) {
136
- sourceRef._readers?.size;
137
- sourceRef._readers?.clear();
138
- sourceRef._derivedSubscribers?.clear();
139
- }
140
- lane._primitiveCandidates.clear();
141
- lane._objectCandidates = /* @__PURE__ */ new WeakMap();
142
- lane._objectCandidateSources.clear();
143
- }
144
- };
145
- return lane;
146
- }
147
- function notifySelectorSource(source) {
148
- notifyReadableSource(source, { skipCurrentDerivedSubscriber: true });
149
- }
150
- function notifyAllSelectorSources(lane) {
151
- for (const source of lane._primitiveCandidates.values()) notifySelectorSource(source);
152
- for (const source of lane._objectCandidateSources) notifySelectorSource(source);
153
- }
154
- function notifySelectorLaneValueChange(lane, prevValue, nextValue) {
155
- if (!lane._bindingCount) return;
156
- if (!isDefaultSelectorEquals(lane._equals)) {
157
- if (lane._equals(prevValue, nextValue)) return;
158
- notifyAllSelectorSources(lane);
159
- return;
160
- }
161
- if (!Object.is(prevValue, nextValue)) {
162
- const prevSource = peekCandidateSource(lane, prevValue);
163
- if (prevSource) notifySelectorSource(prevSource);
164
- const nextSource = peekCandidateSource(lane, nextValue);
165
- if (nextSource) notifySelectorSource(nextSource);
166
- }
167
- }
168
- function recomputeSelectorSourceRecord(record, notifyDownstream) {
169
- if (record._evaluating) throw new Error("selector() cannot read itself recursively");
170
- if (!record._dirty && record._hasValue) return record._value;
171
- record._evaluating = true;
172
- record._dirty = false;
173
- record._pendingDependencySources = /* @__PURE__ */ new Set();
174
- const prevSources = record._sources;
175
- const hadValue = record._hasValue;
176
- const prevValue = record._value;
177
- let nextValue;
178
- try {
179
- nextValue = withDerivedReadTracking(record, record._source);
180
- } catch (error) {
181
- record._dirty = true;
182
- record._pendingDependencySources = void 0;
183
- throw error;
184
- } finally {
185
- record._evaluating = false;
186
- }
187
- const nextSources = record._pendingDependencySources ?? /* @__PURE__ */ new Set();
188
- record._pendingDependencySources = void 0;
189
- syncDerivedDependencySubscriptions(record, prevSources, nextSources);
190
- record._sources = nextSources;
191
- const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);
192
- record._hasValue = true;
193
- record._value = nextValue;
194
- if (valueChanged && notifyDownstream && hadValue) for (const lane of Array.from(record._lanes.values())) notifySelectorLaneValueChange(lane, prevValue, nextValue);
195
- return record._value;
196
- }
197
- function attachSelectorHookBinding(hook, source, equals) {
198
- const record = getSelectorSourceRecord(source);
199
- const lane = getSelectorLane(record, equals);
200
- hook._source = source;
201
- hook._equals = equals;
202
- hook._record = record;
203
- hook._lane = lane;
204
- lane._bindingCount += 1;
205
- }
206
- function detachSelectorHookBinding(hook) {
207
- const record = hook._record;
208
- const lane = hook._lane;
209
- hook._record = null;
210
- hook._lane = null;
211
- if (!record || !lane) return;
212
- if (lane._bindingCount > 0) lane._bindingCount -= 1;
213
- if (lane._bindingCount > 0) return;
214
- lane._cleanup();
215
- record._lanes.delete(lane._equals);
216
- if (record._lanes.size === 0) record._cleanup();
217
- }
218
- function ensureSelectorHookBinding(hook) {
219
- const record = hook._record;
220
- const lane = hook._lane;
221
- if (record && lane && lane._bindingCount > 0 && record._lanes.get(hook._equals) === lane && record._source === hook._source) return record;
222
- if (hook._record || hook._lane) detachSelectorHookBinding(hook);
223
- attachSelectorHookBinding(hook, hook._source, hook._equals);
224
- return hook._record;
225
- }
226
- function createSelectorHook(instance, generation, store, hookIndex, source, equals) {
227
- const hook = function selectorPredicate(candidate) {
228
- const selectorHook = hook;
229
- if (!selectorHook._active) return selectorHook._hasDisposedValue && selectorHook._equals(selectorHook._disposedValue, candidate);
230
- const record = selectorHook._record ?? ensureSelectorHookBinding(selectorHook);
231
- const lane = selectorHook._lane;
232
- if (!lane) throw new Error("selector() binding could not be established.");
233
- const sourceRef = getCandidateSource(lane, candidate);
234
- recordReadableRead(sourceRef);
235
- if (record._evaluating) throw new Error("selector() cannot read itself recursively");
236
- const current = record._dirty || !record._hasValue ? recomputeSelectorSourceRecord(record, record._pending) : record._value;
237
- return lane._equals(current, candidate);
238
- };
239
- hook._owner = instance;
240
- hook._hookIndex = hookIndex;
241
- hook._source = source;
242
- hook._equals = equals;
243
- hook._record = null;
244
- hook._lane = null;
245
- hook._active = true;
246
- hook._disposedValue = void 0;
247
- hook._hasDisposedValue = false;
248
- hook._cleanup = () => {
249
- if (!hook._active) return;
250
- if (hook._record?._hasValue) {
251
- hook._disposedValue = hook._record._value;
252
- hook._hasDisposedValue = true;
253
- }
254
- hook._active = false;
255
- detachSelectorHookBinding(hook);
256
- };
257
- attachSelectorHookBinding(hook, source, equals);
258
- ownCleanup(instance.owner, () => {
259
- try {
260
- hook._cleanup();
261
- } finally {
262
- store.delete(hookIndex);
263
- if (store.size === 0 && selectorCells.get(generation) === store) selectorCells.delete(generation);
264
- }
265
- });
266
- return hook;
267
- }
268
- function getOrCreateSelectorHook(instance, hookIndex, source, equals) {
269
- const store = getSelectorStore(instance);
270
- const existing = store.get(hookIndex);
271
- if (existing) {
272
- if (existing._source !== source || existing._equals !== equals) {
273
- if (existing._equals === equals && existing._record && existing._lane) {
274
- const record = existing._record;
275
- selectorRecords.delete(record._source);
276
- record._source = source;
277
- selectorRecords.set(source, record);
278
- existing._source = source;
279
- record._dirty = true;
280
- recomputeSelectorSourceRecord(record, false);
281
- ensureSelectorHookBinding(existing);
282
- } else {
283
- detachSelectorHookBinding(existing);
284
- attachSelectorHookBinding(existing, source, equals);
285
- }
286
- } else ensureSelectorHookBinding(existing);
287
- return existing;
288
- }
289
- const created = createSelectorHook(instance, instance.owner.identity, store, hookIndex, source, equals);
290
- store.set(hookIndex, created);
291
- return created;
292
- }
293
- /**
294
- * Creates a render-scoped predicate for keyed membership in reactive list rows.
295
- *
296
- * Use this when a `<For>` child needs to compare each stable item with a
297
- * changing selected value. Unlike a plain closure capture, the predicate
298
- * subscribes the affected rows and updates them without rebuilding the list.
299
- * Must be called during component render.
300
- */
301
- function selector(source, equals = Object.is) {
302
- markReadableUsage(source);
303
- const instance = getCurrentComponentInstance();
304
- 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.");
305
- const hook = getOrCreateSelectorHook(instance, claimHookIndex(instance, "selector"), source, equals);
306
- if (!hook._record) throw new Error("selector() record binding was not established.");
307
- if (!hook._record._hasValue) recomputeSelectorSourceRecord(hook._record, false);
308
- return hook;
309
- }
310
- //#endregion
311
- export { selector as t };
@@ -1,29 +0,0 @@
1
- import { P as isPromiseLike } from "./instance-VAFYVJOa.js";
2
- //#region src/common/ssr.ts
3
- /**
4
- * Common call contracts: SSR types
5
- */
6
- function escapedStyleRawText(value) {
7
- return value.replace(/<\//gi, "<\\/");
8
- }
9
- function validateDocumentStyleRegistrations(html, styles, apiName, validation) {
10
- if (validation === "off" || !styles || styles.length === 0) return;
11
- const dropped = styles.filter(({ cssText }) => !html.includes(cssText) && !html.includes(escapedStyleRawText(cssText)));
12
- if (dropped.length === 0) return;
13
- const registrations = dropped.map(({ id }) => JSON.stringify(id)).join(", ");
14
- const message = `${apiName} document() dropped ${dropped.length} registered SSR style${dropped.length === 1 ? "" : "s"}: ${registrations}. Serialize context.styles into the returned document, or set styleRegistrationValidation to "off" when omission is intentional.`;
15
- if (validation === "error") throw new Error(message);
16
- console.warn(message);
17
- }
18
- function renderDocument(document, args, apiName, styleRegistrationValidation = "warn") {
19
- const html = document(args);
20
- if (typeof html !== "string") {
21
- const received = isPromiseLike(html) ? "a Promise-like value" : html === null ? "null" : Array.isArray(html) ? "an array" : typeof html;
22
- throw new Error(`${apiName} document() must synchronously return a string; received ${received}.`);
23
- }
24
- validateDocumentStyleRegistrations(html, args.context.styles, apiName, styleRegistrationValidation);
25
- return html;
26
- }
27
- const SSR_RENDER_DATA_ATTR = "data-askr-render-data";
28
- //#endregion
29
- export { renderDocument as n, SSR_RENDER_DATA_ATTR as t };
@@ -1,91 +0,0 @@
1
- import { T as isProductionEnvironment } from "./access-CEA2pOry.js";
2
- import { f as getCurrentComponentInstance, i as claimHookIndex } from "./scope-Cq_iYbTR.js";
3
- import { a as deferCommitNotification, t as notifyReadableSource, v as recordReadableRead } from "./notify-DxxuDPeY.js";
4
- //#region src/runtime/reactivity/state.ts
5
- /**
6
- * State primitive for Askr components
7
- * Optimized for minimal overhead and fast updates
8
- *
9
- * INVARIANTS ENFORCED:
10
- * - state() only callable during component render (currentInstance exists)
11
- * - state() called at top-level only (indices must be monotonically increasing)
12
- * - state values persist across re-renders (stored in stateValues array)
13
- * - state.set() cannot be called during render (causes infinite loops)
14
- * - state.set() always enqueues through scheduler (never direct mutation)
15
- * - state.set() callback (notifyUpdate) always available
16
- */
17
- /**
18
- * Creates a local state value for a component
19
- * Optimized for:
20
- * - O(1) read performance
21
- * - Minimal allocation per state
22
- * - Fast scheduler integration
23
- *
24
- * IMPORTANT: state() must be called during component render execution.
25
- * It captures the current component instance from context.
26
- * Calling outside a component function will throw an error.
27
- *
28
- * @example
29
- * ```ts
30
- * // ✅ Correct: called during render
31
- * export function Counter() {
32
- * const [count, setCount] = state(0);
33
- * return { type: 'button', children: [count()] };
34
- * }
35
- *
36
- * // ❌ Wrong: called outside component
37
- * const count = state(0);
38
- * export function BadComponent() {
39
- * return { type: 'div' };
40
- * }
41
- * ```
42
- */
43
- function state(initialValue) {
44
- const instance = getCurrentComponentInstance();
45
- if (!instance) throw new Error("state() can only be called during component render execution. Move state() calls to the top level of your component function.");
46
- const index = claimHookIndex(instance, "state");
47
- const stateValues = instance.stateValues ??= [];
48
- if (stateValues[index]) {
49
- const existing = stateValues[index];
50
- if (existing._owner !== instance) throw new Error(`State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`);
51
- return existing;
52
- }
53
- const cell = createStateCell(initialValue, instance);
54
- stateValues[index] = cell;
55
- return cell;
56
- }
57
- /**
58
- * Internal helper: create the backing state cell (value + readers + set semantics)
59
- * This extraction makes it easier to later split hook wiring from storage.
60
- */
61
- function createStateCell(initialValue, instance) {
62
- let value = initialValue;
63
- const readers = /* @__PURE__ */ new Map();
64
- function read() {
65
- read._hasBeenRead = true;
66
- recordReadableRead(read);
67
- return value;
68
- }
69
- read._readers = readers;
70
- read._unusedStateDiagnosticEligible = !isProductionEnvironment();
71
- read._owner = instance;
72
- read.set = (newValueOrUpdater) => {
73
- if (getCurrentComponentInstance() !== null) throw new Error("[Askr] state.set() cannot be called during component render. State mutations during render break the actor model and cause infinite loops. Move state updates to event handlers or use conditional rendering instead.");
74
- let newValue;
75
- if (typeof newValueOrUpdater === "function") newValue = newValueOrUpdater(value);
76
- else newValue = newValueOrUpdater;
77
- if (Object.is(value, newValue)) return;
78
- value = newValue;
79
- if (!deferCommitNotification(read, notify)) notify();
80
- };
81
- function notify() {
82
- notifyReadableSource(read);
83
- }
84
- read[Symbol.iterator] = function* () {
85
- yield read;
86
- yield read.set;
87
- };
88
- return read;
89
- }
90
- //#endregion
91
- export { state as t };