@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
|
@@ -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, F as logger } from "./instance-BAnfmXOR.js";
|
|
2
|
+
import { i as currentComponent, n as createSource, r as currentAppRuntime, s as notify, t as claimHookIndex, u as readSource } from "./hooks-BimKStr4.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-C1bFAlba.js";
|
|
5
|
+
import { a as routeActive, n as windowFocused, s as timer, t as documentVisible } from "./browser-activity-CB8e-V4f.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";
|
|
@@ -46,18 +44,28 @@ function createQueryScope(namespace, invalidate) {
|
|
|
46
44
|
}
|
|
47
45
|
//#endregion
|
|
48
46
|
//#region src/data/invalidation.ts
|
|
49
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Mark all cached queries under `prefix` as stale, triggering a refresh.
|
|
49
|
+
* Matching is by `:`-delimited segment: a key matches when it equals `prefix`,
|
|
50
|
+
* when `prefix` ends in `:`, or when the key continues `prefix` at a `:`
|
|
51
|
+
* (`'user:1'` matches `user:1:posts` but not `user:10`). Only `:` is a
|
|
52
|
+
* segment boundary; the empty prefix matches every key.
|
|
53
|
+
*/
|
|
50
54
|
function invalidate(prefix, options) {
|
|
51
55
|
invalidateQueriesForRuntime(resolveDataRuntimeState(options?.runtime), prefix, options?.markPendingWrite ?? false);
|
|
52
56
|
}
|
|
53
|
-
/** Create a {@link QueryScope} that namespaces keys and invalidations
|
|
54
|
-
function queryScope(namespace) {
|
|
55
|
-
return createQueryScope(namespace, invalidate
|
|
57
|
+
/** Create a {@link QueryScope} that namespaces keys and can bind invalidations to a runtime. */
|
|
58
|
+
function queryScope(namespace, options) {
|
|
59
|
+
return createQueryScope(namespace, (prefix, callOptions) => invalidate(prefix, {
|
|
60
|
+
...callOptions,
|
|
61
|
+
runtime: callOptions?.runtime ?? options?.runtime
|
|
62
|
+
}));
|
|
56
63
|
}
|
|
57
64
|
const INVALIDATE_ON_INTERVAL_OPTIONS_ERROR = "[Askr] invalidateOnInterval() requires an options object with a finite numeric intervalMs.";
|
|
58
65
|
/**
|
|
59
66
|
* Periodically invalidate queries matching `prefix` on a fixed interval,
|
|
60
67
|
* optionally gated by active route, document visibility, or window focus.
|
|
68
|
+
* `prefix` matches key segments the same way as {@link invalidate}.
|
|
61
69
|
*/
|
|
62
70
|
function invalidateOnInterval(prefix, options) {
|
|
63
71
|
if (!options || typeof options !== "object" || typeof options.intervalMs !== "number" || !Number.isFinite(options.intervalMs)) throw new Error(INVALIDATE_ON_INTERVAL_OPTIONS_ERROR);
|
|
@@ -74,8 +82,10 @@ function invalidateOnInterval(prefix, options) {
|
|
|
74
82
|
//#region src/data/mutation-cell.ts
|
|
75
83
|
var MutationCell = class {
|
|
76
84
|
constructor(options, runtimeState) {
|
|
77
|
-
this.source =
|
|
85
|
+
this.source = createSource();
|
|
78
86
|
this.controller = null;
|
|
87
|
+
this.activeControllers = /* @__PURE__ */ new Set();
|
|
88
|
+
this.rollbacks = /* @__PURE__ */ new Map();
|
|
79
89
|
this.generation = 0;
|
|
80
90
|
this.state = {
|
|
81
91
|
status: "idle",
|
|
@@ -84,28 +94,30 @@ var MutationCell = class {
|
|
|
84
94
|
};
|
|
85
95
|
this.runtimeState = runtimeState;
|
|
86
96
|
this.action = options.action;
|
|
97
|
+
this.optimistic = options.optimistic;
|
|
87
98
|
this.affects = options.affects;
|
|
88
99
|
this.afterSuccess = options.afterSuccess;
|
|
89
100
|
}
|
|
90
101
|
setOptions(options) {
|
|
91
102
|
this.action = options.action;
|
|
103
|
+
this.optimistic = options.optimistic;
|
|
92
104
|
this.affects = options.affects;
|
|
93
105
|
this.afterSuccess = options.afterSuccess;
|
|
94
106
|
}
|
|
95
107
|
get status() {
|
|
96
|
-
|
|
108
|
+
readSource(this.source);
|
|
97
109
|
return this.state.status;
|
|
98
110
|
}
|
|
99
111
|
get pending() {
|
|
100
|
-
|
|
112
|
+
readSource(this.source);
|
|
101
113
|
return this.state.status === "pending";
|
|
102
114
|
}
|
|
103
115
|
get error() {
|
|
104
|
-
|
|
116
|
+
readSource(this.source);
|
|
105
117
|
return this.state.error;
|
|
106
118
|
}
|
|
107
119
|
get result() {
|
|
108
|
-
|
|
120
|
+
readSource(this.source);
|
|
109
121
|
return this.state.result;
|
|
110
122
|
}
|
|
111
123
|
setState(next) {
|
|
@@ -113,17 +125,18 @@ var MutationCell = class {
|
|
|
113
125
|
...this.state,
|
|
114
126
|
...next
|
|
115
127
|
};
|
|
116
|
-
|
|
128
|
+
notify(this.source);
|
|
117
129
|
}
|
|
118
130
|
async execute(input) {
|
|
119
131
|
const action = this.action;
|
|
132
|
+
const optimistic = this.optimistic;
|
|
120
133
|
const affects = this.affects;
|
|
121
134
|
const afterSuccess = this.afterSuccess;
|
|
122
135
|
this.generation += 1;
|
|
123
136
|
const generation = this.generation;
|
|
124
|
-
this.controller?.abort();
|
|
125
137
|
const controller = new AbortController();
|
|
126
138
|
this.controller = controller;
|
|
139
|
+
this.activeControllers.add(controller);
|
|
127
140
|
this.setState({
|
|
128
141
|
status: "pending",
|
|
129
142
|
error: null,
|
|
@@ -131,8 +144,17 @@ var MutationCell = class {
|
|
|
131
144
|
});
|
|
132
145
|
let result;
|
|
133
146
|
try {
|
|
147
|
+
const rollback = optimistic?.(input, { signal: controller.signal });
|
|
148
|
+
if (rollback) this.rollbacks.set(controller, rollback);
|
|
134
149
|
result = await action(input, { signal: controller.signal });
|
|
135
|
-
|
|
150
|
+
this.rollbacks.delete(controller);
|
|
151
|
+
} catch (cause) {
|
|
152
|
+
let error = cause;
|
|
153
|
+
try {
|
|
154
|
+
this.rollbackOptimistic(controller);
|
|
155
|
+
} catch (rollbackError) {
|
|
156
|
+
error = new AggregateError([cause, rollbackError], "Mutation failed and its optimistic rollback failed");
|
|
157
|
+
}
|
|
136
158
|
if (!isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) throw error;
|
|
137
159
|
if (isAbortError(error, controller.signal)) {
|
|
138
160
|
this.setState({
|
|
@@ -146,6 +168,9 @@ var MutationCell = class {
|
|
|
146
168
|
error: normalizeAsyncDataError(error, "Unknown mutation error")
|
|
147
169
|
});
|
|
148
170
|
throw error;
|
|
171
|
+
} finally {
|
|
172
|
+
this.activeControllers.delete(controller);
|
|
173
|
+
this.rollbacks.delete(controller);
|
|
149
174
|
}
|
|
150
175
|
if (isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) this.setState({
|
|
151
176
|
status: "success",
|
|
@@ -159,25 +184,44 @@ var MutationCell = class {
|
|
|
159
184
|
return result;
|
|
160
185
|
}
|
|
161
186
|
abort() {
|
|
162
|
-
if (this.
|
|
187
|
+
if (this.activeControllers.size === 0) return;
|
|
163
188
|
this.generation += 1;
|
|
164
|
-
this.controller?.abort();
|
|
165
189
|
this.controller = null;
|
|
166
|
-
this.setState({
|
|
190
|
+
if (this.state.status === "pending") this.setState({
|
|
167
191
|
status: "idle",
|
|
168
192
|
error: null,
|
|
169
193
|
result: null
|
|
170
194
|
});
|
|
195
|
+
this.cancelActive();
|
|
171
196
|
}
|
|
172
197
|
reset() {
|
|
173
198
|
this.generation += 1;
|
|
174
|
-
this.controller?.abort();
|
|
175
199
|
this.controller = null;
|
|
176
200
|
this.setState({
|
|
177
201
|
status: "idle",
|
|
178
202
|
error: null,
|
|
179
203
|
result: null
|
|
180
204
|
});
|
|
205
|
+
this.cancelActive();
|
|
206
|
+
}
|
|
207
|
+
rollbackOptimistic(controller) {
|
|
208
|
+
const rollback = this.rollbacks.get(controller);
|
|
209
|
+
this.rollbacks.delete(controller);
|
|
210
|
+
rollback?.();
|
|
211
|
+
}
|
|
212
|
+
cancelActive() {
|
|
213
|
+
const controllers = [...this.activeControllers];
|
|
214
|
+
this.activeControllers.clear();
|
|
215
|
+
const errors = [];
|
|
216
|
+
for (const controller of controllers) {
|
|
217
|
+
try {
|
|
218
|
+
this.rollbackOptimistic(controller);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
errors.push(error);
|
|
221
|
+
}
|
|
222
|
+
controller.abort();
|
|
223
|
+
}
|
|
224
|
+
if (errors.length > 0) throw new AggregateError(errors, "Optimistic mutation rollback failed");
|
|
181
225
|
}
|
|
182
226
|
};
|
|
183
227
|
/**
|
|
@@ -187,14 +231,14 @@ var MutationCell = class {
|
|
|
187
231
|
*/
|
|
188
232
|
function createMutation(options) {
|
|
189
233
|
if (options.key !== void 0 && options.key.length === 0) throw new TypeError("createMutation key must be a non-empty string.");
|
|
190
|
-
const instance =
|
|
234
|
+
const instance = currentComponent();
|
|
191
235
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
192
236
|
const override = options.key ? runtimeState.mutationTestOverrides.get(options.key) : void 0;
|
|
193
237
|
if (!instance) {
|
|
194
238
|
if (override) return override;
|
|
195
239
|
return new MutationCell(options, runtimeState);
|
|
196
240
|
}
|
|
197
|
-
const hookIndex = claimHookIndex(instance, "
|
|
241
|
+
const hookIndex = claimHookIndex(instance, "createMutation");
|
|
198
242
|
ensureMutationCleanup(runtimeState, instance);
|
|
199
243
|
const slotStore = getMutationSlotStore(runtimeState, instance);
|
|
200
244
|
if (override) {
|
|
@@ -281,19 +325,24 @@ function errorQueryState(data, error) {
|
|
|
281
325
|
//#region src/data/query-cell.ts
|
|
282
326
|
const RECONCILE_MAX_ATTEMPTS = 3;
|
|
283
327
|
const RECONCILE_RETRY_DELAY_MS = 25;
|
|
284
|
-
|
|
328
|
+
const MAX_GC_TIME_MS = 2147483647;
|
|
329
|
+
const DEFAULT_OWNERLESS_GC_TIME_MS = 3e5;
|
|
330
|
+
function validateGcTime(gcTime) {
|
|
331
|
+
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.");
|
|
332
|
+
}
|
|
333
|
+
/** Starts a query fetch in the flush; settles its promise if dropped. */
|
|
334
|
+
var QueryStartWork = class {
|
|
285
335
|
constructor(run, settle) {
|
|
286
|
-
|
|
336
|
+
this.run = run;
|
|
287
337
|
this.settle = settle;
|
|
288
338
|
}
|
|
289
339
|
cancel() {
|
|
290
|
-
super.cancel();
|
|
291
340
|
this.settle();
|
|
292
341
|
}
|
|
293
342
|
};
|
|
294
343
|
var QueryCell = class {
|
|
295
344
|
constructor(options, key, cache) {
|
|
296
|
-
this.source =
|
|
345
|
+
this.source = createSource();
|
|
297
346
|
this.controller = null;
|
|
298
347
|
this.generation = 0;
|
|
299
348
|
this.pendingRefresh = null;
|
|
@@ -304,22 +353,36 @@ var QueryCell = class {
|
|
|
304
353
|
this.reconcileSequence = 0;
|
|
305
354
|
this.destroyed = false;
|
|
306
355
|
this.ownerCount = 0;
|
|
356
|
+
this.gcTimer = null;
|
|
357
|
+
this.unownedTimer = null;
|
|
307
358
|
this.owners = /* @__PURE__ */ new Map();
|
|
308
359
|
this.warnedDefinitionConflictKeys = /* @__PURE__ */ new Set();
|
|
360
|
+
this.definitionOwner = null;
|
|
361
|
+
this.definitionOwnerHook = -1;
|
|
362
|
+
this.conflictCheck = null;
|
|
309
363
|
this.state = loadingQueryState();
|
|
364
|
+
validateGcTime(options.gcTime);
|
|
310
365
|
this.options = options;
|
|
311
366
|
this.key = key;
|
|
312
367
|
this.cache = cache;
|
|
313
368
|
if (options.initialData !== void 0) this.state = freshQueryState(options.initialData);
|
|
314
369
|
}
|
|
315
370
|
attach(generation, hookIndex) {
|
|
371
|
+
if (this.unownedTimer !== null) {
|
|
372
|
+
clearTimeout(this.unownedTimer);
|
|
373
|
+
this.unownedTimer = null;
|
|
374
|
+
}
|
|
375
|
+
if (this.gcTimer !== null) {
|
|
376
|
+
clearTimeout(this.gcTimer);
|
|
377
|
+
this.gcTimer = null;
|
|
378
|
+
}
|
|
316
379
|
let hooks = this.owners.get(generation);
|
|
317
380
|
if (!hooks) {
|
|
318
|
-
hooks = /* @__PURE__ */ new
|
|
381
|
+
hooks = /* @__PURE__ */ new Map();
|
|
319
382
|
this.owners.set(generation, hooks);
|
|
320
383
|
}
|
|
321
384
|
if (hooks.has(hookIndex)) return;
|
|
322
|
-
hooks.
|
|
385
|
+
hooks.set(hookIndex, null);
|
|
323
386
|
this.ownerCount += 1;
|
|
324
387
|
}
|
|
325
388
|
detach(generation, hookIndex) {
|
|
@@ -327,7 +390,51 @@ var QueryCell = class {
|
|
|
327
390
|
if (!hooks || !hooks.delete(hookIndex)) return;
|
|
328
391
|
this.ownerCount -= 1;
|
|
329
392
|
if (hooks.size === 0) this.owners.delete(generation);
|
|
330
|
-
if (this.ownerCount <= 0)
|
|
393
|
+
if (this.ownerCount <= 0) {
|
|
394
|
+
const gcTime = this.options.gcTime ?? 0;
|
|
395
|
+
if (gcTime === 0 || this.state.data === null || isServerRender()) this.destroy();
|
|
396
|
+
else {
|
|
397
|
+
this.generation += 1;
|
|
398
|
+
this.controller?.abort();
|
|
399
|
+
this.controller = null;
|
|
400
|
+
this.finishPendingRefresh();
|
|
401
|
+
this.definitionOwner = null;
|
|
402
|
+
this.definitionOwnerHook = -1;
|
|
403
|
+
this.gcTimer = setTimeout(() => this.destroy(), gcTime);
|
|
404
|
+
}
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (this.definitionOwner === generation && this.definitionOwnerHook === hookIndex) this.promoteDefinitionOwner();
|
|
408
|
+
}
|
|
409
|
+
promoteDefinitionOwner() {
|
|
410
|
+
this.definitionOwner = null;
|
|
411
|
+
for (const [generation, hooks] of this.owners) for (const [hookIndex, options] of hooks) if (options) {
|
|
412
|
+
this.options = options;
|
|
413
|
+
this.definitionOwner = generation;
|
|
414
|
+
this.definitionOwnerHook = hookIndex;
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Record an attached reader's definition for this key. The owning reader's
|
|
420
|
+
* renders replace the definition; with no owner, the reader takes over.
|
|
421
|
+
* Other readers are checked for conflicts once render work settles.
|
|
422
|
+
*/
|
|
423
|
+
define(options, generation, hookIndex) {
|
|
424
|
+
validateGcTime(options.gcTime);
|
|
425
|
+
const hooks = this.owners.get(generation);
|
|
426
|
+
if (this.destroyed || !hooks?.has(hookIndex)) return;
|
|
427
|
+
hooks.set(hookIndex, options);
|
|
428
|
+
if (this.definitionOwner === null || this.definitionOwner === generation && this.definitionOwnerHook === hookIndex) {
|
|
429
|
+
this.options = options;
|
|
430
|
+
this.definitionOwner = generation;
|
|
431
|
+
this.definitionOwnerHook = hookIndex;
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
warnOnConflictingReaders() {
|
|
436
|
+
if (this.destroyed) return;
|
|
437
|
+
for (const hooks of this.owners.values()) for (const options of hooks.values()) if (options) this.warnOnConflictingDefinition(options);
|
|
331
438
|
}
|
|
332
439
|
warnOnConflictingDefinition(options) {
|
|
333
440
|
const conflicts = this.getDefinitionConflicts(options);
|
|
@@ -341,14 +448,45 @@ var QueryCell = class {
|
|
|
341
448
|
destroy() {
|
|
342
449
|
if (this.destroyed) return;
|
|
343
450
|
this.destroyed = true;
|
|
451
|
+
if (this.gcTimer !== null) {
|
|
452
|
+
clearTimeout(this.gcTimer);
|
|
453
|
+
this.gcTimer = null;
|
|
454
|
+
}
|
|
455
|
+
if (this.unownedTimer !== null) {
|
|
456
|
+
clearTimeout(this.unownedTimer);
|
|
457
|
+
this.unownedTimer = null;
|
|
458
|
+
}
|
|
344
459
|
this.controller?.abort();
|
|
345
460
|
this.controller = null;
|
|
346
461
|
this.reconcileAttemptCount = 0;
|
|
347
462
|
this.ownerCount = 0;
|
|
348
463
|
this.owners.clear();
|
|
349
|
-
this.
|
|
464
|
+
this.evictFromCache();
|
|
350
465
|
this.finishPendingRefresh();
|
|
351
466
|
}
|
|
467
|
+
evictFromCache() {
|
|
468
|
+
if (this.cache.get(this.key) === this) this.cache.delete(this.key);
|
|
469
|
+
}
|
|
470
|
+
/** A component's inactive definition must not become an ownerless fetcher. */
|
|
471
|
+
retireInactiveReaderCacheEntry() {
|
|
472
|
+
if (this.gcTimer === null) return false;
|
|
473
|
+
this.destroy();
|
|
474
|
+
return true;
|
|
475
|
+
}
|
|
476
|
+
/** Ownerless handles stay usable after their cache lookup window expires. */
|
|
477
|
+
scheduleUnownedCacheEviction(gcTime) {
|
|
478
|
+
if (isServerRender() || this.ownerCount > 0 || this.destroyed) return;
|
|
479
|
+
if (this.unownedTimer !== null) clearTimeout(this.unownedTimer);
|
|
480
|
+
this.unownedTimer = null;
|
|
481
|
+
if (gcTime === 0) {
|
|
482
|
+
this.evictFromCache();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
this.unownedTimer = setTimeout(() => {
|
|
486
|
+
this.unownedTimer = null;
|
|
487
|
+
if (this.ownerCount === 0) this.evictFromCache();
|
|
488
|
+
}, gcTime);
|
|
489
|
+
}
|
|
352
490
|
getDefinitionConflicts(options) {
|
|
353
491
|
const conflicts = [];
|
|
354
492
|
if ((this.options.definitionIdentity ?? this.options.fetch) !== (options.definitionIdentity ?? options.fetch)) conflicts.push("fetch");
|
|
@@ -357,31 +495,31 @@ var QueryCell = class {
|
|
|
357
495
|
return conflicts;
|
|
358
496
|
}
|
|
359
497
|
get data() {
|
|
360
|
-
|
|
498
|
+
readSource(this.source);
|
|
361
499
|
return this.state.data;
|
|
362
500
|
}
|
|
363
501
|
get error() {
|
|
364
|
-
|
|
502
|
+
readSource(this.source);
|
|
365
503
|
return this.state.error;
|
|
366
504
|
}
|
|
367
505
|
get loading() {
|
|
368
|
-
|
|
506
|
+
readSource(this.source);
|
|
369
507
|
return this.state.loading;
|
|
370
508
|
}
|
|
371
509
|
get refreshing() {
|
|
372
|
-
|
|
510
|
+
readSource(this.source);
|
|
373
511
|
return this.state.refreshing;
|
|
374
512
|
}
|
|
375
513
|
get stale() {
|
|
376
|
-
|
|
514
|
+
readSource(this.source);
|
|
377
515
|
return this.state.stale;
|
|
378
516
|
}
|
|
379
517
|
get consistency() {
|
|
380
|
-
|
|
518
|
+
readSource(this.source);
|
|
381
519
|
return this.state.consistency;
|
|
382
520
|
}
|
|
383
521
|
get staleReason() {
|
|
384
|
-
|
|
522
|
+
readSource(this.source);
|
|
385
523
|
return this.state.staleReason;
|
|
386
524
|
}
|
|
387
525
|
/** @internal Whether a collection should schedule this cell's first load. */
|
|
@@ -394,6 +532,10 @@ var QueryCell = class {
|
|
|
394
532
|
}
|
|
395
533
|
refresh() {
|
|
396
534
|
if (this.destroyed) return Promise.resolve();
|
|
535
|
+
if (this.gcTimer !== null) {
|
|
536
|
+
this.destroy();
|
|
537
|
+
return Promise.resolve();
|
|
538
|
+
}
|
|
397
539
|
if (this.pendingRefresh) {
|
|
398
540
|
if (this.pendingRefreshKind === "invalidation") {
|
|
399
541
|
this.controller?.abort();
|
|
@@ -404,14 +546,26 @@ var QueryCell = class {
|
|
|
404
546
|
this.queueStart(void 0, "manual");
|
|
405
547
|
return this.pendingRefresh ?? Promise.resolve();
|
|
406
548
|
}
|
|
407
|
-
|
|
549
|
+
/** @internal Show an invalidation while a collection waits for a fetch slot. */
|
|
550
|
+
markQueuedInvalidation() {
|
|
408
551
|
if (this.destroyed) return;
|
|
552
|
+
this.generation += 1;
|
|
553
|
+
this.controller?.abort();
|
|
554
|
+
this.setState(this.state.data === null ? loadingQueryState() : refreshingQueryState(this.state.data, this.state.consistency === "pending-write" ? "pending-write" : "refreshing"));
|
|
555
|
+
}
|
|
556
|
+
invalidate() {
|
|
557
|
+
if (this.destroyed) return Promise.resolve();
|
|
558
|
+
if (this.gcTimer !== null) {
|
|
559
|
+
this.destroy();
|
|
560
|
+
return Promise.resolve();
|
|
561
|
+
}
|
|
409
562
|
if (this.pendingRefresh) {
|
|
410
563
|
this.controller?.abort();
|
|
411
564
|
this.queueStart(void 0, "invalidation", true);
|
|
412
|
-
return;
|
|
565
|
+
return this.pendingRefresh ?? Promise.resolve();
|
|
413
566
|
}
|
|
414
567
|
this.queueStart(void 0, "invalidation");
|
|
568
|
+
return this.pendingRefresh ?? Promise.resolve();
|
|
415
569
|
}
|
|
416
570
|
markPendingWrite() {
|
|
417
571
|
if (this.destroyed) return;
|
|
@@ -429,7 +583,7 @@ var QueryCell = class {
|
|
|
429
583
|
if (!continuePending || !this.pendingRefresh) this.pendingRefresh = new Promise((resolve) => {
|
|
430
584
|
this.pendingRefreshResolve = resolve;
|
|
431
585
|
});
|
|
432
|
-
|
|
586
|
+
schedule(new QueryStartWork(() => {
|
|
433
587
|
if (token !== this.pendingRefreshToken) return;
|
|
434
588
|
if (this.destroyed) {
|
|
435
589
|
this.finishPendingRefresh(token);
|
|
@@ -442,7 +596,7 @@ var QueryCell = class {
|
|
|
442
596
|
if (token !== this.pendingRefreshToken) return;
|
|
443
597
|
this.generation += 1;
|
|
444
598
|
this.finishPendingRefresh(token);
|
|
445
|
-
}));
|
|
599
|
+
}), "effect");
|
|
446
600
|
}
|
|
447
601
|
finishPendingRefresh(token = this.pendingRefreshToken) {
|
|
448
602
|
if (token !== this.pendingRefreshToken) return;
|
|
@@ -455,7 +609,7 @@ var QueryCell = class {
|
|
|
455
609
|
setState(next) {
|
|
456
610
|
if (this.destroyed) return;
|
|
457
611
|
this.state = next;
|
|
458
|
-
|
|
612
|
+
notify(this.source);
|
|
459
613
|
}
|
|
460
614
|
async start(reconcileSequence) {
|
|
461
615
|
if (this.destroyed) return;
|
|
@@ -466,9 +620,10 @@ var QueryCell = class {
|
|
|
466
620
|
this.controller = controller;
|
|
467
621
|
const hasData = this.state.data !== null;
|
|
468
622
|
this.setState(hasData ? refreshingQueryState(this.state.data) : loadingQueryState());
|
|
623
|
+
const { fetch, isConsistent: checkConsistent, reconcile } = this.options;
|
|
469
624
|
let nextData;
|
|
470
625
|
try {
|
|
471
|
-
nextData = await
|
|
626
|
+
nextData = await fetch({ signal: controller.signal });
|
|
472
627
|
} catch (error) {
|
|
473
628
|
if (this.destroyed || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
474
629
|
if (isAbortError(error, controller.signal)) {
|
|
@@ -481,7 +636,7 @@ var QueryCell = class {
|
|
|
481
636
|
if (this.destroyed || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
482
637
|
let isConsistent;
|
|
483
638
|
try {
|
|
484
|
-
isConsistent =
|
|
639
|
+
isConsistent = checkConsistent?.(nextData) ?? true;
|
|
485
640
|
} catch (error) {
|
|
486
641
|
this.setState(errorQueryState(this.state.data, normalizeAsyncDataError(error, "Query consistency check failed")));
|
|
487
642
|
return;
|
|
@@ -489,7 +644,7 @@ var QueryCell = class {
|
|
|
489
644
|
if (!isConsistent) {
|
|
490
645
|
this.setState(staleQueryState(nextData, "inconsistent"));
|
|
491
646
|
try {
|
|
492
|
-
await this.reconcile(nextData, generation, controller, reconcileSequence);
|
|
647
|
+
await this.reconcile(reconcile, nextData, generation, controller, reconcileSequence);
|
|
493
648
|
} catch (error) {
|
|
494
649
|
if (isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) this.setState(errorQueryState(this.state.data, normalizeAsyncDataError(error, "Query reconciliation failed")));
|
|
495
650
|
}
|
|
@@ -498,8 +653,8 @@ var QueryCell = class {
|
|
|
498
653
|
this.reconcileAttemptCount = 0;
|
|
499
654
|
this.setState(freshQueryState(nextData));
|
|
500
655
|
}
|
|
501
|
-
async reconcile(data, generation, controller, reconcileSequence) {
|
|
502
|
-
if (!await (
|
|
656
|
+
async reconcile(reconcile, data, generation, controller, reconcileSequence) {
|
|
657
|
+
if (!await (reconcile?.(data, { key: this.key }) ?? false) || this.destroyed || reconcileSequence !== this.reconcileSequence || !isCurrentAsyncOperation(this.generation, generation, this.controller, controller)) return;
|
|
503
658
|
this.reconcileAttemptCount += 1;
|
|
504
659
|
if (this.reconcileAttemptCount > RECONCILE_MAX_ATTEMPTS) {
|
|
505
660
|
this.setState(staleQueryState(this.state.data, "inconsistent"));
|
|
@@ -511,63 +666,71 @@ var QueryCell = class {
|
|
|
511
666
|
this.queueStart(reconcileSequence, "reconcile", true);
|
|
512
667
|
}
|
|
513
668
|
};
|
|
669
|
+
function isServerRender() {
|
|
670
|
+
const context = getActiveRenderContext();
|
|
671
|
+
return context?.mode === "ssr" || context?.mode === void 0 && typeof window === "undefined";
|
|
672
|
+
}
|
|
673
|
+
function createCell(options, cache) {
|
|
674
|
+
const cell = new QueryCell(options.takeInitialData ? {
|
|
675
|
+
...options,
|
|
676
|
+
initialData: options.takeInitialData()
|
|
677
|
+
} : options, options.key, cache);
|
|
678
|
+
cache.set(options.key, cell);
|
|
679
|
+
cell.ensureStarted();
|
|
680
|
+
return cell;
|
|
681
|
+
}
|
|
514
682
|
function createLegacyQuery(options) {
|
|
515
|
-
|
|
683
|
+
validateGcTime(options.gcTime);
|
|
684
|
+
const instance = currentComponent();
|
|
516
685
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
517
686
|
const cache = runtimeState.queryCache;
|
|
518
687
|
const override = runtimeState.queryTestOverrides.get(options.key);
|
|
519
688
|
if (!instance) {
|
|
520
689
|
if (override) return override;
|
|
521
690
|
let cell = cache.get(options.key);
|
|
522
|
-
if (
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
} else cell.warnOnConflictingDefinition(options);
|
|
691
|
+
if (cell?.retireInactiveReaderCacheEntry()) cell = void 0;
|
|
692
|
+
if (!cell) cell = createCell(options, cache);
|
|
693
|
+
else cell.warnOnConflictingDefinition(options);
|
|
694
|
+
cell.scheduleUnownedCacheEviction(options.gcTime ?? DEFAULT_OWNERLESS_GC_TIME_MS);
|
|
527
695
|
return cell;
|
|
528
696
|
}
|
|
529
|
-
const hookIndex = claimHookIndex(instance, "
|
|
697
|
+
const hookIndex = claimHookIndex(instance, "createQuery");
|
|
530
698
|
ensureQueryCleanup(runtimeState, instance);
|
|
699
|
+
const generation = instance;
|
|
531
700
|
const slotStore = getQuerySlotStore(runtimeState, instance);
|
|
532
701
|
const existingSlot = slotStore.get(hookIndex);
|
|
533
702
|
if (existingSlot && existingSlot.key === options.key) {
|
|
534
|
-
existingSlot.cell.
|
|
703
|
+
existingSlot.cell.define(options, generation, hookIndex);
|
|
535
704
|
return existingSlot.cell;
|
|
536
705
|
}
|
|
537
|
-
if (existingSlot) existingSlot.cell.detach(
|
|
706
|
+
if (existingSlot) existingSlot.cell.detach(generation, hookIndex);
|
|
538
707
|
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);
|
|
708
|
+
const cell = cache.get(options.key) ?? createCell(options, cache);
|
|
545
709
|
slotStore.set(hookIndex, {
|
|
546
710
|
key: options.key,
|
|
547
711
|
cell
|
|
548
712
|
});
|
|
549
|
-
cell.attach(
|
|
713
|
+
cell.attach(generation, hookIndex);
|
|
714
|
+
cell.define(options, generation, hookIndex);
|
|
715
|
+
cell.ensureStarted();
|
|
550
716
|
return cell;
|
|
551
717
|
}
|
|
552
718
|
function createDefinedQuery(definition, input, options = {}) {
|
|
553
719
|
const runtime = options.runtime;
|
|
554
|
-
const context = getActiveRenderContext();
|
|
555
720
|
const key = definition.key(input);
|
|
556
|
-
const dataRuntime = runtime ?? getActiveRenderContext()?.dataRuntime ??
|
|
557
|
-
const
|
|
721
|
+
const dataRuntime = runtime ?? getActiveRenderContext()?.dataRuntime ?? currentAppRuntime()?.dataRuntime ?? getDefaultDataRuntime();
|
|
722
|
+
const serverRender = isServerRender();
|
|
723
|
+
const runtimeState = resolveDataRuntimeState(dataRuntime);
|
|
558
724
|
return createLegacyQuery({
|
|
559
725
|
...options,
|
|
560
726
|
key,
|
|
561
727
|
definitionIdentity: definition,
|
|
562
|
-
fetch: ({ signal }) => definition.fetch({
|
|
563
|
-
...input,
|
|
564
|
-
signal
|
|
565
|
-
}),
|
|
728
|
+
fetch: ({ signal }) => definition.fetch(input, { signal }),
|
|
566
729
|
isConsistent: definition.isConsistent,
|
|
567
730
|
reconcile: definition.reconcile,
|
|
568
|
-
|
|
569
|
-
skipInitialFetch:
|
|
570
|
-
runtime: dataRuntime
|
|
731
|
+
takeInitialData: () => readQueryData(runtimeState, key, !serverRender),
|
|
732
|
+
skipInitialFetch: serverRender,
|
|
733
|
+
runtime: dataRuntime
|
|
571
734
|
});
|
|
572
735
|
}
|
|
573
736
|
function createQuery(optionsOrDefinition, input, options) {
|
|
@@ -592,17 +755,13 @@ function getCollectionStore(generation) {
|
|
|
592
755
|
}
|
|
593
756
|
return store;
|
|
594
757
|
}
|
|
595
|
-
function createCellOptions(
|
|
758
|
+
function createCellOptions(query, input, queryKey) {
|
|
596
759
|
return {
|
|
597
760
|
key: queryKey,
|
|
598
761
|
definitionIdentity: query,
|
|
599
|
-
fetch: ({ signal }) => query.fetch({
|
|
600
|
-
...input,
|
|
601
|
-
signal
|
|
602
|
-
}),
|
|
762
|
+
fetch: ({ signal }) => query.fetch(input, { signal }),
|
|
603
763
|
isConsistent: query.isConsistent,
|
|
604
764
|
reconcile: query.reconcile,
|
|
605
|
-
initialData: runtimeState.queryData.get(queryKey),
|
|
606
765
|
skipInitialFetch: true
|
|
607
766
|
};
|
|
608
767
|
}
|
|
@@ -611,12 +770,25 @@ var QueryCollectionCell = class {
|
|
|
611
770
|
this.runtimeState = runtimeState;
|
|
612
771
|
this.records = /* @__PURE__ */ new Map();
|
|
613
772
|
this.ordered = [];
|
|
773
|
+
this.registeredCells = /* @__PURE__ */ new Set();
|
|
614
774
|
this.tasks = /* @__PURE__ */ new Map();
|
|
615
775
|
this.queue = [];
|
|
616
776
|
this.activeCount = 0;
|
|
617
777
|
this.concurrency = DEFAULT_QUERY_COLLECTION_CONCURRENCY;
|
|
618
778
|
this.disposed = false;
|
|
619
779
|
}
|
|
780
|
+
get invalidationConcurrency() {
|
|
781
|
+
return this.concurrency;
|
|
782
|
+
}
|
|
783
|
+
invalidateCell(cell) {
|
|
784
|
+
const ownedCell = cell;
|
|
785
|
+
if (this.tasks.get(ownedCell)?.state === "active") {
|
|
786
|
+
ownedCell.invalidate();
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
ownedCell.markQueuedInvalidation();
|
|
790
|
+
this.schedule(ownedCell, "invalidation");
|
|
791
|
+
}
|
|
620
792
|
get entries() {
|
|
621
793
|
return this.ordered;
|
|
622
794
|
}
|
|
@@ -663,12 +835,12 @@ var QueryCollectionCell = class {
|
|
|
663
835
|
const startCandidates = /* @__PURE__ */ new Set();
|
|
664
836
|
const detachedCells = /* @__PURE__ */ new Set();
|
|
665
837
|
for (const { input, key, queryKey } of desired) {
|
|
666
|
-
const cellOptions = createCellOptions(
|
|
838
|
+
const cellOptions = createCellOptions(query, input, queryKey);
|
|
667
839
|
const previous = this.records.get(key);
|
|
668
840
|
let record;
|
|
669
841
|
if (previous?.queryKey === queryKey) {
|
|
670
842
|
previous.input = input;
|
|
671
|
-
previous.cell.
|
|
843
|
+
previous.cell.define(cellOptions, previous.owner, 0);
|
|
672
844
|
record = previous;
|
|
673
845
|
} else {
|
|
674
846
|
if (previous) {
|
|
@@ -678,11 +850,16 @@ var QueryCollectionCell = class {
|
|
|
678
850
|
const cache = this.runtimeState.queryCache;
|
|
679
851
|
let cell = cache.get(queryKey);
|
|
680
852
|
if (!cell) {
|
|
681
|
-
|
|
853
|
+
const initialData = readQueryData(this.runtimeState, queryKey, startInitialFetches);
|
|
854
|
+
cell = new QueryCell({
|
|
855
|
+
...cellOptions,
|
|
856
|
+
initialData
|
|
857
|
+
}, queryKey, cache);
|
|
682
858
|
cache.set(queryKey, cell);
|
|
683
|
-
}
|
|
859
|
+
}
|
|
684
860
|
const owner = {};
|
|
685
861
|
cell.attach(owner, 0);
|
|
862
|
+
cell.define(cellOptions, owner, 0);
|
|
686
863
|
record = {
|
|
687
864
|
key,
|
|
688
865
|
input,
|
|
@@ -700,8 +877,12 @@ var QueryCollectionCell = class {
|
|
|
700
877
|
this.detach(record);
|
|
701
878
|
detachedCells.add(record.cell);
|
|
702
879
|
}
|
|
880
|
+
const nextCells = new Set(nextOrdered.map((record) => record.cell));
|
|
703
881
|
this.records = nextRecords;
|
|
704
882
|
this.ordered = Object.freeze(nextOrdered);
|
|
883
|
+
for (const cell of this.registeredCells) if (!nextCells.has(cell)) unregisterCollectionCell(cell, this);
|
|
884
|
+
for (const cell of nextCells) if (!this.registeredCells.has(cell)) registerCollectionCell(cell, this);
|
|
885
|
+
this.registeredCells = nextCells;
|
|
705
886
|
for (const cell of detachedCells) this.cancelIfUnused(cell);
|
|
706
887
|
for (const cell of startCandidates) this.schedule(cell);
|
|
707
888
|
this.pump();
|
|
@@ -709,6 +890,8 @@ var QueryCollectionCell = class {
|
|
|
709
890
|
dispose() {
|
|
710
891
|
if (this.disposed) return;
|
|
711
892
|
this.disposed = true;
|
|
893
|
+
for (const cell of this.registeredCells) unregisterCollectionCell(cell, this);
|
|
894
|
+
this.registeredCells.clear();
|
|
712
895
|
const cells = /* @__PURE__ */ new Set();
|
|
713
896
|
for (const record of this.records.values()) {
|
|
714
897
|
cells.add(record.cell);
|
|
@@ -730,15 +913,20 @@ var QueryCollectionCell = class {
|
|
|
730
913
|
const task = this.tasks.get(cell);
|
|
731
914
|
if (!task || task.state === "cancelled" || task.state === "done") return;
|
|
732
915
|
if (task.state === "active") this.activeCount -= 1;
|
|
916
|
+
const rescheduleInvalidation = task.state === "queued" && task.kind === "invalidation";
|
|
733
917
|
task.state = "cancelled";
|
|
734
918
|
this.tasks.delete(cell);
|
|
735
919
|
task.resolve();
|
|
920
|
+
if (rescheduleInvalidation && !invalidateCollectionCell(cell)) cell.invalidate();
|
|
736
921
|
this.pump();
|
|
737
922
|
}
|
|
738
|
-
schedule(cell) {
|
|
923
|
+
schedule(cell, kind = "refresh") {
|
|
739
924
|
if (this.disposed) return Promise.resolve();
|
|
740
925
|
const existing = this.tasks.get(cell);
|
|
741
|
-
if (existing)
|
|
926
|
+
if (existing) {
|
|
927
|
+
if (kind === "invalidation") existing.kind = kind;
|
|
928
|
+
return existing.promise;
|
|
929
|
+
}
|
|
742
930
|
let resolve;
|
|
743
931
|
const promise = new Promise((done) => {
|
|
744
932
|
resolve = done;
|
|
@@ -747,7 +935,8 @@ var QueryCollectionCell = class {
|
|
|
747
935
|
cell,
|
|
748
936
|
promise,
|
|
749
937
|
resolve,
|
|
750
|
-
state: "queued"
|
|
938
|
+
state: "queued",
|
|
939
|
+
kind
|
|
751
940
|
};
|
|
752
941
|
this.tasks.set(cell, task);
|
|
753
942
|
this.queue.push(task);
|
|
@@ -762,7 +951,7 @@ var QueryCollectionCell = class {
|
|
|
762
951
|
if (task.state !== "queued" || this.tasks.get(task.cell) !== task) continue;
|
|
763
952
|
task.state = "active";
|
|
764
953
|
this.activeCount += 1;
|
|
765
|
-
task.cell.refresh().finally(() => this.finish(task));
|
|
954
|
+
(task.kind === "invalidation" ? task.cell.invalidate() : task.cell.refresh()).finally(() => this.finish(task));
|
|
766
955
|
}
|
|
767
956
|
}
|
|
768
957
|
finish(task) {
|
|
@@ -779,13 +968,13 @@ var QueryCollectionCell = class {
|
|
|
779
968
|
* reusable query definition, with bounded collection-started fetches.
|
|
780
969
|
*/
|
|
781
970
|
function createQueryCollection(options) {
|
|
782
|
-
const instance =
|
|
971
|
+
const instance = currentComponent();
|
|
783
972
|
if (!instance) throw new Error("[Askr] createQueryCollection() must be called during component render execution.");
|
|
784
973
|
const hookIndex = claimHookIndex(instance, "createQueryCollection");
|
|
785
974
|
const concurrency = normalizeQueryCollectionConcurrency(options.concurrency);
|
|
786
975
|
const inputs = options.inputs();
|
|
787
976
|
if (!Array.isArray(inputs)) throw new Error("[Askr] createQueryCollection() inputs must return a readonly array.");
|
|
788
|
-
const generation =
|
|
977
|
+
const generation = instance;
|
|
789
978
|
const runtimeState = resolveDataRuntimeState(options.runtime);
|
|
790
979
|
const store = getCollectionStore(generation);
|
|
791
980
|
let slot = store.get(hookIndex);
|
|
@@ -800,7 +989,7 @@ function createQueryCollection(options) {
|
|
|
800
989
|
collection: new QueryCollectionCell(runtimeState)
|
|
801
990
|
};
|
|
802
991
|
store.set(hookIndex, slot);
|
|
803
|
-
|
|
992
|
+
instance.onCleanup(() => {
|
|
804
993
|
const current = store.get(hookIndex);
|
|
805
994
|
try {
|
|
806
995
|
current?.collection.dispose();
|