@askrjs/askr 0.0.3 → 0.0.5

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 (62) hide show
  1. package/README.md +8 -5
  2. package/dist/fx.d.ts +186 -0
  3. package/dist/fx.js +636 -0
  4. package/dist/fx.js.map +1 -0
  5. package/dist/index.d.ts +74 -407
  6. package/dist/index.js +3706 -779
  7. package/dist/index.js.map +1 -1
  8. package/dist/{types-DLTViI21.d.ts → jsx-AzPM8gMS.d.ts} +6 -21
  9. package/dist/{jsx/jsx-dev-runtime.d.ts → jsx-dev-runtime.d.ts} +3 -2
  10. package/dist/jsx-dev-runtime.js +17 -0
  11. package/dist/jsx-dev-runtime.js.map +1 -0
  12. package/dist/jsx-runtime.d.ts +14 -0
  13. package/dist/{chunk-SALJX5PZ.js → jsx-runtime.js} +6 -9
  14. package/dist/jsx-runtime.js.map +1 -0
  15. package/dist/resources.d.ts +21 -0
  16. package/dist/resources.js +785 -0
  17. package/dist/resources.js.map +1 -0
  18. package/dist/router-DaGtH1Sq.d.ts +36 -0
  19. package/dist/router.d.ts +64 -0
  20. package/dist/{chunk-2ONGHQ7Z.js → router.js} +719 -689
  21. package/dist/router.js.map +1 -0
  22. package/dist/ssr.d.ts +123 -0
  23. package/dist/{index.cjs → ssr.js} +1472 -2737
  24. package/dist/ssr.js.map +1 -0
  25. package/dist/types-uOPfcrdz.d.ts +25 -0
  26. package/dist/vite/index.d.ts +17 -0
  27. package/dist/vite/index.js +2306 -0
  28. package/dist/vite/index.js.map +1 -0
  29. package/package.json +37 -28
  30. package/dist/chunk-2ONGHQ7Z.js.map +0 -1
  31. package/dist/chunk-H3NSVHA7.js +0 -80
  32. package/dist/chunk-H3NSVHA7.js.map +0 -1
  33. package/dist/chunk-JHOGWTAW.js +0 -16
  34. package/dist/chunk-JHOGWTAW.js.map +0 -1
  35. package/dist/chunk-OFW6DFBM.js +0 -716
  36. package/dist/chunk-OFW6DFBM.js.map +0 -1
  37. package/dist/chunk-SALJX5PZ.js.map +0 -1
  38. package/dist/index.cjs.map +0 -1
  39. package/dist/index.d.cts +0 -501
  40. package/dist/jsx/jsx-dev-runtime.cjs +0 -46
  41. package/dist/jsx/jsx-dev-runtime.cjs.map +0 -1
  42. package/dist/jsx/jsx-dev-runtime.d.cts +0 -11
  43. package/dist/jsx/jsx-dev-runtime.js +0 -19
  44. package/dist/jsx/jsx-dev-runtime.js.map +0 -1
  45. package/dist/jsx/jsx-runtime.cjs +0 -54
  46. package/dist/jsx/jsx-runtime.cjs.map +0 -1
  47. package/dist/jsx/jsx-runtime.d.cts +0 -20
  48. package/dist/jsx/jsx-runtime.d.ts +0 -20
  49. package/dist/jsx/jsx-runtime.js +0 -16
  50. package/dist/jsx/jsx-runtime.js.map +0 -1
  51. package/dist/navigate-CZEUXFPM.js +0 -16
  52. package/dist/navigate-CZEUXFPM.js.map +0 -1
  53. package/dist/route-USEXGOBT.js +0 -31
  54. package/dist/route-USEXGOBT.js.map +0 -1
  55. package/dist/ssr-QJ5NTQR6.js +0 -28
  56. package/dist/ssr-QJ5NTQR6.js.map +0 -1
  57. package/dist/types-DLTViI21.d.cts +0 -50
  58. package/src/jsx/index.ts +0 -4
  59. package/src/jsx/jsx-dev-runtime.ts +0 -23
  60. package/src/jsx/jsx-runtime.ts +0 -48
  61. package/src/jsx/types.ts +0 -46
  62. package/src/jsx/utils.ts +0 -19
package/dist/index.js CHANGED
@@ -1,792 +1,753 @@
1
- import {
2
- initializeNavigation,
3
- navigate,
4
- registerAppInstance
5
- } from "./chunk-H3NSVHA7.js";
6
- import {
7
- DefaultPortal,
8
- SSRDataMissingError,
9
- _resetDefaultPortal,
10
- cloneElement,
11
- collectResources,
12
- definePortal,
13
- getCurrentRenderData,
14
- getCurrentSSRContext,
15
- getNextKey,
16
- isElement,
17
- renderToStream,
18
- renderToString,
19
- renderToStringSync,
20
- renderToStringSyncForUrl,
21
- resolveResources,
22
- throwSSRDataMissing
23
- } from "./chunk-OFW6DFBM.js";
24
- import {
25
- cleanupComponent,
26
- clearRoutes,
27
- createComponentInstance,
28
- defineContext,
29
- enterBulkCommit,
30
- exitBulkCommit,
31
- finalizeReadSubscriptions,
32
- getCurrentComponentInstance,
33
- getCurrentContextFrame,
34
- getCurrentInstance,
35
- getDevValue,
36
- getKeyMapForElement,
37
- getLoadedNamespaces,
38
- getNamespaceRoutes,
39
- getNextStateIndex,
40
- getRoutes,
41
- getSignal,
42
- globalScheduler,
43
- invariant,
44
- isBulkCommitActive,
45
- isFastPathApplied,
46
- isKeyedReorderFastPathEligible,
47
- logger,
48
- markFastPathApplied,
49
- mountComponent,
50
- populateKeyMapForElement,
51
- readContext,
52
- registerMountOperation,
53
- removeAllListeners,
54
- route,
55
- scheduleEventHandler,
56
- setDevValue,
57
- setServerLocation,
58
- unloadNamespace,
59
- withAsyncResourceContext
60
- } from "./chunk-2ONGHQ7Z.js";
61
- import {
62
- Fragment as Fragment2,
63
- jsx,
64
- jsxs
65
- } from "./chunk-SALJX5PZ.js";
66
- import {
67
- ELEMENT_TYPE,
68
- Fragment
69
- } from "./chunk-JHOGWTAW.js";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
70
10
 
