@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
@@ -0,0 +1,3442 @@
1
+ import {
2
+ Fragment,
3
+ init_jsx_runtime
4
+ } from "./chunk-YNH3D4KW.js";
5
+ import {
6
+ __esm,
7
+ __export,
8
+ __toCommonJS
9
+ } from "./chunk-4CV4JOE5.js";
10
+
11
+ // src/dev/invariant.ts
12
+ function invariant(condition, message, context) {
13
+ if (!condition) {
14
+ const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
15
+ throw new Error(`[Askr Invariant] ${message}${contextStr}`);
16
+ }
17
+ }
18
+ function assertSchedulingPrecondition(condition, violationMessage) {
19
+ invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
20
+ }
21
+ var init_invariant = __esm({
22
+ "src/dev/invariant.ts"() {
23
+ "use strict";
24
+ }
25
+ });
26
+
27
+ // src/dev/logger.ts
28
+ function callConsole(method, args) {
29
+ const c = typeof console !== "undefined" ? console : void 0;
30
+ if (!c) return;
31
+ const fn = c[method];
32
+ if (typeof fn === "function") {
33
+ try {
34
+ fn.apply(console, args);
35
+ } catch {
36
+ }
37
+ }
38
+ }
39
+ var logger;
40
+ var init_logger = __esm({
41
+ "src/dev/logger.ts"() {
42
+ "use strict";
43
+ logger = {
44
+ debug: (...args) => {
45
+ if (process.env.NODE_ENV === "production") return;
46
+ callConsole("debug", args);
47
+ },
48
+ info: (...args) => {
49
+ if (process.env.NODE_ENV === "production") return;
50
+ callConsole("info", args);
51
+ },
52
+ warn: (...args) => {
53
+ if (process.env.NODE_ENV === "production") return;
54
+ callConsole("warn", args);
55
+ },
56
+ error: (...args) => {
57
+ callConsole("error", args);
58
+ }
59
+ };
60
+ }
61
+ });
62
+
63
+ // src/runtime/scheduler.ts
64
+ function isBulkCommitActive() {
65
+ try {
66
+ const fb = globalThis.__ASKR_FASTLANE;
67
+ return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
68
+ } catch (e) {
69
+ void e;
70
+ return false;
71
+ }
72
+ }
73
+ function isSchedulerExecuting() {
74
+ return globalScheduler.isExecuting();
75
+ }
76
+ function scheduleEventHandler(handler) {
77
+ return (event) => {
78
+ globalScheduler.setInHandler(true);
79
+ try {
80
+ handler.call(null, event);
81
+ } catch (error) {
82
+ logger.error("[Askr] Event handler error:", error);
83
+ } finally {
84
+ globalScheduler.setInHandler(false);
85
+ const state = globalScheduler.getState();
86
+ if ((state.queueLength ?? 0) > 0 && !state.running) {
87
+ queueMicrotask(() => {
88
+ try {
89
+ if (!globalScheduler.isExecuting()) globalScheduler.flush();
90
+ } catch (err) {
91
+ setTimeout(() => {
92
+ throw err;
93
+ });
94
+ }
95
+ });
96
+ }
97
+ }
98
+ };
99
+ }
100
+ var MAX_FLUSH_DEPTH, Scheduler, globalScheduler;
101
+ var init_scheduler = __esm({
102
+ "src/runtime/scheduler.ts"() {
103
+ "use strict";
104
+ init_invariant();
105
+ init_logger();
106
+ MAX_FLUSH_DEPTH = 50;
107
+ Scheduler = class {
108
+ constructor() {
109
+ this.q = [];
110
+ this.head = 0;
111
+ this.running = false;
112
+ this.inHandler = false;
113
+ this.depth = 0;
114
+ this.executionDepth = 0;
115
+ // for compat with existing diagnostics
116
+ // Monotonic flush version increments at end of each flush
117
+ this.flushVersion = 0;
118
+ // Best-effort microtask kick scheduling
119
+ this.kickScheduled = false;
120
+ // Escape hatch flag for runWithSyncProgress
121
+ this.allowSyncProgress = false;
122
+ // Waiters waiting for flushVersion >= target
123
+ this.waiters = [];
124
+ // Keep a lightweight taskCount for compatibility/diagnostics
125
+ this.taskCount = 0;
126
+ }
127
+ enqueue(task) {
128
+ assertSchedulingPrecondition(
129
+ typeof task === "function",
130
+ "enqueue() requires a function"
131
+ );
132
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
133
+ if (process.env.NODE_ENV !== "production") {
134
+ throw new Error(
135
+ "[Scheduler] enqueue() during bulk commit (not allowed)"
136
+ );
137
+ }
138
+ return;
139
+ }
140
+ this.q.push(task);
141
+ this.taskCount++;
142
+ if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
143
+ this.kickScheduled = true;
144
+ queueMicrotask(() => {
145
+ this.kickScheduled = false;
146
+ if (this.running) return;
147
+ if (isBulkCommitActive()) return;
148
+ try {
149
+ this.flush();
150
+ } catch (err) {
151
+ setTimeout(() => {
152
+ throw err;
153
+ });
154
+ }
155
+ });
156
+ }
157
+ }
158
+ flush() {
159
+ invariant(
160
+ !this.running,
161
+ "[Scheduler] flush() called while already running"
162
+ );
163
+ if (process.env.NODE_ENV !== "production") {
164
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
165
+ throw new Error(
166
+ "[Scheduler] flush() started during bulk commit (not allowed)"
167
+ );
168
+ }
169
+ }
170
+ this.running = true;
171
+ this.depth = 0;
172
+ let fatal = null;
173
+ try {
174
+ while (this.head < this.q.length) {
175
+ this.depth++;
176
+ if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
177
+ throw new Error(
178
+ `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
179
+ );
180
+ }
181
+ const task = this.q[this.head++];
182
+ try {
183
+ this.executionDepth++;
184
+ task();
185
+ this.executionDepth--;
186
+ } catch (err) {
187
+ if (this.executionDepth > 0) this.executionDepth = 0;
188
+ fatal = err;
189
+ break;
190
+ }
191
+ if (this.taskCount > 0) this.taskCount--;
192
+ }
193
+ } finally {
194
+ this.running = false;
195
+ this.depth = 0;
196
+ this.executionDepth = 0;
197
+ if (this.head >= this.q.length) {
198
+ this.q.length = 0;
199
+ this.head = 0;
200
+ } else if (this.head > 0) {
201
+ const remaining = this.q.length - this.head;
202
+ if (this.head > 1024 || this.head > remaining) {
203
+ this.q = this.q.slice(this.head);
204
+ } else {
205
+ for (let i = 0; i < remaining; i++) {
206
+ this.q[i] = this.q[this.head + i];
207
+ }
208
+ this.q.length = remaining;
209
+ }
210
+ this.head = 0;
211
+ }
212
+ this.flushVersion++;
213
+ this.resolveWaiters();
214
+ }
215
+ if (fatal) throw fatal;
216
+ }
217
+ runWithSyncProgress(fn) {
218
+ const prev = this.allowSyncProgress;
219
+ this.allowSyncProgress = true;
220
+ const g = globalThis;
221
+ const origQueueMicrotask = g.queueMicrotask;
222
+ const origSetTimeout = g.setTimeout;
223
+ if (process.env.NODE_ENV !== "production") {
224
+ g.queueMicrotask = () => {
225
+ throw new Error(
226
+ "[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
227
+ );
228
+ };
229
+ g.setTimeout = () => {
230
+ throw new Error(
231
+ "[Scheduler] setTimeout not allowed during runWithSyncProgress"
232
+ );
233
+ };
234
+ }
235
+ const startVersion = this.flushVersion;
236
+ try {
237
+ const res = fn();
238
+ if (!this.running && this.q.length - this.head > 0) {
239
+ this.flush();
240
+ }
241
+ if (process.env.NODE_ENV !== "production") {
242
+ if (this.q.length - this.head > 0) {
243
+ throw new Error(
244
+ "[Scheduler] tasks remain after runWithSyncProgress flush"
245
+ );
246
+ }
247
+ }
248
+ return res;
249
+ } finally {
250
+ if (process.env.NODE_ENV !== "production") {
251
+ g.queueMicrotask = origQueueMicrotask;
252
+ g.setTimeout = origSetTimeout;
253
+ }
254
+ try {
255
+ if (this.flushVersion === startVersion) {
256
+ this.flushVersion++;
257
+ this.resolveWaiters();
258
+ }
259
+ } catch (e) {
260
+ void e;
261
+ }
262
+ this.allowSyncProgress = prev;
263
+ }
264
+ }
265
+ waitForFlush(targetVersion, timeoutMs = 2e3) {
266
+ const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
267
+ if (this.flushVersion >= target) return Promise.resolve();
268
+ return new Promise((resolve, reject) => {
269
+ const timer = setTimeout(() => {
270
+ const diag = {
271
+ flushVersion: this.flushVersion,
272
+ queueLen: this.q.length - this.head,
273
+ running: this.running,
274
+ inHandler: this.inHandler,
275
+ bulk: isBulkCommitActive(),
276
+ globals: {
277
+ __ASKR_LAST_FASTPATH_STATS: globalThis.__ASKR_LAST_FASTPATH_STATS,
278
+ __ASKR_LAST_BULK_TEXT_FASTPATH_STATS: globalThis.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS,
279
+ __ASKR_FASTPATH_COUNTERS: globalThis.__ASKR_FASTPATH_COUNTERS
280
+ }
281
+ };
282
+ reject(
283
+ new Error(
284
+ `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
285
+ )
286
+ );
287
+ }, timeoutMs);
288
+ this.waiters.push({ target, resolve, reject, timer });
289
+ });
290
+ }
291
+ getState() {
292
+ return {
293
+ queueLength: this.q.length - this.head,
294
+ running: this.running,
295
+ depth: this.depth,
296
+ executionDepth: this.executionDepth,
297
+ taskCount: this.taskCount,
298
+ flushVersion: this.flushVersion,
299
+ // New fields for optional inspection
300
+ inHandler: this.inHandler,
301
+ allowSyncProgress: this.allowSyncProgress
302
+ };
303
+ }
304
+ setInHandler(v) {
305
+ this.inHandler = v;
306
+ }
307
+ isInHandler() {
308
+ return this.inHandler;
309
+ }
310
+ isExecuting() {
311
+ return this.running || this.executionDepth > 0;
312
+ }
313
+ // Clear pending synchronous tasks (used by fastlane enter/exit)
314
+ clearPendingSyncTasks() {
315
+ const remaining = this.q.length - this.head;
316
+ if (remaining <= 0) return 0;
317
+ if (this.running) {
318
+ this.q.length = this.head;
319
+ this.taskCount = Math.max(0, this.taskCount - remaining);
320
+ queueMicrotask(() => {
321
+ try {
322
+ this.flushVersion++;
323
+ this.resolveWaiters();
324
+ } catch (e) {
325
+ void e;
326
+ }
327
+ });
328
+ return remaining;
329
+ }
330
+ this.q.length = 0;
331
+ this.head = 0;
332
+ this.taskCount = Math.max(0, this.taskCount - remaining);
333
+ this.flushVersion++;
334
+ this.resolveWaiters();
335
+ return remaining;
336
+ }
337
+ resolveWaiters() {
338
+ if (this.waiters.length === 0) return;
339
+ const ready = [];
340
+ const remaining = [];
341
+ for (const w of this.waiters) {
342
+ if (this.flushVersion >= w.target) {
343
+ if (w.timer) clearTimeout(w.timer);
344
+ ready.push(w.resolve);
345
+ } else {
346
+ remaining.push(w);
347
+ }
348
+ }
349
+ this.waiters = remaining;
350
+ for (const r of ready) r();
351
+ }
352
+ };
353
+ globalScheduler = new Scheduler();
354
+ }
355
+ });
356
+
357
+ // src/runtime/fastlane.ts
358
+ function enterBulkCommit() {
359
+ _bulkCommitActive = true;
360
+ _appliedParents = /* @__PURE__ */ new WeakSet();
361
+ try {
362
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
363
+ if (process.env.NODE_ENV !== "production") {
364
+ const _g = globalThis;
365
+ _g.__ASKR_FASTLANE_CLEARED_TASKS = cleared;
366
+ }
367
+ } catch (err) {
368
+ if (process.env.NODE_ENV !== "production") throw err;
369
+ }
370
+ }
371
+ function exitBulkCommit() {
372
+ _bulkCommitActive = false;
373
+ _appliedParents = null;
374
+ }
375
+ function isBulkCommitActive2() {
376
+ return _bulkCommitActive;
377
+ }
378
+ function markFastPathApplied(parent) {
379
+ if (!_appliedParents) return;
380
+ try {
381
+ _appliedParents.add(parent);
382
+ } catch (e) {
383
+ void e;
384
+ }
385
+ }
386
+ function isFastPathApplied(parent) {
387
+ return !!(_appliedParents && _appliedParents.has(parent));
388
+ }
389
+ function classifyUpdate(instance, result) {
390
+ if (!result || typeof result !== "object" || !("type" in result))
391
+ return { useFastPath: false, reason: "not-vnode" };
392
+ const vnode = result;
393
+ if (vnode == null || typeof vnode.type !== "string")
394
+ return { useFastPath: false, reason: "not-intrinsic" };
395
+ const parent = instance.target;
396
+ if (!parent) return { useFastPath: false, reason: "no-root" };
397
+ const firstChild = parent.children[0];
398
+ if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
399
+ if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
400
+ return { useFastPath: false, reason: "root-tag-mismatch" };
401
+ const children = vnode.children || vnode.props?.children;
402
+ if (!Array.isArray(children))
403
+ return { useFastPath: false, reason: "no-children-array" };
404
+ for (let i = 0; i < children.length; i++) {
405
+ const c = children[i];
406
+ if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
407
+ return { useFastPath: false, reason: "component-child-present" };
408
+ }
409
+ }
410
+ if (instance.mountOperations.length > 0)
411
+ return { useFastPath: false, reason: "pending-mounts" };
412
+ const oldKeyMap = getKeyMapForElement(firstChild);
413
+ const decision = isKeyedReorderFastPathEligible(
414
+ firstChild,
415
+ children,
416
+ oldKeyMap
417
+ );
418
+ if (!decision.useFastPath || decision.totalKeyed < 128)
419
+ return { ...decision, useFastPath: false, reason: "renderer-declined" };
420
+ return { ...decision, useFastPath: true };
421
+ }
422
+ function commitReorderOnly(instance, result) {
423
+ const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
424
+ if (typeof evaluate2 !== "function") {
425
+ logger.warn(
426
+ "[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
427
+ );
428
+ return false;
429
+ }
430
+ const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
431
+ enterBulkCommit();
432
+ try {
433
+ globalScheduler.runWithSyncProgress(() => {
434
+ evaluate2(result, instance.target);
435
+ try {
436
+ const comp = (init_component(), __toCommonJS(component_exports));
437
+ if (typeof comp?.finalizeReadSubscriptions === "function") {
438
+ try {
439
+ comp.finalizeReadSubscriptions(instance);
440
+ } catch (e) {
441
+ if (process.env.NODE_ENV !== "production") throw e;
442
+ }
443
+ }
444
+ } catch (e) {
445
+ void e;
446
+ }
447
+ });
448
+ try {
449
+ const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
450
+ if (process.env.NODE_ENV !== "production") {
451
+ const _g = globalThis;
452
+ _g.__ASKR_FASTLANE_CLEARED_AFTER = clearedAfter;
453
+ }
454
+ } catch (err) {
455
+ if (process.env.NODE_ENV !== "production") throw err;
456
+ }
457
+ if (process.env.NODE_ENV !== "production") {
458
+ const _g = globalThis;
459
+ const commitCount = _g.__ASKR_LAST_FASTPATH_COMMIT_COUNT ?? 0;
460
+ const invariants = {
461
+ commitCount,
462
+ mountOps: instance.mountOperations.length,
463
+ cleanupFns: instance.cleanupFns.length
464
+ };
465
+ _g.__ASKR_LAST_FASTLANE_INVARIANTS = invariants;
466
+ if (commitCount !== 1) {
467
+ throw new Error(
468
+ "Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
469
+ );
470
+ }
471
+ if (invariants.mountOps > 0) {
472
+ throw new Error(
473
+ "Fast-lane invariant violated: mount operations were registered during bulk commit"
474
+ );
475
+ }
476
+ if (invariants.cleanupFns > 0) {
477
+ throw new Error(
478
+ "Fast-lane invariant violated: cleanup functions were added during bulk commit"
479
+ );
480
+ }
481
+ const schedAfter = globalScheduler.getState();
482
+ if (schedBefore && schedAfter && // Only fail if outstanding tasks increased — consuming existing tasks is allowed
483
+ schedAfter.taskCount > schedBefore.taskCount) {
484
+ try {
485
+ console.error(
486
+ "[FASTLANE] schedBefore, schedAfter",
487
+ schedBefore,
488
+ schedAfter
489
+ );
490
+ console.error(
491
+ "[FASTLANE] enqueue logs",
492
+ globalThis.__ASKR_ENQUEUE_LOGS
493
+ );
494
+ } catch (e) {
495
+ void e;
496
+ }
497
+ throw new Error(
498
+ "Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
499
+ );
500
+ }
501
+ let finalState = globalScheduler.getState();
502
+ const executing = globalScheduler.isExecuting();
503
+ const outstandingAfter = Math.max(
504
+ 0,
505
+ finalState.taskCount - (executing ? 1 : 0)
506
+ );
507
+ if (outstandingAfter !== 0) {
508
+ if (process.env.NODE_ENV !== "production") {
509
+ let attempts = 0;
510
+ while (attempts < 5) {
511
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
512
+ if (cleared === 0) break;
513
+ attempts++;
514
+ }
515
+ finalState = globalScheduler.getState();
516
+ const outstandingAfter2 = Math.max(
517
+ 0,
518
+ finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
519
+ );
520
+ if (outstandingAfter2 !== 0) {
521
+ try {
522
+ const _g2 = globalThis;
523
+ console.error(
524
+ "[FASTLANE] Post-commit enqueue logs:",
525
+ _g2.__ASKR_ENQUEUE_LOGS
526
+ );
527
+ console.error(
528
+ "[FASTLANE] Cleared counts:",
529
+ _g2.__ASKR_FASTLANE_CLEARED_TASKS,
530
+ _g2.__ASKR_FASTLANE_CLEARED_AFTER
531
+ );
532
+ } catch (err) {
533
+ void err;
534
+ }
535
+ throw new Error(
536
+ `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
537
+ );
538
+ }
539
+ } else {
540
+ globalScheduler.clearPendingSyncTasks?.();
541
+ }
542
+ }
543
+ }
544
+ return true;
545
+ } finally {
546
+ exitBulkCommit();
547
+ if (process.env.NODE_ENV !== "production") {
548
+ try {
549
+ const _g = globalThis;
550
+ _g.__ASKR_FASTLANE_BULK_FLAG_CHECK = isBulkCommitActive2();
551
+ } catch (e) {
552
+ void e;
553
+ }
554
+ }
555
+ }
556
+ if (process.env.NODE_ENV !== "production") {
557
+ const _g = globalThis;
558
+ if (_g.__ASKR_FASTLANE_BULK_FLAG_CHECK) {
559
+ delete _g.__ASKR_FASTLANE_BULK_FLAG_CHECK;
560
+ throw new Error(
561
+ "Fast-lane invariant violated: bulk commit flag still set after commit"
562
+ );
563
+ }
564
+ }
565
+ }
566
+ function tryRuntimeFastLaneSync(instance, result) {
567
+ const cls = classifyUpdate(instance, result);
568
+ if (!cls.useFastPath) return false;
569
+ try {
570
+ return commitReorderOnly(instance, result);
571
+ } catch (err) {
572
+ if (process.env.NODE_ENV !== "production") throw err;
573
+ return false;
574
+ }
575
+ }
576
+ var _bulkCommitActive, _appliedParents;
577
+ var init_fastlane = __esm({
578
+ "src/runtime/fastlane.ts"() {
579
+ "use strict";
580
+ init_scheduler();
581
+ init_logger();
582
+ init_dom();
583
+ _bulkCommitActive = false;
584
+ _appliedParents = null;
585
+ if (typeof globalThis !== "undefined") {
586
+ const _g = globalThis;
587
+ _g.__ASKR_FASTLANE = {
588
+ isBulkCommitActive: isBulkCommitActive2,
589
+ enterBulkCommit,
590
+ exitBulkCommit,
591
+ tryRuntimeFastLaneSync,
592
+ markFastPathApplied,
593
+ isFastPathApplied
594
+ };
595
+ }
596
+ }
597
+ });
598
+
599
+ // src/runtime/context.ts
600
+ function withContext(frame, fn) {
601
+ const oldFrame = currentContextFrame;
602
+ currentContextFrame = frame;
603
+ try {
604
+ return fn();
605
+ } finally {
606
+ currentContextFrame = oldFrame;
607
+ }
608
+ }
609
+ function withAsyncResourceContext(frame, fn) {
610
+ const oldFrame = currentAsyncResourceFrame;
611
+ currentAsyncResourceFrame = frame;
612
+ try {
613
+ return fn();
614
+ } finally {
615
+ currentAsyncResourceFrame = oldFrame;
616
+ }
617
+ }
618
+ function defineContext(defaultValue) {
619
+ const key = /* @__PURE__ */ Symbol("AskrContext");
620
+ return {
621
+ key,
622
+ defaultValue,
623
+ Scope: (props) => {
624
+ return {
625
+ type: ContextScopeComponent,
626
+ props: { key, value: props.value, children: props.children }
627
+ };
628
+ }
629
+ };
630
+ }
631
+ function readContext(context) {
632
+ const frame = currentContextFrame || currentAsyncResourceFrame;
633
+ if (!frame) {
634
+ throw new Error(
635
+ "readContext() can only be called during component render or async resource execution. Ensure you are calling this from inside your component or resource function."
636
+ );
637
+ }
638
+ let current = frame;
639
+ while (current) {
640
+ const values = current.values;
641
+ if (values && values.has(context.key)) {
642
+ return values.get(context.key);
643
+ }
644
+ current = current.parent;
645
+ }
646
+ return context.defaultValue;
647
+ }
648
+ function ContextScopeComponent(props) {
649
+ const key = props["key"];
650
+ const value = props["value"];
651
+ const children = props["children"];
652
+ const instance = getCurrentComponentInstance();
653
+ const parentFrame = (() => {
654
+ if (currentContextFrame) return currentContextFrame;
655
+ if (instance && instance.ownerFrame) return instance.ownerFrame;
656
+ return null;
657
+ })();
658
+ const newFrame = {
659
+ parent: parentFrame,
660
+ values: /* @__PURE__ */ new Map([[key, value]])
661
+ };
662
+ if (Array.isArray(children)) {
663
+ return children.map((child) => {
664
+ if (typeof child === "function") {
665
+ return {
666
+ type: ContextFunctionChildInvoker,
667
+ props: {
668
+ fn: child,
669
+ __frame: newFrame,
670
+ __owner: getCurrentComponentInstance()
671
+ }
672
+ };
673
+ }
674
+ return markWithFrame(child, newFrame);
675
+ });
676
+ } else if (typeof children === "function") {
677
+ return {
678
+ type: ContextFunctionChildInvoker,
679
+ props: {
680
+ fn: children,
681
+ __frame: newFrame,
682
+ __owner: getCurrentComponentInstance()
683
+ }
684
+ };
685
+ } else if (children) {
686
+ return markWithFrame(children, newFrame);
687
+ }
688
+ return null;
689
+ }
690
+ function markWithFrame(node, frame) {
691
+ if (typeof node === "object" && node !== null) {
692
+ const obj = node;
693
+ obj[CONTEXT_FRAME_SYMBOL] = frame;
694
+ const children = obj.children;
695
+ if (Array.isArray(children)) {
696
+ for (let i = 0; i < children.length; i++) {
697
+ const child = children[i];
698
+ if (child) {
699
+ children[i] = markWithFrame(child, frame);
700
+ }
701
+ }
702
+ } else if (children) {
703
+ obj.children = markWithFrame(children, frame);
704
+ }
705
+ }
706
+ return node;
707
+ }
708
+ function ContextFunctionChildInvoker(props) {
709
+ const { fn, __frame } = props;
710
+ const res = withContext(__frame, () => fn());
711
+ if (res) return markWithFrame(res, __frame);
712
+ return null;
713
+ }
714
+ function getCurrentContextFrame() {
715
+ return currentContextFrame;
716
+ }
717
+ var CONTEXT_FRAME_SYMBOL, currentContextFrame, currentAsyncResourceFrame;
718
+ var init_context = __esm({
719
+ "src/runtime/context.ts"() {
720
+ "use strict";
721
+ init_component();
722
+ CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
723
+ currentContextFrame = null;
724
+ currentAsyncResourceFrame = null;
725
+ }
726
+ });
727
+
728
+ // src/renderer/dom.ts
729
+ function cleanupInstanceIfPresent(node) {
730
+ if (!node) return;
731
+ if (!(node instanceof Element)) return;
732
+ try {
733
+ const inst = node.__ASKR_INSTANCE;
734
+ if (inst) {
735
+ cleanupComponent(inst);
736
+ try {
737
+ delete node.__ASKR_INSTANCE;
738
+ } catch (e) {
739
+ void e;
740
+ }
741
+ }
742
+ } catch (err) {
743
+ void err;
744
+ }
745
+ try {
746
+ const descendants = node.querySelectorAll("*");
747
+ for (const d of Array.from(descendants)) {
748
+ try {
749
+ const inst = d.__ASKR_INSTANCE;
750
+ if (inst) {
751
+ cleanupComponent(inst);
752
+ try {
753
+ delete d.__ASKR_INSTANCE;
754
+ } catch (e) {
755
+ void e;
756
+ }
757
+ }
758
+ } catch (err) {
759
+ void err;
760
+ }
761
+ }
762
+ } catch (err) {
763
+ void err;
764
+ }
765
+ }
766
+ function _isDOMElement(node) {
767
+ return typeof node === "object" && node !== null && "type" in node;
768
+ }
769
+ function getKeyMapForElement(el) {
770
+ return keyedElements.get(el);
771
+ }
772
+ function removeElementListeners(element) {
773
+ const map = elementListeners.get(element);
774
+ if (map) {
775
+ for (const [eventName, entry] of map) {
776
+ element.removeEventListener(eventName, entry.handler);
777
+ }
778
+ elementListeners.delete(element);
779
+ }
780
+ }
781
+ function removeAllListeners(root) {
782
+ if (!root) return;
783
+ removeElementListeners(root);
784
+ const children = root.querySelectorAll("*");
785
+ for (let i = 0; i < children.length; i++) {
786
+ removeElementListeners(children[i]);
787
+ }
788
+ }
789
+ function evaluate(node, target, context) {
790
+ if (!target) return;
791
+ if (context && domRanges.has(context)) {
792
+ const range = domRanges.get(context);
793
+ let current = range.start.nextSibling;
794
+ while (current && current !== range.end) {
795
+ const next = current.nextSibling;
796
+ current.remove();
797
+ current = next;
798
+ }
799
+ const dom = createDOMNode(node);
800
+ if (dom) {
801
+ target.insertBefore(dom, range.end);
802
+ }
803
+ } else if (context) {
804
+ const start = document.createComment("component-start");
805
+ const end = document.createComment("component-end");
806
+ target.appendChild(start);
807
+ target.appendChild(end);
808
+ domRanges.set(context, { start, end });
809
+ const dom = createDOMNode(node);
810
+ if (dom) {
811
+ target.insertBefore(dom, end);
812
+ }
813
+ } else {
814
+ const vnode = node;
815
+ const firstChild = target.children[0];
816
+ if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && firstChild.tagName.toLowerCase() === vnode.type.toLowerCase()) {
817
+ const vnodeChildren = vnode.children || vnode.props?.children;
818
+ let isSimpleTextVNode = false;
819
+ let textContent;
820
+ if (!Array.isArray(vnodeChildren)) {
821
+ if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
822
+ isSimpleTextVNode = true;
823
+ textContent = String(vnodeChildren);
824
+ }
825
+ } else if (vnodeChildren.length === 1) {
826
+ const child = vnodeChildren[0];
827
+ if (typeof child === "string" || typeof child === "number") {
828
+ isSimpleTextVNode = true;
829
+ textContent = String(child);
830
+ }
831
+ }
832
+ if (isSimpleTextVNode && firstChild.childNodes.length === 1 && firstChild.firstChild?.nodeType === 3) {
833
+ firstChild.firstChild.data = textContent;
834
+ } else {
835
+ if (vnodeChildren) {
836
+ if (Array.isArray(vnodeChildren)) {
837
+ const hasKeys = vnodeChildren.some(
838
+ (child) => typeof child === "object" && child !== null && "key" in child
839
+ );
840
+ if (hasKeys) {
841
+ let oldKeyMap = keyedElements.get(firstChild);
842
+ if (!oldKeyMap) {
843
+ oldKeyMap = /* @__PURE__ */ new Map();
844
+ }
845
+ try {
846
+ if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
847
+ try {
848
+ const keyedVnodes = [];
849
+ for (let i = 0; i < vnodeChildren.length; i++) {
850
+ const c = vnodeChildren[i];
851
+ if (_isDOMElement(c) && c.key !== void 0) {
852
+ keyedVnodes.push({
853
+ key: c.key,
854
+ vnode: c
855
+ });
856
+ }
857
+ }
858
+ if (keyedVnodes.length > 0 && keyedVnodes.length === vnodeChildren.length) {
859
+ logger.warn(
860
+ "[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
861
+ );
862
+ const stats = performBulkPositionalKeyedTextUpdate(
863
+ firstChild,
864
+ keyedVnodes
865
+ );
866
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
867
+ try {
868
+ const gl = globalThis;
869
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
870
+ gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
871
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
872
+ counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
873
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
874
+ } catch (e) {
875
+ void e;
876
+ }
877
+ }
878
+ try {
879
+ const map = /* @__PURE__ */ new Map();
880
+ const children = Array.from(firstChild.children);
881
+ for (let i = 0; i < children.length; i++) {
882
+ const el = children[i];
883
+ const k = el.getAttribute("data-key");
884
+ if (k !== null) {
885
+ map.set(k, el);
886
+ const n = Number(k);
887
+ if (!Number.isNaN(n)) map.set(n, el);
888
+ }
889
+ }
890
+ keyedElements.set(firstChild, map);
891
+ } catch (e) {
892
+ void e;
893
+ }
894
+ } else {
895
+ const newKeyMap = reconcileKeyedChildren(
896
+ firstChild,
897
+ vnodeChildren,
898
+ oldKeyMap
899
+ );
900
+ keyedElements.set(firstChild, newKeyMap);
901
+ }
902
+ } catch (err) {
903
+ logger.warn(
904
+ "[Askr][FASTPATH] forced bulk path failed, falling back",
905
+ err
906
+ );
907
+ const newKeyMap = reconcileKeyedChildren(
908
+ firstChild,
909
+ vnodeChildren,
910
+ oldKeyMap
911
+ );
912
+ keyedElements.set(firstChild, newKeyMap);
913
+ }
914
+ } else {
915
+ const newKeyMap = reconcileKeyedChildren(
916
+ firstChild,
917
+ vnodeChildren,
918
+ oldKeyMap
919
+ );
920
+ keyedElements.set(firstChild, newKeyMap);
921
+ }
922
+ } catch (e) {
923
+ void e;
924
+ const newKeyMap = reconcileKeyedChildren(
925
+ firstChild,
926
+ vnodeChildren,
927
+ oldKeyMap
928
+ );
929
+ keyedElements.set(firstChild, newKeyMap);
930
+ }
931
+ } else {
932
+ if (isBulkTextFastPathEligible(firstChild, vnodeChildren)) {
933
+ const stats = performBulkTextReplace(firstChild, vnodeChildren);
934
+ if (process.env.NODE_ENV !== "production") {
935
+ try {
936
+ const gl = globalThis;
937
+ gl.__ASKR_LAST_BULK_TEXT_FASTPATH_STATS = stats;
938
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
939
+ counters.bulkTextHits = (counters.bulkTextHits || 0) + 1;
940
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
941
+ } catch (e) {
942
+ void e;
943
+ }
944
+ }
945
+ } else {
946
+ if (process.env.NODE_ENV !== "production") {
947
+ try {
948
+ const gl = globalThis;
949
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
950
+ counters.bulkTextMisses = (counters.bulkTextMisses || 0) + 1;
951
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
952
+ } catch (e) {
953
+ void e;
954
+ }
955
+ }
956
+ updateUnkeyedChildren(firstChild, vnodeChildren);
957
+ keyedElements.delete(firstChild);
958
+ }
959
+ }
960
+ } else {
961
+ firstChild.textContent = "";
962
+ const dom = createDOMNode(vnodeChildren);
963
+ if (dom) firstChild.appendChild(dom);
964
+ keyedElements.delete(firstChild);
965
+ }
966
+ } else {
967
+ firstChild.textContent = "";
968
+ keyedElements.delete(firstChild);
969
+ }
970
+ }
971
+ updateElementFromVnode(firstChild, vnode, false);
972
+ } else {
973
+ target.textContent = "";
974
+ if (_isDOMElement(vnode) && typeof vnode.type === "string") {
975
+ const children = vnode.children;
976
+ if (Array.isArray(children) && children.some(
977
+ (child) => typeof child === "object" && child !== null && "key" in child
978
+ )) {
979
+ const el = document.createElement(vnode.type);
980
+ target.appendChild(el);
981
+ const props = vnode.props || {};
982
+ for (const [key, value] of Object.entries(props)) {
983
+ if (key === "children" || key === "key") continue;
984
+ if (value === void 0 || value === null || value === false)
985
+ continue;
986
+ if (key.startsWith("on") && key.length > 2) {
987
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
988
+ const wrappedHandler = (event) => {
989
+ globalScheduler.setInHandler(true);
990
+ try {
991
+ value(event);
992
+ } catch (error) {
993
+ logger.error("[Askr] Event handler error:", error);
994
+ } finally {
995
+ globalScheduler.setInHandler(false);
996
+ }
997
+ };
998
+ el.addEventListener(eventName, wrappedHandler);
999
+ if (!elementListeners.has(el)) {
1000
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1001
+ }
1002
+ elementListeners.get(el).set(eventName, {
1003
+ handler: wrappedHandler,
1004
+ original: value
1005
+ });
1006
+ continue;
1007
+ }
1008
+ if (key === "class" || key === "className") {
1009
+ el.className = String(value);
1010
+ } else if (key === "value" || key === "checked") {
1011
+ el[key] = value;
1012
+ } else {
1013
+ el.setAttribute(key, String(value));
1014
+ }
1015
+ }
1016
+ const newKeyMap = reconcileKeyedChildren(el, children, void 0);
1017
+ keyedElements.set(el, newKeyMap);
1018
+ return;
1019
+ return;
1020
+ }
1021
+ }
1022
+ const dom = createDOMNode(vnode);
1023
+ if (dom) {
1024
+ target.appendChild(dom);
1025
+ }
1026
+ }
1027
+ }
1028
+ }
1029
+ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
1030
+ const keyedVnodes = [];
1031
+ for (let i = 0; i < newChildren.length; i++) {
1032
+ const child = newChildren[i];
1033
+ if (_isDOMElement(child) && child.key !== void 0) {
1034
+ keyedVnodes.push({ key: child.key, vnode: child });
1035
+ }
1036
+ }
1037
+ const totalKeyed = keyedVnodes.length;
1038
+ const newKeyOrder = keyedVnodes.map((kv) => kv.key);
1039
+ const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
1040
+ let moveCount = 0;
1041
+ for (let i = 0; i < newKeyOrder.length; i++) {
1042
+ const k = newKeyOrder[i];
1043
+ if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k || !oldKeyMap?.has(k)) {
1044
+ moveCount++;
1045
+ }
1046
+ }
1047
+ const FAST_MOVE_THRESHOLD_ABS = 64;
1048
+ const FAST_MOVE_THRESHOLD_REL = 0.1;
1049
+ const cheapMoveTrigger = totalKeyed >= 128 && oldKeyOrder.length > 0 && moveCount > Math.max(
1050
+ FAST_MOVE_THRESHOLD_ABS,
1051
+ Math.floor(totalKeyed * FAST_MOVE_THRESHOLD_REL)
1052
+ );
1053
+ let lisTrigger = false;
1054
+ let lisLen = 0;
1055
+ if (totalKeyed >= 128) {
1056
+ const parentChildren = Array.from(parent.children);
1057
+ const positions = new Array(keyedVnodes.length).fill(-1);
1058
+ for (let i = 0; i < keyedVnodes.length; i++) {
1059
+ const key = keyedVnodes[i].key;
1060
+ const el = oldKeyMap?.get(key);
1061
+ if (el && el.parentElement === parent) {
1062
+ positions[i] = parentChildren.indexOf(el);
1063
+ }
1064
+ }
1065
+ const tails = [];
1066
+ for (let i = 0; i < positions.length; i++) {
1067
+ const pos = positions[i];
1068
+ if (pos === -1) continue;
1069
+ let lo = 0;
1070
+ let hi = tails.length;
1071
+ while (lo < hi) {
1072
+ const mid = lo + hi >> 1;
1073
+ if (tails[mid] < pos) lo = mid + 1;
1074
+ else hi = mid;
1075
+ }
1076
+ if (lo === tails.length) tails.push(pos);
1077
+ else tails[lo] = pos;
1078
+ }
1079
+ lisLen = tails.length;
1080
+ lisTrigger = lisLen < Math.floor(totalKeyed * 0.5);
1081
+ }
1082
+ let hasPropsPresent = false;
1083
+ for (let i = 0; i < keyedVnodes.length; i++) {
1084
+ const vnode = keyedVnodes[i].vnode;
1085
+ if (!_isDOMElement(vnode)) continue;
1086
+ const props = vnode.props || {};
1087
+ for (const k of Object.keys(props)) {
1088
+ if (k === "children" || k === "key") continue;
1089
+ if (k.startsWith("on") && k.length > 2) continue;
1090
+ if (k.startsWith("data-")) continue;
1091
+ hasPropsPresent = true;
1092
+ break;
1093
+ }
1094
+ if (hasPropsPresent) break;
1095
+ }
1096
+ let hasPropChanges = false;
1097
+ for (let i = 0; i < keyedVnodes.length; i++) {
1098
+ const { key, vnode } = keyedVnodes[i];
1099
+ const el = oldKeyMap?.get(key);
1100
+ if (!el || !_isDOMElement(vnode)) continue;
1101
+ const props = vnode.props || {};
1102
+ for (const k of Object.keys(props)) {
1103
+ if (k === "children" || k === "key") continue;
1104
+ if (k.startsWith("on") && k.length > 2) continue;
1105
+ if (k.startsWith("data-")) continue;
1106
+ const v = props[k];
1107
+ try {
1108
+ if (k === "class" || k === "className") {
1109
+ if (el.className !== String(v)) {
1110
+ hasPropChanges = true;
1111
+ break;
1112
+ }
1113
+ } else if (k === "value" || k === "checked") {
1114
+ if (el[k] !== v) {
1115
+ hasPropChanges = true;
1116
+ break;
1117
+ }
1118
+ } else {
1119
+ const attr = el.getAttribute(k);
1120
+ if (v === void 0 || v === null || v === false) {
1121
+ if (attr !== null) {
1122
+ hasPropChanges = true;
1123
+ break;
1124
+ }
1125
+ } else if (String(v) !== attr) {
1126
+ hasPropChanges = true;
1127
+ break;
1128
+ }
1129
+ }
1130
+ } catch {
1131
+ hasPropChanges = true;
1132
+ break;
1133
+ }
1134
+ }
1135
+ if (hasPropChanges) break;
1136
+ }
1137
+ const useFastPath = (cheapMoveTrigger || lisTrigger) && !hasPropChanges && !hasPropsPresent;
1138
+ return {
1139
+ useFastPath,
1140
+ totalKeyed,
1141
+ moveCount,
1142
+ lisLen,
1143
+ hasPropChanges
1144
+ };
1145
+ }
1146
+ function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
1147
+ const newKeyMap = /* @__PURE__ */ new Map();
1148
+ const keyedVnodes = [];
1149
+ const unkeyedVnodes = [];
1150
+ for (let i = 0; i < newChildren.length; i++) {
1151
+ const child = newChildren[i];
1152
+ if (_isDOMElement(child) && child.key !== void 0) {
1153
+ keyedVnodes.push({ key: child.key, vnode: child });
1154
+ } else {
1155
+ unkeyedVnodes.push(child);
1156
+ }
1157
+ }
1158
+ const totalKeyed = keyedVnodes.length;
1159
+ const newKeyOrder = keyedVnodes.map((kv) => kv.key);
1160
+ const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
1161
+ let moveCount = 0;
1162
+ for (let i = 0; i < newKeyOrder.length; i++) {
1163
+ const k2 = newKeyOrder[i];
1164
+ if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k2 || !oldKeyMap?.has(k2)) {
1165
+ moveCount++;
1166
+ }
1167
+ }
1168
+ let hasPropChanges = false;
1169
+ for (let i = 0; i < keyedVnodes.length; i++) {
1170
+ const { key, vnode } = keyedVnodes[i];
1171
+ const el = oldKeyMap?.get(key);
1172
+ if (!el || !_isDOMElement(vnode)) continue;
1173
+ const props = vnode.props || {};
1174
+ for (const k2 of Object.keys(props)) {
1175
+ if (k2 === "children" || k2 === "key") continue;
1176
+ if (k2.startsWith("on") && k2.length > 2) {
1177
+ continue;
1178
+ }
1179
+ const v = props[k2];
1180
+ try {
1181
+ if (k2 === "class" || k2 === "className") {
1182
+ if (el.className !== String(v)) {
1183
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch", {
1184
+ key,
1185
+ prop: k2,
1186
+ expected: String(v),
1187
+ actual: el.className
1188
+ });
1189
+ hasPropChanges = true;
1190
+ break;
1191
+ }
1192
+ } else if (k2 === "value" || k2 === "checked") {
1193
+ if (el[k2] !== v) {
1194
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch", {
1195
+ key,
1196
+ prop: k2,
1197
+ expected: v,
1198
+ actual: el[k2]
1199
+ });
1200
+ hasPropChanges = true;
1201
+ break;
1202
+ }
1203
+ } else {
1204
+ const attr = el.getAttribute(k2);
1205
+ if (v === void 0 || v === null || v === false) {
1206
+ if (attr !== null) {
1207
+ logger.warn(
1208
+ "[Askr][FASTPATH][DEV] prop mismatch (missing attr)",
1209
+ {
1210
+ key,
1211
+ prop: k2,
1212
+ expected: v,
1213
+ actual: attr
1214
+ }
1215
+ );
1216
+ hasPropChanges = true;
1217
+ break;
1218
+ }
1219
+ } else if (String(v) !== attr) {
1220
+ logger.warn("[Askr][FASTPATH][DEV] prop mismatch (attr diff)", {
1221
+ key,
1222
+ prop: k2,
1223
+ expected: String(v),
1224
+ actual: attr
1225
+ });
1226
+ hasPropChanges = true;
1227
+ break;
1228
+ }
1229
+ }
1230
+ } catch {
1231
+ hasPropChanges = true;
1232
+ break;
1233
+ }
1234
+ }
1235
+ if (hasPropChanges) break;
1236
+ }
1237
+ const decision = isKeyedReorderFastPathEligible(
1238
+ parent,
1239
+ newChildren,
1240
+ oldKeyMap
1241
+ );
1242
+ const useFastPath = decision.useFastPath;
1243
+ logger.warn("[Askr][FASTPATH][DEV] decision", decision);
1244
+ try {
1245
+ const hugeThreshold = Number(process.env.ASKR_BULK_HUGE_THRESHOLD) || 2048;
1246
+ if (!useFastPath && keyedVnodes.length >= hugeThreshold) {
1247
+ let allSimple = true;
1248
+ for (let i = 0; i < keyedVnodes.length; i++) {
1249
+ const vnode = keyedVnodes[i].vnode;
1250
+ if (!_isDOMElement(vnode)) {
1251
+ allSimple = false;
1252
+ break;
1253
+ }
1254
+ const dv = vnode;
1255
+ if (typeof dv.type !== "string") {
1256
+ allSimple = false;
1257
+ break;
1258
+ }
1259
+ const ch = dv.children || dv.props?.children;
1260
+ if (ch === void 0) continue;
1261
+ if (Array.isArray(ch)) {
1262
+ if (ch.length !== 1 || typeof ch[0] !== "string" && typeof ch[0] !== "number") {
1263
+ allSimple = false;
1264
+ break;
1265
+ }
1266
+ } else if (typeof ch !== "string" && typeof ch !== "number") {
1267
+ allSimple = false;
1268
+ break;
1269
+ }
1270
+ }
1271
+ if (allSimple) {
1272
+ logger.warn("[Askr][FASTPATH] applying huge-list positional fallback");
1273
+ try {
1274
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1275
+ } catch (e) {
1276
+ void e;
1277
+ }
1278
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
1279
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1280
+ try {
1281
+ const gl = globalThis;
1282
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1283
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1284
+ counters.bulkKeyedHugeFallback = (counters.bulkKeyedHugeFallback || 0) + 1;
1285
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1286
+ gl.__ASKR_BULK_DIAG = {
1287
+ phase: "bulk-keyed-huge-fallback",
1288
+ stats
1289
+ };
1290
+ } catch (e) {
1291
+ void e;
1292
+ }
1293
+ }
1294
+ return newKeyMap;
1295
+ }
1296
+ }
1297
+ } catch (e) {
1298
+ void e;
1299
+ }
1300
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1301
+ try {
1302
+ const gl = globalThis;
1303
+ gl.__ASKR_BULK_DIAG = {
1304
+ phase: "keyed-decision",
1305
+ decision,
1306
+ totalKeyed,
1307
+ oldKeyMapSize: oldKeyMap?.size ?? 0
1308
+ };
1309
+ } catch (e) {
1310
+ void e;
1311
+ }
1312
+ }
1313
+ let allSimpleText = false;
1314
+ try {
1315
+ if (keyedVnodes.length >= (Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024)) {
1316
+ let missing = 0;
1317
+ try {
1318
+ const present = /* @__PURE__ */ new Set();
1319
+ const parentChildren2 = Array.from(parent.children);
1320
+ for (let i = 0; i < parentChildren2.length; i++) {
1321
+ const attr = parentChildren2[i].getAttribute("data-key");
1322
+ if (attr !== null) {
1323
+ present.add(attr);
1324
+ const n = Number(attr);
1325
+ if (!Number.isNaN(n)) present.add(n);
1326
+ }
1327
+ }
1328
+ for (let i = 0; i < keyedVnodes.length; i++) {
1329
+ const k2 = keyedVnodes[i].key;
1330
+ if (!present.has(k2)) missing++;
1331
+ }
1332
+ } catch {
1333
+ missing = 0;
1334
+ }
1335
+ allSimpleText = keyedVnodes.length > 0 && keyedVnodes.every(({ vnode }) => {
1336
+ if (!_isDOMElement(vnode)) return false;
1337
+ const dv = vnode;
1338
+ if (typeof dv.type !== "string") return false;
1339
+ const ch = dv.children || dv.props?.children;
1340
+ if (ch === void 0) return true;
1341
+ if (Array.isArray(ch)) {
1342
+ return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
1343
+ }
1344
+ return typeof ch === "string" || typeof ch === "number";
1345
+ });
1346
+ let hasPropsPresent = false;
1347
+ for (let i = 0; i < keyedVnodes.length; i++) {
1348
+ const vnode = keyedVnodes[i].vnode;
1349
+ if (!_isDOMElement(vnode)) continue;
1350
+ const props = vnode.props || {};
1351
+ for (const k2 of Object.keys(props)) {
1352
+ if (k2 === "children" || k2 === "key") continue;
1353
+ if (k2.startsWith("on") && k2.length > 2) continue;
1354
+ if (k2.startsWith("data-")) continue;
1355
+ hasPropsPresent = true;
1356
+ break;
1357
+ }
1358
+ if (hasPropsPresent) break;
1359
+ }
1360
+ const missingRatio = missing / Math.max(1, keyedVnodes.length);
1361
+ if (missingRatio > 0.5 && allSimpleText && !hasPropsPresent) {
1362
+ logger.warn(
1363
+ "[Askr][FASTPATH] switching to positional bulk keyed fast-path due to missing keys ratio",
1364
+ missingRatio
1365
+ );
1366
+ try {
1367
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1368
+ } catch (e) {
1369
+ void e;
1370
+ }
1371
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
1372
+ if (process.env.NODE_ENV !== "production") {
1373
+ try {
1374
+ const gl = globalThis;
1375
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1376
+ try {
1377
+ _reconcilerRecordedParents.add(parent);
1378
+ } catch (e) {
1379
+ void e;
1380
+ }
1381
+ gl.__ASKR_LAST_FASTPATH_COMMIT_COUNT = 1;
1382
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1383
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1384
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1385
+ } catch (e) {
1386
+ void e;
1387
+ }
1388
+ }
1389
+ return newKeyMap;
1390
+ }
1391
+ }
1392
+ } catch (e) {
1393
+ void e;
1394
+ }
1395
+ if (!useFastPath && typeof globalThis !== "undefined") {
1396
+ try {
1397
+ let parentFastpathApplied = false;
1398
+ try {
1399
+ parentFastpathApplied = isFastPathApplied(parent);
1400
+ } catch {
1401
+ parentFastpathApplied = false;
1402
+ }
1403
+ if (!parentFastpathApplied) {
1404
+ const gl = globalThis;
1405
+ try {
1406
+ if (_reconcilerRecordedParents.has(parent)) {
1407
+ _reconcilerRecordedParents.delete(parent);
1408
+ } else {
1409
+ delete gl.__ASKR_LAST_FASTPATH_STATS;
1410
+ delete gl.__ASKR_LAST_FASTPATH_REUSED;
1411
+ }
1412
+ } catch {
1413
+ delete gl.__ASKR_LAST_FASTPATH_STATS;
1414
+ delete gl.__ASKR_LAST_FASTPATH_REUSED;
1415
+ }
1416
+ }
1417
+ } catch (e) {
1418
+ void e;
1419
+ }
1420
+ }
1421
+ let _triedPositionalReuse = false;
1422
+ try {
1423
+ const bulkTextThreshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
1424
+ if (!useFastPath && keyedVnodes.length >= bulkTextThreshold && allSimpleText && !hasPropChanges) {
1425
+ try {
1426
+ if (isFastPathApplied(parent)) {
1427
+ logger.warn(
1428
+ "[Askr][FASTPATH] fast-path already applied on parent; skipping"
1429
+ );
1430
+ return newKeyMap;
1431
+ }
1432
+ } catch (e) {
1433
+ void e;
1434
+ }
1435
+ let stable = true;
1436
+ try {
1437
+ const parentChildren2 = Array.from(parent.children);
1438
+ if (parentChildren2.length === keyedVnodes.length) {
1439
+ const allSimple = keyedVnodes.every(({ vnode }) => {
1440
+ if (!_isDOMElement(vnode)) return false;
1441
+ const dv = vnode;
1442
+ if (typeof dv.type !== "string") return false;
1443
+ const ch = dv.children || dv.props?.children;
1444
+ if (ch === void 0) return true;
1445
+ if (Array.isArray(ch)) {
1446
+ return ch.length === 1 && (typeof ch[0] === "string" || typeof ch[0] === "number");
1447
+ }
1448
+ return typeof ch === "string" || typeof ch === "number";
1449
+ });
1450
+ if (allSimple || process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
1451
+ logger.warn(
1452
+ "[Askr][FASTPATH] len-match heuristic triggered (positional bulk)"
1453
+ );
1454
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1455
+ try {
1456
+ const gl = globalThis;
1457
+ gl.__ASKR_BULK_DIAG = {
1458
+ phase: "bulk-keyed-positional-trigger-lenmatch-early",
1459
+ totalKeyed: keyedVnodes.length,
1460
+ allSimple,
1461
+ forced: process.env.ASKR_FORCE_BULK_POSREUSE === "1"
1462
+ };
1463
+ } catch (e) {
1464
+ void e;
1465
+ }
1466
+ }
1467
+ try {
1468
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1469
+ } catch (e) {
1470
+ void e;
1471
+ }
1472
+ const stats = performBulkPositionalKeyedTextUpdate(
1473
+ parent,
1474
+ keyedVnodes
1475
+ );
1476
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1477
+ try {
1478
+ const gl = globalThis;
1479
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1480
+ gl.__ASKR_BULK_DIAG = {
1481
+ phase: "bulk-keyed-positional-applied",
1482
+ stats
1483
+ };
1484
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1485
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1486
+ if (process.env.ASKR_FORCE_BULK_POSREUSE === "1")
1487
+ counters.bulkKeyedPositionalForced = (counters.bulkKeyedPositionalForced || 0) + 1;
1488
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1489
+ } catch (e) {
1490
+ void e;
1491
+ }
1492
+ }
1493
+ return newKeyMap;
1494
+ }
1495
+ }
1496
+ if (parentChildren2.length !== keyedVnodes.length) stable = false;
1497
+ else {
1498
+ let keyMismatches = 0;
1499
+ for (let i = 0; i < keyedVnodes.length; i++) {
1500
+ const k2 = keyedVnodes[i].key;
1501
+ const ch = parentChildren2[i];
1502
+ if (!ch) {
1503
+ stable = false;
1504
+ break;
1505
+ }
1506
+ const attr = ch.getAttribute("data-key");
1507
+ if (attr === null) {
1508
+ stable = false;
1509
+ break;
1510
+ }
1511
+ if (String(k2) !== attr && String(Number(attr)) !== String(k2)) {
1512
+ keyMismatches++;
1513
+ }
1514
+ }
1515
+ if (stable) {
1516
+ if (keyMismatches === 0) {
1517
+ logger.warn(
1518
+ "[Askr][FASTPATH] applying bulk keyed text fast-path (stable keys)"
1519
+ );
1520
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1521
+ try {
1522
+ const gl = globalThis;
1523
+ gl.__ASKR_BULK_DIAG = {
1524
+ phase: "bulk-keyed-stable-trigger",
1525
+ totalKeyed: keyedVnodes.length,
1526
+ hasPropChanges
1527
+ };
1528
+ } catch (e) {
1529
+ void e;
1530
+ }
1531
+ }
1532
+ try {
1533
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1534
+ } catch (e) {
1535
+ void e;
1536
+ }
1537
+ const stats = performBulkKeyedTextReplace(
1538
+ parent,
1539
+ keyedVnodes,
1540
+ oldKeyMap
1541
+ );
1542
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1543
+ try {
1544
+ const gl = globalThis;
1545
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1546
+ gl.__ASKR_BULK_DIAG = {
1547
+ phase: "bulk-keyed-applied",
1548
+ stats
1549
+ };
1550
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1551
+ counters.bulkKeyedTextHits = (counters.bulkKeyedTextHits || 0) + 1;
1552
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1553
+ } catch (e) {
1554
+ void e;
1555
+ }
1556
+ }
1557
+ return newKeyMap;
1558
+ }
1559
+ if (parentChildren2.length === keyedVnodes.length) {
1560
+ logger.warn(
1561
+ "[Askr][FASTPATH] applying bulk keyed positional text fast-path (len-match)"
1562
+ );
1563
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1564
+ try {
1565
+ const gl = globalThis;
1566
+ gl.__ASKR_BULK_DIAG = {
1567
+ phase: "bulk-keyed-positional-trigger-lenmatch",
1568
+ totalKeyed: keyedVnodes.length,
1569
+ keyMismatches
1570
+ };
1571
+ } catch (e) {
1572
+ void e;
1573
+ }
1574
+ }
1575
+ try {
1576
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1577
+ } catch (e) {
1578
+ void e;
1579
+ }
1580
+ const stats = performBulkPositionalKeyedTextUpdate(
1581
+ parent,
1582
+ keyedVnodes
1583
+ );
1584
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1585
+ try {
1586
+ const gl = globalThis;
1587
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1588
+ gl.__ASKR_BULK_DIAG = {
1589
+ phase: "bulk-keyed-positional-applied",
1590
+ stats
1591
+ };
1592
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1593
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1594
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1595
+ } catch (e) {
1596
+ void e;
1597
+ }
1598
+ }
1599
+ return newKeyMap;
1600
+ }
1601
+ const mismatchRatio = keyMismatches / keyedVnodes.length;
1602
+ const POSITIONAL_THRESHOLD = 0.5;
1603
+ if (mismatchRatio > POSITIONAL_THRESHOLD) {
1604
+ logger.warn(
1605
+ "[Askr][FASTPATH] applying bulk keyed positional text fast-path"
1606
+ );
1607
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1608
+ try {
1609
+ globalThis.__ASKR_BULK_DIAG = {
1610
+ phase: "bulk-keyed-positional-trigger",
1611
+ totalKeyed: keyedVnodes.length,
1612
+ keyMismatches
1613
+ };
1614
+ } catch (e) {
1615
+ void e;
1616
+ }
1617
+ }
1618
+ try {
1619
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1620
+ } catch (e) {
1621
+ void e;
1622
+ }
1623
+ const stats = performBulkPositionalKeyedTextUpdate(
1624
+ parent,
1625
+ keyedVnodes
1626
+ );
1627
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1628
+ try {
1629
+ const gl = globalThis;
1630
+ gl.__ASKR_LAST_FASTPATH_STATS = stats;
1631
+ gl.__ASKR_BULK_DIAG = {
1632
+ phase: "bulk-keyed-positional-applied",
1633
+ stats
1634
+ };
1635
+ const counters = gl.__ASKR_FASTPATH_COUNTERS || {};
1636
+ counters.bulkKeyedPositionalHits = (counters.bulkKeyedPositionalHits || 0) + 1;
1637
+ gl.__ASKR_FASTPATH_COUNTERS = counters;
1638
+ } catch (e) {
1639
+ void e;
1640
+ }
1641
+ }
1642
+ return newKeyMap;
1643
+ }
1644
+ }
1645
+ }
1646
+ } catch {
1647
+ stable = false;
1648
+ }
1649
+ }
1650
+ } catch (e) {
1651
+ void e;
1652
+ }
1653
+ if (!useFastPath) {
1654
+ const totalKeyed2 = keyedVnodes.length;
1655
+ const candidates = newChildren.filter(
1656
+ (c) => _isDOMElement(c) && typeof c.type === "string"
1657
+ );
1658
+ const smallListPositionalReuseEligible = candidates.length > 0 && candidates.length <= 64 && parent.children.length === candidates.length && candidates.every((vnode) => {
1659
+ const children = vnode.children || vnode.props?.children;
1660
+ if (Array.isArray(children)) {
1661
+ return children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number");
1662
+ }
1663
+ return children === void 0 || typeof children === "string" || typeof children === "number";
1664
+ });
1665
+ try {
1666
+ if (smallListPositionalReuseEligible) {
1667
+ let eligible = true;
1668
+ for (let i = 0; i < totalKeyed2; i++) {
1669
+ const vnode = keyedVnodes[i].vnode;
1670
+ if (!_isDOMElement(vnode) || typeof vnode.type !== "string") {
1671
+ eligible = false;
1672
+ break;
1673
+ }
1674
+ const children = vnode.children || vnode.props?.children;
1675
+ if (Array.isArray(children)) {
1676
+ if (children.length !== 1) {
1677
+ eligible = false;
1678
+ break;
1679
+ }
1680
+ const c = children[0];
1681
+ if (typeof c !== "string" && typeof c !== "number") {
1682
+ eligible = false;
1683
+ break;
1684
+ }
1685
+ } else if (children !== void 0 && typeof children !== "string" && typeof children !== "number") {
1686
+ eligible = false;
1687
+ break;
1688
+ }
1689
+ }
1690
+ const anyKeyMatches = !!oldKeyMap && keyedVnodes.some((kv) => oldKeyMap.has(kv.key));
1691
+ if (anyKeyMatches) {
1692
+ eligible = false;
1693
+ }
1694
+ if (eligible || process.env.ASKR_FORCE_POSREUSE === "1") {
1695
+ _triedPositionalReuse = true;
1696
+ if (process.env.ASKR_FORCE_POSREUSE === "1") {
1697
+ logger.warn(
1698
+ "[Askr][POSREUSE][FORCED] forcing positional reuse path for testing"
1699
+ );
1700
+ } else {
1701
+ logger.warn("[Askr][POSREUSE] positional reuse heuristic applied");
1702
+ }
1703
+ const existingChildren = parent.children;
1704
+ for (let i = 0; i < totalKeyed2; i++) {
1705
+ const { key, vnode } = keyedVnodes[i];
1706
+ const current = existingChildren[i];
1707
+ if (current && _isDOMElement(vnode)) {
1708
+ const vnodeType = vnode.type;
1709
+ if (current.tagName.toLowerCase() === vnodeType.toLowerCase()) {
1710
+ updateElementFromVnode(current, vnode);
1711
+ newKeyMap.set(key, current);
1712
+ continue;
1713
+ }
1714
+ }
1715
+ const newEl = createDOMNode(vnode);
1716
+ if (newEl instanceof Element) {
1717
+ if (current) {
1718
+ cleanupInstanceIfPresent(current);
1719
+ parent.replaceChild(newEl, current);
1720
+ } else parent.appendChild(newEl);
1721
+ newKeyMap.set(key, newEl);
1722
+ }
1723
+ }
1724
+ for (const vnode of unkeyedVnodes) {
1725
+ const newEl = createDOMNode(vnode);
1726
+ if (newEl) parent.appendChild(newEl);
1727
+ }
1728
+ return newKeyMap;
1729
+ }
1730
+ }
1731
+ } catch {
1732
+ }
1733
+ }
1734
+ if (useFastPath) {
1735
+ if (!isSchedulerExecuting()) {
1736
+ logger.warn(
1737
+ "[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
1738
+ );
1739
+ }
1740
+ let parentChildrenArr;
1741
+ let localOldKeyMap;
1742
+ if (totalKeyed <= 20) {
1743
+ try {
1744
+ const pc = parent.children;
1745
+ parentChildrenArr = new Array(pc.length);
1746
+ for (let i = 0; i < pc.length; i++)
1747
+ parentChildrenArr[i] = pc[i];
1748
+ } catch {
1749
+ parentChildrenArr = void 0;
1750
+ }
1751
+ } else {
1752
+ localOldKeyMap = /* @__PURE__ */ new Map();
1753
+ try {
1754
+ const parentChildren2 = Array.from(parent.children);
1755
+ for (let i = 0; i < parentChildren2.length; i++) {
1756
+ const ch = parentChildren2[i];
1757
+ const k2 = ch.getAttribute("data-key");
1758
+ if (k2 !== null) {
1759
+ localOldKeyMap.set(k2, ch);
1760
+ const n = Number(k2);
1761
+ if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
1762
+ }
1763
+ }
1764
+ } catch {
1765
+ localOldKeyMap = void 0;
1766
+ }
1767
+ }
1768
+ logger.warn(
1769
+ "[Askr][FASTPATH] oldKeyMap size:",
1770
+ oldKeyMap?.size ?? 0,
1771
+ "localOldKeyMap size:",
1772
+ localOldKeyMap?.size
1773
+ );
1774
+ const tLookupStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1775
+ const finalNodes = [];
1776
+ let mapLookups = 0;
1777
+ let createdNodes = 0;
1778
+ let reusedCount = 0;
1779
+ for (let i = 0; i < keyedVnodes.length; i++) {
1780
+ const { key, vnode } = keyedVnodes[i];
1781
+ mapLookups++;
1782
+ let el;
1783
+ if (totalKeyed <= 20 && parentChildrenArr) {
1784
+ const ks = String(key);
1785
+ for (let j = 0; j < parentChildrenArr.length; j++) {
1786
+ const ch = parentChildrenArr[j];
1787
+ const k2 = ch.getAttribute("data-key");
1788
+ if (k2 !== null && (k2 === ks || Number(k2) === key)) {
1789
+ el = ch;
1790
+ break;
1791
+ }
1792
+ }
1793
+ if (!el) el = oldKeyMap?.get(key);
1794
+ } else {
1795
+ el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
1796
+ }
1797
+ if (el) {
1798
+ finalNodes.push(el);
1799
+ reusedCount++;
1800
+ } else {
1801
+ const newEl = createDOMNode(vnode);
1802
+ if (newEl) {
1803
+ finalNodes.push(newEl);
1804
+ createdNodes++;
1805
+ }
1806
+ }
1807
+ }
1808
+ for (const vnode of unkeyedVnodes) {
1809
+ const newEl = createDOMNode(vnode);
1810
+ if (newEl) {
1811
+ finalNodes.push(newEl);
1812
+ createdNodes++;
1813
+ }
1814
+ }
1815
+ const t_lookup = typeof performance !== "undefined" && performance.now ? performance.now() - tLookupStart : 0;
1816
+ if (process.env.ASKR_FASTPATH_GUARD === "1") {
1817
+ const replaceChildrenCount = 0;
1818
+ const otherMutationCount = 0;
1819
+ const orig = {};
1820
+ const elProto = Element.prototype;
1821
+ const nodeProto = Node.prototype;
1822
+ const removeFn = (() => {
1823
+ if (typeof document === "undefined" || typeof document.createElement !== "function")
1824
+ return void 0;
1825
+ try {
1826
+ const el = document.createElement("div");
1827
+ return typeof el.remove === "function" ? el.remove : void 0;
1828
+ } catch {
1829
+ return void 0;
1830
+ }
1831
+ })();
1832
+ if (elProto.replaceChildren)
1833
+ orig.replaceChildren = elProto.replaceChildren;
1834
+ if (nodeProto.appendChild) orig.appendChild = nodeProto.appendChild;
1835
+ if (nodeProto.insertBefore) orig.insertBefore = nodeProto.insertBefore;
1836
+ if (nodeProto.removeChild) orig.removeChild = nodeProto.removeChild;
1837
+ if (nodeProto.replaceChild) orig.replaceChild = nodeProto.replaceChild;
1838
+ if (removeFn) orig.remove = removeFn;
1839
+ let violation = false;
1840
+ try {
1841
+ const fragment = document.createDocumentFragment();
1842
+ for (let i = 0; i < finalNodes.length; i++)
1843
+ fragment.appendChild(finalNodes[i]);
1844
+ let commitCount = 0;
1845
+ commitCount++;
1846
+ parent.replaceChildren(fragment);
1847
+ if (typeof globalThis !== "undefined") {
1848
+ globalThis["__ASKR_LAST_FASTPATH_COMMIT_COUNT"] = commitCount;
1849
+ }
1850
+ } finally {
1851
+ violation = otherMutationCount !== 0 || replaceChildrenCount < 1;
1852
+ }
1853
+ if (violation) {
1854
+ logger.error(
1855
+ "[Askr][DEV] Fast-path structural mutation invariant violated:",
1856
+ {
1857
+ replaceChildrenCount,
1858
+ otherMutationCount
1859
+ }
1860
+ );
1861
+ throw new Error(
1862
+ "Fast-path must perform a single structural replacement (replaceChildren) and no other structural mutations"
1863
+ );
1864
+ }
1865
+ } else {
1866
+ const tFragmentStart = Date.now();
1867
+ const fragment = document.createDocumentFragment();
1868
+ let fragmentAppendCount = 0;
1869
+ for (let i = 0; i < finalNodes.length; i++) {
1870
+ fragment.appendChild(finalNodes[i]);
1871
+ fragmentAppendCount++;
1872
+ }
1873
+ const t_fragment = Date.now() - tFragmentStart;
1874
+ const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
1875
+ const wasExecuting = process.env.NODE_ENV !== "production" ? isSchedulerExecuting() : false;
1876
+ const tCommitStart = Date.now();
1877
+ if (process.env.NODE_ENV !== "production") {
1878
+ }
1879
+ let commitCount = 0;
1880
+ commitCount++;
1881
+ try {
1882
+ const existing = Array.from(parent.childNodes);
1883
+ for (const n of existing) cleanupInstanceIfPresent(n);
1884
+ } catch (e) {
1885
+ void e;
1886
+ }
1887
+ try {
1888
+ const existing = Array.from(parent.childNodes);
1889
+ for (const n of existing) cleanupInstanceIfPresent(n);
1890
+ } catch (e) {
1891
+ void e;
1892
+ }
1893
+ parent.replaceChildren(fragment);
1894
+ if (typeof globalThis !== "undefined") {
1895
+ globalThis["__ASKR_LAST_FASTPATH_COMMIT_COUNT"] = commitCount;
1896
+ }
1897
+ const t_commit = Date.now() - tCommitStart;
1898
+ if (process.env.NODE_ENV !== "production") {
1899
+ const schedAfter = globalScheduler.getState();
1900
+ if (!wasExecuting) {
1901
+ logger.warn(
1902
+ "[Askr][FASTPATH][DEV] Fast-path commit invoked outside scheduler execution"
1903
+ );
1904
+ }
1905
+ if (schedBefore && schedAfter) {
1906
+ if (schedBefore.taskCount !== schedAfter.taskCount) {
1907
+ logger.error(
1908
+ "[Askr][FASTPATH][DEV] Scheduler tasks were enqueued during fast-path commit",
1909
+ {
1910
+ before: schedBefore,
1911
+ after: schedAfter
1912
+ }
1913
+ );
1914
+ throw new Error("Fast-path must not enqueue scheduler tasks");
1915
+ }
1916
+ }
1917
+ const parentNodes = Array.from(parent.childNodes);
1918
+ if (parentNodes.length !== finalNodes.length) {
1919
+ logger.error("[Askr][FASTPATH][DEV] Parent child count mismatch", {
1920
+ parentCount: parentNodes.length,
1921
+ expected: finalNodes.length
1922
+ });
1923
+ throw new Error(
1924
+ "Fast-path must perform a single structural replacement"
1925
+ );
1926
+ }
1927
+ for (let i = 0; i < finalNodes.length; i++) {
1928
+ if (parentNodes[i] !== finalNodes[i]) {
1929
+ logger.error(
1930
+ "[Askr][FASTPATH][DEV] Final DOM order mismatch at index",
1931
+ i,
1932
+ {
1933
+ expected: finalNodes[i],
1934
+ found: parentNodes[i]
1935
+ }
1936
+ );
1937
+ throw new Error(
1938
+ "Fast-path final DOM order does not match expected nodes"
1939
+ );
1940
+ }
1941
+ }
1942
+ }
1943
+ const tBookkeepingStart = Date.now();
1944
+ for (let i = 0; i < keyedVnodes.length; i++) {
1945
+ const key = keyedVnodes[i].key;
1946
+ const node = finalNodes[i];
1947
+ if (node instanceof Element) newKeyMap.set(key, node);
1948
+ }
1949
+ const t_bookkeeping = Date.now() - tBookkeepingStart;
1950
+ if (process.env.ASKR_FASTPATH_TRACE === "1" || process.env.NODE_ENV !== "production") {
1951
+ const stats = {
1952
+ n: totalKeyed,
1953
+ moves: moveCount,
1954
+ lisLen: 0,
1955
+ t_lookup,
1956
+ t_fragment,
1957
+ t_commit,
1958
+ t_bookkeeping,
1959
+ fragmentAppendCount,
1960
+ mapLookups,
1961
+ createdNodes,
1962
+ reusedCount
1963
+ };
1964
+ if (typeof globalThis !== "undefined") {
1965
+ const _g = globalThis;
1966
+ _g["__ASKR_LAST_FASTPATH_STATS"] = stats;
1967
+ _g["__ASKR_LAST_FASTPATH_REUSED"] = reusedCount > 0;
1968
+ const historyKey = "__ASKR_LAST_FASTPATH_HISTORY";
1969
+ let hist = _g[historyKey];
1970
+ if (!hist) {
1971
+ hist = [];
1972
+ _g[historyKey] = hist;
1973
+ }
1974
+ hist.push(stats);
1975
+ }
1976
+ logger.warn("[Askr][FASTPATH]", JSON.stringify(stats));
1977
+ }
1978
+ }
1979
+ return newKeyMap;
1980
+ }
1981
+ const parentChildren = Array.from(parent.children);
1982
+ const positions = new Array(keyedVnodes.length).fill(-1);
1983
+ for (let i = 0; i < keyedVnodes.length; i++) {
1984
+ const key = keyedVnodes[i].key;
1985
+ const el = oldKeyMap?.get(key);
1986
+ if (el && el.parentElement === parent) {
1987
+ positions[i] = parentChildren.indexOf(el);
1988
+ }
1989
+ }
1990
+ const tailsStart = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
1991
+ const keepSet = /* @__PURE__ */ new Set();
1992
+ const tails = [];
1993
+ const tailsIdx = [];
1994
+ const prev = new Array(positions.length).fill(-1);
1995
+ for (let i = 0; i < positions.length; i++) {
1996
+ const pos = positions[i];
1997
+ if (pos === -1) continue;
1998
+ let lo = 0;
1999
+ let hi = tails.length;
2000
+ while (lo < hi) {
2001
+ const mid = lo + hi >> 1;
2002
+ if (tails[mid] < pos) lo = mid + 1;
2003
+ else hi = mid;
2004
+ }
2005
+ if (lo === tails.length) {
2006
+ tails.push(pos);
2007
+ tailsIdx.push(i);
2008
+ } else {
2009
+ tails[lo] = pos;
2010
+ tailsIdx[lo] = i;
2011
+ }
2012
+ prev[i] = lo > 0 ? tailsIdx[lo - 1] : -1;
2013
+ }
2014
+ let k = tailsIdx.length ? tailsIdx[tailsIdx.length - 1] : -1;
2015
+ while (k !== -1) {
2016
+ keepSet.add(k);
2017
+ k = prev[k];
2018
+ }
2019
+ const tLIS = (typeof performance !== "undefined" && performance.now ? performance.now() : Date.now()) - tailsStart;
2020
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2021
+ try {
2022
+ const prev2 = globalThis.__ASKR_BULK_DIAG;
2023
+ globalThis.__ASKR_BULK_DIAG = {
2024
+ phase: "keyed-fallback-lis",
2025
+ positionsFound: positions.filter((p) => p !== -1).length,
2026
+ keepCount: keepSet.size,
2027
+ tLIS,
2028
+ previousDecision: prev2?.decision
2029
+ };
2030
+ } catch (e) {
2031
+ void e;
2032
+ }
2033
+ }
2034
+ let anchor = parent.firstChild;
2035
+ for (let i = 0; i < keyedVnodes.length; i++) {
2036
+ const { key, vnode } = keyedVnodes[i];
2037
+ const el = oldKeyMap?.get(key);
2038
+ if (el && el.parentElement === parent) {
2039
+ if (keepSet.has(i)) {
2040
+ if (anchor === el) {
2041
+ anchor = el.nextSibling;
2042
+ }
2043
+ updateElementFromVnode(el, vnode);
2044
+ newKeyMap.set(key, el);
2045
+ } else {
2046
+ parent.insertBefore(el, anchor);
2047
+ updateElementFromVnode(el, vnode);
2048
+ newKeyMap.set(key, el);
2049
+ anchor = el.nextSibling;
2050
+ }
2051
+ } else {
2052
+ const newEl = createDOMNode(vnode);
2053
+ if (newEl instanceof Element) {
2054
+ parent.insertBefore(newEl, anchor);
2055
+ newKeyMap.set(key, newEl);
2056
+ anchor = newEl.nextSibling;
2057
+ }
2058
+ }
2059
+ }
2060
+ for (const vnode of unkeyedVnodes) {
2061
+ const newEl = createDOMNode(vnode);
2062
+ if (newEl) {
2063
+ parent.appendChild(newEl);
2064
+ }
2065
+ }
2066
+ return newKeyMap;
2067
+ }
2068
+ function performBulkKeyedTextReplace(parent, keyedVnodes, oldKeyMap) {
2069
+ const total = keyedVnodes.length;
2070
+ const finalNodes = [];
2071
+ let reused = 0;
2072
+ let created = 0;
2073
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2074
+ for (let i = 0; i < total; i++) {
2075
+ const { key, vnode } = keyedVnodes[i];
2076
+ const el = oldKeyMap?.get(key);
2077
+ if (el && _isDOMElement(vnode) && typeof vnode.type === "string") {
2078
+ const children = vnode.children || vnode.props?.children;
2079
+ if (typeof children === "string" || typeof children === "number") {
2080
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2081
+ el.firstChild.data = String(children);
2082
+ } else {
2083
+ el.textContent = String(children);
2084
+ }
2085
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2086
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2087
+ el.firstChild.data = String(children[0]);
2088
+ } else {
2089
+ el.textContent = String(children[0]);
2090
+ }
2091
+ } else {
2092
+ updateElementFromVnode(el, vnode);
2093
+ }
2094
+ finalNodes.push(el);
2095
+ reused++;
2096
+ } else {
2097
+ const dom = createDOMNode(vnode);
2098
+ if (dom) {
2099
+ finalNodes.push(dom);
2100
+ created++;
2101
+ }
2102
+ }
2103
+ }
2104
+ try {
2105
+ const toRemove = Array.from(parent.childNodes).filter(
2106
+ (n) => !finalNodes.includes(n)
2107
+ );
2108
+ for (const n of toRemove) cleanupInstanceIfPresent(n);
2109
+ } catch (e) {
2110
+ void e;
2111
+ }
2112
+ const existingChildren = Array.from(parent.children);
2113
+ const listenerSnapshots = new Array(existingChildren.length).fill(void 0);
2114
+ try {
2115
+ for (let i = 0; i < existingChildren.length; i++) {
2116
+ const ch = existingChildren[i];
2117
+ if (ch) {
2118
+ const map = elementListeners.get(ch);
2119
+ if (map && map.size > 0) {
2120
+ const clone = /* @__PURE__ */ new Map();
2121
+ for (const [k, v] of map) clone.set(k, v);
2122
+ listenerSnapshots[i] = clone;
2123
+ }
2124
+ }
2125
+ }
2126
+ } catch (e) {
2127
+ void e;
2128
+ }
2129
+ const fragment = document.createDocumentFragment();
2130
+ for (let i = 0; i < finalNodes.length; i++)
2131
+ fragment.appendChild(finalNodes[i]);
2132
+ parent.replaceChildren(fragment);
2133
+ try {
2134
+ for (let i = 0; i < finalNodes.length; i++) {
2135
+ const newNode = finalNodes[i];
2136
+ const snapshot = listenerSnapshots[i];
2137
+ if (snapshot && newNode instanceof Element) {
2138
+ for (const [eventName, entry] of snapshot) {
2139
+ const existing = elementListeners.get(newNode)?.get(eventName);
2140
+ if (existing && existing.original === entry.original) continue;
2141
+ newNode.addEventListener(eventName, entry.handler);
2142
+ if (!elementListeners.has(newNode))
2143
+ elementListeners.set(newNode, /* @__PURE__ */ new Map());
2144
+ elementListeners.get(newNode).set(eventName, entry);
2145
+ }
2146
+ }
2147
+ }
2148
+ } catch (e) {
2149
+ void e;
2150
+ }
2151
+ try {
2152
+ keyedElements.delete(parent);
2153
+ } catch (e) {
2154
+ void e;
2155
+ }
2156
+ const t = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2157
+ const stats = {
2158
+ n: total,
2159
+ reused,
2160
+ created,
2161
+ t
2162
+ };
2163
+ return stats;
2164
+ }
2165
+ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
2166
+ const total = keyedVnodes.length;
2167
+ let reused = 0;
2168
+ let updatedKeys = 0;
2169
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2170
+ for (let i = 0; i < total; i++) {
2171
+ const { key, vnode } = keyedVnodes[i];
2172
+ const ch = parent.children[i];
2173
+ if (ch && _isDOMElement(vnode) && typeof vnode.type === "string") {
2174
+ const vnodeType = vnode.type;
2175
+ if (ch.tagName.toLowerCase() === vnodeType.toLowerCase()) {
2176
+ const children = vnode.children || vnode.props?.children;
2177
+ if (typeof children === "string" || typeof children === "number") {
2178
+ if (ch.childNodes.length === 1 && ch.firstChild?.nodeType === 3) {
2179
+ ch.firstChild.data = String(children);
2180
+ } else {
2181
+ ch.textContent = String(children);
2182
+ }
2183
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2184
+ if (ch.childNodes.length === 1 && ch.firstChild?.nodeType === 3) {
2185
+ ch.firstChild.data = String(children[0]);
2186
+ } else {
2187
+ ch.textContent = String(children[0]);
2188
+ }
2189
+ } else {
2190
+ updateElementFromVnode(ch, vnode);
2191
+ }
2192
+ try {
2193
+ ch.setAttribute("data-key", String(key));
2194
+ updatedKeys++;
2195
+ } catch (e) {
2196
+ void e;
2197
+ }
2198
+ reused++;
2199
+ continue;
2200
+ }
2201
+ }
2202
+ const dom = createDOMNode(vnode);
2203
+ if (dom) {
2204
+ const existing = parent.children[i];
2205
+ if (existing) {
2206
+ cleanupInstanceIfPresent(existing);
2207
+ parent.replaceChild(dom, existing);
2208
+ } else parent.appendChild(dom);
2209
+ }
2210
+ }
2211
+ const t = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2212
+ try {
2213
+ const newKeyMap = /* @__PURE__ */ new Map();
2214
+ for (let i = 0; i < total; i++) {
2215
+ const k = keyedVnodes[i].key;
2216
+ const ch = parent.children[i];
2217
+ if (ch) newKeyMap.set(k, ch);
2218
+ }
2219
+ keyedElements.set(parent, newKeyMap);
2220
+ } catch (e) {
2221
+ void e;
2222
+ }
2223
+ const stats = {
2224
+ n: total,
2225
+ reused,
2226
+ updatedKeys,
2227
+ t
2228
+ };
2229
+ return stats;
2230
+ }
2231
+ function isBulkTextFastPathEligible(parent, newChildren) {
2232
+ const threshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
2233
+ const requiredFraction = 0.8;
2234
+ const total = Array.isArray(newChildren) ? newChildren.length : 0;
2235
+ if (total < threshold) {
2236
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2237
+ try {
2238
+ globalThis.__ASKR_BULK_DIAG = {
2239
+ phase: "bulk-unkeyed-eligible",
2240
+ reason: "too-small",
2241
+ total,
2242
+ threshold
2243
+ };
2244
+ } catch (e) {
2245
+ void e;
2246
+ }
2247
+ }
2248
+ return false;
2249
+ }
2250
+ let simple = 0;
2251
+ for (let i = 0; i < newChildren.length; i++) {
2252
+ const c = newChildren[i];
2253
+ if (typeof c === "string" || typeof c === "number") {
2254
+ simple++;
2255
+ continue;
2256
+ }
2257
+ if (typeof c === "object" && c !== null && "type" in c) {
2258
+ const dv = c;
2259
+ if (typeof dv.type === "function") {
2260
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2261
+ try {
2262
+ globalThis.__ASKR_BULK_DIAG = {
2263
+ phase: "bulk-unkeyed-eligible",
2264
+ reason: "component-child",
2265
+ index: i
2266
+ };
2267
+ } catch (e) {
2268
+ void e;
2269
+ }
2270
+ }
2271
+ return false;
2272
+ }
2273
+ if (typeof dv.type === "string") {
2274
+ const children = dv.children || dv.props?.children;
2275
+ if (!children) {
2276
+ simple++;
2277
+ continue;
2278
+ }
2279
+ if (Array.isArray(children)) {
2280
+ if (children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2281
+ simple++;
2282
+ continue;
2283
+ }
2284
+ } else if (typeof children === "string" || typeof children === "number") {
2285
+ simple++;
2286
+ continue;
2287
+ }
2288
+ }
2289
+ }
2290
+ }
2291
+ const fraction = simple / total;
2292
+ const eligible = fraction >= requiredFraction && parent.childNodes.length >= total;
2293
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2294
+ try {
2295
+ globalThis.__ASKR_BULK_DIAG = {
2296
+ phase: "bulk-unkeyed-eligible",
2297
+ total,
2298
+ simple,
2299
+ fraction,
2300
+ requiredFraction,
2301
+ eligible
2302
+ };
2303
+ } catch (e) {
2304
+ void e;
2305
+ }
2306
+ }
2307
+ return eligible;
2308
+ }
2309
+ function performBulkTextReplace(parent, newChildren) {
2310
+ const t0 = typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
2311
+ const existing = Array.from(parent.childNodes);
2312
+ const finalNodes = [];
2313
+ let reused = 0;
2314
+ let created = 0;
2315
+ for (let i = 0; i < newChildren.length; i++) {
2316
+ const vnode = newChildren[i];
2317
+ const existingNode = existing[i];
2318
+ if (typeof vnode === "string" || typeof vnode === "number") {
2319
+ const text = String(vnode);
2320
+ if (existingNode && existingNode.nodeType === 3) {
2321
+ existingNode.data = text;
2322
+ finalNodes.push(existingNode);
2323
+ reused++;
2324
+ } else {
2325
+ finalNodes.push(document.createTextNode(text));
2326
+ created++;
2327
+ }
2328
+ continue;
2329
+ }
2330
+ if (typeof vnode === "object" && vnode !== null && "type" in vnode) {
2331
+ if (typeof vnode.type === "string") {
2332
+ const vtype = vnode.type;
2333
+ if (existingNode && existingNode.nodeType === 1 && existingNode.tagName.toLowerCase() === vtype.toLowerCase()) {
2334
+ const el = existingNode;
2335
+ const children = vnode.children || vnode.props?.children;
2336
+ if (typeof children === "string" || typeof children === "number") {
2337
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2338
+ el.firstChild.data = String(children);
2339
+ } else {
2340
+ el.textContent = String(children);
2341
+ }
2342
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
2343
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2344
+ el.firstChild.data = String(children[0]);
2345
+ } else {
2346
+ el.textContent = String(children[0]);
2347
+ }
2348
+ } else {
2349
+ updateElementFromVnode(el, vnode);
2350
+ }
2351
+ finalNodes.push(el);
2352
+ reused++;
2353
+ continue;
2354
+ }
2355
+ const dom2 = createDOMNode(vnode);
2356
+ if (dom2) {
2357
+ finalNodes.push(dom2);
2358
+ created++;
2359
+ }
2360
+ continue;
2361
+ }
2362
+ }
2363
+ const dom = createDOMNode(vnode);
2364
+ if (dom) {
2365
+ finalNodes.push(dom);
2366
+ created++;
2367
+ }
2368
+ }
2369
+ const tBuild = typeof performance !== "undefined" && performance.now ? performance.now() - t0 : 0;
2370
+ try {
2371
+ const toRemove = Array.from(parent.childNodes).filter(
2372
+ (n) => !finalNodes.includes(n)
2373
+ );
2374
+ for (const n of toRemove) cleanupInstanceIfPresent(n);
2375
+ } catch (e) {
2376
+ void e;
2377
+ }
2378
+ const fragStart = Date.now();
2379
+ const fragment = document.createDocumentFragment();
2380
+ for (let i = 0; i < finalNodes.length; i++)
2381
+ fragment.appendChild(finalNodes[i]);
2382
+ parent.replaceChildren(fragment);
2383
+ const tCommit = Date.now() - fragStart;
2384
+ keyedElements.delete(parent);
2385
+ const stats = {
2386
+ n: newChildren.length,
2387
+ reused,
2388
+ created,
2389
+ tBuild,
2390
+ tCommit
2391
+ };
2392
+ return stats;
2393
+ }
2394
+ function updateElementFromVnode(el, vnode, updateChildren = true) {
2395
+ if (!_isDOMElement(vnode)) {
2396
+ return;
2397
+ }
2398
+ const props = vnode.props || {};
2399
+ if (vnode.key !== void 0) {
2400
+ el.setAttribute("data-key", String(vnode.key));
2401
+ }
2402
+ const existingListeners = elementListeners.get(el);
2403
+ const desiredEventNames = /* @__PURE__ */ new Set();
2404
+ for (const key in props) {
2405
+ const value = props[key];
2406
+ if (key === "children" || key === "key") continue;
2407
+ if (value === void 0 || value === null || value === false) {
2408
+ if (key === "class" || key === "className") {
2409
+ el.className = "";
2410
+ } else if (key.startsWith("on") && key.length > 2) {
2411
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2412
+ if (existingListeners && existingListeners.has(eventName)) {
2413
+ const entry = existingListeners.get(eventName);
2414
+ el.removeEventListener(eventName, entry.handler);
2415
+ existingListeners.delete(eventName);
2416
+ }
2417
+ continue;
2418
+ } else {
2419
+ el.removeAttribute(key);
2420
+ }
2421
+ continue;
2422
+ }
2423
+ if (key === "class" || key === "className") {
2424
+ el.className = String(value);
2425
+ } else if (key === "value" || key === "checked") {
2426
+ el[key] = value;
2427
+ } else if (key.startsWith("on") && key.length > 2) {
2428
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2429
+ desiredEventNames.add(eventName);
2430
+ const existing = existingListeners?.get(eventName);
2431
+ if (existing && existing.original === value) {
2432
+ continue;
2433
+ }
2434
+ if (existing) {
2435
+ el.removeEventListener(eventName, existing.handler);
2436
+ }
2437
+ const wrappedHandler = (event) => {
2438
+ globalScheduler.setInHandler(true);
2439
+ try {
2440
+ value(event);
2441
+ } catch (error) {
2442
+ logger.error("[Askr] Event handler error:", error);
2443
+ } finally {
2444
+ globalScheduler.setInHandler(false);
2445
+ }
2446
+ };
2447
+ el.addEventListener(eventName, wrappedHandler);
2448
+ if (!elementListeners.has(el)) {
2449
+ elementListeners.set(el, /* @__PURE__ */ new Map());
2450
+ }
2451
+ elementListeners.get(el).set(eventName, {
2452
+ handler: wrappedHandler,
2453
+ original: value
2454
+ });
2455
+ } else {
2456
+ el.setAttribute(key, String(value));
2457
+ }
2458
+ }
2459
+ if (existingListeners) {
2460
+ for (const eventName of existingListeners.keys()) {
2461
+ const entry = existingListeners.get(eventName);
2462
+ if (!desiredEventNames.has(eventName)) {
2463
+ el.removeEventListener(eventName, entry.handler);
2464
+ existingListeners.delete(eventName);
2465
+ }
2466
+ }
2467
+ if (existingListeners.size === 0) elementListeners.delete(el);
2468
+ }
2469
+ if (updateChildren) {
2470
+ const children = vnode.children || props.children;
2471
+ updateElementChildren(el, children);
2472
+ }
2473
+ }
2474
+ function updateElementChildren(el, children) {
2475
+ if (!children) {
2476
+ el.textContent = "";
2477
+ return;
2478
+ }
2479
+ if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
2480
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
2481
+ el.firstChild.data = String(children);
2482
+ } else {
2483
+ el.textContent = String(children);
2484
+ }
2485
+ return;
2486
+ }
2487
+ if (Array.isArray(children)) {
2488
+ updateUnkeyedChildren(el, children);
2489
+ return;
2490
+ }
2491
+ el.textContent = "";
2492
+ const dom = createDOMNode(children);
2493
+ if (dom) el.appendChild(dom);
2494
+ }
2495
+ function updateUnkeyedChildren(parent, newChildren) {
2496
+ const existing = Array.from(parent.children);
2497
+ if (existing.length === 0 && parent.childNodes.length > 0) {
2498
+ parent.textContent = "";
2499
+ }
2500
+ const max = Math.max(existing.length, newChildren.length);
2501
+ for (let i = 0; i < max; i++) {
2502
+ const current = existing[i];
2503
+ const next = newChildren[i];
2504
+ if (next === void 0 && current) {
2505
+ cleanupInstanceIfPresent(current);
2506
+ current.remove();
2507
+ continue;
2508
+ }
2509
+ if (!current && next !== void 0) {
2510
+ const dom = createDOMNode(next);
2511
+ if (dom) parent.appendChild(dom);
2512
+ continue;
2513
+ }
2514
+ if (!current || next === void 0) continue;
2515
+ if (typeof next === "string" || typeof next === "number") {
2516
+ current.textContent = String(next);
2517
+ } else if (_isDOMElement(next)) {
2518
+ if (typeof next.type === "string") {
2519
+ if (current.tagName.toLowerCase() === next.type.toLowerCase()) {
2520
+ updateElementFromVnode(current, next);
2521
+ } else {
2522
+ const dom = createDOMNode(next);
2523
+ if (dom) {
2524
+ cleanupInstanceIfPresent(current);
2525
+ parent.replaceChild(dom, current);
2526
+ }
2527
+ }
2528
+ } else {
2529
+ const dom = createDOMNode(next);
2530
+ if (dom) {
2531
+ cleanupInstanceIfPresent(current);
2532
+ parent.replaceChild(dom, current);
2533
+ }
2534
+ }
2535
+ } else {
2536
+ const dom = createDOMNode(next);
2537
+ if (dom) {
2538
+ cleanupInstanceIfPresent(current);
2539
+ parent.replaceChild(dom, current);
2540
+ }
2541
+ }
2542
+ }
2543
+ }
2544
+ function createDOMNode(node) {
2545
+ if (typeof node === "string") {
2546
+ return document.createTextNode(node);
2547
+ }
2548
+ if (typeof node === "number") {
2549
+ return document.createTextNode(String(node));
2550
+ }
2551
+ if (!node) {
2552
+ return null;
2553
+ }
2554
+ if (Array.isArray(node)) {
2555
+ const fragment = document.createDocumentFragment();
2556
+ for (let i = 0; i < node.length; i++) {
2557
+ const dom = createDOMNode(node[i]);
2558
+ if (dom) fragment.appendChild(dom);
2559
+ }
2560
+ return fragment;
2561
+ }
2562
+ if (typeof node === "object" && node !== null && "type" in node) {
2563
+ const type = node.type;
2564
+ const props = node.props || {};
2565
+ if (typeof type === "string") {
2566
+ const el = document.createElement(type);
2567
+ for (const key in props) {
2568
+ const value = props[key];
2569
+ if (key === "children" || key === "key") continue;
2570
+ if (value === void 0 || value === null || value === false) continue;
2571
+ if (key.startsWith("on") && key.length > 2) {
2572
+ const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2573
+ const wrappedHandler = (event) => {
2574
+ globalScheduler.setInHandler(true);
2575
+ try {
2576
+ value(event);
2577
+ } catch (error) {
2578
+ logger.error("[Askr] Event handler error:", error);
2579
+ } finally {
2580
+ globalScheduler.setInHandler(false);
2581
+ const state = globalScheduler.getState();
2582
+ if ((state.queueLength ?? 0) > 0 && !state.running) {
2583
+ queueMicrotask(() => {
2584
+ try {
2585
+ if (!globalScheduler.isExecuting()) globalScheduler.flush();
2586
+ } catch (err) {
2587
+ setTimeout(() => {
2588
+ throw err;
2589
+ });
2590
+ }
2591
+ });
2592
+ }
2593
+ }
2594
+ };
2595
+ el.addEventListener(eventName, wrappedHandler);
2596
+ if (!elementListeners.has(el)) {
2597
+ elementListeners.set(el, /* @__PURE__ */ new Map());
2598
+ }
2599
+ elementListeners.get(el).set(eventName, {
2600
+ handler: wrappedHandler,
2601
+ original: value
2602
+ });
2603
+ } else if (key === "class" || key === "className") {
2604
+ el.className = String(value);
2605
+ } else if (key === "value" || key === "checked") {
2606
+ el[key] = value;
2607
+ el.setAttribute(key, String(value));
2608
+ } else {
2609
+ el.setAttribute(key, String(value));
2610
+ }
2611
+ }
2612
+ const vnodeKey = node.key;
2613
+ if (vnodeKey !== void 0) {
2614
+ el.setAttribute("data-key", String(vnodeKey));
2615
+ }
2616
+ const children = props.children || node.children;
2617
+ if (children) {
2618
+ if (Array.isArray(children)) {
2619
+ if (process.env.NODE_ENV !== "production") {
2620
+ let hasElements = false;
2621
+ let hasKeys = false;
2622
+ for (let i = 0; i < children.length; i++) {
2623
+ const item = children[i];
2624
+ if (typeof item === "object" && item !== null && "type" in item) {
2625
+ hasElements = true;
2626
+ const itemProps = item.props || {};
2627
+ if ("key" in itemProps) {
2628
+ hasKeys = true;
2629
+ break;
2630
+ }
2631
+ }
2632
+ }
2633
+ if (hasElements && !hasKeys) {
2634
+ if (typeof console !== "undefined") {
2635
+ logger.warn(
2636
+ 'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
2637
+ );
2638
+ }
2639
+ }
2640
+ }
2641
+ for (let i = 0; i < children.length; i++) {
2642
+ const dom = createDOMNode(children[i]);
2643
+ if (dom) el.appendChild(dom);
2644
+ }
2645
+ } else {
2646
+ const dom = createDOMNode(children);
2647
+ if (dom) el.appendChild(dom);
2648
+ }
2649
+ }
2650
+ return el;
2651
+ }
2652
+ if (typeof type === "function") {
2653
+ const frame = node[CONTEXT_FRAME_SYMBOL];
2654
+ const snapshot = frame || getCurrentContextFrame();
2655
+ const componentFn = type;
2656
+ const isAsync = componentFn.constructor.name === "AsyncFunction";
2657
+ if (isAsync) {
2658
+ throw new Error(
2659
+ "Async components are not supported. Use resource() for async work."
2660
+ );
2661
+ }
2662
+ const vnodeAny = node;
2663
+ let childInstance = vnodeAny.__instance;
2664
+ if (!childInstance) {
2665
+ childInstance = createComponentInstance(
2666
+ `comp-${Math.random().toString(36).slice(2, 7)}`,
2667
+ componentFn,
2668
+ props || {},
2669
+ null
2670
+ );
2671
+ vnodeAny.__instance = childInstance;
2672
+ }
2673
+ if (snapshot) {
2674
+ childInstance.ownerFrame = snapshot;
2675
+ }
2676
+ const result = withContext(
2677
+ snapshot,
2678
+ () => renderComponentInline(childInstance)
2679
+ );
2680
+ if (result instanceof Promise) {
2681
+ throw new Error(
2682
+ "Async components are not supported. Components must return synchronously."
2683
+ );
2684
+ }
2685
+ const dom = withContext(snapshot, () => createDOMNode(result));
2686
+ if (dom instanceof Element) {
2687
+ mountInstanceInline(childInstance, dom);
2688
+ } else {
2689
+ const host = document.createElement("div");
2690
+ mountInstanceInline(childInstance, host);
2691
+ }
2692
+ return dom;
2693
+ }
2694
+ if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
2695
+ const fragment = document.createDocumentFragment();
2696
+ const children = props.children || node.children;
2697
+ if (children) {
2698
+ if (Array.isArray(children)) {
2699
+ for (let i = 0; i < children.length; i++) {
2700
+ const dom = createDOMNode(children[i]);
2701
+ if (dom) fragment.appendChild(dom);
2702
+ }
2703
+ } else {
2704
+ const dom = createDOMNode(children);
2705
+ if (dom) fragment.appendChild(dom);
2706
+ }
2707
+ }
2708
+ return fragment;
2709
+ }
2710
+ }
2711
+ return null;
2712
+ }
2713
+ var domRanges, elementListeners, keyedElements, _reconcilerRecordedParents;
2714
+ var init_dom = __esm({
2715
+ "src/renderer/dom.ts"() {
2716
+ "use strict";
2717
+ init_scheduler();
2718
+ init_fastlane();
2719
+ init_logger();
2720
+ init_jsx_runtime();
2721
+ init_context();
2722
+ init_component();
2723
+ domRanges = /* @__PURE__ */ new WeakMap();
2724
+ elementListeners = /* @__PURE__ */ new WeakMap();
2725
+ keyedElements = /* @__PURE__ */ new WeakMap();
2726
+ _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
2727
+ if (typeof globalThis !== "undefined") {
2728
+ const _g = globalThis;
2729
+ _g.__ASKR_RENDERER = {
2730
+ evaluate,
2731
+ isKeyedReorderFastPathEligible,
2732
+ getKeyMapForElement
2733
+ };
2734
+ }
2735
+ }
2736
+ });
2737
+
2738
+ // src/runtime/component.ts
2739
+ var component_exports = {};
2740
+ __export(component_exports, {
2741
+ cleanupComponent: () => cleanupComponent,
2742
+ createComponentInstance: () => createComponentInstance,
2743
+ executeComponent: () => executeComponent,
2744
+ finalizeReadSubscriptions: () => finalizeReadSubscriptions,
2745
+ getCurrentComponentInstance: () => getCurrentComponentInstance,
2746
+ getCurrentInstance: () => getCurrentInstance,
2747
+ getNextStateIndex: () => getNextStateIndex,
2748
+ getSignal: () => getSignal,
2749
+ mountComponent: () => mountComponent,
2750
+ mountInstanceInline: () => mountInstanceInline,
2751
+ registerMountOperation: () => registerMountOperation,
2752
+ renderComponentInline: () => renderComponentInline,
2753
+ setCurrentComponentInstance: () => setCurrentComponentInstance
2754
+ });
2755
+ function createComponentInstance(id, fn, props, target) {
2756
+ const instance = {
2757
+ id,
2758
+ fn,
2759
+ props,
2760
+ target,
2761
+ mounted: false,
2762
+ abortController: new AbortController(),
2763
+ // Create per-component
2764
+ stateValues: [],
2765
+ evaluationGeneration: 0,
2766
+ notifyUpdate: null,
2767
+ // Prebound helpers (initialized below) to avoid per-update allocations
2768
+ _pendingFlushTask: void 0,
2769
+ _pendingRunTask: void 0,
2770
+ _enqueueRun: void 0,
2771
+ stateIndexCheck: -1,
2772
+ expectedStateIndices: [],
2773
+ firstRenderComplete: false,
2774
+ mountOperations: [],
2775
+ cleanupFns: [],
2776
+ hasPendingUpdate: false,
2777
+ ownerFrame: null,
2778
+ // Will be set by renderer when vnode is marked
2779
+ ssr: false,
2780
+ isRoot: false,
2781
+ // Render-tracking (for precise state subscriptions)
2782
+ _currentRenderToken: void 0,
2783
+ lastRenderToken: 0,
2784
+ _pendingReadStates: /* @__PURE__ */ new Set(),
2785
+ _lastReadStates: /* @__PURE__ */ new Set()
2786
+ };
2787
+ instance._pendingRunTask = () => {
2788
+ instance.hasPendingUpdate = false;
2789
+ runComponent(instance);
2790
+ };
2791
+ instance._enqueueRun = () => {
2792
+ if (!instance.hasPendingUpdate) {
2793
+ instance.hasPendingUpdate = true;
2794
+ globalScheduler.enqueue(instance._pendingRunTask);
2795
+ }
2796
+ };
2797
+ instance._pendingFlushTask = () => {
2798
+ instance.hasPendingUpdate = false;
2799
+ instance._enqueueRun?.();
2800
+ };
2801
+ return instance;
2802
+ }
2803
+ function getCurrentComponentInstance() {
2804
+ return currentInstance;
2805
+ }
2806
+ function setCurrentComponentInstance(instance) {
2807
+ currentInstance = instance;
2808
+ }
2809
+ function registerMountOperation(operation) {
2810
+ const instance = getCurrentComponentInstance();
2811
+ if (instance) {
2812
+ if (isBulkCommitActive2()) {
2813
+ if (process.env.NODE_ENV !== "production") {
2814
+ throw new Error(
2815
+ "registerMountOperation called during bulk commit fast-lane"
2816
+ );
2817
+ }
2818
+ return;
2819
+ }
2820
+ instance.mountOperations.push(operation);
2821
+ }
2822
+ }
2823
+ function executeMountOperations(instance) {
2824
+ if (!instance.isRoot) return;
2825
+ for (const operation of instance.mountOperations) {
2826
+ const result = operation();
2827
+ if (result instanceof Promise) {
2828
+ result.then((cleanup) => {
2829
+ if (typeof cleanup === "function") {
2830
+ instance.cleanupFns.push(cleanup);
2831
+ }
2832
+ });
2833
+ } else if (typeof result === "function") {
2834
+ instance.cleanupFns.push(result);
2835
+ }
2836
+ }
2837
+ instance.mountOperations = [];
2838
+ }
2839
+ function mountInstanceInline(instance, target) {
2840
+ instance.target = target;
2841
+ try {
2842
+ if (target instanceof Element)
2843
+ target.__ASKR_INSTANCE = instance;
2844
+ } catch (err) {
2845
+ void err;
2846
+ }
2847
+ instance.notifyUpdate = instance._enqueueRun;
2848
+ const wasFirstMount = !instance.mounted;
2849
+ instance.mounted = true;
2850
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2851
+ executeMountOperations(instance);
2852
+ }
2853
+ }
2854
+ function runComponent(instance) {
2855
+ instance.notifyUpdate = instance._enqueueRun;
2856
+ instance._currentRenderToken = ++_globalRenderCounter;
2857
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2858
+ const domSnapshot = instance.target ? instance.target.innerHTML : "";
2859
+ const result = executeComponentSync(instance);
2860
+ if (result instanceof Promise) {
2861
+ throw new Error(
2862
+ "Async components are not supported. Components must be synchronous."
2863
+ );
2864
+ } else {
2865
+ const fastlaneBridge = globalThis.__ASKR_FASTLANE;
2866
+ try {
2867
+ const used = fastlaneBridge?.tryRuntimeFastLaneSync?.(instance, result);
2868
+ if (used) return;
2869
+ } catch (err) {
2870
+ if (process.env.NODE_ENV !== "production") throw err;
2871
+ }
2872
+ globalScheduler.enqueue(() => {
2873
+ if (instance.target) {
2874
+ try {
2875
+ const wasFirstMount = !instance.mounted;
2876
+ const oldInstance = currentInstance;
2877
+ currentInstance = instance;
2878
+ try {
2879
+ evaluate(result, instance.target);
2880
+ } finally {
2881
+ currentInstance = oldInstance;
2882
+ }
2883
+ finalizeReadSubscriptions(instance);
2884
+ instance.mounted = true;
2885
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2886
+ executeMountOperations(instance);
2887
+ }
2888
+ } catch (renderError) {
2889
+ instance.target.innerHTML = domSnapshot;
2890
+ throw renderError;
2891
+ }
2892
+ }
2893
+ });
2894
+ }
2895
+ }
2896
+ function renderComponentInline(instance) {
2897
+ const hadToken = instance._currentRenderToken !== void 0;
2898
+ if (!hadToken) {
2899
+ instance._currentRenderToken = ++_globalRenderCounter;
2900
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2901
+ }
2902
+ try {
2903
+ const result = executeComponentSync(instance);
2904
+ if (!hadToken) {
2905
+ finalizeReadSubscriptions(instance);
2906
+ }
2907
+ return result;
2908
+ } finally {
2909
+ if (!hadToken) {
2910
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2911
+ instance._currentRenderToken = void 0;
2912
+ }
2913
+ }
2914
+ }
2915
+ function executeComponentSync(instance) {
2916
+ instance.stateIndexCheck = -1;
2917
+ for (const state of instance.stateValues) {
2918
+ if (state) {
2919
+ state._hasBeenRead = false;
2920
+ }
2921
+ }
2922
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2923
+ currentInstance = instance;
2924
+ stateIndex = 0;
2925
+ try {
2926
+ const renderStartTime = process.env.NODE_ENV !== "production" ? Date.now() : 0;
2927
+ const context = {
2928
+ signal: instance.abortController.signal
2929
+ };
2930
+ const executionFrame = {
2931
+ parent: instance.ownerFrame,
2932
+ values: null
2933
+ };
2934
+ const result = withContext(
2935
+ executionFrame,
2936
+ () => instance.fn(instance.props, context)
2937
+ );
2938
+ if (process.env.NODE_ENV !== "production") {
2939
+ const renderTime = Date.now() - renderStartTime;
2940
+ if (renderTime > 5) {
2941
+ logger.warn(
2942
+ `[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`
2943
+ );
2944
+ }
2945
+ }
2946
+ if (!instance.firstRenderComplete) {
2947
+ instance.firstRenderComplete = true;
2948
+ }
2949
+ if (process.env.NODE_ENV !== "production") {
2950
+ for (let i = 0; i < instance.stateValues.length; i++) {
2951
+ const state = instance.stateValues[i];
2952
+ if (state && !state._hasBeenRead) {
2953
+ logger.warn(
2954
+ `[askr] Unused state variable detected. State should be read during render or removed.`
2955
+ );
2956
+ }
2957
+ }
2958
+ }
2959
+ return result;
2960
+ } finally {
2961
+ currentInstance = null;
2962
+ }
2963
+ }
2964
+ function executeComponent(instance) {
2965
+ instance.abortController = new AbortController();
2966
+ instance.notifyUpdate = instance._enqueueRun;
2967
+ globalScheduler.enqueue(() => runComponent(instance));
2968
+ }
2969
+ function getCurrentInstance() {
2970
+ return currentInstance;
2971
+ }
2972
+ function getSignal() {
2973
+ if (!currentInstance) {
2974
+ throw new Error(
2975
+ "getSignal() can only be called during component render execution. Ensure you are calling this from inside your component function."
2976
+ );
2977
+ }
2978
+ return currentInstance.abortController.signal;
2979
+ }
2980
+ function finalizeReadSubscriptions(instance) {
2981
+ const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
2982
+ const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
2983
+ const token = instance._currentRenderToken;
2984
+ if (token === void 0) return;
2985
+ for (const s of oldSet) {
2986
+ if (!newSet.has(s)) {
2987
+ const readers = s?._readers;
2988
+ if (readers) readers.delete(instance);
2989
+ }
2990
+ }
2991
+ instance.lastRenderToken = token;
2992
+ for (const s of newSet) {
2993
+ let readers = s?._readers;
2994
+ if (!readers) {
2995
+ readers = /* @__PURE__ */ new Map();
2996
+ s._readers = readers;
2997
+ }
2998
+ readers.set(instance, instance.lastRenderToken ?? 0);
2999
+ }
3000
+ instance._lastReadStates = newSet;
3001
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
3002
+ instance._currentRenderToken = void 0;
3003
+ }
3004
+ function getNextStateIndex() {
3005
+ return stateIndex++;
3006
+ }
3007
+ function mountComponent(instance) {
3008
+ executeComponent(instance);
3009
+ }
3010
+ function cleanupComponent(instance) {
3011
+ for (const cleanup of instance.cleanupFns) {
3012
+ cleanup();
3013
+ }
3014
+ instance.cleanupFns = [];
3015
+ if (instance._lastReadStates) {
3016
+ for (const s of instance._lastReadStates) {
3017
+ const readers = s?._readers;
3018
+ if (readers) readers.delete(instance);
3019
+ }
3020
+ instance._lastReadStates = /* @__PURE__ */ new Set();
3021
+ }
3022
+ instance.abortController.abort();
3023
+ }
3024
+ var currentInstance, stateIndex, _globalRenderCounter;
3025
+ var init_component = __esm({
3026
+ "src/runtime/component.ts"() {
3027
+ "use strict";
3028
+ init_dom();
3029
+ init_scheduler();
3030
+ init_context();
3031
+ init_logger();
3032
+ init_fastlane();
3033
+ currentInstance = null;
3034
+ stateIndex = 0;
3035
+ _globalRenderCounter = 0;
3036
+ }
3037
+ });
3038
+
3039
+ // src/router/route.ts
3040
+ var route_exports = {};
3041
+ __export(route_exports, {
3042
+ _lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
3043
+ _unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
3044
+ clearRoutes: () => clearRoutes,
3045
+ getLoadedNamespaces: () => getLoadedNamespaces,
3046
+ getNamespaceRoutes: () => getNamespaceRoutes,
3047
+ getRoutes: () => getRoutes,
3048
+ lockRouteRegistration: () => lockRouteRegistration,
3049
+ registerRoute: () => registerRoute,
3050
+ resolveRoute: () => resolveRoute,
3051
+ route: () => route,
3052
+ setServerLocation: () => setServerLocation,
3053
+ unloadNamespace: () => unloadNamespace
3054
+ });
3055
+
3056
+ // src/router/match.ts
3057
+ function match(path, pattern) {
3058
+ const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3059
+ const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
3060
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
3061
+ const patternSegments = normalizedPattern.split("/").filter(Boolean);
3062
+ if (patternSegments.length === 1 && patternSegments[0] === "*") {
3063
+ return {
3064
+ matched: true,
3065
+ params: {
3066
+ "*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
3067
+ }
3068
+ };
3069
+ }
3070
+ if (pathSegments.length !== patternSegments.length) {
3071
+ return { matched: false, params: {} };
3072
+ }
3073
+ const params = {};
3074
+ for (let i = 0; i < patternSegments.length; i++) {
3075
+ const patternSegment = patternSegments[i];
3076
+ const pathSegment = pathSegments[i];
3077
+ if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
3078
+ const paramName = patternSegment.slice(1, -1);
3079
+ params[paramName] = decodeURIComponent(pathSegment);
3080
+ } else if (patternSegment === "*") {
3081
+ params["*"] = pathSegment;
3082
+ } else if (patternSegment !== pathSegment) {
3083
+ return { matched: false, params: {} };
3084
+ }
3085
+ }
3086
+ return { matched: true, params };
3087
+ }
3088
+
3089
+ // src/router/route.ts
3090
+ init_component();
3091
+ var routes = [];
3092
+ var namespaces = /* @__PURE__ */ new Set();
3093
+ var routesByDepth = /* @__PURE__ */ new Map();
3094
+ function getDepth(path) {
3095
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3096
+ return normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3097
+ }
3098
+ function getSpecificity(path) {
3099
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3100
+ if (normalized === "/*") {
3101
+ return 0;
3102
+ }
3103
+ const segments = normalized.split("/").filter(Boolean);
3104
+ let score = 0;
3105
+ for (const segment of segments) {
3106
+ if (segment.startsWith("{") && segment.endsWith("}")) {
3107
+ score += 2;
3108
+ } else if (segment === "*") {
3109
+ score += 1;
3110
+ } else {
3111
+ score += 3;
3112
+ }
3113
+ }
3114
+ return score;
3115
+ }
3116
+ var serverLocation = null;
3117
+ function setServerLocation(url) {
3118
+ serverLocation = url;
3119
+ }
3120
+ function parseLocation(url) {
3121
+ try {
3122
+ const u = new URL(url, "http://localhost");
3123
+ return { pathname: u.pathname, search: u.search, hash: u.hash };
3124
+ } catch {
3125
+ return { pathname: "/", search: "", hash: "" };
3126
+ }
3127
+ }
3128
+ function deepFreeze(obj) {
3129
+ if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
3130
+ Object.freeze(obj);
3131
+ for (const key of Object.keys(obj)) {
3132
+ const value = obj[key];
3133
+ if (value && typeof value === "object") deepFreeze(value);
3134
+ }
3135
+ }
3136
+ return obj;
3137
+ }
3138
+ function makeQuery(search) {
3139
+ const usp = new URLSearchParams(search || "");
3140
+ const mapping = /* @__PURE__ */ new Map();
3141
+ for (const [k, v] of usp.entries()) {
3142
+ const existing = mapping.get(k);
3143
+ if (existing) existing.push(v);
3144
+ else mapping.set(k, [v]);
3145
+ }
3146
+ const obj = {
3147
+ get(key) {
3148
+ const arr = mapping.get(key);
3149
+ return arr ? arr[0] : null;
3150
+ },
3151
+ getAll(key) {
3152
+ const arr = mapping.get(key);
3153
+ return arr ? [...arr] : [];
3154
+ },
3155
+ has(key) {
3156
+ return mapping.has(key);
3157
+ },
3158
+ toJSON() {
3159
+ const out = {};
3160
+ for (const [k, arr] of mapping.entries()) {
3161
+ out[k] = arr.length > 1 ? [...arr] : arr[0];
3162
+ }
3163
+ return out;
3164
+ }
3165
+ };
3166
+ return deepFreeze(obj);
3167
+ }
3168
+ function computeMatches(pathname) {
3169
+ const routesList = getRoutes();
3170
+ const matches = [];
3171
+ function getSpecificity2(path) {
3172
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3173
+ if (normalized === "/*") return 0;
3174
+ const segments = normalized.split("/").filter(Boolean);
3175
+ let score = 0;
3176
+ for (const segment of segments) {
3177
+ if (segment.startsWith("{") && segment.endsWith("}")) score += 2;
3178
+ else if (segment === "*") score += 1;
3179
+ else score += 3;
3180
+ }
3181
+ return score;
3182
+ }
3183
+ for (const r of routesList) {
3184
+ const result = match(pathname, r.path);
3185
+ if (result.matched) {
3186
+ matches.push({
3187
+ pattern: r.path,
3188
+ params: result.params,
3189
+ name: r.name,
3190
+ namespace: r.namespace,
3191
+ specificity: getSpecificity2(r.path)
3192
+ });
3193
+ }
3194
+ }
3195
+ matches.sort((a, b) => b.specificity - a.specificity);
3196
+ return matches.map((m) => ({
3197
+ path: m.pattern,
3198
+ params: deepFreeze({ ...m.params }),
3199
+ name: m.name,
3200
+ namespace: m.namespace
3201
+ }));
3202
+ }
3203
+ var registrationLocked = false;
3204
+ function lockRouteRegistration() {
3205
+ registrationLocked = true;
3206
+ }
3207
+ function _lockRouteRegistrationForTests() {
3208
+ registrationLocked = true;
3209
+ }
3210
+ function _unlockRouteRegistrationForTests() {
3211
+ registrationLocked = false;
3212
+ }
3213
+ function route(path, handler, namespace) {
3214
+ if (typeof path === "undefined") {
3215
+ const instance = getCurrentComponentInstance();
3216
+ if (!instance) {
3217
+ throw new Error(
3218
+ "route() can only be called during component render execution. Call route() from inside your component function."
3219
+ );
3220
+ }
3221
+ let pathname = "/";
3222
+ let search = "";
3223
+ let hash = "";
3224
+ if (typeof window !== "undefined" && window.location) {
3225
+ pathname = window.location.pathname || "/";
3226
+ search = window.location.search || "";
3227
+ hash = window.location.hash || "";
3228
+ } else if (serverLocation) {
3229
+ const parsed = parseLocation(serverLocation);
3230
+ pathname = parsed.pathname;
3231
+ search = parsed.search;
3232
+ hash = parsed.hash;
3233
+ }
3234
+ const params = deepFreeze({
3235
+ ...instance.props || {}
3236
+ });
3237
+ const query = makeQuery(search);
3238
+ const matches = computeMatches(pathname);
3239
+ const snapshot = Object.freeze({
3240
+ path: pathname,
3241
+ params,
3242
+ query,
3243
+ hash: hash || null,
3244
+ matches: Object.freeze(matches)
3245
+ });
3246
+ return snapshot;
3247
+ }
3248
+ const currentInst = getCurrentComponentInstance();
3249
+ if (currentInst && currentInst.ssr) {
3250
+ throw new Error(
3251
+ "route() cannot be called during SSR rendering. Register routes at module load time instead."
3252
+ );
3253
+ }
3254
+ if (registrationLocked) {
3255
+ throw new Error(
3256
+ "Route registration is locked after app startup. Register routes at module load time before calling createApp()."
3257
+ );
3258
+ }
3259
+ if (typeof handler !== "function") {
3260
+ throw new Error(
3261
+ "route(path, handler) requires a function handler that returns a VNode (e.g. () => <Page />). Passing JSX elements or VNodes directly is not supported."
3262
+ );
3263
+ }
3264
+ const routeObj = { path, handler, namespace };
3265
+ routes.push(routeObj);
3266
+ const depth = getDepth(path);
3267
+ let depthRoutes = routesByDepth.get(depth);
3268
+ if (!depthRoutes) {
3269
+ depthRoutes = [];
3270
+ routesByDepth.set(depth, depthRoutes);
3271
+ }
3272
+ depthRoutes.push(routeObj);
3273
+ if (namespace) {
3274
+ namespaces.add(namespace);
3275
+ }
3276
+ }
3277
+ function getRoutes() {
3278
+ return [...routes];
3279
+ }
3280
+ function getNamespaceRoutes(namespace) {
3281
+ return routes.filter((r) => r.namespace === namespace);
3282
+ }
3283
+ function unloadNamespace(namespace) {
3284
+ const before = routes.length;
3285
+ for (let i = routes.length - 1; i >= 0; i--) {
3286
+ if (routes[i].namespace === namespace) {
3287
+ const removed = routes[i];
3288
+ routes.splice(i, 1);
3289
+ const depth = getDepth(removed.path);
3290
+ const depthRoutes = routesByDepth.get(depth);
3291
+ if (depthRoutes) {
3292
+ const idx = depthRoutes.indexOf(removed);
3293
+ if (idx >= 0) {
3294
+ depthRoutes.splice(idx, 1);
3295
+ }
3296
+ }
3297
+ }
3298
+ }
3299
+ namespaces.delete(namespace);
3300
+ return before - routes.length;
3301
+ }
3302
+ function clearRoutes() {
3303
+ routes.length = 0;
3304
+ namespaces.clear();
3305
+ routesByDepth.clear();
3306
+ }
3307
+ function normalizeHandler(handler) {
3308
+ if (handler == null) return void 0;
3309
+ if (typeof handler === "function") {
3310
+ return (params, ctx) => {
3311
+ try {
3312
+ return handler(params, ctx);
3313
+ } catch {
3314
+ return handler(params);
3315
+ }
3316
+ };
3317
+ }
3318
+ return void 0;
3319
+ }
3320
+ function registerRoute(path, handler, ...children) {
3321
+ const isRelative = !path.startsWith("/");
3322
+ const descriptor = {
3323
+ path,
3324
+ handler,
3325
+ children: children.filter(Boolean),
3326
+ _isDescriptor: true
3327
+ };
3328
+ if (!isRelative) {
3329
+ const normalized = normalizeHandler(handler);
3330
+ if (handler != null && !normalized) {
3331
+ throw new Error(
3332
+ "registerRoute(path, handler) requires a function handler. Passing JSX elements or VNodes directly is not supported."
3333
+ );
3334
+ }
3335
+ if (normalized) route(path, normalized);
3336
+ for (const child of descriptor.children || []) {
3337
+ const base = path === "/" ? "" : path.replace(/\/$/, "");
3338
+ const childPath = `${base}/${child.path.replace(/^\//, "")}`.replace(
3339
+ /\/\//g,
3340
+ "/"
3341
+ );
3342
+ if (child.handler) {
3343
+ const childNormalized = normalizeHandler(child.handler);
3344
+ if (!childNormalized) {
3345
+ throw new Error(
3346
+ "registerRoute child handler must be a function. Passing JSX elements directly is not supported."
3347
+ );
3348
+ }
3349
+ if (childNormalized) route(childPath, childNormalized);
3350
+ }
3351
+ if (child.children && child.children.length) {
3352
+ registerRoute(
3353
+ childPath,
3354
+ null,
3355
+ ...child.children
3356
+ );
3357
+ }
3358
+ }
3359
+ return descriptor;
3360
+ }
3361
+ return descriptor;
3362
+ }
3363
+ function getLoadedNamespaces() {
3364
+ return Array.from(namespaces);
3365
+ }
3366
+ function resolveRoute(pathname) {
3367
+ const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
3368
+ const depth = normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3369
+ const candidates = [];
3370
+ const depthRoutes = routesByDepth.get(depth);
3371
+ if (depthRoutes) {
3372
+ for (const r of depthRoutes) {
3373
+ const result = match(pathname, r.path);
3374
+ if (result.matched) {
3375
+ candidates.push({
3376
+ route: r,
3377
+ specificity: getSpecificity(r.path),
3378
+ params: result.params
3379
+ });
3380
+ }
3381
+ }
3382
+ }
3383
+ for (const r of routes) {
3384
+ if (depthRoutes?.includes(r)) continue;
3385
+ const result = match(pathname, r.path);
3386
+ if (result.matched) {
3387
+ candidates.push({
3388
+ route: r,
3389
+ specificity: getSpecificity(r.path),
3390
+ params: result.params
3391
+ });
3392
+ }
3393
+ }
3394
+ candidates.sort((a, b) => b.specificity - a.specificity);
3395
+ if (candidates.length > 0) {
3396
+ const best = candidates[0];
3397
+ return { handler: best.route.handler, params: best.params };
3398
+ }
3399
+ return null;
3400
+ }
3401
+
3402
+ export {
3403
+ invariant,
3404
+ init_invariant,
3405
+ logger,
3406
+ init_logger,
3407
+ globalScheduler,
3408
+ scheduleEventHandler,
3409
+ init_scheduler,
3410
+ isBulkCommitActive2 as isBulkCommitActive,
3411
+ init_fastlane,
3412
+ withAsyncResourceContext,
3413
+ defineContext,
3414
+ readContext,
3415
+ getCurrentContextFrame,
3416
+ init_context,
3417
+ removeAllListeners,
3418
+ init_dom,
3419
+ createComponentInstance,
3420
+ getCurrentComponentInstance,
3421
+ setCurrentComponentInstance,
3422
+ getCurrentInstance,
3423
+ getSignal,
3424
+ getNextStateIndex,
3425
+ mountComponent,
3426
+ cleanupComponent,
3427
+ init_component,
3428
+ setServerLocation,
3429
+ lockRouteRegistration,
3430
+ _lockRouteRegistrationForTests,
3431
+ _unlockRouteRegistrationForTests,
3432
+ route,
3433
+ getRoutes,
3434
+ getNamespaceRoutes,
3435
+ unloadNamespace,
3436
+ clearRoutes,
3437
+ registerRoute,
3438
+ getLoadedNamespaces,
3439
+ resolveRoute,
3440
+ route_exports
3441
+ };
3442
+ //# sourceMappingURL=chunk-L7RL4LYV.js.map