@askrjs/askr 0.0.2 → 0.0.4
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.
- package/README.md +8 -5
- package/dist/chunk-64C7W2AE.js +43 -0
- package/dist/chunk-64C7W2AE.js.map +1 -0
- package/dist/chunk-6FLMH4EL.js +124 -0
- package/dist/chunk-6FLMH4EL.js.map +1 -0
- package/dist/chunk-FJUXFA72.js +16 -0
- package/dist/chunk-FJUXFA72.js.map +1 -0
- package/dist/chunk-SALJX5PZ.js +26 -0
- package/dist/{chunk-KR6HG7HF.js.map → chunk-SALJX5PZ.js.map} +1 -1
- package/dist/{chunk-RJWOOUYV.js → chunk-VRAEBIJ3.js} +7 -9
- package/dist/chunk-VRAEBIJ3.js.map +1 -0
- package/dist/chunk-WTFWRSHB.js +98 -0
- package/dist/chunk-WTFWRSHB.js.map +1 -0
- package/dist/chunk-XHKZGJE3.js +2907 -0
- package/dist/chunk-XHKZGJE3.js.map +1 -0
- package/dist/chunk-Z5ZSTLYF.js +420 -0
- package/dist/chunk-Z5ZSTLYF.js.map +1 -0
- package/dist/fx/index.cjs +1193 -0
- package/dist/fx/index.cjs.map +1 -0
- package/dist/fx/index.d.cts +186 -0
- package/dist/fx/index.d.ts +186 -0
- package/dist/fx/index.js +418 -0
- package/dist/fx/index.js.map +1 -0
- package/dist/index.cjs +3020 -3506
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -364
- package/dist/index.d.ts +74 -364
- package/dist/index.js +88 -656
- package/dist/index.js.map +1 -1
- package/dist/jsx/jsx-dev-runtime.cjs +1 -1
- package/dist/jsx/jsx-dev-runtime.cjs.map +1 -1
- package/dist/jsx/jsx-dev-runtime.d.cts +3 -2
- package/dist/jsx/jsx-dev-runtime.d.ts +3 -2
- package/dist/jsx/jsx-dev-runtime.js +2 -5
- package/dist/jsx/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx/jsx-runtime.d.cts +2 -1
- package/dist/jsx/jsx-runtime.d.ts +2 -1
- package/dist/jsx/jsx-runtime.js +2 -4
- package/dist/{types-DLTViI21.d.cts → jsx-AzPM8gMS.d.cts} +6 -21
- package/dist/{types-DLTViI21.d.ts → jsx-AzPM8gMS.d.ts} +6 -21
- package/dist/navigate-LUVYHYZZ.js +17 -0
- package/dist/resources/index.cjs +1200 -0
- package/dist/resources/index.cjs.map +1 -0
- package/dist/resources/index.d.cts +21 -0
- package/dist/resources/index.d.ts +21 -0
- package/dist/resources/index.js +278 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/{route-P5YQBT4T.js → route-BCND6MPK.js} +5 -4
- package/dist/router/index.cjs +3247 -0
- package/dist/router/index.cjs.map +1 -0
- package/dist/router/index.d.cts +64 -0
- package/dist/router/index.d.ts +64 -0
- package/dist/router/index.js +49 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router-DaGtH1Sq.d.cts +36 -0
- package/dist/router-DaGtH1Sq.d.ts +36 -0
- package/dist/ssr/index.cjs +4059 -0
- package/dist/ssr/index.cjs.map +1 -0
- package/dist/ssr/index.d.cts +123 -0
- package/dist/ssr/index.d.ts +123 -0
- package/dist/ssr/index.js +666 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/types-CZ5sWur5.d.cts +23 -0
- package/dist/types-CZHOAiC1.d.ts +23 -0
- package/package.json +21 -7
- package/src/jsx/types.ts +4 -17
- package/dist/chunk-KR6HG7HF.js +0 -38
- package/dist/chunk-MIPES65F.js +0 -3023
- package/dist/chunk-MIPES65F.js.map +0 -1
- package/dist/chunk-PFOLLB6A.js +0 -524
- package/dist/chunk-PFOLLB6A.js.map +0 -1
- package/dist/chunk-QECQ2TF6.js +0 -28
- package/dist/chunk-QECQ2TF6.js.map +0 -1
- package/dist/chunk-RJWOOUYV.js.map +0 -1
- package/dist/navigate-SDZNA2ZE.js +0 -16
- package/dist/ssr-65K3IJ6B.js +0 -28
- package/dist/ssr-65K3IJ6B.js.map +0 -1
- /package/dist/{navigate-SDZNA2ZE.js.map → navigate-LUVYHYZZ.js.map} +0 -0
- /package/dist/{route-P5YQBT4T.js.map → route-BCND6MPK.js.map} +0 -0
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/resources/index.ts
|
|
21
|
+
var resources_exports = {};
|
|
22
|
+
__export(resources_exports, {
|
|
23
|
+
resource: () => resource
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(resources_exports);
|
|
26
|
+
|
|
27
|
+
// src/dev/invariant.ts
|
|
28
|
+
function invariant(condition, message, context) {
|
|
29
|
+
if (!condition) {
|
|
30
|
+
const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
|
|
31
|
+
throw new Error(`[Askr Invariant] ${message}${contextStr}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function assertSchedulingPrecondition(condition, violationMessage) {
|
|
35
|
+
invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/dev/logger.ts
|
|
39
|
+
function callConsole(method, args) {
|
|
40
|
+
const c = typeof console !== "undefined" ? console : void 0;
|
|
41
|
+
if (!c) return;
|
|
42
|
+
const fn = c[method];
|
|
43
|
+
if (typeof fn === "function") {
|
|
44
|
+
try {
|
|
45
|
+
fn.apply(console, args);
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var logger = {
|
|
51
|
+
debug: (...args) => {
|
|
52
|
+
if (process.env.NODE_ENV === "production") return;
|
|
53
|
+
callConsole("debug", args);
|
|
54
|
+
},
|
|
55
|
+
info: (...args) => {
|
|
56
|
+
if (process.env.NODE_ENV === "production") return;
|
|
57
|
+
callConsole("info", args);
|
|
58
|
+
},
|
|
59
|
+
warn: (...args) => {
|
|
60
|
+
if (process.env.NODE_ENV === "production") return;
|
|
61
|
+
callConsole("warn", args);
|
|
62
|
+
},
|
|
63
|
+
error: (...args) => {
|
|
64
|
+
callConsole("error", args);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/runtime/scheduler.ts
|
|
69
|
+
var MAX_FLUSH_DEPTH = 50;
|
|
70
|
+
function isBulkCommitActive() {
|
|
71
|
+
try {
|
|
72
|
+
const fb = globalThis.__ASKR_FASTLANE;
|
|
73
|
+
return typeof fb?.isBulkCommitActive === "function" ? !!fb.isBulkCommitActive() : false;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
void e;
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
var Scheduler = class {
|
|
80
|
+
constructor() {
|
|
81
|
+
this.q = [];
|
|
82
|
+
this.head = 0;
|
|
83
|
+
this.running = false;
|
|
84
|
+
this.inHandler = false;
|
|
85
|
+
this.depth = 0;
|
|
86
|
+
this.executionDepth = 0;
|
|
87
|
+
// for compat with existing diagnostics
|
|
88
|
+
// Monotonic flush version increments at end of each flush
|
|
89
|
+
this.flushVersion = 0;
|
|
90
|
+
// Best-effort microtask kick scheduling
|
|
91
|
+
this.kickScheduled = false;
|
|
92
|
+
// Escape hatch flag for runWithSyncProgress
|
|
93
|
+
this.allowSyncProgress = false;
|
|
94
|
+
// Waiters waiting for flushVersion >= target
|
|
95
|
+
this.waiters = [];
|
|
96
|
+
// Keep a lightweight taskCount for compatibility/diagnostics
|
|
97
|
+
this.taskCount = 0;
|
|
98
|
+
}
|
|
99
|
+
enqueue(task) {
|
|
100
|
+
assertSchedulingPrecondition(
|
|
101
|
+
typeof task === "function",
|
|
102
|
+
"enqueue() requires a function"
|
|
103
|
+
);
|
|
104
|
+
if (isBulkCommitActive() && !this.allowSyncProgress) {
|
|
105
|
+
if (process.env.NODE_ENV !== "production") {
|
|
106
|
+
throw new Error(
|
|
107
|
+
"[Scheduler] enqueue() during bulk commit (not allowed)"
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.q.push(task);
|
|
113
|
+
this.taskCount++;
|
|
114
|
+
if (!this.running && !this.kickScheduled && !this.inHandler && !isBulkCommitActive()) {
|
|
115
|
+
this.kickScheduled = true;
|
|
116
|
+
queueMicrotask(() => {
|
|
117
|
+
this.kickScheduled = false;
|
|
118
|
+
if (this.running) return;
|
|
119
|
+
if (isBulkCommitActive()) return;
|
|
120
|
+
try {
|
|
121
|
+
this.flush();
|
|
122
|
+
} catch (err) {
|
|
123
|
+
setTimeout(() => {
|
|
124
|
+
throw err;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
flush() {
|
|
131
|
+
invariant(
|
|
132
|
+
!this.running,
|
|
133
|
+
"[Scheduler] flush() called while already running"
|
|
134
|
+
);
|
|
135
|
+
if (process.env.NODE_ENV !== "production") {
|
|
136
|
+
if (isBulkCommitActive() && !this.allowSyncProgress) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
"[Scheduler] flush() started during bulk commit (not allowed)"
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
this.running = true;
|
|
143
|
+
this.depth = 0;
|
|
144
|
+
let fatal = null;
|
|
145
|
+
try {
|
|
146
|
+
while (this.head < this.q.length) {
|
|
147
|
+
this.depth++;
|
|
148
|
+
if (process.env.NODE_ENV !== "production" && this.depth > MAX_FLUSH_DEPTH) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const task = this.q[this.head++];
|
|
154
|
+
try {
|
|
155
|
+
this.executionDepth++;
|
|
156
|
+
task();
|
|
157
|
+
this.executionDepth--;
|
|
158
|
+
} catch (err) {
|
|
159
|
+
if (this.executionDepth > 0) this.executionDepth = 0;
|
|
160
|
+
fatal = err;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
if (this.taskCount > 0) this.taskCount--;
|
|
164
|
+
}
|
|
165
|
+
} finally {
|
|
166
|
+
this.running = false;
|
|
167
|
+
this.depth = 0;
|
|
168
|
+
this.executionDepth = 0;
|
|
169
|
+
if (this.head >= this.q.length) {
|
|
170
|
+
this.q.length = 0;
|
|
171
|
+
this.head = 0;
|
|
172
|
+
} else if (this.head > 0) {
|
|
173
|
+
const remaining = this.q.length - this.head;
|
|
174
|
+
for (let i = 0; i < remaining; i++) {
|
|
175
|
+
this.q[i] = this.q[this.head + i];
|
|
176
|
+
}
|
|
177
|
+
this.q.length = remaining;
|
|
178
|
+
this.head = 0;
|
|
179
|
+
}
|
|
180
|
+
this.flushVersion++;
|
|
181
|
+
this.resolveWaiters();
|
|
182
|
+
}
|
|
183
|
+
if (fatal) throw fatal;
|
|
184
|
+
}
|
|
185
|
+
runWithSyncProgress(fn) {
|
|
186
|
+
const prev = this.allowSyncProgress;
|
|
187
|
+
this.allowSyncProgress = true;
|
|
188
|
+
const g = globalThis;
|
|
189
|
+
const origQueueMicrotask = g.queueMicrotask;
|
|
190
|
+
const origSetTimeout = g.setTimeout;
|
|
191
|
+
if (process.env.NODE_ENV !== "production") {
|
|
192
|
+
g.queueMicrotask = () => {
|
|
193
|
+
throw new Error(
|
|
194
|
+
"[Scheduler] queueMicrotask not allowed during runWithSyncProgress"
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
g.setTimeout = () => {
|
|
198
|
+
throw new Error(
|
|
199
|
+
"[Scheduler] setTimeout not allowed during runWithSyncProgress"
|
|
200
|
+
);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const startVersion = this.flushVersion;
|
|
204
|
+
try {
|
|
205
|
+
const res = fn();
|
|
206
|
+
if (!this.running && this.q.length - this.head > 0) {
|
|
207
|
+
this.flush();
|
|
208
|
+
}
|
|
209
|
+
if (process.env.NODE_ENV !== "production") {
|
|
210
|
+
if (this.q.length - this.head > 0) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
"[Scheduler] tasks remain after runWithSyncProgress flush"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return res;
|
|
217
|
+
} finally {
|
|
218
|
+
if (process.env.NODE_ENV !== "production") {
|
|
219
|
+
g.queueMicrotask = origQueueMicrotask;
|
|
220
|
+
g.setTimeout = origSetTimeout;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
if (this.flushVersion === startVersion) {
|
|
224
|
+
this.flushVersion++;
|
|
225
|
+
this.resolveWaiters();
|
|
226
|
+
}
|
|
227
|
+
} catch (e) {
|
|
228
|
+
void e;
|
|
229
|
+
}
|
|
230
|
+
this.allowSyncProgress = prev;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
waitForFlush(targetVersion, timeoutMs = 2e3) {
|
|
234
|
+
const target = typeof targetVersion === "number" ? targetVersion : this.flushVersion + 1;
|
|
235
|
+
if (this.flushVersion >= target) return Promise.resolve();
|
|
236
|
+
return new Promise((resolve, reject) => {
|
|
237
|
+
const timer = setTimeout(() => {
|
|
238
|
+
const ns = globalThis.__ASKR__ || {};
|
|
239
|
+
const diag = {
|
|
240
|
+
flushVersion: this.flushVersion,
|
|
241
|
+
queueLen: this.q.length - this.head,
|
|
242
|
+
running: this.running,
|
|
243
|
+
inHandler: this.inHandler,
|
|
244
|
+
bulk: isBulkCommitActive(),
|
|
245
|
+
namespace: ns
|
|
246
|
+
};
|
|
247
|
+
reject(
|
|
248
|
+
new Error(
|
|
249
|
+
`waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`
|
|
250
|
+
)
|
|
251
|
+
);
|
|
252
|
+
}, timeoutMs);
|
|
253
|
+
this.waiters.push({ target, resolve, reject, timer });
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
getState() {
|
|
257
|
+
return {
|
|
258
|
+
queueLength: this.q.length - this.head,
|
|
259
|
+
running: this.running,
|
|
260
|
+
depth: this.depth,
|
|
261
|
+
executionDepth: this.executionDepth,
|
|
262
|
+
taskCount: this.taskCount,
|
|
263
|
+
flushVersion: this.flushVersion,
|
|
264
|
+
// New fields for optional inspection
|
|
265
|
+
inHandler: this.inHandler,
|
|
266
|
+
allowSyncProgress: this.allowSyncProgress
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
setInHandler(v) {
|
|
270
|
+
this.inHandler = v;
|
|
271
|
+
}
|
|
272
|
+
isInHandler() {
|
|
273
|
+
return this.inHandler;
|
|
274
|
+
}
|
|
275
|
+
isExecuting() {
|
|
276
|
+
return this.running || this.executionDepth > 0;
|
|
277
|
+
}
|
|
278
|
+
// Clear pending synchronous tasks (used by fastlane enter/exit)
|
|
279
|
+
clearPendingSyncTasks() {
|
|
280
|
+
const remaining = this.q.length - this.head;
|
|
281
|
+
if (remaining <= 0) return 0;
|
|
282
|
+
if (this.running) {
|
|
283
|
+
this.q.length = this.head;
|
|
284
|
+
this.taskCount = Math.max(0, this.taskCount - remaining);
|
|
285
|
+
queueMicrotask(() => {
|
|
286
|
+
try {
|
|
287
|
+
this.flushVersion++;
|
|
288
|
+
this.resolveWaiters();
|
|
289
|
+
} catch (e) {
|
|
290
|
+
void e;
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
return remaining;
|
|
294
|
+
}
|
|
295
|
+
this.q.length = 0;
|
|
296
|
+
this.head = 0;
|
|
297
|
+
this.taskCount = Math.max(0, this.taskCount - remaining);
|
|
298
|
+
this.flushVersion++;
|
|
299
|
+
this.resolveWaiters();
|
|
300
|
+
return remaining;
|
|
301
|
+
}
|
|
302
|
+
resolveWaiters() {
|
|
303
|
+
if (this.waiters.length === 0) return;
|
|
304
|
+
const ready = [];
|
|
305
|
+
const remaining = [];
|
|
306
|
+
for (const w of this.waiters) {
|
|
307
|
+
if (this.flushVersion >= w.target) {
|
|
308
|
+
if (w.timer) clearTimeout(w.timer);
|
|
309
|
+
ready.push(w.resolve);
|
|
310
|
+
} else {
|
|
311
|
+
remaining.push(w);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
this.waiters = remaining;
|
|
315
|
+
for (const r of ready) r();
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
var globalScheduler = new Scheduler();
|
|
319
|
+
|
|
320
|
+
// src/runtime/context.ts
|
|
321
|
+
var currentContextFrame = null;
|
|
322
|
+
var currentAsyncResourceFrame = null;
|
|
323
|
+
function withAsyncResourceContext(frame, fn) {
|
|
324
|
+
const oldFrame = currentAsyncResourceFrame;
|
|
325
|
+
currentAsyncResourceFrame = frame;
|
|
326
|
+
try {
|
|
327
|
+
return fn();
|
|
328
|
+
} finally {
|
|
329
|
+
currentAsyncResourceFrame = oldFrame;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function getCurrentContextFrame() {
|
|
333
|
+
return currentContextFrame;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/renderer/utils.ts
|
|
337
|
+
function isIgnoredForPropChanges(key) {
|
|
338
|
+
if (key === "children" || key === "key") return true;
|
|
339
|
+
if (key.startsWith("on") && key.length > 2) return true;
|
|
340
|
+
if (key.startsWith("data-")) return true;
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
function hasPropChanged(el, key, value) {
|
|
344
|
+
try {
|
|
345
|
+
if (key === "class" || key === "className") {
|
|
346
|
+
return el.className !== String(value);
|
|
347
|
+
}
|
|
348
|
+
if (key === "value" || key === "checked") {
|
|
349
|
+
return el[key] !== value;
|
|
350
|
+
}
|
|
351
|
+
const attr = el.getAttribute(key);
|
|
352
|
+
if (value === void 0 || value === null || value === false) {
|
|
353
|
+
return attr !== null;
|
|
354
|
+
}
|
|
355
|
+
return String(value) !== attr;
|
|
356
|
+
} catch {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function hasNonTrivialProps(props) {
|
|
361
|
+
for (const k of Object.keys(props)) {
|
|
362
|
+
if (isIgnoredForPropChanges(k)) continue;
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
function extractKey(vnode) {
|
|
368
|
+
if (typeof vnode !== "object" || vnode === null) return void 0;
|
|
369
|
+
const obj = vnode;
|
|
370
|
+
const rawKey = obj.key ?? obj.props?.key;
|
|
371
|
+
if (rawKey === void 0) return void 0;
|
|
372
|
+
return typeof rawKey === "symbol" ? String(rawKey) : rawKey;
|
|
373
|
+
}
|
|
374
|
+
function buildKeyMapFromChildren(parent) {
|
|
375
|
+
const map = /* @__PURE__ */ new Map();
|
|
376
|
+
for (let ch = parent.firstElementChild; ch; ch = ch.nextElementSibling) {
|
|
377
|
+
const k = ch.getAttribute("data-key");
|
|
378
|
+
if (k !== null) {
|
|
379
|
+
map.set(k, ch);
|
|
380
|
+
const n = Number(k);
|
|
381
|
+
if (!Number.isNaN(n)) map.set(n, ch);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return map;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/renderer/keyed.ts
|
|
388
|
+
var keyedElements = /* @__PURE__ */ new WeakMap();
|
|
389
|
+
function getKeyMapForElement(el) {
|
|
390
|
+
return keyedElements.get(el);
|
|
391
|
+
}
|
|
392
|
+
function populateKeyMapForElement(parent) {
|
|
393
|
+
try {
|
|
394
|
+
if (keyedElements.has(parent)) return;
|
|
395
|
+
let domMap = buildKeyMapFromChildren(parent);
|
|
396
|
+
if (domMap.size === 0) {
|
|
397
|
+
domMap = /* @__PURE__ */ new Map();
|
|
398
|
+
const children = Array.from(parent.children);
|
|
399
|
+
for (const ch of children) {
|
|
400
|
+
const text = (ch.textContent || "").trim();
|
|
401
|
+
if (text) {
|
|
402
|
+
domMap.set(text, ch);
|
|
403
|
+
const n = Number(text);
|
|
404
|
+
if (!Number.isNaN(n)) domMap.set(n, ch);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (domMap.size > 0) keyedElements.set(parent, domMap);
|
|
409
|
+
} catch {
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function extractKeyedVnodes(newChildren) {
|
|
413
|
+
const result = [];
|
|
414
|
+
for (const child of newChildren) {
|
|
415
|
+
const key = extractKey(child);
|
|
416
|
+
if (key !== void 0) {
|
|
417
|
+
result.push({ key, vnode: child });
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
function computeLISLength(positions) {
|
|
423
|
+
const tails = [];
|
|
424
|
+
for (const pos of positions) {
|
|
425
|
+
if (pos === -1) continue;
|
|
426
|
+
let lo = 0;
|
|
427
|
+
let hi = tails.length;
|
|
428
|
+
while (lo < hi) {
|
|
429
|
+
const mid = lo + hi >> 1;
|
|
430
|
+
if (tails[mid] < pos) lo = mid + 1;
|
|
431
|
+
else hi = mid;
|
|
432
|
+
}
|
|
433
|
+
if (lo === tails.length) tails.push(pos);
|
|
434
|
+
else tails[lo] = pos;
|
|
435
|
+
}
|
|
436
|
+
return tails.length;
|
|
437
|
+
}
|
|
438
|
+
function checkVnodesHaveProps(keyedVnodes) {
|
|
439
|
+
for (const { vnode } of keyedVnodes) {
|
|
440
|
+
if (typeof vnode !== "object" || vnode === null) continue;
|
|
441
|
+
const vnodeObj = vnode;
|
|
442
|
+
if (vnodeObj.props && hasNonTrivialProps(vnodeObj.props)) {
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
function checkVnodePropChanges(keyedVnodes, oldKeyMap) {
|
|
449
|
+
for (const { key, vnode } of keyedVnodes) {
|
|
450
|
+
const el = oldKeyMap?.get(key);
|
|
451
|
+
if (!el || typeof vnode !== "object" || vnode === null) continue;
|
|
452
|
+
const vnodeObj = vnode;
|
|
453
|
+
const props = vnodeObj.props || {};
|
|
454
|
+
for (const k of Object.keys(props)) {
|
|
455
|
+
if (isIgnoredForPropChanges(k)) continue;
|
|
456
|
+
if (hasPropChanged(el, k, props[k])) {
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
function isKeyedReorderFastPathEligible(parent, newChildren, oldKeyMap) {
|
|
464
|
+
const keyedVnodes = extractKeyedVnodes(newChildren);
|
|
465
|
+
const totalKeyed = keyedVnodes.length;
|
|
466
|
+
const newKeyOrder = keyedVnodes.map((kv) => kv.key);
|
|
467
|
+
const oldKeyOrder = oldKeyMap ? Array.from(oldKeyMap.keys()) : [];
|
|
468
|
+
let moveCount = 0;
|
|
469
|
+
for (let i = 0; i < newKeyOrder.length; i++) {
|
|
470
|
+
const k = newKeyOrder[i];
|
|
471
|
+
if (i >= oldKeyOrder.length || oldKeyOrder[i] !== k || !oldKeyMap?.has(k)) {
|
|
472
|
+
moveCount++;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const FAST_MOVE_THRESHOLD_ABS = 64;
|
|
476
|
+
const FAST_MOVE_THRESHOLD_REL = 0.1;
|
|
477
|
+
const cheapMoveTrigger = totalKeyed >= 128 && oldKeyOrder.length > 0 && moveCount > Math.max(
|
|
478
|
+
FAST_MOVE_THRESHOLD_ABS,
|
|
479
|
+
Math.floor(totalKeyed * FAST_MOVE_THRESHOLD_REL)
|
|
480
|
+
);
|
|
481
|
+
let lisTrigger = false;
|
|
482
|
+
let lisLen = 0;
|
|
483
|
+
if (totalKeyed >= 128) {
|
|
484
|
+
const parentChildren = Array.from(parent.children);
|
|
485
|
+
const positions = keyedVnodes.map(({ key }) => {
|
|
486
|
+
const el = oldKeyMap?.get(key);
|
|
487
|
+
return el?.parentElement === parent ? parentChildren.indexOf(el) : -1;
|
|
488
|
+
});
|
|
489
|
+
lisLen = computeLISLength(positions);
|
|
490
|
+
lisTrigger = lisLen < Math.floor(totalKeyed * 0.5);
|
|
491
|
+
}
|
|
492
|
+
const hasPropsPresent = checkVnodesHaveProps(keyedVnodes);
|
|
493
|
+
const hasPropChanges = checkVnodePropChanges(keyedVnodes, oldKeyMap);
|
|
494
|
+
const useFastPath = (cheapMoveTrigger || lisTrigger) && !hasPropChanges && !hasPropsPresent;
|
|
495
|
+
return {
|
|
496
|
+
useFastPath,
|
|
497
|
+
totalKeyed,
|
|
498
|
+
moveCount,
|
|
499
|
+
lisLen,
|
|
500
|
+
hasPropChanges
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/common/jsx.ts
|
|
505
|
+
var Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
|
|
506
|
+
|
|
507
|
+
// src/runtime/dev-namespace.ts
|
|
508
|
+
function getDevNamespace() {
|
|
509
|
+
if (process.env.NODE_ENV === "production") return {};
|
|
510
|
+
try {
|
|
511
|
+
const g = globalThis;
|
|
512
|
+
if (!g.__ASKR__) g.__ASKR__ = {};
|
|
513
|
+
return g.__ASKR__;
|
|
514
|
+
} catch {
|
|
515
|
+
return {};
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
function setDevValue(key, value) {
|
|
519
|
+
if (process.env.NODE_ENV === "production") return;
|
|
520
|
+
try {
|
|
521
|
+
getDevNamespace()[key] = value;
|
|
522
|
+
} catch {
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function getDevValue(key) {
|
|
526
|
+
if (process.env.NODE_ENV === "production") return void 0;
|
|
527
|
+
try {
|
|
528
|
+
return getDevNamespace()[key];
|
|
529
|
+
} catch {
|
|
530
|
+
return void 0;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/runtime/fastlane.ts
|
|
535
|
+
var _bulkCommitActive = false;
|
|
536
|
+
var _appliedParents = null;
|
|
537
|
+
function enterBulkCommit() {
|
|
538
|
+
_bulkCommitActive = true;
|
|
539
|
+
_appliedParents = /* @__PURE__ */ new WeakSet();
|
|
540
|
+
try {
|
|
541
|
+
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
542
|
+
setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", cleared);
|
|
543
|
+
} catch (err) {
|
|
544
|
+
if (process.env.NODE_ENV !== "production") throw err;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function exitBulkCommit() {
|
|
548
|
+
_bulkCommitActive = false;
|
|
549
|
+
_appliedParents = null;
|
|
550
|
+
}
|
|
551
|
+
function isBulkCommitActive2() {
|
|
552
|
+
return _bulkCommitActive;
|
|
553
|
+
}
|
|
554
|
+
function markFastPathApplied(parent) {
|
|
555
|
+
if (!_appliedParents) return;
|
|
556
|
+
try {
|
|
557
|
+
_appliedParents.add(parent);
|
|
558
|
+
} catch (e) {
|
|
559
|
+
void e;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
function isFastPathApplied(parent) {
|
|
563
|
+
return !!(_appliedParents && _appliedParents.has(parent));
|
|
564
|
+
}
|
|
565
|
+
function finalizeReadSubscriptions(instance) {
|
|
566
|
+
const newSet = instance._pendingReadStates ?? /* @__PURE__ */ new Set();
|
|
567
|
+
const oldSet = instance._lastReadStates ?? /* @__PURE__ */ new Set();
|
|
568
|
+
const token = instance._currentRenderToken;
|
|
569
|
+
if (token === void 0) return;
|
|
570
|
+
for (const s of oldSet) {
|
|
571
|
+
if (!newSet.has(s)) {
|
|
572
|
+
const readers = s._readers;
|
|
573
|
+
if (readers) readers.delete(instance);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
instance.lastRenderToken = token;
|
|
577
|
+
for (const s of newSet) {
|
|
578
|
+
let readers = s._readers;
|
|
579
|
+
if (!readers) {
|
|
580
|
+
readers = /* @__PURE__ */ new Map();
|
|
581
|
+
s._readers = readers;
|
|
582
|
+
}
|
|
583
|
+
readers.set(instance, instance.lastRenderToken ?? 0);
|
|
584
|
+
}
|
|
585
|
+
instance._lastReadStates = newSet;
|
|
586
|
+
instance._pendingReadStates = /* @__PURE__ */ new Set();
|
|
587
|
+
instance._currentRenderToken = void 0;
|
|
588
|
+
}
|
|
589
|
+
function unwrapFragmentForFastPath(vnode) {
|
|
590
|
+
if (!vnode || typeof vnode !== "object" || !("type" in vnode)) return vnode;
|
|
591
|
+
const v = vnode;
|
|
592
|
+
if (typeof v.type === "symbol" && (v.type === Fragment || String(v.type) === "Symbol(askr.fragment)")) {
|
|
593
|
+
const children = v.children || v.props?.children;
|
|
594
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
595
|
+
for (const child of children) {
|
|
596
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
597
|
+
const c = child;
|
|
598
|
+
if (typeof c.type === "string") {
|
|
599
|
+
return child;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return vnode;
|
|
606
|
+
}
|
|
607
|
+
function classifyUpdate(instance, result) {
|
|
608
|
+
const unwrappedResult = unwrapFragmentForFastPath(result);
|
|
609
|
+
if (!unwrappedResult || typeof unwrappedResult !== "object" || !("type" in unwrappedResult))
|
|
610
|
+
return { useFastPath: false, reason: "not-vnode" };
|
|
611
|
+
const vnode = unwrappedResult;
|
|
612
|
+
if (vnode == null || typeof vnode.type !== "string")
|
|
613
|
+
return { useFastPath: false, reason: "not-intrinsic" };
|
|
614
|
+
const parent = instance.target;
|
|
615
|
+
if (!parent) return { useFastPath: false, reason: "no-root" };
|
|
616
|
+
const firstChild = parent.children[0];
|
|
617
|
+
if (!firstChild) return { useFastPath: false, reason: "no-first-child" };
|
|
618
|
+
if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())
|
|
619
|
+
return { useFastPath: false, reason: "root-tag-mismatch" };
|
|
620
|
+
const children = vnode.children || vnode.props?.children;
|
|
621
|
+
if (!Array.isArray(children))
|
|
622
|
+
return { useFastPath: false, reason: "no-children-array" };
|
|
623
|
+
for (const c of children) {
|
|
624
|
+
if (typeof c === "object" && c !== null && "type" in c && typeof c.type === "function") {
|
|
625
|
+
return { useFastPath: false, reason: "component-child-present" };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (instance.mountOperations.length > 0)
|
|
629
|
+
return { useFastPath: false, reason: "pending-mounts" };
|
|
630
|
+
try {
|
|
631
|
+
populateKeyMapForElement(firstChild);
|
|
632
|
+
} catch {
|
|
633
|
+
}
|
|
634
|
+
const oldKeyMap = getKeyMapForElement(firstChild);
|
|
635
|
+
const decision = isKeyedReorderFastPathEligible(
|
|
636
|
+
firstChild,
|
|
637
|
+
children,
|
|
638
|
+
oldKeyMap
|
|
639
|
+
);
|
|
640
|
+
if (!decision.useFastPath || decision.totalKeyed < 128)
|
|
641
|
+
return { ...decision, useFastPath: false, reason: "renderer-declined" };
|
|
642
|
+
return { ...decision, useFastPath: true };
|
|
643
|
+
}
|
|
644
|
+
function commitReorderOnly(instance, result) {
|
|
645
|
+
const evaluate = globalThis.__ASKR_RENDERER?.evaluate;
|
|
646
|
+
if (typeof evaluate !== "function") {
|
|
647
|
+
logger.warn(
|
|
648
|
+
"[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane"
|
|
649
|
+
);
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
const schedBefore = process.env.NODE_ENV !== "production" ? globalScheduler.getState() : null;
|
|
653
|
+
enterBulkCommit();
|
|
654
|
+
try {
|
|
655
|
+
globalScheduler.runWithSyncProgress(() => {
|
|
656
|
+
evaluate(result, instance.target);
|
|
657
|
+
try {
|
|
658
|
+
finalizeReadSubscriptions(instance);
|
|
659
|
+
} catch (e) {
|
|
660
|
+
if (process.env.NODE_ENV !== "production") throw e;
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
664
|
+
setDevValue("__FASTLANE_CLEARED_AFTER", clearedAfter);
|
|
665
|
+
if (process.env.NODE_ENV !== "production") {
|
|
666
|
+
validateFastLaneInvariants(instance, schedBefore);
|
|
667
|
+
}
|
|
668
|
+
return true;
|
|
669
|
+
} finally {
|
|
670
|
+
exitBulkCommit();
|
|
671
|
+
}
|
|
672
|
+
if (process.env.NODE_ENV !== "production") {
|
|
673
|
+
if (isBulkCommitActive2()) {
|
|
674
|
+
throw new Error(
|
|
675
|
+
"Fast-lane invariant violated: bulk commit flag still set after commit"
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function validateFastLaneInvariants(instance, schedBefore) {
|
|
681
|
+
const commitCount = getDevValue("__LAST_FASTPATH_COMMIT_COUNT") ?? 0;
|
|
682
|
+
const invariants = {
|
|
683
|
+
commitCount,
|
|
684
|
+
mountOps: instance.mountOperations.length,
|
|
685
|
+
cleanupFns: instance.cleanupFns.length
|
|
686
|
+
};
|
|
687
|
+
setDevValue("__LAST_FASTLANE_INVARIANTS", invariants);
|
|
688
|
+
if (commitCount !== 1) {
|
|
689
|
+
console.error(
|
|
690
|
+
"[FASTLANE][INV] commitCount",
|
|
691
|
+
commitCount,
|
|
692
|
+
"diag",
|
|
693
|
+
globalThis.__ASKR_DIAG
|
|
694
|
+
);
|
|
695
|
+
throw new Error(
|
|
696
|
+
"Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
if (invariants.mountOps > 0) {
|
|
700
|
+
throw new Error(
|
|
701
|
+
"Fast-lane invariant violated: mount operations were registered during bulk commit"
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
if (invariants.cleanupFns > 0) {
|
|
705
|
+
throw new Error(
|
|
706
|
+
"Fast-lane invariant violated: cleanup functions were added during bulk commit"
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
const schedAfter = globalScheduler.getState();
|
|
710
|
+
if (schedBefore && schedAfter && schedAfter.taskCount > schedBefore.taskCount) {
|
|
711
|
+
console.error(
|
|
712
|
+
"[FASTLANE] schedBefore, schedAfter",
|
|
713
|
+
schedBefore,
|
|
714
|
+
schedAfter
|
|
715
|
+
);
|
|
716
|
+
console.error("[FASTLANE] enqueue logs", getDevValue("__ENQUEUE_LOGS"));
|
|
717
|
+
throw new Error(
|
|
718
|
+
"Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit"
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
let finalState = globalScheduler.getState();
|
|
722
|
+
const executing = globalScheduler.isExecuting();
|
|
723
|
+
let outstandingAfter = Math.max(
|
|
724
|
+
0,
|
|
725
|
+
finalState.taskCount - (executing ? 1 : 0)
|
|
726
|
+
);
|
|
727
|
+
if (outstandingAfter !== 0) {
|
|
728
|
+
let attempts = 0;
|
|
729
|
+
while (attempts < 5) {
|
|
730
|
+
const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;
|
|
731
|
+
if (cleared === 0) break;
|
|
732
|
+
attempts++;
|
|
733
|
+
}
|
|
734
|
+
finalState = globalScheduler.getState();
|
|
735
|
+
outstandingAfter = Math.max(
|
|
736
|
+
0,
|
|
737
|
+
finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)
|
|
738
|
+
);
|
|
739
|
+
if (outstandingAfter !== 0) {
|
|
740
|
+
console.error(
|
|
741
|
+
"[FASTLANE] Post-commit enqueue logs:",
|
|
742
|
+
getDevValue("__ENQUEUE_LOGS")
|
|
743
|
+
);
|
|
744
|
+
console.error(
|
|
745
|
+
"[FASTLANE] Cleared counts:",
|
|
746
|
+
getDevValue("__FASTLANE_CLEARED_TASKS"),
|
|
747
|
+
getDevValue("__FASTLANE_CLEARED_AFTER")
|
|
748
|
+
);
|
|
749
|
+
throw new Error(
|
|
750
|
+
`Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function tryRuntimeFastLaneSync(instance, result) {
|
|
756
|
+
const cls = classifyUpdate(instance, result);
|
|
757
|
+
if (!cls.useFastPath) {
|
|
758
|
+
setDevValue("__LAST_FASTPATH_STATS", void 0);
|
|
759
|
+
setDevValue("__LAST_FASTPATH_COMMIT_COUNT", 0);
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
try {
|
|
763
|
+
return commitReorderOnly(instance, result);
|
|
764
|
+
} catch (err) {
|
|
765
|
+
if (process.env.NODE_ENV !== "production") throw err;
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (typeof globalThis !== "undefined") {
|
|
770
|
+
globalThis.__ASKR_FASTLANE = {
|
|
771
|
+
isBulkCommitActive: isBulkCommitActive2,
|
|
772
|
+
enterBulkCommit,
|
|
773
|
+
exitBulkCommit,
|
|
774
|
+
tryRuntimeFastLaneSync,
|
|
775
|
+
markFastPathApplied,
|
|
776
|
+
isFastPathApplied
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// src/runtime/component.ts
|
|
781
|
+
var currentInstance = null;
|
|
782
|
+
var stateIndex = 0;
|
|
783
|
+
function getCurrentComponentInstance() {
|
|
784
|
+
return currentInstance;
|
|
785
|
+
}
|
|
786
|
+
function getCurrentInstance() {
|
|
787
|
+
return currentInstance;
|
|
788
|
+
}
|
|
789
|
+
function getNextStateIndex() {
|
|
790
|
+
return stateIndex++;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// src/runtime/ssr-bridge.ts
|
|
794
|
+
var defaultBridge = {
|
|
795
|
+
getCurrentSSRContext() {
|
|
796
|
+
return null;
|
|
797
|
+
},
|
|
798
|
+
throwSSRDataMissing() {
|
|
799
|
+
throw new Error(
|
|
800
|
+
"[Askr] SSR data missing (SSR bridge not installed). If you are rendering on the server, ensure you are using the askr SSR entrypoints."
|
|
801
|
+
);
|
|
802
|
+
},
|
|
803
|
+
getCurrentRenderData() {
|
|
804
|
+
return null;
|
|
805
|
+
},
|
|
806
|
+
getNextKey() {
|
|
807
|
+
throw new Error(
|
|
808
|
+
"[Askr] getNextKey() called outside SSR render phase (SSR bridge not installed)."
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
var bridge = defaultBridge;
|
|
813
|
+
function getSSRBridge() {
|
|
814
|
+
return bridge;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/runtime/resource-cell.ts
|
|
818
|
+
var ResourceCell = class {
|
|
819
|
+
constructor(fn, deps, resourceFrame) {
|
|
820
|
+
this.value = null;
|
|
821
|
+
this.pending = true;
|
|
822
|
+
this.error = null;
|
|
823
|
+
this.generation = 0;
|
|
824
|
+
this.controller = null;
|
|
825
|
+
this.deps = null;
|
|
826
|
+
this.resourceFrame = null;
|
|
827
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
828
|
+
this.fn = fn;
|
|
829
|
+
this.deps = deps ? deps.slice() : null;
|
|
830
|
+
this.resourceFrame = resourceFrame;
|
|
831
|
+
this.snapshot = {
|
|
832
|
+
value: null,
|
|
833
|
+
pending: true,
|
|
834
|
+
error: null,
|
|
835
|
+
refresh: () => this.refresh()
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
subscribe(cb) {
|
|
839
|
+
this.subscribers.add(cb);
|
|
840
|
+
return () => this.subscribers.delete(cb);
|
|
841
|
+
}
|
|
842
|
+
notifySubscribers() {
|
|
843
|
+
this.snapshot.value = this.value;
|
|
844
|
+
this.snapshot.pending = this.pending;
|
|
845
|
+
this.snapshot.error = this.error;
|
|
846
|
+
for (const cb of this.subscribers) cb();
|
|
847
|
+
}
|
|
848
|
+
start(ssr = false, notify = true) {
|
|
849
|
+
const generation = this.generation;
|
|
850
|
+
this.controller?.abort();
|
|
851
|
+
const controller = new AbortController();
|
|
852
|
+
this.controller = controller;
|
|
853
|
+
this.pending = true;
|
|
854
|
+
this.error = null;
|
|
855
|
+
if (notify) this.notifySubscribers();
|
|
856
|
+
let result;
|
|
857
|
+
try {
|
|
858
|
+
result = withAsyncResourceContext(
|
|
859
|
+
this.resourceFrame,
|
|
860
|
+
() => this.fn({ signal: controller.signal })
|
|
861
|
+
);
|
|
862
|
+
} catch (err) {
|
|
863
|
+
this.pending = false;
|
|
864
|
+
this.error = err;
|
|
865
|
+
if (notify) this.notifySubscribers();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (!(result instanceof Promise)) {
|
|
869
|
+
this.value = result;
|
|
870
|
+
this.pending = false;
|
|
871
|
+
this.error = null;
|
|
872
|
+
if (notify) this.notifySubscribers();
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (ssr) {
|
|
876
|
+
getSSRBridge().throwSSRDataMissing();
|
|
877
|
+
}
|
|
878
|
+
result.then((val) => {
|
|
879
|
+
if (this.generation !== generation) return;
|
|
880
|
+
if (this.controller !== controller) return;
|
|
881
|
+
this.value = val;
|
|
882
|
+
this.pending = false;
|
|
883
|
+
this.error = null;
|
|
884
|
+
this.notifySubscribers();
|
|
885
|
+
}).catch((err) => {
|
|
886
|
+
if (this.generation !== generation) return;
|
|
887
|
+
this.pending = false;
|
|
888
|
+
this.error = err;
|
|
889
|
+
try {
|
|
890
|
+
if (this.ownerName) {
|
|
891
|
+
logger.error(
|
|
892
|
+
`[Askr] Async resource error in ${this.ownerName}:`,
|
|
893
|
+
err
|
|
894
|
+
);
|
|
895
|
+
} else {
|
|
896
|
+
logger.error("[Askr] Async resource error:", err);
|
|
897
|
+
}
|
|
898
|
+
} catch {
|
|
899
|
+
}
|
|
900
|
+
this.notifySubscribers();
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
refresh() {
|
|
904
|
+
this.generation++;
|
|
905
|
+
this.controller?.abort();
|
|
906
|
+
this.start();
|
|
907
|
+
}
|
|
908
|
+
abort() {
|
|
909
|
+
this.controller?.abort();
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
// src/runtime/state.ts
|
|
914
|
+
function state(initialValue) {
|
|
915
|
+
const instance = getCurrentInstance();
|
|
916
|
+
if (!instance) {
|
|
917
|
+
throw new Error(
|
|
918
|
+
"state() can only be called during component render execution. Move state() calls to the top level of your component function."
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
const index = getNextStateIndex();
|
|
922
|
+
const stateValues = instance.stateValues;
|
|
923
|
+
if (index < instance.stateIndexCheck) {
|
|
924
|
+
throw new Error(
|
|
925
|
+
`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.`
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
invariant(
|
|
929
|
+
index >= instance.stateIndexCheck,
|
|
930
|
+
"[State] State indices must increase monotonically"
|
|
931
|
+
);
|
|
932
|
+
instance.stateIndexCheck = index;
|
|
933
|
+
if (instance.firstRenderComplete) {
|
|
934
|
+
if (!instance.expectedStateIndices.includes(index)) {
|
|
935
|
+
throw new Error(
|
|
936
|
+
`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.`
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
} else {
|
|
940
|
+
instance.expectedStateIndices.push(index);
|
|
941
|
+
}
|
|
942
|
+
if (stateValues[index]) {
|
|
943
|
+
const existing = stateValues[index];
|
|
944
|
+
if (existing._owner !== instance) {
|
|
945
|
+
throw new Error(
|
|
946
|
+
`State ownership violation: state() called at index ${index} is owned by a different component instance. State ownership is positional and immutable.`
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
return existing;
|
|
950
|
+
}
|
|
951
|
+
const cell = createStateCell(initialValue, instance);
|
|
952
|
+
stateValues[index] = cell;
|
|
953
|
+
return cell;
|
|
954
|
+
}
|
|
955
|
+
function createStateCell(initialValue, instance) {
|
|
956
|
+
let value = initialValue;
|
|
957
|
+
const readers = /* @__PURE__ */ new Map();
|
|
958
|
+
function read() {
|
|
959
|
+
read._hasBeenRead = true;
|
|
960
|
+
const inst = getCurrentInstance();
|
|
961
|
+
if (inst && inst._currentRenderToken !== void 0) {
|
|
962
|
+
if (!inst._pendingReadStates) inst._pendingReadStates = /* @__PURE__ */ new Set();
|
|
963
|
+
inst._pendingReadStates.add(read);
|
|
964
|
+
}
|
|
965
|
+
return value;
|
|
966
|
+
}
|
|
967
|
+
read._readers = readers;
|
|
968
|
+
read._owner = instance;
|
|
969
|
+
read.set = (newValueOrUpdater) => {
|
|
970
|
+
const currentInst = getCurrentInstance();
|
|
971
|
+
if (currentInst !== null) {
|
|
972
|
+
throw new Error(
|
|
973
|
+
`[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.`
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
let newValue;
|
|
977
|
+
if (typeof newValueOrUpdater === "function") {
|
|
978
|
+
const updater = newValueOrUpdater;
|
|
979
|
+
newValue = updater(value);
|
|
980
|
+
} else {
|
|
981
|
+
newValue = newValueOrUpdater;
|
|
982
|
+
}
|
|
983
|
+
if (Object.is(value, newValue)) return;
|
|
984
|
+
if (isBulkCommitActive2()) {
|
|
985
|
+
value = newValue;
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
value = newValue;
|
|
989
|
+
const readersMap = read._readers;
|
|
990
|
+
if (readersMap) {
|
|
991
|
+
for (const [subInst, token] of readersMap) {
|
|
992
|
+
if (subInst.lastRenderToken !== token) continue;
|
|
993
|
+
if (!subInst.hasPendingUpdate) {
|
|
994
|
+
subInst.hasPendingUpdate = true;
|
|
995
|
+
const subTask = subInst._pendingFlushTask;
|
|
996
|
+
if (subTask) globalScheduler.enqueue(subTask);
|
|
997
|
+
else
|
|
998
|
+
globalScheduler.enqueue(() => {
|
|
999
|
+
subInst.hasPendingUpdate = false;
|
|
1000
|
+
subInst.notifyUpdate?.();
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
const readersMapForOwner = readersMap;
|
|
1006
|
+
const ownerRecordedToken = readersMapForOwner?.get(instance);
|
|
1007
|
+
const ownerShouldEnqueue = (
|
|
1008
|
+
// Normal case: owner read this state in last committed render
|
|
1009
|
+
ownerRecordedToken !== void 0 && instance.lastRenderToken === ownerRecordedToken
|
|
1010
|
+
);
|
|
1011
|
+
if (ownerShouldEnqueue && !instance.hasPendingUpdate) {
|
|
1012
|
+
instance.hasPendingUpdate = true;
|
|
1013
|
+
const task = instance._pendingFlushTask;
|
|
1014
|
+
if (task) globalScheduler.enqueue(task);
|
|
1015
|
+
else
|
|
1016
|
+
globalScheduler.enqueue(() => {
|
|
1017
|
+
instance.hasPendingUpdate = false;
|
|
1018
|
+
instance.notifyUpdate?.();
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
return read;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// src/common/ssr-errors.ts
|
|
1026
|
+
var SSRDataMissingError = class _SSRDataMissingError extends Error {
|
|
1027
|
+
constructor(message = "Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.") {
|
|
1028
|
+
super(message);
|
|
1029
|
+
this.code = "SSR_DATA_MISSING";
|
|
1030
|
+
this.name = "SSRDataMissingError";
|
|
1031
|
+
Object.setPrototypeOf(this, _SSRDataMissingError.prototype);
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
// src/runtime/operations.ts
|
|
1036
|
+
function resource(fn, deps = []) {
|
|
1037
|
+
const instance = getCurrentComponentInstance();
|
|
1038
|
+
const inst = instance;
|
|
1039
|
+
if (!instance) {
|
|
1040
|
+
const ssr2 = getSSRBridge();
|
|
1041
|
+
const renderData2 = ssr2.getCurrentRenderData();
|
|
1042
|
+
if (renderData2) {
|
|
1043
|
+
const key = ssr2.getNextKey();
|
|
1044
|
+
if (!(key in renderData2)) {
|
|
1045
|
+
ssr2.throwSSRDataMissing();
|
|
1046
|
+
}
|
|
1047
|
+
const val = renderData2[key];
|
|
1048
|
+
return {
|
|
1049
|
+
value: val,
|
|
1050
|
+
pending: false,
|
|
1051
|
+
error: null,
|
|
1052
|
+
refresh: () => {
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
const ssrCtx = ssr2.getCurrentSSRContext();
|
|
1057
|
+
if (ssrCtx) {
|
|
1058
|
+
ssr2.throwSSRDataMissing();
|
|
1059
|
+
}
|
|
1060
|
+
throw new Error(
|
|
1061
|
+
"[Askr] resource() must be called during component render inside an app. Do not create resources at module scope or outside render."
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
const ssr = getSSRBridge();
|
|
1065
|
+
const renderData = ssr.getCurrentRenderData();
|
|
1066
|
+
if (renderData) {
|
|
1067
|
+
const key = ssr.getNextKey();
|
|
1068
|
+
if (!(key in renderData)) {
|
|
1069
|
+
ssr.throwSSRDataMissing();
|
|
1070
|
+
}
|
|
1071
|
+
const val = renderData[key];
|
|
1072
|
+
const holder2 = state({
|
|
1073
|
+
cell: void 0,
|
|
1074
|
+
snapshot: {
|
|
1075
|
+
value: val,
|
|
1076
|
+
pending: false,
|
|
1077
|
+
error: null,
|
|
1078
|
+
refresh: () => {
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
const h2 = holder2();
|
|
1083
|
+
h2.snapshot.value = val;
|
|
1084
|
+
h2.snapshot.pending = false;
|
|
1085
|
+
h2.snapshot.error = null;
|
|
1086
|
+
holder2.set(h2);
|
|
1087
|
+
return h2.snapshot;
|
|
1088
|
+
}
|
|
1089
|
+
const holder = state(
|
|
1090
|
+
{
|
|
1091
|
+
cell: void 0,
|
|
1092
|
+
snapshot: {
|
|
1093
|
+
value: null,
|
|
1094
|
+
pending: true,
|
|
1095
|
+
error: null,
|
|
1096
|
+
refresh: () => {
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1101
|
+
const h = holder();
|
|
1102
|
+
if (!h.cell) {
|
|
1103
|
+
const frame = getCurrentContextFrame();
|
|
1104
|
+
const cell2 = new ResourceCell(fn, deps, frame);
|
|
1105
|
+
cell2.ownerName = inst.fn?.name || "<anonymous>";
|
|
1106
|
+
h.cell = cell2;
|
|
1107
|
+
h.snapshot = cell2.snapshot;
|
|
1108
|
+
const unsubscribe = cell2.subscribe(() => {
|
|
1109
|
+
const cur = holder();
|
|
1110
|
+
cur.snapshot.value = cell2.snapshot.value;
|
|
1111
|
+
cur.snapshot.pending = cell2.snapshot.pending;
|
|
1112
|
+
cur.snapshot.error = cell2.snapshot.error;
|
|
1113
|
+
holder.set(cur);
|
|
1114
|
+
try {
|
|
1115
|
+
inst._enqueueRun?.();
|
|
1116
|
+
} catch {
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
inst.cleanupFns.push(() => {
|
|
1120
|
+
unsubscribe();
|
|
1121
|
+
cell2.abort();
|
|
1122
|
+
});
|
|
1123
|
+
if (inst.ssr) {
|
|
1124
|
+
cell2.start(true, false);
|
|
1125
|
+
if (!cell2.pending) {
|
|
1126
|
+
const cur = holder();
|
|
1127
|
+
cur.snapshot.value = cell2.value;
|
|
1128
|
+
cur.snapshot.pending = cell2.pending;
|
|
1129
|
+
cur.snapshot.error = cell2.error;
|
|
1130
|
+
}
|
|
1131
|
+
} else {
|
|
1132
|
+
globalScheduler.enqueue(() => {
|
|
1133
|
+
try {
|
|
1134
|
+
cell2.start(false, false);
|
|
1135
|
+
} catch (err) {
|
|
1136
|
+
const cur = holder();
|
|
1137
|
+
cur.snapshot.value = cell2.value;
|
|
1138
|
+
cur.snapshot.pending = cell2.pending;
|
|
1139
|
+
cur.snapshot.error = err ?? null;
|
|
1140
|
+
holder.set(cur);
|
|
1141
|
+
inst._enqueueRun?.();
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
if (!cell2.pending) {
|
|
1145
|
+
const cur = holder();
|
|
1146
|
+
cur.snapshot.value = cell2.value;
|
|
1147
|
+
cur.snapshot.pending = cell2.pending;
|
|
1148
|
+
cur.snapshot.error = cell2.error;
|
|
1149
|
+
holder.set(cur);
|
|
1150
|
+
inst._enqueueRun?.();
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
const cell = h.cell;
|
|
1156
|
+
const depsChanged = !cell.deps || cell.deps.length !== deps.length || cell.deps.some((d, i) => d !== deps[i]);
|
|
1157
|
+
if (depsChanged) {
|
|
1158
|
+
cell.deps = deps.slice();
|
|
1159
|
+
cell.generation++;
|
|
1160
|
+
cell.pending = true;
|
|
1161
|
+
cell.error = null;
|
|
1162
|
+
try {
|
|
1163
|
+
if (inst.ssr) {
|
|
1164
|
+
cell.start(true, false);
|
|
1165
|
+
if (!cell.pending) {
|
|
1166
|
+
const cur = holder();
|
|
1167
|
+
cur.snapshot.value = cell.value;
|
|
1168
|
+
cur.snapshot.pending = cell.pending;
|
|
1169
|
+
cur.snapshot.error = cell.error;
|
|
1170
|
+
}
|
|
1171
|
+
} else {
|
|
1172
|
+
globalScheduler.enqueue(() => {
|
|
1173
|
+
cell.start(false, false);
|
|
1174
|
+
if (!cell.pending) {
|
|
1175
|
+
const cur = holder();
|
|
1176
|
+
cur.snapshot.value = cell.value;
|
|
1177
|
+
cur.snapshot.pending = cell.pending;
|
|
1178
|
+
cur.snapshot.error = cell.error;
|
|
1179
|
+
holder.set(cur);
|
|
1180
|
+
inst._enqueueRun?.();
|
|
1181
|
+
}
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
} catch (err) {
|
|
1185
|
+
if (err instanceof SSRDataMissingError) throw err;
|
|
1186
|
+
cell.error = err;
|
|
1187
|
+
cell.pending = false;
|
|
1188
|
+
const cur = holder();
|
|
1189
|
+
cur.snapshot.value = cell.value;
|
|
1190
|
+
cur.snapshot.pending = cell.pending;
|
|
1191
|
+
cur.snapshot.error = cell.error;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return h.snapshot;
|
|
1195
|
+
}
|
|
1196
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1197
|
+
0 && (module.exports = {
|
|
1198
|
+
resource
|
|
1199
|
+
});
|
|
1200
|
+
//# sourceMappingURL=index.cjs.map
|