@askrjs/askr 0.0.1

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 (43) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +298 -0
  3. package/dist/chunk-4CV4JOE5.js +27 -0
  4. package/dist/chunk-4CV4JOE5.js.map +1 -0
  5. package/dist/chunk-HIWJVOS4.js +503 -0
  6. package/dist/chunk-HIWJVOS4.js.map +1 -0
  7. package/dist/chunk-L7RL4LYV.js +3442 -0
  8. package/dist/chunk-L7RL4LYV.js.map +1 -0
  9. package/dist/chunk-UUM5W2RM.js +84 -0
  10. package/dist/chunk-UUM5W2RM.js.map +1 -0
  11. package/dist/chunk-YNH3D4KW.js +29 -0
  12. package/dist/chunk-YNH3D4KW.js.map +1 -0
  13. package/dist/index.cjs +4733 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.cts +446 -0
  16. package/dist/index.d.ts +446 -0
  17. package/dist/index.js +683 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/jsx/jsx-dev-runtime.cjs +40 -0
  20. package/dist/jsx/jsx-dev-runtime.cjs.map +1 -0
  21. package/dist/jsx/jsx-dev-runtime.d.cts +16 -0
  22. package/dist/jsx/jsx-dev-runtime.d.ts +16 -0
  23. package/dist/jsx/jsx-dev-runtime.js +16 -0
  24. package/dist/jsx/jsx-dev-runtime.js.map +1 -0
  25. package/dist/jsx/jsx-runtime.cjs +45 -0
  26. package/dist/jsx/jsx-runtime.cjs.map +1 -0
  27. package/dist/jsx/jsx-runtime.d.cts +17 -0
  28. package/dist/jsx/jsx-runtime.d.ts +17 -0
  29. package/dist/jsx/jsx-runtime.js +14 -0
  30. package/dist/jsx/jsx-runtime.js.map +1 -0
  31. package/dist/navigate-NLQOZQGM.js +16 -0
  32. package/dist/navigate-NLQOZQGM.js.map +1 -0
  33. package/dist/route-TVYWYCEJ.js +31 -0
  34. package/dist/route-TVYWYCEJ.js.map +1 -0
  35. package/dist/ssr-4ELUFK65.js +24 -0
  36. package/dist/ssr-4ELUFK65.js.map +1 -0
  37. package/dist/types-DUDmnzD8.d.cts +38 -0
  38. package/dist/types-DUDmnzD8.d.ts +38 -0
  39. package/package.json +83 -0
  40. package/src/jsx/jsx-dev-runtime.ts +26 -0
  41. package/src/jsx/jsx-runtime.ts +36 -0
  42. package/src/jsx/react-jsx-runtime.d.ts +0 -0
  43. package/src/jsx/types.ts +27 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,4733 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/dev/invariant.ts
