@askrjs/askr 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +898 -1
- 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-C5HnQZio.js +4032 -0
- package/dist/browser-activity-2r5gA1Cb.js +222 -0
- package/dist/components/index.d.ts +8 -1
- package/dist/components/index.js +1 -43
- package/dist/{aria-hKjThHcp.js → compose-ref-ccRU59BM.js} +48 -5
- package/dist/control/index.d.ts +2 -0
- package/dist/control/index.js +1 -1
- package/dist/control-hr3B0QaD.js +211 -0
- package/dist/core.d.ts +5 -9
- package/dist/csp-nonce-D-XM_uuJ.js +35 -0
- package/dist/data/index.js +3 -3
- package/dist/{data-2edW0jhF.js → data-BsnOUpQ6.js} +294 -95
- package/dist/data-runtime-i-RD0Ffm.js +242 -0
- package/dist/{deferred-CbgNhf67.js → deferred-nGZglpj6.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-ChXoIFVl.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-kjLigwDJ.js +202 -0
- package/dist/index.d.ts +11 -74
- package/dist/index.js +8 -447
- package/dist/instance-DL-YKrj6.js +992 -0
- package/dist/{interactions-CTeACdT_.js → interactions-BAa2xuJ-.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-BNupb86f.js} +3 -3
- package/dist/{navigate-prC5V8XV.js → navigate-DsfO12hB.js} +468 -85
- package/dist/navigation.d.ts +12 -3
- package/dist/peer-types.d.ts +8 -0
- package/dist/portal-LYf4cbHd.js +349 -0
- package/dist/promise-Dz8iIHAm.js +16 -0
- package/dist/query-registry-tzSiVrV_.js +325 -0
- package/dist/readable-DFWOsTac.js +21 -0
- package/dist/{render-context-B7ohlh6t.js → render-context-DGHnEveC.js} +27 -11
- package/dist/render-sync-CUxvoVab.js +1256 -0
- package/dist/resolution-CF1BqHLm.js +1258 -0
- package/dist/resource-BhcaFqdB.js +377 -0
- package/dist/resources/index.d.ts +21 -11
- package/dist/resources/index.js +65 -266
- package/dist/router/index.d.ts +14 -5
- package/dist/router/index.js +22 -53
- package/dist/scope-ila_zaId.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 +43 -22
- package/dist/ssr/index.d.ts +26 -28
- package/dist/ssr/index.js +4 -4
- package/dist/{ssr-CiNm6Vzl.js → ssr-9LOx_bEu.js} +133 -122
- package/dist/ssr-DPfdcq0e.js +229 -0
- package/dist/state-i9D4EtY6.js +250 -0
- package/dist/structures-CkehlOT3.js +231 -0
- package/dist/testing/index.d.ts +8 -4
- package/dist/testing/index.js +29 -34
- package/dist/url-C9xMpMMv.js +185 -0
- package/dist/utilities.d.ts +48 -2
- package/dist/verify-hydration-D_cyn1OX.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-DLplW9h4.js +0 -1104
- 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
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as
|
|
6
|
-
import {
|
|
7
|
-
import { a as getMutationSlotStore, c as resolveDataRuntimeState, i as getDefaultDataRuntime, n as ensureMutationCleanup, o as getQuerySlotStore, r as ensureQueryCleanup, s as invalidateQueriesForRuntime } from "./data-runtime-CxoY98lX.js";
|
|
8
|
-
import { a as normalizeAsyncDataError, i as isCurrentAsyncOperation, n as isAbortError, o as notifySource, t as createReadableSource } from "./shared-kU8yvryp.js";
|
|
1
|
+
import { C as schedule, I as logger } from "./instance-DL-YKrj6.js";
|
|
2
|
+
import { i as currentComponent, n as createSource, r as currentAppRuntime, s as notify, t as claimHookIndex, u as readSource } from "./hooks-kjLigwDJ.js";
|
|
3
|
+
import { n as getActiveRenderContext } from "./render-context-DGHnEveC.js";
|
|
4
|
+
import { a as getDefaultDataRuntime, c as invalidateQueriesForRuntime, f as invalidateCollectionCell, l as readQueryData, m as unregisterCollectionCell, n as ensureMutationCleanup, o as getMutationSlotStore, p as registerCollectionCell, r as ensureQueryCleanup, s as getQuerySlotStore, u as resolveDataRuntimeState } from "./data-runtime-i-RD0Ffm.js";
|
|
5
|
+
import { a as routeActive, n as windowFocused, s as timer, t as documentVisible } from "./browser-activity-2r5gA1Cb.js";
|
|
6
|
+
import { i as normalizeAsyncDataError, r as isCurrentAsyncOperation, t as isAbortError } from "./shared-O2ZnmYAf.js";
|
|
9
7
|
//#region src/data/query-key.ts
|
|
10
8
|
function serializeQueryKeyNumber(part) {
|
|
11
9
|
if (Number.isNaN(part)) return "NaN";
|
|
@@ -23,7 +21,12 @@ function serializeQueryKeyPart(part) {
|
|
|
23
21
|
case "number": return `n=${serializeQueryKeyNumber(part)}`;
|
|
24
22
|
case "boolean": return `b=${part ? "1" : "0"}`;
|
|
25
23
|
case "object":
|
|
26
|
-
if (Array.isArray(part))
|
|
24
|
+
if (Array.isArray(part)) {
|
|
25
|
+
const items = [];
|
|
26
|
+
const length = part.length;
|
|
27
|
+
for (let index = 0; index < length; index++) items.push(serializeQueryKeyPart(part[index]));
|
|
28
|
+
return `a[${items.join(",")}]`;
|
|
29
|
+
}
|
|
27
30
|
const objectPart = part;
|
|
28
31
|
return `o{${Object.keys(objectPart).sort().map((key) => `${encodeURIComponent(key)}=${serializeQueryKeyPart(objectPart[key])}`).join(",")}}`;
|
|
29
32
|
default: return String(part);
|
|
@@ -46,18 +49,28 @@ function createQueryScope(namespace, invalidate) {
|
|
|
46
49
|
}
|
|
47
50
|
//#endregion
|
|
48
51
|
//#region src/data/invalidation.ts
|
|
49
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Mark all cached queries under `prefix` as stale, triggering a refresh.
|
|
54
|
+
* Matching is by `:`-delimited segment: a key matches when it equals `prefix`,
|
|
55
|
+
* when `prefix` ends in `:`, or when the key continues `prefix` at a `:`
|
|
56
|
+
* (`'user:1'` matches `user:1:posts` but not `user:10`). Only `:` is a
|
|
57
|
+
* segment boundary; the empty prefix matches every key.
|
|
58
|
+
*/
|
|
50
59
|
function invalidate(prefix, options) {
|
|
51
60
|
invalidateQueriesForRuntime(resolveDataRuntimeState(options?.runtime), prefix, options?.markPendingWrite ?? false);
|
|
52
61
|
}
|
|
53
|
-
/** Create a {@link QueryScope} that namespaces keys and invalidations
|
|
54
|
-
function queryScope(namespace) {
|
|
55
|
-
return createQueryScope(namespace, invalidate
|
|
62
|
+
/** Create a {@link QueryScope} that namespaces keys and can bind invalidations to a runtime. */
|
|
63
|
+
function queryScope(namespace, options) {
|
|
64
|
+
return createQueryScope(namespace, (prefix, callOptions) => invalidate(prefix, {
|
|
65
|
+
...callOptions,
|
|
66
|
+
runtime: callOptions?.runtime ?? options?.runtime
|
|
67
|
+
}));
|
|
56
68
|
}
|
|
57
69
|
const INVALIDATE_ON_INTERVAL_OPTIONS_ERROR = "[Askr] invalidateOnInterval() requires an options object with a finite numeric intervalMs.";
|
|
58
70
|
/**
|
|
59
71
|
* Periodically invalidate queries matching `prefix` on a fixed interval,
|
|
60
72
|
* optionally gated by active route, document visibility, or window focus.
|
|
73
|
+
* `prefix` matches key segments the same way as {@link invalidate}.
|
|
61
74
|
*/
|
|
62
75
|
function invalidateOnInterval(prefix, options) {
|
|
63
76
|
if (!options || typeof options !== "object" || typeof options.intervalMs !== "number" || !Number.isFinite(options.intervalMs)) throw new Error(INVALIDATE_ON_INTERVAL_OPTIONS_ERROR);
|
|
@@ -74,8 +87,10 @@ function invalidateOnInterval(prefix, options) {
|
|
|
74
87
|
//#region src/data/mutation-cell.ts
|
|
75
88
|
var MutationCell = class {
|
|
76
89
|
constructor(options, runtimeState) {
|
|
77
|
-
this.source =
|
|
90
|
+
this.source = createSource();
|
|
78
91
|
this.controller = null;
|
|
92
|
+
this.activeControllers = /* @__PURE__ */ new Set();
|
|
93
|
+
this.rollbacks = /* @__PURE__ */ new Map();
|
|
79
94
|
this.generation = 0;
|
|
80
95
|
this.state = {
|
|
81
96
|
status: "idle",
|
|
@@ -84,28 +99,30 @@ var MutationCell = class {
|
|
|
84
99
|
};
|
|
85
100
|
this.runtimeState = runtimeState;
|
|
86
101
|
this.action = options.action;
|
|
102
|
+
this.optimistic = options.optimistic;
|
|
87
103
|
this.affects = options.affects;
|
|
88
104
|
this.afterSuccess = options.afterSuccess;
|
|
89
105
|
}
|
|
90
106
|
setOptions(options) {
|
|
91
107
|
this.action = options.action;
|
|
108
|
+
this.optimistic = options.optimistic;
|
|
92
109
|
this.affects = options.affects;
|
|
93
110
|
this.afterSuccess = options.afterSuccess;
|
|
94
111
|
}
|
|
95
112
|
get status() {
|
|
96
|
-
|
|
113
|
+
readSource(this.source);
|
|
97
114
|
return this.state.status;
|
|
98
115
|
}
|
|
99
116
|
get pending() {
|
|
100
|
-
|
|
117
|
+
readSource(this.source);
|
|
101
118
|
return this.state.status === "pending";
|
|
102
119
|
}
|
|
103
120
|
get error() {
|
|
104
|
-
|
|
121
|
+
readSource(this.source);
|
|
105
122
|
return this.state.error;
|
|
106
123
|
}
|
|
107
124
|
get result() {
|
|
108
|
-
|
|
125
|
+
readSource(this.source);
|
|
109
126
|
return this.state.result;
|
|
110
127
|
}
|
|
111
128
|
setState(next) {
|
|
@@ -113,17 +130,18 @@ var MutationCell = class {
|
|
|
113
130
|
...this.state,
|
|
114
131
|
...next
|
|
115
132
|
};
|
|
116
|
-
|
|
133
|
+
notify(this.source);
|
|
117
134
|
}
|
|
118
135
|
async execute(input) {
|
|
119
136
|
const action = this.action;
|
|
137
|
+
const optimistic = this.optimistic;
|
|
120
138
|
const affects = this.affects;
|
|
121
139
|
const afterSuccess = this.afterSuccess;
|
|
122
140
|
this.generation += 1;
|
|
123
141
|
const generation = this.generation;
|
|
124
|
-
this.controller?.abort();
|
|
125
142
|
const controller = new AbortController();
|
|
126
143
|
this.controller = controller;
|
|
144
|
+
this.activeControllers.add(controller);
|
|
127
145
|
this.setState({
|
|
128
146
|
status: "pending",
|
|
129
147
|
error: null,
|
|
@@ -131,8 +149,17 @@ var MutationCell = class {
|
|
|
131
149
|
});
|
|
132
150
|
let result;
|
|
133
151
|
try {
|
|
152
|
+
const rollback = optimistic?.(input, { signal: controller.signal });
|
|
153
|
+
if (rollback) this.rollbacks.set(controller, rollback);
|
|
134
154
|
result = await action(input, { signal: controller.signal });
|
|
135
|
-
|
|
155
|
+
this.rollbacks.delete(controller);
|
|
156
|
+
} catch (cause) {
|
|
157
|
+
let error = cause;
|
|
158
|
+
try {
|
|
159
|
+
this.rollbackOptimistic(controller);
|
|
160
|
+
} catch (rollbackError) {
|
|
161
|
+
error = new AggregateError([cause, rollbackError], "Mutation failed and its optimistic rollback failed");
|
|
162
|
+
}
|
|
136
163
|
if (!isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) throw error;
|
|
137
164
|
if (isAbortError(error, controller.signal)) {
|
|
138
165
|
this.setState({
|
|
@@ -146,6 +173,9 @@ var MutationCell = class {
|
|
|
146
173
|
error: normalizeAsyncDataError(error, "Unknown mutation error")
|
|
147
174
|
});
|
|
148
175
|
throw error;
|
|
176
|
+
} finally {
|
|
177
|
+
this.activeControllers.delete(controller);
|
|
178
|
+
this.rollbacks.delete(controller);
|
|
149
179
|
}
|
|
150
180
|
if (isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) this.setState({
|
|
151
181
|
status: "success",
|
|
@@ -159,25 +189,44 @@ var MutationCell = class {
|
|
|
159
189
|
return result;
|
|
160
190
|
}
|
|
161
191
|
abort() {
|
|
162
|
-
if (this.
|
|
192
|
+
if (this.activeControllers.size === 0) return;
|
|
163
193
|
this.generation += 1;
|
|
164
|
-
this.controller?.abort();
|
|
165
194
|
this.controller = null;
|
|
166
|
-
this.setState({
|
|
195
|
+
if (this.state.status === "pending") this.setState({
|
|
167
196
|
status: "idle",
|
|
168
197
|
error: null,
|
|
169
198
|
result: null
|
|
170
199
|
});
|
|
200
|
+
this.cancelActive();
|
|
171
201
|
}
|
|
172
202
|
reset() {
|
|
173
203
|
this.generation += 1;
|
|
174
|
-
this.controller?.abort();
|
|
175
204
|
this.controller = null;
|
|
176
205
|
this.setState({
|
|
177
206
|
status: "idle",
|
|
178
207
|
error: null,
|
|
179
208
|
result: null
|
|
180
209
|
});
|
|
210
|
+
this.cancelActive();
|
|
211
|
+
}
|
|
212
|
+
rollbackOptimistic(controller) {
|
|
213
|
+
const rollback = this.rollbacks.get(controller);
|
|
214
|
+
this.rollbacks.delete(controller);
|
|
215
|
+
rollback?.();
|
|
216
|
+
}
|
|
217
|
+
cancelActive() {
|
|
218
|
+
const controllers = [...this.activeControllers];
|
|
219
|
+
this.activeControllers.clear();
|
|
220
|
+
const errors = [];
|
|
221
|
+
for (const controller of controllers) {
|
|
222
|
+
try {
|
|
223
|
+
this.rollbackOptimistic(controller);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
errors.push(error);
|
|
226
|
+
}
|
|
227
|
+
controller.abort();
|
|
228
|
+
}
|
|
229
|
+
if (errors.length > 0) throw new AggregateError(errors, "Optimistic mutation rollback failed");
|
|
181
230
|
}
|
|
182
231
|
};
|
|
183
232
|
/**
|
|
@@ -187,14 +236,14 @@ var MutationCell = class {
|
|
|
187
236
|
*/
|
|
188
237
|
function createMutation(options) {
|
|
189
238
|
if (options.key !== void 0 && options.key.length === 0) throw new TypeError("createMutation key must be a non-empty string.");
|
|
190
|
-
const instance =
|
|
239
|
+
const instance = currentComponent();
|
|
191
240
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
192
241
|
const override = options.key ? runtimeState.mutationTestOverrides.get(options.key) : void 0;
|
|
193
242
|
if (!instance) {
|
|
194
243
|
if (override) return override;
|
|
195
244
|
return new MutationCell(options, runtimeState);
|
|
196
245
|
}
|
|
197
|
-
const hookIndex = claimHookIndex(instance, "
|
|
246
|
+
const hookIndex = claimHookIndex(instance, "createMutation");
|
|
198
247
|
ensureMutationCleanup(runtimeState, instance);
|
|
199
248
|
const slotStore = getMutationSlotStore(runtimeState, instance);
|
|
200
249
|
if (override) {
|
|
@@ -281,19 +330,24 @@ function errorQueryState(data, error) {
|
|
|
281
330
|
//#region src/data/query-cell.ts
|
|
282
331
|
const RECONCILE_MAX_ATTEMPTS = 3;
|
|
283
332
|
const RECONCILE_RETRY_DELAY_MS = 25;
|
|
284
|
-
|
|
333
|
+
const MAX_GC_TIME_MS = 2147483647;
|
|
334
|
+
const DEFAULT_OWNERLESS_GC_TIME_MS = 3e5;
|
|
335
|
+
function validateGcTime(gcTime) {
|
|
336
|
+
if (gcTime !== void 0 && (!Number.isFinite(gcTime) || gcTime < 0 || gcTime > MAX_GC_TIME_MS)) throw new RangeError("Query gcTime must be a finite, non-negative timer delay.");
|
|
337
|
+
}
|
|
338
|
+
/** Starts a query fetch in the flush; settles its promise if dropped. */
|
|
339
|
+
var QueryStartWork = class {
|
|
285
340
|
constructor(run, settle) {
|
|
286
|
-
|
|
341
|
+
this.run = run;
|
|
287
342
|
this.settle = settle;
|
|
288
343
|
}
|
|
289
344
|
cancel() {
|
|
290
|
-
super.cancel();
|
|
291
345
|
this.settle();
|
|
292
346
|
}
|
|
293
347
|
};
|
|
294
348
|
var QueryCell = class {
|
|
295
349
|
constructor(options, key, cache) {
|
|
296
|
-
this.source =
|
|
350
|
+
this.source = createSource();
|
|
297
351
|
this.controller = null;
|
|
298
352
|
this.generation = 0;
|
|
299
353
|
this.pendingRefresh = null;
|
|
@@ -304,22 +358,36 @@ var QueryCell = class {
|
|
|
304
358
|
this.reconcileSequence = 0;
|
|
305
359
|
this.destroyed = false;
|
|
306
360
|
this.ownerCount = 0;
|
|
361
|
+
this.gcTimer = null;
|
|
362
|
+
this.unownedTimer = null;
|
|
307
363
|
this.owners = /* @__PURE__ */ new Map();
|
|
308
364
|
this.warnedDefinitionConflictKeys = /* @__PURE__ */ new Set();
|
|
365
|
+
this.definitionOwner = null;
|
|
366
|
+
this.definitionOwnerHook = -1;
|
|
367
|
+
this.conflictCheck = null;
|
|
309
368
|
this.state = loadingQueryState();
|
|
369
|
+
validateGcTime(options.gcTime);
|
|
310
370
|
this.options = options;
|
|
311
371
|
this.key = key;
|
|
312
372
|
this.cache = cache;
|
|
313
373
|
if (options.initialData !== void 0) this.state = freshQueryState(options.initialData);
|
|
314
374
|
}
|
|
315
375
|
attach(generation, hookIndex) {
|
|
376
|
+
if (this.unownedTimer !== null) {
|
|
377
|
+
clearTimeout(this.unownedTimer);
|
|
378
|
+
this.unownedTimer = null;
|
|
379
|
+
}
|
|
380
|
+
if (this.gcTimer !== null) {
|
|
381
|
+
clearTimeout(this.gcTimer);
|
|
382
|
+
this.gcTimer = null;
|
|
383
|
+
}
|
|
316
384
|
let hooks = this.owners.get(generation);
|
|
317
385
|
if (!hooks) {
|
|
318
|
-
hooks = /* @__PURE__ */ new
|
|
386
|
+
hooks = /* @__PURE__ */ new Map();
|
|
319
387
|
this.owners.set(generation, hooks);
|
|
320
388
|
}
|
|
321
389
|
if (hooks.has(hookIndex)) return;
|
|
322
|
-
hooks.
|
|
390
|
+
hooks.set(hookIndex, null);
|
|
323
391
|
this.ownerCount += 1;
|
|
324
392
|
}
|
|
325
393
|
detach(generation, hookIndex) {
|
|
@@ -327,7 +395,54 @@ var QueryCell = class {
|
|
|
327
395
|
if (!hooks || !hooks.delete(hookIndex)) return;
|
|
328
396
|
this.ownerCount -= 1;
|
|
329
397
|
if (hooks.size === 0) this.owners.delete(generation);
|
|
330
|
-
if (this.ownerCount <= 0)
|
|
398
|
+
if (this.ownerCount <= 0) {
|
|
399
|
+
const gcTime = this.options.gcTime ?? 0;
|
|
400
|
+
if (gcTime === 0 || this.state.data === null || isServerRender()) this.destroy();
|
|
401
|
+
else {
|
|
402
|
+
this.generation += 1;
|
|
403
|
+
const controller = this.controller;
|
|
404
|
+
this.controller = null;
|
|
405
|
+
this.finishPendingRefresh();
|
|
406
|
+
this.pendingRefreshToken += 1;
|
|
407
|
+
this.definitionOwner = null;
|
|
408
|
+
this.definitionOwnerHook = -1;
|
|
409
|
+
if (this.state.refreshing) this.setState(staleQueryState(this.state.data, "aborted"));
|
|
410
|
+
this.gcTimer = setTimeout(() => this.destroy(), gcTime);
|
|
411
|
+
controller?.abort();
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (this.definitionOwner === generation && this.definitionOwnerHook === hookIndex) this.promoteDefinitionOwner();
|
|
416
|
+
}
|
|
417
|
+
promoteDefinitionOwner() {
|
|
418
|
+
this.definitionOwner = null;
|
|
419
|
+
for (const [generation, hooks] of this.owners) for (const [hookIndex, options] of hooks) if (options) {
|
|
420
|
+
this.options = options;
|
|
421
|
+
this.definitionOwner = generation;
|
|
422
|
+
this.definitionOwnerHook = hookIndex;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Record an attached reader's definition for this key. The owning reader's
|
|
428
|
+
* renders replace the definition; with no owner, the reader takes over.
|
|
429
|
+
* Other readers are checked for conflicts once render work settles.
|
|
430
|
+
*/
|
|
431
|
+
define(options, generation, hookIndex) {
|
|
432
|
+
validateGcTime(options.gcTime);
|
|
433
|
+
const hooks = this.owners.get(generation);
|
|
434
|
+
if (this.destroyed || !hooks?.has(hookIndex)) return;
|
|
435
|
+
hooks.set(hookIndex, options);
|
|
436
|
+
if (this.definitionOwner === null || this.definitionOwner === generation && this.definitionOwnerHook === hookIndex) {
|
|
437
|
+
this.options = options;
|
|
438
|
+
this.definitionOwner = generation;
|
|
439
|
+
this.definitionOwnerHook = hookIndex;
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
warnOnConflictingReaders() {
|
|
444
|
+
if (this.destroyed) return;
|
|
445
|
+
for (const hooks of this.owners.values()) for (const options of hooks.values()) if (options) this.warnOnConflictingDefinition(options);
|
|
331
446
|
}
|
|
332
447
|
warnOnConflictingDefinition(options) {
|
|
333
448
|
const conflicts = this.getDefinitionConflicts(options);
|
|
@@ -341,14 +456,45 @@ var QueryCell = class {
|
|
|
341
456
|
destroy() {
|
|
342
457
|
if (this.destroyed) return;
|
|
343
458
|
this.destroyed = true;
|
|
459
|
+
if (this.gcTimer !== null) {
|
|
460
|
+
clearTimeout(this.gcTimer);
|
|
461
|
+
this.gcTimer = null;
|
|
462
|
+
}
|
|
463
|
+
if (this.unownedTimer !== null) {
|
|
464
|
+
clearTimeout(this.unownedTimer);
|
|
465
|
+
this.unownedTimer = null;
|
|
466
|
+
}
|
|
344
467
|
this.controller?.abort();
|
|
345
468
|
this.controller = null;
|
|
346
469
|
this.reconcileAttemptCount = 0;
|
|
347
470
|
this.ownerCount = 0;
|
|
348
471
|
this.owners.clear();
|
|
349
|
-
this.
|
|
472
|
+
this.evictFromCache();
|
|
350
473
|
this.finishPendingRefresh();
|
|
351
474
|
}
|
|
475
|
+
evictFromCache() {
|
|
476
|
+
if (this.cache.get(this.key) === this) this.cache.delete(this.key);
|
|
477
|
+
}
|
|
478
|
+
/** A component's inactive definition must not become an ownerless fetcher. */
|
|
479
|
+
retireInactiveReaderCacheEntry() {
|
|
480
|
+
if (this.gcTimer === null) return false;
|
|
481
|
+
this.destroy();
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
/** Ownerless handles stay usable after their cache lookup window expires. */
|
|
485
|
+
scheduleUnownedCacheEviction(gcTime) {
|
|
486
|
+
if (isServerRender() || this.ownerCount > 0 || this.destroyed) return;
|
|
487
|
+
if (this.unownedTimer !== null) clearTimeout(this.unownedTimer);
|
|
488
|
+
this.unownedTimer = null;
|
|
489
|
+
if (gcTime === 0) {
|
|
490
|
+
this.evictFromCache();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
this.unownedTimer = setTimeout(() => {
|
|
494
|
+
this.unownedTimer = null;
|
|
495
|
+
if (this.ownerCount === 0) this.evictFromCache();
|
|
496
|
+
}, gcTime);
|
|
497
|
+
}
|
|
352
498
|
getDefinitionConflicts(options) {
|
|
353
499
|
const conflicts = [];
|
|
354
500
|
if ((this.options.definitionIdentity ?? this.options.fetch) !== (options.definitionIdentity ?? options.fetch)) conflicts.push("fetch");
|
|
@@ -357,31 +503,31 @@ var QueryCell = class {
|
|
|
357
503
|
return conflicts;
|
|
358
504
|
}
|
|
359
505
|
get data() {
|
|
360
|
-
|
|
506
|
+
readSource(this.source);
|
|
361
507
|
return this.state.data;
|
|
362
508
|
}
|
|
363
509
|
get error() {
|
|
364
|
-
|
|
510
|
+
readSource(this.source);
|
|
365
511
|
return this.state.error;
|
|
366
512
|
}
|
|
367
513
|
get loading() {
|
|
368
|
-
|
|
514
|
+
readSource(this.source);
|
|
369
515
|
return this.state.loading;
|
|
370
516
|
}
|
|
371
517
|
get refreshing() {
|
|
372
|
-
|
|
518
|
+
readSource(this.source);
|
|
373
519
|
return this.state.refreshing;
|
|
374
520
|
}
|
|
375
521
|
get stale() {
|
|
376
|
-
|
|
522
|
+
readSource(this.source);
|
|
377
523
|
return this.state.stale;
|
|
378
524
|
}
|
|
379
525
|
get consistency() {
|
|
380
|
-
|
|
526
|
+
readSource(this.source);
|
|
381
527
|
return this.state.consistency;
|
|
382
528
|
}
|
|
383
529
|
get staleReason() {
|
|
384
|
-
|
|
530
|
+
readSource(this.source);
|
|
385
531
|
return this.state.staleReason;
|
|
386
532
|
}
|
|
387
533
|
/** @internal Whether a collection should schedule this cell's first load. */
|
|
@@ -394,8 +540,13 @@ var QueryCell = class {
|
|
|
394
540
|
}
|
|
395
541
|
refresh() {
|
|
396
542
|
if (this.destroyed) return Promise.resolve();
|
|
543
|
+
if (this.gcTimer !== null) {
|
|
544
|
+
this.destroy();
|
|
545
|
+
return Promise.resolve();
|
|
546
|
+
}
|
|
397
547
|
if (this.pendingRefresh) {
|
|
398
548
|
if (this.pendingRefreshKind === "invalidation") {
|
|
549
|
+
this.generation += 1;
|
|
399
550
|
this.controller?.abort();
|
|
400
551
|
this.queueStart(void 0, "manual", true);
|
|
401
552
|
return this.pendingRefresh ?? Promise.resolve();
|
|
@@ -404,14 +555,27 @@ var QueryCell = class {
|
|
|
404
555
|
this.queueStart(void 0, "manual");
|
|
405
556
|
return this.pendingRefresh ?? Promise.resolve();
|
|
406
557
|
}
|
|
407
|
-
|
|
558
|
+
/** @internal Show an invalidation while a collection waits for a fetch slot. */
|
|
559
|
+
markQueuedInvalidation() {
|
|
408
560
|
if (this.destroyed) return;
|
|
561
|
+
this.generation += 1;
|
|
562
|
+
this.controller?.abort();
|
|
563
|
+
this.setState(this.state.data === null ? loadingQueryState() : refreshingQueryState(this.state.data, this.state.consistency === "pending-write" ? "pending-write" : "refreshing"));
|
|
564
|
+
}
|
|
565
|
+
invalidate() {
|
|
566
|
+
if (this.destroyed) return Promise.resolve();
|
|
567
|
+
if (this.gcTimer !== null) {
|
|
568
|
+
this.destroy();
|
|
569
|
+
return Promise.resolve();
|
|
570
|
+
}
|
|
409
571
|
if (this.pendingRefresh) {
|
|
572
|
+
this.generation += 1;
|
|
410
573
|
this.controller?.abort();
|
|
411
574
|
this.queueStart(void 0, "invalidation", true);
|
|
412
|
-
return;
|
|
575
|
+
return this.pendingRefresh ?? Promise.resolve();
|
|
413
576
|
}
|
|
414
577
|
this.queueStart(void 0, "invalidation");
|
|
578
|
+
return this.pendingRefresh ?? Promise.resolve();
|
|
415
579
|
}
|
|
416
580
|
markPendingWrite() {
|
|
417
581
|
if (this.destroyed) return;
|
|
@@ -429,7 +593,7 @@ var QueryCell = class {
|
|
|
429
593
|
if (!continuePending || !this.pendingRefresh) this.pendingRefresh = new Promise((resolve) => {
|
|
430
594
|
this.pendingRefreshResolve = resolve;
|
|
431
595
|
});
|
|
432
|
-
|
|
596
|
+
schedule(new QueryStartWork(() => {
|
|
433
597
|
if (token !== this.pendingRefreshToken) return;
|
|
434
598
|
if (this.destroyed) {
|
|
435
599
|
this.finishPendingRefresh(token);
|
|
@@ -442,7 +606,7 @@ var QueryCell = class {
|
|
|
442
606
|
if (token !== this.pendingRefreshToken) return;
|
|
443
607
|
this.generation += 1;
|
|
444
608
|
this.finishPendingRefresh(token);
|
|
445
|
-
}));
|
|
609
|
+
}), "effect");
|
|
446
610
|
}
|
|
447
611
|
finishPendingRefresh(token = this.pendingRefreshToken) {
|
|
448
612
|
if (token !== this.pendingRefreshToken) return;
|
|
@@ -455,7 +619,7 @@ var QueryCell = class {
|
|
|
455
619
|
setState(next) {
|
|
456
620
|
if (this.destroyed) return;
|
|
457
621
|
this.state = next;
|
|
458
|
-
|
|
622
|
+
notify(this.source);
|
|
459
623
|
}
|
|
460
624
|
async start(reconcileSequence) {
|
|
461
625
|
if (this.destroyed) return;
|
|
@@ -466,9 +630,10 @@ var QueryCell = class {
|
|
|
466
630
|
this.controller = controller;
|
|
467
631
|
const hasData = this.state.data !== null;
|
|
468
632
|
this.setState(hasData ? refreshingQueryState(this.state.data) : loadingQueryState());
|
|
633
|
+
const { fetch, isConsistent: checkConsistent, reconcile } = this.options;
|
|
469
634
|
let nextData;
|
|
470
635
|
try {
|
|
471
|
-
nextData = await
|
|
636
|
+
nextData = await fetch({ signal: controller.signal });
|
|
472
637
|
} catch (error) {
|
|
473
638
|
if (this.destroyed || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
474
639
|
if (isAbortError(error, controller.signal)) {
|
|
@@ -481,7 +646,7 @@ var QueryCell = class {
|
|
|
481
646
|
if (this.destroyed || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
482
647
|
let isConsistent;
|
|
483
648
|
try {
|
|
484
|
-
isConsistent =
|
|
649
|
+
isConsistent = checkConsistent?.(nextData) ?? true;
|
|
485
650
|
} catch (error) {
|
|
486
651
|
this.setState(errorQueryState(this.state.data, normalizeAsyncDataError(error, "Query consistency check failed")));
|
|
487
652
|
return;
|
|
@@ -489,7 +654,7 @@ var QueryCell = class {
|
|
|
489
654
|
if (!isConsistent) {
|
|
490
655
|
this.setState(staleQueryState(nextData, "inconsistent"));
|
|
491
656
|
try {
|
|
492
|
-
await this.reconcile(nextData, generation, controller, reconcileSequence);
|
|
657
|
+
await this.reconcile(reconcile, nextData, generation, controller, reconcileSequence);
|
|
493
658
|
} catch (error) {
|
|
494
659
|
if (isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) this.setState(errorQueryState(this.state.data, normalizeAsyncDataError(error, "Query reconciliation failed")));
|
|
495
660
|
}
|
|
@@ -498,8 +663,8 @@ var QueryCell = class {
|
|
|
498
663
|
this.reconcileAttemptCount = 0;
|
|
499
664
|
this.setState(freshQueryState(nextData));
|
|
500
665
|
}
|
|
501
|
-
async reconcile(data, generation, controller, reconcileSequence) {
|
|
502
|
-
if (!await (
|
|
666
|
+
async reconcile(reconcile, data, generation, controller, reconcileSequence) {
|
|
667
|
+
if (!await (reconcile?.(data, { key: this.key }) ?? false) || this.destroyed || reconcileSequence !== this.reconcileSequence || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
503
668
|
this.reconcileAttemptCount += 1;
|
|
504
669
|
if (this.reconcileAttemptCount > RECONCILE_MAX_ATTEMPTS) {
|
|
505
670
|
this.setState(staleQueryState(this.state.data, "inconsistent"));
|
|
@@ -511,63 +676,71 @@ var QueryCell = class {
|
|
|
511
676
|
this.queueStart(reconcileSequence, "reconcile", true);
|
|
512
677
|
}
|
|
513
678
|
};
|
|
679
|
+
function isServerRender() {
|
|
680
|
+
const context = getActiveRenderContext();
|
|
681
|
+
return context?.mode === "ssr" || context?.mode === void 0 && typeof window === "undefined";
|
|
682
|
+
}
|
|
683
|
+
function createCell(options, cache) {
|
|
684
|
+
const cell = new QueryCell(options.takeInitialData ? {
|
|
685
|
+
...options,
|
|
686
|
+
initialData: options.takeInitialData() ?? options.initialData
|
|
687
|
+
} : options, options.key, cache);
|
|
688
|
+
cache.set(options.key, cell);
|
|
689
|
+
cell.ensureStarted();
|
|
690
|
+
return cell;
|
|
691
|
+
}
|
|
514
692
|
function createLegacyQuery(options) {
|
|
515
|
-
|
|
693
|
+
validateGcTime(options.gcTime);
|
|
694
|
+
const instance = currentComponent();
|
|
516
695
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
517
696
|
const cache = runtimeState.queryCache;
|
|
518
697
|
const override = runtimeState.queryTestOverrides.get(options.key);
|
|
519
698
|
if (!instance) {
|
|
520
699
|
if (override) return override;
|
|
521
700
|
let cell = cache.get(options.key);
|
|
522
|
-
if (
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
} else cell.warnOnConflictingDefinition(options);
|
|
701
|
+
if (cell?.retireInactiveReaderCacheEntry()) cell = void 0;
|
|
702
|
+
if (!cell) cell = createCell(options, cache);
|
|
703
|
+
else cell.warnOnConflictingDefinition(options);
|
|
704
|
+
cell.scheduleUnownedCacheEviction(options.gcTime ?? DEFAULT_OWNERLESS_GC_TIME_MS);
|
|
527
705
|
return cell;
|
|
528
706
|
}
|
|
529
|
-
const hookIndex = claimHookIndex(instance, "
|
|
707
|
+
const hookIndex = claimHookIndex(instance, "createQuery");
|
|
530
708
|
ensureQueryCleanup(runtimeState, instance);
|
|
709
|
+
const generation = instance;
|
|
531
710
|
const slotStore = getQuerySlotStore(runtimeState, instance);
|
|
532
711
|
const existingSlot = slotStore.get(hookIndex);
|
|
533
712
|
if (existingSlot && existingSlot.key === options.key) {
|
|
534
|
-
existingSlot.cell.
|
|
713
|
+
existingSlot.cell.define(options, generation, hookIndex);
|
|
535
714
|
return existingSlot.cell;
|
|
536
715
|
}
|
|
537
|
-
if (existingSlot) existingSlot.cell.detach(
|
|
716
|
+
if (existingSlot) existingSlot.cell.detach(generation, hookIndex);
|
|
538
717
|
if (override) return override;
|
|
539
|
-
|
|
540
|
-
if (!cell) {
|
|
541
|
-
cell = new QueryCell(options, options.key, cache);
|
|
542
|
-
cache.set(options.key, cell);
|
|
543
|
-
cell.ensureStarted();
|
|
544
|
-
} else cell.warnOnConflictingDefinition(options);
|
|
718
|
+
const cell = cache.get(options.key) ?? createCell(options, cache);
|
|
545
719
|
slotStore.set(hookIndex, {
|
|
546
720
|
key: options.key,
|
|
547
721
|
cell
|
|
548
722
|
});
|
|
549
|
-
cell.attach(
|
|
723
|
+
cell.attach(generation, hookIndex);
|
|
724
|
+
cell.define(options, generation, hookIndex);
|
|
725
|
+
cell.ensureStarted();
|
|
550
726
|
return cell;
|
|
551
727
|
}
|
|
552
728
|
function createDefinedQuery(definition, input, options = {}) {
|
|
553
729
|
const runtime = options.runtime;
|
|
554
|
-
const context = getActiveRenderContext();
|
|
555
730
|
const key = definition.key(input);
|
|
556
|
-
const dataRuntime = runtime ?? getActiveRenderContext()?.dataRuntime ??
|
|
557
|
-
const
|
|
731
|
+
const dataRuntime = runtime ?? getActiveRenderContext()?.dataRuntime ?? currentAppRuntime()?.dataRuntime ?? getDefaultDataRuntime();
|
|
732
|
+
const serverRender = isServerRender();
|
|
733
|
+
const runtimeState = resolveDataRuntimeState(dataRuntime);
|
|
558
734
|
return createLegacyQuery({
|
|
559
735
|
...options,
|
|
560
736
|
key,
|
|
561
737
|
definitionIdentity: definition,
|
|
562
|
-
fetch: ({ signal }) => definition.fetch({
|
|
563
|
-
...input,
|
|
564
|
-
signal
|
|
565
|
-
}),
|
|
738
|
+
fetch: ({ signal }) => definition.fetch(input, { signal }),
|
|
566
739
|
isConsistent: definition.isConsistent,
|
|
567
740
|
reconcile: definition.reconcile,
|
|
568
|
-
|
|
569
|
-
skipInitialFetch:
|
|
570
|
-
runtime: dataRuntime
|
|
741
|
+
takeInitialData: () => readQueryData(runtimeState, key, !serverRender),
|
|
742
|
+
skipInitialFetch: serverRender || options.skipInitialFetch === true,
|
|
743
|
+
runtime: dataRuntime
|
|
571
744
|
});
|
|
572
745
|
}
|
|
573
746
|
function createQuery(optionsOrDefinition, input, options) {
|
|
@@ -592,17 +765,13 @@ function getCollectionStore(generation) {
|
|
|
592
765
|
}
|
|
593
766
|
return store;
|
|
594
767
|
}
|
|
595
|
-
function createCellOptions(
|
|
768
|
+
function createCellOptions(query, input, queryKey) {
|
|
596
769
|
return {
|
|
597
770
|
key: queryKey,
|
|
598
771
|
definitionIdentity: query,
|
|
599
|
-
fetch: ({ signal }) => query.fetch({
|
|
600
|
-
...input,
|
|
601
|
-
signal
|
|
602
|
-
}),
|
|
772
|
+
fetch: ({ signal }) => query.fetch(input, { signal }),
|
|
603
773
|
isConsistent: query.isConsistent,
|
|
604
774
|
reconcile: query.reconcile,
|
|
605
|
-
initialData: runtimeState.queryData.get(queryKey),
|
|
606
775
|
skipInitialFetch: true
|
|
607
776
|
};
|
|
608
777
|
}
|
|
@@ -611,12 +780,25 @@ var QueryCollectionCell = class {
|
|
|
611
780
|
this.runtimeState = runtimeState;
|
|
612
781
|
this.records = /* @__PURE__ */ new Map();
|
|
613
782
|
this.ordered = [];
|
|
783
|
+
this.registeredCells = /* @__PURE__ */ new Set();
|
|
614
784
|
this.tasks = /* @__PURE__ */ new Map();
|
|
615
785
|
this.queue = [];
|
|
616
786
|
this.activeCount = 0;
|
|
617
787
|
this.concurrency = DEFAULT_QUERY_COLLECTION_CONCURRENCY;
|
|
618
788
|
this.disposed = false;
|
|
619
789
|
}
|
|
790
|
+
get invalidationConcurrency() {
|
|
791
|
+
return this.concurrency;
|
|
792
|
+
}
|
|
793
|
+
invalidateCell(cell) {
|
|
794
|
+
const ownedCell = cell;
|
|
795
|
+
if (this.tasks.get(ownedCell)?.state === "active") {
|
|
796
|
+
ownedCell.invalidate();
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
ownedCell.markQueuedInvalidation();
|
|
800
|
+
this.schedule(ownedCell, "invalidation");
|
|
801
|
+
}
|
|
620
802
|
get entries() {
|
|
621
803
|
return this.ordered;
|
|
622
804
|
}
|
|
@@ -663,12 +845,12 @@ var QueryCollectionCell = class {
|
|
|
663
845
|
const startCandidates = /* @__PURE__ */ new Set();
|
|
664
846
|
const detachedCells = /* @__PURE__ */ new Set();
|
|
665
847
|
for (const { input, key, queryKey } of desired) {
|
|
666
|
-
const cellOptions = createCellOptions(
|
|
848
|
+
const cellOptions = createCellOptions(query, input, queryKey);
|
|
667
849
|
const previous = this.records.get(key);
|
|
668
850
|
let record;
|
|
669
851
|
if (previous?.queryKey === queryKey) {
|
|
670
852
|
previous.input = input;
|
|
671
|
-
previous.cell.
|
|
853
|
+
previous.cell.define(cellOptions, previous.owner, 0);
|
|
672
854
|
record = previous;
|
|
673
855
|
} else {
|
|
674
856
|
if (previous) {
|
|
@@ -678,11 +860,16 @@ var QueryCollectionCell = class {
|
|
|
678
860
|
const cache = this.runtimeState.queryCache;
|
|
679
861
|
let cell = cache.get(queryKey);
|
|
680
862
|
if (!cell) {
|
|
681
|
-
|
|
863
|
+
const initialData = readQueryData(this.runtimeState, queryKey, startInitialFetches);
|
|
864
|
+
cell = new QueryCell({
|
|
865
|
+
...cellOptions,
|
|
866
|
+
initialData
|
|
867
|
+
}, queryKey, cache);
|
|
682
868
|
cache.set(queryKey, cell);
|
|
683
|
-
}
|
|
869
|
+
}
|
|
684
870
|
const owner = {};
|
|
685
871
|
cell.attach(owner, 0);
|
|
872
|
+
cell.define(cellOptions, owner, 0);
|
|
686
873
|
record = {
|
|
687
874
|
key,
|
|
688
875
|
input,
|
|
@@ -700,8 +887,12 @@ var QueryCollectionCell = class {
|
|
|
700
887
|
this.detach(record);
|
|
701
888
|
detachedCells.add(record.cell);
|
|
702
889
|
}
|
|
890
|
+
const nextCells = new Set(nextOrdered.map((record) => record.cell));
|
|
703
891
|
this.records = nextRecords;
|
|
704
892
|
this.ordered = Object.freeze(nextOrdered);
|
|
893
|
+
for (const cell of this.registeredCells) if (!nextCells.has(cell)) unregisterCollectionCell(cell, this);
|
|
894
|
+
for (const cell of nextCells) if (!this.registeredCells.has(cell)) registerCollectionCell(cell, this);
|
|
895
|
+
this.registeredCells = nextCells;
|
|
705
896
|
for (const cell of detachedCells) this.cancelIfUnused(cell);
|
|
706
897
|
for (const cell of startCandidates) this.schedule(cell);
|
|
707
898
|
this.pump();
|
|
@@ -709,6 +900,8 @@ var QueryCollectionCell = class {
|
|
|
709
900
|
dispose() {
|
|
710
901
|
if (this.disposed) return;
|
|
711
902
|
this.disposed = true;
|
|
903
|
+
for (const cell of this.registeredCells) unregisterCollectionCell(cell, this);
|
|
904
|
+
this.registeredCells.clear();
|
|
712
905
|
const cells = /* @__PURE__ */ new Set();
|
|
713
906
|
for (const record of this.records.values()) {
|
|
714
907
|
cells.add(record.cell);
|
|
@@ -730,15 +923,20 @@ var QueryCollectionCell = class {
|
|
|
730
923
|
const task = this.tasks.get(cell);
|
|
731
924
|
if (!task || task.state === "cancelled" || task.state === "done") return;
|
|
732
925
|
if (task.state === "active") this.activeCount -= 1;
|
|
926
|
+
const rescheduleInvalidation = task.state === "queued" && task.kind === "invalidation";
|
|
733
927
|
task.state = "cancelled";
|
|
734
928
|
this.tasks.delete(cell);
|
|
735
929
|
task.resolve();
|
|
930
|
+
if (rescheduleInvalidation && !invalidateCollectionCell(cell)) cell.invalidate();
|
|
736
931
|
this.pump();
|
|
737
932
|
}
|
|
738
|
-
schedule(cell) {
|
|
933
|
+
schedule(cell, kind = "refresh") {
|
|
739
934
|
if (this.disposed) return Promise.resolve();
|
|
740
935
|
const existing = this.tasks.get(cell);
|
|
741
|
-
if (existing)
|
|
936
|
+
if (existing) {
|
|
937
|
+
if (kind === "invalidation") existing.kind = kind;
|
|
938
|
+
return existing.promise;
|
|
939
|
+
}
|
|
742
940
|
let resolve;
|
|
743
941
|
const promise = new Promise((done) => {
|
|
744
942
|
resolve = done;
|
|
@@ -747,7 +945,8 @@ var QueryCollectionCell = class {
|
|
|
747
945
|
cell,
|
|
748
946
|
promise,
|
|
749
947
|
resolve,
|
|
750
|
-
state: "queued"
|
|
948
|
+
state: "queued",
|
|
949
|
+
kind
|
|
751
950
|
};
|
|
752
951
|
this.tasks.set(cell, task);
|
|
753
952
|
this.queue.push(task);
|
|
@@ -762,7 +961,7 @@ var QueryCollectionCell = class {
|
|
|
762
961
|
if (task.state !== "queued" || this.tasks.get(task.cell) !== task) continue;
|
|
763
962
|
task.state = "active";
|
|
764
963
|
this.activeCount += 1;
|
|
765
|
-
task.cell.refresh().finally(() => this.finish(task));
|
|
964
|
+
(task.kind === "invalidation" ? task.cell.invalidate() : task.cell.refresh()).finally(() => this.finish(task));
|
|
766
965
|
}
|
|
767
966
|
}
|
|
768
967
|
finish(task) {
|
|
@@ -779,13 +978,13 @@ var QueryCollectionCell = class {
|
|
|
779
978
|
* reusable query definition, with bounded collection-started fetches.
|
|
780
979
|
*/
|
|
781
980
|
function createQueryCollection(options) {
|
|
782
|
-
const instance =
|
|
981
|
+
const instance = currentComponent();
|
|
783
982
|
if (!instance) throw new Error("[Askr] createQueryCollection() must be called during component render execution.");
|
|
784
983
|
const hookIndex = claimHookIndex(instance, "createQueryCollection");
|
|
785
984
|
const concurrency = normalizeQueryCollectionConcurrency(options.concurrency);
|
|
786
985
|
const inputs = options.inputs();
|
|
787
986
|
if (!Array.isArray(inputs)) throw new Error("[Askr] createQueryCollection() inputs must return a readonly array.");
|
|
788
|
-
const generation =
|
|
987
|
+
const generation = instance;
|
|
789
988
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
790
989
|
const store = getCollectionStore(generation);
|
|
791
990
|
let slot = store.get(hookIndex);
|
|
@@ -800,7 +999,7 @@ function createQueryCollection(options) {
|
|
|
800
999
|
collection: new QueryCollectionCell(runtimeState)
|
|
801
1000
|
};
|
|
802
1001
|
store.set(hookIndex, slot);
|
|
803
|
-
|
|
1002
|
+
instance.onCleanup(() => {
|
|
804
1003
|
const current = store.get(hookIndex);
|
|
805
1004
|
try {
|
|
806
1005
|
current?.collection.dispose();
|