@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
@@ -1,40 +1,69 @@
1
- "use strict";
2
1
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res) => function __init() {
7
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
- };
9
2
  var __export = (target, all) => {
10
3
  for (var name in all)
11
4
  __defProp(target, name, { get: all[name], enumerable: true });
12
5
  };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
6
+
7
+ // src/router/route.ts
8
+ var route_exports = {};
9
+ __export(route_exports, {
10
+ _lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
11
+ _unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
12
+ clearRoutes: () => clearRoutes,
13
+ getLoadedNamespaces: () => getLoadedNamespaces,
14
+ getNamespaceRoutes: () => getNamespaceRoutes,
15
+ getRoutes: () => getRoutes,
16
+ lockRouteRegistration: () => lockRouteRegistration,
17
+ registerRoute: () => registerRoute,
18
+ resolveRoute: () => resolveRoute,
19
+ route: () => route,
20
+ setServerLocation: () => setServerLocation,
21
+ unloadNamespace: () => unloadNamespace
22
+ });
23
+
24
+ // src/router/match.ts
25
+ function match(path, pattern) {
26
+ const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
27
+ const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
28
+ const pathSegments = normalizedPath.split("/").filter(Boolean);
29
+ const patternSegments = normalizedPattern.split("/").filter(Boolean);
30
+ if (patternSegments.length === 1 && patternSegments[0] === "*") {
31
+ return {
32
+ matched: true,
33
+ params: {
34
+ "*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
35
+ }
36
+ };
18
37
  }
19
- return to;
20
- };
21
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
+ if (pathSegments.length !== patternSegments.length) {
39
+ return { matched: false, params: {} };
40
+ }
41
+ const params = {};
42
+ for (let i = 0; i < patternSegments.length; i++) {
43
+ const patternSegment = patternSegments[i];
44
+ const pathSegment = pathSegments[i];
45
+ if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
46
+ const paramName = patternSegment.slice(1, -1);
47
+ params[paramName] = decodeURIComponent(pathSegment);
48
+ } else if (patternSegment === "*") {
49
+ params["*"] = pathSegment;
50
+ } else if (patternSegment !== pathSegment) {
51
+ return { matched: false, params: {} };
52
+ }
53
+ }
54
+ return { matched: true, params };
55
+ }
22
56
 
23
57
  // src/dev/invariant.ts
24
58
  function invariant(condition, message, context) {
25
59
  if (!condition) {
26
- const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
60
+ const contextStr = "";
27
61
  throw new Error(`[Askr Invariant] ${message}${contextStr}`);
28
62
  }
29
63
  }
30
64
  function assertSchedulingPrecondition(condition, violationMessage) {
31
65
  invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
32
66
  }
33
- var init_invariant = __esm({
34
- "src/dev/invariant.ts"() {
35
- "use strict";
36
- }
37
- });
38
67
 
39
68
  // src/dev/logger.ts
40
69
  function callConsole(method, args) {
@@ -48,322 +77,279 @@ function callConsole(method, args) {
48
77
  }
49
78
  }
50
79
  }
