@askrjs/askr 0.3.0 → 0.4.0
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/CHANGELOG.md +874 -0
- package/README.md +61 -29
- package/capabilities.json +19 -9
- package/dist/actions/index.js +56 -12
- package/dist/benchmark.js +10 -15
- package/dist/boot/index.d.ts +3 -2
- package/dist/boot/index.js +1 -1
- package/dist/boot-DaoTYoCw.js +3989 -0
- package/dist/browser-activity-CB8e-V4f.js +220 -0
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +1 -43
- package/dist/{aria-hKjThHcp.js → compose-ref-DWzdbxsD.js} +41 -4
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -1
- package/dist/control-nfpT2fbK.js +209 -0
- package/dist/core.d.ts +5 -9
- package/dist/csp-nonce-DwGw1A6Q.js +35 -0
- package/dist/data/index.js +3 -3
- package/dist/{data-2edW0jhF.js → data-BCwClJiF.js} +283 -94
- package/dist/data-runtime-C1bFAlba.js +242 -0
- package/dist/{deferred-CbgNhf67.js → deferred-bEEHHvic.js} +42 -20
- package/dist/domains/actions.d.ts +8 -3
- package/dist/domains/component.d.ts +1 -107
- package/dist/domains/context.d.ts +0 -15
- package/dist/domains/control.d.ts +36 -249
- package/dist/domains/data.d.ts +31 -13
- package/dist/domains/diagnostics.d.ts +1 -2
- package/dist/domains/lifecycle.d.ts +2 -5
- package/dist/domains/refs.d.ts +0 -2
- package/dist/domains/routing.d.ts +43 -8
- package/dist/domains/scheduler.d.ts +1 -76
- package/dist/domains/server.d.ts +5 -2
- package/dist/domains/state.d.ts +2 -5
- package/dist/domains/telemetry.d.ts +0 -2
- package/dist/elements.d.ts +214 -51
- package/dist/error-boundary-Bpwofwps.js +293 -0
- package/dist/foundations/icon/index.d.ts +0 -58
- package/dist/foundations/icon/index.js +2 -2
- package/dist/foundations/index.js +2 -1
- package/dist/foundations/interactions/index.js +1 -1
- package/dist/foundations/state/index.d.ts +3 -3
- package/dist/foundations/state/index.js +5 -3
- package/dist/foundations/structures/index.js +2 -1
- package/dist/foundations/utilities/index.d.ts +2 -0
- package/dist/foundations/utilities/index.js +1 -2
- package/dist/fx/index.d.ts +31 -58
- package/dist/fx/index.js +313 -195
- package/dist/hooks-BimKStr4.js +202 -0
- package/dist/index.d.ts +11 -74
- package/dist/index.js +8 -447
- package/dist/instance-BAnfmXOR.js +988 -0
- package/dist/{interactions-CTeACdT_.js → interactions-D2BoREb-.js} +3 -2
- package/dist/jsx-dev-runtime.d.ts +41 -18
- package/dist/jsx-dev-runtime.js +1 -6
- package/dist/{jsx-runtime-CPJXAOBF.js → jsx-runtime-C4idqHY0.js} +18 -7
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx.d.ts +61 -37
- package/dist/{manifest-D1P3UNWV.js → manifest-CW9gyNBY.js} +3 -3
- package/dist/{navigate-prC5V8XV.js → navigate-CP_0Zy5U.js} +454 -87
- package/dist/navigation.d.ts +12 -3
- package/dist/peer-types.d.ts +8 -0
- package/dist/portal-DuOKfnLa.js +349 -0
- package/dist/promise-Dz8iIHAm.js +16 -0
- package/dist/query-registry-WMCN0BJL.js +320 -0
- package/dist/readable-DFWOsTac.js +21 -0
- package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
- package/dist/render-sync-IC5lMFpq.js +1240 -0
- package/dist/resolution-Cx82-xjW.js +1244 -0
- package/dist/resource-CLjB7RBQ.js +377 -0
- package/dist/resources/index.d.ts +21 -11
- package/dist/resources/index.js +45 -244
- package/dist/router/index.d.ts +14 -5
- package/dist/router/index.js +22 -53
- package/dist/scope-CwpVSHVf.js +55 -0
- package/dist/{shared-kU8yvryp.js → shared-O2ZnmYAf.js} +1 -7
- package/dist/{snapshot-source-An4iKajG.js → snapshot-Cjx4N988.js} +6 -1
- package/dist/ssg/index.d.ts +1 -2
- package/dist/ssg/index.js +5 -13
- package/dist/ssr/index.d.ts +26 -28
- package/dist/ssr/index.js +4 -4
- package/dist/{ssr-CiNm6Vzl.js → ssr-BJ8ug7zH.js} +133 -122
- package/dist/ssr-DoV-vJ-5.js +229 -0
- package/dist/state-DWO1KzkX.js +232 -0
- package/dist/structures-D4dDMqHX.js +231 -0
- package/dist/testing/index.d.ts +8 -4
- package/dist/testing/index.js +29 -34
- package/dist/url-CnbfpX0K.js +185 -0
- package/dist/utilities.d.ts +48 -2
- package/dist/verify-hydration-DpVaDnqz.js +152 -0
- package/package.json +19 -9
- package/dist/access-CEA2pOry.js +0 -1046
- package/dist/activity-oy2YFTFF.js +0 -201
- package/dist/boot-BMBMWUGI.js +0 -1084
- package/dist/capabilities-Bbf0mlp9.js +0 -42
- package/dist/compose-ref-v0qGlHoN.js +0 -26
- package/dist/control-BR_mrX__.js +0 -173
- package/dist/control-C-ApnFs1.js +0 -20
- package/dist/csp-nonce-BfFWcd0w.js +0 -173
- package/dist/data-runtime-CxoY98lX.js +0 -149
- package/dist/default-portal-runtime-DvMvWJVp.js +0 -20
- package/dist/dom-renderer.d.ts +0 -77
- package/dist/domains/renderer.d.ts +0 -127
- package/dist/eager-control.d.ts +0 -8
- package/dist/effect-C3Zsc1k6.js +0 -292
- package/dist/for-state-BDykeOJL.js +0 -1753
- package/dist/instance-VAFYVJOa.js +0 -1027
- package/dist/notify-DxxuDPeY.js +0 -266
- package/dist/portal-w3oQ6oQU.js +0 -29
- package/dist/query-registry-LrYpQsDJ.js +0 -83
- package/dist/render-resolved-BC0W7_5b.js +0 -1123
- package/dist/renderer-CT0HeY58.js +0 -8623
- package/dist/resolution-3DskUkjG.js +0 -577
- package/dist/resource-18-sFRl9.js +0 -344
- package/dist/route-matching-CUzZ31gT.js +0 -551
- package/dist/router-internal-7nuNEHfG.js +0 -36
- package/dist/scope-Cq_iYbTR.js +0 -403
- package/dist/selector-BSPVkjKP.js +0 -311
- package/dist/ssr-EPjwJH5R.js +0 -29
- package/dist/state-BXJfudq1.js +0 -91
- package/dist/structures-CjEzfj4h.js +0 -654
- package/dist/timer-C7uqnJVt.js +0 -85
- package/dist/verify-hydration-ikaxotf7.js +0 -27
- package/dist/vnode-D24p6IW2.js +0 -7
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { r as currentAppRuntime } from "./hooks-BimKStr4.js";
|
|
2
|
+
import { n as getActiveRenderContext } from "./render-context-DGHnEveC.js";
|
|
3
|
+
//#region src/data/invalidation-listeners.ts
|
|
4
|
+
const invalidationListeners = /* @__PURE__ */ new Set();
|
|
5
|
+
const activeInvalidationPrefixes = [];
|
|
6
|
+
const MAX_INVALIDATION_CASCADE_DEPTH = 100;
|
|
7
|
+
function addInvalidationListener(listener) {
|
|
8
|
+
invalidationListeners.add(listener);
|
|
9
|
+
return () => {
|
|
10
|
+
invalidationListeners.delete(listener);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Whether any listener is registered. Listeners come only from the testing
|
|
15
|
+
* entry (`createInvalidationRecorder()`), so production invalidations check
|
|
16
|
+
* this and skip dispatch and cascade bookkeeping entirely.
|
|
17
|
+
*/
|
|
18
|
+
function hasInvalidationListeners() {
|
|
19
|
+
return invalidationListeners.size > 0;
|
|
20
|
+
}
|
|
21
|
+
function emitInvalidation(event) {
|
|
22
|
+
if (activeInvalidationPrefixes.includes(event.prefix)) throw new Error(`[Askr] Cyclic invalidation cascade detected for prefix ${JSON.stringify(event.prefix)}.`);
|
|
23
|
+
if (activeInvalidationPrefixes.length >= MAX_INVALIDATION_CASCADE_DEPTH) throw new Error(`[Askr] Invalidation cascade exceeded ${MAX_INVALIDATION_CASCADE_DEPTH} nested events at prefix ${JSON.stringify(event.prefix)}.`);
|
|
24
|
+
activeInvalidationPrefixes.push(event.prefix);
|
|
25
|
+
try {
|
|
26
|
+
for (const listener of invalidationListeners) listener(event);
|
|
27
|
+
} finally {
|
|
28
|
+
activeInvalidationPrefixes.pop();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/data/collection-invalidation.ts
|
|
33
|
+
const owners = /* @__PURE__ */ new WeakMap();
|
|
34
|
+
function registerCollectionCell(cell, owner) {
|
|
35
|
+
let registrations = owners.get(cell);
|
|
36
|
+
if (!registrations) {
|
|
37
|
+
registrations = /* @__PURE__ */ new Set();
|
|
38
|
+
owners.set(cell, registrations);
|
|
39
|
+
}
|
|
40
|
+
registrations.add(owner);
|
|
41
|
+
}
|
|
42
|
+
function unregisterCollectionCell(cell, owner) {
|
|
43
|
+
const registrations = owners.get(cell);
|
|
44
|
+
registrations?.delete(owner);
|
|
45
|
+
if (registrations?.size === 0) owners.delete(cell);
|
|
46
|
+
}
|
|
47
|
+
/** A shared query uses the smallest cap among its live collection readers. */
|
|
48
|
+
function invalidateCollectionCell(cell) {
|
|
49
|
+
const registrations = owners.get(cell);
|
|
50
|
+
if (!registrations?.size) return false;
|
|
51
|
+
let selected;
|
|
52
|
+
for (const owner of registrations) if (!selected || owner.invalidationConcurrency < selected.invalidationConcurrency) selected = owner;
|
|
53
|
+
selected.invalidateCell(cell);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/data/data-runtime.ts
|
|
58
|
+
const dataRuntimeStates = /* @__PURE__ */ new WeakMap();
|
|
59
|
+
const dataRuntimeByQueryCache = /* @__PURE__ */ new WeakMap();
|
|
60
|
+
function createDataRuntimeState(queryCache, queryData) {
|
|
61
|
+
return {
|
|
62
|
+
queryCache,
|
|
63
|
+
queryData,
|
|
64
|
+
unreadPrefetches: /* @__PURE__ */ new Map(),
|
|
65
|
+
prefetches: /* @__PURE__ */ new Map(),
|
|
66
|
+
querySlotsByGeneration: /* @__PURE__ */ new WeakMap(),
|
|
67
|
+
mutationSlotsByGeneration: /* @__PURE__ */ new WeakMap(),
|
|
68
|
+
queryCleanupRegistered: /* @__PURE__ */ new WeakSet(),
|
|
69
|
+
mutationCleanupRegistered: /* @__PURE__ */ new WeakSet(),
|
|
70
|
+
queryTestOverrides: /* @__PURE__ */ new Map(),
|
|
71
|
+
mutationTestOverrides: /* @__PURE__ */ new Map()
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** Create a new, isolated {@link DataRuntime} with its own query/mutation caches. */
|
|
75
|
+
function createDataRuntime(options = {}) {
|
|
76
|
+
const runtime = Object.freeze({
|
|
77
|
+
queryCache: options.queryCache ?? /* @__PURE__ */ new Map(),
|
|
78
|
+
queryData: options.queryData ?? /* @__PURE__ */ new Map()
|
|
79
|
+
});
|
|
80
|
+
dataRuntimeStates.set(runtime, createDataRuntimeState(runtime.queryCache, runtime.queryData));
|
|
81
|
+
dataRuntimeByQueryCache.set(runtime.queryCache, runtime);
|
|
82
|
+
return runtime;
|
|
83
|
+
}
|
|
84
|
+
const defaultDataRuntime = createDataRuntime();
|
|
85
|
+
/** Get the process-wide default {@link DataRuntime} used when none is provided explicitly. */
|
|
86
|
+
function getDefaultDataRuntime() {
|
|
87
|
+
return defaultDataRuntime;
|
|
88
|
+
}
|
|
89
|
+
function getDataRuntimeState(runtime) {
|
|
90
|
+
const state = dataRuntimeStates.get(runtime);
|
|
91
|
+
if (!state) throw new Error("[Askr] data runtime was not created by createDataRuntime().");
|
|
92
|
+
return state;
|
|
93
|
+
}
|
|
94
|
+
function isDataRuntime(value) {
|
|
95
|
+
return typeof value === "object" && value !== null && dataRuntimeStates.has(value);
|
|
96
|
+
}
|
|
97
|
+
function getDataRuntimeForQueryCache(queryCache) {
|
|
98
|
+
let runtime = dataRuntimeByQueryCache.get(queryCache);
|
|
99
|
+
if (!runtime) {
|
|
100
|
+
runtime = createDataRuntime({ queryCache });
|
|
101
|
+
dataRuntimeByQueryCache.set(queryCache, runtime);
|
|
102
|
+
}
|
|
103
|
+
return runtime;
|
|
104
|
+
}
|
|
105
|
+
function getActiveDataRuntime() {
|
|
106
|
+
const ctx = getActiveRenderContext();
|
|
107
|
+
if (isDataRuntime(ctx?.dataRuntime)) return ctx.dataRuntime;
|
|
108
|
+
if (ctx?.queryCache) return getDataRuntimeForQueryCache(ctx.queryCache);
|
|
109
|
+
const appRuntime = currentAppRuntime();
|
|
110
|
+
if (appRuntime?.dataRuntime) return appRuntime.dataRuntime;
|
|
111
|
+
return defaultDataRuntime;
|
|
112
|
+
}
|
|
113
|
+
function getActiveDataRuntimeState() {
|
|
114
|
+
return getDataRuntimeState(getActiveDataRuntime());
|
|
115
|
+
}
|
|
116
|
+
function resolveDataRuntimeState(runtime) {
|
|
117
|
+
return runtime ? getDataRuntimeState(runtime) : getActiveDataRuntimeState();
|
|
118
|
+
}
|
|
119
|
+
/** State for a runtime from createDataRuntime(); undefined for hand-built ones. */
|
|
120
|
+
function findDataRuntimeState(runtime) {
|
|
121
|
+
return dataRuntimeStates.get(runtime);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Read hydrated or prefetched data for a new query cell. Client readers
|
|
125
|
+
* consume it: the cell owns the value from then on, so keeping the entry would
|
|
126
|
+
* revive it as fresh after the cell is gone.
|
|
127
|
+
*/
|
|
128
|
+
function readQueryData(runtimeState, key, consume) {
|
|
129
|
+
const value = runtimeState.queryData.get(key);
|
|
130
|
+
if (consume) {
|
|
131
|
+
runtimeState.queryData.delete(key);
|
|
132
|
+
runtimeState.unreadPrefetches.delete(key);
|
|
133
|
+
}
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Store browser-prefetched data. Unread entries are capped: the oldest one is
|
|
138
|
+
* evicted once more than {@link PREFETCHED_QUERY_DATA_LIMIT} are waiting.
|
|
139
|
+
* Entries replaced or removed through `queryData` directly are no longer
|
|
140
|
+
* tracked and are never evicted by the cap.
|
|
141
|
+
*/
|
|
142
|
+
function writePrefetchedQueryData(runtimeState, key, value) {
|
|
143
|
+
const { queryData, unreadPrefetches } = runtimeState;
|
|
144
|
+
queryData.set(key, value);
|
|
145
|
+
unreadPrefetches.delete(key);
|
|
146
|
+
unreadPrefetches.set(key, value);
|
|
147
|
+
for (const [oldestKey, oldestValue] of unreadPrefetches) {
|
|
148
|
+
if (unreadPrefetches.size <= 50) return;
|
|
149
|
+
unreadPrefetches.delete(oldestKey);
|
|
150
|
+
if (queryData.get(oldestKey) === oldestValue) queryData.delete(oldestKey);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Run `fn` for every entry even when some throw; rethrow the failures. */
|
|
154
|
+
function drain(entries, fn) {
|
|
155
|
+
const errors = [];
|
|
156
|
+
for (const entry of Array.from(entries)) try {
|
|
157
|
+
fn(entry);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
errors.push(error);
|
|
160
|
+
}
|
|
161
|
+
if (errors.length === 1) throw errors[0];
|
|
162
|
+
if (errors.length > 1) throw new AggregateError(errors, "Data cleanup failed");
|
|
163
|
+
}
|
|
164
|
+
function getQuerySlotStore(runtimeState, instance) {
|
|
165
|
+
const generation = instance;
|
|
166
|
+
let store = runtimeState.querySlotsByGeneration.get(generation);
|
|
167
|
+
if (!store) {
|
|
168
|
+
store = /* @__PURE__ */ new Map();
|
|
169
|
+
runtimeState.querySlotsByGeneration.set(generation, store);
|
|
170
|
+
}
|
|
171
|
+
return store;
|
|
172
|
+
}
|
|
173
|
+
function getMutationSlotStore(runtimeState, instance) {
|
|
174
|
+
const generation = instance;
|
|
175
|
+
let store = runtimeState.mutationSlotsByGeneration.get(generation);
|
|
176
|
+
if (!store) {
|
|
177
|
+
store = /* @__PURE__ */ new Map();
|
|
178
|
+
runtimeState.mutationSlotsByGeneration.set(generation, store);
|
|
179
|
+
}
|
|
180
|
+
return store;
|
|
181
|
+
}
|
|
182
|
+
function ensureQueryCleanup(runtimeState, instance) {
|
|
183
|
+
const generation = instance;
|
|
184
|
+
if (runtimeState.queryCleanupRegistered.has(generation)) return;
|
|
185
|
+
runtimeState.queryCleanupRegistered.add(generation);
|
|
186
|
+
const slots = getQuerySlotStore(runtimeState, instance);
|
|
187
|
+
instance.onCleanup(() => {
|
|
188
|
+
try {
|
|
189
|
+
drain(slots, ([hookIndex, slot]) => slot.cell.detach(generation, hookIndex));
|
|
190
|
+
} finally {
|
|
191
|
+
slots.clear();
|
|
192
|
+
runtimeState.querySlotsByGeneration.delete(generation);
|
|
193
|
+
runtimeState.queryCleanupRegistered.delete(generation);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function ensureMutationCleanup(runtimeState, instance) {
|
|
198
|
+
const generation = instance;
|
|
199
|
+
if (runtimeState.mutationCleanupRegistered.has(generation)) return;
|
|
200
|
+
runtimeState.mutationCleanupRegistered.add(generation);
|
|
201
|
+
const slots = getMutationSlotStore(runtimeState, instance);
|
|
202
|
+
instance.onCleanup(() => {
|
|
203
|
+
try {
|
|
204
|
+
drain(slots.values(), (slot) => slot.cell.abort());
|
|
205
|
+
} finally {
|
|
206
|
+
slots.clear();
|
|
207
|
+
runtimeState.mutationSlotsByGeneration.delete(generation);
|
|
208
|
+
runtimeState.mutationCleanupRegistered.delete(generation);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Whether `key` falls under the invalidation `prefix`, matching whole
|
|
214
|
+
* `:`-delimited segments: `user:1` covers `user:1` and `user:1:posts` but not
|
|
215
|
+
* `user:10`. A prefix that already ends in `:` (every `queryScope()` prefix
|
|
216
|
+
* does) covers everything below it, and the empty prefix covers every key.
|
|
217
|
+
*/
|
|
218
|
+
function matchesInvalidationPrefix(key, prefix) {
|
|
219
|
+
return key.startsWith(prefix) && (key.length === prefix.length || prefix.length === 0 || prefix.endsWith(":") || key[prefix.length] === ":");
|
|
220
|
+
}
|
|
221
|
+
function invalidateQueriesForRuntime(runtimeState, prefix, markPendingWrite) {
|
|
222
|
+
if (hasInvalidationListeners()) emitInvalidation({
|
|
223
|
+
prefix,
|
|
224
|
+
markPendingWrite
|
|
225
|
+
});
|
|
226
|
+
for (const [key, prefetch] of runtimeState.prefetches) if (matchesInvalidationPrefix(key, prefix)) {
|
|
227
|
+
prefetch.invalidated = true;
|
|
228
|
+
runtimeState.prefetches.delete(key);
|
|
229
|
+
}
|
|
230
|
+
for (const key of runtimeState.queryData.keys()) if (matchesInvalidationPrefix(key, prefix)) {
|
|
231
|
+
runtimeState.queryData.delete(key);
|
|
232
|
+
runtimeState.unreadPrefetches.delete(key);
|
|
233
|
+
}
|
|
234
|
+
const cache = runtimeState.queryCache;
|
|
235
|
+
for (const [key, query] of cache) {
|
|
236
|
+
if (!matchesInvalidationPrefix(key, prefix)) continue;
|
|
237
|
+
if (markPendingWrite) query.markPendingWrite();
|
|
238
|
+
if (!invalidateCollectionCell(query)) query.invalidate();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
export { getDefaultDataRuntime as a, invalidateQueriesForRuntime as c, writePrefetchedQueryData as d, invalidateCollectionCell as f, addInvalidationListener as h, findDataRuntimeState as i, readQueryData as l, unregisterCollectionCell as m, ensureMutationCleanup as n, getMutationSlotStore as o, registerCollectionCell as p, ensureQueryCleanup as r, getQuerySlotStore as s, createDataRuntime as t, resolveDataRuntimeState as u };
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { allOf } from "@askrjs/auth";
|
|
1
|
+
import { i as currentComponent, r as currentAppRuntime } from "./hooks-BimKStr4.js";
|
|
2
|
+
import { c as registerDeferredBoundary, n as getActiveRenderContext, r as getCurrentRenderData } from "./render-context-DGHnEveC.js";
|
|
3
|
+
import { d as DEFERRED_BOUNDARY, p as isDeferred } from "./query-registry-WMCN0BJL.js";
|
|
4
|
+
import { B as getCurrentPathPrefix, F as getCurrentInheritedMeta, G as getRouteRecords, I as getCurrentInheritedPolicies, J as insertRecordSorted, K as hasActivePageScope, L as getCurrentLayoutChain, O as addRouteToStores, P as getCurrentInheritedAuthRequirements, R as getCurrentPageChain, U as getDefaultRouteBasePath, V as getCurrentScopeKind, X as pushRegistrationScope, dt as routeMatchKey, k as assertRouteRegistrationUnlocked, lt as normalizeRouteSegmentName, pt as guardHydratedRouteData, st as computeRank, tt as createRouteHandler, ut as parseSegments, z as getCurrentPageScope } from "./resolution-Cx82-xjW.js";
|
|
5
|
+
import { i as getExecutionModel } from "./manifest-CW9gyNBY.js";
|
|
6
|
+
import { t as resource } from "./resource-CLjB7RBQ.js";
|
|
8
7
|
//#region src/router/access.ts
|
|
9
8
|
function compileNodePolicies(node) {
|
|
10
9
|
return node.policies ? [...node.policies] : [];
|
|
@@ -43,7 +42,11 @@ function normalizeAbsoluteRoutePath(path) {
|
|
|
43
42
|
}
|
|
44
43
|
function joinRoutePaths(prefix, path) {
|
|
45
44
|
const normalizedPrefix = normalizeAbsoluteRoutePath(prefix || "/");
|
|
46
|
-
|
|
45
|
+
let start = 0;
|
|
46
|
+
let end = path.length;
|
|
47
|
+
while (start < end && path[start] === "/") start++;
|
|
48
|
+
while (end > start && path[end - 1] === "/") end--;
|
|
49
|
+
const normalizedPath = path.slice(start, end);
|
|
47
50
|
if (!normalizedPath) return normalizedPrefix;
|
|
48
51
|
return normalizedPrefix === "/" ? `/${normalizedPath}` : `${normalizedPrefix}/${normalizedPath}`;
|
|
49
52
|
}
|
|
@@ -98,12 +101,13 @@ function normalizeRouteOptions(options) {
|
|
|
98
101
|
const dehydrate = options.dehydrate;
|
|
99
102
|
const preload = options.preload;
|
|
100
103
|
const policies = compileNodePolicies(options);
|
|
101
|
-
if (!loader && !dehydrate && !preload && !options.entries && policies.length === 0 && !options.title && !options.namespace && !options.search && !options.meta && !options.actions && options.auth === void 0) return;
|
|
104
|
+
if (!loader && !dehydrate && !preload && !options.entries && !options.invalidationKeys && policies.length === 0 && !options.title && !options.namespace && !options.search && !options.meta && !options.actions && options.auth === void 0) return;
|
|
102
105
|
return {
|
|
103
106
|
...loader ? { loader } : {},
|
|
104
107
|
...dehydrate ? { dehydrate } : {},
|
|
105
108
|
...preload ? { preload } : {},
|
|
106
109
|
...options.entries ? { entries: options.entries } : {},
|
|
110
|
+
...options.invalidationKeys ? { invalidationKeys: options.invalidationKeys } : {},
|
|
107
111
|
...options.auth !== void 0 ? { auth: options.auth } : {},
|
|
108
112
|
...policies.length > 0 ? { policies } : {},
|
|
109
113
|
...options.title ? { title: options.title } : {},
|
|
@@ -113,18 +117,37 @@ function normalizeRouteOptions(options) {
|
|
|
113
117
|
...options.actions ? { actions: options.actions } : {}
|
|
114
118
|
};
|
|
115
119
|
}
|
|
120
|
+
function assertRouteNotDuplicated(path, segments, fallbackPrefix) {
|
|
121
|
+
const key = routeMatchKey(segments, fallbackPrefix);
|
|
122
|
+
const existing = getRouteRecords().find((record) => routeMatchKey(record.segments, record.fallbackPrefix) === key);
|
|
123
|
+
if (existing) {
|
|
124
|
+
const hint = existing.path === path ? " To generate several pages from one route template, declare it once and return each page's params from entries()." : "";
|
|
125
|
+
throw new Error(`Duplicate route path "${path}": it matches the same URLs as "${existing.path}", which is already registered.${hint}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const authAllowed = Object.freeze({ allowed: true });
|
|
129
|
+
function requireAll(requirements) {
|
|
130
|
+
return async (context) => {
|
|
131
|
+
for (const requirement of requirements) {
|
|
132
|
+
const decision = await requirement(context);
|
|
133
|
+
if (!decision.allowed) return decision;
|
|
134
|
+
}
|
|
135
|
+
return authAllowed;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
116
138
|
function registerRouteAtResolvedPath(path, Component, options, metadata) {
|
|
117
139
|
validateRoutePath(path);
|
|
140
|
+
const segments = parseSegments(path);
|
|
141
|
+
assertRouteNotDuplicated(path, segments, metadata?.fallbackPrefix);
|
|
118
142
|
const chain = getCurrentLayoutChain();
|
|
119
143
|
const pageChain = getCurrentPageChain();
|
|
120
|
-
const segments = parseSegments(path);
|
|
121
144
|
const rank = computeRank(segments);
|
|
122
145
|
const isFallback = metadata?.isFallback ?? path === "/*";
|
|
123
146
|
const comp = Component;
|
|
124
147
|
const normalizedOptions = normalizeRouteOptions(options);
|
|
125
148
|
const policies = [...getCurrentInheritedPolicies(), ...normalizedOptions?.policies ?? []];
|
|
126
149
|
const authRequirements = [...getCurrentInheritedAuthRequirements(), ...normalizedOptions?.auth ? [normalizedOptions.auth] : []];
|
|
127
|
-
const auth = authRequirements.length === 0 ? void 0 : authRequirements.length === 1 ? authRequirements[0] :
|
|
150
|
+
const auth = authRequirements.length === 0 ? void 0 : authRequirements.length === 1 ? authRequirements[0] : requireAll(authRequirements);
|
|
128
151
|
const metaChain = [...getCurrentInheritedMeta(), ...normalizedOptions?.meta ? [normalizedOptions.meta] : []];
|
|
129
152
|
const handler = createRouteHandler(comp, pageChain, chain);
|
|
130
153
|
const renderHandler = createRouteHandler(comp, pageChain, chain, true);
|
|
@@ -192,9 +215,9 @@ function fallback(Component) {
|
|
|
192
215
|
}
|
|
193
216
|
function route(path, Component, options) {
|
|
194
217
|
if (typeof path === "undefined") throw new Error("route() is only for route registration. Use currentRoute() inside components.");
|
|
195
|
-
if (getExecutionModel() === "islands") throw new Error("Routes are not supported with islands. Use createSPA
|
|
196
|
-
const currentInst =
|
|
197
|
-
if (currentInst && currentInst.
|
|
218
|
+
if (getExecutionModel() === "islands") throw new Error("Routes are not supported with islands. Use createSPA or hydrateSPA with a route registry instead.");
|
|
219
|
+
const currentInst = currentComponent();
|
|
220
|
+
if (currentInst && currentInst.server) throw new Error("route() cannot be called during SSR rendering. Register routes at module load time instead.");
|
|
198
221
|
assertRouteRegistrationUnlocked();
|
|
199
222
|
if (typeof Component !== "function") throw new Error("route(path, Component) requires a component function as the second argument. Passing JSX elements or VNodes directly is not supported.");
|
|
200
223
|
if (options?.search && options.search.kind !== "object") throw new Error("route search must be an object schema.");
|
|
@@ -249,7 +272,7 @@ async function resolveDeferredValues(input, signal) {
|
|
|
249
272
|
function routeData() {
|
|
250
273
|
const envelope = getCurrentRenderData();
|
|
251
274
|
if (envelope) return guardHydratedRouteData(envelope.route, envelope.framework);
|
|
252
|
-
const runtime =
|
|
275
|
+
const runtime = currentAppRuntime();
|
|
253
276
|
if (!runtime?.hasRoute) throw new Error("routeData() can only be read while rendering a route with loader data.");
|
|
254
277
|
return guardHydratedRouteData(runtime.route, runtime.framework);
|
|
255
278
|
}
|
|
@@ -258,13 +281,12 @@ function rejectedChild(props, error) {
|
|
|
258
281
|
}
|
|
259
282
|
/** Render a {@link Deferred} value's fulfilled state, a pending placeholder, or a rejected fallback. */
|
|
260
283
|
function Resolve(props) {
|
|
284
|
+
const renderContext = getActiveRenderContext();
|
|
285
|
+
const result = renderContext ? null : resource(() => props.value.state === "pending" ? props.value.promise : null, [props.value]);
|
|
261
286
|
if (props.value.state === "fulfilled") return props.children(props.value.value);
|
|
262
287
|
if (props.value.state === "rejected") return rejectedChild(props, props.value.error);
|
|
263
|
-
const renderContext = getActiveRenderContext();
|
|
264
288
|
if (renderContext) {
|
|
265
|
-
const id =
|
|
266
|
-
renderContext.deferredBoundaries.push({
|
|
267
|
-
id,
|
|
289
|
+
const id = registerDeferredBoundary(renderContext, {
|
|
268
290
|
promise: props.value.promise,
|
|
269
291
|
fulfilled: (value) => props.children(value),
|
|
270
292
|
rejected: (error) => rejectedChild(props, error)
|
|
@@ -277,7 +299,7 @@ function Resolve(props) {
|
|
|
277
299
|
}
|
|
278
300
|
};
|
|
279
301
|
}
|
|
280
|
-
|
|
302
|
+
if (!result) return props.pending ?? null;
|
|
281
303
|
if (result.error) return rejectedChild(props, result.error);
|
|
282
304
|
if (result.pending || result.value === null) return props.pending ?? null;
|
|
283
305
|
return props.children(result.value);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSXElementType, JSXElement, Props } from '../elements.js';
|
|
2
2
|
import '../jsx-globals.js';
|
|
3
|
-
import {
|
|
4
|
-
import { InferSchema, ObjectSchema } from '@askrjs/schema';
|
|
3
|
+
import { InferSchema, ObjectSchema } from '../peer-types.js';
|
|
5
4
|
import { StateTuple, state } from './state.js';
|
|
6
5
|
import { RenderableChild } from './context.js';
|
|
7
6
|
import { on } from './lifecycle.js';
|
|
@@ -50,7 +49,13 @@ interface ActionStatus<TResult = unknown> {
|
|
|
50
49
|
readonly error?: unknown;
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Bind an action descriptor to the calling component and return its
|
|
54
|
+
* `{ state, submit }` handle. `action()` allocates its status with `state()`,
|
|
55
|
+
* so it follows the same rule: call it during component render, at the top
|
|
56
|
+
* level and in the same order on every render. `submit()` itself may be
|
|
57
|
+
* called from event handlers or other async work.
|
|
58
|
+
*/
|
|
54
59
|
declare function action<
|
|
55
60
|
TInput extends Record<string, unknown>,
|
|
56
61
|
TResult = unknown,
|
|
@@ -1,84 +1,4 @@
|
|
|
1
|
-
import { JSXElementType, JSXElement, Props } from '../elements.js';
|
|
2
1
|
import '../jsx-globals.js';
|
|
3
|
-
import { AuthContext, AuthRequirement } from '@askrjs/auth';
|
|
4
|
-
import { InferSchema, ObjectSchema } from '@askrjs/schema';
|
|
5
|
-
import { State, state } from './state.js';
|
|
6
|
-
import { ComponentFunction, ContextFrame, OwnedChildScope } from './context.js';
|
|
7
|
-
import { DataRuntime } from './data.js';
|
|
8
|
-
import { RouteAuthOptions, RouteRegistry } from './routing.js';
|
|
9
|
-
|
|
10
|
-
interface AppRenderRuntime {
|
|
11
|
-
framework: Readonly<Record<string, unknown>>;
|
|
12
|
-
route: unknown;
|
|
13
|
-
hasRoute: boolean;
|
|
14
|
-
dataRuntime?: DataRuntime;
|
|
15
|
-
routeRegistry?: RouteRegistry;
|
|
16
|
-
routeAuth?: RouteAuthOptions;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface ComponentInstance {
|
|
20
|
-
id: string;
|
|
21
|
-
fn: ComponentFunction;
|
|
22
|
-
props: Props;
|
|
23
|
-
target: Element | null;
|
|
24
|
-
parentInstance: ComponentInstance | null;
|
|
25
|
-
portalScope: object | null;
|
|
26
|
-
mounted: boolean;
|
|
27
|
-
abortController: AbortController | null;
|
|
28
|
-
ssr?: boolean;
|
|
29
|
-
cleanupStrict?: boolean;
|
|
30
|
-
/** @internal Private resource-ownership identity for the active mount. */
|
|
31
|
-
_ownershipGeneration: object;
|
|
32
|
-
stateValues?: State<unknown>[];
|
|
33
|
-
evaluationGeneration: number;
|
|
34
|
-
notifyUpdate: (() => void) | null;
|
|
35
|
-
_pendingFlushTask?: () => void;
|
|
36
|
-
_pendingRunTask?: () => void;
|
|
37
|
-
_enqueueRun?: () => void;
|
|
38
|
-
stateIndexCheck: number;
|
|
39
|
-
expectedStateIndices?: number[];
|
|
40
|
-
firstRenderComplete: boolean;
|
|
41
|
-
mountOperations?: Array<
|
|
42
|
-
() => void | (() => void) | PromiseLike<void | (() => void)>
|
|
43
|
-
>;
|
|
44
|
-
commitOperations?: Array<
|
|
45
|
-
() => void | (() => void) | PromiseLike<void | (() => void)>
|
|
46
|
-
>;
|
|
47
|
-
cleanupFns?: Array<() => void>;
|
|
48
|
-
lifecycleSlots?: unknown[];
|
|
49
|
-
lifecycleGeneration: number;
|
|
50
|
-
hasPendingUpdate: boolean;
|
|
51
|
-
ownerFrame: ContextFrame | null;
|
|
52
|
-
isRoot?: boolean;
|
|
53
|
-
_rootComponentFn?: ComponentFunction;
|
|
54
|
-
/** @internal Browser-owned hydration and route state for this app root. */
|
|
55
|
-
_appRenderRuntime?: AppRenderRuntime;
|
|
56
|
-
/** @internal CSP nonce retained across browser route navigation. */
|
|
57
|
-
_cspNonce?: string;
|
|
58
|
-
_vnodeOwner?: object;
|
|
59
|
-
_vnodeParent?: ComponentInstance | null;
|
|
60
|
-
_vnodeParentGeneration?: object;
|
|
61
|
-
_vnodeKey?: string | number;
|
|
62
|
-
_vnodePosition?: number;
|
|
63
|
-
_wrapperDepth?: number;
|
|
64
|
-
_currentRenderToken?: number;
|
|
65
|
-
lastRenderToken?: number;
|
|
66
|
-
_pendingReadSources?: Set<ReadableSource<unknown>>;
|
|
67
|
-
_pendingReadSourceVersions?: Map<ReadableSource<unknown>, number>;
|
|
68
|
-
_lastReadSources?: Set<ReadableSource<unknown>>;
|
|
69
|
-
devWarningsEmitted?: Set<string>;
|
|
70
|
-
_placeholder?: Comment;
|
|
71
|
-
_ownedChildScopes?: Set<OwnedChildScope>;
|
|
72
|
-
errorBoundaryState?: {
|
|
73
|
-
error: unknown | null;
|
|
74
|
-
resetKey: unknown;
|
|
75
|
-
notified: boolean;
|
|
76
|
-
};
|
|
77
|
-
/** @internal Logical error ancestry for content materialized by a portal host. */
|
|
78
|
-
_portalErrorParent?: ComponentInstance | null;
|
|
79
|
-
/** @internal Ownership identity paired with `_portalErrorParent`. */
|
|
80
|
-
_portalErrorParentGeneration?: object;
|
|
81
|
-
}
|
|
82
2
|
|
|
83
3
|
/**
|
|
84
4
|
* Get the abort signal for the current component.
|
|
@@ -90,30 +10,4 @@ interface ComponentInstance {
|
|
|
90
10
|
*/
|
|
91
11
|
declare function getSignal(): AbortSignal;
|
|
92
12
|
|
|
93
|
-
|
|
94
|
-
_markDirty(): void;
|
|
95
|
-
_pendingDependencySources?: Set<ReadableSource<unknown>>;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
interface ReadableSource<T = unknown> {
|
|
99
|
-
(): T;
|
|
100
|
-
_hasBeenRead?: boolean;
|
|
101
|
-
_hasEverBeenRead?: boolean;
|
|
102
|
-
_unusedStateDiagnosticEligible?: boolean;
|
|
103
|
-
_readers?: Map<
|
|
104
|
-
ComponentInstance,
|
|
105
|
-
{
|
|
106
|
-
token: number;
|
|
107
|
-
generation: object;
|
|
108
|
-
}
|
|
109
|
-
>;
|
|
110
|
-
_derivedSubscribers?: Set<DerivedSubscriber>;
|
|
111
|
-
_version?: number;
|
|
112
|
-
}
|
|
113
|
-
export {
|
|
114
|
-
AppRenderRuntime,
|
|
115
|
-
ComponentInstance,
|
|
116
|
-
getSignal,
|
|
117
|
-
DerivedSubscriber,
|
|
118
|
-
ReadableSource,
|
|
119
|
-
};
|
|
13
|
+
export { getSignal };
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { JSXElementType, JSXElement, Props } from '../elements.js';
|
|
2
2
|
import '../jsx-globals.js';
|
|
3
|
-
import { AuthContext, AuthRequirement } from '@askrjs/auth';
|
|
4
|
-
import { InferSchema, ObjectSchema } from '@askrjs/schema';
|
|
5
3
|
import { SSRContext } from './server.js';
|
|
6
|
-
import { ControlBoundaryState } from './control.js';
|
|
7
4
|
|
|
8
5
|
interface DOMElement {
|
|
9
6
|
type: JSXElementType;
|
|
@@ -11,7 +8,6 @@ interface DOMElement {
|
|
|
11
8
|
children?: VNode[];
|
|
12
9
|
key?: string | number | null;
|
|
13
10
|
[Symbol.iterator]?: never;
|
|
14
|
-
_controlState?: ControlBoundaryState;
|
|
15
11
|
}
|
|
16
12
|
|
|
17
13
|
type VNode = DOMElement | string | number | boolean | null | undefined;
|
|
@@ -41,21 +37,12 @@ interface Scope<T> {
|
|
|
41
37
|
readonly defaultValue: T;
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
interface ContextFrame {
|
|
45
|
-
parent: ContextFrame | null;
|
|
46
|
-
values: Map<ContextKey, unknown> | null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
40
|
/** Create a new lexical {@link Scope} with `defaultValue`, readable via {@link readScope}. */
|
|
50
41
|
declare function defineScope<T>(defaultValue: T): Scope<T>;
|
|
51
42
|
|
|
52
43
|
/** Read the current value of a {@link Scope} during component render or an async resource. */
|
|
53
44
|
declare function readScope<T>(context: Scope<T>): T;
|
|
54
45
|
|
|
55
|
-
type OwnedChildScope = {
|
|
56
|
-
key: string | number;
|
|
57
|
-
dispose(): void;
|
|
58
|
-
};
|
|
59
46
|
export {
|
|
60
47
|
DOMElement,
|
|
61
48
|
VNode,
|
|
@@ -66,8 +53,6 @@ export {
|
|
|
66
53
|
Renderable,
|
|
67
54
|
ContextScopeChildren,
|
|
68
55
|
Scope,
|
|
69
|
-
ContextFrame,
|
|
70
56
|
defineScope,
|
|
71
57
|
readScope,
|
|
72
|
-
OwnedChildScope,
|
|
73
58
|
};
|