24
+ function invariant(condition, message, context) {
25
+ if (!condition) {
26
+ const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
27
+ throw new Error(`[Askr Invariant] ${message}${contextStr}`);
28
+ }
29
+ }
30
+ function assertSchedulingPrecondition(condition, violationMessage) {
31
+ invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
32
+ }
33
+ var init_invariant = __esm({
34
+ "src/dev/invariant.ts"() {
35
+ "use strict";
36
+ }
37
+ });
38
+
39
+ // src/dev/logger.ts
40
+ function callConsole(method, args) {
41
+ const c = typeof console !== "undefined" ? console : void 0;
42
+ if (!c) return;
43
+ const fn = c[method];
44
+ if (typeof fn === "function") {
45
+ try {
46
+ fn.apply(console, args);
47
+ } catch {
48
+ }
49
+ }
50
+ }
51
+ var logger;
52
+ var init_logger = __esm({
53
+ "src/dev/logger.ts"() {
54
+ "use strict";
55
+ logger = {
56
+ debug: (...args) => {
57
+ if (process.env.NODE_ENV === "production") return;
58
+ callConsole("debug", args);
59
+ },
60
+ info: (...args) => {
61
+ if (process.env.NODE_ENV === "production") return;
62
+ callConsole("info", args);
63
+ },
64
+ warn: (...args) => {
65
+ if (process.env.NODE_ENV === "production") return;
66
+ callConsole("warn", args);
67
+ },
68
+ error: (...args) => {
69
+ callConsole("error", args);
70
+ }
71
+ };
72
+ }
73
+ });
74
+
75
+ // src/runtime/scheduler.ts
76
+ function isBulkCommitActive() {
77
+ try {
78
+ const fb = globalThis.__ASKR_FASTLANE;
79
+ return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
80
+ } catch (e) {
81
+ void e;
82
+ return false;
83
+ }
84
+ }
85
+ function isSchedulerExecuting() {
86
+ return globalScheduler.isExecuting();
87
+ }
88
+ function scheduleEventHandler(handler) {
89
+ return (event) => {
90
+ globalScheduler.setInHandler(true);
91
+ try {
92
+ handler.call(null, event);
93
+ } catch (error) {
94
+ logger.error("[Askr] Event handler error:", error);
95
+ } finally {
96
+ globalScheduler.setInHandler(false);
97
+ const state2 = globalScheduler.getState();
98
+ if ((state2.queueLength ?? 0) > 0 && !state2.running) {
99
+ queueMicrotask(() => {
100
+ try {
101
+ if (!globalScheduler.isExecuting()) globalScheduler.flush();
102
+ } catch (err) {
103
+ setTimeout(() => {
104
+ throw err;
105
+ });
106
+ }
107
+ });
108
+ }
109
+ }
110
+ };
111
+ }
112
+ var MAX_FLUSH_DEPTH, Scheduler, globalScheduler;
113
+ var init_scheduler = __esm({
114
+ "src/runtime/scheduler.ts"() {
115
+ "use strict";
116
+ init_invariant();
117
+ init_logger();
118
+ MAX_FLUSH_DEPTH = 50;
119
+ Scheduler = class {
120
+ constructor() {
121
+ this.q = [];
122
+ this.head = 0;
123
+ this.running = false;
124
+ this.inHandler = false;
125
+ this.depth = 0;
126
+ this.executionDepth = 0;
127
+ // for compat with existing diagnostics
128
+ // Monotonic flush version increments at end of each flush
129
+ this.flushVersion = 0;
130
+ // Best-effort microtask kick scheduling
131
+ this.kickScheduled = false;
132
+ // Escape hatch flag for runWithSyncProgress
133
+ this.allowSyncProgress = false;
134
+ // Waiters waiting for flushVersion >= target
135
+ this.waiters = [];
136
+ // Keep a lightweight taskCount for compatibility/diagnostics
137
+ this.taskCount = 0;
138
+ }
139
+ enqueue(task) {
140
+ assertSchedulingPrecondition(
141
+ typeof task === "function",
142
+ "enqueue() requires a function"
143
+ );
144
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
145
+ if (process.env.NODE_ENV !== "production") {
146
+ throw new Error(
147
+ "[Scheduler] enqueue() during bulk commit (not allowed)"
148
+ );
149
+ }
150
+ return;
151
+ }
152
+ this.q.push(task);
153
+ this.taskCount++;
154
+ if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
155
+ this.kickScheduled = true;
156
+ queueMicrotask(() => {
157
+ this.kickScheduled = false;
158
+ if (this.running) return;
159
+ if (isBulkCommitActive()) return;
160
+ try {
161
+ this.flush();
162
+ } catch (err) {
163
+ setTimeout(() => {
164
+ throw err;
165
+ });
166
+ }
167
+ });
168
+ }
169
+ }
170
+ flush() {
171
+ invariant(
172
+ !this.running,
173
+ "[Scheduler] flush() called while already running"
174
+ );
175
+ if (process.env.NODE_ENV !== "production") {
176
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
177
+ throw new Error(
178
+ "[Scheduler] flush() started during bulk commit (not allowed)"
179
+ );
180
+ }
181
+ }
182
+ this.running = true;
183
+ this.depth = 0;
184
+ let fatal = null;
185
+ try {
186
+ while (this.head < this.q.length) {
187
+ this.depth++;
188
+ if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
189
+ throw new Error(
190
+ `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
191
+ );
192
+ }
193
+ const task = this.q[this.head++];
194
+ try {
195
+ this.executionDepth++;
196
+ task();
197
+ this.executionDepth--;
198
+ } catch (err) {
199
+ if (this.executionDepth > 0) this.executionDepth = 0;
200
+ fatal = err;
201
+ break;
202
+ }
203
+ if (this.taskCount > 0) this.taskCount--;
204
+ }
205
+ } finally {
206
+ this.running = false;
207
+ this.depth = 0;
208
+ this.executionDepth = 0;
209
+ if (this.head >= this.q.length) {
210
+ this.q.length = 0;
211
+ this.head = 0;
212
+ } else if (this.head > 0) {
213
+ const remaining = this.q.length - this.head;
214
+ if (this.head > 1024 || this.head > remaining) {
215
+ this.q = this.q.slice(this.head);
216
+ } else {
217
+ for (let i = 0; i < remaining; i++) {
218
+ this.q[i] = this.q[this.head + i];
219
+ }
220
+ this.q.length = remaining;
221
+ }
222
+ this.head = 0;
223
+ }
224
+ this.flushVersion++;
225
+ this.resolveWaiters();
226
+ }
227
+ if (fatal) throw fatal;
228
+ }
229
+ runWithSyncProgress(fn) {
230
+ const prev = this.allowSyncProgress;
231
+ this.allowSyncProgress = true;
232
+ const g = globalThis;
233
+ const origQueueMicrotask = g.queueMicrotask;
234
+ const origSetTimeout = g.setTimeout;
235
+ if (process.env.NODE_ENV !== "production") {
236
+ g.queueMicrotask = () => {
237
+ throw new Error(
238
+ "[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
239
+ );
240
+ };
241
+ g.setTimeout = () => {
242
+ throw new Error(
243
+ "[Scheduler] setTimeout not allowed during runWithSyncProgress"
244
+ );
245
+ };
246
+ }
247
+ const startVersion = this.flushVersion;
248
+ try {
249
+ const res = fn();
250
+ if (!this.running && this.q.length - this.head > 0) {
251
+ this.flush();
252
+ }
253
+ if (process.env.NODE_ENV !== "production") {
254
+ if (this.q.length - this.head > 0) {
255
+ throw new Error(
256
+ "[Scheduler] tasks remain after runWithSyncProgress flush"
257
+ );
258
+ }
259
+ }
260
+ return res;
261
+ } finally {
262
+ if (process.env.NODE_ENV !== "production") {
263
+ g.queueMicrotask = origQueueMicrotask;
264
+ g.setTimeout = origSetTimeout;
265
+ }
266
+ try {
267
+ if (this.flushVersion === startVersion) {
268
+ this.flushVersion++;
269
+ this.resolveWaiters();
270
+ }
271
+ } catch (e) {
272
+ void e;
273
+ }
274
+ this.allowSyncProgress = prev;
275
+ }
276
+ }
277
+ waitForFlush(targetVersion, timeoutMs = 2e3) {
278
+ const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
279
+ if (this.flushVersion >= target) return Promise.resolve();
280
+ return new Promise((resolve, reject) => {
281
+ const timer = setTimeout(() => {
282
+ const diag = {
283
+ flushVersion: this.flushVersion,
284
+ queueLen: this.q.length - this.head,
285
+ running: this.running,
286
+ inHandler: this.inHandler,
287
+ bulk: isBulkCommitActive(),
288
+ globals: {
289
+ __ASKR_LAST_FASTPATH_STATS: globalThis.__ASKR_LAST_FASTPATH_STATS,
290
+ __ASKR_LAST_BULK_TEXT_FASTPATH_STATS: globalThis.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS,
291
+ __ASKR_FASTPATH_COUNTERS: globalThis.__ASKR_FASTPATH_COUNTERS
292
+ }
293
+ };
294
+ reject(
295
+ new Error(
296
+ `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
297
+ )
298
+ );
299
+ }, timeoutMs);
300
+ this.waiters.push({ target, resolve, reject, timer });
301
+ });
302
+ }
303
+ getState() {
304
+ return {
305
+ queueLength: this.q.length - this.head,
306
+ running: this.running,
307
+ depth: this.depth,
308
+ executionDepth: this.executionDepth,
309
+ taskCount: this.taskCount,
310
+ flushVersion: this.flushVersion,
311
+ // New fields for optional inspection
312
+ inHandler: this.inHandler,
313
+ allowSyncProgress: this.allowSyncProgress
314
+ };
315
+ }
316
+ setInHandler(v) {
317
+ this.inHandler = v;
318
+ }
319
+ isInHandler() {
320
+ return this.inHandler;
321
+ }
322
+ isExecuting() {
323
+ return this.running || this.executionDepth > 0;
324
+ }
325
+ // Clear pending synchronous tasks (used by fastlane enter/exit)
326
+ clearPendingSyncTasks() {
327
+ const remaining = this.q.length - this.head;
328
+ if (remaining <= 0) return 0;
329
+ if (this.running) {
330
+ this.q.length = this.head;
331
+ this.taskCount = Math.max(0, this.taskCount - remaining);
332
+ queueMicrotask(() => {
333
+ try {
334
+ this.flushVersion++;
335
+ this.resolveWaiters();
336
+ } catch (e) {
337
+ void e;
338
+ }
339
+ });
340
+ return remaining;
341
+ }
342
+ this.q.length = 0;
343
+ this.head = 0;
344
+ this.taskCount = Math.max(0, this.taskCount - remaining);
345
+ this.flushVersion++;
346
+ this.resolveWaiters();
347
+ return remaining;
348
+ }
349
+ resolveWaiters() {
350
+ if (this.waiters.length === 0) return;
351
+ const ready = [];
352
+ const remaining = [];
353
+ for (const w of this.waiters) {
354
+ if (this.flushVersion >= w.target) {
355
+ if (w.timer) clearTimeout(w.timer);
356
+ ready.push(w.resolve);
357
+ } else {
358
+ remaining.push(w);
359
+ }
360
+ }
361
+ this.waiters = remaining;
362
+ for (const r of ready) r();
363
+ }
364
+ };
365
+ globalScheduler = new Scheduler();
366
+ }
367
+ });
368
+
369
+ // src/runtime/fastlane.ts
370
+ function enterBulkCommit() {
371
+ _bulkCommitActive = true;
372
+ _appliedParents = /* @__PURE__ */ new WeakSet();
373
+ try {
374
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
375
+ if (process.env.NODE_ENV !== "production") {
376
+ const _g = globalThis;
377
+ _g.__ASKR_FASTLANE_CLEARED_TASKS = cleared;
378
+ }
379
+ } catch (err) {
380
+ if (process.env.NODE_ENV !== "production") throw err;
381
+ }
382
+ }
383
+ function exitBulkCommit() {
384
+ _bulkCommitActive = false;
385
+ _appliedParents = null;
386
+ }
387
+ function isBulkCommitActive2() {
388
+ return _bulkCommitActive;
389
+ }
390
+ function markFastPathApplied(parent) {
391
+ if (!_appliedParents) return;
392
+ try {
393
+ _appliedParents.add(parent);
394
+ } catch (e) {
395
+ void e;
396
+ }
397
+ }
398
+ function isFastPathApplied(parent) {
399
+ return !!(_appliedParents && _appliedParents.has(parent));
400
+ }
401
+ function classifyUpdate(instance, result) {
402
+ if (!result || typeof result !== "object" || !("type" in result))
403
+ return { useFastPath: false, reason: "not-vnode" };
404
+ const vnode = result;
405
+ if (vnode == null || typeof vnode.type !== "string")
406
+ return { useFastPath: false, reason: "not-intrinsic" };
407
+ const parent = instance.target;
408
+ if (!parent) return { useFastPath: false, reason: "no-root" };
409
+ const firstChild = parent.children[0];
410
+ if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
411
+ if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
412
+ return { useFastPath: false, reason: "root-tag-mismatch" };
413
+ const children = vnode.children || vnode.props?.children;
414
+ if (!Array.isArray(children))
415
+ return { useFastPath: false, reason: "no-children-array" };
416
+ for (let i = 0; i < children.length; i++) {
417
+ const c = children[i];
418
+ if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
419
+ return { useFastPath: false, reason: "component-child-present" };
420
+ }
421
+ }
422
+ if (instance.mountOperations.length > 0)
423
+ return { useFastPath: false, reason: "pending-mounts" };
424
+ const oldKeyMap = getKeyMapForElement(firstChild);
425
+ const decision = isKeyedReorderFastPathEligible(
426
+ firstChild,
427
+ children,
428
+ oldKeyMap
429
+ );
430
+ if (!decision.useFastPath || decision.totalKeyed < 128)
431
+ return { ...decision, useFastPath: false, reason: "renderer-declined" };
432
+ return { ...decision, useFastPath: true };
433
+ }
434
+ function commitReorderOnly(instance, result) {
435
+ const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
436
+ if (typeof evaluate2 !== "function") {
437
+ logger.warn(
438
+ "[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
439
+ );
440
+ return false;
441
+ }
442
+ const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
443
+ enterBulkCommit();
444
+ try {
445
+ globalScheduler.runWithSyncProgress(() => {
446
+ evaluate2(result, instance.target);
447
+ try {
448
+ const comp = (init_component(), __toCommonJS(component_exports));
449
+ if (typeof comp?.finalizeReadSubscriptions === "function") {
450
+ try {
451
+ comp.finalizeReadSubscriptions(instance);
452
+ } catch (e) {
453
+ if (process.env.NODE_ENV !== "production") throw e;
454
+ }
455
+ }
456
+ } catch (e) {
457
+ void e;
458
+ }
459
+ });
460
+ try {
461
+ const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
462
+ if (process.env.NODE_ENV !== "production") {
463
+ const _g = globalThis;
464
+ _g.__ASKR_FASTLANE_CLEARED_AFTER = clearedAfter;
465
+ }
466
+ } catch (err) {
467
+ if (process.env.NODE_ENV !== "production") throw err;
468
+ }
469
+ if (process.env.NODE_ENV !== "production") {
470
+ const _g = globalThis;
471
+ const commitCount = _g.__ASKR_LAST_FASTPATH_COMMIT_COUNT ?? 0;
472
+ const invariants = {
473
+ commitCount,
474
+ mountOps: instance.mountOperations.length,
475
+ cleanupFns: instance.cleanupFns.length
476
+ };
477
+ _g.__ASKR_LAST_FASTLANE_INVARIANTS = invariants;
478
+ if (commitCount !== 1) {
479
+ throw new Error(
480
+ "Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
481
+ );
482
+ }
483
+ if (invariants.mountOps > 0) {
484
+ throw new Error(
485
+ "Fast-lane invariant violated: mount operations were registered during bulk commit"
486
+ );
487
+ }
488
+ if (invariants.cleanupFns > 0) {
489
+ throw new Error(
490
+ "Fast-lane invariant violated: cleanup functions were added during bulk commit"
491
+ );
492
+ }
493
+ const schedAfter = globalScheduler.getState();
494
+ if (schedBefore && schedAfter && // Only fail if outstanding tasks increased — consuming existing tasks is allowed
495
+ schedAfter.taskCount > schedBefore.taskCount) {
496
+ try {
497
+ console.error(
498
+ "[FASTLANE] schedBefore, schedAfter",
499
+ schedBefore,
500
+ schedAfter
501
+ );
502
+ console.error(
503
+ "[FASTLANE] enqueue logs",
504
+ globalThis.__ASKR_ENQUEUE_LOGS
505
+ );
506
+ } catch (e) {
507
+ void e;
508
+ }
509
+ throw new Error(
510
+ "Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
511
+ );
512
+ }
513
+ let finalState = globalScheduler.getState();
514
+ const executing = globalScheduler.isExecuting();
515
+ const outstandingAfter = Math.max(
516
+ 0,
517
+ finalState.taskCount - (executing ? 1 : 0)
518
+ );
519
+ if (outstandingAfter !== 0) {
520
+ if (process.env.NODE_ENV !== "production") {
521
+ let attempts = 0;
522
+ while (attempts < 5) {
523
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
524
+ if (cleared === 0) break;
525
+ attempts++;
526
+ }
527
+ finalState = globalScheduler.getState();
528
+ const outstandingAfter2 = Math.max(
529
+ 0,
530
+ finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
531
+ );
532
+ if (outstandingAfter2 !== 0) {
533
+ try {
534
+ const _g2 = globalThis;
535
+ console.error(
536
+ "[FASTLANE] Post-commit enqueue logs:",
537
+ _g2.__ASKR_ENQUEUE_LOGS
538
+ );
539
+ console.error(
540
+ "[FASTLANE] Cleared counts:",
541
+ _g2.__ASKR_FASTLANE_CLEARED_TASKS,
542
+ _g2.__ASKR_FASTLANE_CLEARED_AFTER
543
+ );
544
+ } catch (err) {
545
+ void err;
546
+ }
547
+ throw new Error(
548
+ `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
549
+ );
550
+ }
551
+ } else {
552
+ globalScheduler.clearPendingSyncTasks?.();
553
+ }
554
+ }
555
+ }
556
+ return true;
557
+ } finally {
558
+ exitBulkCommit();
559
+ if (process.env.NODE_ENV !== "production") {
560
+ try {
561
+ const _g = globalThis;
562
+ _g.__ASKR_FASTLANE_BULK_FLAG_CHECK = isBulkCommitActive2();
563
+ } catch (e) {
564
+ void e;
565
+ }
566
+ }
567
+ }
568
+ if (process.env.NODE_ENV !== "production") {
569
+ const _g = globalThis;
570
+ if (_g.__ASKR_FASTLANE_BULK_FLAG_CHECK) {
571
+ delete _g.__ASKR_FASTLANE_BULK_FLAG_CHECK;
572
+ throw new Error(
573
+ "Fast-lane invariant violated: bulk commit flag still set after commit"
574
+ );
575
+ }
576
+ }
577
+ }
578
+ function tryRuntimeFastLaneSync(instance, result) {
579
+ const cls = classifyUpdate(instance, result);
580
+ if (!cls.useFastPath) return false;
581
+ try {
582
+ return commitReorderOnly(instance, result);
583
+ } catch (err) {
584
+ if (process.env.NODE_ENV !== "production") throw err;
585
+ return false;
586
+ }
587
+ }
588
+ var _bulkCommitActive, _appliedParents;
589
+ var init_fastlane = __esm({
590
+ "src/runtime/fastlane.ts"() {
591
+ "use strict";
592
+ init_scheduler();
593
+ init_logger();
594
+ init_dom();
595
+ _bulkCommitActive = false;
596
+ _appliedParents = null;
597
+ if (typeof globalThis !== "undefined") {
598
+ const _g = globalThis;
599
+ _g.__ASKR_FASTLANE = {
600
+ isBulkCommitActive: isBulkCommitActive2,
601
+ enterBulkCommit,
602
+ exitBulkCommit,
603
+ tryRuntimeFastLaneSync,
604
+ markFastPathApplied,
605
+ isFastPathApplied
606
+ };
607
+ }
608
+ }
609
+ });
610
+
611
+ // src/jsx/jsx-runtime.ts
612
+ function jsx(type, props, key) {
613
+ return {
614
+ type,
615
+ props: props || {},
616
+ key
617
+ };
618
+ }
619
+ function jsxs(type, props, key) {
620
+ return jsx(type, props, key);
621
+ }
622
+ var Fragment;
623
+ var init_jsx_runtime = __esm({
624
+ "src/jsx/jsx-runtime.ts"() {
625
+ "use strict";
626
+ Fragment = /* @__PURE__ */ Symbol.for("@askrjs/askr.Fragment");
627
+ }
628
+ });
629
+
630
+ // src/runtime/context.ts
631
+ function withContext(frame, fn) {
632
+ const oldFrame = currentContextFrame;
633
+ currentContextFrame = frame;
634
+ try {
635
+ return fn();
636
+ } finally {
637
+ currentContextFrame = oldFrame;
638
+ }
639
+ }
640
+ function withAsyncResourceContext(frame, fn) {
641
+ const oldFrame = currentAsyncResourceFrame;
642
+ currentAsyncResourceFrame = frame;
643
+ try {
644
+ return fn();
645
+ } finally {
646
+ currentAsyncResourceFrame = oldFrame;
647
+ }
648
+ }
649
+ function defineContext(defaultValue) {
650
+ const key = /* @__PURE__ */ Symbol("AskrContext");
651
+ return {
652
+ key,
653
+ defaultValue,
654
+ Scope: (props) => {
655
+ return {
656
+ type: ContextScopeComponent,
657
+ props: { key, value: props.value, children: props.children }
658
+ };
659
+ }
660
+ };
661
+ }
662
+ function readContext(context) {
663
+ const frame = currentContextFrame || currentAsyncResourceFrame;
664
+ if (!frame) {
665
+ throw new Error(
666
+ "readContext() can only be called during component render or async resource execution. Ensure you are calling this from inside your component or resource function."
667
+ );
668
+ }
669
+ let current2 = frame;
670
+ while (current2) {
671
+ const values = current2.values;
672
+ if (values && values.has(context.key)) {
673
+ return values.get(context.key);
674
+ }
675
+ current2 = current2.parent;
676
+ }
677
+ return context.defaultValue;
678
+ }
679
+ function ContextScopeComponent(props) {
680
+ const key = props["key"];
681
+ const value = props["value"];
682
+ const children = props["children"];
683
+ const instance = getCurrentComponentInstance();
684
+ const parentFrame = (() => {
685
+ if (currentContextFrame) return currentContextFrame;
686
+ if (instance && instance.ownerFrame) return instance.ownerFrame;
687
+ return null;
688
+ })();
689
+ const newFrame = {
690
+ parent: parentFrame,
691
+ values: /* @__PURE__ */ new Map([[key, value]])
692
+ };
693
+ if (Array.isArray(children)) {
694
+ return children.map((child) => {
695
+ if (typeof child === "function") {
696
+ return {
697
+ type: ContextFunctionChildInvoker,
698
+ props: {
699
+ fn: child,
700
+ __frame: newFrame,
701
+ __owner: getCurrentComponentInstance()
702
+ }
703
+ };
704
+ }
705
+ return markWithFrame(child, newFrame);
706
+ });
707
+ } else if (typeof children === "function") {
708
+ return {
709
+ type: ContextFunctionChildInvoker,
710
+ props: {
711
+ fn: children,
712
+ __frame: newFrame,
713
+ __owner: getCurrentComponentInstance()
714
+ }
715
+ };
716
+ } else if (children) {
717
+ return markWithFrame(children, newFrame);
718
+ }
719
+ return null;
720
+ }
721
+ function markWithFrame(node, frame) {
722
+ if (typeof node === "object" && node !== null) {
723
+ const obj = node;
724
+ obj[CONTEXT_FRAME_SYMBOL] = frame;
725
+ const children = obj.children;
726
+ if (Array.isArray(children)) {
727
+ for (let i = 0; i < children.length; i++) {
728
+ const child = children[i];
729
+ if (child) {
730
+ children[i] = markWithFrame(child, frame);
731
+ }
732
+ }
733
+ } else if (children) {
734
+ obj.children = markWithFrame(children, frame);
735
+ }
736
+ }
737
+ return node;
738
+ }
739
+ function ContextFunctionChildInvoker(props) {
740
+ const { fn, __frame } = props;
741
+ const res = withContext(__frame, () => fn());
742
+ if (res) return markWithFrame(res, __frame);
743
+ return null;
744
+ }
745
+ function getCurrentContextFrame() {
746
+ return currentContextFrame;
747
+ }
748
+ var CONTEXT_FRAME_SYMBOL, currentContextFrame, currentAsyncResourceFrame;
749
+ var init_context = __esm({
750
+ "src/runtime/context.ts"() {
751
+ "use strict";
752
+ init_component();
753
+ CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
754
+ currentContextFrame = null;
755
+ currentAsyncResourceFrame = null;
756
+ }
757
+ });
758
+
759
+ // src/renderer/dom.ts
760
+ function cleanupInstanceIfPresent(node) {
761
+ if (!node) return;
762
+ if (!(node instanceof Element)) return;
763
+ try {
764
+ const inst = node.__ASKR_INSTANCE;
765
+ if (inst) {
766
+ cleanupComponent(inst);
767
+ try {
768
+ delete node.__ASKR_INSTANCE;
769
+ } catch (e) {
770
+ void e;
771
+ }
772
+ }
773
+ } catch (err) {
774
+ void err;
775
+ }
776
+ try {
777
+ const descendants = node.querySelectorAll("*");
778
+ for (const d of Array.from(descendants)) {
779
+ try {
780
+ const inst = d.__ASKR_INSTANCE;
781
+ if (inst) {
782
+ cleanupComponent(inst);
783
+ try {
784
+ delete d.__ASKR_INSTANCE;
785
+ } catch (e) {
786
+ void e;
787
+ }
788
+ }
789
+ } catch (err) {
790
+ void err;
791
+ }
792
+ }
793
+ } catch (err) {
794
+ void err;
795
+ }
796
+ }
797
+ function _isDOMElement(node) {
798
+ return typeof node === "object" && node !== null && "type" in node;
799
+ }
800
+ function getKeyMapForElement(el) {
801
+ return keyedElements.get(el);
802
+ }
803
+ function removeElementListeners(element) {
804
+ const map = elementListeners.get(element);
805
+ if (map) {
806
+ for (const [eventName, entry] of map) {
807
+ element.removeEventListener(eventName, entry.handler);
808
+ }
809
+ elementListeners.delete(element);
810
+ }
811
+ }
812
+ function removeAllListeners(root) {
813
+ if (!root) return;
814
+ removeElementListeners(root);
815
+ const children = root.querySelectorAll("*");
816
+ for (let i = 0; i < children.length; i++) {
817
+ removeElementListeners(children[i]);
818
+ }
819
+ }
820
+ function evaluate(node, target, context) {
821
+ if (!target) return;
822
+ if (context && domRanges.has(context)) {
823
+ const range = domRanges.get(context);
824
+ let current2 = range.start.nextSibling;
825
+ while (current2 && current2 !== range.end) {
826
+ const next = current2.nextSibling;
827
+ current2.remove();
828
+ current2 = next;
829
+ }
830
+ const dom = createDOMNode(node);
831
+ if (dom) {
832
+ target.insertBefore(dom, range.end);
833
+ }
834
+ } else if (context) {
835
+ const start = document.createComment("component-start");
836
+ const end = document.createComment("component-end");
837
+ target.appendChild(start);
838
+ target.appendChild(end);
839
+ domRanges.set(context, { start, end });
840
+ const dom = createDOMNode(node);
841
+ if (dom) {
842
+ target.insertBefore(dom, end);
843
+ }
844
+ } else {
845
+ const vnode = node;
846
+ const firstChild = target.children[0];
847
+ if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && firstChild.tagName.toLowerCase() === vnode.type.toLowerCase()) {
848
+ const vnodeChildren = vnode.children || vnode.props?.children;
849
+ let isSimpleTextVNode = false;
850
+ let textContent;
851
+ if (!Array.isArray(vnodeChildren)) {
852
+ if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
853
+ isSimpleTextVNode = true;
854
+ textContent = String(vnodeChildren);
855
+ }
856
+ } else if (vnodeChildren.length === 1) {
857
+ const child = vnodeChildren[0];
858
+ if (typeof child === "string" || typeof child === "number") {
859
+ isSimpleTextVNode = true;
860
+ textContent = String(child);
861
+ }
862
+ }
863
+ if (isSimpleTextVNode && firstChild.childNodes.length === 1 && firstChild.firstChild?.nodeType === 3) {
864
+ firstChild.firstChild.data = textContent;
865
+ } else {
866
+ if (vnodeChildren) {
867
+ if (Array.isArray(vnodeChildren)) {
868
+ const hasKeys = vnodeChildren.some(
869
+ (child) => typeof child === "object" && child !== null && "key" in child
870
+ );
871
+ if (hasKeys) {
872
+ let oldKeyMap = keyedElements.get(firstChild);
873
+ if (!oldKeyMap) {
874
+ oldKeyMap = /* @__PURE__ */ new Map();
875
+ }
876
+ try {
877
+ if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
878
+ try {
879
+ const keyedVnodes = [];
880
+ for (let i = 0; i < vnodeChildren.length; i++) {
881
+ const c = vnodeChildren[i];
882
+ if (_isDOMElement(c) && c.key !== void 0) {
883
+ keyedVnodes.push({
884
+ key: c.key,
885
+ vnode: c
886
+ });
887
+ }
888
+ }
889
+ if (keyedVnodes.length > 0 && keyedVnodes.length === vnodeChildren.length) {
890
+ logger.warn(
891
+ "[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
892
+ );
893
+ const stats = performBulkPositionalKeyedTextUpdate(
894
+ firstChild,
895
+ keyedVnodes
896
+ );
897
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
898
+ try {
899
+ const gl = globalThis;
900
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
901
+ gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
902
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
903
+ counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
904
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
905
+ } catch (e) {
906
+ void e;
907
+ }
908
+ }
909
+ try {
910
+ const map = /* @__PURE__ */ new Map();
911
+ const children = Array.from(firstChild.children);
912
+ for (let i = 0; i < children.length; i++) {
913
+ const el = children[i];
914
+ const k = el.getAttribute("data-key");
915
+ if (k !== null) {
916
+ map.set(k, el);
917
+ const n = Number(k);
918
+ if (!Number.isNaN(n)) map.set(n, el);
919
+ }
920
+ }
921
+ keyedElements.set(firstChild, map);
922
+ } catch (e) {
923
+ void e;
924
+ }
925
+ } else {
926
+ const newKeyMap = reconcileKeyedChildren(
927
+ firstChild,
928
+ vnodeChildren,
929
+ oldKeyMap
930
+ );
931
+ keyedElements.set(firstChild, newKeyMap);
932
+ }
933
+ } catch (err) {
934
+ logger.warn(
935
+ "[Askr][FASTPATH] forced bulk path failed, falling back",
936
+ err
937
+ );
938
+ const newKeyMap = reconcileKeyedChildren(
939
+ firstChild,
940
+ vnodeChildren,
941
+ oldKeyMap
942
+ );
943
+ keyedElements.set(firstChild, newKeyMap);
944
+ }
945
+ } else {
946
+ const newKeyMap = reconcileKeyedChildren(
947
+ firstChild,
948
+ vnodeChildren,
949
+ oldKeyMap
950
+ );
951
+ keyedElements.set(firstChild, newKeyMap);
952
+ }
953
+ } catch (e) {
954
+ void e;
955
+ const newKeyMap = reconcileKeyedChildren(
956
+ firstChild,
957
+ vnodeChildren,
958
+ oldKeyMap
959
+ );
960
+ keyedElements.set(firstChild, newKeyMap);
961
+ }
962
+ } else {
963
+ if (isBulkTextFastPathEligible(firstChild, vnodeChildren)) {
964
+ const stats = performBulkTextReplace(firstChild, vnodeChildren);
965
+ if (process.env.NODE_ENV !== "production") {
966
+ try {
967
+ const gl = globalThis;
968
+ gl.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS = stats;
969
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
970
+ counters.bulkTextHits = (counters.bulkTextHits || 0) + 1;
971
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
972
+ } catch (e) {
973
+ void e;
974
+ }
975
+ }
976
+ } else {
977
+ if (process.env.NODE_ENV !== "production") {
978
+ try {
979
+ const gl = globalThis;
980
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
981
+ counters.bulkTextMisses = (counters.bulkTextMisses || 0) + 1;
982
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
983
+ } catch (e) {
984
+ void e;
985
+ }
986
+ }
987
+ updateUnkeyedChildren(firstChild, vnodeChildren);
988
+ keyedElements.delete(firstChild);
989
+ }
990
+ }
991
+ } else {
992
+ firstChild.textContent = "";
993
+ const dom = createDOMNode(vnodeChildren);
994
+ if (dom) firstChild.appendChild(dom);
995
+ keyedElements.delete(firstChild);
996
+ }
997
+ } else {
998
+ firstChild.textContent = "";
999
+ keyedElements.delete(firstChild);
1000
+ }
1001
+ }
1002
+ updateElementFromVnode(firstChild, vnode, false);
1003
+ } else {
1004
+ target.textContent = "";
1005
+ if (_isDOMElement(vnode) && typeof vnode.type === "string") {
1006
+ const children = vnode.children;
1007
+ if (Array.isArray(children) && children.some(
1008
+ (child) => typeof child === "object" && child !== null && "key" in child
1009
+ )) {
1010
+ const el = document.createElement(vnode.type);
1011
+ target.appendChild(el);
1012
+ const props = vnode.props || {};
1013
+ for (const [key, value] of Object.entries(props)) {
1014
+ if (key === "children" || key === "key") continue;
1015
+ if (value === void 0 || value === null || value === false)
1016
+ continue;
1017
+ if (key.startsWith("on") && key.length > 2) {
1018
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
1019
+ const wrappedHandler = (event) => {
1020
+ globalScheduler.setInHandler(true);
1021
+ try {
1022
+ value(event);
1023
+ } catch (error) {
1024
+ logger.error("[Askr] Event handler error:", error);
1025
+ } finally {
1026
+ globalScheduler.setInHandler(false);
1027
+ }
1028
+ };
1029
+ el.addEventListener(eventName, wrappedHandler);
1030
+ if (!elementListeners.has(el)) {
1031
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1032
+ }
1033
+ elementListeners.get(el).set(eventName, {
1034
+ handler: wrappedHandler,
1035
+ original: value
1036
+ });
1037
+ continue;
1038
+ }
1039
+ if (key === "class" || key === "className") {
1040
+ el.className = String(value);
1041
+ } else if (key === "value" || key === "checked") {
1042
+ el[key] = value;
1043
+ } else {
1044
+ el.setAttribute(key, String(value));
1045
+ }
1046
+ }
1047
+ const newKeyMap = reconcileKeyedChildren(el, children, void 0);
1048
+ keyedElements.set(el, newKeyMap);
1049
+ return;
1050
+ return;
1051
+ }
1052
+ }
1053
+ const dom = createDOMNode(vnode);
1054
+ if (dom) {
1055
+ target.appendChild(dom);
1056
+ }
1057
+ }
1058
+ }
1059
+ }
1060
+ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
1061
+ const keyedVnodes = [];
1062
+ for (let i = 0; i < newChildren.length; i++) {
1063
+ const child = newChildren[i];
1064
+ if (_isDOMElement(child) && child.key !== void 0) {
1065
+ keyedVnodes.push({ key: child.key, vnode: child });
1066
+ }
1067
+ }
1068
+ const totalKeyed = keyedVnodes.length;
1069
+ const newKeyOrder = keyedVnodes.map((kv) => kv.key);
1070
+ const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
1071
+ let moveCount = 0;
1072
+ for (let i = 0; i < newKeyOrder.length; i++) {
1073
+ const k = newKeyOrder[i];
1074
+ if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k || !oldKeyMap?.has(k)) {
1075
+ moveCount++;
1076
+ }
1077
+ }
1078
+ const FAST_MOVE_THRESHOLD_ABS = 64;
1079
+ const FAST_MOVE_THRESHOLD_REL = 0.1;
1080
+ const cheapMoveTrigger = totalKeyed >= 128 && oldKeyOrder.length > 0 && moveCount > Math.max(
1081
+ FAST_MOVE_THRESHOLD_ABS,
1082
+ Math.floor(totalKeyed * FAST_MOVE_THRESHOLD_REL)
1083
+ );
1084
+ let lisTrigger = false;
1085
+ let lisLen = 0;
1086
+ if (totalKeyed >= 128) {
1087
+ const parentChildren = Array.from(parent.children);
1088
+ const positions = new Array(keyedVnodes.length).fill(-1);
1089
+ for (let i = 0; i < keyedVnodes.length; i++) {
1090
+ const key = keyedVnodes[i].key;
1091
+ const el = oldKeyMap?.get(key);
1092
+ if (el && el.parentElement === parent) {
1093
+ positions[i] = parentChildren.indexOf(el);
1094
+ }
1095
+ }
1096
+ const tails = [];
1097
+ for (let i = 0; i < positions.length; i++) {
1098
+ const pos = positions[i];
1099
+ if (pos === -1) continue;
1100
+ let lo = 0;
1101
+ let hi = tails.length;
1102
+ while (lo < hi) {
1103
+ const mid = lo + hi >> 1;
1104
+ if (tails[mid] < pos) lo = mid + 1;
1105
+ else hi = mid;
1106
+ }
1107
+ if (lo === tails.length) tails.push(pos);
1108
+ else tails[lo] = pos;
1109
+ }
1110
+ lisLen = tails.length;
1111
+ lisTrigger = lisLen < Math.floor(totalKeyed * 0.5);
1112
+ }
1113
+ let hasPropsPresent = false;
1114
+ for (let i = 0; i < keyedVnodes.length; i++) {
1115
+ const vnode = keyedVnodes[i].vnode;
1116
+ if (!_isDOMElement(vnode)) continue;
1117
+ const props = vnode.props || {};
1118
+ for (const k of Object.keys(props)) {
1119
+ if (k === "children" || k === "key") continue;
1120
+ if (k.startsWith("on") && k.length > 2) continue;
1121
+ if (k.startsWith("data-")) continue;
1122
+ hasPropsPresent = true;
1123
+ break;
1124
+ }
1125
+ if (hasPropsPresent) break;
1126
+ }
1127
+ let hasPropChanges = false;
1128
+ for (let i = 0; i < keyedVnodes.length; i++) {
1129
+ const { key, vnode } = keyedVnodes[i];
1130
+ const el = oldKeyMap?.get(key);
1131
+ if (!el || !_isDOMElement(vnode)) continue;
1132
+ const props = vnode.props || {};
1133
+ for (const k of Object.keys(props)) {
1134
+ if (k === "children" || k === "key") continue;
1135
+ if (k.startsWith("on") && k.length > 2) continue;
1136
+ if (k.startsWith("data-")) continue;
1137
+ const v = props[k];
1138
+ try {
1139
+ if (k === "class" || k === "className") {
1140
+ if (el.className !== String(v)) {
1141
+ hasPropChanges = true;
1142
+ break;
1143
+ }
1144
+ } else if (k === "value" || k === "checked") {
1145
+ if (el[k] !== v) {
1146
+ hasPropChanges = true;
1147
+ break;
1148
+ }
1149
+ } else {
1150
+ const attr = el.getAttribute(k);
1151
+ if (v === void 0 || v === null || v === false) {
1152
+ if (attr !== null) {
1153
+ hasPropChanges = true;
1154
+ break;
1155
+ }
1156
+ } else if (String(v) !== attr) {
1157
+ hasPropChanges = true;
1158
+ break;
1159
+ }
1160
+ }
1161
+ } catch {
1162
+ hasPropChanges = true;
1163
+ break;
1164
+ }
1165
+ }
1166
+ if (hasPropChanges) break;
1167
+ }
1168
+ const useFastPath = (cheapMoveTrigger || lisTrigger) && !hasPropChanges && !hasPropsPresent;
1169
+ return {
1170
+ useFastPath,
1171
+ totalKeyed,
1172
+ moveCount,
1173
+ lisLen,
1174
+ hasPropChanges
1175
+ };
1176
+ }
1177
+ function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
1178
+ const newKeyMap = /* @__PURE__ */ new Map();
1179
+ const keyedVnodes = [];
1180
+ const unkeyedVnodes = [];
1181
+ for (let i = 0; i < newChildren.length; i++) {
1182
+ const child = newChildren[i];
1183
+ if (_isDOMElement(child) && child.key !== void 0) {
1184
+ keyedVnodes.push({ key: child.key, vnode: child });
1185
+ } else {
1186
+ unkeyedVnodes.push(child);
1187
+ }
1188
+ }
1189
+ const totalKeyed = keyedVnodes.length;
1190
+ const newKeyOrder = keyedVnodes.map((kv) => kv.key);
1191
+ const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
1192
+ let moveCount = 0;
1193
+ for (let i = 0; i < newKeyOrder.length; i++) {
1194
+ const k2 = newKeyOrder[i];
1195
+ if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k2 || !oldKeyMap?.has(k2)) {
1196
+ moveCount++;
1197
+ }
1198
+ }
1199
+ let hasPropChanges = false;
1200
+ for (let i = 0; i < keyedVnodes.length; i++) {
1201
+ const { key, vnode } = keyedVnodes[i];
1202
+ const el = oldKeyMap?.get(key);
1203
+ if (!el || !_isDOMElement(vnode)) continue;
1204
+ const props = vnode.props || {};
1205
+ for (const k2 of Object.keys(props)) {
1206
+ if (k2 === "children" || k2 === "key") continue;
1207
+ if (k2.startsWith("on") && k2.length > 2) {
1208
+ continue;
1209
+ }
1210
+ const v = props[k2];
1211
+ try {
1212
+ if (k2 === "class" || k2 === "className") {
1213
+ if (el.className !== String(v)) {
1214
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch", {
1215
+ key,
1216
+ prop: k2,
1217
+ expected: String(v),
1218
+ actual: el.className
1219
+ });
1220
+ hasPropChanges = true;
1221
+ break;
1222
+ }
1223
+ } else if (k2 === "value" || k2 === "checked") {
1224
+ if (el[k2] !== v) {
1225
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch", {
1226
+ key,
1227
+ prop: k2,
1228
+ expected: v,
1229
+ actual: el[k2]
1230
+ });
1231
+ hasPropChanges = true;
1232
+ break;
1233
+ }
1234
+ } else {
1235
+ const attr = el.getAttribute(k2);
1236
+ if (v === void 0 || v === null || v === false) {
1237
+ if (attr !== null) {
1238
+ logger.warn(
1239
+ "[Askr][FASTPATH][DEV] prop mismatch (missing attr)",
1240
+ {
1241
+ key,
1242
+ prop: k2,
1243
+ expected: v,
1244
+ actual: attr
1245
+ }
1246
+ );
1247
+ hasPropChanges = true;
1248
+ break;
1249
+ }
1250
+ } else if (String(v) !== attr) {
1251
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch (attr diff)", {
1252
+ key,
1253
+ prop: k2,
1254
+ expected: String(v),
1255
+ actual: attr
1256
+ });
1257
+ hasPropChanges = true;
1258
+ break;
1259
+ }
1260
+ }
1261
+ } catch {
1262
+ hasPropChanges = true;
1263
+ break;
1264
+ }
1265
+ }
1266
+ if (hasPropChanges) break;
1267
+ }
1268
+ const decision = isKeyedReorderFastPathEligible(
1269
+ parent,
1270
+ newChildren,
1271
+ oldKeyMap
1272
+ );
1273
+ const useFastPath = decision.useFastPath;
1274
+ logger.warn("[Askr][FASTPATH][DEV] decision", decision);
1275
+ try {
1276
+ const hugeThreshold = Number(process.env.ASKR_BULK_HUGE_THRESHOLD) || 2048;
1277
+ if (!useFastPath && keyedVnodes.length >= hugeThreshold) {
1278
+ let allSimple = true;
1279
+ for (let i = 0; i < keyedVnodes.length; i++) {
1280
+ const vnode = keyedVnodes[i].vnode;
1281
+ if (!_isDOMElement(vnode)) {
1282
+ allSimple = false;
1283
+ break;
1284
+ }
1285
+ const dv = vnode;
1286
+ if (typeof dv.type !== "string") {
1287
+ allSimple = false;
1288
+ break;
1289
+ }
1290
+ const ch = dv.children || dv.props?.children;
1291
+ if (ch === void 0) continue;
1292
+ if (Array.isArray(ch)) {
1293
+ if (ch.length !== 1 || typeof ch[0] !== "string" && typeof ch[0] !== "number") {
1294
+ allSimple = false;
1295
+ break;
1296
+ }
1297
+ } else if (typeof ch !== "string" && typeof ch !== "number") {
1298
+ allSimple = false;
1299
+ break;
1300
+ }
1301
+ }
1302
+ if (allSimple) {
1303
+ logger.warn("[Askr][FASTPATH] applying huge-list positional fallback");
1304
+ try {
1305
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1306
+ } catch (e) {
1307
+ void e;
1308
+ }
1309
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
1310
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1311
+ try {
1312
+ const gl = globalThis;
1313
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1314
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1315
+ counters.bulkKeyedHugeFallback = (counters.bulkKeyedHugeFallback || 0) + 1;
1316
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1317
+ gl.__ASKR_BULK_DIAG = {
1318
+ phase: "bulk-keyed-huge-fallback",
1319
+ stats
1320
+ };
1321
+ } catch (e) {
1322
+ void e;
1323
+ }
1324
+ }
1325
+ return newKeyMap;
1326
+ }
1327
+ }
1328
+ } catch (e) {
1329
+ void e;
1330
+ }
1331
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1332
+ try {
1333
+ const gl = globalThis;
1334
+ gl.__ASKR_BULK_DIAG = {
1335
+ phase: "keyed-decision",
1336
+ decision,
1337
+ totalKeyed,
1338
+ oldKeyMapSize: oldKeyMap?.size ?? 0
1339
+ };
1340
+ } catch (e) {
1341
+ void e;
1342
+ }
1343
+ }
1344
+ let allSimpleText = false;
1345
+ try {
1346
+ if (keyedVnodes.length >= (Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024)) {
1347
+ let missing = 0;
1348
+ try {
1349
+ const present = /* @__PURE__ */ new Set();
1350
+ const parentChildren2 = Array.from(parent.children);
1351
+ for (let i = 0; i < parentChildren2.length; i++) {
1352
+ const attr = parentChildren2[i].getAttribute("data-key");
1353
+ if (attr !== null) {
1354
+ present.add(attr);
1355
+ const n = Number(attr);
1356
+ if (!Number.isNaN(n)) present.add(n);
1357
+ }
1358
+ }
1359
+ for (let i = 0; i < keyedVnodes.length; i++) {
1360
+ const k2 = keyedVnodes[i].key;
1361
+ if (!present.has(k2)) missing++;
1362
+ }
1363
+ } catch {
1364
+ missing = 0;
1365
+ }
1366
+ allSimpleText = keyedVnodes.length > 0 && keyedVnodes.every(({ vnode }) => {
1367
+ if (!_isDOMElement(vnode)) return false;
1368
+ const dv = vnode;
1369
+ if (typeof dv.type !== "string") return false;
1370
+ const ch = dv.children || dv.props?.children;
1371
+ if (ch === void 0) return true;
1372
+ if (Array.isArray(ch)) {
1373
+ return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
1374
+ }
1375
+ return typeof ch === "string" || typeof ch === "number";
1376
+ });
1377
+ let hasPropsPresent = false;
1378
+ for (let i = 0; i < keyedVnodes.length; i++) {
1379
+ const vnode = keyedVnodes[i].vnode;
1380
+ if (!_isDOMElement(vnode)) continue;
1381
+ const props = vnode.props || {};
1382
+ for (const k2 of Object.keys(props)) {
1383
+ if (k2 === "children" || k2 === "key") continue;
1384
+ if (k2.startsWith("on") && k2.length > 2) continue;
1385
+ if (k2.startsWith("data-")) continue;
1386
+ hasPropsPresent = true;
1387
+ break;
1388
+ }
1389
+ if (hasPropsPresent) break;
1390
+ }
1391
+ const missingRatio = missing / Math.max(1, keyedVnodes.length);
1392
+ if (missingRatio > 0.5 && allSimpleText && !hasPropsPresent) {
1393
+ logger.warn(
1394
+ "[Askr][FASTPATH] switching to positional bulk keyed fast-path due to missing keys ratio",
1395
+ missingRatio
1396
+ );
1397
+ try {
1398
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1399
+ } catch (e) {
1400
+ void e;
1401
+ }
1402
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
1403
+ if (process.env.NODE_ENV !== "production") {
1404
+ try {
1405
+ const gl = globalThis;
1406
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1407
+ try {
1408
+ _reconcilerRecordedParents.add(parent);
1409
+ } catch (e) {
1410
+ void e;
1411
+ }
1412
+ gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
1413
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1414
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1415
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1416
+ } catch (e) {
1417
+ void e;
1418
+ }
1419
+ }
1420
+ return newKeyMap;
1421
+ }
1422
+ }
1423
+ } catch (e) {
1424
+ void e;
1425
+ }
1426
+ if (!useFastPath && typeof globalThis !== "undefined") {
1427
+ try {
1428
+ let parentFastpathApplied = false;
1429
+ try {
1430
+ parentFastpathApplied = isFastPathApplied(parent);
1431
+ } catch {
1432
+ parentFastpathApplied = false;
1433
+ }
1434
+ if (!parentFastpathApplied) {
1435
+ const gl = globalThis;
1436
+ try {
1437
+ if (_reconcilerRecordedParents.has(parent)) {
1438
+ _reconcilerRecordedParents.delete(parent);
1439
+ } else {
1440
+ delete gl.__ASKR_LAST_FASTPATH_STATS;
1441
+ delete gl.__ASKR_LAST_FASTPATH_REUSED;
1442
+ }
1443
+ } catch {
1444
+ delete gl.__ASKR_LAST_FASTPATH_STATS;
1445
+ delete gl.__ASKR_LAST_FASTPATH_REUSED;
1446
+ }
1447
+ }
1448
+ } catch (e) {
1449
+ void e;
1450
+ }
1451
+ }
1452
+ let _triedPositionalReuse = false;
1453
+ try {
1454
+ const bulkTextThreshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
1455
+ if (!useFastPath && keyedVnodes.length >= bulkTextThreshold && allSimpleText && !hasPropChanges) {
1456
+ try {
1457
+ if (isFastPathApplied(parent)) {
1458
+ logger.warn(
1459
+ "[Askr][FASTPATH] fast-path already applied on parent; skipping"
1460
+ );
1461
+ return newKeyMap;
1462
+ }
1463
+ } catch (e) {
1464
+ void e;
1465
+ }
1466
+ let stable = true;
1467
+ try {
1468
+ const parentChildren2 = Array.from(parent.children);
1469
+ if (parentChildren2.length === keyedVnodes.length) {
1470
+ const allSimple = keyedVnodes.every(({ vnode }) => {
1471
+ if (!_isDOMElement(vnode)) return false;
1472
+ const dv = vnode;
1473
+ if (typeof dv.type !== "string") return false;
1474
+ const ch = dv.children || dv.props?.children;
1475
+ if (ch === void 0) return true;
1476
+ if (Array.isArray(ch)) {
1477
+ return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
1478
+ }
1479
+ return typeof ch === "string" || typeof ch === "number";
1480
+ });
1481
+ if (allSimple || process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
1482
+ logger.warn(
1483
+ "[Askr][FASTPATH] len-match heuristic triggered (positional bulk)"
1484
+ );
1485
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1486
+ try {
1487
+ const gl = globalThis;
1488
+ gl.__ASKR_BULK_DIAG = {
1489
+ phase: "bulk-keyed-positional-trigger-lenmatch-early",
1490
+ totalKeyed: keyedVnodes.length,
1491
+ allSimple,
1492
+ forced: process.env.ASKR_FORCE_BULK_POSREUSE === "1"
1493
+ };
1494
+ } catch (e) {
1495
+ void e;
1496
+ }
1497
+ }
1498
+ try {
1499
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1500
+ } catch (e) {
1501
+ void e;
1502
+ }
1503
+ const stats = performBulkPositionalKeyedTextUpdate(
1504
+ parent,
1505
+ keyedVnodes
1506
+ );
1507
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1508
+ try {
1509
+ const gl = globalThis;
1510
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1511
+ gl.__ASKR_BULK_DIAG = {
1512
+ phase: "bulk-keyed-positional-applied",
1513
+ stats
1514
+ };
1515
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1516
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1517
+ if (process.env.ASKR_FORCE_BULK_POSREUSE === "1")
1518
+ counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
1519
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1520
+ } catch (e) {
1521
+ void e;
1522
+ }
1523
+ }
1524
+ return newKeyMap;
1525
+ }
1526
+ }
1527
+ if (parentChildren2.length !== keyedVnodes.length) stable = false;
1528
+ else {
1529
+ let keyMismatches = 0;
1530
+ for (let i = 0; i < keyedVnodes.length; i++) {
1531
+ const k2 = keyedVnodes[i].key;
1532
+ const ch = parentChildren2[i];
1533
+ if (!ch) {
1534
+ stable = false;
1535
+ break;
1536
+ }
1537
+ const attr = ch.getAttribute("data-key");
1538
+ if (attr === null) {
1539
+ stable = false;
1540
+ break;
1541
+ }
1542
+ if (String(k2) !== attr && String(Number(attr)) !== String(k2)) {
1543
+ keyMismatches++;
1544
+ }
1545
+ }
1546
+ if (stable) {
1547
+ if (keyMismatches === 0) {
1548
+ logger.warn(
1549
+ "[Askr][FASTPATH] applying bulk keyed text fast-path (stable keys)"
1550
+ );
1551
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1552
+ try {
1553
+ const gl = globalThis;
1554
+ gl.__ASKR_BULK_DIAG = {
1555
+ phase: "bulk-keyed-stable-trigger",
1556
+ totalKeyed: keyedVnodes.length,
1557
+ hasPropChanges
1558
+ };
1559
+ } catch (e) {
1560
+ void e;
1561
+ }
1562
+ }
1563
+ try {
1564
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1565
+ } catch (e) {
1566
+ void e;
1567
+ }
1568
+ const stats = performBulkKeyedTextReplace(
1569
+ parent,
1570
+ keyedVnodes,
1571
+ oldKeyMap
1572
+ );
1573
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1574
+ try {
1575
+ const gl = globalThis;
1576
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1577
+ gl.__ASKR_BULK_DIAG = {
1578
+ phase: "bulk-keyed-applied",
1579
+ stats
1580
+ };
1581
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1582
+ counters.bulkKeyedTextHits = (counters.bulkKeyedTextHits || 0) + 1;
1583
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1584
+ } catch (e) {
1585
+ void e;
1586
+ }
1587
+ }
1588
+ return newKeyMap;
1589
+ }
1590
+ if (parentChildren2.length === keyedVnodes.length) {
1591
+ logger.warn(
1592
+ "[Askr][FASTPATH] applying bulk keyed positional text fast-path (len-match)"
1593
+ );
1594
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1595
+ try {
1596
+ const gl = globalThis;
1597
+ gl.__ASKR_BULK_DIAG = {
1598
+ phase: "bulk-keyed-positional-trigger-lenmatch",
1599
+ totalKeyed: keyedVnodes.length,
1600
+ keyMismatches
1601
+ };
1602
+ } catch (e) {
1603
+ void e;
1604
+ }
1605
+ }
1606
+ try {
1607
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1608
+ } catch (e) {
1609
+ void e;
1610
+ }
1611
+ const stats = performBulkPositionalKeyedTextUpdate(
1612
+ parent,
1613
+ keyedVnodes
1614
+ );
1615
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1616
+ try {
1617
+ const gl = globalThis;
1618
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1619
+ gl.__ASKR_BULK_DIAG = {
1620
+ phase: "bulk-keyed-positional-applied",
1621
+ stats
1622
+ };
1623
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1624
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1625
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1626
+ } catch (e) {
1627
+ void e;
1628
+ }
1629
+ }
1630
+ return newKeyMap;
1631
+ }
1632
+ const mismatchRatio = keyMismatches / keyedVnodes.length;
1633
+ const POSITIONAL_THRESHOLD = 0.5;
1634
+ if (mismatchRatio > POSITIONAL_THRESHOLD) {
1635
+ logger.warn(
1636
+ "[Askr][FASTPATH] applying bulk keyed positional text fast-path"
1637
+ );
1638
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1639
+ try {
1640
+ globalThis.__ASKR_BULK_DIAG = {
1641
+ phase: "bulk-keyed-positional-trigger",
1642
+ totalKeyed: keyedVnodes.length,
1643
+ keyMismatches
1644
+ };
1645
+ } catch (e) {
1646
+ void e;
1647
+ }
1648
+ }
1649
+ try {
1650
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1651
+ } catch (e) {
1652
+ void e;
1653
+ }
1654
+ const stats = performBulkPositionalKeyedTextUpdate(
1655
+ parent,
1656
+ keyedVnodes
1657
+ );
1658
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1659
+ try {
1660
+ const gl = globalThis;
1661
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1662
+ gl.__ASKR_BULK_DIAG = {
1663
+ phase: "bulk-keyed-positional-applied",
1664
+ stats
1665
+ };
1666
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1667
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1668
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1669
+ } catch (e) {
1670
+ void e;
1671
+ }
1672
+ }
1673
+ return newKeyMap;
1674
+ }
1675
+ }
1676
+ }
1677
+ } catch {
1678
+ stable = false;
1679
+ }
1680
+ }
1681
+ } catch (e) {
1682
+ void e;
1683
+ }
1684
+ if (!useFastPath) {
1685
+ const totalKeyed2 = keyedVnodes.length;
1686
+ const candidates = newChildren.filter(
1687
+ (c) => _isDOMElement(c) && typeof c.type === "string"
1688
+ );
1689
+ const smallListPositionalReuseEligible = candidates.length > 0 && candidates.length <= 64 && parent.children.length === candidates.length && candidates.every((vnode) => {
1690
+ const children = vnode.children || vnode.props?.children;
1691
+ if (Array.isArray(children)) {
1692
+ return children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number");
1693
+ }
1694
+ return children === void 0 || typeof children === "string" || typeof children === "number";
1695
+ });
1696
+ try {
1697
+ if (smallListPositionalReuseEligible) {
1698
+ let eligible = true;
1699
+ for (let i = 0; i < totalKeyed2; i++) {
1700
+ const vnode = keyedVnodes[i].vnode;
1701
+ if (!_isDOMElement(vnode) || typeof vnode.type !== "string") {
1702
+ eligible = false;
1703
+ break;
1704
+ }
1705
+ const children = vnode.children || vnode.props?.children;
1706
+ if (Array.isArray(children)) {
1707
+ if (children.length !== 1) {
1708
+ eligible = false;
1709
+ break;
1710
+ }
1711
+ const c = children[0];
1712
+ if (typeof c !== "string" && typeof c !== "number") {
1713
+ eligible = false;
1714
+ break;
1715
+ }
1716
+ } else if (children !== void 0 && typeof children !== "string" && typeof children !== "number") {
1717
+ eligible = false;
1718
+ break;
1719
+ }
1720
+ }
1721
+ const anyKeyMatches = !!oldKeyMap && keyedVnodes.some((kv) => oldKeyMap.has(kv.key));
1722
+ if (anyKeyMatches) {
1723
+ eligible = false;
1724
+ }
1725
+ if (eligible || process.env.ASKR_FORCE_POSREUSE === "1") {
1726
+ _triedPositionalReuse = true;
1727
+ if (process.env.ASKR_FORCE_POSREUSE === "1") {
1728
+ logger.warn(
1729
+ "[Askr][POSREUSE][FORCED] forcing positional reuse path for testing"
1730
+ );
1731
+ } else {
1732
+ logger.warn("[Askr][POSREUSE] positional reuse heuristic applied");
1733
+ }
1734
+ const existingChildren = parent.children;
1735
+ for (let i = 0; i < totalKeyed2; i++) {
1736
+ const { key, vnode } = keyedVnodes[i];
1737
+ const current2 = existingChildren[i];
1738
+ if (current2 && _isDOMElement(vnode)) {
1739
+ const vnodeType = vnode.type;
1740
+ if (current2.tagName.toLowerCase() === vnodeType.toLowerCase()) {
1741
+ updateElementFromVnode(current2, vnode);
1742
+ newKeyMap.set(key, current2);
1743
+ continue;
1744
+ }
1745
+ }
1746
+ const newEl = createDOMNode(vnode);
1747
+ if (newEl instanceof Element) {
1748
+ if (current2) {
1749
+ cleanupInstanceIfPresent(current2);
1750
+ parent.replaceChild(newEl, current2);
1751
+ } else parent.appendChild(newEl);
1752
+ newKeyMap.set(key, newEl);
1753
+ }
1754
+ }
1755
+ for (const vnode of unkeyedVnodes) {
1756
+ const newEl = createDOMNode(vnode);
1757
+ if (newEl) parent.appendChild(newEl);
1758
+ }
1759
+ return newKeyMap;
1760
+ }
1761
+ }
1762
+ } catch {
1763
+ }
1764
+ }
1765
+ if (useFastPath) {
1766
+ if (!isSchedulerExecuting()) {
1767
+ logger.warn(
1768
+ "[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
1769
+ );
1770
+ }
1771
+ let parentChildrenArr;
1772
+ let localOldKeyMap;
1773
+ if (totalKeyed <= 20) {
1774
+ try {
1775
+ const pc = parent.children;
1776
+ parentChildrenArr = new Array(pc.length);
1777
+ for (let i = 0; i < pc.length; i++)
1778
+ parentChildrenArr[i] = pc[i];
1779
+ } catch {
1780
+ parentChildrenArr = void 0;
1781
+ }
1782
+ } else {
1783
+ localOldKeyMap = /* @__PURE__ */ new Map();
1784
+ try {
1785
+ const parentChildren2 = Array.from(parent.children);
1786
+ for (let i = 0; i < parentChildren2.length; i++) {
1787
+ const ch = parentChildren2[i];
1788
+ const k2 = ch.getAttribute("data-key");
1789
+ if (k2 !== null) {
1790
+ localOldKeyMap.set(k2, ch);
1791
+ const n = Number(k2);
1792
+ if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
1793
+ }
1794
+ }
1795
+ } catch {
1796
+ localOldKeyMap = void 0;
1797
+ }
1798
+ }
1799
+ logger.warn(
1800
+ "[Askr][FASTPATH] oldKeyMap size:",
1801
+ oldKeyMap?.size ?? 0,
1802
+ "localOldKeyMap size:",
1803
+ localOldKeyMap?.size
1804
+ );
1805
+ const tLookupStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1806
+ const finalNodes = [];
1807
+ let mapLookups = 0;
1808
+ let createdNodes = 0;
1809
+ let reusedCount = 0;
1810
+ for (let i = 0; i < keyedVnodes.length; i++) {
1811
+ const { key, vnode } = keyedVnodes[i];
1812
+ mapLookups++;
1813
+ let el;
1814
+ if (totalKeyed <= 20 && parentChildrenArr) {
1815
+ const ks = String(key);
1816
+ for (let j = 0; j < parentChildrenArr.length; j++) {
1817
+ const ch = parentChildrenArr[j];
1818
+ const k2 = ch.getAttribute("data-key");
1819
+ if (k2 !== null && (k2 === ks || Number(k2) === key)) {
1820
+ el = ch;
1821
+ break;
1822
+ }
1823
+ }
1824
+ if (!el) el = oldKeyMap?.get(key);
1825
+ } else {
1826
+ el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
1827
+ }
1828
+ if (el) {
1829
+ finalNodes.push(el);
1830
+ reusedCount++;
1831
+ } else {
1832
+ const newEl = createDOMNode(vnode);
1833
+ if (newEl) {
1834
+ finalNodes.push(newEl);
1835
+ createdNodes++;
1836
+ }
1837
+ }
1838
+ }
1839
+ for (const vnode of unkeyedVnodes) {
1840
+ const newEl = createDOMNode(vnode);
1841
+ if (newEl) {
1842
+ finalNodes.push(newEl);
1843
+ createdNodes++;
1844
+ }
1845
+ }
1846
+ const t_lookup = typeof performance !== "undefined" && performance.now ? performance.now() - tLookupStart : 0;
1847
+ if (process.env.ASKR_FASTPATH_GUARD === "1") {
1848
+ const replaceChildrenCount = 0;
1849
+ const otherMutationCount = 0;
1850
+ const orig = {};
1851
+ const elProto = Element.prototype;
1852
+ const nodeProto = Node.prototype;
1853
+ const removeFn = (() => {
1854
+ if (typeof document === "undefined" || typeof document.createElement !== "function")
1855
+ return void 0;
1856
+ try {
1857
+ const el = document.createElement("div");
1858
+ return typeof el.remove === "function" ? el.remove : void 0;
1859
+ } catch {
1860
+ return void 0;
1861
+ }
1862
+ })();
1863
+ if (elProto.replaceChildren)
1864
+ orig.replaceChildren = elProto.replaceChildren;
1865
+ if (nodeProto.appendChild) orig.appendChild = nodeProto.appendChild;
1866
+ if (nodeProto.insertBefore) orig.insertBefore = nodeProto.insertBefore;
1867
+ if (nodeProto.removeChild) orig.removeChild = nodeProto.removeChild;
1868
+ if (nodeProto.replaceChild) orig.replaceChild = nodeProto.replaceChild;
1869
+ if (removeFn) orig.remove = removeFn;
1870
+ let violation = false;
1871
+ try {
1872
+ const fragment = document.createDocumentFragment();
1873
+ for (let i = 0; i < finalNodes.length; i++)
1874
+ fragment.appendChild(finalNodes[i]);
1875
+ let commitCount = 0;
1876
+ commitCount++;
1877
+ parent.replaceChildren(fragment);
1878
+ if (typeof globalThis !== "undefined") {
1879
+ globalThis["__ASKR_LAST_FASTPATH_COMMIT_COUNT"] = commitCount;
1880
+ }
1881
+ } finally {
1882
+ violation = otherMutationCount !== 0 || replaceChildrenCount < 1;
1883
+ }
1884
+ if (violation) {
1885
+ logger.error(
1886
+ "[Askr][DEV] Fast-path structural mutation invariant violated:",
1887
+ {
1888
+ replaceChildrenCount,
1889
+ otherMutationCount
1890
+ }
1891
+ );
1892
+ throw new Error(
1893
+ "Fast-path must perform a single structural replacement (replaceChildren) and no other structural mutations"
1894
+ );
1895
+ }
1896
+ } else {
1897
+ const tFragmentStart = Date.now();
1898
+ const fragment = document.createDocumentFragment();
1899
+ let fragmentAppendCount = 0;
1900
+ for (let i = 0; i < finalNodes.length; i++) {
1901
+ fragment.appendChild(finalNodes[i]);
1902
+ fragmentAppendCount++;
1903
+ }
1904
+ const t_fragment = Date.now() - tFragmentStart;
1905
+ const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
1906
+ const wasExecuting = process.env.NODE_ENV !== "production" ? isSchedulerExecuting() : false;
1907
+ const tCommitStart = Date.now();
1908
+ if (process.env.NODE_ENV !== "production") {
1909
+ }
1910
+ let commitCount = 0;
1911
+ commitCount++;
1912
+ try {
1913
+ const existing = Array.from(parent.childNodes);
1914
+ for (const n of existing) cleanupInstanceIfPresent(n);
1915
+ } catch (e) {
1916
+ void e;
1917
+ }
1918
+ try {
1919
+ const existing = Array.from(parent.childNodes);
1920
+ for (const n of existing) cleanupInstanceIfPresent(n);
1921
+ } catch (e) {
1922
+ void e;
1923
+ }
1924
+ parent.replaceChildren(fragment);
1925
+ if (typeof globalThis !== "undefined") {
1926
+ globalThis["__ASKR_LAST_FASTPATH_COMMIT_COUNT"] = commitCount;
1927
+ }
1928
+ const t_commit = Date.now() - tCommitStart;
1929
+ if (process.env.NODE_ENV !== "production") {
1930
+ const schedAfter = globalScheduler.getState();
1931
+ if (!wasExecuting) {
1932
+ logger.warn(
1933
+ "[Askr][FASTPATH][DEV] Fast-path commit invoked outside scheduler execution"
1934
+ );
1935
+ }
1936
+ if (schedBefore && schedAfter) {
1937
+ if (schedBefore.taskCount !== schedAfter.taskCount) {
1938
+ logger.error(
1939
+ "[Askr][FASTPATH][DEV] Scheduler tasks were enqueued during fast-path commit",
1940
+ {
1941
+ before: schedBefore,
1942
+ after: schedAfter
1943
+ }
1944
+ );
1945
+ throw new Error("Fast-path must not enqueue scheduler tasks");
1946
+ }
1947
+ }
1948
+ const parentNodes = Array.from(parent.childNodes);
1949
+ if (parentNodes.length !== finalNodes.length) {
1950
+ logger.error("[Askr][FASTPATH][DEV] Parent child count mismatch", {
1951
+ parentCount: parentNodes.length,
1952
+ expected: finalNodes.length
1953
+ });
1954
+ throw new Error(
1955
+ "Fast-path must perform a single structural replacement"
1956
+ );
1957
+ }
1958
+ for (let i = 0; i < finalNodes.length; i++) {
1959
+ if (parentNodes[i] !== finalNodes[i]) {
1960
+ logger.error(
1961
+ "[Askr][FASTPATH][DEV] Final DOM order mismatch at index",
1962
+ i,
1963
+ {
1964
+ expected: finalNodes[i],
1965
+ found: parentNodes[i]
1966
+ }
1967
+ );
1968
+ throw new Error(
1969
+ "Fast-path final DOM order does not match expected nodes"
1970
+ );
1971
+ }
1972
+ }
1973
+ }
1974
+ const tBookkeepingStart = Date.now();
1975
+ for (let i = 0; i < keyedVnodes.length; i++) {
1976
+ const key = keyedVnodes[i].key;
1977
+ const node = finalNodes[i];
1978
+ if (node instanceof Element) newKeyMap.set(key, node);
1979
+ }
1980
+ const t_bookkeeping = Date.now() - tBookkeepingStart;
1981
+ if (process.env.ASKR_FASTPATH_TRACE === "1" || process.env.NODE_ENV !== "production") {
1982
+ const stats = {
1983
+ n: totalKeyed,
1984
+ moves: moveCount,
1985
+ lisLen: 0,
1986
+ t_lookup,
1987
+ t_fragment,
1988
+ t_commit,
1989
+ t_bookkeeping,
1990
+ fragmentAppendCount,
1991
+ mapLookups,
1992
+ createdNodes,
1993
+ reusedCount
1994
+ };
1995
+ if (typeof globalThis !== "undefined") {
1996
+ const _g = globalThis;
1997
+ _g["__ASKR_LAST_FASTPATH_STATS"] = stats;
1998
+ _g["__ASKR_LAST_FASTPATH_REUSED"] = reusedCount > 0;
1999
+ const historyKey = "__ASKR_LAST_FASTPATH_HISTORY";
2000
+ let hist = _g[historyKey];
2001
+ if (!hist) {
2002
+ hist = [];
2003
+ _g[historyKey] = hist;
2004
+ }
2005
+ hist.push(stats);
2006
+ }
2007
+ logger.warn("[Askr][FASTPATH]", JSON.stringify(stats));
2008
+ }
2009
+ }
2010
+ return newKeyMap;
2011
+ }
2012
+ const parentChildren = Array.from(parent.children);
2013
+ const positions = new Array(keyedVnodes.length).fill(-1);
2014
+ for (let i = 0; i < keyedVnodes.length; i++) {
2015
+ const key = keyedVnodes[i].key;
2016
+ const el = oldKeyMap?.get(key);
2017
+ if (el && el.parentElement === parent) {
2018
+ positions[i] = parentChildren.indexOf(el);
2019
+ }
2020
+ }
2021
+ const tailsStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2022
+ const keepSet = /* @__PURE__ */ new Set();
2023
+ const tails = [];
2024
+ const tailsIdx = [];
2025
+ const prev = new Array(positions.length).fill(-1);
2026
+ for (let i = 0; i < positions.length; i++) {
2027
+ const pos = positions[i];
2028
+ if (pos === -1) continue;
2029
+ let lo = 0;
2030
+ let hi = tails.length;
2031
+ while (lo < hi) {
2032
+ const mid = lo + hi >> 1;
2033
+ if (tails[mid] < pos) lo = mid + 1;
2034
+ else hi = mid;
2035
+ }
2036
+ if (lo === tails.length) {
2037
+ tails.push(pos);
2038
+ tailsIdx.push(i);
2039
+ } else {
2040
+ tails[lo] = pos;
2041
+ tailsIdx[lo] = i;
2042
+ }
2043
+ prev[i] = lo > 0 ? tailsIdx[lo - 1] : -1;
2044
+ }
2045
+ let k = tailsIdx.length ? tailsIdx[tailsIdx.length - 1] : -1;
2046
+ while (k !== -1) {
2047
+ keepSet.add(k);
2048
+ k = prev[k];
2049
+ }
2050
+ const tLIS = (typeof performance !== "undefined" && performance.now ? performance.now() : Date.now()) - tailsStart;
2051
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2052
+ try {
2053
+ const prev2 = globalThis.__ASKR_BULK_DIAG;
2054
+ globalThis.__ASKR_BULK_DIAG = {
2055
+ phase: "keyed-fallback-lis",
2056
+ positionsFound: positions.filter((p) => p !== -1).length,
2057
+ keepCount: keepSet.size,
2058
+ tLIS,
2059
+ previousDecision: prev2?.decision
2060
+ };
2061
+ } catch (e) {
2062
+ void e;
2063
+ }
2064
+ }
2065
+ let anchor = parent.firstChild;
2066
+ for (let i = 0; i < keyedVnodes.length; i++) {
2067
+ const { key, vnode } = keyedVnodes[i];
2068
+ const el = oldKeyMap?.get(key);
2069
+ if (el && el.parentElement === parent) {
2070
+ if (keepSet.has(i)) {
2071
+ if (anchor === el) {
2072
+ anchor = el.nextSibling;
2073
+ }
2074
+ updateElementFromVnode(el, vnode);
2075
+ newKeyMap.set(key, el);
2076
+ } else {
2077
+ parent.insertBefore(el, anchor);
2078
+ updateElementFromVnode(el, vnode);
2079
+ newKeyMap.set(key, el);
2080
+ anchor = el.nextSibling;
2081
+ }
2082
+ } else {
2083
+ const newEl = createDOMNode(vnode);
2084
+ if (newEl instanceof Element) {
2085
+ parent.insertBefore(newEl, anchor);
2086
+ newKeyMap.set(key, newEl);
2087
+ anchor = newEl.nextSibling;
2088
+ }
2089
+ }
2090
+ }
2091
+ for (const vnode of unkeyedVnodes) {
2092
+ const newEl = createDOMNode(vnode);
2093
+ if (newEl) {
2094
+ parent.appendChild(newEl);
2095
+ }
2096
+ }
2097
+ return newKeyMap;
2098
+ }
2099
+ function performBulkKeyedTextReplace(parent, keyedVnodes, oldKeyMap) {
2100
+ const total = keyedVnodes.length;
2101
+ const finalNodes = [];
2102
+ let reused = 0;
2103
+ let created = 0;
2104
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2105
+ for (let i = 0; i < total; i++) {
2106
+ const { key, vnode } = keyedVnodes[i];
2107
+ const el = oldKeyMap?.get(key);
2108
+ if (el && _isDOMElement(vnode) && typeof vnode.type === "string") {
2109
+ const children = vnode.children || vnode.props?.children;
2110
+ if (typeof children === "string" || typeof children === "number") {
2111
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2112
+ el.firstChild.data = String(children);
2113
+ } else {
2114
+ el.textContent = String(children);
2115
+ }
2116
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2117
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2118
+ el.firstChild.data = String(children[0]);
2119
+ } else {
2120
+ el.textContent = String(children[0]);
2121
+ }
2122
+ } else {
2123
+ updateElementFromVnode(el, vnode);
2124
+ }
2125
+ finalNodes.push(el);
2126
+ reused++;
2127
+ } else {
2128
+ const dom = createDOMNode(vnode);
2129
+ if (dom) {
2130
+ finalNodes.push(dom);
2131
+ created++;
2132
+ }
2133
+ }
2134
+ }
2135
+ try {
2136
+ const toRemove = Array.from(parent.childNodes).filter(
2137
+ (n) => !finalNodes.includes(n)
2138
+ );
2139
+ for (const n of toRemove) cleanupInstanceIfPresent(n);
2140
+ } catch (e) {
2141
+ void e;
2142
+ }
2143
+ const existingChildren = Array.from(parent.children);
2144
+ const listenerSnapshots = new Array(existingChildren.length).fill(void 0);
2145
+ try {
2146
+ for (let i = 0; i < existingChildren.length; i++) {
2147
+ const ch = existingChildren[i];
2148
+ if (ch) {
2149
+ const map = elementListeners.get(ch);
2150
+ if (map && map.size > 0) {
2151
+ const clone = /* @__PURE__ */ new Map();
2152
+ for (const [k, v] of map) clone.set(k, v);
2153
+ listenerSnapshots[i] = clone;
2154
+ }
2155
+ }
2156
+ }
2157
+ } catch (e) {
2158
+ void e;
2159
+ }
2160
+ const fragment = document.createDocumentFragment();
2161
+ for (let i = 0; i < finalNodes.length; i++)
2162
+ fragment.appendChild(finalNodes[i]);
2163
+ parent.replaceChildren(fragment);
2164
+ try {
2165
+ for (let i = 0; i < finalNodes.length; i++) {
2166
+ const newNode = finalNodes[i];
2167
+ const snapshot = listenerSnapshots[i];
2168
+ if (snapshot && newNode instanceof Element) {
2169
+ for (const [eventName, entry] of snapshot) {
2170
+ const existing = elementListeners.get(newNode)?.get(eventName);
2171
+ if (existing && existing.original === entry.original) continue;
2172
+ newNode.addEventListener(eventName, entry.handler);
2173
+ if (!elementListeners.has(newNode))
2174
+ elementListeners.set(newNode, /* @__PURE__ */ new Map());
2175
+ elementListeners.get(newNode).set(eventName, entry);
2176
+ }
2177
+ }
2178
+ }
2179
+ } catch (e) {
2180
+ void e;
2181
+ }
2182
+ try {
2183
+ keyedElements.delete(parent);
2184
+ } catch (e) {
2185
+ void e;
2186
+ }
2187
+ const t = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2188
+ const stats = {
2189
+ n: total,
2190
+ reused,
2191
+ created,
2192
+ t
2193
+ };
2194
+ return stats;
2195
+ }
2196
+ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
2197
+ const total = keyedVnodes.length;
2198
+ let reused = 0;
2199
+ let updatedKeys = 0;
2200
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2201
+ for (let i = 0; i < total; i++) {
2202
+ const { key, vnode } = keyedVnodes[i];
2203
+ const ch = parent.children[i];
2204
+ if (ch && _isDOMElement(vnode) && typeof vnode.type === "string") {
2205
+ const vnodeType = vnode.type;
2206
+ if (ch.tagName.toLowerCase() === vnodeType.toLowerCase()) {
2207
+ const children = vnode.children || vnode.props?.children;
2208
+ if (typeof children === "string" || typeof children === "number") {
2209
+ if (ch.childNodes.length === 1 && ch.firstChild?.nodeType === 3) {
2210
+ ch.firstChild.data = String(children);
2211
+ } else {
2212
+ ch.textContent = String(children);
2213
+ }
2214
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2215
+ if (ch.childNodes.length === 1 && ch.firstChild?.nodeType === 3) {
2216
+ ch.firstChild.data = String(children[0]);
2217
+ } else {
2218
+ ch.textContent = String(children[0]);
2219
+ }
2220
+ } else {
2221
+ updateElementFromVnode(ch, vnode);
2222
+ }
2223
+ try {
2224
+ ch.setAttribute("data-key", String(key));
2225
+ updatedKeys++;
2226
+ } catch (e) {
2227
+ void e;
2228
+ }
2229
+ reused++;
2230
+ continue;
2231
+ }
2232
+ }
2233
+ const dom = createDOMNode(vnode);
2234
+ if (dom) {
2235
+ const existing = parent.children[i];
2236
+ if (existing) {
2237
+ cleanupInstanceIfPresent(existing);
2238
+ parent.replaceChild(dom, existing);
2239
+ } else parent.appendChild(dom);
2240
+ }
2241
+ }
2242
+ const t = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2243
+ try {
2244
+ const newKeyMap = /* @__PURE__ */ new Map();
2245
+ for (let i = 0; i < total; i++) {
2246
+ const k = keyedVnodes[i].key;
2247
+ const ch = parent.children[i];
2248
+ if (ch) newKeyMap.set(k, ch);
2249
+ }
2250
+ keyedElements.set(parent, newKeyMap);
2251
+ } catch (e) {
2252
+ void e;
2253
+ }
2254
+ const stats = {
2255
+ n: total,
2256
+ reused,
2257
+ updatedKeys,
2258
+ t
2259
+ };
2260
+ return stats;
2261
+ }
2262
+ function isBulkTextFastPathEligible(parent, newChildren) {
2263
+ const threshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
2264
+ const requiredFraction = 0.8;
2265
+ const total = Array.isArray(newChildren) ? newChildren.length : 0;
2266
+ if (total < threshold) {
2267
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2268
+ try {
2269
+ globalThis.__ASKR_BULK_DIAG = {
2270
+ phase: "bulk-unkeyed-eligible",
2271
+ reason: "too-small",
2272
+ total,
2273
+ threshold
2274
+ };
2275
+ } catch (e) {
2276
+ void e;
2277
+ }
2278
+ }
2279
+ return false;
2280
+ }
2281
+ let simple = 0;
2282
+ for (let i = 0; i < newChildren.length; i++) {
2283
+ const c = newChildren[i];
2284
+ if (typeof c === "string" || typeof c === "number") {
2285
+ simple++;
2286
+ continue;
2287
+ }
2288
+ if (typeof c === "object" && c !== null && "type" in c) {
2289
+ const dv = c;
2290
+ if (typeof dv.type === "function") {
2291
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2292
+ try {
2293
+ globalThis.__ASKR_BULK_DIAG = {
2294
+ phase: "bulk-unkeyed-eligible",
2295
+ reason: "component-child",
2296
+ index: i
2297
+ };
2298
+ } catch (e) {
2299
+ void e;
2300
+ }
2301
+ }
2302
+ return false;
2303
+ }
2304
+ if (typeof dv.type === "string") {
2305
+ const children = dv.children || dv.props?.children;
2306
+ if (!children) {
2307
+ simple++;
2308
+ continue;
2309
+ }
2310
+ if (Array.isArray(children)) {
2311
+ if (children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2312
+ simple++;
2313
+ continue;
2314
+ }
2315
+ } else if (typeof children === "string" || typeof children === "number") {
2316
+ simple++;
2317
+ continue;
2318
+ }
2319
+ }
2320
+ }
2321
+ }
2322
+ const fraction = simple / total;
2323
+ const eligible = fraction >= requiredFraction && parent.childNodes.length >= total;
2324
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2325
+ try {
2326
+ globalThis.__ASKR_BULK_DIAG = {
2327
+ phase: "bulk-unkeyed-eligible",
2328
+ total,
2329
+ simple,
2330
+ fraction,
2331
+ requiredFraction,
2332
+ eligible
2333
+ };
2334
+ } catch (e) {
2335
+ void e;
2336
+ }
2337
+ }
2338
+ return eligible;
2339
+ }
2340
+ function performBulkTextReplace(parent, newChildren) {
2341
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2342
+ const existing = Array.from(parent.childNodes);
2343
+ const finalNodes = [];
2344
+ let reused = 0;
2345
+ let created = 0;
2346
+ for (let i = 0; i < newChildren.length; i++) {
2347
+ const vnode = newChildren[i];
2348
+ const existingNode = existing[i];
2349
+ if (typeof vnode === "string" || typeof vnode === "number") {
2350
+ const text = String(vnode);
2351
+ if (existingNode && existingNode.nodeType === 3) {
2352
+ existingNode.data = text;
2353
+ finalNodes.push(existingNode);
2354
+ reused++;
2355
+ } else {
2356
+ finalNodes.push(document.createTextNode(text));
2357
+ created++;
2358
+ }
2359
+ continue;
2360
+ }
2361
+ if (typeof vnode === "object" && vnode !== null && "type" in vnode) {
2362
+ if (typeof vnode.type === "string") {
2363
+ const vtype = vnode.type;
2364
+ if (existingNode && existingNode.nodeType === 1 && existingNode.tagName.toLowerCase() === vtype.toLowerCase()) {
2365
+ const el = existingNode;
2366
+ const children = vnode.children || vnode.props?.children;
2367
+ if (typeof children === "string" || typeof children === "number") {
2368
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2369
+ el.firstChild.data = String(children);
2370
+ } else {
2371
+ el.textContent = String(children);
2372
+ }
2373
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2374
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2375
+ el.firstChild.data = String(children[0]);
2376
+ } else {
2377
+ el.textContent = String(children[0]);
2378
+ }
2379
+ } else {
2380
+ updateElementFromVnode(el, vnode);
2381
+ }
2382
+ finalNodes.push(el);
2383
+ reused++;
2384
+ continue;
2385
+ }
2386
+ const dom2 = createDOMNode(vnode);
2387
+ if (dom2) {
2388
+ finalNodes.push(dom2);
2389
+ created++;
2390
+ }
2391
+ continue;
2392
+ }
2393
+ }
2394
+ const dom = createDOMNode(vnode);
2395
+ if (dom) {
2396
+ finalNodes.push(dom);
2397
+ created++;
2398
+ }
2399
+ }
2400
+ const tBuild = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2401
+ try {
2402
+ const toRemove = Array.from(parent.childNodes).filter(
2403
+ (n) => !finalNodes.includes(n)
2404
+ );
2405
+ for (const n of toRemove) cleanupInstanceIfPresent(n);
2406
+ } catch (e) {
2407
+ void e;
2408
+ }
2409
+ const fragStart = Date.now();
2410
+ const fragment = document.createDocumentFragment();
2411
+ for (let i = 0; i < finalNodes.length; i++)
2412
+ fragment.appendChild(finalNodes[i]);
2413
+ parent.replaceChildren(fragment);
2414
+ const tCommit = Date.now() - fragStart;
2415
+ keyedElements.delete(parent);
2416
+ const stats = {
2417
+ n: newChildren.length,
2418
+ reused,
2419
+ created,
2420
+ tBuild,
2421
+ tCommit
2422
+ };
2423
+ return stats;
2424
+ }
2425
+ function updateElementFromVnode(el, vnode, updateChildren = true) {
2426
+ if (!_isDOMElement(vnode)) {
2427
+ return;
2428
+ }
2429
+ const props = vnode.props || {};
2430
+ if (vnode.key !== void 0) {
2431
+ el.setAttribute("data-key", String(vnode.key));
2432
+ }
2433
+ const existingListeners = elementListeners.get(el);
2434
+ const desiredEventNames = /* @__PURE__ */ new Set();
2435
+ for (const key in props) {
2436
+ const value = props[key];
2437
+ if (key === "children" || key === "key") continue;
2438
+ if (value === void 0 || value === null || value === false) {
2439
+ if (key === "class" || key === "className") {
2440
+ el.className = "";
2441
+ } else if (key.startsWith("on") && key.length > 2) {
2442
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2443
+ if (existingListeners && existingListeners.has(eventName)) {
2444
+ const entry = existingListeners.get(eventName);
2445
+ el.removeEventListener(eventName, entry.handler);
2446
+ existingListeners.delete(eventName);
2447
+ }
2448
+ continue;
2449
+ } else {
2450
+ el.removeAttribute(key);
2451
+ }
2452
+ continue;
2453
+ }
2454
+ if (key === "class" || key === "className") {
2455
+ el.className = String(value);
2456
+ } else if (key === "value" || key === "checked") {
2457
+ el[key] = value;
2458
+ } else if (key.startsWith("on") && key.length > 2) {
2459
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2460
+ desiredEventNames.add(eventName);
2461
+ const existing = existingListeners?.get(eventName);
2462
+ if (existing && existing.original === value) {
2463
+ continue;
2464
+ }
2465
+ if (existing) {
2466
+ el.removeEventListener(eventName, existing.handler);
2467
+ }
2468
+ const wrappedHandler = (event) => {
2469
+ globalScheduler.setInHandler(true);
2470
+ try {
2471
+ value(event);
2472
+ } catch (error) {
2473
+ logger.error("[Askr] Event handler error:", error);
2474
+ } finally {
2475
+ globalScheduler.setInHandler(false);
2476
+ }
2477
+ };
2478
+ el.addEventListener(eventName, wrappedHandler);
2479
+ if (!elementListeners.has(el)) {
2480
+ elementListeners.set(el, /* @__PURE__ */ new Map());
2481
+ }
2482
+ elementListeners.get(el).set(eventName, {
2483
+ handler: wrappedHandler,
2484
+ original: value
2485
+ });
2486
+ } else {
2487
+ el.setAttribute(key, String(value));
2488
+ }
2489
+ }
2490
+ if (existingListeners) {
2491
+ for (const eventName of existingListeners.keys()) {
2492
+ const entry = existingListeners.get(eventName);
2493
+ if (!desiredEventNames.has(eventName)) {
2494
+ el.removeEventListener(eventName, entry.handler);
2495
+ existingListeners.delete(eventName);
2496
+ }
2497
+ }
2498
+ if (existingListeners.size === 0) elementListeners.delete(el);
2499
+ }
2500
+ if (updateChildren) {
2501
+ const children = vnode.children || props.children;
2502
+ updateElementChildren(el, children);
2503
+ }
2504
+ }
2505
+ function updateElementChildren(el, children) {
2506
+ if (!children) {
2507
+ el.textContent = "";
2508
+ return;
2509
+ }
2510
+ if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
2511
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2512
+ el.firstChild.data = String(children);
2513
+ } else {
2514
+ el.textContent = String(children);
2515
+ }
2516
+ return;
2517
+ }
2518
+ if (Array.isArray(children)) {
2519
+ updateUnkeyedChildren(el, children);
2520
+ return;
2521
+ }
2522
+ el.textContent = "";
2523
+ const dom = createDOMNode(children);
2524
+ if (dom) el.appendChild(dom);
2525
+ }
2526
+ function updateUnkeyedChildren(parent, newChildren) {
2527
+ const existing = Array.from(parent.children);
2528
+ if (existing.length === 0 && parent.childNodes.length > 0) {
2529
+ parent.textContent = "";
2530
+ }
2531
+ const max = Math.max(existing.length, newChildren.length);
2532
+ for (let i = 0; i < max; i++) {
2533
+ const current2 = existing[i];
2534
+ const next = newChildren[i];
2535
+ if (next === void 0 && current2) {
2536
+ cleanupInstanceIfPresent(current2);
2537
+ current2.remove();
2538
+ continue;
2539
+ }
2540
+ if (!current2 && next !== void 0) {
2541
+ const dom = createDOMNode(next);
2542
+ if (dom) parent.appendChild(dom);
2543
+ continue;
2544
+ }
2545
+ if (!current2 || next === void 0) continue;
2546
+ if (typeof next === "string" || typeof next === "number") {
2547
+ current2.textContent = String(next);
2548
+ } else if (_isDOMElement(next)) {
2549
+ if (typeof next.type === "string") {
2550
+ if (current2.tagName.toLowerCase() === next.type.toLowerCase()) {
2551
+ updateElementFromVnode(current2, next);
2552
+ } else {
2553
+ const dom = createDOMNode(next);
2554
+ if (dom) {
2555
+ cleanupInstanceIfPresent(current2);
2556
+ parent.replaceChild(dom, current2);
2557
+ }
2558
+ }
2559
+ } else {
2560
+ const dom = createDOMNode(next);
2561
+ if (dom) {
2562
+ cleanupInstanceIfPresent(current2);
2563
+ parent.replaceChild(dom, current2);
2564
+ }
2565
+ }
2566
+ } else {
2567
+ const dom = createDOMNode(next);
2568
+ if (dom) {
2569
+ cleanupInstanceIfPresent(current2);
2570
+ parent.replaceChild(dom, current2);
2571
+ }
2572
+ }
2573
+ }
2574
+ }
2575
+ function createDOMNode(node) {
2576
+ if (typeof node === "string") {
2577
+ return document.createTextNode(node);
2578
+ }
2579
+ if (typeof node === "number") {
2580
+ return document.createTextNode(String(node));
2581
+ }
2582
+ if (!node) {
2583
+ return null;
2584
+ }
2585
+ if (Array.isArray(node)) {
2586
+ const fragment = document.createDocumentFragment();
2587
+ for (let i = 0; i < node.length; i++) {
2588
+ const dom = createDOMNode(node[i]);
2589
+ if (dom) fragment.appendChild(dom);
2590
+ }
2591
+ return fragment;
2592
+ }
2593
+ if (typeof node === "object" && node !== null && "type" in node) {
2594
+ const type = node.type;
2595
+ const props = node.props || {};
2596
+ if (typeof type === "string") {
2597
+ const el = document.createElement(type);
2598
+ for (const key in props) {
2599
+ const value = props[key];
2600
+ if (key === "children" || key === "key") continue;
2601
+ if (value === void 0 || value === null || value === false) continue;
2602
+ if (key.startsWith("on") && key.length > 2) {
2603
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2604
+ const wrappedHandler = (event) => {
2605
+ globalScheduler.setInHandler(true);
2606
+ try {
2607
+ value(event);
2608
+ } catch (error) {
2609
+ logger.error("[Askr] Event handler error:", error);
2610
+ } finally {
2611
+ globalScheduler.setInHandler(false);
2612
+ const state2 = globalScheduler.getState();
2613
+ if ((state2.queueLength ?? 0) > 0 && !state2.running) {
2614
+ queueMicrotask(() => {
2615
+ try {
2616
+ if (!globalScheduler.isExecuting()) globalScheduler.flush();
2617
+ } catch (err) {
2618
+ setTimeout(() => {
2619
+ throw err;
2620
+ });
2621
+ }
2622
+ });
2623
+ }
2624
+ }
2625
+ };
2626
+ el.addEventListener(eventName, wrappedHandler);
2627
+ if (!elementListeners.has(el)) {
2628
+ elementListeners.set(el, /* @__PURE__ */ new Map());
2629
+ }
2630
+ elementListeners.get(el).set(eventName, {
2631
+ handler: wrappedHandler,
2632
+ original: value
2633
+ });
2634
+ } else if (key === "class" || key === "className") {
2635
+ el.className = String(value);
2636
+ } else if (key === "value" || key === "checked") {
2637
+ el[key] = value;
2638
+ el.setAttribute(key, String(value));
2639
+ } else {
2640
+ el.setAttribute(key, String(value));
2641
+ }
2642
+ }
2643
+ const vnodeKey = node.key;
2644
+ if (vnodeKey !== void 0) {
2645
+ el.setAttribute("data-key", String(vnodeKey));
2646
+ }
2647
+ const children = props.children || node.children;
2648
+ if (children) {
2649
+ if (Array.isArray(children)) {
2650
+ if (process.env.NODE_ENV !== "production") {
2651
+ let hasElements = false;
2652
+ let hasKeys = false;
2653
+ for (let i = 0; i < children.length; i++) {
2654
+ const item = children[i];
2655
+ if (typeof item === "object" && item !== null && "type" in item) {
2656
+ hasElements = true;
2657
+ const itemProps = item.props || {};
2658
+ if ("key" in itemProps) {
2659
+ hasKeys = true;
2660
+ break;
2661
+ }
2662
+ }
2663
+ }
2664
+ if (hasElements && !hasKeys) {
2665
+ if (typeof console !== "undefined") {
2666
+ logger.warn(
2667
+ 'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
2668
+ );
2669
+ }
2670
+ }
2671
+ }
2672
+ for (let i = 0; i < children.length; i++) {
2673
+ const dom = createDOMNode(children[i]);
2674
+ if (dom) el.appendChild(dom);
2675
+ }
2676
+ } else {
2677
+ const dom = createDOMNode(children);
2678
+ if (dom) el.appendChild(dom);
2679
+ }
2680
+ }
2681
+ return el;
2682
+ }
2683
+ if (typeof type === "function") {
2684
+ const frame = node[CONTEXT_FRAME_SYMBOL];
2685
+ const snapshot = frame || getCurrentContextFrame();
2686
+ const componentFn = type;
2687
+ const isAsync = componentFn.constructor.name === "AsyncFunction";
2688
+ if (isAsync) {
2689
+ throw new Error(
2690
+ "Async components are not supported. Use resource() for async work."
2691
+ );
2692
+ }
2693
+ const vnodeAny = node;
2694
+ let childInstance = vnodeAny.__instance;
2695
+ if (!childInstance) {
2696
+ childInstance = createComponentInstance(
2697
+ `comp-${Math.random().toString(36).slice(2, 7)}`,
2698
+ componentFn,
2699
+ props || {},
2700
+ null
2701
+ );
2702
+ vnodeAny.__instance = childInstance;
2703
+ }
2704
+ if (snapshot) {
2705
+ childInstance.ownerFrame = snapshot;
2706
+ }
2707
+ const result = withContext(
2708
+ snapshot,
2709
+ () => renderComponentInline(childInstance)
2710
+ );
2711
+ if (result instanceof Promise) {
2712
+ throw new Error(
2713
+ "Async components are not supported. Components must return synchronously."
2714
+ );
2715
+ }
2716
+ const dom = withContext(snapshot, () => createDOMNode(result));
2717
+ if (dom instanceof Element) {
2718
+ mountInstanceInline(childInstance, dom);
2719
+ } else {
2720
+ const host = document.createElement("div");
2721
+ mountInstanceInline(childInstance, host);
2722
+ }
2723
+ return dom;
2724
+ }
2725
+ if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
2726
+ const fragment = document.createDocumentFragment();
2727
+ const children = props.children || node.children;
2728
+ if (children) {
2729
+ if (Array.isArray(children)) {
2730
+ for (let i = 0; i < children.length; i++) {
2731
+ const dom = createDOMNode(children[i]);
2732
+ if (dom) fragment.appendChild(dom);
2733
+ }
2734
+ } else {
2735
+ const dom = createDOMNode(children);
2736
+ if (dom) fragment.appendChild(dom);
2737
+ }
2738
+ }
2739
+ return fragment;
2740
+ }
2741
+ }
2742
+ return null;
2743
+ }
2744
+ var domRanges, elementListeners, keyedElements, _reconcilerRecordedParents;
2745
+ var init_dom = __esm({
2746
+ "src/renderer/dom.ts"() {
2747
+ "use strict";
2748
+ init_scheduler();
2749
+ init_fastlane();
2750
+ init_logger();
2751
+ init_jsx_runtime();
2752
+ init_context();
2753
+ init_component();
2754
+ domRanges = /* @__PURE__ */ new WeakMap();
2755
+ elementListeners = /* @__PURE__ */ new WeakMap();
2756
+ keyedElements = /* @__PURE__ */ new WeakMap();
2757
+ _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
2758
+ if (typeof globalThis !== "undefined") {
2759
+ const _g = globalThis;
2760
+ _g.__ASKR_RENDERER = {
2761
+ evaluate,
2762
+ isKeyedReorderFastPathEligible,
2763
+ getKeyMapForElement
2764
+ };
2765
+ }
2766
+ }
2767
+ });
2768
+
2769
+ // src/runtime/component.ts
2770
+ var component_exports = {};
2771
+ __export(component_exports, {
2772
+ cleanupComponent: () => cleanupComponent,
2773
+ createComponentInstance: () => createComponentInstance,
2774
+ executeComponent: () => executeComponent,
2775
+ finalizeReadSubscriptions: () => finalizeReadSubscriptions,
2776
+ getCurrentComponentInstance: () => getCurrentComponentInstance,
2777
+ getCurrentInstance: () => getCurrentInstance,
2778
+ getNextStateIndex: () => getNextStateIndex,
2779
+ getSignal: () => getSignal,
2780
+ mountComponent: () => mountComponent,
2781
+ mountInstanceInline: () => mountInstanceInline,
2782
+ registerMountOperation: () => registerMountOperation,
2783
+ renderComponentInline: () => renderComponentInline,
2784
+ setCurrentComponentInstance: () => setCurrentComponentInstance
2785
+ });
2786
+ function createComponentInstance(id, fn, props, target) {
2787
+ const instance = {
2788
+ id,
2789
+ fn,
2790
+ props,
2791
+ target,
2792
+ mounted: false,
2793
+ abortController: new AbortController(),
2794
+ // Create per-component
2795
+ stateValues: [],
2796
+ evaluationGeneration: 0,
2797
+ notifyUpdate: null,
2798
+ // Prebound helpers (initialized below) to avoid per-update allocations
2799
+ _pendingFlushTask: void 0,
2800
+ _pendingRunTask: void 0,
2801
+ _enqueueRun: void 0,
2802
+ stateIndexCheck: -1,
2803
+ expectedStateIndices: [],
2804
+ firstRenderComplete: false,
2805
+ mountOperations: [],
2806
+ cleanupFns: [],
2807
+ hasPendingUpdate: false,
2808
+ ownerFrame: null,
2809
+ // Will be set by renderer when vnode is marked
2810
+ ssr: false,
2811
+ isRoot: false,
2812
+ // Render-tracking (for precise state subscriptions)
2813
+ _currentRenderToken: void 0,
2814
+ lastRenderToken: 0,
2815
+ _pendingReadStates: /* @__PURE__ */ new Set(),
2816
+ _lastReadStates: /* @__PURE__ */ new Set()
2817
+ };
2818
+ instance._pendingRunTask = () => {
2819
+ instance.hasPendingUpdate = false;
2820
+ runComponent(instance);
2821
+ };
2822
+ instance._enqueueRun = () => {
2823
+ if (!instance.hasPendingUpdate) {
2824
+ instance.hasPendingUpdate = true;
2825
+ globalScheduler.enqueue(instance._pendingRunTask);
2826
+ }
2827
+ };
2828
+ instance._pendingFlushTask = () => {
2829
+ instance.hasPendingUpdate = false;
2830
+ instance._enqueueRun?.();
2831
+ };
2832
+ return instance;
2833
+ }
2834
+ function getCurrentComponentInstance() {
2835
+ return currentInstance;
2836
+ }
2837
+ function setCurrentComponentInstance(instance) {
2838
+ currentInstance = instance;
2839
+ }
2840
+ function registerMountOperation(operation) {
2841
+ const instance = getCurrentComponentInstance();
2842
+ if (instance) {
2843
+ if (isBulkCommitActive2()) {
2844
+ if (process.env.NODE_ENV !== "production") {
2845
+ throw new Error(
2846
+ "registerMountOperation called during bulk commit fast-lane"
2847
+ );
2848
+ }
2849
+ return;
2850
+ }
2851
+ instance.mountOperations.push(operation);
2852
+ }
2853
+ }
2854
+ function executeMountOperations(instance) {
2855
+ if (!instance.isRoot) return;
2856
+ for (const operation of instance.mountOperations) {
2857
+ const result = operation();
2858
+ if (result instanceof Promise) {
2859
+ result.then((cleanup) => {
2860
+ if (typeof cleanup === "function") {
2861
+ instance.cleanupFns.push(cleanup);
2862
+ }
2863
+ });
2864
+ } else if (typeof result === "function") {
2865
+ instance.cleanupFns.push(result);
2866
+ }
2867
+ }
2868
+ instance.mountOperations = [];
2869
+ }
2870
+ function mountInstanceInline(instance, target) {
2871
+ instance.target = target;
2872
+ try {
2873
+ if (target instanceof Element)
2874
+ target.__ASKR_INSTANCE = instance;
2875
+ } catch (err) {
2876
+ void err;
2877
+ }
2878
+ instance.notifyUpdate = instance._enqueueRun;
2879
+ const wasFirstMount = !instance.mounted;
2880
+ instance.mounted = true;
2881
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2882
+ executeMountOperations(instance);
2883
+ }
2884
+ }
2885
+ function runComponent(instance) {
2886
+ instance.notifyUpdate = instance._enqueueRun;
2887
+ instance._currentRenderToken = ++_globalRenderCounter;
2888
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2889
+ const domSnapshot = instance.target ? instance.target.innerHTML : "";
2890
+ const result = executeComponentSync(instance);
2891
+ if (result instanceof Promise) {
2892
+ throw new Error(
2893
+ "Async components are not supported. Components must be synchronous."
2894
+ );
2895
+ } else {
2896
+ const fastlaneBridge = globalThis.__ASKR_FASTLANE;
2897
+ try {
2898
+ const used = fastlaneBridge?.tryRuntimeFastLaneSync?.(instance, result);
2899
+ if (used) return;
2900
+ } catch (err) {
2901
+ if (process.env.NODE_ENV !== "production") throw err;
2902
+ }
2903
+ globalScheduler.enqueue(() => {
2904
+ if (instance.target) {
2905
+ try {
2906
+ const wasFirstMount = !instance.mounted;
2907
+ const oldInstance = currentInstance;
2908
+ currentInstance = instance;
2909
+ try {
2910
+ evaluate(result, instance.target);
2911
+ } finally {
2912
+ currentInstance = oldInstance;
2913
+ }
2914
+ finalizeReadSubscriptions(instance);
2915
+ instance.mounted = true;
2916
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2917
+ executeMountOperations(instance);
2918
+ }
2919
+ } catch (renderError) {
2920
+ instance.target.innerHTML = domSnapshot;
2921
+ throw renderError;
2922
+ }
2923
+ }
2924
+ });
2925
+ }
2926
+ }
2927
+ function renderComponentInline(instance) {
2928
+ const hadToken = instance._currentRenderToken !== void 0;
2929
+ if (!hadToken) {
2930
+ instance._currentRenderToken = ++_globalRenderCounter;
2931
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2932
+ }
2933
+ try {
2934
+ const result = executeComponentSync(instance);
2935
+ if (!hadToken) {
2936
+ finalizeReadSubscriptions(instance);
2937
+ }
2938
+ return result;
2939
+ } finally {
2940
+ if (!hadToken) {
2941
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2942
+ instance._currentRenderToken = void 0;
2943
+ }
2944
+ }
2945
+ }
2946
+ function executeComponentSync(instance) {
2947
+ instance.stateIndexCheck = -1;
2948
+ for (const state2 of instance.stateValues) {
2949
+ if (state2) {
2950
+ state2._hasBeenRead = false;
2951
+ }
2952
+ }
2953
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2954
+ currentInstance = instance;
2955
+ stateIndex = 0;
2956
+ try {
2957
+ const renderStartTime = process.env.NODE_ENV !== "production" ? Date.now() : 0;
2958
+ const context = {
2959
+ signal: instance.abortController.signal
2960
+ };
2961
+ const executionFrame = {
2962
+ parent: instance.ownerFrame,
2963
+ values: null
2964
+ };
2965
+ const result = withContext(
2966
+ executionFrame,
2967
+ () => instance.fn(instance.props, context)
2968
+ );
2969
+ if (process.env.NODE_ENV !== "production") {
2970
+ const renderTime = Date.now() - renderStartTime;
2971
+ if (renderTime > 5) {
2972
+ logger.warn(
2973
+ `[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`
2974
+ );
2975
+ }
2976
+ }
2977
+ if (!instance.firstRenderComplete) {
2978
+ instance.firstRenderComplete = true;
2979
+ }
2980
+ if (process.env.NODE_ENV !== "production") {
2981
+ for (let i = 0; i < instance.stateValues.length; i++) {
2982
+ const state2 = instance.stateValues[i];
2983
+ if (state2 && !state2._hasBeenRead) {
2984
+ logger.warn(
2985
+ `[askr] Unused state variable detected. State should be read during render or removed.`
2986
+ );
2987
+ }
2988
+ }
2989
+ }
2990
+ return result;
2991
+ } finally {
2992
+ currentInstance = null;
2993
+ }
2994
+ }
2995
+ function executeComponent(instance) {
2996
+ instance.abortController = new AbortController();
2997
+ instance.notifyUpdate = instance._enqueueRun;
2998
+ globalScheduler.enqueue(() => runComponent(instance));
2999
+ }
3000
+ function getCurrentInstance() {
3001
+ return currentInstance;
3002
+ }
3003
+ function getSignal() {
3004
+ if (!currentInstance) {
3005
+ throw new Error(
3006
+ "getSignal() can only be called during component render execution. Ensure you are calling this from inside your component function."
3007
+ );
3008
+ }
3009
+ return currentInstance.abortController.signal;
3010
+ }
3011
+ function finalizeReadSubscriptions(instance) {
3012
+ const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
3013
+ const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
3014
+ const token = instance._currentRenderToken;
3015
+ if (token === void 0) return;
3016
+ for (const s of oldSet) {
3017
+ if (!newSet.has(s)) {
3018
+ const readers = s?._readers;
3019
+ if (readers) readers.delete(instance);
3020
+ }
3021
+ }
3022
+ instance.lastRenderToken = token;
3023
+ for (const s of newSet) {
3024
+ let readers = s?._readers;
3025
+ if (!readers) {
3026
+ readers = /* @__PURE__ */ new Map();
3027
+ s._readers = readers;
3028
+ }
3029
+ readers.set(instance, instance.lastRenderToken ?? 0);
3030
+ }
3031
+ instance._lastReadStates = newSet;
3032
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
3033
+ instance._currentRenderToken = void 0;
3034
+ }
3035
+ function getNextStateIndex() {
3036
+ return stateIndex++;
3037
+ }
3038
+ function mountComponent(instance) {
3039
+ executeComponent(instance);
3040
+ }
3041
+ function cleanupComponent(instance) {
3042
+ for (const cleanup of instance.cleanupFns) {
3043
+ cleanup();
3044
+ }
3045
+ instance.cleanupFns = [];
3046
+ if (instance._lastReadStates) {
3047
+ for (const s of instance._lastReadStates) {
3048
+ const readers = s?._readers;
3049
+ if (readers) readers.delete(instance);
3050
+ }
3051
+ instance._lastReadStates = /* @__PURE__ */ new Set();
3052
+ }
3053
+ instance.abortController.abort();
3054
+ }
3055
+ var currentInstance, stateIndex, _globalRenderCounter;
3056
+ var init_component = __esm({
3057
+ "src/runtime/component.ts"() {
3058
+ "use strict";
3059
+ init_dom();
3060
+ init_scheduler();
3061
+ init_context();
3062
+ init_logger();
3063
+ init_fastlane();
3064
+ currentInstance = null;
3065
+ stateIndex = 0;
3066
+ _globalRenderCounter = 0;
3067
+ }
3068
+ });
3069
+
3070
+ // src/ssr/errors.ts
3071
+ var SSRDataMissingError;
3072
+ var init_errors = __esm({
3073
+ "src/ssr/errors.ts"() {
3074
+ "use strict";
3075
+ SSRDataMissingError = class _SSRDataMissingError extends Error {
3076
+ constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
3077
+ super(message);
3078
+ this.code = "SSR_DATA_MISSING";
3079
+ this.name = "SSRDataMissingError";
3080
+ Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
3081
+ }
3082
+ };
3083
+ }
3084
+ });
3085
+
3086
+ // src/ssr/context.ts
3087
+ function withSSRContext(ctx, fn) {
3088
+ const prev = current;
3089
+ current = ctx;
3090
+ try {
3091
+ return fn();
3092
+ } finally {
3093
+ current = prev;
3094
+ }
3095
+ }
3096
+ function createRenderContext(seed = 12345) {
3097
+ const rng = new SeededRNG(seed);
3098
+ return { seed, rng };
3099
+ }
3100
+ function getCurrentSSRContext() {
3101
+ return currentSSRContext;
3102
+ }
3103
+ function runWithSSRContext(ctx, fn) {
3104
+ const prev = currentSSRContext;
3105
+ currentSSRContext = ctx;
3106
+ try {
3107
+ return fn();
3108
+ } finally {
3109
+ currentSSRContext = prev;
3110
+ }
3111
+ }
3112
+ function throwSSRDataMissing() {
3113
+ throw new SSRDataMissingError();
3114
+ }
3115
+ var current, SeededRNG, currentSSRContext;
3116
+ var init_context2 = __esm({
3117
+ "src/ssr/context.ts"() {
3118
+ "use strict";
3119
+ init_errors();
3120
+ current = null;
3121
+ SeededRNG = class {
3122
+ constructor(seed = 12345) {
3123
+ this.seed = seed | 0;
3124
+ }
3125
+ reset(seed = 12345) {
3126
+ this.seed = seed | 0;
3127
+ }
3128
+ // Simple LCG, stable and deterministic
3129
+ random() {
3130
+ this.seed = (this.seed * 9301 + 49297) % 233280;
3131
+ return this.seed / 233280;
3132
+ }
3133
+ };
3134
+ currentSSRContext = null;
3135
+ }
3136
+ });
3137
+
3138
+ // src/ssr/data.ts
3139
+ function getCurrentRenderData() {
3140
+ return currentRenderData;
3141
+ }
3142
+ function resetKeyCounter() {
3143
+ keyCounter = 0;
3144
+ }
3145
+ function getNextKey() {
3146
+ return `r:${keyCounter++}`;
3147
+ }
3148
+ function startRenderPhase(data) {
3149
+ currentRenderData = data ?? null;
3150
+ resetKeyCounter();
3151
+ }
3152
+ function stopRenderPhase() {
3153
+ currentRenderData = null;
3154
+ resetKeyCounter();
3155
+ }
3156
+ async function resolvePlan(_plan) {
3157
+ throw new Error(
3158
+ "SSR resolution of prepass plans is removed: SSR is strictly synchronous and does not support resolving async resource plans"
3159
+ );
3160
+ }
3161
+ function collectResources(_opts) {
3162
+ throw new Error(
3163
+ "SSR collection/prepass (collectResources) is removed: SSR is strictly synchronous and does not support prepass collection"
3164
+ );
3165
+ }
3166
+ var keyCounter, currentRenderData, resolveResources;
3167
+ var init_data = __esm({
3168
+ "src/ssr/data.ts"() {
3169
+ "use strict";
3170
+ keyCounter = 0;
3171
+ currentRenderData = null;
3172
+ resolveResources = resolvePlan;
3173
+ }
3174
+ });
3175
+
3176
+ // src/router/match.ts
3177
+ function match(path, pattern) {
3178
+ const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3179
+ const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
3180
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
3181
+ const patternSegments = normalizedPattern.split("/").filter(Boolean);
3182
+ if (patternSegments.length === 1 && patternSegments[0] === "*") {
3183
+ return {
3184
+ matched: true,
3185
+ params: {
3186
+ "*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
3187
+ }
3188
+ };
3189
+ }
3190
+ if (pathSegments.length !== patternSegments.length) {
3191
+ return { matched: false, params: {} };
3192
+ }
3193
+ const params = {};
3194
+ for (let i = 0; i < patternSegments.length; i++) {
3195
+ const patternSegment = patternSegments[i];
3196
+ const pathSegment = pathSegments[i];
3197
+ if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
3198
+ const paramName = patternSegment.slice(1, -1);
3199
+ params[paramName] = decodeURIComponent(pathSegment);
3200
+ } else if (patternSegment === "*") {
3201
+ params["*"] = pathSegment;
3202
+ } else if (patternSegment !== pathSegment) {
3203
+ return { matched: false, params: {} };
3204
+ }
3205
+ }
3206
+ return { matched: true, params };
3207
+ }
3208
+ var init_match = __esm({
3209
+ "src/router/match.ts"() {
3210
+ "use strict";
3211
+ }
3212
+ });
3213
+
3214
+ // src/router/route.ts
3215
+ var route_exports = {};
3216
+ __export(route_exports, {
3217
+ _lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
3218
+ _unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
3219
+ clearRoutes: () => clearRoutes,
3220
+ getLoadedNamespaces: () => getLoadedNamespaces,
3221
+ getNamespaceRoutes: () => getNamespaceRoutes,
3222
+ getRoutes: () => getRoutes,
3223
+ lockRouteRegistration: () => lockRouteRegistration,
3224
+ registerRoute: () => registerRoute,
3225
+ resolveRoute: () => resolveRoute,
3226
+ route: () => route,
3227
+ setServerLocation: () => setServerLocation,
3228
+ unloadNamespace: () => unloadNamespace
3229
+ });
3230
+ function getDepth(path) {
3231
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3232
+ return normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3233
+ }
3234
+ function getSpecificity(path) {
3235
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3236
+ if (normalized === "/*") {
3237
+ return 0;
3238
+ }
3239
+ const segments = normalized.split("/").filter(Boolean);
3240
+ let score = 0;
3241
+ for (const segment of segments) {
3242
+ if (segment.startsWith("{") && segment.endsWith("}")) {
3243
+ score += 2;
3244
+ } else if (segment === "*") {
3245
+ score += 1;
3246
+ } else {
3247
+ score += 3;
3248
+ }
3249
+ }
3250
+ return score;
3251
+ }
3252
+ function setServerLocation(url) {
3253
+ serverLocation = url;
3254
+ }
3255
+ function parseLocation(url) {
3256
+ try {
3257
+ const u = new URL(url, "http://localhost");
3258
+ return { pathname: u.pathname, search: u.search, hash: u.hash };
3259
+ } catch {
3260
+ return { pathname: "/", search: "", hash: "" };
3261
+ }
3262
+ }
3263
+ function deepFreeze(obj) {
3264
+ if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
3265
+ Object.freeze(obj);
3266
+ for (const key of Object.keys(obj)) {
3267
+ const value = obj[key];
3268
+ if (value && typeof value === "object") deepFreeze(value);
3269
+ }
3270
+ }
3271
+ return obj;
3272
+ }
3273
+ function makeQuery(search) {
3274
+ const usp = new URLSearchParams(search || "");
3275
+ const mapping = /* @__PURE__ */ new Map();
3276
+ for (const [k, v] of usp.entries()) {
3277
+ const existing = mapping.get(k);
3278
+ if (existing) existing.push(v);
3279
+ else mapping.set(k, [v]);
3280
+ }
3281
+ const obj = {
3282
+ get(key) {
3283
+ const arr = mapping.get(key);
3284
+ return arr ? arr[0] : null;
3285
+ },
3286
+ getAll(key) {
3287
+ const arr = mapping.get(key);
3288
+ return arr ? [...arr] : [];
3289
+ },
3290
+ has(key) {
3291
+ return mapping.has(key);
3292
+ },
3293
+ toJSON() {
3294
+ const out = {};
3295
+ for (const [k, arr] of mapping.entries()) {
3296
+ out[k] = arr.length > 1 ? [...arr] : arr[0];
3297
+ }
3298
+ return out;
3299
+ }
3300
+ };
3301
+ return deepFreeze(obj);
3302
+ }
3303
+ function computeMatches(pathname) {
3304
+ const routesList = getRoutes();
3305
+ const matches = [];
3306
+ function getSpecificity2(path) {
3307
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3308
+ if (normalized === "/*") return 0;
3309
+ const segments = normalized.split("/").filter(Boolean);
3310
+ let score = 0;
3311
+ for (const segment of segments) {
3312
+ if (segment.startsWith("{") && segment.endsWith("}")) score += 2;
3313
+ else if (segment === "*") score += 1;
3314
+ else score += 3;
3315
+ }
3316
+ return score;
3317
+ }
3318
+ for (const r of routesList) {
3319
+ const result = match(pathname, r.path);
3320
+ if (result.matched) {
3321
+ matches.push({
3322
+ pattern: r.path,
3323
+ params: result.params,
3324
+ name: r.name,
3325
+ namespace: r.namespace,
3326
+ specificity: getSpecificity2(r.path)
3327
+ });
3328
+ }
3329
+ }
3330
+ matches.sort((a, b) => b.specificity - a.specificity);
3331
+ return matches.map((m) => ({
3332
+ path: m.pattern,
3333
+ params: deepFreeze({ ...m.params }),
3334
+ name: m.name,
3335
+ namespace: m.namespace
3336
+ }));
3337
+ }
3338
+ function lockRouteRegistration() {
3339
+ registrationLocked = true;
3340
+ }
3341
+ function _lockRouteRegistrationForTests() {
3342
+ registrationLocked = true;
3343
+ }
3344
+ function _unlockRouteRegistrationForTests() {
3345
+ registrationLocked = false;
3346
+ }
3347
+ function route(path, handler, namespace) {
3348
+ if (typeof path === "undefined") {
3349
+ const instance = getCurrentComponentInstance();
3350
+ if (!instance) {
3351
+ throw new Error(
3352
+ "route() can only be called during component render execution. Call route() from inside your component function."
3353
+ );
3354
+ }
3355
+ let pathname = "/";
3356
+ let search = "";
3357
+ let hash = "";
3358
+ if (typeof window !== "undefined" && window.location) {
3359
+ pathname = window.location.pathname || "/";
3360
+ search = window.location.search || "";
3361
+ hash = window.location.hash || "";
3362
+ } else if (serverLocation) {
3363
+ const parsed = parseLocation(serverLocation);
3364
+ pathname = parsed.pathname;
3365
+ search = parsed.search;
3366
+ hash = parsed.hash;
3367
+ }
3368
+ const params = deepFreeze({
3369
+ ...instance.props || {}
3370
+ });
3371
+ const query = makeQuery(search);
3372
+ const matches = computeMatches(pathname);
3373
+ const snapshot = Object.freeze({
3374
+ path: pathname,
3375
+ params,
3376
+ query,
3377
+ hash: hash || null,
3378
+ matches: Object.freeze(matches)
3379
+ });
3380
+ return snapshot;
3381
+ }
3382
+ const currentInst = getCurrentComponentInstance();
3383
+ if (currentInst && currentInst.ssr) {
3384
+ throw new Error(
3385
+ "route() cannot be called during SSR rendering. Register routes at module load time instead."
3386
+ );
3387
+ }
3388
+ if (registrationLocked) {
3389
+ throw new Error(
3390
+ "Route registration is locked after app startup. Register routes at module load time before calling createApp()."
3391
+ );
3392
+ }
3393
+ if (typeof handler !== "function") {
3394
+ throw new Error(
3395
+ "route(path, handler) requires a function handler that returns a VNode (e.g. () => <Page />). Passing JSX elements or VNodes directly is not supported."
3396
+ );
3397
+ }
3398
+ const routeObj = { path, handler, namespace };
3399
+ routes.push(routeObj);
3400
+ const depth = getDepth(path);
3401
+ let depthRoutes = routesByDepth.get(depth);
3402
+ if (!depthRoutes) {
3403
+ depthRoutes = [];
3404
+ routesByDepth.set(depth, depthRoutes);
3405
+ }
3406
+ depthRoutes.push(routeObj);
3407
+ if (namespace) {
3408
+ namespaces.add(namespace);
3409
+ }
3410
+ }
3411
+ function getRoutes() {
3412
+ return [...routes];
3413
+ }
3414
+ function getNamespaceRoutes(namespace) {
3415
+ return routes.filter((r) => r.namespace === namespace);
3416
+ }
3417
+ function unloadNamespace(namespace) {
3418
+ const before = routes.length;
3419
+ for (let i = routes.length - 1; i >= 0; i--) {
3420
+ if (routes[i].namespace === namespace) {
3421
+ const removed = routes[i];
3422
+ routes.splice(i, 1);
3423
+ const depth = getDepth(removed.path);
3424
+ const depthRoutes = routesByDepth.get(depth);
3425
+ if (depthRoutes) {
3426
+ const idx = depthRoutes.indexOf(removed);
3427
+ if (idx >= 0) {
3428
+ depthRoutes.splice(idx, 1);
3429
+ }
3430
+ }
3431
+ }
3432
+ }
3433
+ namespaces.delete(namespace);
3434
+ return before - routes.length;
3435
+ }
3436
+ function clearRoutes() {
3437
+ routes.length = 0;
3438
+ namespaces.clear();
3439
+ routesByDepth.clear();
3440
+ }
3441
+ function normalizeHandler(handler) {
3442
+ if (handler == null) return void 0;
3443
+ if (typeof handler === "function") {
3444
+ return (params, ctx) => {
3445
+ try {
3446
+ return handler(params, ctx);
3447
+ } catch {
3448
+ return handler(params);
3449
+ }
3450
+ };
3451
+ }
3452
+ return void 0;
3453
+ }
3454
+ function registerRoute(path, handler, ...children) {
3455
+ const isRelative = !path.startsWith("/");
3456
+ const descriptor = {
3457
+ path,
3458
+ handler,
3459
+ children: children.filter(Boolean),
3460
+ _isDescriptor: true
3461
+ };
3462
+ if (!isRelative) {
3463
+ const normalized = normalizeHandler(handler);
3464
+ if (handler != null && !normalized) {
3465
+ throw new Error(
3466
+ "registerRoute(path, handler) requires a function handler. Passing JSX elements or VNodes directly is not supported."
3467
+ );
3468
+ }
3469
+ if (normalized) route(path, normalized);
3470
+ for (const child of descriptor.children || []) {
3471
+ const base = path === "/" ? "" : path.replace(/\/$/, "");
3472
+ const childPath = `${base}/${child.path.replace(/^\//, "")}`.replace(
3473
+ /\/\//g,
3474
+ "/"
3475
+ );
3476
+ if (child.handler) {
3477
+ const childNormalized = normalizeHandler(child.handler);
3478
+ if (!childNormalized) {
3479
+ throw new Error(
3480
+ "registerRoute child handler must be a function. Passing JSX elements directly is not supported."
3481
+ );
3482
+ }
3483
+ if (childNormalized) route(childPath, childNormalized);
3484
+ }
3485
+ if (child.children && child.children.length) {
3486
+ registerRoute(
3487
+ childPath,
3488
+ null,
3489
+ ...child.children
3490
+ );
3491
+ }
3492
+ }
3493
+ return descriptor;
3494
+ }
3495
+ return descriptor;
3496
+ }
3497
+ function getLoadedNamespaces() {
3498
+ return Array.from(namespaces);
3499
+ }
3500
+ function resolveRoute(pathname) {
3501
+ const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
3502
+ const depth = normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3503
+ const candidates = [];
3504
+ const depthRoutes = routesByDepth.get(depth);
3505
+ if (depthRoutes) {
3506
+ for (const r of depthRoutes) {
3507
+ const result = match(pathname, r.path);
3508
+ if (result.matched) {
3509
+ candidates.push({
3510
+ route: r,
3511
+ specificity: getSpecificity(r.path),
3512
+ params: result.params
3513
+ });
3514
+ }
3515
+ }
3516
+ }
3517
+ for (const r of routes) {
3518
+ if (depthRoutes?.includes(r)) continue;
3519
+ const result = match(pathname, r.path);
3520
+ if (result.matched) {
3521
+ candidates.push({
3522
+ route: r,
3523
+ specificity: getSpecificity(r.path),
3524
+ params: result.params
3525
+ });
3526
+ }
3527
+ }
3528
+ candidates.sort((a, b) => b.specificity - a.specificity);
3529
+ if (candidates.length > 0) {
3530
+ const best = candidates[0];
3531
+ return { handler: best.route.handler, params: best.params };
3532
+ }
3533
+ return null;
3534
+ }
3535
+ var routes, namespaces, routesByDepth, serverLocation, registrationLocked;
3536
+ var init_route = __esm({
3537
+ "src/router/route.ts"() {
3538
+ "use strict";
3539
+ init_match();
3540
+ init_component();
3541
+ routes = [];
3542
+ namespaces = /* @__PURE__ */ new Set();
3543
+ routesByDepth = /* @__PURE__ */ new Map();
3544
+ serverLocation = null;
3545
+ registrationLocked = false;
3546
+ }
3547
+ });
3548
+
3549
+ // src/router/navigate.ts
3550
+ var navigate_exports = {};
3551
+ __export(navigate_exports, {
3552
+ cleanupNavigation: () => cleanupNavigation,
3553
+ initializeNavigation: () => initializeNavigation,
3554
+ navigate: () => navigate,
3555
+ registerAppInstance: () => registerAppInstance
3556
+ });
3557
+ function registerAppInstance(instance, _path) {
3558
+ currentInstance2 = instance;
3559
+ if (process.env.NODE_ENV === "production") {
3560
+ lockRouteRegistration();
3561
+ }
3562
+ }
3563
+ function navigate(path) {
3564
+ if (typeof window === "undefined") {
3565
+ return;
3566
+ }
3567
+ const resolved = resolveRoute(path);
3568
+ if (!resolved) {
3569
+ if (process.env.NODE_ENV !== "production") {
3570
+ logger.warn(`No route found for path: ${path}`);
3571
+ }
3572
+ return;
3573
+ }
3574
+ window.history.pushState({ path }, "", path);
3575
+ if (currentInstance2) {
3576
+ cleanupComponent(currentInstance2);
3577
+ currentInstance2.fn = resolved.handler;
3578
+ currentInstance2.props = resolved.params;
3579
+ currentInstance2.stateValues = [];
3580
+ currentInstance2.expectedStateIndices = [];
3581
+ currentInstance2.firstRenderComplete = false;
3582
+ currentInstance2.stateIndexCheck = -1;
3583
+ currentInstance2.evaluationGeneration++;
3584
+ currentInstance2.notifyUpdate = null;
3585
+ currentInstance2.abortController = new AbortController();
3586
+ mountComponent(currentInstance2);
3587
+ }
3588
+ }
3589
+ function handlePopState(_event) {
3590
+ const path = window.location.pathname;
3591
+ if (!currentInstance2) {
3592
+ return;
3593
+ }
3594
+ const resolved = resolveRoute(path);
3595
+ if (resolved) {
3596
+ cleanupComponent(currentInstance2);
3597
+ currentInstance2.fn = resolved.handler;
3598
+ currentInstance2.props = resolved.params;
3599
+ currentInstance2.stateValues = [];
3600
+ currentInstance2.expectedStateIndices = [];
3601
+ currentInstance2.firstRenderComplete = false;
3602
+ currentInstance2.stateIndexCheck = -1;
3603
+ currentInstance2.evaluationGeneration++;
3604
+ currentInstance2.notifyUpdate = null;
3605
+ currentInstance2.abortController = new AbortController();
3606
+ mountComponent(currentInstance2);
3607
+ }
3608
+ }
3609
+ function initializeNavigation() {
3610
+ if (typeof window !== "undefined") {
3611
+ window.addEventListener("popstate", handlePopState);
3612
+ }
3613
+ }
3614
+ function cleanupNavigation() {
3615
+ if (typeof window !== "undefined") {
3616
+ window.removeEventListener("popstate", handlePopState);
3617
+ }
3618
+ }
3619
+ var currentInstance2;
3620
+ var init_navigate = __esm({
3621
+ "src/router/navigate.ts"() {
3622
+ "use strict";
3623
+ init_route();
3624
+ init_component();
3625
+ init_logger();
3626
+ currentInstance2 = null;
3627
+ }
3628
+ });
3629
+
3630
+ // src/ssr/sink.ts
3631
+ var StringSink, StreamSink;
3632
+ var init_sink = __esm({
3633
+ "src/ssr/sink.ts"() {
3634
+ "use strict";
3635
+ StringSink = class {
3636
+ constructor() {
3637
+ this.chunks = [];
3638
+ }
3639
+ write(html) {
3640
+ if (html) this.chunks.push(html);
3641
+ }
3642
+ end() {
3643
+ }
3644
+ toString() {
3645
+ return this.chunks.join("");
3646
+ }
3647
+ };
3648
+ StreamSink = class {
3649
+ constructor(onChunk, onComplete) {
3650
+ this.onChunk = onChunk;
3651
+ this.onComplete = onComplete;
3652
+ }
3653
+ write(html) {
3654
+ if (html) this.onChunk(html);
3655
+ }
3656
+ end() {
3657
+ this.onComplete();
3658
+ }
3659
+ };
3660
+ }
3661
+ });
3662
+
3663
+ // src/ssr/render.ts
3664
+ function escapeText(text) {
3665
+ const cached = escapeCache.get(text);
3666
+ if (cached) return cached;
3667
+ const str = String(text);
3668
+ if (!str.includes("&") && !str.includes("<") && !str.includes(">")) {
3669
+ if (escapeCache.size < 256) escapeCache.set(text, str);
3670
+ return str;
3671
+ }
3672
+ const result = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3673
+ if (escapeCache.size < 256) escapeCache.set(text, result);
3674
+ return result;
3675
+ }
3676
+ function escapeAttr(value) {
3677
+ const str = String(value);
3678
+ if (!str.includes("&") && !str.includes('"') && !str.includes("'") && !str.includes("<") && !str.includes(">")) {
3679
+ return str;
3680
+ }
3681
+ return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3682
+ }
3683
+ function styleObjToCss(value) {
3684
+ if (!value || typeof value !== "object") return null;
3685
+ const entries = Object.entries(value);
3686
+ if (entries.length === 0) return "";
3687
+ let out = "";
3688
+ for (const [k, v] of entries) {
3689
+ if (v === null || v === void 0 || v === false) continue;
3690
+ const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
3691
+ out += `${prop}:${String(v)};`;
3692
+ }
3693
+ return out;
3694
+ }
3695
+ function renderAttrs(props) {
3696
+ if (!props || typeof props !== "object") return "";
3697
+ let result = "";
3698
+ for (const [key, value] of Object.entries(props)) {
3699
+ if (key === "children") continue;
3700
+ if (key.startsWith("on") && key[2] === key[2]?.toUpperCase()) continue;
3701
+ if (key.startsWith("_")) continue;
3702
+ const attrName = key === "class" || key === "className" ? "class" : key;
3703
+ if (attrName === "style") {
3704
+ const css = typeof value === "string" ? value : styleObjToCss(value);
3705
+ if (css === null) continue;
3706
+ if (css === "") continue;
3707
+ result += ` style="${escapeAttr(css)}"`;
3708
+ continue;
3709
+ }
3710
+ if (value === true) {
3711
+ result += ` ${attrName}`;
3712
+ } else if (value === false || value === null || value === void 0) {
3713
+ continue;
3714
+ } else {
3715
+ result += ` ${attrName}="${escapeAttr(String(value))}"`;
3716
+ }
3717
+ }
3718
+ return result;
3719
+ }
3720
+ function isVNodeLike(x) {
3721
+ return !!x && typeof x === "object" && "type" in x;
3722
+ }
3723
+ function normalizeChildren(node) {
3724
+ const n = node;
3725
+ const direct = Array.isArray(n?.children) ? n?.children : null;
3726
+ const fromProps = n?.props?.children;
3727
+ const raw = direct ?? fromProps;
3728
+ if (raw === null || raw === void 0 || raw === false) return [];
3729
+ if (Array.isArray(raw)) return raw;
3730
+ return [raw];
3731
+ }
3732
+ function renderChildrenToSink(children, sink, ctx) {
3733
+ for (const c of children)
3734
+ renderNodeToSink(
3735
+ c,
3736
+ sink,
3737
+ ctx
3738
+ );
3739
+ }
3740
+ function executeComponent2(type, props, ctx) {
3741
+ const res = type(props ?? {}, { signal: ctx.signal });
3742
+ if (res && typeof res === "object" && "then" in res && typeof res.then === "function") {
3743
+ throwSSRDataMissing();
3744
+ }
3745
+ return res;
3746
+ }
3747
+ function renderNodeToSink(node, sink, ctx) {
3748
+ if (node === null || node === void 0) return;
3749
+ if (typeof node === "string") {
3750
+ sink.write(escapeText(node));
3751
+ return;
3752
+ }
3753
+ if (typeof node === "number") {
3754
+ sink.write(escapeText(String(node)));
3755
+ return;
3756
+ }
3757
+ if (!isVNodeLike(node)) return;
3758
+ const { type, props } = node;
3759
+ if (typeof type === "function") {
3760
+ const out = withSSRContext(
3761
+ ctx,
3762
+ () => executeComponent2(type, props, ctx)
3763
+ );
3764
+ renderNodeToSink(
3765
+ out,
3766
+ sink,
3767
+ ctx
3768
+ );
3769
+ return;
3770
+ }
3771
+ const tag = String(type);
3772
+ const attrs = renderAttrs(props);
3773
+ if (VOID_ELEMENTS.has(tag)) {
3774
+ sink.write(`<${tag}${attrs} />`);
3775
+ return;
3776
+ }
3777
+ sink.write(`<${tag}${attrs}>`);
3778
+ const children = normalizeChildren(node);
3779
+ renderChildrenToSink(children, sink, ctx);
3780
+ sink.write(`</${tag}>`);
3781
+ }
3782
+ var VOID_ELEMENTS, escapeCache;
3783
+ var init_render = __esm({
3784
+ "src/ssr/render.ts"() {
3785
+ "use strict";
3786
+ init_context2();
3787
+ VOID_ELEMENTS = /* @__PURE__ */ new Set([
3788
+ "area",
3789
+ "base",
3790
+ "br",
3791
+ "col",
3792
+ "embed",
3793
+ "hr",
3794
+ "img",
3795
+ "input",
3796
+ "link",
3797
+ "meta",
3798
+ "param",
3799
+ "source",
3800
+ "track",
3801
+ "wbr"
3802
+ ]);
3803
+ escapeCache = /* @__PURE__ */ new Map();
3804
+ }
3805
+ });
3806
+
3807
+ // src/ssr/index.ts
3808
+ var ssr_exports = {};
3809
+ __export(ssr_exports, {
3810
+ SSRDataMissingError: () => SSRDataMissingError,
3811
+ collectResources: () => collectResources,
3812
+ renderToStream: () => renderToStream,
3813
+ renderToString: () => renderToString,
3814
+ renderToStringSync: () => renderToStringSync,
3815
+ renderToStringSyncForUrl: () => renderToStringSyncForUrl,
3816
+ resolvePlan: () => resolvePlan,
3817
+ resolveResources: () => resolveResources
3818
+ });
3819
+ function escapeText2(text) {
3820
+ const cached = escapeCache2.get(text);
3821
+ if (cached) return cached;
3822
+ const str = String(text);
3823
+ if (!str.includes("&") && !str.includes("<") && !str.includes(">")) {
3824
+ escapeCache2.set(text, str);
3825
+ return str;
3826
+ }
3827
+ const result = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3828
+ if (escapeCache2.size < 256) {
3829
+ escapeCache2.set(text, result);
3830
+ }
3831
+ return result;
3832
+ }
3833
+ function escapeAttr2(value) {
3834
+ const str = String(value);
3835
+ if (!str.includes("&") && !str.includes('"') && !str.includes("'") && !str.includes("<") && !str.includes(">")) {
3836
+ return str;
3837
+ }
3838
+ return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3839
+ }
3840
+ function renderAttrs2(props) {
3841
+ if (!props || typeof props !== "object") return "";
3842
+ let result = "";
3843
+ for (const [key, value] of Object.entries(props)) {
3844
+ if (key.startsWith("on") && key[2] === key[2].toUpperCase()) {
3845
+ continue;
3846
+ }
3847
+ if (key.startsWith("_")) {
3848
+ continue;
3849
+ }
3850
+ const attrName = key === "class" || key === "className" ? "class" : key;
3851
+ if (value === true) {
3852
+ result += ` ${attrName}`;
3853
+ } else if (value === false || value === null || value === void 0) {
3854
+ continue;
3855
+ } else {
3856
+ result += ` ${attrName}="${escapeAttr2(String(value))}"`;
3857
+ }
3858
+ }
3859
+ return result;
3860
+ }
3861
+ function renderChildSync(child, ctx) {
3862
+ if (typeof child === "string") return escapeText2(child);
3863
+ if (typeof child === "number") return escapeText2(String(child));
3864
+ if (child === null || child === void 0 || child === false) return "";
3865
+ if (typeof child === "object" && child !== null && "type" in child) {
3866
+ return renderNodeSync(child, ctx);
3867
+ }
3868
+ return "";
3869
+ }
3870
+ function renderChildrenSync(children, ctx) {
3871
+ if (!children || !Array.isArray(children) || children.length === 0) return "";
3872
+ let result = "";
3873
+ for (const child of children) result += renderChildSync(child, ctx);
3874
+ return result;
3875
+ }
3876
+ function renderNodeSync(node, ctx) {
3877
+ const { type, props } = node;
3878
+ if (typeof type === "function") {
3879
+ const result = executeComponentSync2(type, props, ctx);
3880
+ if (result instanceof Promise) {
3881
+ throwSSRDataMissing();
3882
+ }
3883
+ return renderNodeSync(result, ctx);
3884
+ }
3885
+ const typeStr = type;
3886
+ if (VOID_ELEMENTS2.has(typeStr)) {
3887
+ const attrs2 = renderAttrs2(props);
3888
+ return `<${typeStr}${attrs2} />`;
3889
+ }
3890
+ const attrs = renderAttrs2(props);
3891
+ const children = node.children;
3892
+ const childrenHtml = renderChildrenSync(children, ctx);
3893
+ return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;
3894
+ }
3895
+ function executeComponentSync2(component, props, ctx) {
3896
+ const originalRandom = Math.random;
3897
+ const originalDateNow = Date.now;
3898
+ try {
3899
+ if (process.env.NODE_ENV !== "production") {
3900
+ Math.random = () => {
3901
+ throw new Error(
3902
+ "SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
3903
+ );
3904
+ };
3905
+ Date.now = () => {
3906
+ throw new Error(
3907
+ "SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
3908
+ );
3909
+ };
3910
+ }
3911
+ const prev = getCurrentComponentInstance();
3912
+ const temp = createComponentInstance(
3913
+ "ssr-temp",
3914
+ component,
3915
+ props || {},
3916
+ null
3917
+ );
3918
+ temp.ssr = true;
3919
+ setCurrentComponentInstance(temp);
3920
+ try {
3921
+ return runWithSSRContext(ctx, () => {
3922
+ const result = component(props || {}, { ssr: ctx });
3923
+ if (result instanceof Promise) {
3924
+ throwSSRDataMissing();
3925
+ }
3926
+ return result;
3927
+ });
3928
+ } finally {
3929
+ setCurrentComponentInstance(prev);
3930
+ }
3931
+ } finally {
3932
+ Math.random = originalRandom;
3933
+ Date.now = originalDateNow;
3934
+ }
3935
+ }
3936
+ function renderToStringSync(component, props, options) {
3937
+ const seed = options?.seed ?? 12345;
3938
+ const ctx = createRenderContext(seed);
3939
+ startRenderPhase(options?.data ?? null);
3940
+ try {
3941
+ const node = executeComponentSync2(component, props || {}, ctx);
3942
+ return renderNodeSync(node, ctx);
3943
+ } finally {
3944
+ stopRenderPhase();
3945
+ }
3946
+ }
3947
+ function renderToStringSyncForUrl(opts) {
3948
+ const { url, routes: routes2, options } = opts;
3949
+ const {
3950
+ clearRoutes: clearRoutes2,
3951
+ route: route2,
3952
+ setServerLocation: setServerLocation2,
3953
+ lockRouteRegistration: lockRouteRegistration2,
3954
+ resolveRoute: resolveRoute2
3955
+ } = route_exports;
3956
+ clearRoutes2();
3957
+ for (const r of routes2) {
3958
+ route2(r.path, r.handler, r.namespace);
3959
+ }
3960
+ setServerLocation2(url);
3961
+ if (process.env.NODE_ENV === "production") lockRouteRegistration2();
3962
+ const resolved = resolveRoute2(url);
3963
+ if (!resolved)
3964
+ throw new Error(`renderToStringSync: no route found for url: ${url}`);
3965
+ const seed = options?.seed ?? 12345;
3966
+ const ctx = createRenderContext(seed);
3967
+ startRenderPhase(options?.data ?? null);
3968
+ try {
3969
+ const node = executeComponentSync2(
3970
+ resolved.handler,
3971
+ resolved.params || {},
3972
+ ctx
3973
+ );
3974
+ return renderNodeSync(node, ctx);
3975
+ } finally {
3976
+ stopRenderPhase();
3977
+ }
3978
+ }
3979
+ function renderToString(arg) {
3980
+ if (typeof arg === "function") {
3981
+ return renderToStringSync(
3982
+ arg
3983
+ );
3984
+ }
3985
+ const opts = arg;
3986
+ const sink = new StringSink();
3987
+ renderToSinkInternal({ ...opts, sink });
3988
+ sink.end();
3989
+ return sink.toString();
3990
+ }
3991
+ function renderToStream(opts) {
3992
+ const sink = new StreamSink(opts.onChunk, opts.onComplete);
3993
+ renderToSinkInternal({ ...opts, sink });
3994
+ sink.end();
3995
+ }
3996
+ function renderToSinkInternal(opts) {
3997
+ const { url, routes: routes2, seed = 1, data, sink } = opts;
3998
+ const {
3999
+ clearRoutes: clearRoutes2,
4000
+ route: route2,
4001
+ setServerLocation: setServerLocation2,
4002
+ lockRouteRegistration: lockRouteRegistration2,
4003
+ resolveRoute: resolveRoute2
4004
+ } = route_exports;
4005
+ clearRoutes2();
4006
+ for (const r of routes2) route2(r.path, r.handler, r.namespace);
4007
+ setServerLocation2(url);
4008
+ if (process.env.NODE_ENV === "production") lockRouteRegistration2();
4009
+ const resolved = resolveRoute2(url);
4010
+ if (!resolved) throw new Error(`SSR: no route found for url: ${url}`);
4011
+ const ctx = {
4012
+ url,
4013
+ seed,
4014
+ data,
4015
+ params: resolved.params,
4016
+ signal: void 0
4017
+ };
4018
+ const node = resolved.handler(resolved.params);
4019
+ startRenderPhase(data || null);
4020
+ try {
4021
+ renderNodeToSink(node, sink, ctx);
4022
+ } finally {
4023
+ stopRenderPhase();
4024
+ }
4025
+ }
4026
+ var VOID_ELEMENTS2, escapeCache2;
4027
+ var init_ssr = __esm({
4028
+ "src/ssr/index.ts"() {
4029
+ "use strict";
4030
+ init_route();
4031
+ init_context2();
4032
+ init_component();
4033
+ init_context2();
4034
+ init_sink();
4035
+ init_render();
4036
+ init_data();
4037
+ VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
4038
+ "area",
4039
+ "base",
4040
+ "br",
4041
+ "col",
4042
+ "embed",
4043
+ "hr",
4044
+ "img",
4045
+ "input",
4046
+ "link",
4047
+ "meta",
4048
+ "param",
4049
+ "source",
4050
+ "track",
4051
+ "wbr"
4052
+ ]);
4053
+ escapeCache2 = /* @__PURE__ */ new Map();
4054
+ }
4055
+ });
4056
+
4057
+ // src/index.ts
4058
+ var index_exports = {};
4059
+ __export(index_exports, {
4060
+ Fragment: () => Fragment,
4061
+ Link: () => Link,
4062
+ cleanupApp: () => cleanupApp,
4063
+ clearRoutes: () => clearRoutes,
4064
+ collectResources: () => collectResources,
4065
+ createApp: () => createApp,
4066
+ createIsland: () => createIsland,
4067
+ createSPA: () => createSPA,
4068
+ defineContext: () => defineContext,
4069
+ getLoadedNamespaces: () => getLoadedNamespaces,
4070
+ getNamespaceRoutes: () => getNamespaceRoutes,
4071
+ getRoutes: () => getRoutes,
4072
+ getSignal: () => getSignal,
4073
+ hasApp: () => hasApp,
4074
+ hydrateSPA: () => hydrateSPA,
4075
+ jsx: () => jsx,
4076
+ jsxs: () => jsxs,
4077
+ layout: () => layout,
4078
+ navigate: () => navigate,
4079
+ readContext: () => readContext,
4080
+ renderToStream: () => renderToStream,
4081
+ renderToString: () => renderToString,
4082
+ renderToStringSync: () => renderToStringSync,
4083
+ renderToStringSyncForUrl: () => renderToStringSyncForUrl,
4084
+ resolveResources: () => resolveResources,
4085
+ resource: () => resource,
4086
+ route: () => route,
4087
+ scheduleEventHandler: () => scheduleEventHandler,
4088
+ setServerLocation: () => setServerLocation,
4089
+ state: () => state,
4090
+ unloadNamespace: () => unloadNamespace
4091
+ });
4092
+ module.exports = __toCommonJS(index_exports);
4093
+
4094
+ // src/runtime/state.ts
4095
+ init_scheduler();
4096
+ init_component();
4097
+ init_invariant();
4098
+ init_fastlane();
4099
+ function state(initialValue) {
4100
+ const instance = getCurrentInstance();
4101
+ if (!instance) {
4102
+ throw new Error(
4103
+ "state() can only be called during component render execution. Move state() calls to the top level of your component function."
4104
+ );
4105
+ }
4106
+ const index = getNextStateIndex();
4107
+ const stateValues = instance.stateValues;
4108
+ if (index < instance.stateIndexCheck) {
4109
+ throw new Error(
4110
+ `State index violation: state() call at index ${index}, but previously saw index ${instance.stateIndexCheck}. This happens when state() is called conditionally (inside if/for/etc). Move all state() calls to the top level of your component function, before any conditionals.`
4111
+ );
4112
+ }
4113
+ invariant(
4114
+ index >= instance.stateIndexCheck,
4115
+ "[State] State indices must increase monotonically"
4116
+ );
4117
+ instance.stateIndexCheck = index;
4118
+ if (instance.firstRenderComplete) {
4119
+ if (!instance.expectedStateIndices.includes(index)) {
4120
+ throw new Error(
4121
+ `Hook order violation: state() called at index ${index}, but this index was not in the first render's sequence [${instance.expectedStateIndices.join(", ")}]. This usually means state() is inside a conditional or loop. Move all state() calls to the top level of your component function.`
4122
+ );
4123
+ }
4124
+ } else {
4125
+ instance.expectedStateIndices.push(index);
4126
+ }
4127
+ if (stateValues[index]) {
4128
+ const existing = stateValues[index];
4129
+ if (existing._owner !== instance) {
4130
+ throw new Error(
4131
+ `State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
4132
+ );
4133
+ }
4134
+ return existing;
4135
+ }
4136
+ const cell = createStateCell(initialValue, instance);
4137
+ stateValues[index] = cell;
4138
+ return cell;
4139
+ }
4140
+ function createStateCell(initialValue, instance) {
4141
+ let value = initialValue;
4142
+ const readers = /* @__PURE__ */ new Map();
4143
+ function read() {
4144
+ read._hasBeenRead = true;
4145
+ const inst = getCurrentInstance();
4146
+ if (inst && inst._currentRenderToken !== void 0) {
4147
+ if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
4148
+ inst._pendingReadStates.add(read);
4149
+ }
4150
+ return value;
4151
+ }
4152
+ read._readers = readers;
4153
+ read._owner = instance;
4154
+ read.set = (newValue) => {
4155
+ const currentInst = getCurrentInstance();
4156
+ if (currentInst !== null && process.env.NODE_ENV !== "production") {
4157
+ throw new Error(
4158
+ `[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.`
4159
+ );
4160
+ }
4161
+ if (currentInst !== null && process.env.NODE_ENV === "production") {
4162
+ return;
4163
+ }
4164
+ if (Object.is(value, newValue)) return;
4165
+ if (isBulkCommitActive2()) {
4166
+ value = newValue;
4167
+ return;
4168
+ }
4169
+ value = newValue;
4170
+ const readersMap = read._readers;
4171
+ if (readersMap) {
4172
+ for (const [subInst, token] of readersMap) {
4173
+ if (subInst.lastRenderToken !== token) continue;
4174
+ if (!subInst.hasPendingUpdate) {
4175
+ subInst.hasPendingUpdate = true;
4176
+ const subTask = subInst._pendingFlushTask;
4177
+ if (subTask) globalScheduler.enqueue(subTask);
4178
+ else
4179
+ globalScheduler.enqueue(() => {
4180
+ subInst.hasPendingUpdate = false;
4181
+ subInst.notifyUpdate?.();
4182
+ });
4183
+ }
4184
+ }
4185
+ }
4186
+ const readersMapForOwner = readersMap;
4187
+ const ownerRecordedToken = readersMapForOwner?.get(instance);
4188
+ const ownerShouldEnqueue = (
4189
+ // Normal case: owner read this state in last committed render
4190
+ ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
4191
+ );
4192
+ if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
4193
+ instance.hasPendingUpdate = true;
4194
+ const task = instance._pendingFlushTask;
4195
+ if (task) globalScheduler.enqueue(task);
4196
+ else
4197
+ globalScheduler.enqueue(() => {
4198
+ instance.hasPendingUpdate = false;
4199
+ instance.notifyUpdate?.();
4200
+ });
4201
+ }
4202
+ };
4203
+ return read;
4204
+ }
4205
+
4206
+ // src/index.ts
4207
+ init_component();
4208
+ init_scheduler();
4209
+ init_context();
4210
+
4211
+ // src/runtime/operations.ts
4212
+ init_component();
4213
+ init_context();
4214
+
4215
+ // src/runtime/resource_cell.ts
4216
+ init_context();
4217
+ init_logger();
4218
+ init_context2();
4219
+ var ResourceCell = class {
4220
+ constructor(fn, deps, resourceFrame) {
4221
+ this.value = null;
4222
+ this.pending = true;
4223
+ this.error = null;
4224
+ this.generation = 0;
4225
+ this.controller = null;
4226
+ this.deps = null;
4227
+ this.resourceFrame = null;
4228
+ this.subscribers = /* @__PURE__ */ new Set();
4229
+ this.fn = fn;
4230
+ this.deps = deps ? deps.slice() : null;
4231
+ this.resourceFrame = resourceFrame;
4232
+ this.snapshot = {
4233
+ value: null,
4234
+ pending: true,
4235
+ error: null,
4236
+ refresh: () => this.refresh()
4237
+ };
4238
+ }
4239
+ subscribe(cb) {
4240
+ this.subscribers.add(cb);
4241
+ return () => this.subscribers.delete(cb);
4242
+ }
4243
+ notifySubscribers() {
4244
+ this.snapshot.value = this.value;
4245
+ this.snapshot.pending = this.pending;
4246
+ this.snapshot.error = this.error;
4247
+ for (const cb of this.subscribers) cb();
4248
+ }
4249
+ start(ssr = false, notify = true) {
4250
+ const generation = this.generation;
4251
+ this.controller?.abort();
4252
+ const controller = new AbortController();
4253
+ this.controller = controller;
4254
+ this.pending = true;
4255
+ this.error = null;
4256
+ if (notify) this.notifySubscribers();
4257
+ let result;
4258
+ try {
4259
+ result = withAsyncResourceContext(
4260
+ this.resourceFrame,
4261
+ () => this.fn({ signal: controller.signal })
4262
+ );
4263
+ } catch (err) {
4264
+ this.pending = false;
4265
+ this.error = err;
4266
+ if (notify) this.notifySubscribers();
4267
+ return;
4268
+ }
4269
+ if (!(result instanceof Promise)) {
4270
+ this.value = result;
4271
+ this.pending = false;
4272
+ this.error = null;
4273
+ if (notify) this.notifySubscribers();
4274
+ return;
4275
+ }
4276
+ if (ssr) {
4277
+ throwSSRDataMissing();
4278
+ }
4279
+ result.then((val) => {
4280
+ if (this.generation !== generation) return;
4281
+ if (this.controller !== controller) return;
4282
+ this.value = val;
4283
+ this.pending = false;
4284
+ this.error = null;
4285
+ this.notifySubscribers();
4286
+ }).catch((err) => {
4287
+ if (this.generation !== generation) return;
4288
+ this.pending = false;
4289
+ this.error = err;
4290
+ try {
4291
+ logger.error("[Askr] Async resource error:", err);
4292
+ } catch {
4293
+ }
4294
+ this.notifySubscribers();
4295
+ });
4296
+ }
4297
+ refresh() {
4298
+ this.generation++;
4299
+ this.controller?.abort();
4300
+ this.start();
4301
+ }
4302
+ abort() {
4303
+ this.controller?.abort();
4304
+ }
4305
+ };
4306
+
4307
+ // src/runtime/operations.ts
4308
+ init_context2();
4309
+ init_data();
4310
+ function resource(fn, deps = []) {
4311
+ const instance = getCurrentComponentInstance();
4312
+ const inst = instance;
4313
+ if (!instance) {
4314
+ const renderData2 = getCurrentRenderData();
4315
+ if (renderData2) {
4316
+ const key = getNextKey();
4317
+ if (!(key in renderData2)) {
4318
+ throwSSRDataMissing();
4319
+ }
4320
+ const val = renderData2[key];
4321
+ return {
4322
+ value: val,
4323
+ pending: false,
4324
+ error: null,
4325
+ refresh: () => {
4326
+ }
4327
+ };
4328
+ }
4329
+ const ssrCtx = getCurrentSSRContext();
4330
+ if (ssrCtx) {
4331
+ throwSSRDataMissing();
4332
+ }
4333
+ return {
4334
+ value: null,
4335
+ pending: true,
4336
+ error: null,
4337
+ refresh: () => {
4338
+ }
4339
+ };
4340
+ }
4341
+ const renderData = getCurrentRenderData();
4342
+ if (renderData) {
4343
+ const key = getNextKey();
4344
+ if (!(key in renderData)) {
4345
+ throwSSRDataMissing();
4346
+ }
4347
+ const val = renderData[key];
4348
+ const holder2 = state({
4349
+ cell: void 0,
4350
+ snapshot: {
4351
+ value: val,
4352
+ pending: false,
4353
+ error: null,
4354
+ refresh: () => {
4355
+ }
4356
+ }
4357
+ });
4358
+ const h2 = holder2();
4359
+ h2.snapshot.value = val;
4360
+ h2.snapshot.pending = false;
4361
+ h2.snapshot.error = null;
4362
+ holder2.set(h2);
4363
+ return h2.snapshot;
4364
+ }
4365
+ const holder = state({
4366
+ cell: void 0,
4367
+ snapshot: {
4368
+ value: null,
4369
+ pending: true,
4370
+ error: null,
4371
+ refresh: () => {
4372
+ }
4373
+ }
4374
+ });
4375
+ const h = holder();
4376
+ if (!h.cell) {
4377
+ const frame = getCurrentContextFrame();
4378
+ const cell2 = new ResourceCell(fn, deps, frame);
4379
+ h.cell = cell2;
4380
+ h.snapshot = cell2.snapshot;
4381
+ const unsubscribe = cell2.subscribe(() => {
4382
+ const cur = holder();
4383
+ cur.snapshot.value = cell2.snapshot.value;
4384
+ cur.snapshot.pending = cell2.snapshot.pending;
4385
+ cur.snapshot.error = cell2.snapshot.error;
4386
+ holder.set(cur);
4387
+ try {
4388
+ inst._enqueueRun?.();
4389
+ } catch {
4390
+ }
4391
+ });
4392
+ inst.cleanupFns.push(() => {
4393
+ unsubscribe();
4394
+ cell2.abort();
4395
+ });
4396
+ try {
4397
+ cell2.start(inst.ssr ?? false, false);
4398
+ if (!cell2.pending) {
4399
+ const cur = holder();
4400
+ cur.snapshot.value = cell2.value;
4401
+ cur.snapshot.pending = cell2.pending;
4402
+ cur.snapshot.error = cell2.error;
4403
+ }
4404
+ } catch (err) {
4405
+ if (err instanceof SSRDataMissingError) throw err;
4406
+ cell2.error = err;
4407
+ cell2.pending = false;
4408
+ const cur = holder();
4409
+ cur.snapshot.value = cell2.value;
4410
+ cur.snapshot.pending = cell2.pending;
4411
+ cur.snapshot.error = cell2.error;
4412
+ }
4413
+ }
4414
+ const cell = h.cell;
4415
+ const depsChanged = !cell.deps || cell.deps.length !== deps.length || cell.deps.some((d, i) => d !== deps[i]);
4416
+ if (depsChanged) {
4417
+ cell.deps = deps.slice();
4418
+ cell.generation++;
4419
+ cell.pending = true;
4420
+ cell.error = null;
4421
+ try {
4422
+ cell.start(inst.ssr ?? false, false);
4423
+ if (!cell.pending) {
4424
+ const cur = holder();
4425
+ cur.snapshot.value = cell.value;
4426
+ cur.snapshot.pending = cell.pending;
4427
+ cur.snapshot.error = cell.error;
4428
+ }
4429
+ } catch (err) {
4430
+ if (err instanceof SSRDataMissingError) throw err;
4431
+ cell.error = err;
4432
+ cell.pending = false;
4433
+ const cur = holder();
4434
+ cur.snapshot.value = cell.value;
4435
+ cur.snapshot.pending = cell.pending;
4436
+ cur.snapshot.error = cell.error;
4437
+ }
4438
+ }
4439
+ return h.snapshot;
4440
+ }
4441
+
4442
+ // src/app/createApp.ts
4443
+ init_component();
4444
+ init_scheduler();
4445
+ init_logger();
4446
+ init_dom();
4447
+ init_navigate();
4448
+ var componentIdCounter = 0;
4449
+ var instancesByRoot = /* @__PURE__ */ new WeakMap();
4450
+ var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
4451
+ function createApp(config) {
4452
+ if (!config || typeof config !== "object") {
4453
+ throw new Error("createApp requires a config object");
4454
+ }
4455
+ if ("routes" in config) {
4456
+ throw new Error(
4457
+ "The `createApp` API is removed. Use `createSPA({ root, routes })` for routed apps, or `hydrateSPA({ root, routes })` for SSR hydration."
4458
+ );
4459
+ }
4460
+ const appCfg = config;
4461
+ createIsland({
4462
+ root: appCfg.root,
4463
+ component: appCfg.component
4464
+ });
4465
+ }
4466
+ function attachCleanupForRoot(rootElement, instance) {
4467
+ rootElement[CLEANUP_SYMBOL] = () => {
4468
+ removeAllListeners(rootElement);
4469
+ cleanupComponent(instance);
4470
+ };
4471
+ try {
4472
+ const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
4473
+ Object.getPrototypeOf(rootElement),
4474
+ "innerHTML"
4475
+ ) || Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
4476
+ if (descriptor && (descriptor.get || descriptor.set)) {
4477
+ Object.defineProperty(rootElement, "innerHTML", {
4478
+ get: descriptor.get ? function() {
4479
+ return descriptor.get.call(this);
4480
+ } : void 0,
4481
+ set: function(value) {
4482
+ if (value === "" && instancesByRoot.get(this) === instance) {
4483
+ removeAllListeners(rootElement);
4484
+ cleanupComponent(instance);
4485
+ }
4486
+ if (descriptor.set) {
4487
+ return descriptor.set.call(this, value);
4488
+ }
4489
+ },
4490
+ configurable: true
4491
+ });
4492
+ }
4493
+ } catch {
4494
+ }
4495
+ }
4496
+ function mountOrUpdate(rootElement, componentFn) {
4497
+ const existingCleanup = rootElement[CLEANUP_SYMBOL];
4498
+ if (existingCleanup) existingCleanup();
4499
+ let instance = instancesByRoot.get(rootElement);
4500
+ if (instance) {
4501
+ removeAllListeners(rootElement);
4502
+ cleanupComponent(instance);
4503
+ instance.fn = componentFn;
4504
+ instance.evaluationGeneration++;
4505
+ instance.mounted = false;
4506
+ instance.expectedStateIndices = [];
4507
+ instance.firstRenderComplete = false;
4508
+ instance.isRoot = true;
4509
+ } else {
4510
+ const componentId = String(++componentIdCounter);
4511
+ instance = createComponentInstance(
4512
+ componentId,
4513
+ componentFn,
4514
+ {},
4515
+ rootElement
4516
+ );
4517
+ instancesByRoot.set(rootElement, instance);
4518
+ instance.isRoot = true;
4519
+ }
4520
+ attachCleanupForRoot(rootElement, instance);
4521
+ mountComponent(instance);
4522
+ globalScheduler.flush();
4523
+ }
4524
+ function createIsland(config) {
4525
+ if (!config || typeof config !== "object") {
4526
+ throw new Error("createIsland requires a config object");
4527
+ }
4528
+ if (typeof config.component !== "function") {
4529
+ throw new Error("createIsland: component must be a function");
4530
+ }
4531
+ const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4532
+ if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4533
+ if ("routes" in config) {
4534
+ throw new Error(
4535
+ "createIsland does not accept routes; use createSPA for routed apps"
4536
+ );
4537
+ }
4538
+ mountOrUpdate(rootElement, config.component);
4539
+ }
4540
+ async function createSPA(config) {
4541
+ if (!config || typeof config !== "object") {
4542
+ throw new Error("createSPA requires a config object");
4543
+ }
4544
+ if (!Array.isArray(config.routes) || config.routes.length === 0) {
4545
+ throw new Error(
4546
+ "createSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
4547
+ );
4548
+ }
4549
+ const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4550
+ if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4551
+ const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration: lockRouteRegistration2, resolveRoute: resolveRoute2 } = await Promise.resolve().then(() => (init_route(), route_exports));
4552
+ clearRoutes2();
4553
+ for (const r of config.routes) {
4554
+ route2(r.path, r.handler, r.namespace);
4555
+ }
4556
+ if (process.env.NODE_ENV === "production") lockRouteRegistration2();
4557
+ const path = typeof window !== "undefined" ? window.location.pathname : "/";
4558
+ const resolved = resolveRoute2(path);
4559
+ if (!resolved) {
4560
+ if (process.env.NODE_ENV !== "production") {
4561
+ logger.warn(
4562
+ `createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
4563
+ );
4564
+ }
4565
+ mountOrUpdate(rootElement, () => ({ type: "div", children: [] }));
4566
+ const instance2 = instancesByRoot.get(rootElement);
4567
+ if (!instance2) throw new Error("Internal error: app instance missing");
4568
+ registerAppInstance(instance2, path);
4569
+ initializeNavigation();
4570
+ return;
4571
+ }
4572
+ mountOrUpdate(rootElement, resolved.handler);
4573
+ const instance = instancesByRoot.get(rootElement);
4574
+ if (!instance) throw new Error("Internal error: app instance missing");
4575
+ registerAppInstance(instance, path);
4576
+ initializeNavigation();
4577
+ }
4578
+ async function hydrateSPA(config) {
4579
+ if (!config || typeof config !== "object") {
4580
+ throw new Error("hydrateSPA requires a config object");
4581
+ }
4582
+ if (!Array.isArray(config.routes) || config.routes.length === 0) {
4583
+ throw new Error(
4584
+ "hydrateSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
4585
+ );
4586
+ }
4587
+ const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4588
+ if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4589
+ const serverHTML = rootElement.innerHTML;
4590
+ const {
4591
+ clearRoutes: clearRoutes2,
4592
+ route: route2,
4593
+ setServerLocation: setServerLocation2,
4594
+ lockRouteRegistration: lockRouteRegistration2,
4595
+ resolveRoute: resolveRoute2
4596
+ } = await Promise.resolve().then(() => (init_route(), route_exports));
4597
+ clearRoutes2();
4598
+ for (const r of config.routes) {
4599
+ route2(r.path, r.handler, r.namespace);
4600
+ }
4601
+ const path = typeof window !== "undefined" ? window.location.pathname : "/";
4602
+ setServerLocation2(path);
4603
+ if (process.env.NODE_ENV === "production") lockRouteRegistration2();
4604
+ const resolved = resolveRoute2(path);
4605
+ if (!resolved) {
4606
+ throw new Error(`hydrateSPA: no route found for current path (${path}).`);
4607
+ }
4608
+ const { renderToStringSync: renderToStringSync2 } = await Promise.resolve().then(() => (init_ssr(), ssr_exports));
4609
+ const expectedHTML = renderToStringSync2(() => {
4610
+ const out = resolved.handler(resolved.params);
4611
+ return out ?? {
4612
+ type: "div",
4613
+ children: []
4614
+ };
4615
+ });
4616
+ const serverContainer = document.createElement("div");
4617
+ serverContainer.innerHTML = serverHTML;
4618
+ const expectedContainer = document.createElement("div");
4619
+ expectedContainer.innerHTML = expectedHTML;
4620
+ if (!serverContainer.isEqualNode(expectedContainer)) {
4621
+ throw new Error(
4622
+ "[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output."
4623
+ );
4624
+ }
4625
+ mountOrUpdate(rootElement, resolved.handler);
4626
+ const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await Promise.resolve().then(() => (init_navigate(), navigate_exports));
4627
+ const instance = instancesByRoot.get(rootElement);
4628
+ if (!instance) throw new Error("Internal error: app instance missing");
4629
+ registerAppInstance2(instance, path);
4630
+ initializeNavigation2();
4631
+ }
4632
+ function cleanupApp(root) {
4633
+ const rootElement = typeof root === "string" ? document.getElementById(root) : root;
4634
+ if (!rootElement) return;
4635
+ const cleanupFn = rootElement[CLEANUP_SYMBOL];
4636
+ if (typeof cleanupFn === "function") {
4637
+ cleanupFn();
4638
+ }
4639
+ instancesByRoot.delete(rootElement);
4640
+ }
4641
+ function hasApp(root) {
4642
+ const rootElement = typeof root === "string" ? document.getElementById(root) : root;
4643
+ if (!rootElement) return false;
4644
+ return instancesByRoot.has(rootElement);
4645
+ }
4646
+
4647
+ // src/index.ts
4648
+ init_route();
4649
+
4650
+ // src/router/layouts.ts
4651
+ function layout(Layout) {
4652
+ return (children) => Layout({ children });
4653
+ }
4654
+
4655
+ // src/index.ts
4656
+ init_route();
4657
+ init_navigate();
4658
+
4659
+ // src/components/Link.tsx
4660
+ init_navigate();
4661
+ function Link({ href, children }) {
4662
+ return {
4663
+ type: "a",
4664
+ props: {
4665
+ href,
4666
+ children,
4667
+ onClick: (e) => {
4668
+ const event = e;
4669
+ const button = event.button ?? 0;
4670
+ if (button !== 0 || // not left-click
4671
+ event.ctrlKey || // Ctrl/Cmd+click
4672
+ event.metaKey || // Cmd on Mac
4673
+ event.shiftKey || // Shift+click
4674
+ event.altKey) {
4675
+ return;
4676
+ }
4677
+ event.preventDefault();
4678
+ navigate(href);
4679
+ }
4680
+ }
4681
+ };
4682
+ }
4683
+
4684
+ // src/index.ts
4685
+ init_ssr();
4686
+ init_jsx_runtime();
4687
+ init_route();
4688
+ init_navigate();
4689
+ if (typeof globalThis !== "undefined") {
4690
+ const g = globalThis;
4691
+ if (!g.createApp) g.createApp = createApp;
4692
+ if (!g.createIsland) g.createIsland = createIsland;
4693
+ if (!g.createSPA) g.createSPA = createSPA;
4694
+ if (!g.hydrateSPA) g.hydrateSPA = hydrateSPA;
4695
+ if (!g.route) g.route = route;
4696
+ if (!g.getRoutes) g.getRoutes = getRoutes;
4697
+ if (!g.navigate) g.navigate = navigate;
4698
+ }
4699
+ // Annotate the CommonJS export names for ESM import in node:
4700
+ 0 && (module.exports = {
4701
+ Fragment,
4702
+ Link,
4703
+ cleanupApp,
4704
+ clearRoutes,
4705
+ collectResources,
4706
+ createApp,
4707
+ createIsland,
4708
+ createSPA,
4709
+ defineContext,
4710
+ getLoadedNamespaces,
4711
+ getNamespaceRoutes,
4712
+ getRoutes,
4713
+ getSignal,
4714
+ hasApp,
4715
+ hydrateSPA,
4716
+ jsx,
4717
+ jsxs,
4718
+ layout,
4719
+ navigate,
4720
+ readContext,
4721
+ renderToStream,
4722
+ renderToString,
4723
+ renderToStringSync,
4724
+ renderToStringSyncForUrl,
4725
+ resolveResources,
4726
+ resource,
4727
+ route,
4728
+ scheduleEventHandler,
4729
+ setServerLocation,
4730
+ state,
4731
+ unloadNamespace
4732
+ });
4733
+ //# sourceMappingURL=index.cjs.map