51
- var logger;
52
- var init_logger = __esm({
53
- "src/dev/logger.ts"() {
54
- "use strict";
55
- logger = {
56
- debug: (...args) => {
57
- if (process.env.NODE_ENV === "production") return;
58
- callConsole("debug", args);
59
- },
60
- info: (...args) => {
61
- if (process.env.NODE_ENV === "production") return;
62
- callConsole("info", args);
63
- },
64
- warn: (...args) => {
65
- if (process.env.NODE_ENV === "production") return;
66
- callConsole("warn", args);
67
- },
68
- error: (...args) => {
69
- callConsole("error", args);
70
- }
71
- };
80
+ var logger = {
81
+ debug: (...args) => {
82
+ if (process.env.NODE_ENV === "production") return;
83
+ callConsole("debug", args);
84
+ },
85
+ info: (...args) => {
86
+ if (process.env.NODE_ENV === "production") return;
87
+ callConsole("info", args);
88
+ },
89
+ warn: (...args) => {
90
+ if (process.env.NODE_ENV === "production") return;
91
+ callConsole("warn", args);
92
+ },
93
+ error: (...args) => {
94
+ callConsole("error", args);
72
95
  }
73
- });
96
+ };
74
97
 
75
98
  // src/runtime/scheduler.ts
99
+ var MAX_FLUSH_DEPTH = 50;
76
100
  function isBulkCommitActive() {
77
101
  try {
78
102
  const fb = globalThis.__ASKR_FASTLANE;
79
103
  return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
80
104
  } catch (e) {
81
- void e;
82
105
  return false;
83
106
  }
84
107
  }
85
- function isSchedulerExecuting() {
86
- return globalScheduler.isExecuting();
87
- }
88
- function scheduleEventHandler(handler) {
89
- return (event) => {
90
- globalScheduler.setInHandler(true);
91
- try {
92
- handler.call(null, event);
93
- } catch (error) {
94
- logger.error("[Askr] Event handler error:", error);
95
- } finally {
96
- globalScheduler.setInHandler(false);
97
- const state2 = globalScheduler.getState();
98
- if ((state2.queueLength ?? 0) > 0 && !state2.running) {
99
- queueMicrotask(() => {
100
- try {
101
- if (!globalScheduler.isExecuting()) globalScheduler.flush();
102
- } catch (err) {
103
- setTimeout(() => {
104
- throw err;
105
- });
106
- }
107
- });
108
+ var Scheduler = class {
109
+ constructor() {
110
+ this.q = [];
111
+ this.head = 0;
112
+ this.running = false;
113
+ this.inHandler = false;
114
+ this.depth = 0;
115
+ this.executionDepth = 0;
116
+ // for compat with existing diagnostics
117
+ // Monotonic flush version increments at end of each flush
118
+ this.flushVersion = 0;
119
+ // Best-effort microtask kick scheduling
120
+ this.kickScheduled = false;
121
+ // Escape hatch flag for runWithSyncProgress
122
+ this.allowSyncProgress = false;
123
+ // Waiters waiting for flushVersion >= target
124
+ this.waiters = [];
125
+ // Keep a lightweight taskCount for compatibility/diagnostics
126
+ this.taskCount = 0;
127
+ }
128
+ enqueue(task) {
129
+ assertSchedulingPrecondition(
130
+ typeof task === "function",
131
+ "enqueue() requires a function"
132
+ );
133
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
134
+ if (process.env.NODE_ENV !== "production") {
135
+ throw new Error(
136
+ "[Scheduler] enqueue() during bulk commit (not allowed)"
137
+ );
108
138
  }
139
+ return;
109
140
  }
110
- };
111
- }
112
- var MAX_FLUSH_DEPTH, Scheduler, globalScheduler;
113
- var init_scheduler = __esm({
114
- "src/runtime/scheduler.ts"() {
115
- "use strict";
116
- init_invariant();
117
- init_logger();
118
- MAX_FLUSH_DEPTH = 50;
119
- Scheduler = class {
120
- constructor() {
121
- this.q = [];
122
- this.head = 0;
123
- this.running = false;
124
- this.inHandler = false;
125
- this.depth = 0;
126
- this.executionDepth = 0;
127
- // for compat with existing diagnostics
128
- // Monotonic flush version increments at end of each flush
129
- this.flushVersion = 0;
130
- // Best-effort microtask kick scheduling
141
+ this.q.push(task);
142
+ this.taskCount++;
143
+ if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
144
+ this.kickScheduled = true;
145
+ queueMicrotask(() => {
131
146
  this.kickScheduled = false;
132
- // Escape hatch flag for runWithSyncProgress
133
- this.allowSyncProgress = false;
134
- // Waiters waiting for flushVersion >= target
135
- this.waiters = [];
136
- // Keep a lightweight taskCount for compatibility/diagnostics
137
- this.taskCount = 0;
138
- }
139
- enqueue(task2) {
140
- assertSchedulingPrecondition(
141
- typeof task2 === "function",
142
- "enqueue() requires a function"
143
- );
144
- if (isBulkCommitActive() && !this.allowSyncProgress) {
145
- if (process.env.NODE_ENV !== "production") {
146
- throw new Error(
147
- "[Scheduler] enqueue() during bulk commit (not allowed)"
148
- );
149
- }
150
- return;
151
- }
152
- this.q.push(task2);
153
- this.taskCount++;
154
- if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
155
- this.kickScheduled = true;
156
- queueMicrotask(() => {
157
- this.kickScheduled = false;
158
- if (this.running) return;
159
- if (isBulkCommitActive()) return;
160
- try {
161
- this.flush();
162
- } catch (err) {
163
- setTimeout(() => {
164
- throw err;
165
- });
166
- }
147
+ if (this.running) return;
148
+ if (isBulkCommitActive()) return;
149
+ try {
150
+ this.flush();
151
+ } catch (err) {
152
+ setTimeout(() => {
153
+ throw err;
167
154
  });
168
155
  }
169
- }
170
- flush() {
171
- invariant(
172
- !this.running,
173
- "[Scheduler] flush() called while already running"
156
+ });
157
+ }
158
+ }
159
+ flush() {
160
+ invariant(
161
+ !this.running,
162
+ "[Scheduler] flush() called while already running"
163
+ );
164
+ if (process.env.NODE_ENV !== "production") {
165
+ if (isBulkCommitActive() && !this.allowSyncProgress) {
166
+ throw new Error(
167
+ "[Scheduler] flush() started during bulk commit (not allowed)"
174
168
  );
175
- if (process.env.NODE_ENV !== "production") {
176
- if (isBulkCommitActive() && !this.allowSyncProgress) {
177
- throw new Error(
178
- "[Scheduler] flush() started during bulk commit (not allowed)"
179
- );
180
- }
181
- }
182
- this.running = true;
183
- this.depth = 0;
184
- let fatal = null;
185
- try {
186
- while (this.head < this.q.length) {
187
- this.depth++;
188
- if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
189
- throw new Error(
190
- `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
191
- );
192
- }
193
- const task2 = this.q[this.head++];
194
- try {
195
- this.executionDepth++;
196
- task2();
197
- this.executionDepth--;
198
- } catch (err) {
199
- if (this.executionDepth > 0) this.executionDepth = 0;
200
- fatal = err;
201
- break;
202
- }
203
- if (this.taskCount > 0) this.taskCount--;
204
- }
205
- } finally {
206
- this.running = false;
207
- this.depth = 0;
208
- this.executionDepth = 0;
209
- if (this.head >= this.q.length) {
210
- this.q.length = 0;
211
- this.head = 0;
212
- } else if (this.head > 0) {
213
- const remaining = this.q.length - this.head;
214
- if (this.head > 1024 || this.head > remaining) {
215
- this.q = this.q.slice(this.head);
216
- } else {
217
- for (let i = 0; i < remaining; i++) {
218
- this.q[i] = this.q[this.head + i];
219
- }
220
- this.q.length = remaining;
221
- }
222
- this.head = 0;
223
- }
224
- this.flushVersion++;
225
- this.resolveWaiters();
226
- }
227
- if (fatal) throw fatal;
228
169
  }
229
- runWithSyncProgress(fn) {
230
- const prev = this.allowSyncProgress;
231
- this.allowSyncProgress = true;
232
- const g = globalThis;
233
- const origQueueMicrotask = g.queueMicrotask;
234
- const origSetTimeout = g.setTimeout;
235
- if (process.env.NODE_ENV !== "production") {
236
- g.queueMicrotask = () => {
237
- throw new Error(
238
- "[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
239
- );
240
- };
241
- g.setTimeout = () => {
242
- throw new Error(
243
- "[Scheduler] setTimeout not allowed during runWithSyncProgress"
244
- );
245
- };
170
+ }
171
+ this.running = true;
172
+ this.depth = 0;
173
+ let fatal = null;
174
+ try {
175
+ while (this.head < this.q.length) {
176
+ this.depth++;
177
+ if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
178
+ throw new Error(
179
+ `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
180
+ );
246
181
  }
247
- const startVersion = this.flushVersion;
182
+ const task = this.q[this.head++];
248
183
  try {
249
- const res = fn();
250
- if (!this.running && this.q.length - this.head > 0) {
251
- this.flush();
252
- }
253
- if (process.env.NODE_ENV !== "production") {
254
- if (this.q.length - this.head > 0) {
255
- throw new Error(
256
- "[Scheduler] tasks remain after runWithSyncProgress flush"
257
- );
258
- }
259
- }
260
- return res;
261
- } finally {
262
- if (process.env.NODE_ENV !== "production") {
263
- g.queueMicrotask = origQueueMicrotask;
264
- g.setTimeout = origSetTimeout;
265
- }
266
- try {
267
- if (this.flushVersion === startVersion) {
268
- this.flushVersion++;
269
- this.resolveWaiters();
270
- }
271
- } catch (e) {
272
- void e;
273
- }
274
- this.allowSyncProgress = prev;
184
+ this.executionDepth++;
185
+ task();
186
+ this.executionDepth--;
187
+ } catch (err) {
188
+ if (this.executionDepth > 0) this.executionDepth = 0;
189
+ fatal = err;
190
+ break;
275
191
  }
192
+ if (this.taskCount > 0) this.taskCount--;
276
193
  }
277
- waitForFlush(targetVersion, timeoutMs = 2e3) {
278
- const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
279
- if (this.flushVersion >= target) return Promise.resolve();
280
- return new Promise((resolve, reject) => {
281
- const timer = setTimeout(() => {
282
- const ns = globalThis.__ASKR__ || {};
283
- const diag = {
284
- flushVersion: this.flushVersion,
285
- queueLen: this.q.length - this.head,
286
- running: this.running,
287
- inHandler: this.inHandler,
288
- bulk: isBulkCommitActive(),
289
- namespace: ns
290
- };
291
- reject(
292
- new Error(
293
- `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
294
- )
295
- );
296
- }, timeoutMs);
297
- this.waiters.push({ target, resolve, reject, timer });
298
- });
299
- }
300
- getState() {
301
- return {
302
- queueLength: this.q.length - this.head,
303
- running: this.running,
304
- depth: this.depth,
305
- executionDepth: this.executionDepth,
306
- taskCount: this.taskCount,
307
- flushVersion: this.flushVersion,
308
- // New fields for optional inspection
309
- inHandler: this.inHandler,
310
- allowSyncProgress: this.allowSyncProgress
311
- };
194
+ } finally {
195
+ this.running = false;
196
+ this.depth = 0;
197
+ this.executionDepth = 0;
198
+ if (this.head >= this.q.length) {
199
+ this.q.length = 0;
200
+ this.head = 0;
201
+ } else if (this.head > 0) {
202
+ const remaining = this.q.length - this.head;
203
+ for (let i = 0; i < remaining; i++) {
204
+ this.q[i] = this.q[this.head + i];
205
+ }
206
+ this.q.length = remaining;
207
+ this.head = 0;
312
208
  }
313
- setInHandler(v) {
314
- this.inHandler = v;
209
+ this.flushVersion++;
210
+ this.resolveWaiters();
211
+ }
212
+ if (fatal) throw fatal;
213
+ }
214
+ runWithSyncProgress(fn) {
215
+ const prev = this.allowSyncProgress;
216
+ this.allowSyncProgress = true;
217
+ const g = globalThis;
218
+ const origQueueMicrotask = g.queueMicrotask;
219
+ const origSetTimeout = g.setTimeout;
220
+ if (process.env.NODE_ENV !== "production") {
221
+ g.queueMicrotask = () => {
222
+ throw new Error(
223
+ "[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
224
+ );
225
+ };
226
+ g.setTimeout = () => {
227
+ throw new Error(
228
+ "[Scheduler] setTimeout not allowed during runWithSyncProgress"
229
+ );
230
+ };
231
+ }
232
+ const startVersion = this.flushVersion;
233
+ try {
234
+ const res = fn();
235
+ if (!this.running && this.q.length - this.head > 0) {
236
+ this.flush();
315
237
  }
316
- isInHandler() {
317
- return this.inHandler;
238
+ if (process.env.NODE_ENV !== "production") {
239
+ if (this.q.length - this.head > 0) {
240
+ throw new Error(
241
+ "[Scheduler] tasks remain after runWithSyncProgress flush"
242
+ );
243
+ }
318
244
  }
319
- isExecuting() {
320
- return this.running || this.executionDepth > 0;
245
+ return res;
246
+ } finally {
247
+ if (process.env.NODE_ENV !== "production") {
248
+ g.queueMicrotask = origQueueMicrotask;
249
+ g.setTimeout = origSetTimeout;
321
250
  }
322
- // Clear pending synchronous tasks (used by fastlane enter/exit)
323
- clearPendingSyncTasks() {
324
- const remaining = this.q.length - this.head;
325
- if (remaining <= 0) return 0;
326
- if (this.running) {
327
- this.q.length = this.head;
328
- this.taskCount = Math.max(0, this.taskCount - remaining);
329
- queueMicrotask(() => {
330
- try {
331
- this.flushVersion++;
332
- this.resolveWaiters();
333
- } catch (e) {
334
- void e;
335
- }
336
- });
337
- return remaining;
251
+ try {
252
+ if (this.flushVersion === startVersion) {
253
+ this.flushVersion++;
254
+ this.resolveWaiters();
338
255
  }
339
- this.q.length = 0;
340
- this.head = 0;
341
- this.taskCount = Math.max(0, this.taskCount - remaining);
342
- this.flushVersion++;
343
- this.resolveWaiters();
344
- return remaining;
256
+ } catch (e) {
345
257
  }
346
- resolveWaiters() {
347
- if (this.waiters.length === 0) return;
348
- const ready = [];
349
- const remaining = [];
350
- for (const w of this.waiters) {
351
- if (this.flushVersion >= w.target) {
352
- if (w.timer) clearTimeout(w.timer);
353
- ready.push(w.resolve);
354
- } else {
355
- remaining.push(w);
356
- }
258
+ this.allowSyncProgress = prev;
259
+ }
260
+ }
261
+ waitForFlush(targetVersion, timeoutMs = 2e3) {
262
+ const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
263
+ if (this.flushVersion >= target) return Promise.resolve();
264
+ return new Promise((resolve, reject) => {
265
+ const timer = setTimeout(() => {
266
+ const ns = globalThis.__ASKR__ || {};
267
+ const diag = {
268
+ flushVersion: this.flushVersion,
269
+ queueLen: this.q.length - this.head,
270
+ running: this.running,
271
+ inHandler: this.inHandler,
272
+ bulk: isBulkCommitActive(),
273
+ namespace: ns
274
+ };
275
+ reject(
276
+ new Error(
277
+ `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
278
+ )
279
+ );
280
+ }, timeoutMs);
281
+ this.waiters.push({ target, resolve, reject, timer });
282
+ });
283
+ }
284
+ getState() {
285
+ return {
286
+ queueLength: this.q.length - this.head,
287
+ running: this.running,
288
+ depth: this.depth,
289
+ executionDepth: this.executionDepth,
290
+ taskCount: this.taskCount,
291
+ flushVersion: this.flushVersion,
292
+ // New fields for optional inspection
293
+ inHandler: this.inHandler,
294
+ allowSyncProgress: this.allowSyncProgress
295
+ };
296
+ }
297
+ setInHandler(v) {
298
+ this.inHandler = v;
299
+ }
300
+ isInHandler() {
301
+ return this.inHandler;
302
+ }
303
+ isExecuting() {
304
+ return this.running || this.executionDepth > 0;
305
+ }
306
+ // Clear pending synchronous tasks (used by fastlane enter/exit)
307
+ clearPendingSyncTasks() {
308
+ const remaining = this.q.length - this.head;
309
+ if (remaining <= 0) return 0;
310
+ if (this.running) {
311
+ this.q.length = this.head;
312
+ this.taskCount = Math.max(0, this.taskCount - remaining);
313
+ queueMicrotask(() => {
314
+ try {
315
+ this.flushVersion++;
316
+ this.resolveWaiters();
317
+ } catch (e) {
357
318
  }
358
- this.waiters = remaining;
359
- for (const r of ready) r();
319
+ });
320
+ return remaining;
321
+ }
322
+ this.q.length = 0;
323
+ this.head = 0;
324
+ this.taskCount = Math.max(0, this.taskCount - remaining);
325
+ this.flushVersion++;
326
+ this.resolveWaiters();
327
+ return remaining;
328
+ }
329
+ resolveWaiters() {
330
+ if (this.waiters.length === 0) return;
331
+ const ready = [];
332
+ const remaining = [];
333
+ for (const w of this.waiters) {
334
+ if (this.flushVersion >= w.target) {
335
+ if (w.timer) clearTimeout(w.timer);
336
+ ready.push(w.resolve);
337
+ } else {
338
+ remaining.push(w);
360
339
  }
361
- };
362
- globalScheduler = new Scheduler();
340
+ }
341
+ this.waiters = remaining;
342
+ for (const r of ready) r();
363
343
  }
364
- });
344
+ };
345
+ var globalScheduler = new Scheduler();
346
+ function isSchedulerExecuting() {
347
+ return globalScheduler.isExecuting();
348
+ }
365
349
 
366
350
  // src/runtime/context.ts
351
+ var CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
352
+ var currentContextFrame = null;
367
353
  function withContext(frame, fn) {
368
354
  const oldFrame = currentContextFrame;
369
355
  currentContextFrame = frame;
@@ -373,125 +359,9 @@ function withContext(frame, fn) {
373
359
  currentContextFrame = oldFrame;
374
360
  }
375
361
  }
376
- function withAsyncResourceContext(frame, fn) {
377
- const oldFrame = currentAsyncResourceFrame;
378
- currentAsyncResourceFrame = frame;
379
- try {
380
- return fn();
381
- } finally {
382
- currentAsyncResourceFrame = oldFrame;
383
- }
384
- }
385
- function defineContext(defaultValue) {
386
- const key = /* @__PURE__ */ Symbol("AskrContext");
387
- return {
388
- key,
389
- defaultValue,
390
- Scope: (props) => {
391
- const value = props.value;
392
- return {
393
- type: ContextScopeComponent,
394
- props: { key, value, children: props.children }
395
- };
396
- }
397
- };
398
- }
399
- function readContext(context) {
400
- const frame = currentContextFrame || currentAsyncResourceFrame;
401
- if (!frame) {
402
- throw new Error(
403
- "readContext() can only be called during component render or async resource execution. Ensure you are calling this from inside your component or resource function."
404
- );
405
- }
406
- let current2 = frame;
407
- while (current2) {
408
- const values = current2.values;
409
- if (values && values.has(context.key)) {
410
- return values.get(context.key);
411
- }
412
- current2 = current2.parent;
413
- }
414
- return context.defaultValue;
415
- }
416
- function ContextScopeComponent(props) {
417
- const key = props["key"];
418
- const value = props["value"];
419
- const children = props["children"];
420
- const instance = getCurrentComponentInstance();
421
- const parentFrame = (() => {
422
- if (currentContextFrame) return currentContextFrame;
423
- if (instance && instance.ownerFrame) return instance.ownerFrame;
424
- return null;
425
- })();
426
- const newFrame = {
427
- parent: parentFrame,
428
- values: /* @__PURE__ */ new Map([[key, value]])
429
- };
430
- function createFunctionChildInvoker(fn, frame, owner) {
431
- return {
432
- type: ContextFunctionChildInvoker,
433
- props: { fn, __frame: frame, __owner: owner }
434
- };
435
- }
436
- if (Array.isArray(children)) {
437
- return children.map((child) => {
438
- if (typeof child === "function") {
439
- return createFunctionChildInvoker(
440
- child,
441
- newFrame,
442
- getCurrentComponentInstance()
443
- );
444
- }
445
- return markWithFrame(child, newFrame);
446
- });
447
- } else if (typeof children === "function") {
448
- return createFunctionChildInvoker(
449
- children,
450
- newFrame,
451
- getCurrentComponentInstance()
452
- );
453
- } else if (children) {
454
- return markWithFrame(children, newFrame);
455
- }
456
- return null;
457
- }
458
- function markWithFrame(node, frame) {
459
- if (typeof node === "object" && node !== null) {
460
- const obj = node;
461
- obj[CONTEXT_FRAME_SYMBOL] = frame;
462
- const children = obj.children;
463
- if (Array.isArray(children)) {
464
- for (let i = 0; i < children.length; i++) {
465
- const child = children[i];
466
- if (child) {
467
- children[i] = markWithFrame(child, frame);
468
- }
469
- }
470
- } else if (children) {
471
- obj.children = markWithFrame(children, frame);
472
- }
473
- }
474
- return node;
475
- }
476
- function ContextFunctionChildInvoker(props) {
477
- const { fn, __frame } = props;
478
- const res = withContext(__frame, () => fn());
479
- if (res) return markWithFrame(res, __frame);
480
- return null;
481
- }
482
362
  function getCurrentContextFrame() {
483
363
  return currentContextFrame;
484
364
  }
485
- var CONTEXT_FRAME_SYMBOL, currentContextFrame, currentAsyncResourceFrame;
486
- var init_context = __esm({
487
- "src/runtime/context.ts"() {
488
- "use strict";
489
- init_component();
490
- CONTEXT_FRAME_SYMBOL = /* @__PURE__ */ Symbol("__tempoContextFrame__");
491
- currentContextFrame = null;
492
- currentAsyncResourceFrame = null;
493
- }
494
- });
495
365
 
496
366
  // src/renderer/diag/index.ts
497
367
  function getDiagMap() {
@@ -500,7 +370,6 @@ function getDiagMap() {
500
370
  if (!root.__ASKR_DIAG) root.__ASKR_DIAG = {};
501
371
  return root.__ASKR_DIAG;
502
372
  } catch (e) {
503
- void e;
504
373
  return {};
505
374
  }
506
375
  }
@@ -524,7 +393,6 @@ function __ASKR_set(key, value) {
524
393
  void e;
525
394
  }
526
395
  } catch (e) {
527
- void e;
528
396
  }
529
397
  }
530
398
  function __ASKR_incCounter(key) {
@@ -546,180 +414,8 @@ function __ASKR_incCounter(key) {
546
414
  void e;
547
415
  }
548
416
  } catch (e) {
549
- void e;
550
417
  }
551
418
  }
552
- var init_diag = __esm({
553
- "src/renderer/diag/index.ts"() {
554
- "use strict";
555
- }
556
- });
557
-
558
- // src/runtime/dev-namespace.ts
559
- function getDevNamespace() {
560
- if (process.env.NODE_ENV === "production") return {};
561
- try {
562
- const g = globalThis;
563
- if (!g.__ASKR__) g.__ASKR__ = {};
564
- return g.__ASKR__;
565
- } catch {
566
- return {};
567
- }
568
- }
569
- function setDevValue(key, value) {
570
- if (process.env.NODE_ENV === "production") return;
571
- try {
572
- getDevNamespace()[key] = value;
573
- } catch {
574
- }
575
- }
576
- function getDevValue(key) {
577
- if (process.env.NODE_ENV === "production") return void 0;
578
- try {
579
- return getDevNamespace()[key];
580
- } catch {
581
- return void 0;
582
- }
583
- }
584
- var init_dev_namespace = __esm({
585
- "src/runtime/dev-namespace.ts"() {
586
- "use strict";
587
- }
588
- });
589
-
590
- // src/runtime/fastlane-shared.ts
591
- function enterBulkCommit() {
592
- _bulkCommitActive = true;
593
- _appliedParents = /* @__PURE__ */ new WeakSet();
594
- try {
595
- const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
596
- setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", cleared);
597
- } catch (err) {
598
- if (process.env.NODE_ENV !== "production") throw err;
599
- }
600
- }
601
- function exitBulkCommit() {
602
- _bulkCommitActive = false;
603
- _appliedParents = null;
604
- }
605
- function isBulkCommitActive2() {
606
- return _bulkCommitActive;
607
- }
608
- function markFastPathApplied(parent) {
609
- if (!_appliedParents) return;
610
- try {
611
- _appliedParents.add(parent);
612
- } catch (e) {
613
- void e;
614
- }
615
- }
616
- function isFastPathApplied(parent) {
617
- return !!(_appliedParents && _appliedParents.has(parent));
618
- }
619
- var _bulkCommitActive, _appliedParents;
620
- var init_fastlane_shared = __esm({
621
- "src/runtime/fastlane-shared.ts"() {
622
- "use strict";
623
- init_scheduler();
624
- init_dev_namespace();
625
- _bulkCommitActive = false;
626
- _appliedParents = null;
627
- }
628
- });
629
-
630
- // src/renderer/types.ts
631
- function _isDOMElement(node) {
632
- return typeof node === "object" && node !== null && "type" in node;
633
- }
634
- var init_types = __esm({
635
- "src/renderer/types.ts"() {
636
- "use strict";
637
- }
638
- });
639
-
640
- // src/renderer/cleanup.ts
641
- function cleanupSingleInstance(node, errors, strict) {
642
- const inst = node.__ASKR_INSTANCE;
643
- if (!inst) return;
644
- try {
645
- cleanupComponent(inst);
646
- } catch (err) {
647
- if (strict) errors.push(err);
648
- else logger.warn("[Askr] cleanupComponent failed:", err);
649
- }
650
- try {
651
- delete node.__ASKR_INSTANCE;
652
- } catch (e) {
653
- if (strict) errors.push(e);
654
- }
655
- }
656
- function cleanupInstanceIfPresent(node, opts) {
657
- if (!node || !(node instanceof Element)) return;
658
- const errors = [];
659
- const strict = opts?.strict ?? false;
660
- try {
661
- cleanupSingleInstance(node, errors, strict);
662
- } catch (err) {
663
- if (strict) errors.push(err);
664
- else logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
665
- }
666
- try {
667
- const descendants = node.querySelectorAll("*");
668
- for (const d of Array.from(descendants)) {
669
- try {
670
- cleanupSingleInstance(d, errors, strict);
671
- } catch (err) {
672
- if (strict) errors.push(err);
673
- else
674
- logger.warn(
675
- "[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
676
- err
677
- );
678
- }
679
- }
680
- } catch (err) {
681
- if (strict) errors.push(err);
682
- else
683
- logger.warn(
684
- "[Askr] cleanupInstanceIfPresent descendant query failed:",
685
- err
686
- );
687
- }
688
- if (errors.length > 0) {
689
- throw new AggregateError(errors, "cleanupInstanceIfPresent failed");
690
- }
691
- }
692
- function cleanupInstancesUnder(node, opts) {
693
- cleanupInstanceIfPresent(node, opts);
694
- }
695
- function removeElementListeners(element) {
696
- const map = elementListeners.get(element);
697
- if (map) {
698
- for (const [eventName, entry] of map) {
699
- if (entry.options !== void 0)
700
- element.removeEventListener(eventName, entry.handler, entry.options);
701
- else element.removeEventListener(eventName, entry.handler);
702
- }
703
- elementListeners.delete(element);
704
- }
705
- }
706
- function removeAllListeners(root) {
707
- if (!root) return;
708
- removeElementListeners(root);
709
- const children = root.querySelectorAll("*");
710
- for (let i = 0; i < children.length; i++) {
711
- removeElementListeners(children[i]);
712
- }
713
- }
714
- var elementListeners;
715
- var init_cleanup = __esm({
716
- "src/renderer/cleanup.ts"() {
717
- "use strict";
718
- init_component();
719
- init_logger();
720
- elementListeners = /* @__PURE__ */ new WeakMap();
721
- }
722
- });
723
419
 
724
420
  // src/renderer/utils.ts
725
421
  function parseEventName(propName) {
@@ -742,8 +438,8 @@ function createWrappedHandler(handler, flushAfter = false) {
742
438
  } finally {
743
439
  globalScheduler.setInHandler(false);
744
440
  if (flushAfter) {
745
- const state2 = globalScheduler.getState();
746
- if ((state2.queueLength ?? 0) > 0 && !state2.running) {
441
+ const state = globalScheduler.getState();
442
+ if ((state.queueLength ?? 0) > 0 && !state.running) {
747
443
  queueMicrotask(() => {
748
444
  try {
749
445
  if (!globalScheduler.isExecuting()) globalScheduler.flush();
@@ -809,8 +505,7 @@ function extractKey(vnode) {
809
505
  }
810
506
  function buildKeyMapFromChildren(parent) {
811
507
  const map = /* @__PURE__ */ new Map();
812
- const children = Array.from(parent.children);
813
- for (const ch of children) {
508
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
814
509
  const k = ch.getAttribute("data-key");
815
510
  if (k !== null) {
816
511
  map.set(k, ch);
@@ -851,16 +546,9 @@ function logFastPathDebug(message, indexOrData, data) {
851
546
  function now() {
852
547
  return typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
853
548
  }
854
- var init_utils = __esm({
855
- "src/renderer/utils.ts"() {
856
- "use strict";
857
- init_scheduler();
858
- init_logger();
859
- init_diag();
860
- }
861
- });
862
549
 
863
550
  // src/renderer/keyed.ts
551
+ var keyedElements = /* @__PURE__ */ new WeakMap();
864
552
  function getKeyMapForElement(el) {
865
553
  return keyedElements.get(el);
866
554
  }
@@ -884,6 +572,7 @@ function populateKeyMapForElement(parent) {
884
572
  } catch {
885
573
  }
886
574
  }
575
+ var _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
887
576
  function extractKeyedVnodes(newChildren) {
888
577
  const result = [];
889
578
  for (const child of newChildren) {
@@ -975,398 +664,739 @@ function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
975
664
  hasPropChanges
976
665
  };
977
666
  }
978
- var keyedElements, _reconcilerRecordedParents;
979
- var init_keyed = __esm({
980
- "src/renderer/keyed.ts"() {
981
- "use strict";
982
- init_utils();
983
- keyedElements = /* @__PURE__ */ new WeakMap();
984
- _reconcilerRecordedParents = /* @__PURE__ */ new WeakSet();
985
- }
986
- });
987
667
 
988
- // src/jsx/types.ts
989
- var ELEMENT_TYPE, Fragment;
990
- var init_types2 = __esm({
991
- "src/jsx/types.ts"() {
992
- "use strict";
993
- ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
994
- Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
995
- }
996
- });
668
+ // src/common/jsx.ts
669
+ var ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
670
+ var Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
997
671
 
998
- // src/jsx/jsx-runtime.ts
999
- function jsxDEV(type, props, key) {
1000
- return {
1001
- $$typeof: ELEMENT_TYPE2,
1002
- type,
1003
- props: props ?? {},
1004
- key: key ?? null
1005
- };
1006
- }
1007
- function jsx(type, props, key) {
1008
- return jsxDEV(type, props, key);
672
+ // src/runtime/dev-namespace.ts
673
+ function getDevNamespace() {
674
+ if (process.env.NODE_ENV === "production") return {};
675
+ try {
676
+ const g = globalThis;
677
+ if (!g.__ASKR__) g.__ASKR__ = {};
678
+ return g.__ASKR__;
679
+ } catch {
680
+ return {};
681
+ }
1009
682
  }
1010
- function jsxs(type, props, key) {
1011
- return jsxDEV(type, props, key);
683
+ function setDevValue(key, value) {
684
+ if (process.env.NODE_ENV === "production") return;
685
+ try {
686
+ getDevNamespace()[key] = value;
687
+ } catch {
688
+ }
1012
689
  }
1013
- var ELEMENT_TYPE2, Fragment2;
1014
- var init_jsx_runtime = __esm({
1015
- "src/jsx/jsx-runtime.ts"() {
1016
- "use strict";
1017
- init_types2();
1018
- ELEMENT_TYPE2 = /* @__PURE__ */ Symbol.for("askr.element");
1019
- Fragment2 = /* @__PURE__ */ Symbol.for("askr.fragment");
690
+ function getDevValue(key) {
691
+ if (process.env.NODE_ENV === "production") return void 0;
692
+ try {
693
+ return getDevNamespace()[key];
694
+ } catch {
695
+ return void 0;
1020
696
  }
1021
- });
697
+ }
1022
698
 
1023
- // src/renderer/dom.ts
1024
- function addTrackedListener(el, eventName, handler) {
1025
- const wrappedHandler = createWrappedHandler(handler, true);
1026
- const options = getPassiveOptions(eventName);
1027
- if (options !== void 0) {
1028
- el.addEventListener(eventName, wrappedHandler, options);
1029
- } else {
1030
- el.addEventListener(eventName, wrappedHandler);
699
+ // src/runtime/fastlane.ts
700
+ var _bulkCommitActive = false;
701
+ var _appliedParents = null;
702
+ function enterBulkCommit() {
703
+ _bulkCommitActive = true;
704
+ _appliedParents = /* @__PURE__ */ new WeakSet();
705
+ try {
706
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
707
+ setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", cleared);
708
+ } catch (err) {
709
+ if (process.env.NODE_ENV !== "production") throw err;
1031
710
  }
1032
- if (!elementListeners.has(el)) {
1033
- elementListeners.set(el, /* @__PURE__ */ new Map());
711
+ }
712
+ function exitBulkCommit() {
713
+ _bulkCommitActive = false;
714
+ _appliedParents = null;
715
+ }
716
+ function isBulkCommitActive2() {
717
+ return _bulkCommitActive;
718
+ }
719
+ function markFastPathApplied(parent) {
720
+ if (!_appliedParents) return;
721
+ try {
722
+ _appliedParents.add(parent);
723
+ } catch (e) {
1034
724
  }
1035
- elementListeners.get(el).set(eventName, {
1036
- handler: wrappedHandler,
1037
- original: handler,
1038
- options
1039
- });
1040
725
  }
1041
- function applyPropsToElement(el, props, tagName) {
1042
- for (const key in props) {
1043
- const value = props[key];
1044
- if (isSkippedProp(key)) continue;
1045
- if (value === void 0 || value === null || value === false) continue;
1046
- const eventName = parseEventName(key);
1047
- if (eventName) {
1048
- addTrackedListener(el, eventName, value);
1049
- continue;
726
+ function isFastPathApplied(parent) {
727
+ return !!(_appliedParents && _appliedParents.has(parent));
728
+ }
729
+ function finalizeReadSubscriptions(instance) {
730
+ const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
731
+ const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
732
+ const token = instance._currentRenderToken;
733
+ if (token === void 0) return;
734
+ for (const s of oldSet) {
735
+ if (!newSet.has(s)) {
736
+ const readers = s._readers;
737
+ if (readers) readers.delete(instance);
1050
738
  }
1051
- if (key === "class" || key === "className") {
1052
- el.className = String(value);
1053
- } else if (key === "value" || key === "checked") {
1054
- applyFormControlProp(el, key, value, tagName);
1055
- } else {
1056
- el.setAttribute(key, String(value));
739
+ }
740
+ instance.lastRenderToken = token;
741
+ for (const s of newSet) {
742
+ let readers = s._readers;
743
+ if (!readers) {
744
+ readers = /* @__PURE__ */ new Map();
745
+ s._readers = readers;
1057
746
  }
747
+ readers.set(instance, instance.lastRenderToken ?? 0);
1058
748
  }
749
+ instance._lastReadStates = newSet;
750
+ instance._pendingReadStates = /* @__PURE__ */ new Set();
751
+ instance._currentRenderToken = void 0;
1059
752
  }
1060
- function applyFormControlProp(el, key, value, tagName) {
1061
- const tag = tagName.toLowerCase();
1062
- if (key === "value") {
1063
- if (tag === "input" || tag === "textarea" || tag === "select") {
1064
- el.value = String(value);
1065
- el.setAttribute("value", String(value));
1066
- } else {
1067
- el.setAttribute("value", String(value));
1068
- }
1069
- } else if (key === "checked") {
1070
- if (tag === "input") {
1071
- el.checked = Boolean(value);
1072
- el.setAttribute("checked", String(Boolean(value)));
1073
- } else {
1074
- el.setAttribute("checked", String(Boolean(value)));
753
+ function unwrapFragmentForFastPath(vnode) {
754
+ if (!vnode || typeof vnode !== "object" || !("type" in vnode)) return vnode;
755
+ const v = vnode;
756
+ if (typeof v.type === "symbol" && (v.type === Fragment || String(v.type) === "Symbol(askr.fragment)")) {
757
+ const children = v.children || v.props?.children;
758
+ if (Array.isArray(children) && children.length > 0) {
759
+ for (const child of children) {
760
+ if (child && typeof child === "object" && "type" in child) {
761
+ const c = child;
762
+ if (typeof c.type === "string") {
763
+ return child;
764
+ }
765
+ }
766
+ }
1075
767
  }
1076
768
  }
769
+ return vnode;
1077
770
  }
1078
- function materializeKey(el, vnode, props) {
1079
- const vnodeKey = vnode.key ?? props?.key;
1080
- if (vnodeKey !== void 0) {
1081
- el.setAttribute("data-key", String(vnodeKey));
1082
- }
1083
- }
1084
- function warnMissingKeys(children) {
1085
- if (process.env.NODE_ENV === "production") return;
1086
- let hasElements = false;
1087
- let hasKeys = false;
1088
- for (const item of children) {
1089
- if (typeof item === "object" && item !== null && "type" in item) {
1090
- hasElements = true;
1091
- const rawKey = item.key ?? item.props?.key;
1092
- if (rawKey !== void 0) {
1093
- hasKeys = true;
1094
- break;
1095
- }
771
+ function classifyUpdate(instance, result) {
772
+ const unwrappedResult = unwrapFragmentForFastPath(result);
773
+ if (!unwrappedResult || typeof unwrappedResult !== "object" || !("type" in unwrappedResult))
774
+ return { useFastPath: false, reason: "not-vnode" };
775
+ const vnode = unwrappedResult;
776
+ if (vnode == null || typeof vnode.type !== "string")
777
+ return { useFastPath: false, reason: "not-intrinsic" };
778
+ const parent = instance.target;
779
+ if (!parent) return { useFastPath: false, reason: "no-root" };
780
+ const firstChild = parent.children[0];
781
+ if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
782
+ if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
783
+ return { useFastPath: false, reason: "root-tag-mismatch" };
784
+ const children = vnode.children || vnode.props?.children;
785
+ if (!Array.isArray(children))
786
+ return { useFastPath: false, reason: "no-children-array" };
787
+ for (const c of children) {
788
+ if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
789
+ return { useFastPath: false, reason: "component-child-present" };
1096
790
  }
1097
791
  }
1098
- if (hasElements && !hasKeys) {
1099
- try {
1100
- const inst = getCurrentInstance();
1101
- const name = inst?.fn?.name || "<anonymous>";
1102
- logger.warn(
1103
- `Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`
1104
- );
1105
- } catch {
1106
- logger.warn(
1107
- 'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
1108
- );
1109
- }
792
+ if (instance.mountOperations.length > 0)
793
+ return { useFastPath: false, reason: "pending-mounts" };
794
+ try {
795
+ populateKeyMapForElement(firstChild);
796
+ } catch {
1110
797
  }
798
+ const oldKeyMap = getKeyMapForElement(firstChild);
799
+ const decision = isKeyedReorderFastPathEligible(
800
+ firstChild,
801
+ children,
802
+ oldKeyMap
803
+ );
804
+ if (!decision.useFastPath || decision.totalKeyed < 128)
805
+ return { ...decision, useFastPath: false, reason: "renderer-declined" };
806
+ return { ...decision, useFastPath: true };
1111
807
  }
1112
- function createDOMNode(node) {
1113
- if (!IS_DOM_AVAILABLE) {
1114
- if (process.env.NODE_ENV !== "production") {
808
+ function commitReorderOnly(instance, result) {
809
+ const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
810
+ if (typeof evaluate2 !== "function") {
811
+ logger.warn(
812
+ "[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
813
+ );
814
+ return false;
815
+ }
816
+ const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
817
+ enterBulkCommit();
818
+ try {
819
+ globalScheduler.runWithSyncProgress(() => {
820
+ evaluate2(result, instance.target);
1115
821
  try {
1116
- logger.warn("[Askr] createDOMNode called in non-DOM environment");
1117
- } catch {
822
+ finalizeReadSubscriptions(instance);
823
+ } catch (e) {
824
+ if (process.env.NODE_ENV !== "production") throw e;
1118
825
  }
826
+ });
827
+ const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
828
+ setDevValue("__FASTLANE_CLEARED_AFTER", clearedAfter);
829
+ if (process.env.NODE_ENV !== "production") {
830
+ validateFastLaneInvariants(instance, schedBefore);
1119
831
  }
1120
- return null;
1121
- }
1122
- if (typeof node === "string") {
1123
- return document.createTextNode(node);
1124
- }
1125
- if (typeof node === "number") {
1126
- return document.createTextNode(String(node));
1127
- }
1128
- if (!node) {
1129
- return null;
1130
- }
1131
- if (Array.isArray(node)) {
1132
- const fragment = document.createDocumentFragment();
1133
- for (const child of node) {
1134
- const dom = createDOMNode(child);
1135
- if (dom) fragment.appendChild(dom);
1136
- }
1137
- return fragment;
832
+ return true;
833
+ } finally {
834
+ exitBulkCommit();
1138
835
  }
1139
- if (typeof node === "object" && node !== null && "type" in node) {
1140
- const type = node.type;
1141
- const props = node.props || {};
1142
- if (typeof type === "string") {
1143
- return createIntrinsicElement(node, type, props);
1144
- }
1145
- if (typeof type === "function") {
1146
- return createComponentElement(node, type, props);
1147
- }
1148
- if (typeof type === "symbol" && (type === Fragment2 || String(type) === "Symbol(Fragment)")) {
1149
- return createFragmentElement(node, props);
836
+ if (process.env.NODE_ENV !== "production") {
837
+ if (isBulkCommitActive2()) {
838
+ throw new Error(
839
+ "Fast-lane invariant violated: bulk commit flag still set after commit"
840
+ );
1150
841
  }
1151
842
  }
1152
- return null;
1153
843
  }
1154
- function createIntrinsicElement(node, type, props) {
1155
- const el = document.createElement(type);
1156
- materializeKey(el, node, props);
1157
- applyPropsToElement(el, props, type);
1158
- const children = props.children || node.children;
1159
- if (children) {
1160
- if (Array.isArray(children)) {
1161
- warnMissingKeys(children);
1162
- for (const child of children) {
1163
- const dom = createDOMNode(child);
1164
- if (dom) el.appendChild(dom);
1165
- }
1166
- } else {
1167
- const dom = createDOMNode(children);
1168
- if (dom) el.appendChild(dom);
1169
- }
844
+ function validateFastLaneInvariants(instance, schedBefore) {
845
+ const commitCount = getDevValue("__LAST_FASTPATH_COMMIT_COUNT") ?? 0;
846
+ const invariants = {
847
+ commitCount,
848
+ mountOps: instance.mountOperations.length,
849
+ cleanupFns: instance.cleanupFns.length
850
+ };
851
+ setDevValue("__LAST_FASTLANE_INVARIANTS", invariants);
852
+ if (commitCount !== 1) {
853
+ console.error(
854
+ "[FASTLANE][INV] commitCount",
855
+ commitCount,
856
+ "diag",
857
+ globalThis.__ASKR_DIAG
858
+ );
859
+ throw new Error(
860
+ "Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
861
+ );
1170
862
  }
1171
- return el;
1172
- }
1173
- function createComponentElement(node, type, props) {
1174
- const frame = node[CONTEXT_FRAME_SYMBOL];
1175
- const snapshot = frame || getCurrentContextFrame();
1176
- const componentFn = type;
1177
- const isAsync = componentFn.constructor.name === "AsyncFunction";
1178
- if (isAsync) {
863
+ if (invariants.mountOps > 0) {
1179
864
  throw new Error(
1180
- "Async components are not supported. Use resource() for async work."
865
+ "Fast-lane invariant violated: mount operations were registered during bulk commit"
1181
866
  );
1182
867
  }
1183
- let childInstance = node.__instance;
1184
- if (!childInstance) {
1185
- childInstance = createComponentInstance(
1186
- `comp-${Math.random().toString(36).slice(2, 7)}`,
1187
- componentFn,
1188
- props || {},
1189
- null
868
+ if (invariants.cleanupFns > 0) {
869
+ throw new Error(
870
+ "Fast-lane invariant violated: cleanup functions were added during bulk commit"
1190
871
  );
1191
- node.__instance = childInstance;
1192
872
  }
1193
- if (snapshot) {
1194
- childInstance.ownerFrame = snapshot;
873
+ const schedAfter = globalScheduler.getState();
874
+ if (schedBefore && schedAfter && schedAfter.taskCount > schedBefore.taskCount) {
875
+ console.error(
876
+ "[FASTLANE] schedBefore, schedAfter",
877
+ schedBefore,
878
+ schedAfter
879
+ );
880
+ console.error("[FASTLANE] enqueue logs", getDevValue("__ENQUEUE_LOGS"));
881
+ throw new Error(
882
+ "Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
883
+ );
1195
884
  }
1196
- const result = withContext(
1197
- snapshot,
1198
- () => renderComponentInline(childInstance)
885
+ let finalState = globalScheduler.getState();
886
+ const executing = globalScheduler.isExecuting();
887
+ let outstandingAfter = Math.max(
888
+ 0,
889
+ finalState.taskCount - (executing ? 1 : 0)
1199
890
  );
1200
- if (result instanceof Promise) {
1201
- throw new Error(
1202
- "Async components are not supported. Components must return synchronously."
891
+ if (outstandingAfter !== 0) {
892
+ let attempts = 0;
893
+ while (attempts < 5) {
894
+ const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
895
+ if (cleared === 0) break;
896
+ attempts++;
897
+ }
898
+ finalState = globalScheduler.getState();
899
+ outstandingAfter = Math.max(
900
+ 0,
901
+ finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
1203
902
  );
903
+ if (outstandingAfter !== 0) {
904
+ console.error(
905
+ "[FASTLANE] Post-commit enqueue logs:",
906
+ getDevValue("__ENQUEUE_LOGS")
907
+ );
908
+ console.error(
909
+ "[FASTLANE] Cleared counts:",
910
+ getDevValue("__FASTLANE_CLEARED_TASKS"),
911
+ getDevValue("__FASTLANE_CLEARED_AFTER")
912
+ );
913
+ throw new Error(
914
+ `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
915
+ );
916
+ }
1204
917
  }
1205
- const dom = withContext(snapshot, () => createDOMNode(result));
1206
- if (dom instanceof Element) {
1207
- mountInstanceInline(childInstance, dom);
1208
- return dom;
918
+ }
919
+ function tryRuntimeFastLaneSync(instance, result) {
920
+ const cls = classifyUpdate(instance, result);
921
+ if (!cls.useFastPath) {
922
+ setDevValue("__LAST_FASTPATH_STATS", void 0);
923
+ setDevValue("__LAST_FASTPATH_COMMIT_COUNT", 0);
924
+ return false;
1209
925
  }
1210
- if (!dom) {
1211
- const placeholder = document.createComment("");
1212
- childInstance._placeholder = placeholder;
1213
- childInstance.mounted = true;
1214
- childInstance.notifyUpdate = childInstance._enqueueRun;
1215
- return placeholder;
926
+ try {
927
+ return commitReorderOnly(instance, result);
928
+ } catch (err) {
929
+ if (process.env.NODE_ENV !== "production") throw err;
930
+ return false;
1216
931
  }
1217
- const host = document.createElement("div");
1218
- host.appendChild(dom);
1219
- mountInstanceInline(childInstance, host);
1220
- return host;
1221
932
  }
1222
- function createFragmentElement(node, props) {
1223
- const fragment = document.createDocumentFragment();
1224
- const children = props.children || node.children;
1225
- if (children) {
1226
- if (Array.isArray(children)) {
1227
- for (const child of children) {
1228
- const dom = createDOMNode(child);
1229
- if (dom) fragment.appendChild(dom);
933
+ if (typeof globalThis !== "undefined") {
934
+ globalThis.__ASKR_FASTLANE = {
935
+ isBulkCommitActive: isBulkCommitActive2,
936
+ enterBulkCommit,
937
+ exitBulkCommit,
938
+ tryRuntimeFastLaneSync,
939
+ markFastPathApplied,
940
+ isFastPathApplied
941
+ };
942
+ }
943
+
944
+ // src/common/vnode.ts
945
+ function _isDOMElement(node) {
946
+ return typeof node === "object" && node !== null && "type" in node;
947
+ }
948
+
949
+ // src/renderer/cleanup.ts
950
+ function cleanupSingleInstance(node, errors, strict) {
951
+ const inst = node.__ASKR_INSTANCE;
952
+ if (!inst) return;
953
+ try {
954
+ cleanupComponent(inst);
955
+ } catch (err) {
956
+ logger.warn("[Askr] cleanupComponent failed:", err);
957
+ }
958
+ try {
959
+ delete node.__ASKR_INSTANCE;
960
+ } catch (e) {
961
+ }
962
+ }
963
+ function forEachDescendantElement(root, visit) {
964
+ try {
965
+ const doc = root.ownerDocument;
966
+ const createTreeWalker = doc?.createTreeWalker;
967
+ if (typeof createTreeWalker === "function") {
968
+ const walker = createTreeWalker.call(doc, root, 1);
969
+ let n = walker.firstChild();
970
+ while (n) {
971
+ visit(n);
972
+ n = walker.nextNode();
1230
973
  }
1231
- } else {
1232
- const dom = createDOMNode(children);
1233
- if (dom) fragment.appendChild(dom);
974
+ return;
1234
975
  }
976
+ } catch {
977
+ }
978
+ const descendants = root.querySelectorAll("*");
979
+ for (let i = 0; i < descendants.length; i++) {
980
+ visit(descendants[i]);
1235
981
  }
1236
- return fragment;
1237
982
  }
1238
- function updateElementFromVnode(el, vnode, updateChildren = true) {
1239
- if (!_isDOMElement(vnode)) {
1240
- return;
983
+ function cleanupInstanceIfPresent(node, opts) {
984
+ if (!node || !(node instanceof Element)) return;
985
+ const strict = false;
986
+ const errors = null;
987
+ try {
988
+ cleanupSingleInstance(node, errors, strict);
989
+ } catch (err) {
990
+ logger.warn("[Askr] cleanupInstanceIfPresent failed:", err);
1241
991
  }
1242
- const props = vnode.props || {};
1243
- materializeKey(el, vnode, props);
1244
- const existingListeners = elementListeners.get(el);
1245
- const desiredEventNames = /* @__PURE__ */ new Set();
992
+ try {
993
+ forEachDescendantElement(node, (d) => {
994
+ try {
995
+ cleanupSingleInstance(d, errors, strict);
996
+ } catch (err) {
997
+ if (strict) ;
998
+ else
999
+ logger.warn(
1000
+ "[Askr] cleanupInstanceIfPresent descendant cleanup failed:",
1001
+ err
1002
+ );
1003
+ }
1004
+ });
1005
+ } catch (err) {
1006
+ logger.warn(
1007
+ "[Askr] cleanupInstanceIfPresent descendant query failed:",
1008
+ err
1009
+ );
1010
+ }
1011
+ }
1012
+ function cleanupInstancesUnder(node, opts) {
1013
+ cleanupInstanceIfPresent(node);
1014
+ }
1015
+ var elementListeners = /* @__PURE__ */ new WeakMap();
1016
+ function removeElementListeners(element) {
1017
+ const map = elementListeners.get(element);
1018
+ if (map) {
1019
+ for (const [eventName, entry] of map) {
1020
+ if (entry.options !== void 0)
1021
+ element.removeEventListener(eventName, entry.handler, entry.options);
1022
+ else element.removeEventListener(eventName, entry.handler);
1023
+ }
1024
+ elementListeners.delete(element);
1025
+ }
1026
+ }
1027
+ function removeAllListeners(root) {
1028
+ if (!root) return;
1029
+ removeElementListeners(root);
1030
+ forEachDescendantElement(root, removeElementListeners);
1031
+ }
1032
+
1033
+ // src/renderer/dom.ts
1034
+ var IS_DOM_AVAILABLE = typeof document !== "undefined";
1035
+ function addTrackedListener(el, eventName, handler) {
1036
+ const wrappedHandler = createWrappedHandler(handler, true);
1037
+ const options = getPassiveOptions(eventName);
1038
+ if (options !== void 0) {
1039
+ el.addEventListener(eventName, wrappedHandler, options);
1040
+ } else {
1041
+ el.addEventListener(eventName, wrappedHandler);
1042
+ }
1043
+ if (!elementListeners.has(el)) {
1044
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1045
+ }
1046
+ elementListeners.get(el).set(eventName, {
1047
+ handler: wrappedHandler,
1048
+ original: handler,
1049
+ options
1050
+ });
1051
+ }
1052
+ function applyPropsToElement(el, props, tagName) {
1246
1053
  for (const key in props) {
1247
1054
  const value = props[key];
1248
1055
  if (isSkippedProp(key)) continue;
1056
+ if (value === void 0 || value === null || value === false) continue;
1249
1057
  const eventName = parseEventName(key);
1250
- if (value === void 0 || value === null || value === false) {
1251
- if (key === "class" || key === "className") {
1252
- el.className = "";
1253
- } else if (eventName && existingListeners?.has(eventName)) {
1254
- const entry = existingListeners.get(eventName);
1255
- if (entry.options !== void 0) {
1256
- el.removeEventListener(eventName, entry.handler, entry.options);
1257
- } else {
1258
- el.removeEventListener(eventName, entry.handler);
1259
- }
1260
- existingListeners.delete(eventName);
1261
- } else {
1262
- el.removeAttribute(key);
1263
- }
1058
+ if (eventName) {
1059
+ addTrackedListener(el, eventName, value);
1264
1060
  continue;
1265
1061
  }
1266
1062
  if (key === "class" || key === "className") {
1267
1063
  el.className = String(value);
1268
1064
  } else if (key === "value" || key === "checked") {
1269
- el[key] = value;
1270
- } else if (eventName) {
1271
- desiredEventNames.add(eventName);
1272
- const existing = existingListeners?.get(eventName);
1273
- if (existing && existing.original === value) {
1274
- continue;
1275
- }
1276
- if (existing) {
1277
- el.removeEventListener(eventName, existing.handler);
1278
- }
1279
- const wrappedHandler = createWrappedHandler(
1280
- value,
1281
- false
1282
- );
1283
- const options = getPassiveOptions(eventName);
1284
- if (options !== void 0) {
1285
- el.addEventListener(eventName, wrappedHandler, options);
1286
- } else {
1287
- el.addEventListener(eventName, wrappedHandler);
1288
- }
1289
- if (!elementListeners.has(el)) {
1290
- elementListeners.set(el, /* @__PURE__ */ new Map());
1291
- }
1292
- elementListeners.get(el).set(eventName, {
1293
- handler: wrappedHandler,
1294
- original: value,
1295
- options
1296
- });
1065
+ applyFormControlProp(el, key, value, tagName);
1297
1066
  } else {
1298
1067
  el.setAttribute(key, String(value));
1299
1068
  }
1300
1069
  }
1301
- if (existingListeners) {
1302
- for (const eventName of existingListeners.keys()) {
1303
- if (!desiredEventNames.has(eventName)) {
1304
- const entry = existingListeners.get(eventName);
1305
- el.removeEventListener(eventName, entry.handler);
1306
- existingListeners.delete(eventName);
1307
- }
1070
+ }
1071
+ function applyFormControlProp(el, key, value, tagName) {
1072
+ if (key === "value") {
1073
+ if (tagNamesEqualIgnoreCase(tagName, "input") || tagNamesEqualIgnoreCase(tagName, "textarea") || tagNamesEqualIgnoreCase(tagName, "select")) {
1074
+ el.value = String(value);
1075
+ el.setAttribute("value", String(value));
1076
+ } else {
1077
+ el.setAttribute("value", String(value));
1078
+ }
1079
+ } else if (key === "checked") {
1080
+ if (tagNamesEqualIgnoreCase(tagName, "input")) {
1081
+ el.checked = Boolean(value);
1082
+ el.setAttribute("checked", String(Boolean(value)));
1083
+ } else {
1084
+ el.setAttribute("checked", String(Boolean(value)));
1308
1085
  }
1309
- if (existingListeners.size === 0) elementListeners.delete(el);
1310
- }
1311
- if (updateChildren) {
1312
- const children = vnode.children || props.children;
1313
- updateElementChildren(el, children);
1314
1086
  }
1315
1087
  }
1316
- function updateElementChildren(el, children) {
1317
- if (!children) {
1318
- el.textContent = "";
1319
- return;
1088
+ function materializeKey(el, vnode, props) {
1089
+ const vnodeKey = vnode.key ?? props?.key;
1090
+ if (vnodeKey !== void 0) {
1091
+ el.setAttribute("data-key", String(vnodeKey));
1320
1092
  }
1321
- if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
1322
- if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1323
- el.firstChild.data = String(children);
1324
- } else {
1325
- el.textContent = String(children);
1093
+ }
1094
+ function warnMissingKeys(children) {
1095
+ if (process.env.NODE_ENV === "production") return;
1096
+ let hasElements = false;
1097
+ let hasKeys = false;
1098
+ for (const item of children) {
1099
+ if (typeof item === "object" && item !== null && "type" in item) {
1100
+ hasElements = true;
1101
+ const rawKey = item.key ?? item.props?.key;
1102
+ if (rawKey !== void 0) {
1103
+ hasKeys = true;
1104
+ break;
1105
+ }
1326
1106
  }
1327
- return;
1328
1107
  }
1329
- if (Array.isArray(children)) {
1330
- updateUnkeyedChildren(el, children);
1331
- return;
1108
+ if (hasElements && !hasKeys) {
1109
+ try {
1110
+ const inst = getCurrentInstance();
1111
+ const name = inst?.fn?.name || "<anonymous>";
1112
+ logger.warn(
1113
+ `Missing keys on dynamic lists in ${name}. Each child in a list should have a unique "key" prop.`
1114
+ );
1115
+ } catch {
1116
+ logger.warn(
1117
+ 'Missing keys on dynamic lists. Each child in a list should have a unique "key" prop.'
1118
+ );
1119
+ }
1332
1120
  }
1333
- el.textContent = "";
1334
- const dom = createDOMNode(children);
1335
- if (dom) el.appendChild(dom);
1336
1121
  }
1337
- function updateUnkeyedChildren(parent, newChildren) {
1338
- const existing = Array.from(parent.children);
1339
- if (newChildren.length === 1 && existing.length === 0 && parent.childNodes.length === 1) {
1340
- const firstNewChild = newChildren[0];
1341
- const firstExisting = parent.firstChild;
1342
- if ((typeof firstNewChild === "string" || typeof firstNewChild === "number") && firstExisting?.nodeType === 3) {
1343
- firstExisting.data = String(firstNewChild);
1344
- return;
1122
+ function createDOMNode(node) {
1123
+ if (!IS_DOM_AVAILABLE) {
1124
+ if (process.env.NODE_ENV !== "production") {
1125
+ try {
1126
+ logger.warn("[Askr] createDOMNode called in non-DOM environment");
1127
+ } catch {
1128
+ }
1345
1129
  }
1130
+ return null;
1346
1131
  }
1347
- if (existing.length === 0 && parent.childNodes.length > 0) {
1348
- parent.textContent = "";
1132
+ if (typeof node === "string") {
1133
+ return document.createTextNode(node);
1349
1134
  }
1350
- const max = Math.max(existing.length, newChildren.length);
1351
- for (let i = 0; i < max; i++) {
1352
- const current2 = existing[i];
1353
- const next = newChildren[i];
1354
- if (next === void 0 && current2) {
1355
- cleanupInstanceIfPresent(current2);
1356
- current2.remove();
1357
- continue;
1358
- }
1359
- if (!current2 && next !== void 0) {
1360
- const dom = createDOMNode(next);
1361
- if (dom) parent.appendChild(dom);
1362
- continue;
1363
- }
1364
- if (!current2 || next === void 0) continue;
1365
- if (typeof next === "string" || typeof next === "number") {
1366
- current2.textContent = String(next);
1367
- } else if (_isDOMElement(next)) {
1135
+ if (typeof node === "number") {
1136
+ return document.createTextNode(String(node));
1137
+ }
1138
+ if (!node) {
1139
+ return null;
1140
+ }
1141
+ if (Array.isArray(node)) {
1142
+ const fragment = document.createDocumentFragment();
1143
+ for (const child of node) {
1144
+ const dom = createDOMNode(child);
1145
+ if (dom) fragment.appendChild(dom);
1146
+ }
1147
+ return fragment;
1148
+ }
1149
+ if (typeof node === "object" && node !== null && "type" in node) {
1150
+ const type = node.type;
1151
+ const props = node.props || {};
1152
+ if (typeof type === "string") {
1153
+ return createIntrinsicElement(node, type, props);
1154
+ }
1155
+ if (typeof type === "function") {
1156
+ return createComponentElement(node, type, props);
1157
+ }
1158
+ if (typeof type === "symbol" && (type === Fragment || String(type) === "Symbol(Fragment)")) {
1159
+ return createFragmentElement(node, props);
1160
+ }
1161
+ }
1162
+ return null;
1163
+ }
1164
+ function createIntrinsicElement(node, type, props) {
1165
+ const el = document.createElement(type);
1166
+ materializeKey(el, node, props);
1167
+ applyPropsToElement(el, props, type);
1168
+ const children = props.children || node.children;
1169
+ if (children) {
1170
+ if (Array.isArray(children)) {
1171
+ warnMissingKeys(children);
1172
+ for (const child of children) {
1173
+ const dom = createDOMNode(child);
1174
+ if (dom) el.appendChild(dom);
1175
+ }
1176
+ } else {
1177
+ const dom = createDOMNode(children);
1178
+ if (dom) el.appendChild(dom);
1179
+ }
1180
+ }
1181
+ return el;
1182
+ }
1183
+ function createComponentElement(node, type, props) {
1184
+ const frame = node[CONTEXT_FRAME_SYMBOL];
1185
+ const snapshot = frame || getCurrentContextFrame();
1186
+ const componentFn = type;
1187
+ const isAsync = componentFn.constructor.name === "AsyncFunction";
1188
+ if (isAsync) {
1189
+ throw new Error(
1190
+ "Async components are not supported. Use resource() for async work."
1191
+ );
1192
+ }
1193
+ let childInstance = node.__instance;
1194
+ if (!childInstance) {
1195
+ childInstance = createComponentInstance(
1196
+ `comp-${Math.random().toString(36).slice(2, 7)}`,
1197
+ componentFn,
1198
+ props || {},
1199
+ null
1200
+ );
1201
+ node.__instance = childInstance;
1202
+ }
1203
+ if (snapshot) {
1204
+ childInstance.ownerFrame = snapshot;
1205
+ }
1206
+ const result = withContext(
1207
+ snapshot,
1208
+ () => renderComponentInline(childInstance)
1209
+ );
1210
+ if (result instanceof Promise) {
1211
+ throw new Error(
1212
+ "Async components are not supported. Components must return synchronously."
1213
+ );
1214
+ }
1215
+ const dom = withContext(snapshot, () => createDOMNode(result));
1216
+ if (dom instanceof Element) {
1217
+ mountInstanceInline(childInstance, dom);
1218
+ return dom;
1219
+ }
1220
+ if (!dom) {
1221
+ const placeholder = document.createComment("");
1222
+ childInstance._placeholder = placeholder;
1223
+ childInstance.mounted = true;
1224
+ childInstance.notifyUpdate = childInstance._enqueueRun;
1225
+ return placeholder;
1226
+ }
1227
+ const host = document.createElement("div");
1228
+ host.appendChild(dom);
1229
+ mountInstanceInline(childInstance, host);
1230
+ return host;
1231
+ }
1232
+ function createFragmentElement(node, props) {
1233
+ const fragment = document.createDocumentFragment();
1234
+ const children = props.children || node.children;
1235
+ if (children) {
1236
+ if (Array.isArray(children)) {
1237
+ for (const child of children) {
1238
+ const dom = createDOMNode(child);
1239
+ if (dom) fragment.appendChild(dom);
1240
+ }
1241
+ } else {
1242
+ const dom = createDOMNode(children);
1243
+ if (dom) fragment.appendChild(dom);
1244
+ }
1245
+ }
1246
+ return fragment;
1247
+ }
1248
+ function updateElementFromVnode(el, vnode, updateChildren = true) {
1249
+ if (!_isDOMElement(vnode)) {
1250
+ return;
1251
+ }
1252
+ const props = vnode.props || {};
1253
+ materializeKey(el, vnode, props);
1254
+ const existingListeners = elementListeners.get(el);
1255
+ let desiredEventNames = null;
1256
+ for (const key in props) {
1257
+ const value = props[key];
1258
+ if (isSkippedProp(key)) continue;
1259
+ const eventName = parseEventName(key);
1260
+ if (value === void 0 || value === null || value === false) {
1261
+ if (key === "class" || key === "className") {
1262
+ el.className = "";
1263
+ } else if (eventName && existingListeners?.has(eventName)) {
1264
+ const entry = existingListeners.get(eventName);
1265
+ if (entry.options !== void 0) {
1266
+ el.removeEventListener(eventName, entry.handler, entry.options);
1267
+ } else {
1268
+ el.removeEventListener(eventName, entry.handler);
1269
+ }
1270
+ existingListeners.delete(eventName);
1271
+ } else {
1272
+ el.removeAttribute(key);
1273
+ }
1274
+ continue;
1275
+ }
1276
+ if (key === "class" || key === "className") {
1277
+ el.className = String(value);
1278
+ } else if (key === "value" || key === "checked") {
1279
+ el[key] = value;
1280
+ } else if (eventName) {
1281
+ if (existingListeners && existingListeners.size > 0) {
1282
+ (desiredEventNames ??= /* @__PURE__ */ new Set()).add(eventName);
1283
+ }
1284
+ const existing = existingListeners?.get(eventName);
1285
+ if (existing && existing.original === value) {
1286
+ continue;
1287
+ }
1288
+ if (existing) {
1289
+ if (existing.options !== void 0) {
1290
+ el.removeEventListener(eventName, existing.handler, existing.options);
1291
+ } else {
1292
+ el.removeEventListener(eventName, existing.handler);
1293
+ }
1294
+ }
1295
+ const wrappedHandler = createWrappedHandler(
1296
+ value,
1297
+ false
1298
+ );
1299
+ const options = getPassiveOptions(eventName);
1300
+ if (options !== void 0) {
1301
+ el.addEventListener(eventName, wrappedHandler, options);
1302
+ } else {
1303
+ el.addEventListener(eventName, wrappedHandler);
1304
+ }
1305
+ if (!elementListeners.has(el)) {
1306
+ elementListeners.set(el, /* @__PURE__ */ new Map());
1307
+ }
1308
+ elementListeners.get(el).set(eventName, {
1309
+ handler: wrappedHandler,
1310
+ original: value,
1311
+ options
1312
+ });
1313
+ } else {
1314
+ el.setAttribute(key, String(value));
1315
+ }
1316
+ }
1317
+ if (existingListeners && existingListeners.size > 0) {
1318
+ if (desiredEventNames === null) {
1319
+ for (const [eventName, entry] of existingListeners) {
1320
+ if (entry.options !== void 0) {
1321
+ el.removeEventListener(eventName, entry.handler, entry.options);
1322
+ } else {
1323
+ el.removeEventListener(eventName, entry.handler);
1324
+ }
1325
+ }
1326
+ elementListeners.delete(el);
1327
+ } else {
1328
+ for (const [eventName, entry] of existingListeners) {
1329
+ if (!desiredEventNames.has(eventName)) {
1330
+ if (entry.options !== void 0) {
1331
+ el.removeEventListener(eventName, entry.handler, entry.options);
1332
+ } else {
1333
+ el.removeEventListener(eventName, entry.handler);
1334
+ }
1335
+ existingListeners.delete(eventName);
1336
+ }
1337
+ }
1338
+ if (existingListeners.size === 0) elementListeners.delete(el);
1339
+ }
1340
+ }
1341
+ if (updateChildren) {
1342
+ const children = vnode.children || props.children;
1343
+ updateElementChildren(el, children);
1344
+ }
1345
+ }
1346
+ function updateElementChildren(el, children) {
1347
+ if (!children) {
1348
+ el.textContent = "";
1349
+ return;
1350
+ }
1351
+ if (!Array.isArray(children) && (typeof children === "string" || typeof children === "number")) {
1352
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1353
+ el.firstChild.data = String(children);
1354
+ } else {
1355
+ el.textContent = String(children);
1356
+ }
1357
+ return;
1358
+ }
1359
+ if (Array.isArray(children)) {
1360
+ updateUnkeyedChildren(el, children);
1361
+ return;
1362
+ }
1363
+ el.textContent = "";
1364
+ const dom = createDOMNode(children);
1365
+ if (dom) el.appendChild(dom);
1366
+ }
1367
+ function updateUnkeyedChildren(parent, newChildren) {
1368
+ const existing = Array.from(parent.children);
1369
+ if (newChildren.length === 1 && existing.length === 0 && parent.childNodes.length === 1) {
1370
+ const firstNewChild = newChildren[0];
1371
+ const firstExisting = parent.firstChild;
1372
+ if ((typeof firstNewChild === "string" || typeof firstNewChild === "number") && firstExisting?.nodeType === 3) {
1373
+ firstExisting.data = String(firstNewChild);
1374
+ return;
1375
+ }
1376
+ }
1377
+ if (existing.length === 0 && parent.childNodes.length > 0) {
1378
+ parent.textContent = "";
1379
+ }
1380
+ const max = Math.max(existing.length, newChildren.length);
1381
+ for (let i = 0; i < max; i++) {
1382
+ const current2 = existing[i];
1383
+ const next = newChildren[i];
1384
+ if (next === void 0 && current2) {
1385
+ cleanupInstanceIfPresent(current2);
1386
+ current2.remove();
1387
+ continue;
1388
+ }
1389
+ if (!current2 && next !== void 0) {
1390
+ const dom = createDOMNode(next);
1391
+ if (dom) parent.appendChild(dom);
1392
+ continue;
1393
+ }
1394
+ if (!current2 || next === void 0) continue;
1395
+ if (typeof next === "string" || typeof next === "number") {
1396
+ current2.textContent = String(next);
1397
+ } else if (_isDOMElement(next)) {
1368
1398
  if (typeof next.type === "string") {
1369
- if (current2.tagName.toLowerCase() === next.type.toLowerCase()) {
1399
+ if (tagsEqualIgnoreCase(current2.tagName, next.type)) {
1370
1400
  updateElementFromVnode(current2, next);
1371
1401
  } else {
1372
1402
  const dom = createDOMNode(next);
@@ -1399,31 +1429,38 @@ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
1399
1429
  let reused = 0;
1400
1430
  let updatedKeys = 0;
1401
1431
  const t0 = now();
1432
+ const debugFastPath = process.env.ASKR_FASTPATH_DEBUG === "1" || process.env.ASKR_FASTPATH_DEBUG === "true";
1402
1433
  for (let i = 0; i < total; i++) {
1403
1434
  const { key, vnode } = keyedVnodes[i];
1404
1435
  const ch = parent.children[i];
1405
1436
  if (ch && _isDOMElement(vnode) && typeof vnode.type === "string") {
1406
1437
  const vnodeType = vnode.type;
1407
- if (ch.tagName.toLowerCase() === vnodeType.toLowerCase()) {
1438
+ if (tagsEqualIgnoreCase(ch.tagName, vnodeType)) {
1408
1439
  const children = vnode.children || vnode.props?.children;
1409
- logFastPathDebug("positional idx", i, {
1410
- chTag: ch.tagName.toLowerCase(),
1411
- vnodeType,
1412
- chChildNodes: ch.childNodes.length,
1413
- childrenType: Array.isArray(children) ? "array" : typeof children
1414
- });
1415
- updateTextContent(ch, children);
1440
+ if (debugFastPath) {
1441
+ logFastPathDebug("positional idx", i, {
1442
+ chTag: ch.tagName,
1443
+ vnodeType,
1444
+ chChildNodes: ch.childNodes.length,
1445
+ childrenType: Array.isArray(children) ? "array" : typeof children
1446
+ });
1447
+ }
1448
+ updateTextContent(ch, children, vnode);
1416
1449
  setDataKey(ch, key, () => updatedKeys++);
1417
1450
  reused++;
1418
1451
  continue;
1419
1452
  } else {
1420
- logFastPathDebug("positional tag mismatch", i, {
1421
- chTag: ch.tagName.toLowerCase(),
1422
- vnodeType
1423
- });
1453
+ if (debugFastPath) {
1454
+ logFastPathDebug("positional tag mismatch", i, {
1455
+ chTag: ch.tagName,
1456
+ vnodeType
1457
+ });
1458
+ }
1424
1459
  }
1425
1460
  } else {
1426
- logFastPathDebug("positional missing or invalid", i, { ch: !!ch });
1461
+ if (debugFastPath) {
1462
+ logFastPathDebug("positional missing or invalid", i, { ch: !!ch });
1463
+ }
1427
1464
  }
1428
1465
  replaceNodeAtPosition(parent, i, vnode);
1429
1466
  }
@@ -1433,29 +1470,106 @@ function performBulkPositionalKeyedTextUpdate(parent, keyedVnodes) {
1433
1470
  recordFastPathStats(stats, "bulkKeyedPositionalHits");
1434
1471
  return stats;
1435
1472
  }
1436
- function updateTextContent(el, children) {
1473
+ function updateTextContent(el, children, vnode) {
1437
1474
  if (typeof children === "string" || typeof children === "number") {
1438
1475
  setTextNodeData(el, String(children));
1439
1476
  } else if (Array.isArray(children) && children.length === 1 && (typeof children[0] === "string" || typeof children[0] === "number")) {
1440
1477
  setTextNodeData(el, String(children[0]));
1441
1478
  } else {
1442
- updateElementFromVnode(el, el);
1479
+ if (!tryUpdateTwoChildTextPattern(el, vnode)) {
1480
+ updateElementFromVnode(el, vnode);
1481
+ }
1443
1482
  }
1444
1483
  }
1445
- function setTextNodeData(el, text) {
1446
- if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1447
- el.firstChild.data = text;
1484
+ function tryUpdateTwoChildTextPattern(parentEl, vnode) {
1485
+ const vnodeChildren = vnode.children || vnode.props?.children;
1486
+ if (!Array.isArray(vnodeChildren) || vnodeChildren.length !== 2) return false;
1487
+ const c0 = vnodeChildren[0];
1488
+ const c1 = vnodeChildren[1];
1489
+ if (!_isDOMElement(c0) || !_isDOMElement(c1)) return false;
1490
+ if (typeof c0.type !== "string" || typeof c1.type !== "string") return false;
1491
+ const el0 = parentEl.children[0];
1492
+ const el1 = parentEl.children[1];
1493
+ if (!el0 || !el1) return false;
1494
+ if (!tagsEqualIgnoreCase(el0.tagName, c0.type)) return false;
1495
+ if (!tagsEqualIgnoreCase(el1.tagName, c1.type)) return false;
1496
+ const t0 = c0.children || c0.props?.children;
1497
+ const t1 = c1.children || c1.props?.children;
1498
+ if (typeof t0 === "string" || typeof t0 === "number") {
1499
+ setTextNodeData(el0, String(t0));
1500
+ } else if (Array.isArray(t0) && t0.length === 1 && (typeof t0[0] === "string" || typeof t0[0] === "number")) {
1501
+ setTextNodeData(el0, String(t0[0]));
1502
+ } else {
1503
+ return false;
1504
+ }
1505
+ if (typeof t1 === "string" || typeof t1 === "number") {
1506
+ setTextNodeData(el1, String(t1));
1507
+ } else if (Array.isArray(t1) && t1.length === 1 && (typeof t1[0] === "string" || typeof t1[0] === "number")) {
1508
+ setTextNodeData(el1, String(t1[0]));
1509
+ } else {
1510
+ return false;
1511
+ }
1512
+ return true;
1513
+ }
1514
+ function setTextNodeData(el, text) {
1515
+ if (el.childNodes.length === 1 && el.firstChild?.nodeType === 3) {
1516
+ el.firstChild.data = text;
1448
1517
  } else {
1449
1518
  el.textContent = text;
1450
1519
  }
1451
1520
  }
1452
1521
  function setDataKey(el, key, onSet) {
1453
1522
  try {
1454
- el.setAttribute("data-key", String(key));
1523
+ const next = String(key);
1524
+ if (el.getAttribute("data-key") === next) return;
1525
+ el.setAttribute("data-key", next);
1455
1526
  onSet();
1456
1527
  } catch {
1457
1528
  }
1458
1529
  }
1530
+ function upperCommonTagName(tag) {
1531
+ switch (tag) {
1532
+ case "div":
1533
+ return "DIV";
1534
+ case "span":
1535
+ return "SPAN";
1536
+ case "p":
1537
+ return "P";
1538
+ case "a":
1539
+ return "A";
1540
+ case "button":
1541
+ return "BUTTON";
1542
+ case "input":
1543
+ return "INPUT";
1544
+ case "ul":
1545
+ return "UL";
1546
+ case "ol":
1547
+ return "OL";
1548
+ case "li":
1549
+ return "LI";
1550
+ default:
1551
+ return null;
1552
+ }
1553
+ }
1554
+ function tagNamesEqualIgnoreCase(a, b) {
1555
+ if (a === b) return true;
1556
+ const len = a.length;
1557
+ if (len !== b.length) return false;
1558
+ for (let i = 0; i < len; i++) {
1559
+ const ac = a.charCodeAt(i);
1560
+ const bc = b.charCodeAt(i);
1561
+ if (ac === bc) continue;
1562
+ const an = ac >= 65 && ac <= 90 ? ac + 32 : ac;
1563
+ const bn = bc >= 65 && bc <= 90 ? bc + 32 : bc;
1564
+ if (an !== bn) return false;
1565
+ }
1566
+ return true;
1567
+ }
1568
+ function tagsEqualIgnoreCase(elementTagName, vnodeType) {
1569
+ const upperCommon = upperCommonTagName(vnodeType);
1570
+ if (upperCommon !== null && elementTagName === upperCommon) return true;
1571
+ return tagNamesEqualIgnoreCase(elementTagName, vnodeType);
1572
+ }
1459
1573
  function replaceNodeAtPosition(parent, index, vnode) {
1460
1574
  const dom = createDOMNode(vnode);
1461
1575
  if (dom) {
@@ -1470,7 +1584,8 @@ function replaceNodeAtPosition(parent, index, vnode) {
1470
1584
  }
1471
1585
  function updateKeyedElementsMap(parent, keyedVnodes) {
1472
1586
  try {
1473
- const newKeyMap = /* @__PURE__ */ new Map();
1587
+ const existing = keyedElements.get(parent);
1588
+ const newKeyMap = existing ? (existing.clear(), existing) : /* @__PURE__ */ new Map();
1474
1589
  for (let i = 0; i < keyedVnodes.length; i++) {
1475
1590
  const k = keyedVnodes[i].key;
1476
1591
  const ch = parent.children[i];
@@ -1492,7 +1607,6 @@ function performBulkTextReplace(parent, newChildren) {
1492
1607
  else if (result === "created") created++;
1493
1608
  }
1494
1609
  const tBuild = now() - t0;
1495
- cleanupRemovedNodes(parent, finalNodes);
1496
1610
  const tCommit = commitBulkReplace(parent, finalNodes);
1497
1611
  keyedElements.delete(parent);
1498
1612
  const stats = {
@@ -1527,7 +1641,7 @@ function processElementVnode(vnode, existingNode, finalNodes) {
1527
1641
  const vnodeObj = vnode;
1528
1642
  if (typeof vnodeObj.type === "string") {
1529
1643
  const tag = vnodeObj.type;
1530
- if (existingNode && existingNode.nodeType === 1 && existingNode.tagName.toLowerCase() === tag.toLowerCase()) {
1644
+ if (existingNode && existingNode.nodeType === 1 && tagsEqualIgnoreCase(existingNode.tagName, tag)) {
1531
1645
  updateElementFromVnode(existingNode, vnode);
1532
1646
  finalNodes.push(existingNode);
1533
1647
  return "reused";
@@ -1540,24 +1654,21 @@ function processElementVnode(vnode, existingNode, finalNodes) {
1540
1654
  }
1541
1655
  return "skipped";
1542
1656
  }
1543
- function cleanupRemovedNodes(parent, keepNodes) {
1544
- try {
1545
- const toRemove = Array.from(parent.childNodes).filter(
1546
- (n) => !keepNodes.includes(n)
1547
- );
1548
- for (const n of toRemove) {
1549
- if (n instanceof Element) removeAllListeners(n);
1550
- cleanupInstanceIfPresent(n);
1551
- }
1552
- } catch {
1553
- }
1554
- }
1555
1657
  function commitBulkReplace(parent, nodes) {
1556
1658
  const fragStart = Date.now();
1557
1659
  const fragment = document.createDocumentFragment();
1558
1660
  for (let i = 0; i < nodes.length; i++) {
1559
1661
  fragment.appendChild(nodes[i]);
1560
1662
  }
1663
+ try {
1664
+ for (let n = parent.firstChild; n; ) {
1665
+ const next = n.nextSibling;
1666
+ if (n instanceof Element) removeAllListeners(n);
1667
+ cleanupInstanceIfPresent(n);
1668
+ n = next;
1669
+ }
1670
+ } catch {
1671
+ }
1561
1672
  recordDOMReplace("bulk-text-replace");
1562
1673
  parent.replaceChildren(fragment);
1563
1674
  return Date.now() - fragStart;
@@ -1644,22 +1755,6 @@ function recordBulkDiag(data) {
1644
1755
  }
1645
1756
  }
1646
1757
  }
1647
- var IS_DOM_AVAILABLE;
1648
- var init_dom = __esm({
1649
- "src/renderer/dom.ts"() {
1650
- "use strict";
1651
- init_logger();
1652
- init_jsx_runtime();
1653
- init_context();
1654
- init_component();
1655
- init_cleanup();
1656
- init_diag();
1657
- init_types();
1658
- init_keyed();
1659
- init_utils();
1660
- IS_DOM_AVAILABLE = typeof document !== "undefined";
1661
- }
1662
- });
1663
1758
 
1664
1759
  // src/renderer/fastpath.ts
1665
1760
  function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
@@ -1682,14 +1777,11 @@ function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
1682
1777
  parentChildrenArr[i] = pc[i];
1683
1778
  } catch (e) {
1684
1779
  parentChildrenArr = void 0;
1685
- void e;
1686
1780
  }
1687
1781
  } else {
1688
1782
  localOldKeyMap = /* @__PURE__ */ new Map();
1689
1783
  try {
1690
- const parentChildren = Array.from(parent.children);
1691
- for (let i = 0; i < parentChildren.length; i++) {
1692
- const ch = parentChildren[i];
1784
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
1693
1785
  const k = ch.getAttribute("data-key");
1694
1786
  if (k !== null) {
1695
1787
  localOldKeyMap.set(k, ch);
@@ -1699,7 +1791,6 @@ function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
1699
1791
  }
1700
1792
  } catch (e) {
1701
1793
  localOldKeyMap = void 0;
1702
- void e;
1703
1794
  }
1704
1795
  }
1705
1796
  const finalNodes = [];
@@ -1753,11 +1844,11 @@ function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
1753
1844
  fragmentAppendCount++;
1754
1845
  }
1755
1846
  try {
1756
- const existing = Array.from(parent.childNodes);
1757
- const toRemove = existing.filter((n) => !finalNodes.includes(n));
1758
- for (const n of toRemove) {
1847
+ for (let n = parent.firstChild; n; ) {
1848
+ const next = n.nextSibling;
1759
1849
  if (n instanceof Element) removeAllListeners(n);
1760
1850
  cleanupInstanceIfPresent(n);
1851
+ n = next;
1761
1852
  }
1762
1853
  } catch (e) {
1763
1854
  void e;
@@ -1820,26 +1911,25 @@ function applyRendererFastPath(parent, keyedVnodes, oldKeyMap, unkeyedVnodes) {
1820
1911
  }
1821
1912
  return newKeyMap;
1822
1913
  } catch (e) {
1823
- void e;
1824
1914
  return null;
1825
1915
  }
1826
1916
  }
1827
- var init_fastpath = __esm({
1828
- "src/renderer/fastpath.ts"() {
1829
- "use strict";
1830
- init_dom();
1831
- init_keyed();
1832
- init_logger();
1833
- init_cleanup();
1834
- init_diag();
1835
- init_scheduler();
1836
- init_fastlane_shared();
1837
- }
1838
- });
1839
1917
 
1840
1918
  // src/renderer/reconcile.ts
1919
+ function tagNamesEqualIgnoreCase2(a, b) {
1920
+ if (a === b) return true;
1921
+ if (a.length !== b.length) return false;
1922
+ for (let i = 0; i < a.length; i++) {
1923
+ const ca = a.charCodeAt(i);
1924
+ const cb = b.charCodeAt(i);
1925
+ if (ca === cb) continue;
1926
+ const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
1927
+ const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
1928
+ if (fa !== fb) return false;
1929
+ }
1930
+ return true;
1931
+ }
1841
1932
  function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
1842
- logReconcileDebug(newChildren);
1843
1933
  const { keyedVnodes, unkeyedVnodes } = partitionChildren(newChildren);
1844
1934
  const fastPathResult = tryFastPaths(
1845
1935
  parent,
@@ -1851,20 +1941,6 @@ function reconcileKeyedChildren(parent, newChildren, oldKeyMap) {
1851
1941
  if (fastPathResult) return fastPathResult;
1852
1942
  return performFullReconciliation(parent, newChildren, keyedVnodes, oldKeyMap);
1853
1943
  }
1854
- function logReconcileDebug(newChildren) {
1855
- if (process.env.NODE_ENV !== "production") {
1856
- try {
1857
- logger.warn(
1858
- "[Askr][RECONCILE] reconcileKeyedChildren newChildren sample",
1859
- {
1860
- sample: newChildren && newChildren.length && newChildren[0] || null,
1861
- len: newChildren.length
1862
- }
1863
- );
1864
- } catch {
1865
- }
1866
- }
1867
- }
1868
1944
  function partitionChildren(newChildren) {
1869
1945
  const keyedVnodes = [];
1870
1946
  const unkeyedVnodes = [];
@@ -1922,7 +1998,6 @@ function tryPositionalBulkUpdate(parent, keyedVnodes) {
1922
1998
  const total = keyedVnodes.length;
1923
1999
  if (total < 10) return null;
1924
2000
  const matchCount = countPositionalMatches(parent, keyedVnodes);
1925
- logPositionalCheck(total, matchCount, parent.children.length);
1926
2001
  if (matchCount / total < 0.9) return null;
1927
2002
  if (hasPositionalPropChanges(parent, keyedVnodes)) return null;
1928
2003
  try {
@@ -1943,7 +2018,7 @@ function countPositionalMatches(parent, keyedVnodes) {
1943
2018
  continue;
1944
2019
  const el = parent.children[i];
1945
2020
  if (!el) continue;
1946
- if (el.tagName.toLowerCase() === String(vnode.type).toLowerCase()) {
2021
+ if (tagNamesEqualIgnoreCase2(el.tagName, vnode.type)) {
1947
2022
  matchCount++;
1948
2023
  }
1949
2024
  }
@@ -1951,18 +2026,6 @@ function countPositionalMatches(parent, keyedVnodes) {
1951
2026
  }
1952
2027
  return matchCount;
1953
2028
  }
1954
- function logPositionalCheck(total, matchCount, parentChildren) {
1955
- if (process.env.NODE_ENV !== "production") {
1956
- try {
1957
- logger.warn("[Askr][FASTPATH] positional check", {
1958
- total,
1959
- matchCount,
1960
- parentChildren
1961
- });
1962
- } catch {
1963
- }
1964
- }
1965
- }
1966
2029
  function hasPositionalPropChanges(parent, keyedVnodes) {
1967
2030
  try {
1968
2031
  for (let i = 0; i < keyedVnodes.length; i++) {
@@ -1981,9 +2044,7 @@ function hasPositionalPropChanges(parent, keyedVnodes) {
1981
2044
  function rebuildKeyedMap(parent) {
1982
2045
  try {
1983
2046
  const map = /* @__PURE__ */ new Map();
1984
- const children = Array.from(parent.children);
1985
- for (let i = 0; i < children.length; i++) {
1986
- const el = children[i];
2047
+ for (let el = parent.firstElementChild; el; el = el.nextElementSibling) {
1987
2048
  const k = el.getAttribute("data-key");
1988
2049
  if (k !== null) {
1989
2050
  map.set(k, el);
@@ -2044,18 +2105,19 @@ function createOldElResolver(parent, oldKeyMap, usedOldEls) {
2044
2105
  }
2045
2106
  function scanForElementByKey(parent, k, keyStr, usedOldEls) {
2046
2107
  try {
2047
- const children = Array.from(parent.children);
2048
- for (const ch of children) {
2108
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
2049
2109
  if (usedOldEls.has(ch)) continue;
2050
2110
  const attr = ch.getAttribute("data-key");
2051
2111
  if (attr === keyStr) {
2052
2112
  usedOldEls.add(ch);
2053
2113
  return ch;
2054
2114
  }
2055
- const numAttr = Number(attr);
2056
- if (!Number.isNaN(numAttr) && numAttr === k) {
2057
- usedOldEls.add(ch);
2058
- return ch;
2115
+ if (attr !== null) {
2116
+ const numAttr = Number(attr);
2117
+ if (!Number.isNaN(numAttr) && numAttr === k) {
2118
+ usedOldEls.add(ch);
2119
+ return ch;
2120
+ }
2059
2121
  }
2060
2122
  }
2061
2123
  } catch {
@@ -2072,9 +2134,17 @@ function reconcileSingleChild(child, index, parent, resolveOldElOnce, usedOldEls
2072
2134
  function reconcileKeyedChild(child, key, parent, resolveOldElOnce, newKeyMap) {
2073
2135
  const el = resolveOldElOnce(key);
2074
2136
  if (el && el.parentElement === parent) {
2075
- updateElementFromVnode(el, child);
2076
- newKeyMap.set(key, el);
2077
- return el;
2137
+ try {
2138
+ const childObj = child;
2139
+ if (childObj && typeof childObj === "object" && typeof childObj.type === "string") {
2140
+ if (tagNamesEqualIgnoreCase2(el.tagName, childObj.type)) {
2141
+ updateElementFromVnode(el, child);
2142
+ newKeyMap.set(key, el);
2143
+ return el;
2144
+ }
2145
+ }
2146
+ } catch {
2147
+ }
2078
2148
  }
2079
2149
  const dom = createDOMNode(child);
2080
2150
  if (dom) {
@@ -2111,13 +2181,16 @@ function canReuseElement(existing, child) {
2111
2181
  if (typeof child !== "object" || child === null || !("type" in child))
2112
2182
  return false;
2113
2183
  const childObj = child;
2114
- const hasNoKey = existing.getAttribute("data-key") === null || existing.getAttribute("data-key") === void 0;
2115
- return hasNoKey && typeof childObj.type === "string" && existing.tagName.toLowerCase() === String(childObj.type).toLowerCase();
2184
+ const existingKey = existing.getAttribute("data-key");
2185
+ const hasNoKey = existingKey === null || existingKey === void 0;
2186
+ return hasNoKey && typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(existing.tagName, childObj.type);
2116
2187
  }
2117
2188
  function findAvailableUnkeyedElement(parent, usedOldEls) {
2118
- return Array.from(parent.children).find(
2119
- (ch) => !usedOldEls.has(ch) && ch.getAttribute("data-key") === null
2120
- );
2189
+ for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
2190
+ if (usedOldEls.has(ch)) continue;
2191
+ if (ch.getAttribute("data-key") === null) return ch;
2192
+ }
2193
+ return void 0;
2121
2194
  }
2122
2195
  function tryReuseElement(avail, child, usedOldEls) {
2123
2196
  if (typeof child === "string" || typeof child === "number") {
@@ -2127,7 +2200,7 @@ function tryReuseElement(avail, child, usedOldEls) {
2127
2200
  }
2128
2201
  if (typeof child === "object" && child !== null && "type" in child) {
2129
2202
  const childObj = child;
2130
- if (typeof childObj.type === "string" && avail.tagName.toLowerCase() === String(childObj.type).toLowerCase()) {
2203
+ if (typeof childObj.type === "string" && tagNamesEqualIgnoreCase2(avail.tagName, childObj.type)) {
2131
2204
  updateElementFromVnode(avail, child);
2132
2205
  usedOldEls.add(avail);
2133
2206
  return avail;
@@ -2141,30 +2214,33 @@ function commitReconciliation(parent, finalNodes) {
2141
2214
  fragment.appendChild(finalNodes[i]);
2142
2215
  }
2143
2216
  try {
2144
- const existing = Array.from(parent.childNodes);
2145
- for (const n of existing) {
2217
+ for (let n = parent.firstChild; n; ) {
2218
+ const next = n.nextSibling;
2146
2219
  if (n instanceof Element) removeAllListeners(n);
2147
2220
  cleanupInstanceIfPresent(n);
2221
+ n = next;
2148
2222
  }
2149
2223
  } catch {
2150
2224
  }
2151
2225
  recordDOMReplace("reconcile");
2152
2226
  parent.replaceChildren(fragment);
2153
2227
  }
2154
- var init_reconcile = __esm({
2155
- "src/renderer/reconcile.ts"() {
2156
- "use strict";
2157
- init_dom();
2158
- init_keyed();
2159
- init_cleanup();
2160
- init_fastlane_shared();
2161
- init_fastpath();
2162
- init_logger();
2163
- init_utils();
2164
- }
2165
- });
2166
2228
 
2167
2229
  // src/renderer/evaluate.ts
2230
+ var domRanges = /* @__PURE__ */ new WeakMap();
2231
+ function tagNamesEqualIgnoreCase3(a, b) {
2232
+ if (a === b) return true;
2233
+ if (a.length !== b.length) return false;
2234
+ for (let i = 0; i < a.length; i++) {
2235
+ const ca = a.charCodeAt(i);
2236
+ const cb = b.charCodeAt(i);
2237
+ if (ca === cb) continue;
2238
+ const fa = ca >= 65 && ca <= 90 ? ca + 32 : ca;
2239
+ const fb = cb >= 65 && cb <= 90 ? cb + 32 : cb;
2240
+ if (fa !== fb) return false;
2241
+ }
2242
+ return true;
2243
+ }
2168
2244
  function checkSimpleText(vnodeChildren) {
2169
2245
  if (!Array.isArray(vnodeChildren)) {
2170
2246
  if (typeof vnodeChildren === "string" || typeof vnodeChildren === "number") {
@@ -2187,8 +2263,7 @@ function tryUpdateTextInPlace(element, text) {
2187
2263
  }
2188
2264
  function buildKeyMapFromDOM(parent) {
2189
2265
  const keyMap = /* @__PURE__ */ new Map();
2190
- const children = Array.from(parent.children);
2191
- for (const child of children) {
2266
+ for (let child = parent.firstElementChild; child; child = child.nextElementSibling) {
2192
2267
  const k = child.getAttribute("data-key");
2193
2268
  if (k !== null) {
2194
2269
  keyMap.set(k, child);
@@ -2209,9 +2284,10 @@ function getOrBuildKeyMap(parent) {
2209
2284
  return keyMap.size > 0 ? keyMap : void 0;
2210
2285
  }
2211
2286
  function hasKeyedChildren(children) {
2212
- return children.some(
2213
- (child) => typeof child === "object" && child !== null && "key" in child
2214
- );
2287
+ for (let i = 0; i < children.length; i++) {
2288
+ if (extractKey(children[i]) !== void 0) return true;
2289
+ }
2290
+ return false;
2215
2291
  }
2216
2292
  function trackBulkTextStats(stats) {
2217
2293
  if (process.env.NODE_ENV !== "production") {
@@ -2321,19 +2397,22 @@ function updateElementChildren2(element, vnodeChildren) {
2321
2397
  function smartUpdateElement(element, vnode) {
2322
2398
  const vnodeChildren = vnode.children || vnode.props?.children;
2323
2399
  const textCheck = checkSimpleText(vnodeChildren);
2324
- if (textCheck.isSimple && tryUpdateTextInPlace(element, textCheck.text)) {
2325
- } else {
2400
+ if (textCheck.isSimple && tryUpdateTextInPlace(element, textCheck.text)) ; else {
2326
2401
  updateElementChildren2(element, vnodeChildren);
2327
2402
  }
2328
2403
  updateElementFromVnode(element, vnode, false);
2329
2404
  }
2330
2405
  function processFragmentChildren(target, childArray) {
2331
- const existingChildren = Array.from(target.children);
2406
+ let existingNode = target.firstElementChild;
2332
2407
  for (let i = 0; i < childArray.length; i++) {
2333
2408
  const childVnode = childArray[i];
2334
- const existingNode = existingChildren[i];
2335
- if (existingNode && _isDOMElement(childVnode) && typeof childVnode.type === "string" && existingNode.tagName.toLowerCase() === childVnode.type.toLowerCase()) {
2409
+ const nextExisting = existingNode ? existingNode.nextElementSibling : null;
2410
+ if (existingNode && _isDOMElement(childVnode) && typeof childVnode.type === "string" && tagNamesEqualIgnoreCase3(
2411
+ existingNode.tagName,
2412
+ childVnode.type
2413
+ )) {
2336
2414
  smartUpdateElement(existingNode, childVnode);
2415
+ existingNode = nextExisting;
2337
2416
  continue;
2338
2417
  }
2339
2418
  const newDom = createDOMNode(childVnode);
@@ -2344,39 +2423,29 @@ function processFragmentChildren(target, childArray) {
2344
2423
  target.appendChild(newDom);
2345
2424
  }
2346
2425
  }
2426
+ existingNode = nextExisting;
2347
2427
  }
2348
- while (target.children.length > childArray.length) {
2349
- target.removeChild(target.lastChild);
2428
+ while (existingNode) {
2429
+ const next = existingNode.nextElementSibling;
2430
+ target.removeChild(existingNode);
2431
+ existingNode = next;
2350
2432
  }
2351
2433
  }
2352
- function createWrappedEventHandler(handler) {
2353
- return (event) => {
2354
- globalScheduler.setInHandler(true);
2355
- try {
2356
- handler(event);
2357
- } catch (error) {
2358
- logger.error("[Askr] Event handler error:", error);
2359
- } finally {
2360
- globalScheduler.setInHandler(false);
2361
- }
2362
- };
2363
- }
2364
2434
  function applyPropsToElement2(el, props) {
2365
2435
  for (const [key, value] of Object.entries(props)) {
2366
2436
  if (key === "children" || key === "key") continue;
2367
2437
  if (value === void 0 || value === null || value === false) continue;
2368
- if (key.startsWith("on") && key.length > 2) {
2369
- const eventName = key.slice(2).charAt(0).toLowerCase() + key.slice(3).toLowerCase();
2370
- const wrappedHandler = createWrappedEventHandler(value);
2371
- const options = eventName === "wheel" || eventName === "scroll" || eventName.startsWith("touch") ? { passive: true } : void 0;
2372
- if (options !== void 0) {
2438
+ const eventName = parseEventName(key);
2439
+ if (eventName) {
2440
+ const wrappedHandler = createWrappedHandler(
2441
+ value,
2442
+ false
2443
+ );
2444
+ const options = getPassiveOptions(eventName);
2445
+ if (options !== void 0)
2373
2446
  el.addEventListener(eventName, wrappedHandler, options);
2374
- } else {
2375
- el.addEventListener(eventName, wrappedHandler);
2376
- }
2377
- if (!elementListeners.has(el)) {
2378
- elementListeners.set(el, /* @__PURE__ */ new Map());
2379
- }
2447
+ else el.addEventListener(eventName, wrappedHandler);
2448
+ if (!elementListeners.has(el)) elementListeners.set(el, /* @__PURE__ */ new Map());
2380
2449
  elementListeners.get(el).set(eventName, {
2381
2450
  handler: wrappedHandler,
2382
2451
  original: value,
@@ -2419,7 +2488,6 @@ function evaluate(node, target, context) {
2419
2488
  try {
2420
2489
  console.warn("[Askr] evaluate() called in non-DOM environment; no-op.");
2421
2490
  } catch (e) {
2422
- void e;
2423
2491
  }
2424
2492
  }
2425
2493
  return;
@@ -2458,7 +2526,7 @@ function evaluate(node, target, context) {
2458
2526
  }
2459
2527
  }
2460
2528
  const firstChild = target.children[0];
2461
- if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && firstChild.tagName.toLowerCase() === vnode.type.toLowerCase()) {
2529
+ if (firstChild && _isDOMElement(vnode) && typeof vnode.type === "string" && tagNamesEqualIgnoreCase3(firstChild.tagName, vnode.type)) {
2462
2530
  smartUpdateElement(firstChild, vnode);
2463
2531
  } else {
2464
2532
  target.textContent = "";
@@ -2472,44 +2540,16 @@ function evaluate(node, target, context) {
2472
2540
  }
2473
2541
  }
2474
2542
  }
2475
- var domRanges;
2476
- var init_evaluate = __esm({
2477
- "src/renderer/evaluate.ts"() {
2478
- "use strict";
2479
- init_scheduler();
2480
- init_logger();
2481
- init_cleanup();
2482
- init_keyed();
2483
- init_reconcile();
2484
- init_types();
2485
- init_dom();
2486
- init_diag();
2487
- init_types2();
2488
- domRanges = /* @__PURE__ */ new WeakMap();
2489
- }
2490
- });
2491
2543
 
2492
2544
  // src/renderer/index.ts
2493
- var init_renderer = __esm({
2494
- "src/renderer/index.ts"() {
2495
- "use strict";
2496
- init_types();
2497
- init_cleanup();
2498
- init_keyed();
2499
- init_dom();
2500
- init_evaluate();
2501
- init_evaluate();
2502
- init_keyed();
2503
- if (typeof globalThis !== "undefined") {
2504
- const _g = globalThis;
2505
- _g.__ASKR_RENDERER = {
2506
- evaluate,
2507
- isKeyedReorderFastPathEligible,
2508
- getKeyMapForElement
2509
- };
2510
- }
2511
- }
2512
- });
2545
+ if (typeof globalThis !== "undefined") {
2546
+ const _g = globalThis;
2547
+ _g.__ASKR_RENDERER = {
2548
+ evaluate,
2549
+ isKeyedReorderFastPathEligible,
2550
+ getKeyMapForElement
2551
+ };
2552
+ }
2513
2553
 
2514
2554
  // src/runtime/component.ts
2515
2555
  function createComponentInstance(id, fn, props, target) {
@@ -2561,26 +2601,13 @@ function createComponentInstance(id, fn, props, target) {
2561
2601
  };
2562
2602
  return instance;
2563
2603
  }
2604
+ var currentInstance = null;
2564
2605
  function getCurrentComponentInstance() {
2565
2606
  return currentInstance;
2566
2607
  }
2567
2608
  function setCurrentComponentInstance(instance) {
2568
2609
  currentInstance = instance;
2569
2610
  }
2570
- function registerMountOperation(operation) {
2571
- const instance = getCurrentComponentInstance();
2572
- if (instance) {
2573
- if (isBulkCommitActive2()) {
2574
- if (process.env.NODE_ENV !== "production") {
2575
- throw new Error(
2576
- "registerMountOperation called during bulk commit fast-lane"
2577
- );
2578
- }
2579
- return;
2580
- }
2581
- instance.mountOperations.push(operation);
2582
- }
2583
- }
2584
2611
  function executeMountOperations(instance) {
2585
2612
  if (!instance.isRoot) return;
2586
2613
  for (const operation of instance.mountOperations) {
@@ -2603,7 +2630,6 @@ function mountInstanceInline(instance, target) {
2603
2630
  if (target instanceof Element)
2604
2631
  target.__ASKR_INSTANCE = instance;
2605
2632
  } catch (err) {
2606
- void err;
2607
2633
  }
2608
2634
  instance.notifyUpdate = instance._enqueueRun;
2609
2635
  const wasFirstMount = !instance.mounted;
@@ -2612,6 +2638,7 @@ function mountInstanceInline(instance, target) {
2612
2638
  executeMountOperations(instance);
2613
2639
  }
2614
2640
  }
2641
+ var _globalRenderCounter = 0;
2615
2642
  function runComponent(instance) {
2616
2643
  instance.notifyUpdate = instance._enqueueRun;
2617
2644
  instance._currentRenderToken = ++_globalRenderCounter;
@@ -2633,7 +2660,7 @@ function runComponent(instance) {
2633
2660
  globalScheduler.enqueue(() => {
2634
2661
  if (!instance.target && instance._placeholder) {
2635
2662
  if (result === null || result === void 0) {
2636
- finalizeReadSubscriptions(instance);
2663
+ finalizeReadSubscriptions2(instance);
2637
2664
  return;
2638
2665
  }
2639
2666
  const placeholder = instance._placeholder;
@@ -2653,7 +2680,7 @@ function runComponent(instance) {
2653
2680
  instance.target = host;
2654
2681
  instance._placeholder = void 0;
2655
2682
  host.__ASKR_INSTANCE = instance;
2656
- finalizeReadSubscriptions(instance);
2683
+ finalizeReadSubscriptions2(instance);
2657
2684
  } finally {
2658
2685
  currentInstance = oldInstance;
2659
2686
  }
@@ -2698,7 +2725,7 @@ function runComponent(instance) {
2698
2725
  } finally {
2699
2726
  currentInstance = oldInstance;
2700
2727
  }
2701
- finalizeReadSubscriptions(instance);
2728
+ finalizeReadSubscriptions2(instance);
2702
2729
  instance.mounted = true;
2703
2730
  if (wasFirstMount && instance.mountOperations.length > 0) {
2704
2731
  executeMountOperations(instance);
@@ -2717,7 +2744,6 @@ function runComponent(instance) {
2717
2744
  }
2718
2745
  }
2719
2746
  } catch (_err) {
2720
- void _err;
2721
2747
  }
2722
2748
  try {
2723
2749
  try {
@@ -2750,7 +2776,7 @@ function renderComponentInline(instance) {
2750
2776
  try {
2751
2777
  const result = executeComponentSync(instance);
2752
2778
  if (!hadToken) {
2753
- finalizeReadSubscriptions(instance);
2779
+ finalizeReadSubscriptions2(instance);
2754
2780
  }
2755
2781
  return result;
2756
2782
  } finally {
@@ -2760,14 +2786,13 @@ function renderComponentInline(instance) {
2760
2786
  }
2761
2787
  function executeComponentSync(instance) {
2762
2788
  instance.stateIndexCheck = -1;
2763
- for (const state2 of instance.stateValues) {
2764
- if (state2) {
2765
- state2._hasBeenRead = false;
2789
+ for (const state of instance.stateValues) {
2790
+ if (state) {
2791
+ state._hasBeenRead = false;
2766
2792
  }
2767
2793
  }
2768
2794
  instance._pendingReadStates = /* @__PURE__ */ new Set();
2769
2795
  currentInstance = instance;
2770
- stateIndex = 0;
2771
2796
  try {
2772
2797
  const renderStartTime = process.env.NODE_ENV !== "production" ? Date.now() : 0;
2773
2798
  const context = {
@@ -2791,8 +2816,8 @@ function executeComponentSync(instance) {
2791
2816
  instance.firstRenderComplete = true;
2792
2817
  }
2793
2818
  for (let i = 0; i < instance.stateValues.length; i++) {
2794
- const state2 = instance.stateValues[i];
2795
- if (state2 && !state2._hasBeenRead) {
2819
+ const state = instance.stateValues[i];
2820
+ if (state && !state._hasBeenRead) {
2796
2821
  try {
2797
2822
  const name = instance.fn?.name || "<anonymous>";
2798
2823
  logger.warn(
@@ -2810,23 +2835,10 @@ function executeComponentSync(instance) {
2810
2835
  currentInstance = null;
2811
2836
  }
2812
2837
  }
2813
- function executeComponent(instance) {
2814
- instance.abortController = new AbortController();
2815
- instance.notifyUpdate = instance._enqueueRun;
2816
- globalScheduler.enqueue(() => runComponent(instance));
2817
- }
2818
2838
  function getCurrentInstance() {
2819
2839
  return currentInstance;
2820
2840
  }
2821
- function getSignal() {
2822
- if (!currentInstance) {
2823
- throw new Error(
2824
- "getSignal() can only be called during component render execution. Ensure you are calling this from inside your component function."
2825
- );
2826
- }
2827
- return currentInstance.abortController.signal;
2828
- }
2829
- function finalizeReadSubscriptions(instance) {
2841
+ function finalizeReadSubscriptions2(instance) {
2830
2842
  const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
2831
2843
  const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
2832
2844
  const token = instance._currentRenderToken;
@@ -2850,12 +2862,6 @@ function finalizeReadSubscriptions(instance) {
2850
2862
  instance._pendingReadStates = /* @__PURE__ */ new Set();
2851
2863
  instance._currentRenderToken = void 0;
2852
2864
  }
2853
- function getNextStateIndex() {
2854
- return stateIndex++;
2855
- }
2856
- function mountComponent(instance) {
2857
- executeComponent(instance);
2858
- }
2859
2865
  function cleanupComponent(instance) {
2860
2866
  const cleanupErrors = [];
2861
2867
  for (const cleanup of instance.cleanupFns) {
@@ -2889,167 +2895,27 @@ function cleanupComponent(instance) {
2889
2895
  instance.notifyUpdate = null;
2890
2896
  instance.mounted = false;
2891
2897
  }
2892
- var currentInstance, stateIndex, _globalRenderCounter;
2893
- var init_component = __esm({
2894
- "src/runtime/component.ts"() {
2895
- "use strict";
2896
- init_scheduler();
2897
- init_context();
2898
- init_logger();
2899
- init_diag();
2900
- init_fastlane_shared();
2901
- init_renderer();
2902
- currentInstance = null;
2903
- stateIndex = 0;
2904
- _globalRenderCounter = 0;
2905
- }
2906
- });
2907
-
2908
- // src/ssr/errors.ts
2909
- var SSRDataMissingError;
2910
- var init_errors = __esm({
2911
- "src/ssr/errors.ts"() {
2912
- "use strict";
2913
- SSRDataMissingError = class _SSRDataMissingError extends Error {
2914
- constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
2915
- super(message);
2916
- this.code = "SSR_DATA_MISSING";
2917
- this.name = "SSRDataMissingError";
2918
- Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
2919
- }
2920
- };
2921
- }
2922
- });
2923
-
2924
- // src/ssr/context.ts
2925
- function withSSRContext(ctx, fn) {
2926
- const prev = current;
2927
- current = ctx;
2928
- try {
2929
- return fn();
2930
- } finally {
2931
- current = prev;
2932
- }
2933
- }
2934
- function createRenderContext(seed = 12345) {
2935
- return { seed };
2936
- }
2937
- function getCurrentSSRContext() {
2938
- return currentSSRContext;
2939
- }
2940
- function runWithSSRContext(ctx, fn) {
2941
- const prev = currentSSRContext;
2942
- currentSSRContext = ctx;
2943
- try {
2944
- return fn();
2945
- } finally {
2946
- currentSSRContext = prev;
2947
- }
2948
- }
2949
- function throwSSRDataMissing() {
2950
- throw new SSRDataMissingError();
2951
- }
2952
- var current, currentSSRContext;
2953
- var init_context2 = __esm({
2954
- "src/ssr/context.ts"() {
2955
- "use strict";
2956
- init_errors();
2957
- current = null;
2958
- currentSSRContext = null;
2959
- }
2960
- });
2961
2898
 
2962
- // src/ssr/render-keys.ts
2963
- function getCurrentRenderData() {
2964
- return currentRenderData;
2965
- }
2966
- function resetKeyCounter() {
2967
- keyCounter = 0;
2968
- }
2969
- function getNextKey() {
2970
- return `r:${keyCounter++}`;
2971
- }
2972
- function startRenderPhase(data) {
2973
- currentRenderData = data ?? null;
2974
- resetKeyCounter();
2975
- }
2976
- function stopRenderPhase() {
2977
- currentRenderData = null;
2978
- resetKeyCounter();
2979
- }
2980
- async function resolvePlan(_plan) {
2981
- throw new Error(
2982
- `${PREPASS_REMOVED_MSG}; async resource plans are not supported`
2983
- );
2984
- }
2985
- function collectResources(_opts) {
2986
- throw new Error(`${PREPASS_REMOVED_MSG}; collectResources is disabled`);
2899
+ // src/runtime/execution-model.ts
2900
+ var EXECUTION_MODEL_KEY = /* @__PURE__ */ Symbol.for("__ASKR_EXECUTION_MODEL__");
2901
+ function getExecutionModel() {
2902
+ const g = globalThis;
2903
+ return g[EXECUTION_MODEL_KEY];
2987
2904
  }
2988
- var keyCounter, currentRenderData, PREPASS_REMOVED_MSG, resolveResources;
2989
- var init_render_keys = __esm({
2990
- "src/ssr/render-keys.ts"() {
2991
- "use strict";
2992
- keyCounter = 0;
2993
- currentRenderData = null;
2994
- PREPASS_REMOVED_MSG = "SSR collection/prepass is removed: SSR is strictly synchronous";
2995
- resolveResources = resolvePlan;
2996
- }
2997
- });
2998
2905
 
2999
- // src/router/match.ts
3000
- function match(path, pattern) {
3001
- const normalizedPath = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3002
- const normalizedPattern = pattern.endsWith("/") && pattern !== "/" ? pattern.slice(0, -1) : pattern;
3003
- const pathSegments = normalizedPath.split("/").filter(Boolean);
3004
- const patternSegments = normalizedPattern.split("/").filter(Boolean);
3005
- if (patternSegments.length === 1 && patternSegments[0] === "*") {
3006
- return {
3007
- matched: true,
3008
- params: {
3009
- "*": pathSegments.length > 1 ? normalizedPath : pathSegments[0]
3010
- }
3011
- };
3012
- }
3013
- if (pathSegments.length !== patternSegments.length) {
3014
- return { matched: false, params: {} };
3015
- }
3016
- const params = {};
3017
- for (let i = 0; i < patternSegments.length; i++) {
3018
- const patternSegment = patternSegments[i];
3019
- const pathSegment = pathSegments[i];
3020
- if (patternSegment.startsWith("{") && patternSegment.endsWith("}")) {
3021
- const paramName = patternSegment.slice(1, -1);
3022
- params[paramName] = decodeURIComponent(pathSegment);
3023
- } else if (patternSegment === "*") {
3024
- params["*"] = pathSegment;
3025
- } else if (patternSegment !== pathSegment) {
3026
- return { matched: false, params: {} };
3027
- }
2906
+ // src/router/route.ts
2907
+ var routes = [];
2908
+ var namespaces = /* @__PURE__ */ new Set();
2909
+ var HAS_ROUTES_KEY = /* @__PURE__ */ Symbol.for("__ASKR_HAS_ROUTES__");
2910
+ function setHasRoutes(value) {
2911
+ try {
2912
+ const g = globalThis;
2913
+ g[HAS_ROUTES_KEY] = value;
2914
+ } catch {
3028
2915
  }
3029
- return { matched: true, params };
3030
2916
  }
3031
- var init_match = __esm({
3032
- "src/router/match.ts"() {
3033
- "use strict";
3034
- }
3035
- });
3036
-
3037
- // src/router/route.ts
3038
- var route_exports = {};
3039
- __export(route_exports, {
3040
- _lockRouteRegistrationForTests: () => _lockRouteRegistrationForTests,
3041
- _unlockRouteRegistrationForTests: () => _unlockRouteRegistrationForTests,
3042
- clearRoutes: () => clearRoutes,
3043
- getLoadedNamespaces: () => getLoadedNamespaces,
3044
- getNamespaceRoutes: () => getNamespaceRoutes,
3045
- getRoutes: () => getRoutes,
3046
- lockRouteRegistration: () => lockRouteRegistration,
3047
- registerRoute: () => registerRoute,
3048
- resolveRoute: () => resolveRoute,
3049
- route: () => route,
3050
- setServerLocation: () => setServerLocation,
3051
- unloadNamespace: () => unloadNamespace
3052
- });
2917
+ setHasRoutes(false);
2918
+ var routesByDepth = /* @__PURE__ */ new Map();
3053
2919
  function getDepth(path) {
3054
2920
  const normalized = path.endsWith("/") && path !== "/" ? path.slice(0, -1) : path;
3055
2921
  return normalized === "/" ? 0 : normalized.split("/").filter(Boolean).length;
@@ -3072,6 +2938,7 @@ function getSpecificity(path) {
3072
2938
  }
3073
2939
  return score;
3074
2940
  }
2941
+ var serverLocation = null;
3075
2942
  function setServerLocation(url) {
3076
2943
  serverLocation = url;
3077
2944
  }
@@ -3158,6 +3025,7 @@ function computeMatches(pathname) {
3158
3025
  namespace: m.namespace
3159
3026
  }));
3160
3027
  }
3028
+ var registrationLocked = false;
3161
3029
  function lockRouteRegistration() {
3162
3030
  registrationLocked = true;
3163
3031
  }
@@ -3168,6 +3036,11 @@ function _unlockRouteRegistrationForTests() {
3168
3036
  registrationLocked = false;
3169
3037
  }
3170
3038
  function route(path, handler, namespace) {
3039
+ if (getExecutionModel() === "islands") {
3040
+ throw new Error(
3041
+ "Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead."
3042
+ );
3043
+ }
3171
3044
  if (typeof path === "undefined") {
3172
3045
  const instance = getCurrentComponentInstance();
3173
3046
  if (!instance) {
@@ -3210,7 +3083,7 @@ function route(path, handler, namespace) {
3210
3083
  }
3211
3084
  if (registrationLocked) {
3212
3085
  throw new Error(
3213
- "Route registration is locked after app startup. Register routes at module load time before calling createIsland()."
3086
+ "Route registration is locked after app startup. Register routes at module load time before calling createSPA or createSSR."
3214
3087
  );
3215
3088
  }
3216
3089
  if (typeof handler !== "function") {
@@ -3220,6 +3093,7 @@ function route(path, handler, namespace) {
3220
3093
  }
3221
3094
  const routeObj = { path, handler, namespace };
3222
3095
  routes.push(routeObj);
3096
+ setHasRoutes(true);
3223
3097
  const depth = getDepth(path);
3224
3098
  let depthRoutes = routesByDepth.get(depth);
3225
3099
  if (!depthRoutes) {
@@ -3260,6 +3134,8 @@ function clearRoutes() {
3260
3134
  routes.length = 0;
3261
3135
  namespaces.clear();
3262
3136
  routesByDepth.clear();
3137
+ registrationLocked = false;
3138
+ setHasRoutes(false);
3263
3139
  }
3264
3140
  function normalizeHandler(handler) {
3265
3141
  if (handler == null) return void 0;
@@ -3355,186 +3231,40 @@ function resolveRoute(pathname) {
3355
3231
  }
3356
3232
  return null;
3357
3233
  }
3358
- var routes, namespaces, routesByDepth, serverLocation, registrationLocked;
3359
- var init_route = __esm({
3360
- "src/router/route.ts"() {
3361
- "use strict";
3362
- init_match();
3363
- init_component();
3364
- routes = [];
3365
- namespaces = /* @__PURE__ */ new Set();
3366
- routesByDepth = /* @__PURE__ */ new Map();
3367
- serverLocation = null;
3368
- registrationLocked = false;
3369
- }
3370
- });
3371
-
3372
- // src/router/navigate.ts
3373
- var navigate_exports = {};
3374
- __export(navigate_exports, {
3375
- cleanupNavigation: () => cleanupNavigation,
3376
- initializeNavigation: () => initializeNavigation,
3377
- navigate: () => navigate,
3378
- registerAppInstance: () => registerAppInstance
3379
- });
3380
- function registerAppInstance(instance, _path) {
3381
- currentInstance2 = instance;
3382
- if (process.env.NODE_ENV === "production") {
3383
- lockRouteRegistration();
3384
- }
3385
- }
3386
- function navigate(path) {
3387
- if (typeof window === "undefined") {
3388
- return;
3389
- }
3390
- const resolved = resolveRoute(path);
3391
- if (!resolved) {
3392
- if (process.env.NODE_ENV !== "production") {
3393
- logger.warn(`No route found for path: ${path}`);
3394
- }
3395
- return;
3396
- }
3397
- window.history.pushState({ path }, "", path);
3398
- if (currentInstance2) {
3399
- cleanupComponent(currentInstance2);
3400
- currentInstance2.fn = resolved.handler;
3401
- currentInstance2.props = resolved.params;
3402
- currentInstance2.stateValues = [];
3403
- currentInstance2.expectedStateIndices = [];
3404
- currentInstance2.firstRenderComplete = false;
3405
- currentInstance2.stateIndexCheck = -1;
3406
- currentInstance2.evaluationGeneration++;
3407
- currentInstance2.notifyUpdate = null;
3408
- currentInstance2.abortController = new AbortController();
3409
- mountComponent(currentInstance2);
3410
- }
3411
- }
3412
- function handlePopState(_event) {
3413
- const path = window.location.pathname;
3414
- if (!currentInstance2) {
3415
- return;
3416
- }
3417
- const resolved = resolveRoute(path);
3418
- if (resolved) {
3419
- cleanupComponent(currentInstance2);
3420
- currentInstance2.fn = resolved.handler;
3421
- currentInstance2.props = resolved.params;
3422
- currentInstance2.stateValues = [];
3423
- currentInstance2.expectedStateIndices = [];
3424
- currentInstance2.firstRenderComplete = false;
3425
- currentInstance2.stateIndexCheck = -1;
3426
- currentInstance2.evaluationGeneration++;
3427
- currentInstance2.notifyUpdate = null;
3428
- currentInstance2.abortController = new AbortController();
3429
- mountComponent(currentInstance2);
3430
- }
3431
- }
3432
- function initializeNavigation() {
3433
- if (typeof window !== "undefined") {
3434
- window.addEventListener("popstate", handlePopState);
3435
- }
3436
- }
3437
- function cleanupNavigation() {
3438
- if (typeof window !== "undefined") {
3439
- window.removeEventListener("popstate", handlePopState);
3440
- }
3441
- }
3442
- var currentInstance2;
3443
- var init_navigate = __esm({
3444
- "src/router/navigate.ts"() {
3445
- "use strict";
3446
- init_route();
3447
- init_component();
3448
- init_logger();
3449
- currentInstance2 = null;
3450
- }
3451
- });
3452
-
3453
- // src/jsx/utils.ts
3454
- function isElement(value) {
3455
- return typeof value === "object" && value !== null && value.$$typeof === ELEMENT_TYPE;
3456
- }
3457
- function cloneElement(element, props) {
3458
- return {
3459
- ...element,
3460
- props: { ...element.props, ...props }
3461
- };
3462
- }
3463
- var init_utils2 = __esm({
3464
- "src/jsx/utils.ts"() {
3465
- "use strict";
3466
- init_types2();
3467
- }
3468
- });
3469
-
3470
- // src/jsx/index.ts
3471
- var init_jsx = __esm({
3472
- "src/jsx/index.ts"() {
3473
- "use strict";
3474
- init_types2();
3475
- init_utils2();
3476
- }
3477
- });
3478
3234
 
3479
3235
  // src/foundations/portal.tsx
3480
3236
  function definePortal() {
3481
3237
  if (typeof createPortalSlot !== "function") {
3482
3238
  let HostFallback2 = function() {
3483
- hosts = hosts.filter((h) => h.mounted !== false);
3484
- const inst = getCurrentComponentInstance();
3485
- if (inst && !hosts.includes(inst)) hosts.push(inst);
3486
- const owner = hosts.find((h) => h.mounted === true) || null;
3487
- const mountedHosts = hosts.filter((h) => h.mounted === true);
3488
- if (mountedHosts.length > 1) {
3489
- logger.warn(
3490
- "[Portal] multiple hosts are mounted for same portal; first mounted host will be owner"
3491
- );
3492
- }
3493
- if (inst && owner && owner !== inst) {
3494
- logger.debug(
3495
- "[Portal] non-owner reader detected; only owner renders portal content"
3496
- );
3239
+ if (owner && owner.mounted === false) {
3240
+ owner = null;
3241
+ pending = void 0;
3497
3242
  }
3243
+ const inst = getCurrentComponentInstance();
3244
+ if (!owner && inst) owner = inst;
3498
3245
  if (process.env.NODE_ENV !== "production") {
3499
3246
  const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3500
3247
  ns.__PORTAL_READS = (ns.__PORTAL_READS || 0) + 1;
3501
3248
  }
3502
- if (process.env.NODE_ENV !== "production" && inst && owner && inst === owner) {
3503
- logger.debug("[Portal] owner read ->", inst.id, "pending=", pending);
3504
- const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3505
- ns.__PORTAL_HOST_ATTACHED = !!(inst && inst.target);
3506
- ns.__PORTAL_HOST_ID = inst ? inst.id : void 0;
3249
+ if (process.env.NODE_ENV !== "production") {
3250
+ if (inst && owner && inst !== owner && inst.mounted === true) {
3251
+ logger.warn(
3252
+ "[Portal] multiple mounted hosts detected; first mounted host is owner"
3253
+ );
3254
+ }
3507
3255
  }
3508
- return inst === owner ? pending : void 0;
3256
+ return inst && owner && inst === owner ? pending : void 0;
3509
3257
  };
3510
- var HostFallback = HostFallback2;
3511
- let hosts = [];
3258
+ let owner = null;
3512
3259
  let pending;
3513
3260
  HostFallback2.render = function RenderFallback(props) {
3514
- hosts = hosts.filter((h) => h.mounted !== false);
3515
- const owner = hosts.find((h) => h.mounted === true) || null;
3516
- if (!owner) {
3517
- logger.debug(
3518
- "[Portal] fallback.write dropped -> no owner or not mounted",
3519
- props?.children
3520
- );
3521
- return null;
3522
- }
3523
- pending = props.children;
3524
- logger.debug("[Portal] fallback.write ->", pending, "owner=", owner.id);
3261
+ if (!owner || owner.mounted !== true) return null;
3525
3262
  if (process.env.NODE_ENV !== "production") {
3526
3263
  const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3527
3264
  ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
3528
3265
  }
3529
- if (owner && owner.notifyUpdate) {
3530
- if (process.env.NODE_ENV !== "production")
3531
- logger.debug(
3532
- "[Portal] fallback.write notify ->",
3533
- owner.id,
3534
- !!owner.notifyUpdate
3535
- );
3536
- owner.notifyUpdate();
3537
- }
3266
+ pending = props.children;
3267
+ if (owner.notifyUpdate) owner.notifyUpdate();
3538
3268
  return null;
3539
3269
  };
3540
3270
  return HostFallback2;
@@ -3544,7 +3274,6 @@ function definePortal() {
3544
3274
  return slot.read();
3545
3275
  }
3546
3276
  PortalHost.render = function PortalRender(props) {
3547
- logger.debug("[Portal] write ->", props?.children);
3548
3277
  if (process.env.NODE_ENV !== "production") {
3549
3278
  const ns = globalThis.__ASKR__ || (globalThis.__ASKR__ = {});
3550
3279
  ns.__PORTAL_WRITES = (ns.__PORTAL_WRITES || 0) + 1;
@@ -3554,26 +3283,16 @@ function definePortal() {
3554
3283
  };
3555
3284
  return PortalHost;
3556
3285
  }
3557
- function _resetDefaultPortal() {
3558
- _defaultPortal = void 0;
3559
- _defaultPortalIsFallback = false;
3560
- }
3286
+ var _defaultPortal;
3287
+ var _defaultPortalIsFallback = false;
3561
3288
  function ensureDefaultPortal() {
3562
- logger.debug(
3563
- "[DefaultPortal] ensureDefaultPortal _defaultPortalIsFallback=",
3564
- _defaultPortalIsFallback,
3565
- "createPortalSlot=",
3566
- typeof createPortalSlot === "function"
3567
- );
3568
3289
  if (!_defaultPortal) {
3569
3290
  if (typeof createPortalSlot === "function") {
3570
3291
  _defaultPortal = definePortal();
3571
3292
  _defaultPortalIsFallback = false;
3572
- logger.debug("[DefaultPortal] created real portal");
3573
3293
  } else {
3574
3294
  _defaultPortal = definePortal();
3575
3295
  _defaultPortalIsFallback = true;
3576
- logger.debug("[DefaultPortal] created fallback portal");
3577
3296
  }
3578
3297
  return _defaultPortal;
3579
3298
  }
@@ -3586,32 +3305,122 @@ function ensureDefaultPortal() {
3586
3305
  const fallback = definePortal();
3587
3306
  _defaultPortal = fallback;
3588
3307
  _defaultPortalIsFallback = true;
3589
- logger.debug("[DefaultPortal] reverted to fallback portal");
3590
3308
  }
3591
3309
  return _defaultPortal;
3592
3310
  }
3593
- var _defaultPortal, _defaultPortalIsFallback, DefaultPortal;
3594
- var init_portal = __esm({
3595
- "src/foundations/portal.tsx"() {
3596
- "use strict";
3597
- init_component();
3598
- init_logger();
3599
- _defaultPortalIsFallback = false;
3600
- DefaultPortal = (() => {
3601
- function Host() {
3602
- const v = ensureDefaultPortal()();
3603
- return v === void 0 ? null : v;
3604
- }
3605
- Host.render = function Render(props) {
3606
- ensureDefaultPortal().render(props);
3607
- return null;
3608
- };
3609
- return Host;
3610
- })();
3311
+ var DefaultPortal = (() => {
3312
+ function Host() {
3313
+ const v = ensureDefaultPortal()();
3314
+ return v === void 0 ? null : v;
3611
3315
  }
3612
- });
3316
+ Host.render = function Render(props) {
3317
+ ensureDefaultPortal().render(props);
3318
+ return null;
3319
+ };
3320
+ return Host;
3321
+ })();
3322
+
3323
+ // src/common/ssr-errors.ts
3324
+ var SSRDataMissingError = class _SSRDataMissingError extends Error {
3325
+ constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
3326
+ super(message);
3327
+ this.code = "SSR_DATA_MISSING";
3328
+ this.name = "SSRDataMissingError";
3329
+ Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
3330
+ }
3331
+ };
3332
+ function withSSRContext(ctx, fn) {
3333
+ try {
3334
+ return fn();
3335
+ } finally {
3336
+ }
3337
+ }
3338
+ function createRenderContext(seed = 12345) {
3339
+ return { seed };
3340
+ }
3341
+ function runWithSSRContext(ctx, fn) {
3342
+ try {
3343
+ return fn();
3344
+ } finally {
3345
+ }
3346
+ }
3347
+ function throwSSRDataMissing() {
3348
+ throw new SSRDataMissingError();
3349
+ }
3350
+ function startRenderPhase(data) {
3351
+ }
3352
+ var PREPASS_REMOVED_MSG = "SSR collection/prepass is removed: SSR is strictly synchronous";
3353
+ async function resolvePlan(_plan) {
3354
+ throw new Error(
3355
+ `${PREPASS_REMOVED_MSG}; async resource plans are not supported`
3356
+ );
3357
+ }
3358
+ function collectResources(_opts) {
3359
+ throw new Error(`${PREPASS_REMOVED_MSG}; collectResources is disabled`);
3360
+ }
3361
+ var resolveResources = resolvePlan;
3613
3362
 
3614
3363
  // src/ssr/escape.ts
3364
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
3365
+ "area",
3366
+ "base",
3367
+ "br",
3368
+ "col",
3369
+ "embed",
3370
+ "hr",
3371
+ "img",
3372
+ "input",
3373
+ "link",
3374
+ "meta",
3375
+ "param",
3376
+ "source",
3377
+ "track",
3378
+ "wbr"
3379
+ ]);
3380
+ var escapeCache = /* @__PURE__ */ new Map();
3381
+ var MAX_CACHE_SIZE = 256;
3382
+ var TEXT_ESCAPE_TEST_RE = /[&<>]/;
3383
+ var TEXT_ESCAPE_RE = /[&<>]/g;
3384
+ var ATTR_ESCAPE_TEST_RE = /[&"'<>]/;
3385
+ var ATTR_ESCAPE_RE = /[&"'<>]/g;
3386
+ var CSS_UNSAFE_TEST_RE = /[{}<>\\]/;
3387
+ var CSS_UNSAFE_RE = /[{}<>\\]/g;
3388
+ var CSS_DANGEROUS_FN_RE = /(?:url|expression|javascript)\s*\(/i;
3389
+ var STYLE_PROP_CACHE = /* @__PURE__ */ new Map();
3390
+ var MAX_STYLE_PROP_CACHE_SIZE = 512;
3391
+ function toKebabCached(prop) {
3392
+ const cached = STYLE_PROP_CACHE.get(prop);
3393
+ if (cached !== void 0) return cached;
3394
+ const kebab = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
3395
+ if (STYLE_PROP_CACHE.size < MAX_STYLE_PROP_CACHE_SIZE) {
3396
+ STYLE_PROP_CACHE.set(prop, kebab);
3397
+ }
3398
+ return kebab;
3399
+ }
3400
+ function mapTextEscape(ch) {
3401
+ switch (ch) {
3402
+ case "&":
3403
+ return "&amp;";
3404
+ case "<":
3405
+ return "&lt;";
3406
+ default:
3407
+ return "&gt;";
3408
+ }
3409
+ }
3410
+ function mapAttrEscape(ch) {
3411
+ switch (ch) {
3412
+ case "&":
3413
+ return "&amp;";
3414
+ case '"':
3415
+ return "&quot;";
3416
+ case "'":
3417
+ return "&#x27;";
3418
+ case "<":
3419
+ return "&lt;";
3420
+ default:
3421
+ return "&gt;";
3422
+ }
3423
+ }
3615
3424
  function escapeText(text) {
3616
3425
  const useCache = text.length <= 64;
3617
3426
  if (useCache) {
@@ -3619,13 +3428,13 @@ function escapeText(text) {
3619
3428
  if (cached !== void 0) return cached;
3620
3429
  }
3621
3430
  const str = String(text);
3622
- if (!str.includes("&") && !str.includes("<") && !str.includes(">")) {
3431
+ if (!TEXT_ESCAPE_TEST_RE.test(str)) {
3623
3432
  if (useCache && escapeCache.size < MAX_CACHE_SIZE) {
3624
3433
  escapeCache.set(text, str);
3625
3434
  }
3626
3435
  return str;
3627
3436
  }
3628
- const result = str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3437
+ const result = str.replace(TEXT_ESCAPE_RE, mapTextEscape);
3629
3438
  if (useCache && escapeCache.size < MAX_CACHE_SIZE) {
3630
3439
  escapeCache.set(text, result);
3631
3440
  }
@@ -3633,17 +3442,20 @@ function escapeText(text) {
3633
3442
  }
3634
3443
  function escapeAttr(value) {
3635
3444
  const str = String(value);
3636
- if (!str.includes("&") && !str.includes('"') && !str.includes("'") && !str.includes("<") && !str.includes(">")) {
3445
+ if (!ATTR_ESCAPE_TEST_RE.test(str)) {
3637
3446
  return str;
3638
3447
  }
3639
- return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3448
+ return str.replace(ATTR_ESCAPE_RE, mapAttrEscape);
3640
3449
  }
3641
3450
  function escapeCssValue(value) {
3642
3451
  const str = String(value);
3643
- if (/(?:url|expression|javascript)\s*\(/i.test(str)) {
3452
+ const hasUnsafeChars = CSS_UNSAFE_TEST_RE.test(str);
3453
+ const openParen = str.indexOf("(");
3454
+ if (!hasUnsafeChars && openParen === -1) return str;
3455
+ if (openParen !== -1 && CSS_DANGEROUS_FN_RE.test(str)) {
3644
3456
  return "";
3645
3457
  }
3646
- return str.replace(/[{}<>\\]/g, "");
3458
+ return hasUnsafeChars ? str.replace(CSS_UNSAFE_RE, "") : str;
3647
3459
  }
3648
3460
  function styleObjToCss(value) {
3649
3461
  if (!value || typeof value !== "object") return null;
@@ -3652,7 +3464,7 @@ function styleObjToCss(value) {
3652
3464
  let out = "";
3653
3465
  for (const [k, v] of entries) {
3654
3466
  if (v === null || v === void 0 || v === false) continue;
3655
- const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
3467
+ const prop = toKebabCached(k);
3656
3468
  const safeValue = escapeCssValue(String(v));
3657
3469
  if (safeValue) {
3658
3470
  out += `${prop}:${safeValue};`;
@@ -3660,30 +3472,6 @@ function styleObjToCss(value) {
3660
3472
  }
3661
3473
  return out;
3662
3474
  }
3663
- var VOID_ELEMENTS, escapeCache, MAX_CACHE_SIZE;
3664
- var init_escape = __esm({
3665
- "src/ssr/escape.ts"() {
3666
- "use strict";
3667
- VOID_ELEMENTS = /* @__PURE__ */ new Set([
3668
- "area",
3669
- "base",
3670
- "br",
3671
- "col",
3672
- "embed",
3673
- "hr",
3674
- "img",
3675
- "input",
3676
- "link",
3677
- "meta",
3678
- "param",
3679
- "source",
3680
- "track",
3681
- "wbr"
3682
- ]);
3683
- escapeCache = /* @__PURE__ */ new Map();
3684
- MAX_CACHE_SIZE = 256;
3685
- }
3686
- });
3687
3475
 
3688
3476
  // src/ssr/attrs.ts
3689
3477
  function renderAttrs(props, opts) {
@@ -3692,8 +3480,11 @@ function renderAttrs(props, opts) {
3692
3480
  }
3693
3481
  let result = "";
3694
3482
  let dangerousHtml;
3695
- for (const [key, value] of Object.entries(props)) {
3483
+ for (const key in props) {
3484
+ if (!Object.prototype.hasOwnProperty.call(props, key)) continue;
3485
+ const value = props[key];
3696
3486
  if (key === "children") continue;
3487
+ if (key === "key" || key === "ref") continue;
3697
3488
  if (key === "dangerouslySetInnerHTML") {
3698
3489
  if (value && typeof value === "object" && "__html" in value) {
3699
3490
  dangerousHtml = String(value.__html);
@@ -3724,45 +3515,57 @@ function renderAttrs(props, opts) {
3724
3515
  }
3725
3516
  return result;
3726
3517
  }
3727
- var init_attrs = __esm({
3728
- "src/ssr/attrs.ts"() {
3729
- "use strict";
3730
- init_escape();
3731
- }
3732
- });
3733
3518
 
3734
3519
  // src/ssr/sink.ts
3735
- var StringSink, StreamSink;
3736
- var init_sink = __esm({
3737
- "src/ssr/sink.ts"() {
3738
- "use strict";
3739
- StringSink = class {
3740
- constructor() {
3741
- this.chunks = [];
3742
- }
3743
- write(html) {
3744
- if (html) this.chunks.push(html);
3745
- }
3746
- end() {
3747
- }
3748
- toString() {
3749
- return this.chunks.join("");
3750
- }
3751
- };
3752
- StreamSink = class {
3753
- constructor(onChunk, onComplete) {
3754
- this.onChunk = onChunk;
3755
- this.onComplete = onComplete;
3756
- }
3757
- write(html) {
3758
- if (html) this.onChunk(html);
3759
- }
3760
- end() {
3761
- this.onComplete();
3762
- }
3763
- };
3520
+ var _StringSink = class _StringSink {
3521
+ constructor() {
3522
+ this.chunks = [];
3523
+ this.bufferChunks = [];
3524
+ this.bufferLen = 0;
3764
3525
  }
3765
- });
3526
+ write(html) {
3527
+ if (!html) return;
3528
+ this.bufferChunks.push(html);
3529
+ this.bufferLen += html.length;
3530
+ if (this.bufferLen >= _StringSink.FLUSH_THRESHOLD) {
3531
+ this.chunks.push(this.bufferChunks.join(""));
3532
+ this.bufferChunks.length = 0;
3533
+ this.bufferLen = 0;
3534
+ }
3535
+ }
3536
+ end() {
3537
+ if (this.bufferLen) {
3538
+ this.chunks.push(this.bufferChunks.join(""));
3539
+ this.bufferChunks.length = 0;
3540
+ this.bufferLen = 0;
3541
+ }
3542
+ }
3543
+ toString() {
3544
+ if (this.bufferLen) {
3545
+ this.chunks.push(this.bufferChunks.join(""));
3546
+ this.bufferChunks.length = 0;
3547
+ this.bufferLen = 0;
3548
+ }
3549
+ return this.chunks.join("");
3550
+ }
3551
+ };
3552
+ // Reduce array churn by batching many small writes into a larger buffer.
3553
+ // This is especially important for large SSR trees where we may write
3554
+ // hundreds of thousands of small fragments.
3555
+ _StringSink.FLUSH_THRESHOLD = 32 * 1024;
3556
+ var StringSink = _StringSink;
3557
+ var StreamSink = class {
3558
+ constructor(onChunk, onComplete) {
3559
+ this.onChunk = onChunk;
3560
+ this.onComplete = onComplete;
3561
+ }
3562
+ write(html) {
3563
+ if (html) this.onChunk(html);
3564
+ }
3565
+ end() {
3566
+ this.onComplete();
3567
+ }
3568
+ };
3766
3569
 
3767
3570
  // src/ssr/stream-render.ts
3768
3571
  function isVNodeLike(x) {
@@ -3790,7 +3593,7 @@ function isPromiseLike(x) {
3790
3593
  const then = x.then;
3791
3594
  return typeof then === "function";
3792
3595
  }
3793
- function executeComponent2(type, props, ctx) {
3596
+ function executeComponent(type, props, ctx) {
3794
3597
  const res = type(props ?? {}, { signal: ctx.signal });
3795
3598
  if (isPromiseLike(res)) {
3796
3599
  throwSSRDataMissing();
@@ -3817,7 +3620,7 @@ function renderNodeToSink(node, sink, ctx) {
3817
3620
  if (typeof type === "function") {
3818
3621
  const out = withSSRContext(
3819
3622
  ctx,
3820
- () => executeComponent2(type, props, ctx)
3623
+ () => executeComponent(type, props, ctx)
3821
3624
  );
3822
3625
  renderNodeToSink(
3823
3626
  out,
@@ -3843,30 +3646,10 @@ function renderNodeToSink(node, sink, ctx) {
3843
3646
  }
3844
3647
  sink.write(`</${tag}>`);
3845
3648
  }
3846
- var init_stream_render = __esm({
3847
- "src/ssr/stream-render.ts"() {
3848
- "use strict";
3849
- init_jsx();
3850
- init_context2();
3851
- init_escape();
3852
- init_attrs();
3853
- }
3854
- });
3855
3649
 
3856
3650
  // src/ssr/index.ts
3857
- var ssr_exports = {};
3858
- __export(ssr_exports, {
3859
- SSRDataMissingError: () => SSRDataMissingError,
3860
- collectResources: () => collectResources,
3861
- popSSRStrictPurityGuard: () => popSSRStrictPurityGuard,
3862
- pushSSRStrictPurityGuard: () => pushSSRStrictPurityGuard,
3863
- renderToStream: () => renderToStream,
3864
- renderToString: () => renderToString,
3865
- renderToStringSync: () => renderToStringSync,
3866
- renderToStringSyncForUrl: () => renderToStringSyncForUrl,
3867
- resolvePlan: () => resolvePlan,
3868
- resolveResources: () => resolveResources
3869
- });
3651
+ process.env.NODE_ENV !== "production" && (process.env.ASKR_SSR_DEBUG === "1" || process.env.ASKR_SSR_DEBUG === "true");
3652
+ var __ssrGuardStack = [];
3870
3653
  function pushSSRStrictPurityGuard() {
3871
3654
  if (process.env.NODE_ENV === "production") return;
3872
3655
  __ssrGuardStack.push({
@@ -3892,65 +3675,80 @@ function popSSRStrictPurityGuard() {
3892
3675
  Reflect.set(Date, "now", prev.now);
3893
3676
  }
3894
3677
  }
3895
- function renderChildSync(child, ctx) {
3896
- if (typeof child === "string") return escapeText(child);
3897
- if (typeof child === "number") return escapeText(String(child));
3898
- if (child === null || child === void 0 || child === false) return "";
3899
- if (typeof child === "object" && child !== null && "type" in child) {
3900
- return renderNodeSync(child, ctx);
3678
+ function renderChildSyncToSink(child, sink, ctx) {
3679
+ if (child === null || child === void 0 || child === false) return;
3680
+ if (typeof child === "string") {
3681
+ sink.write(escapeText(child));
3682
+ return;
3683
+ }
3684
+ if (typeof child === "number") {
3685
+ sink.write(escapeText(String(child)));
3686
+ return;
3687
+ }
3688
+ if (child && typeof child === "object" && "type" in child) {
3689
+ renderNodeSyncToSink(child, sink, ctx);
3901
3690
  }
3902
- return "";
3903
3691
  }
3904
- function renderChildrenSync(children, ctx) {
3905
- if (!children || !Array.isArray(children) || children.length === 0) return "";
3906
- let result = "";
3907
- for (const child of children) result += renderChildSync(child, ctx);
3908
- return result;
3692
+ function renderChildrenSyncToSink(children, sink, ctx) {
3693
+ if (!children || !Array.isArray(children) || children.length === 0) return;
3694
+ for (let i = 0; i < children.length; i++) {
3695
+ renderChildSyncToSink(children[i], sink, ctx);
3696
+ }
3909
3697
  }
3910
- function renderNodeSync(node, ctx) {
3698
+ function renderNodeSyncToSink(node, sink, ctx) {
3911
3699
  const { type, props } = node;
3912
- if (process.env.NODE_ENV !== "production") {
3913
- try {
3914
- logger.warn("[SSR] renderNodeSync type:", typeof type, type);
3915
- } catch {
3916
- }
3917
- }
3918
3700
  if (typeof type === "function") {
3919
3701
  const result = executeComponentSync2(type, props, ctx);
3920
- if (result instanceof Promise) {
3921
- throwSSRDataMissing();
3922
- }
3923
- return renderNodeSync(result, ctx);
3702
+ renderNodeSyncToSink(result, sink, ctx);
3703
+ return;
3924
3704
  }
3925
3705
  if (typeof type === "symbol") {
3926
3706
  if (type === Fragment) {
3927
3707
  const childrenArr = Array.isArray(node.children) ? node.children : Array.isArray(props?.children) ? props?.children : void 0;
3928
- if (process.env.NODE_ENV !== "production") {
3929
- try {
3930
- logger.warn("[SSR] fragment children length:", childrenArr?.length);
3931
- } catch {
3932
- }
3933
- }
3934
- return renderChildrenSync(childrenArr, ctx);
3708
+ renderChildrenSyncToSink(childrenArr, sink, ctx);
3709
+ return;
3935
3710
  }
3936
3711
  throw new Error(
3937
- `renderNodeSync: unsupported VNode symbol type: ${String(type)}`
3712
+ `renderNodeSyncToSink: unsupported VNode symbol type: ${String(type)}`
3938
3713
  );
3939
3714
  }
3940
3715
  const typeStr = type;
3941
3716
  if (VOID_ELEMENTS.has(typeStr)) {
3942
- const attrs2 = renderAttrs(props);
3943
- return `<${typeStr}${attrs2} />`;
3717
+ const attrs2 = props ? renderAttrs(props) : "";
3718
+ sink.write(`<${typeStr}${attrs2} />`);
3719
+ return;
3944
3720
  }
3945
- const { attrs, dangerousHtml } = renderAttrs(props, {
3946
- returnDangerousHtml: true
3947
- });
3948
- if (dangerousHtml !== void 0) {
3949
- return `<${typeStr}${attrs}>${dangerousHtml}</${typeStr}>`;
3721
+ const maybeDangerous = props ? props?.dangerouslySetInnerHTML : void 0;
3722
+ if (maybeDangerous !== void 0 && maybeDangerous !== null) {
3723
+ const { attrs: attrs2, dangerousHtml } = renderAttrs(props, {
3724
+ returnDangerousHtml: true
3725
+ });
3726
+ sink.write(`<${typeStr}${attrs2}>`);
3727
+ if (dangerousHtml !== void 0) {
3728
+ sink.write(dangerousHtml);
3729
+ } else {
3730
+ renderChildrenSyncToSink(node.children, sink, ctx);
3731
+ }
3732
+ sink.write(`</${typeStr}>`);
3733
+ return;
3950
3734
  }
3735
+ const attrs = props ? renderAttrs(props) : "";
3951
3736
  const children = node.children;
3952
- const childrenHtml = renderChildrenSync(children, ctx);
3953
- return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;
3737
+ if (Array.isArray(children) && children.length === 1) {
3738
+ const only = children[0];
3739
+ if (typeof only === "string") {
3740
+ sink.write(`<${typeStr}${attrs}>${escapeText(only)}</${typeStr}>`);
3741
+ return;
3742
+ }
3743
+ if (typeof only === "number") {
3744
+ const escaped = escapeText(String(only));
3745
+ sink.write(`<${typeStr}${attrs}>${escaped}</${typeStr}>`);
3746
+ return;
3747
+ }
3748
+ }
3749
+ sink.write(`<${typeStr}${attrs}>`);
3750
+ renderChildrenSyncToSink(children, sink, ctx);
3751
+ sink.write(`</${typeStr}>`);
3954
3752
  }
3955
3753
  function executeComponentSync2(component, props, ctx) {
3956
3754
  try {
@@ -4019,9 +3817,11 @@ function renderToStringSync(component, props, options) {
4019
3817
  if (!node) {
4020
3818
  throw new Error("renderToStringSync: wrapped component returned empty");
4021
3819
  }
4022
- return renderNodeSync(node, ctx);
3820
+ const sink = new StringSink();
3821
+ renderNodeSyncToSink(node, sink, ctx);
3822
+ sink.end();
3823
+ return sink.toString();
4023
3824
  } finally {
4024
- stopRenderPhase();
4025
3825
  }
4026
3826
  }
4027
3827
  function renderToStringSyncForUrl(opts) {
@@ -4068,9 +3868,11 @@ function renderToStringSyncForUrl(opts) {
4068
3868
  };
4069
3869
  };
4070
3870
  const node = executeComponentSync2(wrapped, resolved.params || {}, ctx);
4071
- return renderNodeSync(node, ctx);
3871
+ const sink = new StringSink();
3872
+ renderNodeSyncToSink(node, sink, ctx);
3873
+ sink.end();
3874
+ return sink.toString();
4072
3875
  } finally {
4073
- stopRenderPhase();
4074
3876
  }
4075
3877
  }
4076
3878
  function renderToString(arg) {
@@ -4113,1079 +3915,12 @@ function renderToSinkInternal(opts) {
4113
3915
  signal: void 0
4114
3916
  };
4115
3917
  const node = resolved.handler(resolved.params);
4116
- startRenderPhase(data || null);
4117
3918
  try {
4118
3919
  renderNodeToSink(node, sink, ctx);
4119
3920
  } finally {
4120
- stopRenderPhase();
4121
- }
4122
- }
4123
- var __ssrGuardStack;
4124
- var init_ssr = __esm({
4125
- "src/ssr/index.ts"() {
4126
- "use strict";
4127
- init_route();
4128
- init_jsx();
4129
- init_portal();
4130
- init_context2();
4131
- init_component();
4132
- init_escape();
4133
- init_attrs();
4134
- init_logger();
4135
- init_context2();
4136
- init_sink();
4137
- init_stream_render();
4138
- init_render_keys();
4139
- __ssrGuardStack = [];
4140
- }
4141
- });
4142
-
4143
- // src/index.ts
4144
- var index_exports = {};
4145
- __export(index_exports, {
4146
- DefaultPortal: () => DefaultPortal,
4147
- Fragment: () => Fragment2,
4148
- Link: () => Link,
4149
- Slot: () => Slot,
4150
- _resetDefaultPortal: () => _resetDefaultPortal,
4151
- cleanupApp: () => cleanupApp,
4152
- clearRoutes: () => clearRoutes,
4153
- collectResources: () => collectResources,
4154
- createIsland: () => createIsland,
4155
- createSPA: () => createSPA,
4156
- defineContext: () => defineContext,
4157
- definePortal: () => definePortal,
4158
- derive: () => derive,
4159
- getLoadedNamespaces: () => getLoadedNamespaces,
4160
- getNamespaceRoutes: () => getNamespaceRoutes,
4161
- getRoutes: () => getRoutes,
4162
- getSignal: () => getSignal,
4163
- hasApp: () => hasApp,
4164
- hydrateSPA: () => hydrateSPA,
4165
- jsx: () => jsx,
4166
- jsxs: () => jsxs,
4167
- layout: () => layout,
4168
- navigate: () => navigate,
4169
- readContext: () => readContext,
4170
- renderToStream: () => renderToStream,
4171
- renderToString: () => renderToString,
4172
- renderToStringSync: () => renderToStringSync,
4173
- renderToStringSyncForUrl: () => renderToStringSyncForUrl,
4174
- resolveResources: () => resolveResources,
4175
- resource: () => resource,
4176
- route: () => route,
4177
- scheduleEventHandler: () => scheduleEventHandler,
4178
- setServerLocation: () => setServerLocation,
4179
- state: () => state,
4180
- task: () => task,
4181
- unloadNamespace: () => unloadNamespace
4182
- });
4183
- module.exports = __toCommonJS(index_exports);
4184
-
4185
- // src/runtime/state.ts
4186
- init_scheduler();
4187
- init_component();
4188
- init_invariant();
4189
- init_fastlane_shared();
4190
- function state(initialValue) {
4191
- const instance = getCurrentInstance();
4192
- if (!instance) {
4193
- throw new Error(
4194
- "state() can only be called during component render execution. Move state() calls to the top level of your component function."
4195
- );
4196
- }
4197
- const index = getNextStateIndex();
4198
- const stateValues = instance.stateValues;
4199
- if (index < instance.stateIndexCheck) {
4200
- throw new Error(
4201
- `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.`
4202
- );
4203
- }
4204
- invariant(
4205
- index >= instance.stateIndexCheck,
4206
- "[State] State indices must increase monotonically"
4207
- );
4208
- instance.stateIndexCheck = index;
4209
- if (instance.firstRenderComplete) {
4210
- if (!instance.expectedStateIndices.includes(index)) {
4211
- throw new Error(
4212
- `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.`
4213
- );
4214
- }
4215
- } else {
4216
- instance.expectedStateIndices.push(index);
4217
- }
4218
- if (stateValues[index]) {
4219
- const existing = stateValues[index];
4220
- if (existing._owner !== instance) {
4221
- throw new Error(
4222
- `State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
4223
- );
4224
- }
4225
- return existing;
4226
- }
4227
- const cell = createStateCell(initialValue, instance);
4228
- stateValues[index] = cell;
4229
- return cell;
4230
- }
4231
- function createStateCell(initialValue, instance) {
4232
- let value = initialValue;
4233
- const readers = /* @__PURE__ */ new Map();
4234
- function read() {
4235
- read._hasBeenRead = true;
4236
- const inst = getCurrentInstance();
4237
- if (inst && inst._currentRenderToken !== void 0) {
4238
- if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
4239
- inst._pendingReadStates.add(read);
4240
- }
4241
- return value;
4242
- }
4243
- read._readers = readers;
4244
- read._owner = instance;
4245
- read.set = (newValueOrUpdater) => {
4246
- const currentInst = getCurrentInstance();
4247
- if (currentInst !== null && process.env.NODE_ENV !== "production") {
4248
- throw new Error(
4249
- `[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.`
4250
- );
4251
- }
4252
- if (currentInst !== null && process.env.NODE_ENV === "production") {
4253
- if (typeof console !== "undefined" && console.warn) {
4254
- console.warn(
4255
- "[Askr] state.set() called during render - update skipped. Move state updates to event handlers."
4256
- );
4257
- }
4258
- return;
4259
- }
4260
- let newValue;
4261
- if (typeof newValueOrUpdater === "function") {
4262
- const updater = newValueOrUpdater;
4263
- newValue = updater(value);
4264
- } else {
4265
- newValue = newValueOrUpdater;
4266
- }
4267
- if (Object.is(value, newValue)) return;
4268
- if (isBulkCommitActive2()) {
4269
- value = newValue;
4270
- return;
4271
- }
4272
- value = newValue;
4273
- const readersMap = read._readers;
4274
- if (readersMap) {
4275
- for (const [subInst, token] of readersMap) {
4276
- if (subInst.lastRenderToken !== token) continue;
4277
- if (!subInst.hasPendingUpdate) {
4278
- subInst.hasPendingUpdate = true;
4279
- const subTask = subInst._pendingFlushTask;
4280
- if (subTask) globalScheduler.enqueue(subTask);
4281
- else
4282
- globalScheduler.enqueue(() => {
4283
- subInst.hasPendingUpdate = false;
4284
- subInst.notifyUpdate?.();
4285
- });
4286
- }
4287
- }
4288
- }
4289
- const readersMapForOwner = readersMap;
4290
- const ownerRecordedToken = readersMapForOwner?.get(instance);
4291
- const ownerShouldEnqueue = (
4292
- // Normal case: owner read this state in last committed render
4293
- ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
4294
- );
4295
- if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
4296
- instance.hasPendingUpdate = true;
4297
- const task2 = instance._pendingFlushTask;
4298
- if (task2) globalScheduler.enqueue(task2);
4299
- else
4300
- globalScheduler.enqueue(() => {
4301
- instance.hasPendingUpdate = false;
4302
- instance.notifyUpdate?.();
4303
- });
4304
- }
4305
- };
4306
- return read;
4307
- }
4308
-
4309
- // src/index.ts
4310
- init_component();
4311
- init_scheduler();
4312
- init_context();
4313
-
4314
- // src/runtime/operations.ts
4315
- init_component();
4316
- init_context();
4317
-
4318
- // src/runtime/resource-cell.ts
4319
- init_context();
4320
- init_logger();
4321
- init_context2();
4322
- var ResourceCell = class {
4323
- constructor(fn, deps, resourceFrame) {
4324
- this.value = null;
4325
- this.pending = true;
4326
- this.error = null;
4327
- this.generation = 0;
4328
- this.controller = null;
4329
- this.deps = null;
4330
- this.resourceFrame = null;
4331
- this.subscribers = /* @__PURE__ */ new Set();
4332
- this.fn = fn;
4333
- this.deps = deps ? deps.slice() : null;
4334
- this.resourceFrame = resourceFrame;
4335
- this.snapshot = {
4336
- value: null,
4337
- pending: true,
4338
- error: null,
4339
- refresh: () => this.refresh()
4340
- };
4341
- }
4342
- subscribe(cb) {
4343
- this.subscribers.add(cb);
4344
- return () => this.subscribers.delete(cb);
4345
- }
4346
- notifySubscribers() {
4347
- this.snapshot.value = this.value;
4348
- this.snapshot.pending = this.pending;
4349
- this.snapshot.error = this.error;
4350
- for (const cb of this.subscribers) cb();
4351
- }
4352
- start(ssr = false, notify = true) {
4353
- const generation = this.generation;
4354
- this.controller?.abort();
4355
- const controller = new AbortController();
4356
- this.controller = controller;
4357
- this.pending = true;
4358
- this.error = null;
4359
- if (notify) this.notifySubscribers();
4360
- let result;
4361
- try {
4362
- result = withAsyncResourceContext(
4363
- this.resourceFrame,
4364
- () => this.fn({ signal: controller.signal })
4365
- );
4366
- } catch (err) {
4367
- this.pending = false;
4368
- this.error = err;
4369
- if (notify) this.notifySubscribers();
4370
- return;
4371
- }
4372
- if (!(result instanceof Promise)) {
4373
- this.value = result;
4374
- this.pending = false;
4375
- this.error = null;
4376
- if (notify) this.notifySubscribers();
4377
- return;
4378
- }
4379
- if (ssr) {
4380
- throwSSRDataMissing();
4381
- }
4382
- result.then((val) => {
4383
- if (this.generation !== generation) return;
4384
- if (this.controller !== controller) return;
4385
- this.value = val;
4386
- this.pending = false;
4387
- this.error = null;
4388
- this.notifySubscribers();
4389
- }).catch((err) => {
4390
- if (this.generation !== generation) return;
4391
- this.pending = false;
4392
- this.error = err;
4393
- try {
4394
- if (this.ownerName) {
4395
- logger.error(
4396
- `[Askr] Async resource error in ${this.ownerName}:`,
4397
- err
4398
- );
4399
- } else {
4400
- logger.error("[Askr] Async resource error:", err);
4401
- }
4402
- } catch {
4403
- }
4404
- this.notifySubscribers();
4405
- });
4406
- }
4407
- refresh() {
4408
- this.generation++;
4409
- this.controller?.abort();
4410
- this.start();
4411
- }
4412
- abort() {
4413
- this.controller?.abort();
4414
- }
4415
- };
4416
-
4417
- // src/shared/derive-cache.ts
4418
- var deriveCacheMap = /* @__PURE__ */ new WeakMap();
4419
- function getDeriveCache(instance) {
4420
- let cache = deriveCacheMap.get(instance);
4421
- if (!cache) {
4422
- cache = /* @__PURE__ */ new Map();
4423
- deriveCacheMap.set(instance, cache);
4424
- }
4425
- return cache;
4426
- }
4427
-
4428
- // src/runtime/operations.ts
4429
- init_context2();
4430
- init_render_keys();
4431
- function resource(fn, deps = []) {
4432
- const instance = getCurrentComponentInstance();
4433
- const inst = instance;
4434
- if (!instance) {
4435
- const renderData2 = getCurrentRenderData();
4436
- if (renderData2) {
4437
- const key = getNextKey();
4438
- if (!(key in renderData2)) {
4439
- throwSSRDataMissing();
4440
- }
4441
- const val = renderData2[key];
4442
- return {
4443
- value: val,
4444
- pending: false,
4445
- error: null,
4446
- refresh: () => {
4447
- }
4448
- };
4449
- }
4450
- const ssrCtx = getCurrentSSRContext();
4451
- if (ssrCtx) {
4452
- throwSSRDataMissing();
4453
- }
4454
- return {
4455
- value: null,
4456
- pending: true,
4457
- error: null,
4458
- refresh: () => {
4459
- }
4460
- };
4461
- }
4462
- const renderData = getCurrentRenderData();
4463
- if (renderData) {
4464
- const key = getNextKey();
4465
- if (!(key in renderData)) {
4466
- throwSSRDataMissing();
4467
- }
4468
- const val = renderData[key];
4469
- const holder2 = state({
4470
- cell: void 0,
4471
- snapshot: {
4472
- value: val,
4473
- pending: false,
4474
- error: null,
4475
- refresh: () => {
4476
- }
4477
- }
4478
- });
4479
- const h2 = holder2();
4480
- h2.snapshot.value = val;
4481
- h2.snapshot.pending = false;
4482
- h2.snapshot.error = null;
4483
- holder2.set(h2);
4484
- return h2.snapshot;
4485
- }
4486
- const holder = state({
4487
- cell: void 0,
4488
- snapshot: {
4489
- value: null,
4490
- pending: true,
4491
- error: null,
4492
- refresh: () => {
4493
- }
4494
- }
4495
- });
4496
- const h = holder();
4497
- if (!h.cell) {
4498
- const frame = getCurrentContextFrame();
4499
- const cell2 = new ResourceCell(fn, deps, frame);
4500
- cell2.ownerName = inst.fn?.name || "<anonymous>";
4501
- h.cell = cell2;
4502
- h.snapshot = cell2.snapshot;
4503
- const unsubscribe = cell2.subscribe(() => {
4504
- const cur = holder();
4505
- cur.snapshot.value = cell2.snapshot.value;
4506
- cur.snapshot.pending = cell2.snapshot.pending;
4507
- cur.snapshot.error = cell2.snapshot.error;
4508
- holder.set(cur);
4509
- try {
4510
- inst._enqueueRun?.();
4511
- } catch {
4512
- }
4513
- });
4514
- inst.cleanupFns.push(() => {
4515
- unsubscribe();
4516
- cell2.abort();
4517
- });
4518
- try {
4519
- cell2.start(inst.ssr ?? false, false);
4520
- if (!cell2.pending) {
4521
- const cur = holder();
4522
- cur.snapshot.value = cell2.value;
4523
- cur.snapshot.pending = cell2.pending;
4524
- cur.snapshot.error = cell2.error;
4525
- }
4526
- } catch (err) {
4527
- if (err instanceof SSRDataMissingError) throw err;
4528
- cell2.error = err;
4529
- cell2.pending = false;
4530
- const cur = holder();
4531
- cur.snapshot.value = cell2.value;
4532
- cur.snapshot.pending = cell2.pending;
4533
- cur.snapshot.error = cell2.error;
4534
- }
4535
- }
4536
- const cell = h.cell;
4537
- const depsChanged = !cell.deps || cell.deps.length !== deps.length || cell.deps.some((d, i) => d !== deps[i]);
4538
- if (depsChanged) {
4539
- cell.deps = deps.slice();
4540
- cell.generation++;
4541
- cell.pending = true;
4542
- cell.error = null;
4543
- try {
4544
- cell.start(inst.ssr ?? false, false);
4545
- if (!cell.pending) {
4546
- const cur = holder();
4547
- cur.snapshot.value = cell.value;
4548
- cur.snapshot.pending = cell.pending;
4549
- cur.snapshot.error = cell.error;
4550
- }
4551
- } catch (err) {
4552
- if (err instanceof SSRDataMissingError) throw err;
4553
- cell.error = err;
4554
- cell.pending = false;
4555
- const cur = holder();
4556
- cur.snapshot.value = cell.value;
4557
- cur.snapshot.pending = cell.pending;
4558
- cur.snapshot.error = cell.error;
4559
- }
4560
- }
4561
- return h.snapshot;
4562
- }
4563
- function derive(source, map) {
4564
- if (map === void 0 && typeof source === "function") {
4565
- const value2 = source();
4566
- if (value2 == null) return null;
4567
- const instance2 = getCurrentComponentInstance();
4568
- if (!instance2) {
4569
- return value2;
4570
- }
4571
- const cache2 = getDeriveCache(instance2);
4572
- if (cache2.has(value2)) return cache2.get(value2);
4573
- cache2.set(value2, value2);
4574
- return value2;
4575
- }
4576
- let value;
4577
- if (typeof source === "function" && !("value" in source)) {
4578
- value = source();
4579
- } else {
4580
- value = source?.value ?? source;
4581
3921
  }
4582
- if (value == null) return null;
4583
- const instance = getCurrentComponentInstance();
4584
- if (!instance) {
4585
- return map(value);
4586
- }
4587
- const cache = getDeriveCache(instance);
4588
- if (cache.has(value)) {
4589
- return cache.get(value);
4590
- }
4591
- const result = map(value);
4592
- cache.set(value, result);
4593
- return result;
4594
- }
4595
- function task(fn) {
4596
- const ownerIsRoot = getCurrentComponentInstance()?.isRoot ?? false;
4597
- registerMountOperation(async () => {
4598
- if (!ownerIsRoot) {
4599
- throw new Error("[Askr] task() may only be used in root components");
4600
- }
4601
- return await fn();
4602
- });
4603
3922
  }
4604
3923
 
4605
- // src/boot/index.ts
4606
- init_component();
4607
- init_scheduler();
4608
- init_logger();
4609
- init_navigate();
4610
- init_jsx();
4611
- init_portal();
4612
- init_renderer();
4613
- var componentIdCounter = 0;
4614
- var instancesByRoot = /* @__PURE__ */ new WeakMap();
4615
- var CLEANUP_SYMBOL = /* @__PURE__ */ Symbol.for("__tempoCleanup__");
4616
- function attachCleanupForRoot(rootElement, instance) {
4617
- rootElement[CLEANUP_SYMBOL] = () => {
4618
- const errors = [];
4619
- try {
4620
- removeAllListeners(rootElement);
4621
- } catch (e) {
4622
- errors.push(e);
4623
- }
4624
- try {
4625
- const descendants = rootElement.querySelectorAll("*");
4626
- for (const d of Array.from(descendants)) {
4627
- try {
4628
- const inst = d.__ASKR_INSTANCE;
4629
- if (inst) {
4630
- try {
4631
- cleanupComponent(inst);
4632
- } catch (err) {
4633
- errors.push(err);
4634
- }
4635
- try {
4636
- delete d.__ASKR_INSTANCE;
4637
- } catch (err) {
4638
- errors.push(err);
4639
- }
4640
- }
4641
- } catch (err) {
4642
- errors.push(err);
4643
- }
4644
- }
4645
- } catch (e) {
4646
- errors.push(e);
4647
- }
4648
- try {
4649
- cleanupComponent(instance);
4650
- } catch (e) {
4651
- errors.push(e);
4652
- }
4653
- if (errors.length > 0) {
4654
- if (instance.cleanupStrict) {
4655
- throw new AggregateError(errors, `cleanup failed for app root`);
4656
- } else if (process.env.NODE_ENV !== "production") {
4657
- for (const err of errors) logger.warn("[Askr] cleanup error:", err);
4658
- }
4659
- }
4660
- };
4661
- try {
4662
- const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(
4663
- Object.getPrototypeOf(rootElement),
4664
- "innerHTML"
4665
- ) || Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
4666
- if (descriptor && (descriptor.get || descriptor.set)) {
4667
- Object.defineProperty(rootElement, "innerHTML", {
4668
- get: descriptor.get ? function() {
4669
- return descriptor.get.call(this);
4670
- } : void 0,
4671
- set: function(value) {
4672
- if (value === "" && instancesByRoot.get(this) === instance) {
4673
- try {
4674
- removeAllListeners(rootElement);
4675
- } catch (e) {
4676
- if (instance.cleanupStrict) throw e;
4677
- if (process.env.NODE_ENV !== "production")
4678
- logger.warn("[Askr] cleanup error:", e);
4679
- }
4680
- try {
4681
- cleanupComponent(instance);
4682
- } catch (e) {
4683
- if (instance.cleanupStrict) throw e;
4684
- if (process.env.NODE_ENV !== "production")
4685
- logger.warn("[Askr] cleanup error:", e);
4686
- }
4687
- }
4688
- if (descriptor.set) {
4689
- return descriptor.set.call(this, value);
4690
- }
4691
- },
4692
- configurable: true
4693
- });
4694
- }
4695
- } catch {
4696
- }
4697
- }
4698
- function mountOrUpdate(rootElement, componentFn, options) {
4699
- const wrappedFn = (props, ctx) => {
4700
- const out = componentFn(props, ctx);
4701
- const portalVNode = {
4702
- $$typeof: ELEMENT_TYPE,
4703
- type: DefaultPortal,
4704
- props: {},
4705
- key: "__default_portal"
4706
- };
4707
- return {
4708
- $$typeof: ELEMENT_TYPE,
4709
- type: Fragment,
4710
- props: {
4711
- children: out === void 0 || out === null ? [portalVNode] : [out, portalVNode]
4712
- }
4713
- };
4714
- };
4715
- Object.defineProperty(wrappedFn, "name", {
4716
- value: componentFn.name || "Component"
4717
- });
4718
- const existingCleanup = rootElement[CLEANUP_SYMBOL];
4719
- if (existingCleanup) existingCleanup();
4720
- let instance = instancesByRoot.get(rootElement);
4721
- if (instance) {
4722
- removeAllListeners(rootElement);
4723
- try {
4724
- cleanupComponent(instance);
4725
- } catch (e) {
4726
- if (process.env.NODE_ENV !== "production")
4727
- logger.warn("[Askr] prior cleanup threw:", e);
4728
- }
4729
- instance.fn = wrappedFn;
4730
- instance.evaluationGeneration++;
4731
- instance.mounted = false;
4732
- instance.expectedStateIndices = [];
4733
- instance.firstRenderComplete = false;
4734
- instance.isRoot = true;
4735
- if (options && typeof options.cleanupStrict === "boolean") {
4736
- instance.cleanupStrict = options.cleanupStrict;
4737
- }
4738
- } else {
4739
- const componentId = String(++componentIdCounter);
4740
- instance = createComponentInstance(componentId, wrappedFn, {}, rootElement);
4741
- instancesByRoot.set(rootElement, instance);
4742
- instance.isRoot = true;
4743
- if (options && typeof options.cleanupStrict === "boolean") {
4744
- instance.cleanupStrict = options.cleanupStrict;
4745
- }
4746
- }
4747
- attachCleanupForRoot(rootElement, instance);
4748
- mountComponent(instance);
4749
- globalScheduler.flush();
4750
- }
4751
- function createIsland(config) {
4752
- if (!config || typeof config !== "object") {
4753
- throw new Error("createIsland requires a config object");
4754
- }
4755
- if (typeof config.component !== "function") {
4756
- throw new Error("createIsland: component must be a function");
4757
- }
4758
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4759
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4760
- if ("routes" in config) {
4761
- throw new Error(
4762
- "createIsland does not accept routes; use createSPA for routed apps"
4763
- );
4764
- }
4765
- mountOrUpdate(rootElement, config.component, {
4766
- cleanupStrict: config.cleanupStrict
4767
- });
4768
- }
4769
- async function createSPA(config) {
4770
- if (!config || typeof config !== "object") {
4771
- throw new Error("createSPA requires a config object");
4772
- }
4773
- if (!Array.isArray(config.routes) || config.routes.length === 0) {
4774
- throw new Error(
4775
- "createSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
4776
- );
4777
- }
4778
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4779
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4780
- const { clearRoutes: clearRoutes2, route: route2, lockRouteRegistration: lockRouteRegistration2, resolveRoute: resolveRoute2 } = await Promise.resolve().then(() => (init_route(), route_exports));
4781
- clearRoutes2();
4782
- for (const r of config.routes) {
4783
- route2(r.path, r.handler, r.namespace);
4784
- }
4785
- if (process.env.NODE_ENV === "production") lockRouteRegistration2();
4786
- const path = typeof window !== "undefined" ? window.location.pathname : "/";
4787
- const resolved = resolveRoute2(path);
4788
- if (!resolved) {
4789
- if (process.env.NODE_ENV !== "production") {
4790
- logger.warn(
4791
- `createSPA: no route found for current path (${path}). Mounting empty placeholder; navigation will activate routes when requested.`
4792
- );
4793
- }
4794
- mountOrUpdate(rootElement, () => ({ type: "div", children: [] }), {
4795
- cleanupStrict: false
4796
- });
4797
- const instance2 = instancesByRoot.get(rootElement);
4798
- if (!instance2) throw new Error("Internal error: app instance missing");
4799
- registerAppInstance(instance2, path);
4800
- initializeNavigation();
4801
- return;
4802
- }
4803
- mountOrUpdate(rootElement, resolved.handler, {
4804
- cleanupStrict: false
4805
- });
4806
- const instance = instancesByRoot.get(rootElement);
4807
- if (!instance) throw new Error("Internal error: app instance missing");
4808
- registerAppInstance(instance, path);
4809
- initializeNavigation();
4810
- }
4811
- async function hydrateSPA(config) {
4812
- if (!config || typeof config !== "object") {
4813
- throw new Error("hydrateSPA requires a config object");
4814
- }
4815
- if (!Array.isArray(config.routes) || config.routes.length === 0) {
4816
- throw new Error(
4817
- "hydrateSPA requires a route table. If you are enhancing existing HTML, use createIsland instead."
4818
- );
4819
- }
4820
- const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
4821
- if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
4822
- const serverHTML = rootElement.innerHTML;
4823
- const {
4824
- clearRoutes: clearRoutes2,
4825
- route: route2,
4826
- setServerLocation: setServerLocation2,
4827
- lockRouteRegistration: lockRouteRegistration2,
4828
- resolveRoute: resolveRoute2
4829
- } = await Promise.resolve().then(() => (init_route(), route_exports));
4830
- clearRoutes2();
4831
- for (const r of config.routes) {
4832
- route2(r.path, r.handler, r.namespace);
4833
- }
4834
- const path = typeof window !== "undefined" ? window.location.pathname : "/";
4835
- setServerLocation2(path);
4836
- if (process.env.NODE_ENV === "production") lockRouteRegistration2();
4837
- const resolved = resolveRoute2(path);
4838
- if (!resolved) {
4839
- throw new Error(`hydrateSPA: no route found for current path (${path}).`);
4840
- }
4841
- const { renderToStringSync: renderToStringSync2 } = await Promise.resolve().then(() => (init_ssr(), ssr_exports));
4842
- const expectedHTML = renderToStringSync2(() => {
4843
- const out = resolved.handler(resolved.params);
4844
- return out ?? {
4845
- type: "div",
4846
- children: []
4847
- };
4848
- });
4849
- const serverContainer = document.createElement("div");
4850
- serverContainer.innerHTML = serverHTML;
4851
- const expectedContainer = document.createElement("div");
4852
- expectedContainer.innerHTML = expectedHTML;
4853
- if (!serverContainer.isEqualNode(expectedContainer)) {
4854
- throw new Error(
4855
- "[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output."
4856
- );
4857
- }
4858
- mountOrUpdate(rootElement, resolved.handler, {
4859
- cleanupStrict: false
4860
- });
4861
- const { registerAppInstance: registerAppInstance2, initializeNavigation: initializeNavigation2 } = await Promise.resolve().then(() => (init_navigate(), navigate_exports));
4862
- const instance = instancesByRoot.get(rootElement);
4863
- if (!instance) throw new Error("Internal error: app instance missing");
4864
- registerAppInstance2(instance, path);
4865
- initializeNavigation2();
4866
- }
4867
- function cleanupApp(root) {
4868
- const rootElement = typeof root === "string" ? document.getElementById(root) : root;
4869
- if (!rootElement) return;
4870
- const cleanupFn = rootElement[CLEANUP_SYMBOL];
4871
- if (typeof cleanupFn === "function") {
4872
- cleanupFn();
4873
- }
4874
- instancesByRoot.delete(rootElement);
4875
- }
4876
- function hasApp(root) {
4877
- const rootElement = typeof root === "string" ? document.getElementById(root) : root;
4878
- if (!rootElement) return false;
4879
- return instancesByRoot.has(rootElement);
4880
- }
4881
-
4882
- // src/index.ts
4883
- init_route();
4884
- init_route();
4885
- init_navigate();
4886
-
4887
- // src/components/Link.tsx
4888
- init_navigate();
4889
- function Link({ href, children }) {
4890
- return {
4891
- type: "a",
4892
- props: {
4893
- href,
4894
- children,
4895
- onClick: (e) => {
4896
- const event = e;
4897
- const button = event.button ?? 0;
4898
- if (button !== 0 || // not left-click
4899
- event.ctrlKey || // Ctrl/Cmd+click
4900
- event.metaKey || // Cmd on Mac
4901
- event.shiftKey || // Shift+click
4902
- event.altKey) {
4903
- return;
4904
- }
4905
- event.preventDefault();
4906
- navigate(href);
4907
- }
4908
- }
4909
- };
4910
- }
4911
-
4912
- // src/foundations/layout.tsx
4913
- function layout(Layout) {
4914
- return (children, props) => Layout({ ...props, children });
4915
- }
4916
-
4917
- // src/foundations/slot.tsx
4918
- init_logger();
4919
- init_jsx();
4920
- function Slot(props) {
4921
- if (props.asChild) {
4922
- const { children, ...rest } = props;
4923
- if (isElement(children)) {
4924
- return cloneElement(children, rest);
4925
- }
4926
- logger.warn("<Slot asChild> expects a single JSX element child.");
4927
- return null;
4928
- }
4929
- return {
4930
- $$typeof: ELEMENT_TYPE,
4931
- type: Fragment,
4932
- props: { children: props.children }
4933
- };
4934
- }
4935
-
4936
- // src/index.ts
4937
- init_portal();
4938
- init_ssr();
4939
- init_jsx_runtime();
4940
- init_route();
4941
- init_navigate();
4942
-
4943
- // src/runtime/fastlane.ts
4944
- init_scheduler();
4945
- init_logger();
4946
- init_component();
4947
- init_renderer();
4948
- init_fastlane_shared();
4949
- init_types2();
4950
- init_dev_namespace();
4951
- function unwrapFragmentForFastPath(vnode) {
4952
- if (!vnode || typeof vnode !== "object" || !("type" in vnode)) return vnode;
4953
- const v = vnode;
4954
- if (typeof v.type === "symbol" && (v.type === Fragment || String(v.type) === "Symbol(askr.fragment)")) {
4955
- const children = v.children || v.props?.children;
4956
- if (Array.isArray(children) && children.length > 0) {
4957
- for (const child of children) {
4958
- if (child && typeof child === "object" && "type" in child) {
4959
- const c = child;
4960
- if (typeof c.type === "string") {
4961
- return child;
4962
- }
4963
- }
4964
- }
4965
- }
4966
- }
4967
- return vnode;
4968
- }
4969
- function classifyUpdate(instance, result) {
4970
- const unwrappedResult = unwrapFragmentForFastPath(result);
4971
- if (!unwrappedResult || typeof unwrappedResult !== "object" || !("type" in unwrappedResult))
4972
- return { useFastPath: false, reason: "not-vnode" };
4973
- const vnode = unwrappedResult;
4974
- if (vnode == null || typeof vnode.type !== "string")
4975
- return { useFastPath: false, reason: "not-intrinsic" };
4976
- const parent = instance.target;
4977
- if (!parent) return { useFastPath: false, reason: "no-root" };
4978
- const firstChild = parent.children[0];
4979
- if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
4980
- if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
4981
- return { useFastPath: false, reason: "root-tag-mismatch" };
4982
- const children = vnode.children || vnode.props?.children;
4983
- if (!Array.isArray(children))
4984
- return { useFastPath: false, reason: "no-children-array" };
4985
- for (const c of children) {
4986
- if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
4987
- return { useFastPath: false, reason: "component-child-present" };
4988
- }
4989
- }
4990
- if (instance.mountOperations.length > 0)
4991
- return { useFastPath: false, reason: "pending-mounts" };
4992
- try {
4993
- populateKeyMapForElement(firstChild);
4994
- } catch {
4995
- }
4996
- const oldKeyMap = getKeyMapForElement(firstChild);
4997
- const decision = isKeyedReorderFastPathEligible(
4998
- firstChild,
4999
- children,
5000
- oldKeyMap
5001
- );
5002
- if (!decision.useFastPath || decision.totalKeyed < 128)
5003
- return { ...decision, useFastPath: false, reason: "renderer-declined" };
5004
- return { ...decision, useFastPath: true };
5005
- }
5006
- function commitReorderOnly(instance, result) {
5007
- const evaluate2 = globalThis.__ASKR_RENDERER?.evaluate;
5008
- if (typeof evaluate2 !== "function") {
5009
- logger.warn(
5010
- "[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
5011
- );
5012
- return false;
5013
- }
5014
- const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
5015
- enterBulkCommit();
5016
- try {
5017
- globalScheduler.runWithSyncProgress(() => {
5018
- evaluate2(result, instance.target);
5019
- try {
5020
- finalizeReadSubscriptions(instance);
5021
- } catch (e) {
5022
- if (process.env.NODE_ENV !== "production") throw e;
5023
- }
5024
- });
5025
- const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
5026
- setDevValue("__FASTLANE_CLEARED_AFTER", clearedAfter);
5027
- if (process.env.NODE_ENV !== "production") {
5028
- validateFastLaneInvariants(instance, schedBefore);
5029
- }
5030
- return true;
5031
- } finally {
5032
- exitBulkCommit();
5033
- }
5034
- if (process.env.NODE_ENV !== "production") {
5035
- if (isBulkCommitActive2()) {
5036
- throw new Error(
5037
- "Fast-lane invariant violated: bulk commit flag still set after commit"
5038
- );
5039
- }
5040
- }
5041
- }
5042
- function validateFastLaneInvariants(instance, schedBefore) {
5043
- const commitCount = getDevValue("__LAST_FASTPATH_COMMIT_COUNT") ?? 0;
5044
- const invariants = {
5045
- commitCount,
5046
- mountOps: instance.mountOperations.length,
5047
- cleanupFns: instance.cleanupFns.length
5048
- };
5049
- setDevValue("__LAST_FASTLANE_INVARIANTS", invariants);
5050
- if (commitCount !== 1) {
5051
- console.error(
5052
- "[FASTLANE][INV] commitCount",
5053
- commitCount,
5054
- "diag",
5055
- globalThis.__ASKR_DIAG
5056
- );
5057
- throw new Error(
5058
- "Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
5059
- );
5060
- }
5061
- if (invariants.mountOps > 0) {
5062
- throw new Error(
5063
- "Fast-lane invariant violated: mount operations were registered during bulk commit"
5064
- );
5065
- }
5066
- if (invariants.cleanupFns > 0) {
5067
- throw new Error(
5068
- "Fast-lane invariant violated: cleanup functions were added during bulk commit"
5069
- );
5070
- }
5071
- const schedAfter = globalScheduler.getState();
5072
- if (schedBefore && schedAfter && schedAfter.taskCount > schedBefore.taskCount) {
5073
- console.error(
5074
- "[FASTLANE] schedBefore, schedAfter",
5075
- schedBefore,
5076
- schedAfter
5077
- );
5078
- console.error("[FASTLANE] enqueue logs", getDevValue("__ENQUEUE_LOGS"));
5079
- throw new Error(
5080
- "Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
5081
- );
5082
- }
5083
- let finalState = globalScheduler.getState();
5084
- const executing = globalScheduler.isExecuting();
5085
- let outstandingAfter = Math.max(
5086
- 0,
5087
- finalState.taskCount - (executing ? 1 : 0)
5088
- );
5089
- if (outstandingAfter !== 0) {
5090
- let attempts = 0;
5091
- while (attempts < 5) {
5092
- const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
5093
- if (cleared === 0) break;
5094
- attempts++;
5095
- }
5096
- finalState = globalScheduler.getState();
5097
- outstandingAfter = Math.max(
5098
- 0,
5099
- finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
5100
- );
5101
- if (outstandingAfter !== 0) {
5102
- console.error(
5103
- "[FASTLANE] Post-commit enqueue logs:",
5104
- getDevValue("__ENQUEUE_LOGS")
5105
- );
5106
- console.error(
5107
- "[FASTLANE] Cleared counts:",
5108
- getDevValue("__FASTLANE_CLEARED_TASKS"),
5109
- getDevValue("__FASTLANE_CLEARED_AFTER")
5110
- );
5111
- throw new Error(
5112
- `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
5113
- );
5114
- }
5115
- }
5116
- }
5117
- function tryRuntimeFastLaneSync(instance, result) {
5118
- const cls = classifyUpdate(instance, result);
5119
- if (!cls.useFastPath) {
5120
- setDevValue("__LAST_FASTPATH_STATS", void 0);
5121
- setDevValue("__LAST_FASTPATH_COMMIT_COUNT", 0);
5122
- return false;
5123
- }
5124
- try {
5125
- return commitReorderOnly(instance, result);
5126
- } catch (err) {
5127
- if (process.env.NODE_ENV !== "production") throw err;
5128
- return false;
5129
- }
5130
- }
5131
- if (typeof globalThis !== "undefined") {
5132
- globalThis.__ASKR_FASTLANE = {
5133
- isBulkCommitActive: isBulkCommitActive2,
5134
- enterBulkCommit,
5135
- exitBulkCommit,
5136
- tryRuntimeFastLaneSync,
5137
- markFastPathApplied,
5138
- isFastPathApplied
5139
- };
5140
- }
5141
-
5142
- // src/index.ts
5143
- if (typeof globalThis !== "undefined") {
5144
- const g = globalThis;
5145
- if (!g.createIsland) g.createIsland = createIsland;
5146
- if (!g.createSPA) g.createSPA = createSPA;
5147
- if (!g.hydrateSPA) g.hydrateSPA = hydrateSPA;
5148
- if (!g.route) g.route = route;
5149
- if (!g.getRoutes) g.getRoutes = getRoutes;
5150
- if (!g.navigate) g.navigate = navigate;
5151
- }
5152
- // Annotate the CommonJS export names for ESM import in node:
5153
- 0 && (module.exports = {
5154
- DefaultPortal,
5155
- Fragment,
5156
- Link,
5157
- Slot,
5158
- _resetDefaultPortal,
5159
- cleanupApp,
5160
- clearRoutes,
5161
- collectResources,
5162
- createIsland,
5163
- createSPA,
5164
- defineContext,
5165
- definePortal,
5166
- derive,
5167
- getLoadedNamespaces,
5168
- getNamespaceRoutes,
5169
- getRoutes,
5170
- getSignal,
5171
- hasApp,
5172
- hydrateSPA,
5173
- jsx,
5174
- jsxs,
5175
- layout,
5176
- navigate,
5177
- readContext,
5178
- renderToStream,
5179
- renderToString,
5180
- renderToStringSync,
5181
- renderToStringSyncForUrl,
5182
- resolveResources,
5183
- resource,
5184
- route,
5185
- scheduleEventHandler,
5186
- setServerLocation,
5187
- state,
5188
- task,
5189
- unloadNamespace
5190
- });
5191
- //# sourceMappingURL=index.cjs.map
3924
+ export { SSRDataMissingError, collectResources, popSSRStrictPurityGuard, pushSSRStrictPurityGuard, renderToStream, renderToString, renderToStringSync, renderToStringSyncForUrl, resolvePlan, resolveResources };
3925
+ //# sourceMappingURL=ssr.js.map
3926
+ //# sourceMappingURL=ssr.js.map