@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
@@ -0,0 +1,988 @@
1
+ //#region src/common/env.ts
2
+ function normalizeEnvValue(value) {
3
+ if (typeof value === "string") return value;
4
+ if (typeof value === "boolean" || typeof value === "number") return String(value);
5
+ }
6
+ function getBuildTimeMetaEnv() {
7
+ return import.meta.env;
8
+ }
9
+ function getBuildTimeNodeEnv(metaEnv) {
10
+ const nodeEnv = normalizeEnvValue(metaEnv?.NODE_ENV);
11
+ if (nodeEnv != null || !metaEnv) return nodeEnv;
12
+ if (typeof metaEnv.MODE === "string" && metaEnv.MODE.length > 0) return metaEnv.MODE;
13
+ if (metaEnv.PROD === true || metaEnv.PROD === "true") return "production";
14
+ if (metaEnv.DEV === true || metaEnv.DEV === "true") return "development";
15
+ }
16
+ function resolveNodeEnv(processNodeEnv, buildNodeEnv) {
17
+ if (buildNodeEnv === "production") return "production";
18
+ if (processNodeEnv != null) return processNodeEnv;
19
+ if (buildNodeEnv === "development") return "development";
20
+ return buildNodeEnv === "test" ? void 0 : buildNodeEnv;
21
+ }
22
+ /**
23
+ * Resolves one environment variable. Build-time values (`import.meta.env`)
24
+ * take precedence over `process.env`, except that `NODE_ENV` follows
25
+ * `resolveNodeEnv`. Only the requested variable is read: enumerating
26
+ * `process.env` is costly on some hosts (every enumeration copies the
27
+ * environment block on Windows), and these checks run on hot paths such as
28
+ * every component render.
29
+ */
30
+ function getRuntimeEnvValue(name) {
31
+ const processValue = globalThis.process?.env?.[name];
32
+ const metaEnv = getBuildTimeMetaEnv();
33
+ if (name === "NODE_ENV") return resolveNodeEnv(processValue, getBuildTimeNodeEnv(metaEnv));
34
+ return normalizeEnvValue(metaEnv?.[name]) ?? processValue;
35
+ }
36
+ function isProductionEnvironment() {
37
+ return getRuntimeEnvValue("NODE_ENV") === "production";
38
+ }
39
+ function isDevelopmentEnvironment() {
40
+ return !isProductionEnvironment();
41
+ }
42
+ //#endregion
43
+ //#region src/common/logger.ts
44
+ /**
45
+ * Shared logger interface for runtime and tooling code.
46
+ *
47
+ * Debug, info, and warn stay silent in production. Errors always log.
48
+ */
49
+ function callConsole(method, args) {
50
+ const c = typeof console !== "undefined" ? console : void 0;
51
+ if (!c) return;
52
+ const fn = c[method];
53
+ if (typeof fn === "function") try {
54
+ fn.apply(console, args);
55
+ } catch {}
56
+ }
57
+ const logger = {
58
+ debug: (...args) => {
59
+ if (isProductionEnvironment()) return;
60
+ callConsole("debug", args);
61
+ },
62
+ info: (...args) => {
63
+ if (isProductionEnvironment()) return;
64
+ callConsole("info", args);
65
+ },
66
+ warn: (...args) => {
67
+ if (isProductionEnvironment()) return;
68
+ callConsole("warn", args);
69
+ },
70
+ error: (...args) => {
71
+ callConsole("error", args);
72
+ }
73
+ };
74
+ //#endregion
75
+ //#region src/core/component/diagnostics.ts
76
+ let settings = {
77
+ slowRenderWarnings: true,
78
+ slowRenderThresholdMs: 5
79
+ };
80
+ /** Configure render diagnostics; returns a function restoring the previous settings. */
81
+ function configureRenderDiagnostics(options) {
82
+ const threshold = options.slowRenderThresholdMs;
83
+ if (threshold !== void 0 && (!Number.isFinite(threshold) || threshold < 0)) throw new TypeError("configureRenderDiagnostics slowRenderThresholdMs must be a finite, non-negative number.");
84
+ const previous = settings;
85
+ settings = {
86
+ slowRenderWarnings: options.slowRenderWarnings ?? previous.slowRenderWarnings,
87
+ slowRenderThresholdMs: threshold ?? previous.slowRenderThresholdMs
88
+ };
89
+ let restored = false;
90
+ return () => {
91
+ if (restored) return;
92
+ restored = true;
93
+ settings = previous;
94
+ };
95
+ }
96
+ const warned = /* @__PURE__ */ new WeakSet();
97
+ function isTimingRenders() {
98
+ return false;
99
+ }
100
+ function reportRenderTime(instance, name, milliseconds) {
101
+ if (milliseconds <= settings.slowRenderThresholdMs || warned.has(instance)) return;
102
+ warned.add(instance);
103
+ logger.warn(`[askr] Slow render detected in ${name}: ${milliseconds}ms. Consider optimizing component performance.`);
104
+ }
105
+ //#endregion
106
+ //#region src/core/reactive/owner.ts
107
+ var Owner = class {
108
+ constructor(parent) {
109
+ this.owned = null;
110
+ this.ownedHoles = 0;
111
+ this.ownedIndex = -1;
112
+ this.cleanups = null;
113
+ this.context = null;
114
+ this.disposed = false;
115
+ this.parent = parent;
116
+ if (parent) {
117
+ const owned = parent.owned ??= [];
118
+ this.ownedIndex = owned.length;
119
+ owned.push(this);
120
+ }
121
+ }
122
+ onCleanup(fn) {
123
+ if (this.disposed) {
124
+ fn();
125
+ return;
126
+ }
127
+ (this.cleanups ??= []).push(fn);
128
+ }
129
+ lookup(key) {
130
+ if (this.context?.has(key)) return this.context.get(key);
131
+ for (let owner = this.parent; owner; owner = owner.parent) if (owner.context?.has(key)) return owner.context.get(key);
132
+ }
133
+ /** Detach from the parent without disposing (the caller disposes). */
134
+ detach() {
135
+ const parent = this.parent;
136
+ const siblings = parent?.owned;
137
+ if (parent && siblings && siblings[this.ownedIndex] === this) {
138
+ if (this.ownedIndex === siblings.length - 1) {
139
+ siblings.pop();
140
+ while (siblings.length && siblings[siblings.length - 1] === null) {
141
+ siblings.pop();
142
+ parent.ownedHoles--;
143
+ }
144
+ } else {
145
+ siblings[this.ownedIndex] = null;
146
+ parent.ownedHoles++;
147
+ if (parent.ownedHoles > 16 && parent.ownedHoles * 2 > siblings.length) compactOwned(parent, siblings);
148
+ }
149
+ }
150
+ this.parent = null;
151
+ this.ownedIndex = -1;
152
+ }
153
+ /**
154
+ * Dispose this owner and everything it owns. Returns the failures instead of
155
+ * throwing so a caller can decide whether to report or aggregate them.
156
+ */
157
+ dispose(errors = []) {
158
+ if (this.disposed) return errors;
159
+ this.detach();
160
+ disposeTree(this, errors);
161
+ return errors;
162
+ }
163
+ /** Dispose owned children and run cleanups, keeping this owner alive. */
164
+ reset(errors = []) {
165
+ disposeChildren(this, errors);
166
+ runCleanups(this, errors);
167
+ return errors;
168
+ }
169
+ onDispose() {}
170
+ };
171
+ function compactOwned(parent, siblings) {
172
+ let next = 0;
173
+ for (const child of siblings) {
174
+ if (!child) continue;
175
+ child.ownedIndex = next;
176
+ siblings[next++] = child;
177
+ }
178
+ siblings.length = next;
179
+ parent.ownedHoles = 0;
180
+ }
181
+ /** Take `owner`'s children, leaving it with none. */
182
+ function takeOwned(owner) {
183
+ const owned = owner.owned;
184
+ owner.owned = null;
185
+ owner.ownedHoles = 0;
186
+ return owned;
187
+ }
188
+ function disposeChildren(owner, errors) {
189
+ const owned = takeOwned(owner);
190
+ if (!owned) return;
191
+ for (let i = owned.length - 1; i >= 0; i--) {
192
+ const child = owned[i];
193
+ if (!child) continue;
194
+ child.parent = null;
195
+ disposeTree(child, errors);
196
+ }
197
+ }
198
+ function runCleanups(owner, errors) {
199
+ const cleanups = owner.cleanups;
200
+ if (!cleanups) return;
201
+ owner.cleanups = null;
202
+ for (let i = cleanups.length - 1; i >= 0; i--) try {
203
+ cleanups[i]();
204
+ } catch (error) {
205
+ errors.push(error);
206
+ }
207
+ }
208
+ function disposeTree(owner, errors) {
209
+ const pending = [{
210
+ owner,
211
+ finish: false
212
+ }];
213
+ while (pending.length) {
214
+ const frame = pending.pop();
215
+ const current = frame.owner;
216
+ if (frame.finish) {
217
+ runCleanups(current, errors);
218
+ try {
219
+ current.onDispose();
220
+ } catch (error) {
221
+ errors.push(error);
222
+ }
223
+ continue;
224
+ }
225
+ if (frame.detach) current.parent = null;
226
+ if (current.disposed) continue;
227
+ current.disposed = true;
228
+ pending.push({
229
+ owner: current,
230
+ finish: true
231
+ });
232
+ const children = takeOwned(current);
233
+ if (!children) continue;
234
+ for (const child of children) if (child) pending.push({
235
+ owner: child,
236
+ finish: false,
237
+ detach: true
238
+ });
239
+ }
240
+ }
241
+ let currentOwner = null;
242
+ function getOwner() {
243
+ return currentOwner;
244
+ }
245
+ function runWithOwner(owner, fn) {
246
+ const previous = currentOwner;
247
+ currentOwner = owner;
248
+ try {
249
+ return fn();
250
+ } finally {
251
+ currentOwner = previous;
252
+ }
253
+ }
254
+ //#endregion
255
+ //#region src/core/reactive/graph.ts
256
+ /**
257
+ * Reactive graph.
258
+ *
259
+ * Sources hold values; computations derive values or perform effects from
260
+ * the sources they read. A write marks direct observers DIRTY and everything
261
+ * downstream of them CHECK. A computation that is read (or run by the
262
+ * scheduler) first brings its CHECK sources up to date and only re-runs if
263
+ * one of them actually changed, so updates are glitch-free and unchanged
264
+ * derived values cut propagation off.
265
+ *
266
+ * There is one subscriber kind. `derive()`, `selector()`, fine-grained
267
+ * bindings, `watch()`, and component renders are all computations; they
268
+ * differ only in how they are scheduled when they go stale.
269
+ */
270
+ const CLEAN = 0;
271
+ const CHECK = 1;
272
+ const DIRTY = 2;
273
+ function unobserve(source, observer) {
274
+ const observers = source._observers;
275
+ if (!observers?.delete(observer) || observers.size > 0) return;
276
+ source._unobserved?.();
277
+ }
278
+ let tracking = null;
279
+ let trackingSources = null;
280
+ function track(source) {
281
+ if (trackingSources) trackingSources.add(source);
282
+ }
283
+ /** Notify every observer of `source` that its value changed. */
284
+ function notifySource(source, except) {
285
+ const observers = source._observers;
286
+ if (!observers) return;
287
+ for (const observer of observers) if (observer !== except) observer._mark(DIRTY);
288
+ }
289
+ /** Record a read of `source` by the running computation. */
290
+ function trackSource(source) {
291
+ track(source);
292
+ }
293
+ function isTracking() {
294
+ return trackingSources !== null;
295
+ }
296
+ function getTrackingComputation() {
297
+ return tracking;
298
+ }
299
+ function untrack(fn) {
300
+ const previous = tracking;
301
+ const previousSources = trackingSources;
302
+ tracking = null;
303
+ trackingSources = null;
304
+ try {
305
+ return fn();
306
+ } finally {
307
+ tracking = previous;
308
+ trackingSources = previousSources;
309
+ }
310
+ }
311
+ var Signal = class {
312
+ constructor(value, equals = Object.is) {
313
+ this._observers = null;
314
+ this._value = value;
315
+ this._equals = equals;
316
+ }
317
+ read() {
318
+ track(this);
319
+ return this._value;
320
+ }
321
+ peek() {
322
+ return this._value;
323
+ }
324
+ /** Returns true when the value changed and observers were notified. */
325
+ write(value) {
326
+ if (this._equals(this._value, value)) return false;
327
+ this._value = value;
328
+ notifySource(this);
329
+ return true;
330
+ }
331
+ };
332
+ var Computation = class Computation extends Owner {
333
+ constructor(owner, fn, schedule, equals = Object.is, failedRunSources = "union") {
334
+ super(owner);
335
+ this._observers = null;
336
+ this._sources = null;
337
+ this._state = DIRTY;
338
+ this._value = void 0;
339
+ this._error = void 0;
340
+ this._hasError = false;
341
+ this._running = false;
342
+ this._invalidatedWhileRunning = false;
343
+ this._dropped = false;
344
+ this._fn = fn;
345
+ this._schedule = schedule;
346
+ this._equals = equals;
347
+ this._failedRunSources = failedRunSources;
348
+ }
349
+ /** Read the current value, recomputing if a source changed. */
350
+ read() {
351
+ if (this._running) throw new Error("Circular reactive dependency detected.");
352
+ track(this);
353
+ this.update();
354
+ if (this._hasError) throw this._error;
355
+ return this._value;
356
+ }
357
+ get stale() {
358
+ return this._state !== CLEAN;
359
+ }
360
+ /** Bring this computation up to date, running it only if a source changed. */
361
+ update() {
362
+ if (this.disposed) return;
363
+ if (this._state === CHECK) {
364
+ for (const source of this._sources ?? EMPTY) if (source instanceof Computation) {
365
+ source.update();
366
+ if (this._state === DIRTY) break;
367
+ }
368
+ }
369
+ if (this._state === DIRTY) this.run();
370
+ else this._state = CLEAN;
371
+ }
372
+ /** Run unconditionally, tracking the sources read. */
373
+ run() {
374
+ if (this.disposed) return;
375
+ const previous = tracking;
376
+ const previousSources = trackingSources;
377
+ const nextSources = /* @__PURE__ */ new Set();
378
+ tracking = this;
379
+ trackingSources = nextSources;
380
+ this._running = true;
381
+ this._invalidatedWhileRunning = false;
382
+ this._dropped = false;
383
+ let value;
384
+ let error;
385
+ let failed = false;
386
+ try {
387
+ value = this._fn();
388
+ } catch (caught) {
389
+ failed = true;
390
+ error = caught;
391
+ } finally {
392
+ this._running = false;
393
+ tracking = previous;
394
+ trackingSources = previousSources;
395
+ }
396
+ if (this.disposed) return;
397
+ this._state = this._invalidatedWhileRunning ? DIRTY : CLEAN;
398
+ this.setSources(failed && this._failedRunSources === "previous" ? new Set(this._sources ?? EMPTY) : nextSources, failed && this._failedRunSources === "union");
399
+ if (failed) {
400
+ const changed = !this._hasError || this._error !== error;
401
+ this._hasError = true;
402
+ this._error = error;
403
+ this._value = void 0;
404
+ if (changed) this.markObserversDirty();
405
+ if (this._schedule) throw error;
406
+ return;
407
+ }
408
+ const changed = this._hasError || this._equals === null || !this._equals(this._value, value);
409
+ this._hasError = false;
410
+ this._error = void 0;
411
+ this._value = value;
412
+ if (changed) this.markObserversDirty();
413
+ }
414
+ /** Replace the function this computation runs; it runs again on next update. */
415
+ setFn(fn) {
416
+ this._fn = fn;
417
+ this._mark(DIRTY);
418
+ }
419
+ /** Restore subscriptions captured before a discarded component pass. */
420
+ restoreSources(sources) {
421
+ this.setSources(new Set(sources), false);
422
+ }
423
+ /** Force a re-run on the next update, as if a source changed. */
424
+ invalidate() {
425
+ this._mark(DIRTY);
426
+ }
427
+ /** Retry after a later source change, without rerunning a discarded pass. */
428
+ deferRetry() {
429
+ if (this.disposed) return;
430
+ this._state = DIRTY;
431
+ this._dropped = true;
432
+ }
433
+ markObserversDirty() {
434
+ const observers = this._observers;
435
+ if (!observers) return;
436
+ for (const observer of observers) observer._state = DIRTY;
437
+ }
438
+ /**
439
+ * A failed run keeps its previous subscriptions as well, so a change to
440
+ * anything either run read retries it.
441
+ */
442
+ setSources(next, keepPrevious) {
443
+ const previous = this._sources;
444
+ if (previous) {
445
+ for (const source of previous) if (keepPrevious) next.add(source);
446
+ else if (!next.has(source)) unobserve(source, this);
447
+ }
448
+ for (const source of next) (source._observers ??= /* @__PURE__ */ new Set()).add(this);
449
+ this._sources = next.size ? next : null;
450
+ }
451
+ /**
452
+ * The scheduler dropped this computation's pending run (loop guard or
453
+ * clear). It stays stale, and the next change schedules it again.
454
+ */
455
+ dropScheduled() {
456
+ if (!this.disposed && this._state !== CLEAN) this._dropped = true;
457
+ }
458
+ _mark(state) {
459
+ if (this.disposed) return;
460
+ if (this._running && state === DIRTY) {
461
+ const firstInvalidation = !this._invalidatedWhileRunning;
462
+ this._invalidatedWhileRunning = true;
463
+ if (state > this._state) this._state = state;
464
+ this._dropped = false;
465
+ this._schedule?.(this);
466
+ if (firstInvalidation) {
467
+ const observers = this._observers;
468
+ if (observers) for (const observer of observers) observer._mark(CHECK);
469
+ }
470
+ return;
471
+ }
472
+ const dropped = this._dropped;
473
+ if (this._state >= state && !dropped) return;
474
+ const wasClean = this._state === CLEAN;
475
+ if (state > this._state) this._state = state;
476
+ if (!wasClean && !dropped) return;
477
+ this._dropped = false;
478
+ if (this._schedule) this._schedule(this);
479
+ if (!wasClean) return;
480
+ const observers = this._observers;
481
+ if (observers) for (const observer of observers) observer._mark(CHECK);
482
+ }
483
+ onDispose() {
484
+ for (const source of this._sources ?? EMPTY) unobserve(source, this);
485
+ this._sources = null;
486
+ this._observers = null;
487
+ }
488
+ };
489
+ const EMPTY = /* @__PURE__ */ new Set();
490
+ /** FIFO queue with an advancing head, so taking the next job is O(1). */
491
+ var JobQueue = class {
492
+ constructor() {
493
+ this.items = [];
494
+ this.head = 0;
495
+ }
496
+ get length() {
497
+ return this.items.length - this.head;
498
+ }
499
+ push(job) {
500
+ this.items.push(job);
501
+ }
502
+ shift() {
503
+ if (this.head >= this.items.length) return void 0;
504
+ const job = this.items[this.head];
505
+ this.items[this.head++] = void 0;
506
+ if (this.head === this.items.length) {
507
+ this.items.length = 0;
508
+ this.head = 0;
509
+ } else if (this.head > 1024 && this.head * 2 > this.items.length) {
510
+ this.items = this.items.slice(this.head);
511
+ this.head = 0;
512
+ }
513
+ return job;
514
+ }
515
+ clear() {
516
+ this.items.length = 0;
517
+ this.head = 0;
518
+ }
519
+ };
520
+ /**
521
+ * Render lane: a binary min-heap ordered by depth, then by queue order, so the
522
+ * shallowest job runs first and equal depths run in the order they queued.
523
+ */
524
+ var RenderQueue = class {
525
+ constructor() {
526
+ this.heap = [];
527
+ this.seq = 0;
528
+ }
529
+ get length() {
530
+ return this.heap.length;
531
+ }
532
+ push(job) {
533
+ const heap = this.heap;
534
+ const entry = {
535
+ job,
536
+ depth: job.depth ?? 0,
537
+ seq: this.seq++
538
+ };
539
+ let index = heap.push(entry) - 1;
540
+ while (index > 0) {
541
+ const parent = index - 1 >> 1;
542
+ if (!before(entry, heap[parent])) break;
543
+ heap[index] = heap[parent];
544
+ index = parent;
545
+ }
546
+ heap[index] = entry;
547
+ }
548
+ shift() {
549
+ const heap = this.heap;
550
+ if (heap.length === 0) return void 0;
551
+ const top = heap[0];
552
+ const last = heap.pop();
553
+ if (heap.length > 0) {
554
+ let index = 0;
555
+ for (;;) {
556
+ const left = index * 2 + 1;
557
+ if (left >= heap.length) break;
558
+ const right = left + 1;
559
+ const child = right < heap.length && before(heap[right], heap[left]) ? right : left;
560
+ if (!before(heap[child], last)) break;
561
+ heap[index] = heap[child];
562
+ index = child;
563
+ }
564
+ heap[index] = last;
565
+ }
566
+ if (heap.length === 0) this.seq = 0;
567
+ return top.job;
568
+ }
569
+ clear() {
570
+ this.heap.length = 0;
571
+ this.seq = 0;
572
+ }
573
+ };
574
+ function before(a, b) {
575
+ return a.depth < b.depth || a.depth === b.depth && a.seq < b.seq;
576
+ }
577
+ const lanes = {
578
+ render: new RenderQueue(),
579
+ effect: new JobQueue(),
580
+ post: new JobQueue()
581
+ };
582
+ const queued = /* @__PURE__ */ new Set();
583
+ let flushing = false;
584
+ let batchDepth = 0;
585
+ let kickScheduled = false;
586
+ let flushVersion = 0;
587
+ let runCounts = null;
588
+ const flushWaiters = [];
589
+ function schedule(job, lane) {
590
+ if (queued.has(job)) return;
591
+ queued.add(job);
592
+ lanes[lane].push(job);
593
+ kick();
594
+ }
595
+ function queueTask(fn) {
596
+ const owner = getOwner();
597
+ schedule({ run: () => runWithOwner(owner, fn) }, "post");
598
+ }
599
+ const computationJobs = /* @__PURE__ */ new WeakMap();
600
+ /**
601
+ * A scheduler for computations that run as effects: when one goes stale it
602
+ * is queued in `lane` and brought up to date (re-running only if a source
603
+ * actually changed) when the flush reaches it.
604
+ */
605
+ function effectScheduler(lane, depth = 0, onLimit, maxRuns) {
606
+ return (computation) => {
607
+ let job = computationJobs.get(computation);
608
+ if (!job) {
609
+ job = {
610
+ depth,
611
+ run: () => computation.update(),
612
+ cancel: () => computation.dropScheduled(),
613
+ onLimit,
614
+ maxRuns,
615
+ get skip() {
616
+ return computation.disposed;
617
+ }
618
+ };
619
+ computationJobs.set(computation, job);
620
+ }
621
+ schedule(job, lane);
622
+ };
623
+ }
624
+ function isFlushing() {
625
+ return flushing;
626
+ }
627
+ function kick() {
628
+ if (flushing || batchDepth > 0 || kickScheduled) return;
629
+ kickScheduled = true;
630
+ queueMicrotask(() => {
631
+ kickScheduled = false;
632
+ if (!flushing && batchDepth === 0 && queued.size > 0) flushSync();
633
+ });
634
+ }
635
+ /**
636
+ * Run `fn` with scheduling deferred, then flush synchronously when the
637
+ * outermost batch exits. Event handlers run inside a batch.
638
+ */
639
+ function batch(fn) {
640
+ batchDepth++;
641
+ let value;
642
+ let callbackError;
643
+ let callbackFailed = false;
644
+ try {
645
+ value = fn();
646
+ } catch (error) {
647
+ callbackFailed = true;
648
+ callbackError = error;
649
+ }
650
+ batchDepth--;
651
+ let flushError;
652
+ let flushFailed = false;
653
+ if (batchDepth === 0 && !flushing && queued.size > 0) try {
654
+ flushSync();
655
+ } catch (error) {
656
+ flushFailed = true;
657
+ flushError = error;
658
+ }
659
+ if (callbackFailed && flushFailed) throw new AggregateError([callbackError, flushError], "Batch callback and scheduler flush failed");
660
+ if (callbackFailed) throw callbackError;
661
+ if (flushFailed) throw flushError;
662
+ return value;
663
+ }
664
+ function takeNext() {
665
+ return lanes.render.shift() ?? lanes.effect.shift() ?? lanes.post.shift() ?? null;
666
+ }
667
+ /** Drain every queued job now. Nested calls during a flush are no-ops. */
668
+ function flushSync() {
669
+ if (flushing) return;
670
+ flushing = true;
671
+ runCounts = /* @__PURE__ */ new Map();
672
+ const failures = [];
673
+ try {
674
+ for (let job = takeNext(); job; job = takeNext()) {
675
+ queued.delete(job);
676
+ if (job.skip) continue;
677
+ const count = (runCounts.get(job) ?? 0) + 1;
678
+ runCounts.set(job, count);
679
+ if (count > (job.maxRuns ?? 50)) {
680
+ job.cancel?.();
681
+ if (job.onLimit) try {
682
+ job.onLimit();
683
+ } catch (error) {
684
+ failures.push(error);
685
+ }
686
+ else failures.push(/* @__PURE__ */ new Error(`[Askr] exceeded MAX_FLUSH_DEPTH (50): a scheduled update kept re-queueing itself.`));
687
+ continue;
688
+ }
689
+ try {
690
+ job.run();
691
+ } catch (error) {
692
+ failures.push(error);
693
+ }
694
+ }
695
+ } finally {
696
+ flushing = false;
697
+ runCounts = null;
698
+ flushVersion++;
699
+ for (const resolve of flushWaiters.splice(0)) resolve();
700
+ }
701
+ if (failures.length === 1) throw failures[0];
702
+ if (failures.length > 1) throw new AggregateError(failures, "Scheduler flush failed");
703
+ }
704
+ function getFlushVersion() {
705
+ return flushVersion;
706
+ }
707
+ //#endregion
708
+ //#region src/core/component/render-state.ts
709
+ /**
710
+ * Whether a component render or a function child is executing. State writes
711
+ * are rejected while one is, because they would re-trigger the render.
712
+ */
713
+ let renderDepth = 0;
714
+ function isRendering() {
715
+ return renderDepth > 0;
716
+ }
717
+ function withRendering(fn) {
718
+ renderDepth++;
719
+ try {
720
+ return fn();
721
+ } finally {
722
+ renderDepth--;
723
+ }
724
+ }
725
+ /** Run `fn` outside any render (event handlers and lifecycle callbacks). */
726
+ function outsideRendering(fn) {
727
+ const saved = renderDepth;
728
+ renderDepth = 0;
729
+ try {
730
+ return fn();
731
+ } finally {
732
+ renderDepth = saved;
733
+ }
734
+ }
735
+ //#endregion
736
+ //#region src/core/component/journal.ts
737
+ let activeJournal = null;
738
+ function createRenderJournal() {
739
+ return { entries: [] };
740
+ }
741
+ /** Run synchronous render work with `journal` as its undo destination. */
742
+ function withRenderJournal(journal, render) {
743
+ const previous = activeJournal;
744
+ activeJournal = journal;
745
+ try {
746
+ return render();
747
+ } finally {
748
+ activeJournal = previous;
749
+ }
750
+ }
751
+ function recordUndo(undo, journal = activeJournal) {
752
+ journal?.entries.push(undo);
753
+ }
754
+ function journalMark(journal) {
755
+ return journal.entries.length;
756
+ }
757
+ /** Undo everything recorded after `mark`, most recent first. */
758
+ function rewindJournal(journal, mark, errors) {
759
+ while (journal.entries.length > mark) try {
760
+ journal.entries.pop()();
761
+ } catch (error) {
762
+ errors.push(error);
763
+ }
764
+ }
765
+ /** Keep the changes recorded after `mark` (their render committed). */
766
+ function settleJournal(journal, mark) {
767
+ journal.entries.length = Math.min(journal.entries.length, mark);
768
+ }
769
+ //#endregion
770
+ //#region src/core/component/setup.ts
771
+ const definitions = /* @__PURE__ */ new WeakMap();
772
+ function setupDefinitionFor(component) {
773
+ return definitions.get(component);
774
+ }
775
+ //#endregion
776
+ //#region src/core/component/instance.ts
777
+ let renderHost = null;
778
+ let nextContextRevision = 0;
779
+ /** Bumped whenever any instance's `contextRevision` changes or is undone. */
780
+ let contextEpoch = 0;
781
+ /** Current context epoch; cached inherited revisions are valid within one. */
782
+ function getContextEpoch() {
783
+ return contextEpoch;
784
+ }
785
+ function setRenderHost(host) {
786
+ renderHost = host;
787
+ }
788
+ var ComponentInstance = class extends Owner {
789
+ get displayName() {
790
+ return this.name ?? this.fn.name;
791
+ }
792
+ constructor(parent, fn, props, onStale) {
793
+ super(parent);
794
+ this.propsSource = null;
795
+ this.hooks = [];
796
+ this.hookKinds = [];
797
+ this.hookIndex = 0;
798
+ this.name = null;
799
+ this.mounted = false;
800
+ this.renderCount = 0;
801
+ this.commitQueue = null;
802
+ this.commitSyncQueue = null;
803
+ this.abortController = null;
804
+ this.setupRender = null;
805
+ this.setupPhase = null;
806
+ this.view = null;
807
+ this.server = false;
808
+ this.serverResourceKeys = [];
809
+ this.hydrationResourceKeys = null;
810
+ this.hydrationResourceIndex = 0;
811
+ this.serverContext = void 0;
812
+ this.boundary = null;
813
+ this.contextRevision = 0;
814
+ this.seenAncestorContextRevision = 0;
815
+ this.inheritedContextRevision = 0;
816
+ this.inheritedContextEpoch = -1;
817
+ this.fn = fn;
818
+ this.props = props;
819
+ this.setupDefinition = setupDefinitionFor(fn);
820
+ this.depth = depthOf(parent) + 1;
821
+ this.computation = new Computation(this, () => this.invoke(), onStale ?? renderLaneScheduler(this), null, "previous");
822
+ }
823
+ get signal() {
824
+ return (this.abortController ??= new AbortController()).signal;
825
+ }
826
+ /** Run the component function. Called only through `computation`. */
827
+ invoke() {
828
+ const previous = enterInstance(this);
829
+ this.hookIndex = 0;
830
+ this.hydrationResourceIndex = 0;
831
+ if (this.server) this.serverResourceKeys = [];
832
+ this.commitQueue = null;
833
+ this.commitSyncQueue = null;
834
+ try {
835
+ const context = this.server ? {
836
+ signal: this.signal,
837
+ ssr: this.serverContext
838
+ } : { signal: this.signal };
839
+ const started = !this.server && isTimingRenders() ? Date.now() : 0;
840
+ const output = withRendering(() => runWithOwner(this, () => {
841
+ const setup = this.setupDefinition;
842
+ if (!setup) return this.fn(this.props, context);
843
+ if (!this.setupRender) {
844
+ this.setupPhase = "setup";
845
+ try {
846
+ this.setupRender = setup(this.props, context, () => (this.propsSource ??= new Signal(this.props)).read());
847
+ } finally {
848
+ this.setupPhase = null;
849
+ }
850
+ verifyHookCount(this);
851
+ }
852
+ this.setupPhase = "render";
853
+ try {
854
+ return this.setupRender(this.props, context);
855
+ } finally {
856
+ this.setupPhase = null;
857
+ }
858
+ }));
859
+ if (started) reportRenderTime(this, this.displayName || "<anonymous>", Date.now() - started);
860
+ if (!this.setupDefinition) verifyHookCount(this);
861
+ this.renderCount++;
862
+ return output;
863
+ } finally {
864
+ enterInstance(previous);
865
+ }
866
+ }
867
+ /** Render now with the current props, tracking reads. Throws on failure. */
868
+ render(onDiscard) {
869
+ if (onDiscard && this.mounted) {
870
+ const sources = new Set(this.computation._sources ?? []);
871
+ onDiscard(() => this.computation.restoreSources(sources));
872
+ }
873
+ this.computation.run();
874
+ if (this.computation._hasError) throw this.computation._error;
875
+ return this.computation._value;
876
+ }
877
+ /**
878
+ * Make `value` visible under `key` to everything this instance renders.
879
+ * Called during render; undone if the render is discarded.
880
+ */
881
+ provide(key, value) {
882
+ const context = this.context ??= /* @__PURE__ */ new Map();
883
+ const had = context.has(key);
884
+ const previous = context.get(key);
885
+ if (had && Object.is(previous, value)) return;
886
+ const previousRevision = this.contextRevision;
887
+ this.contextRevision = ++nextContextRevision;
888
+ contextEpoch++;
889
+ context.set(key, value);
890
+ recordUndo(() => {
891
+ this.contextRevision = previousRevision;
892
+ contextEpoch++;
893
+ if (had) context.set(key, previous);
894
+ else context.delete(key);
895
+ });
896
+ }
897
+ /** Replace props for the render that follows; undone if it is discarded. */
898
+ setProps(props) {
899
+ const previous = this.props;
900
+ if (previous === props) return;
901
+ this.props = props;
902
+ this.propsSource?.write(props);
903
+ recordUndo(() => {
904
+ this.props = previous;
905
+ this.propsSource?.write(previous);
906
+ });
907
+ }
908
+ onCommit(fn) {
909
+ (this.commitQueue ??= []).push(fn);
910
+ }
911
+ onCommitSync(fn) {
912
+ (this.commitSyncQueue ??= []).push(fn);
913
+ }
914
+ isSetupRenderPhase() {
915
+ return this.setupPhase === "render";
916
+ }
917
+ onDispose() {
918
+ this.abortController?.abort(COMPONENT_ABORT_REASON);
919
+ }
920
+ };
921
+ const COMPONENT_ABORT_REASON = new DOMException("This operation was aborted", "AbortError");
922
+ function depthOf(owner) {
923
+ for (let o = owner; o; o = o.parent) {
924
+ if (o instanceof ComponentInstance) return o.depth;
925
+ const depth = o.depth;
926
+ if (typeof depth === "number") return depth;
927
+ }
928
+ return 0;
929
+ }
930
+ function renderLaneScheduler(instance) {
931
+ let job = null;
932
+ return () => {
933
+ job ??= {
934
+ depth: instance.depth,
935
+ run: () => renderHost?.rerender(instance),
936
+ cancel: () => instance.computation.dropScheduled(),
937
+ get skip() {
938
+ return instance.disposed || !instance.computation.stale;
939
+ }
940
+ };
941
+ schedule(job, "render");
942
+ };
943
+ }
944
+ let currentInstance = null;
945
+ function enterInstance(instance) {
946
+ const previous = currentInstance;
947
+ currentInstance = instance;
948
+ return previous;
949
+ }
950
+ function getCurrentInstance() {
951
+ return currentInstance;
952
+ }
953
+ function requireInstance(api) {
954
+ const instance = currentInstance;
955
+ if (!instance) throw new Error(`${api} can only be called during component render execution. Move ${api} calls to the top level of your component function.`);
956
+ return instance;
957
+ }
958
+ /**
959
+ * Claim the next hook slot. Returns the slot index; the caller stores its
960
+ * value in `instance.hooks[index]`.
961
+ */
962
+ function claimHook(instance, kind) {
963
+ if (instance.isSetupRenderPhase()) throw new Error(`[Askr] ${kind}() cannot be called during setup component render. Declare lifecycle values in the setup callback.`);
964
+ const index = instance.hookIndex++;
965
+ const expected = instance.hookKinds[index];
966
+ if (expected === void 0) {
967
+ if (instance.renderCount > 0) throw hookOrderError(instance, index, kind, void 0);
968
+ instance.hookKinds[index] = kind;
969
+ } else if (expected !== kind) throw hookOrderError(instance, index, kind, expected);
970
+ return index;
971
+ }
972
+ function verifyHookCount(instance) {
973
+ if (instance.renderCount > 0 && instance.hookIndex !== instance.hookKinds.length) throw hookOrderError(instance, instance.hookIndex, void 0, instance.hookKinds[instance.hookIndex]);
974
+ }
975
+ var HookOrderChangeError = class extends Error {
976
+ constructor(instance, message) {
977
+ super(message);
978
+ this.instance = instance;
979
+ }
980
+ };
981
+ function hookOrderError(instance, index, actual, expected) {
982
+ return new HookOrderChangeError(instance, `[Askr] Hook order changed in ${instance.displayName || "anonymous component"}: slot ${index} was ${expected ? `${expected}()` : "not claimed"} on the first render but ${actual ? `${actual}()` : "not claimed"} now. Call state(), derive() and other lifecycle APIs unconditionally at the top level of the component, in the same order on every render.`);
983
+ }
984
+ function getRenderHost() {
985
+ return renderHost;
986
+ }
987
+ //#endregion
988
+ export { untrack as A, schedule as C, isTracking as D, getTrackingComputation as E, logger as F, isDevelopmentEnvironment as I, isProductionEnvironment as L, getOwner as M, runWithOwner as N, notifySource as O, configureRenderDiagnostics as P, queueTask as S, Signal as T, batch as _, getCurrentInstance as a, getFlushVersion as b, setRenderHost as c, recordUndo as d, rewindJournal as f, outsideRendering as g, isRendering as h, getContextEpoch as i, Owner as j, trackSource as k, createRenderJournal as l, withRenderJournal as m, HookOrderChangeError as n, getRenderHost as o, settleJournal as p, claimHook as r, requireInstance as s, ComponentInstance as t, journalMark as u, effectScheduler as v, Computation as w, isFlushing as x, flushSync as y };