71
- // src/runtime/state.ts
72
- function state(initialValue) {
73
- const instance = getCurrentInstance();
74
- if (!instance) {
75
- throw new Error(
76
- "state() can only be called during component render execution. Move state() calls to the top level of your component function."
77
- );
78
- }
79
- const index = getNextStateIndex();
80
- const stateValues = instance.stateValues;
81
- if (index < instance.stateIndexCheck) {
82
- throw new Error(
83
- `State index violation: state() call at index ${index}, but previously saw index ${instance.stateIndexCheck}. This happens when state() is called conditionally (inside if/for/etc). Move all state() calls to the top level of your component function, before any conditionals.`
84
- );
11
+ // src/dev/invariant.ts
12
+ function invariant(condition, message, context) {
13
+ if (!condition) {
14
+ const contextStr = "";
15
+ throw new Error(`[Askr Invariant] ${message}${contextStr}`);
85
16
  }
86
- invariant(
87
- index >= instance.stateIndexCheck,
88
- "[State] State indices must increase monotonically"
89
- );
90
- instance.stateIndexCheck = index;
91
- if (instance.firstRenderComplete) {
92
- if (!instance.expectedStateIndices.includes(index)) {
93
- throw new Error(
94
- `Hook order violation: state() called at index ${index}, but this index was not in the first render's sequence [${instance.expectedStateIndices.join(", ")}]. This usually means state() is inside a conditional or loop. Move all state() calls to the top level of your component function.`
95
- );
96
- }
97
- } else {
98
- instance.expectedStateIndices.push(index);
17
+ }
18
+ function assertSchedulingPrecondition(condition, violationMessage) {
19
+ invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
20
+ }
21
+ var init_invariant = __esm({
22
+ "src/dev/invariant.ts"() {
99
23
  }
100
- if (stateValues[index]) {
101
- const existing = stateValues[index];
102
- if (existing._owner !== instance) {
103
- throw new Error(
104
- `State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
105
- );
24
+ });
25
+
26
+ // src/dev/logger.ts
27
+ function callConsole(method, args) {
28
+ const c = typeof console !== "undefined" ? console : void 0;
29
+ if (!c) return;
30
+ const fn = c[method];
31
+ if (typeof fn === "function") {
32
+ try {
33
+ fn.apply(console, args);
34
+ } catch {
106
35
  }
107
- return existing;
108
36
  }
109
- const cell = createStateCell(initialValue, instance);
110
- stateValues[index] = cell;
111
- return cell;
112
37
  }
113
- function createStateCell(initialValue, instance) {
114
- let value = initialValue;
115
- const readers = /* @__PURE__ */ new Map();
116
- function read() {
117
- read._hasBeenRead = true;
118
- const inst = getCurrentInstance();
119
- if (inst && inst._currentRenderToken !== void 0) {
120
- if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
121
- inst._pendingReadStates.add(read);
122
- }
123
- return value;
38
+ var logger;
39
+ var init_logger = __esm({
40
+ "src/dev/logger.ts"() {
41
+ logger = {
42
+ debug: (...args) => {
43
+ if (process.env.NODE_ENV === "production") return;
44
+ callConsole("debug", args);
45
+ },
46
+ info: (...args) => {
47
+ if (process.env.NODE_ENV === "production") return;
48
+ callConsole("info", args);
49
+ },
50
+ warn: (...args) => {
51
+ if (process.env.NODE_ENV === "production") return;
52
+ callConsole("warn", args);
53
+ },
54
+ error: (...args) => {
55
+ callConsole("error", args);
56
+ }
57
+ };
124
58
  }
125
- read._readers = readers;
126
- read._owner = instance;
127
- read.set = (newValueOrUpdater) => {
128
- const currentInst = getCurrentInstance();
129
- if (currentInst !== null && process.env.NODE_ENV !== "production") {
130
- throw new Error(
131
- `[Askr] state.set() cannot be called during component render. State mutations during render break the actor model and cause infinite loops. Move state updates to event handlers or use conditional rendering instead.`
132
- );
133
- }
134
- if (currentInst !== null && process.env.NODE_ENV === "production") {
135
- if (typeof console !== "undefined" && console.warn) {
136
- console.warn(
137
- "[Askr] state.set() called during render - update skipped. Move state updates to event handlers."
59
+ });
60
+
61
+ // src/runtime/scheduler.ts
62
+ function isBulkCommitActive() {
63
+ try {
64
+ const fb = globalThis.__ASKR_FASTLANE;
65
+ return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
66
+ } catch (e) {
67
+ return false;
68
+ }
69
+ }
70
+ function isSchedulerExecuting() {
71
+ return globalScheduler.isExecuting();
72
+ }
73
+ var MAX_FLUSH_DEPTH, Scheduler, globalScheduler;
74
+ var init_scheduler = __esm({
75
+ "src/runtime/scheduler.ts"() {
76
+ init_invariant();
77
+ MAX_FLUSH_DEPTH = 50;
78
+ Scheduler = class {
79
+ constructor() {
80
+ this.q = [];
81
+ this.head = 0;
82
+ this.running = false;
83
+ this.inHandler = false;
84
+ this.depth = 0;
85
+ this.executionDepth = 0;
86
+ // for compat with existing diagnostics
87
+ // Monotonic flush version increments at end of each flush
88
+ this.flushVersion = 0;
89
+ // Best-effort microtask kick scheduling
90
+ this.kickScheduled = false;
91
+ // Escape hatch flag for runWithSyncProgress
92
+ this.allowSyncProgress = false;
93
+ // Waiters waiting for flushVersion >= target
94
+ this.waiters = [];
95
+ // Keep a lightweight taskCount for compatibility/diagnostics
96
+ this.taskCount = 0;
97
+ }
98
+ enqueue(task) {
99
+ assertSchedulingPrecondition(
100
+ typeof task === "function",
101
+ "enqueue() requires a function"
138
102
  );
103
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
104
+ if (process.env.NODE_ENV !== "production") {
105
+ throw new Error(
106
+ "[Scheduler] enqueue() during bulk commit (not allowed)"
107
+ );
108
+ }
109
+ return;
110
+ }
111
+ this.q.push(task);
112
+ this.taskCount++;
113
+ if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
114
+ this.kickScheduled = true;
115
+ queueMicrotask(() => {
116
+ this.kickScheduled = false;
117
+ if (this.running) return;
118
+ if (isBulkCommitActive()) return;
119
+ try {
120
+ this.flush();
121
+ } catch (err) {
122
+ setTimeout(() => {
123
+ throw err;
124
+ });
125
+ }
126
+ });
127
+ }
139
128
  }
140
- return;
141
- }
142
- let newValue;
143
- if (typeof newValueOrUpdater === "function") {
144
- const updater = newValueOrUpdater;
145
- newValue = updater(value);
146
- } else {
147
- newValue = newValueOrUpdater;
148
- }
149
- if (Object.is(value, newValue)) return;
150
- if (isBulkCommitActive()) {
151
- value = newValue;
152
- return;
153
- }
154
- value = newValue;
155
- const readersMap = read._readers;
156
- if (readersMap) {
157
- for (const [subInst, token] of readersMap) {
158
- if (subInst.lastRenderToken !== token) continue;
159
- if (!subInst.hasPendingUpdate) {
160
- subInst.hasPendingUpdate = true;
161
- const subTask = subInst._pendingFlushTask;
162
- if (subTask) globalScheduler.enqueue(subTask);
163
- else
164
- globalScheduler.enqueue(() => {
165
- subInst.hasPendingUpdate = false;
166
- subInst.notifyUpdate?.();
167
- });
129
+ flush() {
130
+ invariant(
131
+ !this.running,
132
+ "[Scheduler] flush() called while already running"
133
+ );
134
+ if (process.env.NODE_ENV !== "production") {
135
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
136
+ throw new Error(
137
+ "[Scheduler] flush() started during bulk commit (not allowed)"
138
+ );
139
+ }
140
+ }
141
+ this.running = true;
142
+ this.depth = 0;
143
+ let fatal = null;
144
+ try {
145
+ while (this.head < this.q.length) {
146
+ this.depth++;
147
+ if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
148
+ throw new Error(
149
+ `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
150
+ );
151
+ }
152
+ const task = this.q[this.head++];
153
+ try {
154
+ this.executionDepth++;
155
+ task();
156
+ this.executionDepth--;
157
+ } catch (err) {
158
+ if (this.executionDepth > 0) this.executionDepth = 0;
159
+ fatal = err;
160
+ break;
161
+ }
162
+ if (this.taskCount > 0) this.taskCount--;
163
+ }
164
+ } finally {
165
+ this.running = false;
166
+ this.depth = 0;
167
+ this.executionDepth = 0;
168
+ if (this.head >= this.q.length) {
169
+ this.q.length = 0;
170
+ this.head = 0;
171
+ } else if (this.head > 0) {
172
+ const remaining = this.q.length - this.head;
173
+ for (let i = 0; i < remaining; i++) {
174
+ this.q[i] = this.q[this.head + i];
175
+ }
176
+ this.q.length = remaining;
177
+ this.head = 0;
178
+ }
179
+ this.flushVersion++;
180
+ this.resolveWaiters();
168
181
  }
182
+ if (fatal) throw fatal;
169
183
  }
170
- }
171
- const readersMapForOwner = readersMap;
172
- const ownerRecordedToken = readersMapForOwner?.get(instance);
173
- const ownerShouldEnqueue = (
174
- // Normal case: owner read this state in last committed render
175
- ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
176
- );
177
- if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
178
- instance.hasPendingUpdate = true;
179
- const task2 = instance._pendingFlushTask;
180
- if (task2) globalScheduler.enqueue(task2);
181
- else
182
- globalScheduler.enqueue(() => {
183
- instance.hasPendingUpdate = false;
184
- instance.notifyUpdate?.();
184
+ runWithSyncProgress(fn) {
185
+ const prev = this.allowSyncProgress;
186
+ this.allowSyncProgress = true;
187
+ const g = globalThis;
188
+ const origQueueMicrotask = g.queueMicrotask;
189
+ const origSetTimeout = g.setTimeout;
190
+ if (process.env.NODE_ENV !== "production") {
191
+ g.queueMicrotask = () => {
192
+ throw new Error(
193
+ "[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
194
+ );
195
+ };
196
+ g.setTimeout = () => {
197
+ throw new Error(
198
+ "[Scheduler] setTimeout not allowed during runWithSyncProgress"
199
+ );
200
+ };
201
+ }
202
+ const startVersion = this.flushVersion;
203
+ try {
204
+ const res = fn();
205
+ if (!this.running && this.q.length - this.head > 0) {
206
+ this.flush();
207
+ }
208
+ if (process.env.NODE_ENV !== "production") {
209
+ if (this.q.length - this.head > 0) {
210
+ throw new Error(
211
+ "[Scheduler] tasks remain after runWithSyncProgress flush"
212
+ );
213
+ }
214
+ }
215
+ return res;
216
+ } finally {
217
+ if (process.env.NODE_ENV !== "production") {
218
+ g.queueMicrotask = origQueueMicrotask;
219
+ g.setTimeout = origSetTimeout;
220
+ }
221
+ try {
222
+ if (this.flushVersion === startVersion) {
223
+ this.flushVersion++;
224
+ this.resolveWaiters();
225
+ }
226
+ } catch (e) {
227
+ }
228
+ this.allowSyncProgress = prev;
229
+ }
230
+ }
231
+ waitForFlush(targetVersion, timeoutMs = 2e3) {
232
+ const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
233
+ if (this.flushVersion >= target) return Promise.resolve();
234
+ return new Promise((resolve, reject) => {
235
+ const timer = setTimeout(() => {
236
+ const ns = globalThis.__ASKR__ || {};
237
+ const diag = {
238
+ flushVersion: this.flushVersion,
239
+ queueLen: this.q.length - this.head,
240
+ running: this.running,
241
+ inHandler: this.inHandler,
242
+ bulk: isBulkCommitActive(),
243
+ namespace: ns
244
+ };
245
+ reject(
246
+ new Error(
247
+ `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
248
+ )
249
+ );
250
+ }, timeoutMs);
251
+ this.waiters.push({ target, resolve, reject, timer });
185
252
  });
186
- }
187
- };
188
- return read;
253
+ }
254
+ getState() {
255
+ return {
256
+ queueLength: this.q.length - this.head,
257
+ running: this.running,
258
+ depth: this.depth,
259
+ executionDepth: this.executionDepth,
260
+ taskCount: this.taskCount,
261
+ flushVersion: this.flushVersion,
262
+ // New fields for optional inspection
263
+ inHandler: this.inHandler,
264
+ allowSyncProgress: this.allowSyncProgress
265
+ };
266
+ }
267
+ setInHandler(v) {
268
+ this.inHandler = v;
269
+ }
270
+ isInHandler() {
271
+ return this.inHandler;
272
+ }
273
+ isExecuting() {
274
+ return this.running || this.executionDepth > 0;
275
+ }
276
+ // Clear pending synchronous tasks (used by fastlane enter/exit)
277
+ clearPendingSyncTasks() {
278
+ const remaining = this.q.length - this.head;
279
+ if (remaining <= 0) return 0;
280
+ if (this.running) {
281
+ this.q.length = this.head;
282
+ this.taskCount = Math.max(0, this.taskCount - remaining);
283
+ queueMicrotask(() => {
284
+ try {
285
+ this.flushVersion++;
286
+ this.resolveWaiters();
287
+ } catch (e) {
288
+ }
289
+ });
290
+ return remaining;
291
+ }
292
+ this.q.length = 0;
293
+ this.head = 0;
294
+ this.taskCount = Math.max(0, this.taskCount - remaining);
295
+ this.flushVersion++;
296
+ this.resolveWaiters();
297
+ return remaining;
298
+ }
299
+ resolveWaiters() {
300
+ if (this.waiters.length === 0) return;
301
+ const ready = [];
302
+ const remaining = [];
303
+ for (const w of this.waiters) {
304
+ if (this.flushVersion >= w.target) {
305
+ if (w.timer) clearTimeout(w.timer);
306
+ ready.push(w.resolve);
307
+ } else {
308
+ remaining.push(w);
309
+ }
310
+ }
311
+ this.waiters = remaining;
312
+ for (const r of ready) r();
313
+ }
314
+ };
315
+ globalScheduler = new Scheduler();
316
+ }
317
+ });
318
+
319
+ // src/runtime/context.ts
320
+ function withContext(frame, fn) {
321
+ const oldFrame = currentContextFrame;
322
+ currentContextFrame = frame;
323
+ try {
324
+ return fn();
325
+ } finally {
326
+ currentContextFrame = oldFrame;
327
+ }
328
+ }
329
+ function getCurrentContextFrame() {
330
+ return currentContextFrame;
189
331
  }
332
+ var CONTEXT_FRAME_SYMBOL, currentContextFrame;
333
+ var init_context = __esm({
334
+ "src/runtime/context.ts"() {
335
+ CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
336
+ currentContextFrame = null;
337
+ }
338
+ });
190
339
 
191
- // src/runtime/resource-cell.ts
192
- var ResourceCell = class {
193
- constructor(fn, deps, resourceFrame) {
194
- this.value = null;
195
- this.pending = true;
196
- this.error = null;
197
- this.generation = 0;
198
- this.controller = null;
199
- this.deps = null;
200
- this.resourceFrame = null;
201
- this.subscribers = /* @__PURE__ */ new Set();
202
- this.fn = fn;
203
- this.deps = deps ? deps.slice() : null;
204
- this.resourceFrame = resourceFrame;
205
- this.snapshot = {
206
- value: null,
207
- pending: true,
208
- error: null,
209
- refresh: () => this.refresh()
210
- };
340
+ // src/renderer/diag/index.ts
341
+ function getDiagMap() {
342
+ try {
343
+ const root = globalThis;
344
+ if (!root.__ASKR_DIAG) root.__ASKR_DIAG = {};
345
+ return root.__ASKR_DIAG;
346
+ } catch (e) {
347
+ return {};
211
348
  }
212
- subscribe(cb) {
213
- this.subscribers.add(cb);
214
- return () => this.subscribers.delete(cb);
215
- }
216
- notifySubscribers() {
217
- this.snapshot.value = this.value;
218
- this.snapshot.pending = this.pending;
219
- this.snapshot.error = this.error;
220
- for (const cb of this.subscribers) cb();
221
- }
222
- start(ssr = false, notify = true) {
223
- const generation = this.generation;
224
- this.controller?.abort();
225
- const controller = new AbortController();
226
- this.controller = controller;
227
- this.pending = true;
228
- this.error = null;
229
- if (notify) this.notifySubscribers();
230
- let result;
349
+ }
350
+ function __ASKR_set(key, value) {
351
+ try {
352
+ const g = getDiagMap();
353
+ g[key] = value;
231
354
  try {
232
- result = withAsyncResourceContext(
233
- this.resourceFrame,
234
- () => this.fn({ signal: controller.signal })
235
- );
236
- } catch (err) {
237
- this.pending = false;
238
- this.error = err;
239
- if (notify) this.notifySubscribers();
240
- return;
241
- }
242
- if (!(result instanceof Promise)) {
243
- this.value = result;
244
- this.pending = false;
245
- this.error = null;
246
- if (notify) this.notifySubscribers();
247
- return;
248
- }
249
- if (ssr) {
250
- throwSSRDataMissing();
251
- }
252
- result.then((val) => {
253
- if (this.generation !== generation) return;
254
- if (this.controller !== controller) return;
255
- this.value = val;
256
- this.pending = false;
257
- this.error = null;
258
- this.notifySubscribers();
259
- }).catch((err) => {
260
- if (this.generation !== generation) return;
261
- this.pending = false;
262
- this.error = err;
355
+ const root = globalThis;
263
356
  try {
264
- if (this.ownerName) {
265
- logger.error(
266
- `[Askr] Async resource error in ${this.ownerName}:`,
267
- err
268
- );
269
- } else {
270
- logger.error("[Askr] Async resource error:", err);
357
+ const ns = root.__ASKR__ || (root.__ASKR__ = {});
358
+ try {
359
+ ns[key] = value;
360
+ } catch (e) {
361
+ void e;
271
362
  }
272
- } catch {
363
+ } catch (e) {
364
+ void e;
273
365
  }
274
- this.notifySubscribers();
275
- });
366
+ } catch (e) {
367
+ void e;
368
+ }
369
+ } catch (e) {
276
370
  }
277
- refresh() {
278
- this.generation++;
279
- this.controller?.abort();
280
- this.start();
371
+ }
372
+ function __ASKR_incCounter(key) {
373
+ try {
374
+ const g = getDiagMap();
375
+ const prev = typeof g[key] === "number" ? g[key] : 0;
376
+ const next = prev + 1;
377
+ g[key] = next;
378
+ try {
379
+ const root = globalThis;
380
+ const ns = root.__ASKR__ || (root.__ASKR__ = {});
381
+ try {
382
+ const nsPrev = typeof ns[key] === "number" ? ns[key] : 0;
383
+ ns[key] = nsPrev + 1;
384
+ } catch (e) {
385
+ void e;
386
+ }
387
+ } catch (e) {
388
+ void e;
389
+ }
390
+ } catch (e) {
281
391
  }
282
- abort() {
283
- this.controller?.abort();
392
+ }
393
+ var init_diag = __esm({
394
+ "src/renderer/diag/index.ts"() {
284
395
  }
285
- };
396
+ });
286
397
 
287
- // src/shared/derive-cache.ts
288
- var deriveCacheMap = /* @__PURE__ */ new WeakMap();
289
- function getDeriveCache(instance) {
290
- let cache = deriveCacheMap.get(instance);
291
- if (!cache) {
292
- cache = /* @__PURE__ */ new Map();
293
- deriveCacheMap.set(instance, cache);
398
+ // src/renderer/utils.ts
399
+ function parseEventName(propName) {
400
+ if (!propName.startsWith("on") || propName.length <= 2) return null;
401
+ return propName.slice(2).charAt(0).toLowerCase() + propName.slice(3).toLowerCase();
402
+ }
403
+ function getPassiveOptions(eventName) {
404
+ if (eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch")) {
405
+ return { passive: true };
294
406
  }
295
- return cache;
407
+ return void 0;
296
408
  }
297
-
298
- // src/runtime/operations.ts
299
- function resource(fn, deps = []) {
300
- const instance = getCurrentComponentInstance();
301
- const inst = instance;
302
- if (!instance) {
303
- const renderData2 = getCurrentRenderData();
304
- if (renderData2) {
305
- const key = getNextKey();
306
- if (!(key in renderData2)) {
307
- throwSSRDataMissing();
308
- }
309
- const val = renderData2[key];
310
- return {
311
- value: val,
312
- pending: false,
313
- error: null,
314
- refresh: () => {
409
+ function createWrappedHandler(handler, flushAfter = false) {
410
+ return (event) => {
411
+ globalScheduler.setInHandler(true);
412
+ try {
413
+ handler(event);
414
+ } catch (error) {
415
+ logger.error("[Askr] Event handler error:", error);
416
+ } finally {
417
+ globalScheduler.setInHandler(false);
418
+ if (flushAfter) {
419
+ const state2 = globalScheduler.getState();
420
+ if ((state2.queueLength ?? 0) > 0 && !state2.running) {
421
+ queueMicrotask(() => {
422
+ try {
423
+ if (!globalScheduler.isExecuting()) globalScheduler.flush();
424
+ } catch (err) {
425
+ queueMicrotask(() => {
426
+ throw err;
427
+ });
428
+ }
429
+ });
315
430
  }
316
- };
431
+ }
317
432
  }
318
- const ssrCtx = getCurrentSSRContext();
319
- if (ssrCtx) {
320
- throwSSRDataMissing();
433
+ };
434
+ }
435
+ function isSkippedProp(key) {
436
+ return key === "children" || key === "key";
437
+ }
438
+ function isIgnoredForPropChanges(key) {
439
+ if (key === "children" || key === "key") return true;
440
+ if (key.startsWith("on") && key.length > 2) return true;
441
+ if (key.startsWith("data-")) return true;
442
+ return false;
443
+ }
444
+ function hasPropChanged(el, key, value) {
445
+ try {
446
+ if (key === "class" || key === "className") {
447
+ return el.className !== String(value);
321
448
  }
322
- return {
323
- value: null,
324
- pending: true,
325
- error: null,
326
- refresh: () => {
327
- }
328
- };
329
- }
330
- const renderData = getCurrentRenderData();
331
- if (renderData) {
332
- const key = getNextKey();
333
- if (!(key in renderData)) {
334
- throwSSRDataMissing();
335
- }
336
- const val = renderData[key];
337
- const holder2 = state({
338
- cell: void 0,
339
- snapshot: {
340
- value: val,
341
- pending: false,
342
- error: null,
343
- refresh: () => {
344
- }
345
- }
346
- });
347
- const h2 = holder2();
348
- h2.snapshot.value = val;
349
- h2.snapshot.pending = false;
350
- h2.snapshot.error = null;
351
- holder2.set(h2);
352
- return h2.snapshot;
353
- }
354
- const holder = state({
355
- cell: void 0,
356
- snapshot: {
357
- value: null,
358
- pending: true,
359
- error: null,
360
- refresh: () => {
361
- }
449
+ if (key === "value" || key === "checked") {
450
+ return el[key] !== value;
362
451
  }
363
- });
364
- const h = holder();
365
- if (!h.cell) {
366
- const frame = getCurrentContextFrame();
367
- const cell2 = new ResourceCell(fn, deps, frame);
368
- cell2.ownerName = inst.fn?.name || "<anonymous>";
369
- h.cell = cell2;
370
- h.snapshot = cell2.snapshot;
371
- const unsubscribe = cell2.subscribe(() => {
372
- const cur = holder();
373
- cur.snapshot.value = cell2.snapshot.value;
374
- cur.snapshot.pending = cell2.snapshot.pending;
375
- cur.snapshot.error = cell2.snapshot.error;
376
- holder.set(cur);
377
- try {
378
- inst._enqueueRun?.();
379
- } catch {
380
- }
381
- });
382
- inst.cleanupFns.push(() => {
383
- unsubscribe();
384
- cell2.abort();
385
- });
386
- try {
387
- cell2.start(inst.ssr ?? false, false);
388
- if (!cell2.pending) {
389
- const cur = holder();
390
- cur.snapshot.value = cell2.value;
391
- cur.snapshot.pending = cell2.pending;
392
- cur.snapshot.error = cell2.error;
393
- }
394
- } catch (err) {
395
- if (err instanceof SSRDataMissingError) throw err;
396
- cell2.error = err;
397
- cell2.pending = false;
398
- const cur = holder();
399
- cur.snapshot.value = cell2.value;
400
- cur.snapshot.pending = cell2.pending;
401
- cur.snapshot.error = cell2.error;
402
- }
403
- }
404
- const cell = h.cell;
405
- const depsChanged = !cell.deps || cell.deps.length !== deps.length || cell.deps.some((d, i) => d !== deps[i]);
406
- if (depsChanged) {
407
- cell.deps = deps.slice();
408
- cell.generation++;
409
- cell.pending = true;
410
- cell.error = null;
411
- try {
412
- cell.start(inst.ssr ?? false, false);
413
- if (!cell.pending) {
414
- const cur = holder();
415
- cur.snapshot.value = cell.value;
416
- cur.snapshot.pending = cell.pending;
417
- cur.snapshot.error = cell.error;
418
- }
419
- } catch (err) {
420
- if (err instanceof SSRDataMissingError) throw err;
421
- cell.error = err;
422
- cell.pending = false;
423
- const cur = holder();
424
- cur.snapshot.value = cell.value;
425
- cur.snapshot.pending = cell.pending;
426
- cur.snapshot.error = cell.error;
452
+ const attr = el.getAttribute(key);
453
+ if (value === void 0 || value === null || value === false) {
454
+ return attr !== null;
427
455
  }
456
+ return String(value) !== attr;
457
+ } catch {
458
+ return true;
428
459
  }
429
- return h.snapshot;
430
460
  }
431
- function derive(source, map) {
432
- if (map === void 0 && typeof source === "function") {
433
- const value2 = source();
434
- if (value2 == null) return null;
435
- const instance2 = getCurrentComponentInstance();
436
- if (!instance2) {
437
- return value2;
461
+ function hasNonTrivialProps(props) {
462
+ for (const k of Object.keys(props)) {
463
+ if (isIgnoredForPropChanges(k)) continue;
464
+ return true;
465
+ }
466
+ return false;
467
+ }
468
+ function checkPropChanges(el, props) {
469
+ for (const k of Object.keys(props)) {
470
+ if (isIgnoredForPropChanges(k)) continue;
471
+ if (hasPropChanged(el, k, props[k])) {
472
+ return true;
438
473
  }
439
- const cache2 = getDeriveCache(instance2);
440
- if (cache2.has(value2)) return cache2.get(value2);
441
- cache2.set(value2, value2);
442
- return value2;
443
474
  }
444
- let value;
445
- if (typeof source === "function" && !("value" in source)) {
446
- value = source();
447
- } else {
448
- value = source?.value ?? source;
475
+ return false;
476
+ }
477
+ function extractKey(vnode) {
478
+ if (typeof vnode !== "object" || vnode === null) return void 0;
479
+ const obj = vnode;
480
+ const rawKey = obj.key ?? obj.props?.key;
481
+ if (rawKey === void 0) return void 0;
482
+ return typeof rawKey === "symbol" ? String(rawKey) : rawKey;
483
+ }
484
+ function buildKeyMapFromChildren(parent) {
485
+ const map = /* @__PURE__ */ new Map();
486
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
487
+ const k = ch.getAttribute("data-key");
488
+ if (k !== null) {
489
+ map.set(k, ch);
490
+ const n = Number(k);
491
+ if (!Number.isNaN(n)) map.set(n, ch);
492
+ }
449
493
  }
450
- if (value == null) return null;
451
- const instance = getCurrentComponentInstance();
452
- if (!instance) {
453
- return map(value);
494
+ return map;
495
+ }
496
+ function recordDOMReplace(source) {
497
+ try {
498
+ __ASKR_incCounter("__DOM_REPLACE_COUNT");
499
+ __ASKR_set(`__LAST_DOM_REPLACE_STACK_${source}`, new Error().stack);
500
+ } catch {
454
501
  }
455
- const cache = getDeriveCache(instance);
456
- if (cache.has(value)) {
457
- return cache.get(value);
502
+ }
503
+ function recordFastPathStats(stats, counterName) {
504
+ try {
505
+ __ASKR_set("__LAST_FASTPATH_STATS", stats);
506
+ __ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
507
+ if (counterName) {
508
+ __ASKR_incCounter(counterName);
509
+ }
510
+ } catch {
458
511
  }
459
- const result = map(value);
460
- cache.set(value, result);
461
- return result;
462
512
  }
463
- function task(fn) {
464
- const ownerIsRoot = getCurrentComponentInstance()?.isRoot ?? false;
465
- registerMountOperation(async () => {
466
- if (!ownerIsRoot) {
467
- throw new Error("[Askr] task() may only be used in root components");
513
+ function logFastPathDebug(message, indexOrData, data) {
514
+ if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
515
+ if (data !== void 0) {
516
+ logger.warn(`[Askr][FASTPATH] ${message}`, indexOrData, data);
517
+ } else if (indexOrData !== void 0) {
518
+ logger.warn(`[Askr][FASTPATH] ${message}`, indexOrData);
519
+ } else {
520
+ logger.warn(`[Askr][FASTPATH] ${message}`);
468
521
  }
469
- return await fn();
470
- });
522
+ }
523
+ }
524
+ function now() {
525
+ return typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
471
526
  }
527
+ var init_utils = __esm({
528
+ "src/renderer/utils.ts"() {
529
+ init_scheduler();
530
+ init_logger();
531
+ init_diag();
532
+ }
533
+ });
472
534
 
473
- // src/boot/index.ts
474
- var componentIdCounter = 0;
475
- var instancesByRoot = /* @__PURE__ */ new WeakMap();
476
- var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
477
- function attachCleanupForRoot(rootElement, instance) {
478
- rootElement[CLEANUP_SYMBOL] = () => {
479
- const errors = [];
480
- try {
481
- removeAllListeners(rootElement);
482
- } catch (e) {
483
- errors.push(e);
484
- }
485
- try {
486
- const descendants = rootElement.querySelectorAll("*");
487
- for (const d of Array.from(descendants)) {
488
- try {
489
- const inst = d.__ASKR_INSTANCE;
490
- if (inst) {
491
- try {
492
- cleanupComponent(inst);
493
- } catch (err) {
494
- errors.push(err);
495
- }
496
- try {
497
- delete d.__ASKR_INSTANCE;
498
- } catch (err) {
499
- errors.push(err);
500
- }
501
- }
502
- } catch (err) {
503
- errors.push(err);
535
+ // src/renderer/keyed.ts
536
+ function getKeyMapForElement(el) {
537
+ return keyedElements.get(el);
538
+ }
539
+ function populateKeyMapForElement(parent) {
540
+ try {
541
+ if (keyedElements.has(parent)) return;
542
+ let domMap = buildKeyMapFromChildren(parent);
543
+ if (domMap.size === 0) {
544
+ domMap = /* @__PURE__ */ new Map();
545
+ const children = Array.from(parent.children);
546
+ for (const ch of children) {
547
+ const text = (ch.textContent || "").trim();
548
+ if (text) {
549
+ domMap.set(text, ch);
550
+ const n = Number(text);
551
+ if (!Number.isNaN(n)) domMap.set(n, ch);
504
552
  }
505
553
  }
506
- } catch (e) {
507
- errors.push(e);
508
- }
509
- try {
510
- cleanupComponent(instance);
511
- } catch (e) {
512
- errors.push(e);
513
- }
514
- if (errors.length > 0) {
515
- if (instance.cleanupStrict) {
516
- throw new AggregateError(errors, `cleanup failed for app root`);
517
- } else if (process.env.NODE_ENV !== "production") {
518
- for (const err of errors) logger.warn("[Askr] cleanup error:", err);
519
- }
520
- }
521
- };
522
- try {
523
- const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
524
- Object.getPrototypeOf(rootElement),
525
- "innerHTML"
526
- ) || Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
527
- if (descriptor && (descriptor.get || descriptor.set)) {
528
- Object.defineProperty(rootElement, "innerHTML", {
529
- get: descriptor.get ? function() {
530
- return descriptor.get.call(this);
531
- } : void 0,
532
- set: function(value) {
533
- if (value === "" && instancesByRoot.get(this) === instance) {
534
- try {
535
- removeAllListeners(rootElement);
536
- } catch (e) {
537
- if (instance.cleanupStrict) throw e;
538
- if (process.env.NODE_ENV !== "production")
539
- logger.warn("[Askr] cleanup error:", e);
540
- }
541
- try {
542
- cleanupComponent(instance);
543
- } catch (e) {
544
- if (instance.cleanupStrict) throw e;
545
- if (process.env.NODE_ENV !== "production")
546
- logger.warn("[Askr] cleanup error:", e);
547
- }
548
- }
549
- if (descriptor.set) {
550
- return descriptor.set.call(this, value);
551
- }
552
- },
553
- configurable: true
554
- });
555
554
  }
555
+ if (domMap.size > 0) keyedElements.set(parent, domMap);
556
556
  } catch {
557
557
  }
558
558
  }
559
- function mountOrUpdate(rootElement, componentFn, options) {
560
- const wrappedFn = (props, ctx) => {
561
- const out = componentFn(props, ctx);
562
- const portalVNode = {
563
- $$typeof: ELEMENT_TYPE,
564
- type: DefaultPortal,
565
- props: {},
566
- key: "__default_portal"
567
- };
568
- return {
569
- $$typeof: ELEMENT_TYPE,
570
- type: Fragment,
571
- props: {
572
- children: out === void 0 || out === null ? [portalVNode] : [out, portalVNode]
573
- }
574
- };
575
- };
576
- Object.defineProperty(wrappedFn, "name", {
577
- value: componentFn.name || "Component"
578
- });
579
- const existingCleanup = rootElement[CLEANUP_SYMBOL];
580
- if (existingCleanup) existingCleanup();
581
- let instance = instancesByRoot.get(rootElement);
582
- if (instance) {
583
- removeAllListeners(rootElement);
584
- try {
585
- cleanupComponent(instance);
586
- } catch (e) {
587
- if (process.env.NODE_ENV !== "production")
588
- logger.warn("[Askr] prior cleanup threw:", e);
559
+ function extractKeyedVnodes(newChildren) {
560
+ const result = [];
561
+ for (const child of newChildren) {
562
+ const key = extractKey(child);
563
+ if (key !== void 0) {
564
+ result.push({ key, vnode: child });
589
565
  }
590
- instance.fn = wrappedFn;
591
- instance.evaluationGeneration++;
592
- instance.mounted = false;
593
- instance.expectedStateIndices = [];
594
- instance.firstRenderComplete = false;
595
- instance.isRoot = true;
596
- if (options && typeof options.cleanupStrict === "boolean") {
597
- instance.cleanupStrict = options.cleanupStrict;
566
+ }
567
+ return result;
568
+ }
569
+ function computeLISLength(positions) {
570
+ const tails = [];
571
+ for (const pos of positions) {
572
+ if (pos === -1) continue;
573
+ let lo = 0;
574
+ let hi = tails.length;
575
+ while (lo < hi) {
576
+ const mid = lo + hi >> 1;
577
+ if (tails[mid] < pos) lo = mid + 1;
578
+ else hi = mid;
598
579
  }
599
- } else {
600
- const componentId = String(++componentIdCounter);
601
- instance = createComponentInstance(componentId, wrappedFn, {}, rootElement);
602
- instancesByRoot.set(rootElement, instance);
603
- instance.isRoot = true;
604
- if (options && typeof options.cleanupStrict === "boolean") {
605
- instance.cleanupStrict = options.cleanupStrict;
580
+ if (lo === tails.length) tails.push(pos);
581
+ else tails[lo] = pos;
582
+ }
583
+ return tails.length;
584
+ }
585
+ function checkVnodesHaveProps(keyedVnodes) {
586
+ for (const { vnode } of keyedVnodes) {
587
+ if (typeof vnode !== "object" || vnode === null) continue;
588
+ const vnodeObj = vnode;
589
+ if (vnodeObj.props && hasNonTrivialProps(vnodeObj.props)) {
590
+ return true;
606
591
  }
607
592
  }
608
- attachCleanupForRoot(rootElement, instance);
609
- mountComponent(instance);
610
- globalScheduler.flush();
593
+ return false;
611
594
  }
612
- function createIsland(config) {
613
- if (!config || typeof config !== "object") {
614
- throw new Error("createIsland requires a config object");
595
+ function checkVnodePropChanges(keyedVnodes, oldKeyMap) {
596
+ for (const { key, vnode } of keyedVnodes) {
597
+ const el = oldKeyMap?.get(key);
598
+ if (!el || typeof vnode !== "object" || vnode === null) continue;
599
+ const vnodeObj = vnode;
600
+ const props = vnodeObj.props || {};
601
+ for (const k of Object.keys(props)) {
602
+ if (isIgnoredForPropChanges(k)) continue;
603
+ if (hasPropChanged(el, k, props[k])) {
604
+ return true;
605
+ }
606
+ }
615
607
  }
616
- if (typeof config.component !== "function") {
617
- throw new Error("createIsland: component must be a function");
608
+ return false;
609
+ }
610
+ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
611
+ const keyedVnodes = extractKeyedVnodes(newChildren);
612
+ const totalKeyed = keyedVnodes.length;
613
+ const newKeyOrder = keyedVnodes.map((kv) => kv.key);
614
+ const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
615
+ let moveCount = 0;
616
+ for (let i = 0; i < newKeyOrder.length; i++) {
617
+ const k = newKeyOrder[i];
618
+ if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k || !oldKeyMap?.has(k)) {
619
+ moveCount++;
620
+ }
618
621
  }
619
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
620
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
621
- if ("routes" in config) {
622
- throw new Error(
623
- "createIsland does not accept routes; use createSPA for routed apps"
624
- );
622
+ const FAST_MOVE_THRESHOLD_ABS = 64;
623
+ const FAST_MOVE_THRESHOLD_REL = 0.1;
624
+ const cheapMoveTrigger = totalKeyed >= 128 && oldKeyOrder.length > 0 && moveCount > Math.max(
625
+ FAST_MOVE_THRESHOLD_ABS,
626
+ Math.floor(totalKeyed * FAST_MOVE_THRESHOLD_REL)
627
+ );
628
+ let lisTrigger = false;
629
+ let lisLen = 0;
630
+ if (totalKeyed >= 128) {
631
+ const parentChildren = Array.from(parent.children);
632
+ const positions = keyedVnodes.map(({ key }) => {
633
+ const el = oldKeyMap?.get(key);
634
+ return el?.parentElement === parent ? parentChildren.indexOf(el) : -1;
635
+ });
636
+ lisLen = computeLISLength(positions);
637
+ lisTrigger = lisLen < Math.floor(totalKeyed * 0.5);
625
638
  }
626
- mountOrUpdate(rootElement, config.component, {
627
- cleanupStrict: config.cleanupStrict
628
- });
639
+ const hasPropsPresent = checkVnodesHaveProps(keyedVnodes);
640
+ const hasPropChanges = checkVnodePropChanges(keyedVnodes, oldKeyMap);
641
+ const useFastPath = (cheapMoveTrigger || lisTrigger) && !hasPropChanges && !hasPropsPresent;
642
+ return {
643
+ useFastPath,
644
+ totalKeyed,
645
+ moveCount,
646
+ lisLen,
647
+ hasPropChanges
648
+ };
629
649
  }
630
- async function createSPA(config) {
631
- if (!config || typeof config !== "object") {
632
- throw new Error("createSPA requires a config object");
633
- }
634
- if (!Array.isArray(config.routes) || config.routes.length === 0) {
635
- throw new Error(
636
- "createSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
637
- );
650
+ var keyedElements, _reconcilerRecordedParents;
651
+ var init_keyed = __esm({
652
+ "src/renderer/keyed.ts"() {
653
+ init_utils();
654
+ keyedElements = /* @__PURE__ */ new WeakMap();
655
+ _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
638
656
  }
639
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
640
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
641
- const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration, resolveRoute } = await import("./route-USEXGOBT.js");
642
- clearRoutes2();
643
- for (const r of config.routes) {
644
- route2(r.path, r.handler, r.namespace);
657
+ });
658
+
659
+ // src/common/jsx.ts
660
+ var ELEMENT_TYPE, Fragment;
661
+ var init_jsx = __esm({
662
+ "src/common/jsx.ts"() {
663
+ ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
664
+ Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
645
665
  }
646
- if (process.env.NODE_ENV === "production") lockRouteRegistration();
647
- const path = typeof window !== "undefined" ? window.location.pathname : "/";
648
- const resolved = resolveRoute(path);
649
- if (!resolved) {
650
- if (process.env.NODE_ENV !== "production") {
651
- logger.warn(
652
- `createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
653
- );
654
- }
655
- mountOrUpdate(rootElement, () => ({ type: "div", children: [] }), {
656
- cleanupStrict: false
657
- });
658
- const instance2 = instancesByRoot.get(rootElement);
659
- if (!instance2) throw new Error("Internal error: app instance missing");
660
- registerAppInstance(instance2, path);
661
- initializeNavigation();
662
- return;
666
+ });
667
+
668
+ // src/runtime/dev-namespace.ts
669
+ function getDevNamespace() {
670
+ if (process.env.NODE_ENV === "production") return {};
671
+ try {
672
+ const g = globalThis;
673
+ if (!g.__ASKR__) g.__ASKR__ = {};
674
+ return g.__ASKR__;
675
+ } catch {
676
+ return {};
663
677
  }
664
- mountOrUpdate(rootElement, resolved.handler, {
665
- cleanupStrict: false
666
- });
667
- const instance = instancesByRoot.get(rootElement);
668
- if (!instance) throw new Error("Internal error: app instance missing");
669
- registerAppInstance(instance, path);
670
- initializeNavigation();
671
678
  }
672
- async function hydrateSPA(config) {
673
- if (!config || typeof config !== "object") {
674
- throw new Error("hydrateSPA requires a config object");
679
+ function setDevValue(key, value) {
680
+ if (process.env.NODE_ENV === "production") return;
681
+ try {
682
+ getDevNamespace()[key] = value;
683
+ } catch {
675
684
  }
676
- if (!Array.isArray(config.routes) || config.routes.length === 0) {
677
- throw new Error(
678
- "hydrateSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
679
- );
685
+ }
686
+ function getDevValue(key) {
687
+ if (process.env.NODE_ENV === "production") return void 0;
688
+ try {
689
+ return getDevNamespace()[key];
690
+ } catch {
691
+ return void 0;
680
692
  }
681
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
682
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
683
- const serverHTML = rootElement.innerHTML;
684
- const {
685
- clearRoutes: clearRoutes2,
686
- route: route2,
687
- setServerLocation: setServerLocation2,
688
- lockRouteRegistration,
689
- resolveRoute
690
- } = await import("./route-USEXGOBT.js");
691
- clearRoutes2();
692
- for (const r of config.routes) {
693
- route2(r.path, r.handler, r.namespace);
693
+ }
694
+ var init_dev_namespace = __esm({
695
+ "src/runtime/dev-namespace.ts"() {
694
696
  }
695
- const path = typeof window !== "undefined" ? window.location.pathname : "/";
696
- setServerLocation2(path);
697
- if (process.env.NODE_ENV === "production") lockRouteRegistration();
698
- const resolved = resolveRoute(path);
699
- if (!resolved) {
700
- throw new Error(`hydrateSPA: no route found for current path (${path}).`);
701
- }
702
- const { renderToStringSync: renderToStringSync2 } = await import("./ssr-QJ5NTQR6.js");
703
- const expectedHTML = renderToStringSync2(() => {
704
- const out = resolved.handler(resolved.params);
705
- return out ?? {
706
- type: "div",
707
- children: []
708
- };
709
- });
710
- const serverContainer = document.createElement("div");
711
- serverContainer.innerHTML = serverHTML;
712
- const expectedContainer = document.createElement("div");
713
- expectedContainer.innerHTML = expectedHTML;
714
- if (!serverContainer.isEqualNode(expectedContainer)) {
715
- throw new Error(
716
- "[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output."
717
- );
697
+ });
698
+
699
+ // src/runtime/fastlane.ts
700
+ function enterBulkCommit() {
701
+ _bulkCommitActive = true;
702
+ _appliedParents = /* @__PURE__ */ new WeakSet();
703
+ try {
704
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
705
+ setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", cleared);
706
+ } catch (err) {
707
+ if (process.env.NODE_ENV !== "production") throw err;
718
708
  }
719
- mountOrUpdate(rootElement, resolved.handler, {
720
- cleanupStrict: false
721
- });
722
- const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await import("./navigate-CZEUXFPM.js");
723
- const instance = instancesByRoot.get(rootElement);
724
- if (!instance) throw new Error("Internal error: app instance missing");
725
- registerAppInstance2(instance, path);
726
- initializeNavigation2();
727
709
  }
728
- function cleanupApp(root) {
729
- const rootElement = typeof root === "string" ? document.getElementById(root) : root;
730
- if (!rootElement) return;
731
- const cleanupFn = rootElement[CLEANUP_SYMBOL];
732
- if (typeof cleanupFn === "function") {
733
- cleanupFn();
710
+ function exitBulkCommit() {
711
+ _bulkCommitActive = false;
712
+ _appliedParents = null;
713
+ }
714
+ function isBulkCommitActive2() {
715
+ return _bulkCommitActive;
716
+ }
717
+ function markFastPathApplied(parent) {
718
+ if (!_appliedParents) return;
719
+ try {
720
+ _appliedParents.add(parent);
721
+ } catch (e) {
734
722
  }
735
- instancesByRoot.delete(rootElement);
736
723
  }
737
- function hasApp(root) {
738
- const rootElement = typeof root === "string" ? document.getElementById(root) : root;
739
- if (!rootElement) return false;
740
- return instancesByRoot.has(rootElement);
724
+ function isFastPathApplied(parent) {
725
+ return !!(_appliedParents && _appliedParents.has(parent));
741
726
  }
742
-
743
- // src/components/Link.tsx
744
- function Link({ href, children }) {
745
- return {
746
- type: "a",
747
- props: {
748
- href,
749
- children,
750
- onClick: (e) => {
751
- const event = e;
752
- const button = event.button ?? 0;
753
- if (button !== 0 || // not left-click
754
- event.ctrlKey || // Ctrl/Cmd+click
755
- event.metaKey || // Cmd on Mac
756
- event.shiftKey || // Shift+click
757
- event.altKey) {
758
- return;
759
- }
760
- event.preventDefault();
761
- navigate(href);
762
- }
727
+ function finalizeReadSubscriptions(instance) {
728
+ const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
729
+ const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
730
+ const token = instance._currentRenderToken;
731
+ if (token === void 0) return;
732
+ for (const s of oldSet) {
733
+ if (!newSet.has(s)) {
734
+ const readers = s._readers;
735
+ if (readers) readers.delete(instance);
763
736
  }
764
- };
765
- }
766
-
767
- // src/foundations/layout.tsx
768
- function layout(Layout) {
769
- return (children, props) => Layout({ ...props, children });
770
- }
771
-
772
- // src/foundations/slot.tsx
773
- function Slot(props) {
774
- if (props.asChild) {
775
- const { children, ...rest } = props;
776
- if (isElement(children)) {
777
- return cloneElement(children, rest);
778
- }
779
- logger.warn("<Slot asChild> expects a single JSX element child.");
780
- return null;
781
737
  }
782
- return {
783
- $$typeof: ELEMENT_TYPE,
784
- type: Fragment,
785
- props: { children: props.children }
786
- };
738
+ instance.lastRenderToken = token;
739
+ for (const s of newSet) {
740
+ let readers = s._readers;
741
+ if (!readers) {
742
+ readers = /* @__PURE__ */ new Map();
743
+ s._readers = readers;
744
+ }
745
+ readers.set(instance, instance.lastRenderToken ?? 0);
746
+ }
747
+ instance._lastReadStates = newSet;
748
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
749
+ instance._currentRenderToken = void 0;
787
750
  }
788
-
789
- // src/runtime/fastlane.ts
790
751
  function unwrapFragmentForFastPath(vnode) {
791
752
  if (!vnode || typeof vnode !== "object" || !("type" in vnode)) return vnode;
792
753
  const v = vnode;
@@ -843,8 +804,8 @@ function classifyUpdate(instance, result) {
843
804
  return { ...decision, useFastPath: true };
844
805
  }
845
806
  function commitReorderOnly(instance, result) {
846
- const evaluate = globalThis.__ASKR_RENDERER?.evaluate;
847
- if (typeof evaluate !== "function") {
807
+ const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
808
+ if (typeof evaluate2 !== "function") {
848
809
  logger.warn(
849
810
  "[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
850
811
  );
@@ -854,7 +815,7 @@ function commitReorderOnly(instance, result) {
854
815
  enterBulkCommit();
855
816
  try {
856
817
  globalScheduler.runWithSyncProgress(() => {
857
- evaluate(result, instance.target);
818
+ evaluate2(result, instance.target);
858
819
  try {
859
820
  finalizeReadSubscriptions(instance);
860
821
  } catch (e) {
@@ -871,7 +832,7 @@ function commitReorderOnly(instance, result) {
871
832
  exitBulkCommit();
872
833
  }
873
834
  if (process.env.NODE_ENV !== "production") {
874
- if (isBulkCommitActive()) {
835
+ if (isBulkCommitActive2()) {
875
836
  throw new Error(
876
837
  "Fast-lane invariant violated: bulk commit flag still set after commit"
877
838
  );
@@ -967,63 +928,3029 @@ function tryRuntimeFastLaneSync(instance, result) {
967
928
  return false;
968
929
  }
969
930
  }
970
- if (typeof globalThis !== "undefined") {
971
- globalThis.__ASKR_FASTLANE = {
972
- isBulkCommitActive,
973
- enterBulkCommit,
974
- exitBulkCommit,
975
- tryRuntimeFastLaneSync,
976
- markFastPathApplied,
977
- isFastPathApplied
978
- };
931
+ var _bulkCommitActive, _appliedParents;
932
+ var init_fastlane = __esm({
933
+ "src/runtime/fastlane.ts"() {
934
+ init_scheduler();
935
+ init_logger();
936
+ init_keyed();
937
+ init_jsx();
938
+ init_dev_namespace();
939
+ _bulkCommitActive = false;
940
+ _appliedParents = null;
941
+ if (typeof globalThis !== "undefined") {
942
+ globalThis.__ASKR_FASTLANE = {
943
+ isBulkCommitActive: isBulkCommitActive2,
944
+ enterBulkCommit,
945
+ exitBulkCommit,
946
+ tryRuntimeFastLaneSync,
947
+ markFastPathApplied,
948
+ isFastPathApplied
949
+ };
950
+ }
951
+ }
952
+ });
953
+
954
+ // src/common/vnode.ts
955
+ function _isDOMElement(node) {
956
+ return typeof node === "object" && node !== null && "type" in node;
979
957
  }
958
+ var init_vnode = __esm({
959
+ "src/common/vnode.ts"() {
960
+ }
961
+ });
980
962
 
981
- // src/index.ts
982
- if (typeof globalThis !== "undefined") {
983
- const g = globalThis;
984
- if (!g.createIsland) g.createIsland = createIsland;
985
- if (!g.createSPA) g.createSPA = createSPA;
986
- if (!g.hydrateSPA) g.hydrateSPA = hydrateSPA;
987
- if (!g.route) g.route = route;
988
- if (!g.getRoutes) g.getRoutes = getRoutes;
989
- if (!g.navigate) g.navigate = navigate;
990
- }
991
- export {
992
- DefaultPortal,
993
- Fragment2 as Fragment,
994
- Link,
995
- Slot,
996
- _resetDefaultPortal,
997
- cleanupApp,
998
- clearRoutes,
999
- collectResources,
1000
- createIsland,
1001
- createSPA,
1002
- defineContext,
1003
- definePortal,
1004
- derive,
1005
- getLoadedNamespaces,
1006
- getNamespaceRoutes,
1007
- getRoutes,
1008
- getSignal,
1009
- hasApp,
1010
- hydrateSPA,
1011
- jsx,
1012
- jsxs,
1013
- layout,
1014
- navigate,
1015
- readContext,
1016
- renderToStream,
1017
- renderToString,
1018
- renderToStringSync,
1019
- renderToStringSyncForUrl,
1020
- resolveResources,
1021
- resource,
1022
- route,
1023
- scheduleEventHandler,
1024
- setServerLocation,
1025
- state,
1026
- task,
1027
- unloadNamespace
1028
- };
963
+ // src/renderer/types.ts
964
+ var init_types = __esm({
965
+ "src/renderer/types.ts"() {
966
+ init_vnode();
967
+ }
968
+ });
969
+
970
+ // src/renderer/cleanup.ts
971
+ function cleanupSingleInstance(node, errors, strict) {
972
+ const inst = node.__ASKR_INSTANCE;
973
+ if (!inst) return;
974
+ try {
975
+ cleanupComponent(inst);
976
+ } catch (err) {
977
+ logger.warn("[Askr] cleanupComponent failed:", err);
978
+ }
979
+ try {
980
+ delete node.__ASKR_INSTANCE;
981
+ } catch (e) {
982
+ }
983
+ }
984
+ function forEachDescendantElement(root, visit) {
985
+ try {
986
+ const doc = root.ownerDocument;
987
+ const createTreeWalker = doc?.createTreeWalker;
988
+ if (typeof createTreeWalker === "function") {
989
+ const walker = createTreeWalker.call(doc, root, 1);
990
+ let n = walker.firstChild();
991
+ while (n) {
992
+ visit(n);
993
+ n = walker.nextNode();
994
+ }
995
+ return;
996
+ }
997
+ } catch {
998
+ }
999
+ const descendants = root.querySelectorAll("*");
1000
+ for (let i = 0; i < descendants.length; i++) {
1001
+ visit(descendants[i]);
1002
+ }
1003
+ }
1004
+ function cleanupInstanceIfPresent(node, opts) {
1005
+ if (!node || !(node instanceof Element)) return;
1006
+ const strict = false;
1007
+ const errors = null;
1008
+ try {
1009
+ cleanupSingleInstance(node, errors, strict);
1010
+ } catch (err) {
1011
+ logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
1012
+ }
1013
+ try {
1014
+ forEachDescendantElement(node, (d) => {
1015
+ try {
1016
+ cleanupSingleInstance(d, errors, strict);
1017
+ } catch (err) {
1018
+ if (strict) ;
1019
+ else
1020
+ logger.warn(
1021
+ "[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
1022
+ err
1023
+ );
1024
+ }
1025
+ });
1026
+ } catch (err) {
1027
+ logger.warn(
1028
+ "[Askr] cleanupInstanceIfPresent descendant query failed:",
1029
+ err
1030
+ );
1031
+ }
1032
+ }
1033
+ function cleanupInstancesUnder(node, opts) {
1034
+ cleanupInstanceIfPresent(node);
1035
+ }
1036
+ function removeElementListeners(element) {
1037
+ const map = elementListeners.get(element);
1038
+ if (map) {
1039
+ for (const [eventName, entry] of map) {
1040
+ if (entry.options !== void 0)
1041
+ element.removeEventListener(eventName, entry.handler, entry.options);
1042
+ else element.removeEventListener(eventName, entry.handler);
1043
+ }
1044
+ elementListeners.delete(element);
1045
+ }
1046
+ }
1047
+ function removeAllListeners(root) {
1048
+ if (!root) return;
1049
+ removeElementListeners(root);
1050
+ forEachDescendantElement(root, removeElementListeners);
1051
+ }
1052
+ var elementListeners;
1053
+ var init_cleanup = __esm({
1054
+ "src/renderer/cleanup.ts"() {
1055
+ init_component();
1056
+ init_logger();
1057
+ elementListeners = /* @__PURE__ */ new WeakMap();
1058
+ }
1059
+ });
1060
+
1061
+ // src/jsx/types.ts
1062
+ var init_types2 = __esm({
1063
+ "src/jsx/types.ts"() {
1064
+ init_jsx();
1065
+ }
1066
+ });
1067
+
1068
+ // src/jsx/jsx-runtime.ts
1069
+ var init_jsx_runtime = __esm({
1070
+ "src/jsx/jsx-runtime.ts"() {
1071
+ init_types2();
1072
+ }
1073
+ });
1074
+
1075
+ // src/renderer/dom.ts
1076
+ function addTrackedListener(el, eventName, handler) {
1077
+ const wrappedHandler = createWrappedHandler(handler, true);
1078
+ const options = getPassiveOptions(eventName);
1079
+ if (options !== void 0) {
1080
+ el.addEventListener(eventName, wrappedHandler, options);
1081
+ } else {
1082
+ el.addEventListener(eventName, wrappedHandler);
1083
+ }
1084
+ if (!elementListeners.has(el)) {
1085
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1086
+ }
1087
+ elementListeners.get(el).set(eventName, {
1088
+ handler: wrappedHandler,
1089
+ original: handler,
1090
+ options
1091
+ });
1092
+ }
1093
+ function applyPropsToElement(el, props, tagName) {
1094
+ for (const key in props) {
1095
+ const value = props[key];
1096
+ if (isSkippedProp(key)) continue;
1097
+ if (value === void 0 || value === null || value === false) continue;
1098
+ const eventName = parseEventName(key);
1099
+ if (eventName) {
1100
+ addTrackedListener(el, eventName, value);
1101
+ continue;
1102
+ }
1103
+ if (key === "class" || key === "className") {
1104
+ el.className = String(value);
1105
+ } else if (key === "value" || key === "checked") {
1106
+ applyFormControlProp(el, key, value, tagName);
1107
+ } else {
1108
+ el.setAttribute(key, String(value));
1109
+ }
1110
+ }
1111
+ }
1112
+ function applyFormControlProp(el, key, value, tagName) {
1113
+ if (key === "value") {
1114
+ if (tagNamesEqualIgnoreCase(tagName, "input") || tagNamesEqualIgnoreCase(tagName, "textarea") || tagNamesEqualIgnoreCase(tagName, "select")) {
1115
+ el.value = String(value);
1116
+ el.setAttribute("value", String(value));
1117
+ } else {
1118
+ el.setAttribute("value", String(value));
1119
+ }
1120
+ } else if (key === "checked") {
1121
+ if (tagNamesEqualIgnoreCase(tagName, "input")) {
1122
+ el.checked = Boolean(value);
1123
+ el.setAttribute("checked", String(Boolean(value)));
1124
+ } else {
1125
+ el.setAttribute("checked", String(Boolean(value)));
1126
+ }
1127
+ }
1128
+ }
1129
+ function materializeKey(el, vnode, props) {
1130
+ const vnodeKey = vnode.key ?? props?.key;
1131
+ if (vnodeKey !== void 0) {
1132
+ el.setAttribute("data-key", String(vnodeKey));
1133
+ }
1134
+ }
1135
+ function warnMissingKeys(children) {
1136
+ if (process.env.NODE_ENV === "production") return;
1137
+ let hasElements = false;
1138
+ let hasKeys = false;
1139
+ for (const item of children) {
1140
+ if (typeof item === "object" && item !== null && "type" in item) {
1141
+ hasElements = true;
1142
+ const rawKey = item.key ?? item.props?.key;
1143
+ if (rawKey !== void 0) {
1144
+ hasKeys = true;
1145
+ break;
1146
+ }
1147
+ }
1148
+ }
1149
+ if (hasElements && !hasKeys) {
1150
+ try {
1151
+ const inst = getCurrentInstance();
1152
+ const name = inst?.fn?.name || "<anonymous>";
1153
+ logger.warn(
1154
+ `Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`
1155
+ );
1156
+ } catch {
1157
+ logger.warn(
1158
+ 'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
1159
+ );
1160
+ }
1161
+ }
1162
+ }
1163
+ function createDOMNode(node) {
1164
+ if (!IS_DOM_AVAILABLE) {
1165
+ if (process.env.NODE_ENV !== "production") {
1166
+ try {
1167
+ logger.warn("[Askr] createDOMNode called in non-DOM environment");
1168
+ } catch {
1169
+ }
1170
+ }
1171
+ return null;
1172
+ }
1173
+ if (typeof node === "string") {
1174
+ return document.createTextNode(node);
1175
+ }
1176
+ if (typeof node === "number") {
1177
+ return document.createTextNode(String(node));
1178
+ }
1179
+ if (!node) {
1180
+ return null;
1181
+ }
1182
+ if (Array.isArray(node)) {
1183
+ const fragment = document.createDocumentFragment();
1184
+ for (const child of node) {
1185
+ const dom = createDOMNode(child);
1186
+ if (dom) fragment.appendChild(dom);
1187
+ }
1188
+ return fragment;
1189
+ }
1190
+ if (typeof node === "object" && node !== null && "type" in node) {
1191
+ const type = node.type;
1192
+ const props = node.props || {};
1193
+ if (typeof type === "string") {
1194
+ return createIntrinsicElement(node, type, props);
1195
+ }
1196
+ if (typeof type === "function") {
1197
+ return createComponentElement(node, type, props);
1198
+ }
1199
+ if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
1200
+ return createFragmentElement(node, props);
1201
+ }
1202
+ }
1203
+ return null;
1204
+ }
1205
+ function createIntrinsicElement(node, type, props) {
1206
+ const el = document.createElement(type);
1207
+ materializeKey(el, node, props);
1208
+ applyPropsToElement(el, props, type);
1209
+ const children = props.children || node.children;
1210
+ if (children) {
1211
+ if (Array.isArray(children)) {
1212
+ warnMissingKeys(children);
1213
+ for (const child of children) {
1214
+ const dom = createDOMNode(child);
1215
+ if (dom) el.appendChild(dom);
1216
+ }
1217
+ } else {
1218
+ const dom = createDOMNode(children);
1219
+ if (dom) el.appendChild(dom);
1220
+ }
1221
+ }
1222
+ return el;
1223
+ }
1224
+ function createComponentElement(node, type, props) {
1225
+ const frame = node[CONTEXT_FRAME_SYMBOL];
1226
+ const snapshot = frame || getCurrentContextFrame();
1227
+ const componentFn = type;
1228
+ const isAsync = componentFn.constructor.name === "AsyncFunction";
1229
+ if (isAsync) {
1230
+ throw new Error(
1231
+ "Async components are not supported. Use resource() for async work."
1232
+ );
1233
+ }
1234
+ let childInstance = node.__instance;
1235
+ if (!childInstance) {
1236
+ childInstance = createComponentInstance(
1237
+ `comp-${Math.random().toString(36).slice(2, 7)}`,
1238
+ componentFn,
1239
+ props || {},
1240
+ null
1241
+ );
1242
+ node.__instance = childInstance;
1243
+ }
1244
+ if (snapshot) {
1245
+ childInstance.ownerFrame = snapshot;
1246
+ }
1247
+ const result = withContext(
1248
+ snapshot,
1249
+ () => renderComponentInline(childInstance)
1250
+ );
1251
+ if (result instanceof Promise) {
1252
+ throw new Error(
1253
+ "Async components are not supported. Components must return synchronously."
1254
+ );
1255
+ }
1256
+ const dom = withContext(snapshot, () => createDOMNode(result));
1257
+ if (dom instanceof Element) {
1258
+ mountInstanceInline(childInstance, dom);
1259
+ return dom;
1260
+ }
1261
+ if (!dom) {
1262
+ const placeholder = document.createComment("");
1263
+ childInstance._placeholder = placeholder;
1264
+ childInstance.mounted = true;
1265
+ childInstance.notifyUpdate = childInstance._enqueueRun;
1266
+ return placeholder;
1267
+ }
1268
+ const host = document.createElement("div");
1269
+ host.appendChild(dom);
1270
+ mountInstanceInline(childInstance, host);
1271
+ return host;
1272
+ }
1273
+ function createFragmentElement(node, props) {
1274
+ const fragment = document.createDocumentFragment();
1275
+ const children = props.children || node.children;
1276
+ if (children) {
1277
+ if (Array.isArray(children)) {
1278
+ for (const child of children) {
1279
+ const dom = createDOMNode(child);
1280
+ if (dom) fragment.appendChild(dom);
1281
+ }
1282
+ } else {
1283
+ const dom = createDOMNode(children);
1284
+ if (dom) fragment.appendChild(dom);
1285
+ }
1286
+ }
1287
+ return fragment;
1288
+ }
1289
+ function updateElementFromVnode(el, vnode, updateChildren = true) {
1290
+ if (!_isDOMElement(vnode)) {
1291
+ return;
1292
+ }
1293
+ const props = vnode.props || {};
1294
+ materializeKey(el, vnode, props);
1295
+ const existingListeners = elementListeners.get(el);
1296
+ let desiredEventNames = null;
1297
+ for (const key in props) {
1298
+ const value = props[key];
1299
+ if (isSkippedProp(key)) continue;
1300
+ const eventName = parseEventName(key);
1301
+ if (value === void 0 || value === null || value === false) {
1302
+ if (key === "class" || key === "className") {
1303
+ el.className = "";
1304
+ } else if (eventName && existingListeners?.has(eventName)) {
1305
+ const entry = existingListeners.get(eventName);
1306
+ if (entry.options !== void 0) {
1307
+ el.removeEventListener(eventName, entry.handler, entry.options);
1308
+ } else {
1309
+ el.removeEventListener(eventName, entry.handler);
1310
+ }
1311
+ existingListeners.delete(eventName);
1312
+ } else {
1313
+ el.removeAttribute(key);
1314
+ }
1315
+ continue;
1316
+ }
1317
+ if (key === "class" || key === "className") {
1318
+ el.className = String(value);
1319
+ } else if (key === "value" || key === "checked") {
1320
+ el[key] = value;
1321
+ } else if (eventName) {
1322
+ if (existingListeners && existingListeners.size > 0) {
1323
+ (desiredEventNames ??= /* @__PURE__ */ new Set()).add(eventName);
1324
+ }
1325
+ const existing = existingListeners?.get(eventName);
1326
+ if (existing && existing.original === value) {
1327
+ continue;
1328
+ }
1329
+ if (existing) {
1330
+ if (existing.options !== void 0) {
1331
+ el.removeEventListener(eventName, existing.handler, existing.options);
1332
+ } else {
1333
+ el.removeEventListener(eventName, existing.handler);
1334
+ }
1335
+ }
1336
+ const wrappedHandler = createWrappedHandler(
1337
+ value,
1338
+ false
1339
+ );
1340
+ const options = getPassiveOptions(eventName);
1341
+ if (options !== void 0) {
1342
+ el.addEventListener(eventName, wrappedHandler, options);
1343
+ } else {
1344
+ el.addEventListener(eventName, wrappedHandler);
1345
+ }
1346
+ if (!elementListeners.has(el)) {
1347
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1348
+ }
1349
+ elementListeners.get(el).set(eventName, {
1350
+ handler: wrappedHandler,
1351
+ original: value,
1352
+ options
1353
+ });
1354
+ } else {
1355
+ el.setAttribute(key, String(value));
1356
+ }
1357
+ }
1358
+ if (existingListeners && existingListeners.size > 0) {
1359
+ if (desiredEventNames === null) {
1360
+ for (const [eventName, entry] of existingListeners) {
1361
+ if (entry.options !== void 0) {
1362
+ el.removeEventListener(eventName, entry.handler, entry.options);
1363
+ } else {
1364
+ el.removeEventListener(eventName, entry.handler);
1365
+ }
1366
+ }
1367
+ elementListeners.delete(el);
1368
+ } else {
1369
+ for (const [eventName, entry] of existingListeners) {
1370
+ if (!desiredEventNames.has(eventName)) {
1371
+ if (entry.options !== void 0) {
1372
+ el.removeEventListener(eventName, entry.handler, entry.options);
1373
+ } else {
1374
+ el.removeEventListener(eventName, entry.handler);
1375
+ }
1376
+ existingListeners.delete(eventName);
1377
+ }
1378
+ }
1379
+ if (existingListeners.size === 0) elementListeners.delete(el);
1380
+ }
1381
+ }
1382
+ if (updateChildren) {
1383
+ const children = vnode.children || props.children;
1384
+ updateElementChildren(el, children);
1385
+ }
1386
+ }
1387
+ function updateElementChildren(el, children) {
1388
+ if (!children) {
1389
+ el.textContent = "";
1390
+ return;
1391
+ }
1392
+ if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
1393
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1394
+ el.firstChild.data = String(children);
1395
+ } else {
1396
+ el.textContent = String(children);
1397
+ }
1398
+ return;
1399
+ }
1400
+ if (Array.isArray(children)) {
1401
+ updateUnkeyedChildren(el, children);
1402
+ return;
1403
+ }
1404
+ el.textContent = "";
1405
+ const dom = createDOMNode(children);
1406
+ if (dom) el.appendChild(dom);
1407
+ }
1408
+ function updateUnkeyedChildren(parent, newChildren) {
1409
+ const existing = Array.from(parent.children);
1410
+ if (newChildren.length === 1 && existing.length === 0 && parent.childNodes.length === 1) {
1411
+ const firstNewChild = newChildren[0];
1412
+ const firstExisting = parent.firstChild;
1413
+ if ((typeof firstNewChild === "string" || typeof firstNewChild === "number") && firstExisting?.nodeType === 3) {
1414
+ firstExisting.data = String(firstNewChild);
1415
+ return;
1416
+ }
1417
+ }
1418
+ if (existing.length === 0 && parent.childNodes.length > 0) {
1419
+ parent.textContent = "";
1420
+ }
1421
+ const max = Math.max(existing.length, newChildren.length);
1422
+ for (let i = 0; i < max; i++) {
1423
+ const current = existing[i];
1424
+ const next = newChildren[i];
1425
+ if (next === void 0 && current) {
1426
+ cleanupInstanceIfPresent(current);
1427
+ current.remove();
1428
+ continue;
1429
+ }
1430
+ if (!current && next !== void 0) {
1431
+ const dom = createDOMNode(next);
1432
+ if (dom) parent.appendChild(dom);
1433
+ continue;
1434
+ }
1435
+ if (!current || next === void 0) continue;
1436
+ if (typeof next === "string" || typeof next === "number") {
1437
+ current.textContent = String(next);
1438
+ } else if (_isDOMElement(next)) {
1439
+ if (typeof next.type === "string") {
1440
+ if (tagsEqualIgnoreCase(current.tagName, next.type)) {
1441
+ updateElementFromVnode(current, next);
1442
+ } else {
1443
+ const dom = createDOMNode(next);
1444
+ if (dom) {
1445
+ if (current instanceof Element) removeAllListeners(current);
1446
+ cleanupInstanceIfPresent(current);
1447
+ parent.replaceChild(dom, current);
1448
+ }
1449
+ }
1450
+ } else {
1451
+ const dom = createDOMNode(next);
1452
+ if (dom) {
1453
+ if (current instanceof Element) removeAllListeners(current);
1454
+ cleanupInstanceIfPresent(current);
1455
+ parent.replaceChild(dom, current);
1456
+ }
1457
+ }
1458
+ } else {
1459
+ const dom = createDOMNode(next);
1460
+ if (dom) {
1461
+ if (current instanceof Element) removeAllListeners(current);
1462
+ cleanupInstanceIfPresent(current);
1463
+ parent.replaceChild(dom, current);
1464
+ }
1465
+ }
1466
+ }
1467
+ }
1468
+ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
1469
+ const total = keyedVnodes.length;
1470
+ let reused = 0;
1471
+ let updatedKeys = 0;
1472
+ const t0 = now();
1473
+ const debugFastPath = process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true";
1474
+ for (let i = 0; i < total; i++) {
1475
+ const { key, vnode } = keyedVnodes[i];
1476
+ const ch = parent.children[i];
1477
+ if (ch && _isDOMElement(vnode) && typeof vnode.type === "string") {
1478
+ const vnodeType = vnode.type;
1479
+ if (tagsEqualIgnoreCase(ch.tagName, vnodeType)) {
1480
+ const children = vnode.children || vnode.props?.children;
1481
+ if (debugFastPath) {
1482
+ logFastPathDebug("positional idx", i, {
1483
+ chTag: ch.tagName,
1484
+ vnodeType,
1485
+ chChildNodes: ch.childNodes.length,
1486
+ childrenType: Array.isArray(children) ? "array" : typeof children
1487
+ });
1488
+ }
1489
+ updateTextContent(ch, children, vnode);
1490
+ setDataKey(ch, key, () => updatedKeys++);
1491
+ reused++;
1492
+ continue;
1493
+ } else {
1494
+ if (debugFastPath) {
1495
+ logFastPathDebug("positional tag mismatch", i, {
1496
+ chTag: ch.tagName,
1497
+ vnodeType
1498
+ });
1499
+ }
1500
+ }
1501
+ } else {
1502
+ if (debugFastPath) {
1503
+ logFastPathDebug("positional missing or invalid", i, { ch: !!ch });
1504
+ }
1505
+ }
1506
+ replaceNodeAtPosition(parent, i, vnode);
1507
+ }
1508
+ const t = now() - t0;
1509
+ updateKeyedElementsMap(parent, keyedVnodes);
1510
+ const stats = { n: total, reused, updatedKeys, t };
1511
+ recordFastPathStats(stats, "bulkKeyedPositionalHits");
1512
+ return stats;
1513
+ }
1514
+ function updateTextContent(el, children, vnode) {
1515
+ if (typeof children === "string" || typeof children === "number") {
1516
+ setTextNodeData(el, String(children));
1517
+ } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
1518
+ setTextNodeData(el, String(children[0]));
1519
+ } else {
1520
+ if (!tryUpdateTwoChildTextPattern(el, vnode)) {
1521
+ updateElementFromVnode(el, vnode);
1522
+ }
1523
+ }
1524
+ }
1525
+ function tryUpdateTwoChildTextPattern(parentEl, vnode) {
1526
+ const vnodeChildren = vnode.children || vnode.props?.children;
1527
+ if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;
1528
+ const c0 = vnodeChildren[0];
1529
+ const c1 = vnodeChildren[1];
1530
+ if (!_isDOMElement(c0) || !_isDOMElement(c1)) return false;
1531
+ if (typeof c0.type !== "string" || typeof c1.type !== "string") return false;
1532
+ const el0 = parentEl.children[0];
1533
+ const el1 = parentEl.children[1];
1534
+ if (!el0 || !el1) return false;
1535
+ if (!tagsEqualIgnoreCase(el0.tagName, c0.type)) return false;
1536
+ if (!tagsEqualIgnoreCase(el1.tagName, c1.type)) return false;
1537
+ const t0 = c0.children || c0.props?.children;
1538
+ const t1 = c1.children || c1.props?.children;
1539
+ if (typeof t0 === "string" || typeof t0 === "number") {
1540
+ setTextNodeData(el0, String(t0));
1541
+ } else if (Array.isArray(t0) && t0.length === 1 && (typeof t0[0] === "string" || typeof t0[0] === "number")) {
1542
+ setTextNodeData(el0, String(t0[0]));
1543
+ } else {
1544
+ return false;
1545
+ }
1546
+ if (typeof t1 === "string" || typeof t1 === "number") {
1547
+ setTextNodeData(el1, String(t1));
1548
+ } else if (Array.isArray(t1) && t1.length === 1 && (typeof t1[0] === "string" || typeof t1[0] === "number")) {
1549
+ setTextNodeData(el1, String(t1[0]));
1550
+ } else {
1551
+ return false;
1552
+ }
1553
+ return true;
1554
+ }
1555
+ function setTextNodeData(el, text) {
1556
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1557
+ el.firstChild.data = text;
1558
+ } else {
1559
+ el.textContent = text;
1560
+ }
1561
+ }
1562
+ function setDataKey(el, key, onSet) {
1563
+ try {
1564
+ const next = String(key);
1565
+ if (el.getAttribute("data-key") === next) return;
1566
+ el.setAttribute("data-key", next);
1567
+ onSet();
1568
+ } catch {
1569
+ }
1570
+ }
1571
+ function upperCommonTagName(tag) {
1572
+ switch (tag) {
1573
+ case "div":
1574
+ return "DIV";
1575
+ case "span":
1576
+ return "SPAN";
1577
+ case "p":
1578
+ return "P";
1579
+ case "a":
1580
+ return "A";
1581
+ case "button":
1582
+ return "BUTTON";
1583
+ case "input":
1584
+ return "INPUT";
1585
+ case "ul":
1586
+ return "UL";
1587
+ case "ol":
1588
+ return "OL";
1589
+ case "li":
1590
+ return "LI";
1591
+ default:
1592
+ return null;
1593
+ }
1594
+ }
1595
+ function tagNamesEqualIgnoreCase(a, b) {
1596
+ if (a === b) return true;
1597
+ const len = a.length;
1598
+ if (len !== b.length) return false;
1599
+ for (let i = 0; i < len; i++) {
1600
+ const ac = a.charCodeAt(i);
1601
+ const bc = b.charCodeAt(i);
1602
+ if (ac === bc) continue;
1603
+ const an = ac >= 65 && ac <= 90 ? ac + 32 : ac;
1604
+ const bn = bc >= 65 && bc <= 90 ? bc + 32 : bc;
1605
+ if (an !== bn) return false;
1606
+ }
1607
+ return true;
1608
+ }
1609
+ function tagsEqualIgnoreCase(elementTagName, vnodeType) {
1610
+ const upperCommon = upperCommonTagName(vnodeType);
1611
+ if (upperCommon !== null && elementTagName === upperCommon) return true;
1612
+ return tagNamesEqualIgnoreCase(elementTagName, vnodeType);
1613
+ }
1614
+ function replaceNodeAtPosition(parent, index, vnode) {
1615
+ const dom = createDOMNode(vnode);
1616
+ if (dom) {
1617
+ const existing = parent.children[index];
1618
+ if (existing) {
1619
+ cleanupInstanceIfPresent(existing);
1620
+ parent.replaceChild(dom, existing);
1621
+ } else {
1622
+ parent.appendChild(dom);
1623
+ }
1624
+ }
1625
+ }
1626
+ function updateKeyedElementsMap(parent, keyedVnodes) {
1627
+ try {
1628
+ const existing = keyedElements.get(parent);
1629
+ const newKeyMap = existing ? (existing.clear(), existing) : /* @__PURE__ */ new Map();
1630
+ for (let i = 0; i < keyedVnodes.length; i++) {
1631
+ const k = keyedVnodes[i].key;
1632
+ const ch = parent.children[i];
1633
+ if (ch) newKeyMap.set(k, ch);
1634
+ }
1635
+ keyedElements.set(parent, newKeyMap);
1636
+ } catch {
1637
+ }
1638
+ }
1639
+ function performBulkTextReplace(parent, newChildren) {
1640
+ const t0 = now();
1641
+ const existing = Array.from(parent.childNodes);
1642
+ const finalNodes = [];
1643
+ let reused = 0;
1644
+ let created = 0;
1645
+ for (let i = 0; i < newChildren.length; i++) {
1646
+ const result = processChildNode(newChildren[i], existing[i], finalNodes);
1647
+ if (result === "reused") reused++;
1648
+ else if (result === "created") created++;
1649
+ }
1650
+ const tBuild = now() - t0;
1651
+ const tCommit = commitBulkReplace(parent, finalNodes);
1652
+ keyedElements.delete(parent);
1653
+ const stats = {
1654
+ n: newChildren.length,
1655
+ reused,
1656
+ created,
1657
+ tBuild,
1658
+ tCommit
1659
+ };
1660
+ recordBulkTextStats(stats);
1661
+ return stats;
1662
+ }
1663
+ function processChildNode(vnode, existingNode, finalNodes) {
1664
+ if (typeof vnode === "string" || typeof vnode === "number") {
1665
+ return processTextVnode(String(vnode), existingNode, finalNodes);
1666
+ }
1667
+ if (typeof vnode === "object" && vnode !== null && "type" in vnode) {
1668
+ return processElementVnode(vnode, existingNode, finalNodes);
1669
+ }
1670
+ return "skipped";
1671
+ }
1672
+ function processTextVnode(text, existingNode, finalNodes) {
1673
+ if (existingNode && existingNode.nodeType === 3) {
1674
+ existingNode.data = text;
1675
+ finalNodes.push(existingNode);
1676
+ return "reused";
1677
+ }
1678
+ finalNodes.push(document.createTextNode(text));
1679
+ return "created";
1680
+ }
1681
+ function processElementVnode(vnode, existingNode, finalNodes) {
1682
+ const vnodeObj = vnode;
1683
+ if (typeof vnodeObj.type === "string") {
1684
+ const tag = vnodeObj.type;
1685
+ if (existingNode && existingNode.nodeType === 1 && tagsEqualIgnoreCase(existingNode.tagName, tag)) {
1686
+ updateElementFromVnode(existingNode, vnode);
1687
+ finalNodes.push(existingNode);
1688
+ return "reused";
1689
+ }
1690
+ }
1691
+ const dom = createDOMNode(vnode);
1692
+ if (dom) {
1693
+ finalNodes.push(dom);
1694
+ return "created";
1695
+ }
1696
+ return "skipped";
1697
+ }
1698
+ function commitBulkReplace(parent, nodes) {
1699
+ const fragStart = Date.now();
1700
+ const fragment = document.createDocumentFragment();
1701
+ for (let i = 0; i < nodes.length; i++) {
1702
+ fragment.appendChild(nodes[i]);
1703
+ }
1704
+ try {
1705
+ for (let n = parent.firstChild; n; ) {
1706
+ const next = n.nextSibling;
1707
+ if (n instanceof Element) removeAllListeners(n);
1708
+ cleanupInstanceIfPresent(n);
1709
+ n = next;
1710
+ }
1711
+ } catch {
1712
+ }
1713
+ recordDOMReplace("bulk-text-replace");
1714
+ parent.replaceChildren(fragment);
1715
+ return Date.now() - fragStart;
1716
+ }
1717
+ function recordBulkTextStats(stats) {
1718
+ try {
1719
+ __ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
1720
+ __ASKR_set("__LAST_FASTPATH_STATS", stats);
1721
+ __ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
1722
+ __ASKR_incCounter("bulkTextFastpathHits");
1723
+ } catch {
1724
+ }
1725
+ }
1726
+ function isBulkTextFastPathEligible(parent, newChildren) {
1727
+ const threshold = Number(process.env.ASKR_BULK_TEXT_THRESHOLD) || 1024;
1728
+ const requiredFraction = 0.8;
1729
+ const total = Array.isArray(newChildren) ? newChildren.length : 0;
1730
+ if (total < threshold) {
1731
+ recordBulkDiag({
1732
+ phase: "bulk-unkeyed-eligible",
1733
+ reason: "too-small",
1734
+ total,
1735
+ threshold
1736
+ });
1737
+ return false;
1738
+ }
1739
+ const result = countSimpleChildren(newChildren);
1740
+ if (result.componentFound !== void 0) {
1741
+ recordBulkDiag({
1742
+ phase: "bulk-unkeyed-eligible",
1743
+ reason: "component-child",
1744
+ index: result.componentFound
1745
+ });
1746
+ return false;
1747
+ }
1748
+ const fraction = result.simple / total;
1749
+ const eligible = fraction >= requiredFraction && parent.childNodes.length >= total;
1750
+ recordBulkDiag({
1751
+ phase: "bulk-unkeyed-eligible",
1752
+ total,
1753
+ simple: result.simple,
1754
+ fraction,
1755
+ requiredFraction,
1756
+ eligible
1757
+ });
1758
+ return eligible;
1759
+ }
1760
+ function countSimpleChildren(children) {
1761
+ let simple = 0;
1762
+ for (let i = 0; i < children.length; i++) {
1763
+ const c = children[i];
1764
+ if (typeof c === "string" || typeof c === "number") {
1765
+ simple++;
1766
+ continue;
1767
+ }
1768
+ if (typeof c === "object" && c !== null && "type" in c) {
1769
+ const dv = c;
1770
+ if (typeof dv.type === "function") {
1771
+ return { simple, componentFound: i };
1772
+ }
1773
+ if (typeof dv.type === "string" && isSimpleElement(dv)) {
1774
+ simple++;
1775
+ }
1776
+ }
1777
+ }
1778
+ return { simple };
1779
+ }
1780
+ function isSimpleElement(dv) {
1781
+ const children = dv.children || dv.props?.children;
1782
+ if (!children) return true;
1783
+ if (typeof children === "string" || typeof children === "number") {
1784
+ return true;
1785
+ }
1786
+ if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
1787
+ return true;
1788
+ }
1789
+ return false;
1790
+ }
1791
+ function recordBulkDiag(data) {
1792
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
1793
+ try {
1794
+ __ASKR_set("__BULK_DIAG", data);
1795
+ } catch {
1796
+ }
1797
+ }
1798
+ }
1799
+ var IS_DOM_AVAILABLE;
1800
+ var init_dom = __esm({
1801
+ "src/renderer/dom.ts"() {
1802
+ init_logger();
1803
+ init_jsx_runtime();
1804
+ init_context();
1805
+ init_component();
1806
+ init_cleanup();
1807
+ init_diag();
1808
+ init_types();
1809
+ init_keyed();
1810
+ init_utils();
1811
+ IS_DOM_AVAILABLE = typeof document !== "undefined";
1812
+ }
1813
+ });
1814
+
1815
+ // src/renderer/fastpath.ts
1816
+ function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
1817
+ if (typeof document === "undefined") return null;
1818
+ const totalKeyed = keyedVnodes.length;
1819
+ if (totalKeyed === 0 && (!unkeyedVnodes || unkeyedVnodes.length === 0))
1820
+ return null;
1821
+ if (!isSchedulerExecuting()) {
1822
+ logger.warn(
1823
+ "[Askr][FASTPATH][DEV] Fast-path reconciliation invoked outside scheduler execution"
1824
+ );
1825
+ }
1826
+ let parentChildrenArr;
1827
+ let localOldKeyMap;
1828
+ if (totalKeyed <= 20) {
1829
+ try {
1830
+ const pc = parent.children;
1831
+ parentChildrenArr = new Array(pc.length);
1832
+ for (let i = 0; i < pc.length; i++)
1833
+ parentChildrenArr[i] = pc[i];
1834
+ } catch (e) {
1835
+ parentChildrenArr = void 0;
1836
+ }
1837
+ } else {
1838
+ localOldKeyMap = /* @__PURE__ */ new Map();
1839
+ try {
1840
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
1841
+ const k = ch.getAttribute("data-key");
1842
+ if (k !== null) {
1843
+ localOldKeyMap.set(k, ch);
1844
+ const n = Number(k);
1845
+ if (!Number.isNaN(n)) localOldKeyMap.set(n, ch);
1846
+ }
1847
+ }
1848
+ } catch (e) {
1849
+ localOldKeyMap = void 0;
1850
+ }
1851
+ }
1852
+ const finalNodes = [];
1853
+ let mapLookups = 0;
1854
+ let createdNodes = 0;
1855
+ let reusedCount = 0;
1856
+ for (let i = 0; i < keyedVnodes.length; i++) {
1857
+ const { key, vnode } = keyedVnodes[i];
1858
+ mapLookups++;
1859
+ let el;
1860
+ if (totalKeyed <= 20 && parentChildrenArr) {
1861
+ const ks = String(key);
1862
+ for (let j = 0; j < parentChildrenArr.length; j++) {
1863
+ const ch = parentChildrenArr[j];
1864
+ const k = ch.getAttribute("data-key");
1865
+ if (k !== null && (k === ks || Number(k) === key)) {
1866
+ el = ch;
1867
+ break;
1868
+ }
1869
+ }
1870
+ if (!el) el = oldKeyMap?.get(key);
1871
+ } else {
1872
+ el = localOldKeyMap?.get(key) ?? oldKeyMap?.get(key);
1873
+ }
1874
+ if (el) {
1875
+ finalNodes.push(el);
1876
+ reusedCount++;
1877
+ } else {
1878
+ const newEl = createDOMNode(vnode);
1879
+ if (newEl) {
1880
+ finalNodes.push(newEl);
1881
+ createdNodes++;
1882
+ }
1883
+ }
1884
+ }
1885
+ if (unkeyedVnodes && unkeyedVnodes.length) {
1886
+ for (const vnode of unkeyedVnodes) {
1887
+ const newEl = createDOMNode(vnode);
1888
+ if (newEl) {
1889
+ finalNodes.push(newEl);
1890
+ createdNodes++;
1891
+ }
1892
+ }
1893
+ }
1894
+ try {
1895
+ const tFragmentStart = Date.now();
1896
+ const fragment = document.createDocumentFragment();
1897
+ let fragmentAppendCount = 0;
1898
+ for (let i = 0; i < finalNodes.length; i++) {
1899
+ fragment.appendChild(finalNodes[i]);
1900
+ fragmentAppendCount++;
1901
+ }
1902
+ try {
1903
+ for (let n = parent.firstChild; n; ) {
1904
+ const next = n.nextSibling;
1905
+ if (n instanceof Element) removeAllListeners(n);
1906
+ cleanupInstanceIfPresent(n);
1907
+ n = next;
1908
+ }
1909
+ } catch (e) {
1910
+ void e;
1911
+ }
1912
+ try {
1913
+ __ASKR_incCounter("__DOM_REPLACE_COUNT");
1914
+ __ASKR_set("__LAST_DOM_REPLACE_STACK_FASTPATH", new Error().stack);
1915
+ } catch (e) {
1916
+ void e;
1917
+ }
1918
+ parent.replaceChildren(fragment);
1919
+ try {
1920
+ __ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
1921
+ } catch (e) {
1922
+ void e;
1923
+ }
1924
+ try {
1925
+ if (isBulkCommitActive2()) markFastPathApplied(parent);
1926
+ } catch (e) {
1927
+ void e;
1928
+ }
1929
+ const newKeyMap = /* @__PURE__ */ new Map();
1930
+ for (let i = 0; i < keyedVnodes.length; i++) {
1931
+ const key = keyedVnodes[i].key;
1932
+ const node = finalNodes[i];
1933
+ if (node instanceof Element) newKeyMap.set(key, node);
1934
+ }
1935
+ try {
1936
+ const stats = {
1937
+ n: totalKeyed,
1938
+ moves: 0,
1939
+ lisLen: 0,
1940
+ t_lookup: 0,
1941
+ t_fragment: Date.now() - tFragmentStart,
1942
+ t_commit: 0,
1943
+ t_bookkeeping: 0,
1944
+ fragmentAppendCount,
1945
+ mapLookups,
1946
+ createdNodes,
1947
+ reusedCount
1948
+ };
1949
+ if (typeof globalThis !== "undefined") {
1950
+ __ASKR_set("__LAST_FASTPATH_STATS", stats);
1951
+ __ASKR_set("__LAST_FASTPATH_REUSED", reusedCount > 0);
1952
+ __ASKR_incCounter("fastpathHistoryPush");
1953
+ }
1954
+ if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
1955
+ logger.warn(
1956
+ "[Askr][FASTPATH]",
1957
+ JSON.stringify({ n: totalKeyed, createdNodes, reusedCount })
1958
+ );
1959
+ }
1960
+ } catch (e) {
1961
+ void e;
1962
+ }
1963
+ try {
1964
+ _reconcilerRecordedParents.add(parent);
1965
+ } catch (e) {
1966
+ void e;
1967
+ }
1968
+ return newKeyMap;
1969
+ } catch (e) {
1970
+ return null;
1971
+ }
1972
+ }
1973
+ var init_fastpath = __esm({
1974
+ "src/renderer/fastpath.ts"() {
1975
+ init_dom();
1976
+ init_keyed();
1977
+ init_logger();
1978
+ init_cleanup();
1979
+ init_diag();
1980
+ init_scheduler();
1981
+ init_fastlane();
1982
+ }
1983
+ });
1984
+
1985
+ // src/renderer/reconcile.ts
1986
+ function tagNamesEqualIgnoreCase2(a, b) {
1987
+ if (a === b) return true;
1988
+ if (a.length !== b.length) return false;
1989
+ for (let i = 0; i < a.length; i++) {
1990
+ const ca = a.charCodeAt(i);
1991
+ const cb = b.charCodeAt(i);
1992
+ if (ca === cb) continue;
1993
+ const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
1994
+ const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
1995
+ if (fa !== fb) return false;
1996
+ }
1997
+ return true;
1998
+ }
1999
+ function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
2000
+ const { keyedVnodes, unkeyedVnodes } = partitionChildren(newChildren);
2001
+ const fastPathResult = tryFastPaths(
2002
+ parent,
2003
+ newChildren,
2004
+ keyedVnodes,
2005
+ unkeyedVnodes,
2006
+ oldKeyMap
2007
+ );
2008
+ if (fastPathResult) return fastPathResult;
2009
+ return performFullReconciliation(parent, newChildren, keyedVnodes, oldKeyMap);
2010
+ }
2011
+ function partitionChildren(newChildren) {
2012
+ const keyedVnodes = [];
2013
+ const unkeyedVnodes = [];
2014
+ for (let i = 0; i < newChildren.length; i++) {
2015
+ const child = newChildren[i];
2016
+ const key = extractKey(child);
2017
+ if (key !== void 0) {
2018
+ keyedVnodes.push({ key, vnode: child });
2019
+ } else {
2020
+ unkeyedVnodes.push(child);
2021
+ }
2022
+ }
2023
+ return { keyedVnodes, unkeyedVnodes };
2024
+ }
2025
+ function tryFastPaths(parent, newChildren, keyedVnodes, unkeyedVnodes, oldKeyMap) {
2026
+ try {
2027
+ const rendererResult = tryRendererFastPath(
2028
+ parent,
2029
+ newChildren,
2030
+ keyedVnodes,
2031
+ unkeyedVnodes,
2032
+ oldKeyMap
2033
+ );
2034
+ if (rendererResult) return rendererResult;
2035
+ const positionalResult = tryPositionalBulkUpdate(parent, keyedVnodes);
2036
+ if (positionalResult) return positionalResult;
2037
+ } catch {
2038
+ }
2039
+ return null;
2040
+ }
2041
+ function tryRendererFastPath(parent, newChildren, keyedVnodes, unkeyedVnodes, oldKeyMap) {
2042
+ const decision = isKeyedReorderFastPathEligible(
2043
+ parent,
2044
+ newChildren,
2045
+ oldKeyMap
2046
+ );
2047
+ if (decision.useFastPath && keyedVnodes.length >= 128 || isBulkCommitActive2()) {
2048
+ try {
2049
+ const map = applyRendererFastPath(
2050
+ parent,
2051
+ keyedVnodes,
2052
+ oldKeyMap,
2053
+ unkeyedVnodes
2054
+ );
2055
+ if (map) {
2056
+ keyedElements.set(parent, map);
2057
+ return map;
2058
+ }
2059
+ } catch {
2060
+ }
2061
+ }
2062
+ return null;
2063
+ }
2064
+ function tryPositionalBulkUpdate(parent, keyedVnodes) {
2065
+ const total = keyedVnodes.length;
2066
+ if (total < 10) return null;
2067
+ const matchCount = countPositionalMatches(parent, keyedVnodes);
2068
+ if (matchCount / total < 0.9) return null;
2069
+ if (hasPositionalPropChanges(parent, keyedVnodes)) return null;
2070
+ try {
2071
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
2072
+ recordFastPathStats(stats, "bulkKeyedPositionalHits");
2073
+ rebuildKeyedMap(parent);
2074
+ return keyedElements.get(parent);
2075
+ } catch {
2076
+ return null;
2077
+ }
2078
+ }
2079
+ function countPositionalMatches(parent, keyedVnodes) {
2080
+ let matchCount = 0;
2081
+ try {
2082
+ for (let i = 0; i < keyedVnodes.length; i++) {
2083
+ const vnode = keyedVnodes[i].vnode;
2084
+ if (!vnode || typeof vnode !== "object" || typeof vnode.type !== "string")
2085
+ continue;
2086
+ const el = parent.children[i];
2087
+ if (!el) continue;
2088
+ if (tagNamesEqualIgnoreCase2(el.tagName, vnode.type)) {
2089
+ matchCount++;
2090
+ }
2091
+ }
2092
+ } catch {
2093
+ }
2094
+ return matchCount;
2095
+ }
2096
+ function hasPositionalPropChanges(parent, keyedVnodes) {
2097
+ try {
2098
+ for (let i = 0; i < keyedVnodes.length; i++) {
2099
+ const vnode = keyedVnodes[i].vnode;
2100
+ const el = parent.children[i];
2101
+ if (!el || !vnode || typeof vnode !== "object") continue;
2102
+ if (checkPropChanges(el, vnode.props || {})) {
2103
+ return true;
2104
+ }
2105
+ }
2106
+ } catch {
2107
+ return true;
2108
+ }
2109
+ return false;
2110
+ }
2111
+ function rebuildKeyedMap(parent) {
2112
+ try {
2113
+ const map = /* @__PURE__ */ new Map();
2114
+ for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {
2115
+ const k = el.getAttribute("data-key");
2116
+ if (k !== null) {
2117
+ map.set(k, el);
2118
+ const n = Number(k);
2119
+ if (!Number.isNaN(n)) map.set(n, el);
2120
+ }
2121
+ }
2122
+ keyedElements.set(parent, map);
2123
+ } catch {
2124
+ }
2125
+ }
2126
+ function performFullReconciliation(parent, newChildren, keyedVnodes, oldKeyMap) {
2127
+ const newKeyMap = /* @__PURE__ */ new Map();
2128
+ const finalNodes = [];
2129
+ const usedOldEls = /* @__PURE__ */ new WeakSet();
2130
+ const resolveOldElOnce = createOldElResolver(parent, oldKeyMap, usedOldEls);
2131
+ for (let i = 0; i < newChildren.length; i++) {
2132
+ const child = newChildren[i];
2133
+ const node = reconcileSingleChild(
2134
+ child,
2135
+ i,
2136
+ parent,
2137
+ resolveOldElOnce,
2138
+ usedOldEls,
2139
+ newKeyMap
2140
+ );
2141
+ if (node) finalNodes.push(node);
2142
+ }
2143
+ if (typeof document === "undefined") return newKeyMap;
2144
+ commitReconciliation(parent, finalNodes);
2145
+ keyedElements.delete(parent);
2146
+ return newKeyMap;
2147
+ }
2148
+ function createOldElResolver(parent, oldKeyMap, usedOldEls) {
2149
+ return (k) => {
2150
+ if (!oldKeyMap) return void 0;
2151
+ const direct = oldKeyMap.get(k);
2152
+ if (direct && !usedOldEls.has(direct)) {
2153
+ usedOldEls.add(direct);
2154
+ return direct;
2155
+ }
2156
+ const s = String(k);
2157
+ const byString = oldKeyMap.get(s);
2158
+ if (byString && !usedOldEls.has(byString)) {
2159
+ usedOldEls.add(byString);
2160
+ return byString;
2161
+ }
2162
+ const n = Number(s);
2163
+ if (!Number.isNaN(n)) {
2164
+ const byNum = oldKeyMap.get(n);
2165
+ if (byNum && !usedOldEls.has(byNum)) {
2166
+ usedOldEls.add(byNum);
2167
+ return byNum;
2168
+ }
2169
+ }
2170
+ return scanForElementByKey(parent, k, s, usedOldEls);
2171
+ };
2172
+ }
2173
+ function scanForElementByKey(parent, k, keyStr, usedOldEls) {
2174
+ try {
2175
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
2176
+ if (usedOldEls.has(ch)) continue;
2177
+ const attr = ch.getAttribute("data-key");
2178
+ if (attr === keyStr) {
2179
+ usedOldEls.add(ch);
2180
+ return ch;
2181
+ }
2182
+ if (attr !== null) {
2183
+ const numAttr = Number(attr);
2184
+ if (!Number.isNaN(numAttr) && numAttr === k) {
2185
+ usedOldEls.add(ch);
2186
+ return ch;
2187
+ }
2188
+ }
2189
+ }
2190
+ } catch {
2191
+ }
2192
+ return void 0;
2193
+ }
2194
+ function reconcileSingleChild(child, index, parent, resolveOldElOnce, usedOldEls, newKeyMap) {
2195
+ const key = extractKey(child);
2196
+ if (key !== void 0) {
2197
+ return reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap);
2198
+ }
2199
+ return reconcileUnkeyedChild(child, index, parent, usedOldEls);
2200
+ }
2201
+ function reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap) {
2202
+ const el = resolveOldElOnce(key);
2203
+ if (el && el.parentElement === parent) {
2204
+ try {
2205
+ const childObj = child;
2206
+ if (childObj && typeof childObj === "object" && typeof childObj.type === "string") {
2207
+ if (tagNamesEqualIgnoreCase2(el.tagName, childObj.type)) {
2208
+ updateElementFromVnode(el, child);
2209
+ newKeyMap.set(key, el);
2210
+ return el;
2211
+ }
2212
+ }
2213
+ } catch {
2214
+ }
2215
+ }
2216
+ const dom = createDOMNode(child);
2217
+ if (dom) {
2218
+ if (dom instanceof Element) newKeyMap.set(key, dom);
2219
+ return dom;
2220
+ }
2221
+ return null;
2222
+ }
2223
+ function reconcileUnkeyedChild(child, index, parent, usedOldEls) {
2224
+ try {
2225
+ const existing = parent.children[index];
2226
+ if (existing && (typeof child === "string" || typeof child === "number") && existing.nodeType === 1) {
2227
+ existing.textContent = String(child);
2228
+ usedOldEls.add(existing);
2229
+ return existing;
2230
+ }
2231
+ if (canReuseElement(existing, child)) {
2232
+ updateElementFromVnode(existing, child);
2233
+ usedOldEls.add(existing);
2234
+ return existing;
2235
+ }
2236
+ const avail = findAvailableUnkeyedElement(parent, usedOldEls);
2237
+ if (avail) {
2238
+ const reuseResult = tryReuseElement(avail, child, usedOldEls);
2239
+ if (reuseResult) return reuseResult;
2240
+ }
2241
+ } catch {
2242
+ }
2243
+ const dom = createDOMNode(child);
2244
+ return dom;
2245
+ }
2246
+ function canReuseElement(existing, child) {
2247
+ if (!existing) return false;
2248
+ if (typeof child !== "object" || child === null || !("type" in child))
2249
+ return false;
2250
+ const childObj = child;
2251
+ const existingKey = existing.getAttribute("data-key");
2252
+ const hasNoKey = existingKey === null || existingKey === void 0;
2253
+ return hasNoKey && typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(existing.tagName, childObj.type);
2254
+ }
2255
+ function findAvailableUnkeyedElement(parent, usedOldEls) {
2256
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
2257
+ if (usedOldEls.has(ch)) continue;
2258
+ if (ch.getAttribute("data-key") === null) return ch;
2259
+ }
2260
+ return void 0;
2261
+ }
2262
+ function tryReuseElement(avail, child, usedOldEls) {
2263
+ if (typeof child === "string" || typeof child === "number") {
2264
+ avail.textContent = String(child);
2265
+ usedOldEls.add(avail);
2266
+ return avail;
2267
+ }
2268
+ if (typeof child === "object" && child !== null && "type" in child) {
2269
+ const childObj = child;
2270
+ if (typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(avail.tagName, childObj.type)) {
2271
+ updateElementFromVnode(avail, child);
2272
+ usedOldEls.add(avail);
2273
+ return avail;
2274
+ }
2275
+ }
2276
+ return null;
2277
+ }
2278
+ function commitReconciliation(parent, finalNodes) {
2279
+ const fragment = document.createDocumentFragment();
2280
+ for (let i = 0; i < finalNodes.length; i++) {
2281
+ fragment.appendChild(finalNodes[i]);
2282
+ }
2283
+ try {
2284
+ for (let n = parent.firstChild; n; ) {
2285
+ const next = n.nextSibling;
2286
+ if (n instanceof Element) removeAllListeners(n);
2287
+ cleanupInstanceIfPresent(n);
2288
+ n = next;
2289
+ }
2290
+ } catch {
2291
+ }
2292
+ recordDOMReplace("reconcile");
2293
+ parent.replaceChildren(fragment);
2294
+ }
2295
+ var init_reconcile = __esm({
2296
+ "src/renderer/reconcile.ts"() {
2297
+ init_dom();
2298
+ init_keyed();
2299
+ init_cleanup();
2300
+ init_fastlane();
2301
+ init_fastpath();
2302
+ init_utils();
2303
+ }
2304
+ });
2305
+
2306
+ // src/renderer/evaluate.ts
2307
+ function tagNamesEqualIgnoreCase3(a, b) {
2308
+ if (a === b) return true;
2309
+ if (a.length !== b.length) return false;
2310
+ for (let i = 0; i < a.length; i++) {
2311
+ const ca = a.charCodeAt(i);
2312
+ const cb = b.charCodeAt(i);
2313
+ if (ca === cb) continue;
2314
+ const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
2315
+ const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
2316
+ if (fa !== fb) return false;
2317
+ }
2318
+ return true;
2319
+ }
2320
+ function checkSimpleText(vnodeChildren) {
2321
+ if (!Array.isArray(vnodeChildren)) {
2322
+ if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
2323
+ return { isSimple: true, text: String(vnodeChildren) };
2324
+ }
2325
+ } else if (vnodeChildren.length === 1) {
2326
+ const child = vnodeChildren[0];
2327
+ if (typeof child === "string" || typeof child === "number") {
2328
+ return { isSimple: true, text: String(child) };
2329
+ }
2330
+ }
2331
+ return { isSimple: false };
2332
+ }
2333
+ function tryUpdateTextInPlace(element, text) {
2334
+ if (element.childNodes.length === 1 && element.firstChild?.nodeType === 3) {
2335
+ element.firstChild.data = text;
2336
+ return true;
2337
+ }
2338
+ return false;
2339
+ }
2340
+ function buildKeyMapFromDOM(parent) {
2341
+ const keyMap = /* @__PURE__ */ new Map();
2342
+ for (let child = parent.firstElementChild; child; child = child.nextElementSibling) {
2343
+ const k = child.getAttribute("data-key");
2344
+ if (k !== null) {
2345
+ keyMap.set(k, child);
2346
+ const n = Number(k);
2347
+ if (!Number.isNaN(n)) keyMap.set(n, child);
2348
+ }
2349
+ }
2350
+ return keyMap;
2351
+ }
2352
+ function getOrBuildKeyMap(parent) {
2353
+ let keyMap = keyedElements.get(parent);
2354
+ if (!keyMap) {
2355
+ keyMap = buildKeyMapFromDOM(parent);
2356
+ if (keyMap.size > 0) {
2357
+ keyedElements.set(parent, keyMap);
2358
+ }
2359
+ }
2360
+ return keyMap.size > 0 ? keyMap : void 0;
2361
+ }
2362
+ function hasKeyedChildren(children) {
2363
+ for (let i = 0; i < children.length; i++) {
2364
+ if (extractKey(children[i]) !== void 0) return true;
2365
+ }
2366
+ return false;
2367
+ }
2368
+ function trackBulkTextStats(stats) {
2369
+ if (process.env.NODE_ENV !== "production") {
2370
+ try {
2371
+ __ASKR_set("__LAST_BULK_TEXT_FASTPATH_STATS", stats);
2372
+ __ASKR_incCounter("bulkTextHits");
2373
+ } catch {
2374
+ }
2375
+ }
2376
+ }
2377
+ function trackBulkTextMiss() {
2378
+ if (process.env.NODE_ENV !== "production") {
2379
+ try {
2380
+ __ASKR_incCounter("bulkTextMisses");
2381
+ } catch {
2382
+ }
2383
+ }
2384
+ }
2385
+ function reconcileKeyed(parent, children, oldKeyMap) {
2386
+ if (process.env.ASKR_FORCE_BULK_POSREUSE === "1") {
2387
+ const result = tryForcedBulkKeyedPath(parent, children);
2388
+ if (result) return;
2389
+ }
2390
+ const newKeyMap = reconcileKeyedChildren(parent, children, oldKeyMap);
2391
+ keyedElements.set(parent, newKeyMap);
2392
+ }
2393
+ function tryForcedBulkKeyedPath(parent, children) {
2394
+ try {
2395
+ const keyedVnodes = [];
2396
+ for (const child of children) {
2397
+ if (_isDOMElement(child) && child.key !== void 0) {
2398
+ keyedVnodes.push({
2399
+ key: child.key,
2400
+ vnode: child
2401
+ });
2402
+ }
2403
+ }
2404
+ if (keyedVnodes.length === 0 || keyedVnodes.length !== children.length) {
2405
+ return false;
2406
+ }
2407
+ if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
2408
+ logger.warn(
2409
+ "[Askr][FASTPATH] forced positional bulk keyed reuse (evaluate-level)"
2410
+ );
2411
+ }
2412
+ const stats = performBulkPositionalKeyedTextUpdate(parent, keyedVnodes);
2413
+ if (process.env.NODE_ENV !== "production" || process.env.ASKR_FASTPATH_DEBUG === "1") {
2414
+ try {
2415
+ __ASKR_set("__LAST_FASTPATH_STATS", stats);
2416
+ __ASKR_set("__LAST_FASTPATH_COMMIT_COUNT", 1);
2417
+ __ASKR_incCounter("bulkKeyedPositionalForced");
2418
+ } catch {
2419
+ }
2420
+ }
2421
+ const newMap = buildKeyMapFromDOM(parent);
2422
+ keyedElements.set(parent, newMap);
2423
+ return true;
2424
+ } catch (err) {
2425
+ if (process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true") {
2426
+ logger.warn(
2427
+ "[Askr][FASTPATH] forced bulk path failed, falling back",
2428
+ err
2429
+ );
2430
+ }
2431
+ return false;
2432
+ }
2433
+ }
2434
+ function reconcileUnkeyed(parent, children) {
2435
+ if (isBulkTextFastPathEligible(parent, children)) {
2436
+ const stats = performBulkTextReplace(parent, children);
2437
+ trackBulkTextStats(stats);
2438
+ } else {
2439
+ trackBulkTextMiss();
2440
+ updateUnkeyedChildren(parent, children);
2441
+ }
2442
+ keyedElements.delete(parent);
2443
+ }
2444
+ function updateElementChildren2(element, vnodeChildren) {
2445
+ if (!vnodeChildren) {
2446
+ element.textContent = "";
2447
+ keyedElements.delete(element);
2448
+ return;
2449
+ }
2450
+ if (!Array.isArray(vnodeChildren)) {
2451
+ element.textContent = "";
2452
+ const dom = createDOMNode(vnodeChildren);
2453
+ if (dom) element.appendChild(dom);
2454
+ keyedElements.delete(element);
2455
+ return;
2456
+ }
2457
+ if (hasKeyedChildren(vnodeChildren)) {
2458
+ const oldKeyMap = getOrBuildKeyMap(element);
2459
+ try {
2460
+ reconcileKeyed(element, vnodeChildren, oldKeyMap);
2461
+ } catch {
2462
+ const newKeyMap = reconcileKeyedChildren(
2463
+ element,
2464
+ vnodeChildren,
2465
+ oldKeyMap
2466
+ );
2467
+ keyedElements.set(element, newKeyMap);
2468
+ }
2469
+ } else {
2470
+ reconcileUnkeyed(element, vnodeChildren);
2471
+ }
2472
+ }
2473
+ function smartUpdateElement(element, vnode) {
2474
+ const vnodeChildren = vnode.children || vnode.props?.children;
2475
+ const textCheck = checkSimpleText(vnodeChildren);
2476
+ if (textCheck.isSimple && tryUpdateTextInPlace(element, textCheck.text)) ; else {
2477
+ updateElementChildren2(element, vnodeChildren);
2478
+ }
2479
+ updateElementFromVnode(element, vnode, false);
2480
+ }
2481
+ function processFragmentChildren(target, childArray) {
2482
+ let existingNode = target.firstElementChild;
2483
+ for (let i = 0; i < childArray.length; i++) {
2484
+ const childVnode = childArray[i];
2485
+ const nextExisting = existingNode ? existingNode.nextElementSibling : null;
2486
+ if (existingNode && _isDOMElement(childVnode) && typeof childVnode.type === "string" && tagNamesEqualIgnoreCase3(
2487
+ existingNode.tagName,
2488
+ childVnode.type
2489
+ )) {
2490
+ smartUpdateElement(existingNode, childVnode);
2491
+ existingNode = nextExisting;
2492
+ continue;
2493
+ }
2494
+ const newDom = createDOMNode(childVnode);
2495
+ if (newDom) {
2496
+ if (existingNode) {
2497
+ target.replaceChild(newDom, existingNode);
2498
+ } else {
2499
+ target.appendChild(newDom);
2500
+ }
2501
+ }
2502
+ existingNode = nextExisting;
2503
+ }
2504
+ while (existingNode) {
2505
+ const next = existingNode.nextElementSibling;
2506
+ target.removeChild(existingNode);
2507
+ existingNode = next;
2508
+ }
2509
+ }
2510
+ function applyPropsToElement2(el, props) {
2511
+ for (const [key, value] of Object.entries(props)) {
2512
+ if (key === "children" || key === "key") continue;
2513
+ if (value === void 0 || value === null || value === false) continue;
2514
+ const eventName = parseEventName(key);
2515
+ if (eventName) {
2516
+ const wrappedHandler = createWrappedHandler(
2517
+ value,
2518
+ false
2519
+ );
2520
+ const options = getPassiveOptions(eventName);
2521
+ if (options !== void 0)
2522
+ el.addEventListener(eventName, wrappedHandler, options);
2523
+ else el.addEventListener(eventName, wrappedHandler);
2524
+ if (!elementListeners.has(el)) elementListeners.set(el, /* @__PURE__ */ new Map());
2525
+ elementListeners.get(el).set(eventName, {
2526
+ handler: wrappedHandler,
2527
+ original: value,
2528
+ options
2529
+ });
2530
+ continue;
2531
+ }
2532
+ if (key === "class" || key === "className") {
2533
+ el.className = String(value);
2534
+ } else if (key === "value" || key === "checked") {
2535
+ el[key] = value;
2536
+ } else {
2537
+ el.setAttribute(key, String(value));
2538
+ }
2539
+ }
2540
+ }
2541
+ function tryFirstRenderKeyedChildren(target, vnode) {
2542
+ const children = vnode.children;
2543
+ if (!Array.isArray(children) || !hasKeyedChildren(children)) {
2544
+ return false;
2545
+ }
2546
+ const el = document.createElement(vnode.type);
2547
+ target.appendChild(el);
2548
+ applyPropsToElement2(el, vnode.props || {});
2549
+ const newKeyMap = reconcileKeyedChildren(el, children, void 0);
2550
+ keyedElements.set(el, newKeyMap);
2551
+ return true;
2552
+ }
2553
+ function isFragment(vnode) {
2554
+ return _isDOMElement(vnode) && typeof vnode.type === "symbol" && (vnode.type === Fragment || String(vnode.type) === "Symbol(askr.fragment)");
2555
+ }
2556
+ function getFragmentChildren(vnode) {
2557
+ const fragmentChildren = vnode.props?.children || vnode.children || [];
2558
+ return Array.isArray(fragmentChildren) ? fragmentChildren : [fragmentChildren];
2559
+ }
2560
+ function evaluate(node, target, context) {
2561
+ if (!target) return;
2562
+ if (typeof document === "undefined") {
2563
+ if (process.env.NODE_ENV !== "production") {
2564
+ try {
2565
+ console.warn("[Askr] evaluate() called in non-DOM environment; no-op.");
2566
+ } catch (e) {
2567
+ }
2568
+ }
2569
+ return;
2570
+ }
2571
+ if (context && domRanges.has(context)) {
2572
+ const range = domRanges.get(context);
2573
+ let current = range.start.nextSibling;
2574
+ while (current && current !== range.end) {
2575
+ const next = current.nextSibling;
2576
+ current.remove();
2577
+ current = next;
2578
+ }
2579
+ const dom = createDOMNode(node);
2580
+ if (dom) {
2581
+ target.insertBefore(dom, range.end);
2582
+ }
2583
+ } else if (context) {
2584
+ const start = document.createComment("component-start");
2585
+ const end = document.createComment("component-end");
2586
+ target.appendChild(start);
2587
+ target.appendChild(end);
2588
+ domRanges.set(context, { start, end });
2589
+ const dom = createDOMNode(node);
2590
+ if (dom) {
2591
+ target.insertBefore(dom, end);
2592
+ }
2593
+ } else {
2594
+ let vnode = node;
2595
+ if (isFragment(vnode)) {
2596
+ const childArray = getFragmentChildren(vnode);
2597
+ if (childArray.length === 1 && _isDOMElement(childArray[0]) && typeof childArray[0].type === "string") {
2598
+ vnode = childArray[0];
2599
+ } else {
2600
+ processFragmentChildren(target, childArray);
2601
+ return;
2602
+ }
2603
+ }
2604
+ const firstChild = target.children[0];
2605
+ if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && tagNamesEqualIgnoreCase3(firstChild.tagName, vnode.type)) {
2606
+ smartUpdateElement(firstChild, vnode);
2607
+ } else {
2608
+ target.textContent = "";
2609
+ if (_isDOMElement(vnode) && typeof vnode.type === "string" && tryFirstRenderKeyedChildren(target, vnode)) {
2610
+ return;
2611
+ }
2612
+ const dom = createDOMNode(vnode);
2613
+ if (dom) {
2614
+ target.appendChild(dom);
2615
+ }
2616
+ }
2617
+ }
2618
+ }
2619
+ var domRanges;
2620
+ var init_evaluate = __esm({
2621
+ "src/renderer/evaluate.ts"() {
2622
+ init_logger();
2623
+ init_cleanup();
2624
+ init_keyed();
2625
+ init_reconcile();
2626
+ init_types();
2627
+ init_dom();
2628
+ init_diag();
2629
+ init_jsx();
2630
+ init_utils();
2631
+ domRanges = /* @__PURE__ */ new WeakMap();
2632
+ }
2633
+ });
2634
+
2635
+ // src/renderer/index.ts
2636
+ var init_renderer = __esm({
2637
+ "src/renderer/index.ts"() {
2638
+ init_types();
2639
+ init_cleanup();
2640
+ init_keyed();
2641
+ init_dom();
2642
+ init_evaluate();
2643
+ init_evaluate();
2644
+ init_keyed();
2645
+ if (typeof globalThis !== "undefined") {
2646
+ const _g = globalThis;
2647
+ _g.__ASKR_RENDERER = {
2648
+ evaluate,
2649
+ isKeyedReorderFastPathEligible,
2650
+ getKeyMapForElement
2651
+ };
2652
+ }
2653
+ }
2654
+ });
2655
+
2656
+ // src/runtime/component.ts
2657
+ function createComponentInstance(id, fn, props, target) {
2658
+ const instance = {
2659
+ id,
2660
+ fn,
2661
+ props,
2662
+ target,
2663
+ mounted: false,
2664
+ abortController: new AbortController(),
2665
+ // Create per-component
2666
+ stateValues: [],
2667
+ evaluationGeneration: 0,
2668
+ notifyUpdate: null,
2669
+ // Prebound helpers (initialized below) to avoid per-update allocations
2670
+ _pendingFlushTask: void 0,
2671
+ _pendingRunTask: void 0,
2672
+ _enqueueRun: void 0,
2673
+ stateIndexCheck: -1,
2674
+ expectedStateIndices: [],
2675
+ firstRenderComplete: false,
2676
+ mountOperations: [],
2677
+ cleanupFns: [],
2678
+ hasPendingUpdate: false,
2679
+ ownerFrame: null,
2680
+ // Will be set by renderer when vnode is marked
2681
+ ssr: false,
2682
+ cleanupStrict: false,
2683
+ isRoot: false,
2684
+ // Render-tracking (for precise state subscriptions)
2685
+ _currentRenderToken: void 0,
2686
+ lastRenderToken: 0,
2687
+ _pendingReadStates: /* @__PURE__ */ new Set(),
2688
+ _lastReadStates: /* @__PURE__ */ new Set()
2689
+ };
2690
+ instance._pendingRunTask = () => {
2691
+ instance.hasPendingUpdate = false;
2692
+ runComponent(instance);
2693
+ };
2694
+ instance._enqueueRun = () => {
2695
+ if (!instance.hasPendingUpdate) {
2696
+ instance.hasPendingUpdate = true;
2697
+ globalScheduler.enqueue(instance._pendingRunTask);
2698
+ }
2699
+ };
2700
+ instance._pendingFlushTask = () => {
2701
+ instance.hasPendingUpdate = false;
2702
+ instance._enqueueRun?.();
2703
+ };
2704
+ return instance;
2705
+ }
2706
+ function getCurrentComponentInstance() {
2707
+ return currentInstance;
2708
+ }
2709
+ function executeMountOperations(instance) {
2710
+ if (!instance.isRoot) return;
2711
+ for (const operation of instance.mountOperations) {
2712
+ const result = operation();
2713
+ if (result instanceof Promise) {
2714
+ result.then((cleanup) => {
2715
+ if (typeof cleanup === "function") {
2716
+ instance.cleanupFns.push(cleanup);
2717
+ }
2718
+ });
2719
+ } else if (typeof result === "function") {
2720
+ instance.cleanupFns.push(result);
2721
+ }
2722
+ }
2723
+ instance.mountOperations = [];
2724
+ }
2725
+ function mountInstanceInline(instance, target) {
2726
+ instance.target = target;
2727
+ try {
2728
+ if (target instanceof Element)
2729
+ target.__ASKR_INSTANCE = instance;
2730
+ } catch (err) {
2731
+ }
2732
+ instance.notifyUpdate = instance._enqueueRun;
2733
+ const wasFirstMount = !instance.mounted;
2734
+ instance.mounted = true;
2735
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2736
+ executeMountOperations(instance);
2737
+ }
2738
+ }
2739
+ function runComponent(instance) {
2740
+ instance.notifyUpdate = instance._enqueueRun;
2741
+ instance._currentRenderToken = ++_globalRenderCounter;
2742
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2743
+ const domSnapshot = instance.target ? instance.target.innerHTML : "";
2744
+ const result = executeComponentSync(instance);
2745
+ if (result instanceof Promise) {
2746
+ throw new Error(
2747
+ "Async components are not supported. Components must be synchronous."
2748
+ );
2749
+ } else {
2750
+ const fastlaneBridge = globalThis.__ASKR_FASTLANE;
2751
+ try {
2752
+ const used = fastlaneBridge?.tryRuntimeFastLaneSync?.(instance, result);
2753
+ if (used) return;
2754
+ } catch (err) {
2755
+ if (process.env.NODE_ENV !== "production") throw err;
2756
+ }
2757
+ globalScheduler.enqueue(() => {
2758
+ if (!instance.target && instance._placeholder) {
2759
+ if (result === null || result === void 0) {
2760
+ finalizeReadSubscriptions2(instance);
2761
+ return;
2762
+ }
2763
+ const placeholder = instance._placeholder;
2764
+ const parent = placeholder.parentNode;
2765
+ if (!parent) {
2766
+ logger.warn(
2767
+ "[Askr] placeholder no longer in DOM, cannot render component"
2768
+ );
2769
+ return;
2770
+ }
2771
+ const host = document.createElement("div");
2772
+ const oldInstance = currentInstance;
2773
+ currentInstance = instance;
2774
+ try {
2775
+ evaluate(result, host);
2776
+ parent.replaceChild(host, placeholder);
2777
+ instance.target = host;
2778
+ instance._placeholder = void 0;
2779
+ host.__ASKR_INSTANCE = instance;
2780
+ finalizeReadSubscriptions2(instance);
2781
+ } finally {
2782
+ currentInstance = oldInstance;
2783
+ }
2784
+ return;
2785
+ }
2786
+ if (instance.target) {
2787
+ let oldChildren = [];
2788
+ try {
2789
+ const wasFirstMount = !instance.mounted;
2790
+ const oldInstance = currentInstance;
2791
+ currentInstance = instance;
2792
+ oldChildren = Array.from(instance.target.childNodes);
2793
+ try {
2794
+ evaluate(result, instance.target);
2795
+ } catch (e) {
2796
+ try {
2797
+ const newChildren = Array.from(instance.target.childNodes);
2798
+ for (const n of newChildren) {
2799
+ try {
2800
+ cleanupInstancesUnder(n);
2801
+ } catch (err) {
2802
+ logger.warn(
2803
+ "[Askr] error cleaning up failed commit children:",
2804
+ err
2805
+ );
2806
+ }
2807
+ }
2808
+ } catch (_err) {
2809
+ void _err;
2810
+ }
2811
+ try {
2812
+ __ASKR_incCounter("__DOM_REPLACE_COUNT");
2813
+ __ASKR_set(
2814
+ "__LAST_DOM_REPLACE_STACK_COMPONENT_RESTORE",
2815
+ new Error().stack
2816
+ );
2817
+ } catch (e2) {
2818
+ void e2;
2819
+ }
2820
+ instance.target.replaceChildren(...oldChildren);
2821
+ throw e;
2822
+ } finally {
2823
+ currentInstance = oldInstance;
2824
+ }
2825
+ finalizeReadSubscriptions2(instance);
2826
+ instance.mounted = true;
2827
+ if (wasFirstMount && instance.mountOperations.length > 0) {
2828
+ executeMountOperations(instance);
2829
+ }
2830
+ } catch (renderError) {
2831
+ try {
2832
+ const currentChildren = Array.from(instance.target.childNodes);
2833
+ for (const n of currentChildren) {
2834
+ try {
2835
+ cleanupInstancesUnder(n);
2836
+ } catch (err) {
2837
+ logger.warn(
2838
+ "[Askr] error cleaning up partial children during rollback:",
2839
+ err
2840
+ );
2841
+ }
2842
+ }
2843
+ } catch (_err) {
2844
+ }
2845
+ try {
2846
+ try {
2847
+ __ASKR_incCounter("__DOM_REPLACE_COUNT");
2848
+ __ASKR_set(
2849
+ "__LAST_DOM_REPLACE_STACK_COMPONENT_ROLLBACK",
2850
+ new Error().stack
2851
+ );
2852
+ } catch (e) {
2853
+ void e;
2854
+ }
2855
+ instance.target.replaceChildren(...oldChildren);
2856
+ } catch {
2857
+ instance.target.innerHTML = domSnapshot;
2858
+ }
2859
+ throw renderError;
2860
+ }
2861
+ }
2862
+ });
2863
+ }
2864
+ }
2865
+ function renderComponentInline(instance) {
2866
+ const hadToken = instance._currentRenderToken !== void 0;
2867
+ const prevToken = instance._currentRenderToken;
2868
+ const prevPendingReads = instance._pendingReadStates;
2869
+ if (!hadToken) {
2870
+ instance._currentRenderToken = ++_globalRenderCounter;
2871
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2872
+ }
2873
+ try {
2874
+ const result = executeComponentSync(instance);
2875
+ if (!hadToken) {
2876
+ finalizeReadSubscriptions2(instance);
2877
+ }
2878
+ return result;
2879
+ } finally {
2880
+ instance._currentRenderToken = prevToken;
2881
+ instance._pendingReadStates = prevPendingReads ?? /* @__PURE__ */ new Set();
2882
+ }
2883
+ }
2884
+ function executeComponentSync(instance) {
2885
+ instance.stateIndexCheck = -1;
2886
+ for (const state2 of instance.stateValues) {
2887
+ if (state2) {
2888
+ state2._hasBeenRead = false;
2889
+ }
2890
+ }
2891
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2892
+ currentInstance = instance;
2893
+ stateIndex = 0;
2894
+ try {
2895
+ const renderStartTime = process.env.NODE_ENV !== "production" ? Date.now() : 0;
2896
+ const context = {
2897
+ signal: instance.abortController.signal
2898
+ };
2899
+ const executionFrame = {
2900
+ parent: instance.ownerFrame,
2901
+ values: null
2902
+ };
2903
+ const result = withContext(
2904
+ executionFrame,
2905
+ () => instance.fn(instance.props, context)
2906
+ );
2907
+ const renderTime = Date.now() - renderStartTime;
2908
+ if (renderTime > 5) {
2909
+ logger.warn(
2910
+ `[askr] Slow render detected: ${renderTime}ms. Consider optimizing component performance.`
2911
+ );
2912
+ }
2913
+ if (!instance.firstRenderComplete) {
2914
+ instance.firstRenderComplete = true;
2915
+ }
2916
+ for (let i = 0; i < instance.stateValues.length; i++) {
2917
+ const state2 = instance.stateValues[i];
2918
+ if (state2 && !state2._hasBeenRead) {
2919
+ try {
2920
+ const name = instance.fn?.name || "<anonymous>";
2921
+ logger.warn(
2922
+ `[askr] Unused state variable detected in ${name} at index ${i}. State should be read during render or removed.`
2923
+ );
2924
+ } catch {
2925
+ logger.warn(
2926
+ `[askr] Unused state variable detected. State should be read during render or removed.`
2927
+ );
2928
+ }
2929
+ }
2930
+ }
2931
+ return result;
2932
+ } finally {
2933
+ currentInstance = null;
2934
+ }
2935
+ }
2936
+ function executeComponent(instance) {
2937
+ instance.abortController = new AbortController();
2938
+ instance.notifyUpdate = instance._enqueueRun;
2939
+ globalScheduler.enqueue(() => runComponent(instance));
2940
+ }
2941
+ function getCurrentInstance() {
2942
+ return currentInstance;
2943
+ }
2944
+ function finalizeReadSubscriptions2(instance) {
2945
+ const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
2946
+ const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
2947
+ const token = instance._currentRenderToken;
2948
+ if (token === void 0) return;
2949
+ for (const s of oldSet) {
2950
+ if (!newSet.has(s)) {
2951
+ const readers = s._readers;
2952
+ if (readers) readers.delete(instance);
2953
+ }
2954
+ }
2955
+ instance.lastRenderToken = token;
2956
+ for (const s of newSet) {
2957
+ let readers = s._readers;
2958
+ if (!readers) {
2959
+ readers = /* @__PURE__ */ new Map();
2960
+ s._readers = readers;
2961
+ }
2962
+ readers.set(instance, instance.lastRenderToken ?? 0);
2963
+ }
2964
+ instance._lastReadStates = newSet;
2965
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
2966
+ instance._currentRenderToken = void 0;
2967
+ }
2968
+ function getNextStateIndex() {
2969
+ return stateIndex++;
2970
+ }
2971
+ function mountComponent(instance) {
2972
+ executeComponent(instance);
2973
+ }
2974
+ function cleanupComponent(instance) {
2975
+ const cleanupErrors = [];
2976
+ for (const cleanup of instance.cleanupFns) {
2977
+ try {
2978
+ cleanup();
2979
+ } catch (err) {
2980
+ if (instance.cleanupStrict) {
2981
+ cleanupErrors.push(err);
2982
+ } else {
2983
+ if (process.env.NODE_ENV !== "production") {
2984
+ logger.warn("[Askr] cleanup function threw:", err);
2985
+ }
2986
+ }
2987
+ }
2988
+ }
2989
+ instance.cleanupFns = [];
2990
+ if (cleanupErrors.length > 0) {
2991
+ throw new AggregateError(
2992
+ cleanupErrors,
2993
+ `Cleanup failed for component ${instance.id}`
2994
+ );
2995
+ }
2996
+ if (instance._lastReadStates) {
2997
+ for (const s of instance._lastReadStates) {
2998
+ const readers = s._readers;
2999
+ if (readers) readers.delete(instance);
3000
+ }
3001
+ instance._lastReadStates = /* @__PURE__ */ new Set();
3002
+ }
3003
+ instance.abortController.abort();
3004
+ instance.notifyUpdate = null;
3005
+ instance.mounted = false;
3006
+ }
3007
+ var currentInstance, stateIndex, _globalRenderCounter;
3008
+ var init_component = __esm({
3009
+ "src/runtime/component.ts"() {
3010
+ init_scheduler();
3011
+ init_context();
3012
+ init_logger();
3013
+ init_diag();
3014
+ init_renderer();
3015
+ currentInstance = null;
3016
+ stateIndex = 0;
3017
+ _globalRenderCounter = 0;
3018
+ }
3019
+ });
3020
+
3021
+ // src/router/match.ts
3022
+ function match(path, pattern) {
3023
+ const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3024
+ const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
3025
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
3026
+ const patternSegments = normalizedPattern.split("/").filter(Boolean);
3027
+ if (patternSegments.length === 1 && patternSegments[0] === "*") {
3028
+ return {
3029
+ matched: true,
3030
+ params: {
3031
+ "*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
3032
+ }
3033
+ };
3034
+ }
3035
+ if (pathSegments.length !== patternSegments.length) {
3036
+ return { matched: false, params: {} };
3037
+ }
3038
+ const params = {};
3039
+ for (let i = 0; i < patternSegments.length; i++) {
3040
+ const patternSegment = patternSegments[i];
3041
+ const pathSegment = pathSegments[i];
3042
+ if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
3043
+ const paramName = patternSegment.slice(1, -1);
3044
+ params[paramName] = decodeURIComponent(pathSegment);
3045
+ } else if (patternSegment === "*") {
3046
+ params["*"] = pathSegment;
3047
+ } else if (patternSegment !== pathSegment) {
3048
+ return { matched: false, params: {} };
3049
+ }
3050
+ }
3051
+ return { matched: true, params };
3052
+ }
3053
+ var init_match = __esm({
3054
+ "src/router/match.ts"() {
3055
+ }
3056
+ });
3057
+
3058
+ // src/runtime/execution-model.ts
3059
+ function getExecutionModel() {
3060
+ const g = globalThis;
3061
+ return g[EXECUTION_MODEL_KEY];
3062
+ }
3063
+ function assertExecutionModel(model) {
3064
+ const g = globalThis;
3065
+ const cur = g[EXECUTION_MODEL_KEY];
3066
+ if (cur && cur !== model) {
3067
+ throw new Error(
3068
+ `[Askr] mixing execution models is not allowed (current: ${cur}, attempted: ${model}). Choose exactly one: createSPA, createSSR, or createIslands.`
3069
+ );
3070
+ }
3071
+ if (!cur) g[EXECUTION_MODEL_KEY] = model;
3072
+ }
3073
+ var EXECUTION_MODEL_KEY;
3074
+ var init_execution_model = __esm({
3075
+ "src/runtime/execution-model.ts"() {
3076
+ EXECUTION_MODEL_KEY = /* @__PURE__ */ Symbol.for("__ASKR_EXECUTION_MODEL__");
3077
+ }
3078
+ });
3079
+
3080
+ // src/router/route.ts
3081
+ var route_exports = {};
3082
+ __export(route_exports, {
3083
+ _lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
3084
+ _unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
3085
+ clearRoutes: () => clearRoutes,
3086
+ getLoadedNamespaces: () => getLoadedNamespaces,
3087
+ getNamespaceRoutes: () => getNamespaceRoutes,
3088
+ getRoutes: () => getRoutes,
3089
+ lockRouteRegistration: () => lockRouteRegistration,
3090
+ registerRoute: () => registerRoute,
3091
+ resolveRoute: () => resolveRoute,
3092
+ route: () => route,
3093
+ setServerLocation: () => setServerLocation,
3094
+ unloadNamespace: () => unloadNamespace
3095
+ });
3096
+ function setHasRoutes(value) {
3097
+ try {
3098
+ const g = globalThis;
3099
+ g[HAS_ROUTES_KEY] = value;
3100
+ } catch {
3101
+ }
3102
+ }
3103
+ function getDepth(path) {
3104
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3105
+ return normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3106
+ }
3107
+ function getSpecificity(path) {
3108
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3109
+ if (normalized === "/*") {
3110
+ return 0;
3111
+ }
3112
+ const segments = normalized.split("/").filter(Boolean);
3113
+ let score = 0;
3114
+ for (const segment of segments) {
3115
+ if (segment.startsWith("{") && segment.endsWith("}")) {
3116
+ score += 2;
3117
+ } else if (segment === "*") {
3118
+ score += 1;
3119
+ } else {
3120
+ score += 3;
3121
+ }
3122
+ }
3123
+ return score;
3124
+ }
3125
+ function setServerLocation(url) {
3126
+ serverLocation = url;
3127
+ }
3128
+ function parseLocation(url) {
3129
+ try {
3130
+ const u = new URL(url, "http://localhost");
3131
+ return { pathname: u.pathname, search: u.search, hash: u.hash };
3132
+ } catch {
3133
+ return { pathname: "/", search: "", hash: "" };
3134
+ }
3135
+ }
3136
+ function deepFreeze(obj) {
3137
+ if (obj && typeof obj === "object" && !Object.isFrozen(obj)) {
3138
+ Object.freeze(obj);
3139
+ for (const key of Object.keys(obj)) {
3140
+ const value = obj[key];
3141
+ if (value && typeof value === "object") deepFreeze(value);
3142
+ }
3143
+ }
3144
+ return obj;
3145
+ }
3146
+ function makeQuery(search) {
3147
+ const usp = new URLSearchParams(search || "");
3148
+ const mapping = /* @__PURE__ */ new Map();
3149
+ for (const [k, v] of usp.entries()) {
3150
+ const existing = mapping.get(k);
3151
+ if (existing) existing.push(v);
3152
+ else mapping.set(k, [v]);
3153
+ }
3154
+ const obj = {
3155
+ get(key) {
3156
+ const arr = mapping.get(key);
3157
+ return arr ? arr[0] : null;
3158
+ },
3159
+ getAll(key) {
3160
+ const arr = mapping.get(key);
3161
+ return arr ? [...arr] : [];
3162
+ },
3163
+ has(key) {
3164
+ return mapping.has(key);
3165
+ },
3166
+ toJSON() {
3167
+ const out = {};
3168
+ for (const [k, arr] of mapping.entries()) {
3169
+ out[k] = arr.length > 1 ? [...arr] : arr[0];
3170
+ }
3171
+ return out;
3172
+ }
3173
+ };
3174
+ return deepFreeze(obj);
3175
+ }
3176
+ function computeMatches(pathname) {
3177
+ const routesList = getRoutes();
3178
+ const matches = [];
3179
+ function getSpecificity2(path) {
3180
+ const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3181
+ if (normalized === "/*") return 0;
3182
+ const segments = normalized.split("/").filter(Boolean);
3183
+ let score = 0;
3184
+ for (const segment of segments) {
3185
+ if (segment.startsWith("{") && segment.endsWith("}")) score += 2;
3186
+ else if (segment === "*") score += 1;
3187
+ else score += 3;
3188
+ }
3189
+ return score;
3190
+ }
3191
+ for (const r of routesList) {
3192
+ const result = match(pathname, r.path);
3193
+ if (result.matched) {
3194
+ matches.push({
3195
+ pattern: r.path,
3196
+ params: result.params,
3197
+ name: r.name,
3198
+ namespace: r.namespace,
3199
+ specificity: getSpecificity2(r.path)
3200
+ });
3201
+ }
3202
+ }
3203
+ matches.sort((a, b) => b.specificity - a.specificity);
3204
+ return matches.map((m) => ({
3205
+ path: m.pattern,
3206
+ params: deepFreeze({ ...m.params }),
3207
+ name: m.name,
3208
+ namespace: m.namespace
3209
+ }));
3210
+ }
3211
+ function lockRouteRegistration() {
3212
+ registrationLocked = true;
3213
+ }
3214
+ function _lockRouteRegistrationForTests() {
3215
+ registrationLocked = true;
3216
+ }
3217
+ function _unlockRouteRegistrationForTests() {
3218
+ registrationLocked = false;
3219
+ }
3220
+ function route(path, handler, namespace) {
3221
+ if (getExecutionModel() === "islands") {
3222
+ throw new Error(
3223
+ "Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead."
3224
+ );
3225
+ }
3226
+ if (typeof path === "undefined") {
3227
+ const instance = getCurrentComponentInstance();
3228
+ if (!instance) {
3229
+ throw new Error(
3230
+ "route() can only be called during component render execution. Call route() from inside your component function."
3231
+ );
3232
+ }
3233
+ let pathname = "/";
3234
+ let search = "";
3235
+ let hash = "";
3236
+ if (typeof window !== "undefined" && window.location) {
3237
+ pathname = window.location.pathname || "/";
3238
+ search = window.location.search || "";
3239
+ hash = window.location.hash || "";
3240
+ } else if (serverLocation) {
3241
+ const parsed = parseLocation(serverLocation);
3242
+ pathname = parsed.pathname;
3243
+ search = parsed.search;
3244
+ hash = parsed.hash;
3245
+ }
3246
+ const params = deepFreeze({
3247
+ ...instance.props || {}
3248
+ });
3249
+ const query = makeQuery(search);
3250
+ const matches = computeMatches(pathname);
3251
+ const snapshot = Object.freeze({
3252
+ path: pathname,
3253
+ params,
3254
+ query,
3255
+ hash: hash || null,
3256
+ matches: Object.freeze(matches)
3257
+ });
3258
+ return snapshot;
3259
+ }
3260
+ const currentInst = getCurrentComponentInstance();
3261
+ if (currentInst && currentInst.ssr) {
3262
+ throw new Error(
3263
+ "route() cannot be called during SSR rendering. Register routes at module load time instead."
3264
+ );
3265
+ }
3266
+ if (registrationLocked) {
3267
+ throw new Error(
3268
+ "Route registration is locked after app startup. Register routes at module load time before calling createSPA or createSSR."
3269
+ );
3270
+ }
3271
+ if (typeof handler !== "function") {
3272
+ throw new Error(
3273
+ "route(path, handler) requires a function handler that returns a VNode (e.g. () => <Page />). Passing JSX elements or VNodes directly is not supported."
3274
+ );
3275
+ }
3276
+ const routeObj = { path, handler, namespace };
3277
+ routes.push(routeObj);
3278
+ setHasRoutes(true);
3279
+ const depth = getDepth(path);
3280
+ let depthRoutes = routesByDepth.get(depth);
3281
+ if (!depthRoutes) {
3282
+ depthRoutes = [];
3283
+ routesByDepth.set(depth, depthRoutes);
3284
+ }
3285
+ depthRoutes.push(routeObj);
3286
+ if (namespace) {
3287
+ namespaces.add(namespace);
3288
+ }
3289
+ }
3290
+ function getRoutes() {
3291
+ return [...routes];
3292
+ }
3293
+ function getNamespaceRoutes(namespace) {
3294
+ return routes.filter((r) => r.namespace === namespace);
3295
+ }
3296
+ function unloadNamespace(namespace) {
3297
+ const before = routes.length;
3298
+ for (let i = routes.length - 1; i >= 0; i--) {
3299
+ if (routes[i].namespace === namespace) {
3300
+ const removed = routes[i];
3301
+ routes.splice(i, 1);
3302
+ const depth = getDepth(removed.path);
3303
+ const depthRoutes = routesByDepth.get(depth);
3304
+ if (depthRoutes) {
3305
+ const idx = depthRoutes.indexOf(removed);
3306
+ if (idx >= 0) {
3307
+ depthRoutes.splice(idx, 1);
3308
+ }
3309
+ }
3310
+ }
3311
+ }
3312
+ namespaces.delete(namespace);
3313
+ return before - routes.length;
3314
+ }
3315
+ function clearRoutes() {
3316
+ routes.length = 0;
3317
+ namespaces.clear();
3318
+ routesByDepth.clear();
3319
+ registrationLocked = false;
3320
+ setHasRoutes(false);
3321
+ }
3322
+ function normalizeHandler(handler) {
3323
+ if (handler == null) return void 0;
3324
+ if (typeof handler === "function") {
3325
+ return (params, ctx) => {
3326
+ try {
3327
+ return handler(params, ctx);
3328
+ } catch {
3329
+ return handler(params);
3330
+ }
3331
+ };
3332
+ }
3333
+ return void 0;
3334
+ }
3335
+ function registerRoute(path, handler, ...children) {
3336
+ const isRelative = !path.startsWith("/");
3337
+ const descriptor = {
3338
+ path,
3339
+ handler,
3340
+ children: children.filter(Boolean),
3341
+ _isDescriptor: true
3342
+ };
3343
+ if (!isRelative) {
3344
+ const normalized = normalizeHandler(handler);
3345
+ if (handler != null && !normalized) {
3346
+ throw new Error(
3347
+ "registerRoute(path, handler) requires a function handler. Passing JSX elements or VNodes directly is not supported."
3348
+ );
3349
+ }
3350
+ if (normalized) route(path, normalized);
3351
+ for (const child of descriptor.children || []) {
3352
+ const base = path === "/" ? "" : path.replace(/\/$/, "");
3353
+ const childPath = `${base}/${child.path.replace(/^\//, "")}`.replace(
3354
+ /\/\//g,
3355
+ "/"
3356
+ );
3357
+ if (child.handler) {
3358
+ const childNormalized = normalizeHandler(child.handler);
3359
+ if (!childNormalized) {
3360
+ throw new Error(
3361
+ "registerRoute child handler must be a function. Passing JSX elements directly is not supported."
3362
+ );
3363
+ }
3364
+ if (childNormalized) route(childPath, childNormalized);
3365
+ }
3366
+ if (child.children && child.children.length) {
3367
+ registerRoute(
3368
+ childPath,
3369
+ null,
3370
+ ...child.children
3371
+ );
3372
+ }
3373
+ }
3374
+ return descriptor;
3375
+ }
3376
+ return descriptor;
3377
+ }
3378
+ function getLoadedNamespaces() {
3379
+ return Array.from(namespaces);
3380
+ }
3381
+ function resolveRoute(pathname) {
3382
+ const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
3383
+ const depth = normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
3384
+ const candidates = [];
3385
+ const depthRoutes = routesByDepth.get(depth);
3386
+ if (depthRoutes) {
3387
+ for (const r of depthRoutes) {
3388
+ const result = match(pathname, r.path);
3389
+ if (result.matched) {
3390
+ candidates.push({
3391
+ route: r,
3392
+ specificity: getSpecificity(r.path),
3393
+ params: result.params
3394
+ });
3395
+ }
3396
+ }
3397
+ }
3398
+ for (const r of routes) {
3399
+ if (depthRoutes?.includes(r)) continue;
3400
+ const result = match(pathname, r.path);
3401
+ if (result.matched) {
3402
+ candidates.push({
3403
+ route: r,
3404
+ specificity: getSpecificity(r.path),
3405
+ params: result.params
3406
+ });
3407
+ }
3408
+ }
3409
+ candidates.sort((a, b) => b.specificity - a.specificity);
3410
+ if (candidates.length > 0) {
3411
+ const best = candidates[0];
3412
+ return { handler: best.route.handler, params: best.params };
3413
+ }
3414
+ return null;
3415
+ }
3416
+ var routes, namespaces, HAS_ROUTES_KEY, routesByDepth, serverLocation, registrationLocked;
3417
+ var init_route = __esm({
3418
+ "src/router/route.ts"() {
3419
+ init_match();
3420
+ init_component();
3421
+ init_execution_model();
3422
+ routes = [];
3423
+ namespaces = /* @__PURE__ */ new Set();
3424
+ HAS_ROUTES_KEY = /* @__PURE__ */ Symbol.for("__ASKR_HAS_ROUTES__");
3425
+ setHasRoutes(false);
3426
+ routesByDepth = /* @__PURE__ */ new Map();
3427
+ serverLocation = null;
3428
+ registrationLocked = false;
3429
+ }
3430
+ });
3431
+
3432
+ // src/router/navigate.ts
3433
+ function registerAppInstance(instance, _path) {
3434
+ currentInstance2 = instance;
3435
+ if (process.env.NODE_ENV === "production") {
3436
+ lockRouteRegistration();
3437
+ }
3438
+ }
3439
+ function handlePopState(_event) {
3440
+ const path = window.location.pathname;
3441
+ if (!currentInstance2) {
3442
+ return;
3443
+ }
3444
+ const resolved = resolveRoute(path);
3445
+ if (resolved) {
3446
+ cleanupComponent(currentInstance2);
3447
+ currentInstance2.fn = resolved.handler;
3448
+ currentInstance2.props = resolved.params;
3449
+ currentInstance2.stateValues = [];
3450
+ currentInstance2.expectedStateIndices = [];
3451
+ currentInstance2.firstRenderComplete = false;
3452
+ currentInstance2.stateIndexCheck = -1;
3453
+ currentInstance2.evaluationGeneration++;
3454
+ currentInstance2.notifyUpdate = null;
3455
+ currentInstance2.abortController = new AbortController();
3456
+ mountComponent(currentInstance2);
3457
+ }
3458
+ }
3459
+ function initializeNavigation() {
3460
+ if (typeof window !== "undefined") {
3461
+ window.addEventListener("popstate", handlePopState);
3462
+ }
3463
+ }
3464
+ var currentInstance2;
3465
+ var init_navigate = __esm({
3466
+ "src/router/navigate.ts"() {
3467
+ init_route();
3468
+ init_component();
3469
+ currentInstance2 = null;
3470
+ }
3471
+ });
3472
+
3473
+ // src/jsx/index.ts
3474
+ var init_jsx2 = __esm({
3475
+ "src/jsx/index.ts"() {
3476
+ init_types2();
3477
+ }
3478
+ });
3479
+
3480
+ // src/foundations/portal.tsx
3481
+ function definePortal() {
3482
+ if (typeof createPortalSlot !== "function") {
3483
+ let HostFallback2 = function() {
3484
+ if (owner && owner.mounted === false) {
3485
+ owner = null;
3486
+ pending = void 0;
3487
+ }
3488
+ const inst = getCurrentComponentInstance();
3489
+ if (!owner && inst) owner = inst;
3490
+ if (process.env.NODE_ENV !== "production") {
3491
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3492
+ ns.__PORTAL_READS = (ns.__PORTAL_READS || 0) + 1;
3493
+ }
3494
+ if (process.env.NODE_ENV !== "production") {
3495
+ if (inst && owner && inst !== owner && inst.mounted === true) {
3496
+ logger.warn(
3497
+ "[Portal] multiple mounted hosts detected; first mounted host is owner"
3498
+ );
3499
+ }
3500
+ }
3501
+ return inst && owner && inst === owner ? pending : void 0;
3502
+ };
3503
+ let owner = null;
3504
+ let pending;
3505
+ HostFallback2.render = function RenderFallback(props) {
3506
+ if (!owner || owner.mounted !== true) return null;
3507
+ if (process.env.NODE_ENV !== "production") {
3508
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3509
+ ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
3510
+ }
3511
+ pending = props.children;
3512
+ if (owner.notifyUpdate) owner.notifyUpdate();
3513
+ return null;
3514
+ };
3515
+ return HostFallback2;
3516
+ }
3517
+ const slot = createPortalSlot();
3518
+ function PortalHost() {
3519
+ return slot.read();
3520
+ }
3521
+ PortalHost.render = function PortalRender(props) {
3522
+ if (process.env.NODE_ENV !== "production") {
3523
+ const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3524
+ ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
3525
+ }
3526
+ slot.write(props.children);
3527
+ return null;
3528
+ };
3529
+ return PortalHost;
3530
+ }
3531
+ function ensureDefaultPortal() {
3532
+ if (!_defaultPortal) {
3533
+ if (typeof createPortalSlot === "function") {
3534
+ _defaultPortal = definePortal();
3535
+ _defaultPortalIsFallback = false;
3536
+ } else {
3537
+ _defaultPortal = definePortal();
3538
+ _defaultPortalIsFallback = true;
3539
+ }
3540
+ return _defaultPortal;
3541
+ }
3542
+ if (_defaultPortalIsFallback && typeof createPortalSlot === "function") {
3543
+ const real = definePortal();
3544
+ _defaultPortal = real;
3545
+ _defaultPortalIsFallback = false;
3546
+ }
3547
+ if (!_defaultPortalIsFallback && typeof createPortalSlot !== "function") {
3548
+ const fallback = definePortal();
3549
+ _defaultPortal = fallback;
3550
+ _defaultPortalIsFallback = true;
3551
+ }
3552
+ return _defaultPortal;
3553
+ }
3554
+ var _defaultPortal, _defaultPortalIsFallback, DefaultPortal;
3555
+ var init_portal = __esm({
3556
+ "src/foundations/portal.tsx"() {
3557
+ init_component();
3558
+ init_logger();
3559
+ _defaultPortalIsFallback = false;
3560
+ DefaultPortal = (() => {
3561
+ function Host() {
3562
+ const v = ensureDefaultPortal()();
3563
+ return v === void 0 ? null : v;
3564
+ }
3565
+ Host.render = function Render(props) {
3566
+ ensureDefaultPortal().render(props);
3567
+ return null;
3568
+ };
3569
+ return Host;
3570
+ })();
3571
+ }
3572
+ });
3573
+
3574
+ // src/boot/index.ts
3575
+ init_component();
3576
+ init_scheduler();
3577
+ init_logger();
3578
+ init_navigate();
3579
+ init_execution_model();
3580
+ init_jsx2();
3581
+ init_portal();
3582
+ init_renderer();
3583
+ var HAS_ROUTES_KEY2 = /* @__PURE__ */ Symbol.for("__ASKR_HAS_ROUTES__");
3584
+ var componentIdCounter = 0;
3585
+ var instancesByRoot = /* @__PURE__ */ new WeakMap();
3586
+ var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
3587
+ function attachCleanupForRoot(rootElement, instance) {
3588
+ rootElement[CLEANUP_SYMBOL] = () => {
3589
+ const errors = [];
3590
+ try {
3591
+ removeAllListeners(rootElement);
3592
+ } catch (e) {
3593
+ errors.push(e);
3594
+ }
3595
+ try {
3596
+ const descendants = rootElement.querySelectorAll("*");
3597
+ for (const d of Array.from(descendants)) {
3598
+ try {
3599
+ const inst = d.__ASKR_INSTANCE;
3600
+ if (inst) {
3601
+ try {
3602
+ cleanupComponent(inst);
3603
+ } catch (err) {
3604
+ errors.push(err);
3605
+ }
3606
+ try {
3607
+ delete d.__ASKR_INSTANCE;
3608
+ } catch (err) {
3609
+ errors.push(err);
3610
+ }
3611
+ }
3612
+ } catch (err) {
3613
+ errors.push(err);
3614
+ }
3615
+ }
3616
+ } catch (e) {
3617
+ errors.push(e);
3618
+ }
3619
+ try {
3620
+ cleanupComponent(instance);
3621
+ } catch (e) {
3622
+ errors.push(e);
3623
+ }
3624
+ if (errors.length > 0) {
3625
+ if (instance.cleanupStrict) {
3626
+ throw new AggregateError(errors, `cleanup failed for app root`);
3627
+ } else if (process.env.NODE_ENV !== "production") {
3628
+ for (const err of errors) logger.warn("[Askr] cleanup error:", err);
3629
+ }
3630
+ }
3631
+ };
3632
+ try {
3633
+ const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
3634
+ Object.getPrototypeOf(rootElement),
3635
+ "innerHTML"
3636
+ ) || Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
3637
+ if (descriptor && (descriptor.get || descriptor.set)) {
3638
+ Object.defineProperty(rootElement, "innerHTML", {
3639
+ get: descriptor.get ? function() {
3640
+ return descriptor.get.call(this);
3641
+ } : void 0,
3642
+ set: function(value) {
3643
+ if (value === "" && instancesByRoot.get(this) === instance) {
3644
+ try {
3645
+ removeAllListeners(rootElement);
3646
+ } catch (e) {
3647
+ if (instance.cleanupStrict) throw e;
3648
+ if (process.env.NODE_ENV !== "production")
3649
+ logger.warn("[Askr] cleanup error:", e);
3650
+ }
3651
+ try {
3652
+ cleanupComponent(instance);
3653
+ } catch (e) {
3654
+ if (instance.cleanupStrict) throw e;
3655
+ if (process.env.NODE_ENV !== "production")
3656
+ logger.warn("[Askr] cleanup error:", e);
3657
+ }
3658
+ }
3659
+ if (descriptor.set) {
3660
+ return descriptor.set.call(this, value);
3661
+ }
3662
+ },
3663
+ configurable: true
3664
+ });
3665
+ }
3666
+ } catch {
3667
+ }
3668
+ }
3669
+ function mountOrUpdate(rootElement, componentFn, options) {
3670
+ const wrappedFn = (props, ctx) => {
3671
+ const out = componentFn(props, ctx);
3672
+ const portalVNode = {
3673
+ $$typeof: ELEMENT_TYPE,
3674
+ type: DefaultPortal,
3675
+ props: {},
3676
+ key: "__default_portal"
3677
+ };
3678
+ return {
3679
+ $$typeof: ELEMENT_TYPE,
3680
+ type: Fragment,
3681
+ props: {
3682
+ children: out === void 0 || out === null ? [portalVNode] : [out, portalVNode]
3683
+ }
3684
+ };
3685
+ };
3686
+ Object.defineProperty(wrappedFn, "name", {
3687
+ value: componentFn.name || "Component"
3688
+ });
3689
+ const existingCleanup = rootElement[CLEANUP_SYMBOL];
3690
+ if (existingCleanup) existingCleanup();
3691
+ let instance = instancesByRoot.get(rootElement);
3692
+ if (instance) {
3693
+ removeAllListeners(rootElement);
3694
+ try {
3695
+ cleanupComponent(instance);
3696
+ } catch (e) {
3697
+ if (process.env.NODE_ENV !== "production")
3698
+ logger.warn("[Askr] prior cleanup threw:", e);
3699
+ }
3700
+ instance.fn = wrappedFn;
3701
+ instance.evaluationGeneration++;
3702
+ instance.mounted = false;
3703
+ instance.expectedStateIndices = [];
3704
+ instance.firstRenderComplete = false;
3705
+ instance.isRoot = true;
3706
+ if (options && typeof options.cleanupStrict === "boolean") {
3707
+ instance.cleanupStrict = options.cleanupStrict;
3708
+ }
3709
+ } else {
3710
+ const componentId = String(++componentIdCounter);
3711
+ instance = createComponentInstance(componentId, wrappedFn, {}, rootElement);
3712
+ instancesByRoot.set(rootElement, instance);
3713
+ instance.isRoot = true;
3714
+ if (options && typeof options.cleanupStrict === "boolean") {
3715
+ instance.cleanupStrict = options.cleanupStrict;
3716
+ }
3717
+ }
3718
+ attachCleanupForRoot(rootElement, instance);
3719
+ mountComponent(instance);
3720
+ globalScheduler.flush();
3721
+ }
3722
+ function createIsland(config) {
3723
+ assertExecutionModel("islands");
3724
+ if (!config || typeof config !== "object") {
3725
+ throw new Error("createIsland requires a config object");
3726
+ }
3727
+ if (typeof config.component !== "function") {
3728
+ throw new Error("createIsland: component must be a function");
3729
+ }
3730
+ const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
3731
+ if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
3732
+ if ("routes" in config) {
3733
+ throw new Error(
3734
+ "createIsland does not accept routes; use createSPA for routed apps"
3735
+ );
3736
+ }
3737
+ try {
3738
+ const g = globalThis;
3739
+ if (g[HAS_ROUTES_KEY2]) {
3740
+ throw new Error(
3741
+ "Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead."
3742
+ );
3743
+ }
3744
+ } catch {
3745
+ }
3746
+ mountOrUpdate(rootElement, config.component, {
3747
+ cleanupStrict: config.cleanupStrict
3748
+ });
3749
+ }
3750
+ async function createSPA(config) {
3751
+ assertExecutionModel("spa");
3752
+ if (!config || typeof config !== "object") {
3753
+ throw new Error("createSPA requires a config object");
3754
+ }
3755
+ if (!Array.isArray(config.routes) || config.routes.length === 0) {
3756
+ throw new Error(
3757
+ "createSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
3758
+ );
3759
+ }
3760
+ const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
3761
+ if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
3762
+ const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration: lockRouteRegistration2, resolveRoute: resolveRoute2 } = await Promise.resolve().then(() => (init_route(), route_exports));
3763
+ clearRoutes2();
3764
+ for (const r of config.routes) {
3765
+ route2(r.path, r.handler, r.namespace);
3766
+ }
3767
+ if (process.env.NODE_ENV === "production") lockRouteRegistration2();
3768
+ const path = typeof window !== "undefined" ? window.location.pathname : "/";
3769
+ const resolved = resolveRoute2(path);
3770
+ if (!resolved) {
3771
+ if (process.env.NODE_ENV !== "production") {
3772
+ logger.warn(
3773
+ `createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
3774
+ );
3775
+ }
3776
+ mountOrUpdate(rootElement, () => ({ type: "div", children: [] }), {
3777
+ cleanupStrict: false
3778
+ });
3779
+ const instance2 = instancesByRoot.get(rootElement);
3780
+ if (!instance2) throw new Error("Internal error: app instance missing");
3781
+ registerAppInstance(instance2);
3782
+ initializeNavigation();
3783
+ return;
3784
+ }
3785
+ mountOrUpdate(rootElement, resolved.handler, {
3786
+ cleanupStrict: false
3787
+ });
3788
+ const instance = instancesByRoot.get(rootElement);
3789
+ if (!instance) throw new Error("Internal error: app instance missing");
3790
+ registerAppInstance(instance);
3791
+ initializeNavigation();
3792
+ }
3793
+
3794
+ // src/runtime/state.ts
3795
+ init_scheduler();
3796
+ init_component();
3797
+ init_invariant();
3798
+ init_fastlane();
3799
+ function state(initialValue) {
3800
+ const instance = getCurrentInstance();
3801
+ if (!instance) {
3802
+ throw new Error(
3803
+ "state() can only be called during component render execution. Move state() calls to the top level of your component function."
3804
+ );
3805
+ }
3806
+ const index = getNextStateIndex();
3807
+ const stateValues = instance.stateValues;
3808
+ if (index < instance.stateIndexCheck) {
3809
+ throw new Error(
3810
+ `State index violation: state() call at index ${index}, but previously saw index ${instance.stateIndexCheck}. This happens when state() is called conditionally (inside if/for/etc). Move all state() calls to the top level of your component function, before any conditionals.`
3811
+ );
3812
+ }
3813
+ invariant(
3814
+ index >= instance.stateIndexCheck,
3815
+ "[State] State indices must increase monotonically"
3816
+ );
3817
+ instance.stateIndexCheck = index;
3818
+ if (instance.firstRenderComplete) {
3819
+ if (!instance.expectedStateIndices.includes(index)) {
3820
+ throw new Error(
3821
+ `Hook order violation: state() called at index ${index}, but this index was not in the first render's sequence [${instance.expectedStateIndices.join(", ")}]. This usually means state() is inside a conditional or loop. Move all state() calls to the top level of your component function.`
3822
+ );
3823
+ }
3824
+ } else {
3825
+ instance.expectedStateIndices.push(index);
3826
+ }
3827
+ if (stateValues[index]) {
3828
+ const existing = stateValues[index];
3829
+ if (existing._owner !== instance) {
3830
+ throw new Error(
3831
+ `State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
3832
+ );
3833
+ }
3834
+ return existing;
3835
+ }
3836
+ const cell = createStateCell(initialValue, instance);
3837
+ stateValues[index] = cell;
3838
+ return cell;
3839
+ }
3840
+ function createStateCell(initialValue, instance) {
3841
+ let value = initialValue;
3842
+ const readers = /* @__PURE__ */ new Map();
3843
+ function read() {
3844
+ read._hasBeenRead = true;
3845
+ const inst = getCurrentInstance();
3846
+ if (inst && inst._currentRenderToken !== void 0) {
3847
+ if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
3848
+ inst._pendingReadStates.add(read);
3849
+ }
3850
+ return value;
3851
+ }
3852
+ read._readers = readers;
3853
+ read._owner = instance;
3854
+ read.set = (newValueOrUpdater) => {
3855
+ const currentInst = getCurrentInstance();
3856
+ if (currentInst !== null) {
3857
+ throw new Error(
3858
+ `[Askr] state.set() cannot be called during component render. State mutations during render break the actor model and cause infinite loops. Move state updates to event handlers or use conditional rendering instead.`
3859
+ );
3860
+ }
3861
+ let newValue;
3862
+ if (typeof newValueOrUpdater === "function") {
3863
+ const updater = newValueOrUpdater;
3864
+ newValue = updater(value);
3865
+ } else {
3866
+ newValue = newValueOrUpdater;
3867
+ }
3868
+ if (Object.is(value, newValue)) return;
3869
+ if (isBulkCommitActive2()) {
3870
+ value = newValue;
3871
+ return;
3872
+ }
3873
+ value = newValue;
3874
+ const readersMap = read._readers;
3875
+ if (readersMap) {
3876
+ for (const [subInst, token] of readersMap) {
3877
+ if (subInst.lastRenderToken !== token) continue;
3878
+ if (!subInst.hasPendingUpdate) {
3879
+ subInst.hasPendingUpdate = true;
3880
+ const subTask = subInst._pendingFlushTask;
3881
+ if (subTask) globalScheduler.enqueue(subTask);
3882
+ else
3883
+ globalScheduler.enqueue(() => {
3884
+ subInst.hasPendingUpdate = false;
3885
+ subInst.notifyUpdate?.();
3886
+ });
3887
+ }
3888
+ }
3889
+ }
3890
+ const readersMapForOwner = readersMap;
3891
+ const ownerRecordedToken = readersMapForOwner?.get(instance);
3892
+ const ownerShouldEnqueue = (
3893
+ // Normal case: owner read this state in last committed render
3894
+ ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
3895
+ );
3896
+ if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
3897
+ instance.hasPendingUpdate = true;
3898
+ const task = instance._pendingFlushTask;
3899
+ if (task) globalScheduler.enqueue(task);
3900
+ else
3901
+ globalScheduler.enqueue(() => {
3902
+ instance.hasPendingUpdate = false;
3903
+ instance.notifyUpdate?.();
3904
+ });
3905
+ }
3906
+ };
3907
+ return read;
3908
+ }
3909
+
3910
+ // src/runtime/derive.ts
3911
+ init_component();
3912
+ var deriveCaches = /* @__PURE__ */ new WeakMap();
3913
+ function getDeriveCache(instance) {
3914
+ let cache = deriveCaches.get(instance);
3915
+ if (!cache) {
3916
+ cache = /* @__PURE__ */ new Map();
3917
+ deriveCaches.set(instance, cache);
3918
+ }
3919
+ return cache;
3920
+ }
3921
+ function derive(source, map) {
3922
+ if (map === void 0 && typeof source === "function") {
3923
+ const value2 = source();
3924
+ if (value2 == null) return null;
3925
+ const instance2 = getCurrentComponentInstance();
3926
+ if (!instance2) {
3927
+ return value2;
3928
+ }
3929
+ const cache2 = getDeriveCache(instance2);
3930
+ if (cache2.has(value2)) return cache2.get(value2);
3931
+ cache2.set(value2, value2);
3932
+ return value2;
3933
+ }
3934
+ let value;
3935
+ if (typeof source === "function" && !("value" in source)) {
3936
+ value = source();
3937
+ } else {
3938
+ value = source?.value ?? source;
3939
+ }
3940
+ if (value == null) return null;
3941
+ const instance = getCurrentComponentInstance();
3942
+ if (!instance) {
3943
+ return map(value);
3944
+ }
3945
+ const cache = getDeriveCache(instance);
3946
+ if (cache.has(value)) {
3947
+ return cache.get(value);
3948
+ }
3949
+ const result = map(value);
3950
+ cache.set(value, result);
3951
+ return result;
3952
+ }
3953
+
3954
+ export { createIsland, createSPA, derive, state };
3955
+ //# sourceMappingURL=index.js.map
1029
3956
  //# sourceMappingURL=index.js.map