@spoosh/angular 0.1.3 → 0.2.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/dist/index.d.mts +18 -6
- package/dist/index.d.ts +18 -6
- package/dist/index.js +365 -213
- package/dist/index.mjs +365 -213
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -47,9 +47,10 @@ function createInjectRead(options) {
|
|
|
47
47
|
let currentController = null;
|
|
48
48
|
let currentQueryKey = null;
|
|
49
49
|
let currentSubscription = null;
|
|
50
|
+
let currentResolvedTags = [];
|
|
50
51
|
let prevContext = null;
|
|
51
|
-
let initialized = false;
|
|
52
52
|
let isMounted = false;
|
|
53
|
+
const hookId = `angular-${Math.random().toString(36).slice(2)}`;
|
|
53
54
|
const captureSelector = () => {
|
|
54
55
|
const selectorResult = {
|
|
55
56
|
call: null,
|
|
@@ -64,6 +65,43 @@ function createInjectRead(options) {
|
|
|
64
65
|
readFn(selectorProxy);
|
|
65
66
|
return selectorResult;
|
|
66
67
|
};
|
|
68
|
+
const createController = (capturedCall, resolvedPath, resolvedTags, queryKey) => {
|
|
69
|
+
if (currentSubscription) {
|
|
70
|
+
currentSubscription();
|
|
71
|
+
}
|
|
72
|
+
const controller = (0, import_core2.createOperationController)({
|
|
73
|
+
operationType: "read",
|
|
74
|
+
path: capturedCall.path,
|
|
75
|
+
method: capturedCall.method,
|
|
76
|
+
tags: resolvedTags,
|
|
77
|
+
requestOptions: capturedCall.options,
|
|
78
|
+
stateManager,
|
|
79
|
+
eventEmitter,
|
|
80
|
+
pluginExecutor,
|
|
81
|
+
hookId,
|
|
82
|
+
fetchFn: async (fetchOpts) => {
|
|
83
|
+
let current = api;
|
|
84
|
+
for (const segment of resolvedPath) {
|
|
85
|
+
current = current[segment];
|
|
86
|
+
}
|
|
87
|
+
const method = current[capturedCall.method];
|
|
88
|
+
return method(fetchOpts);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
controller.setPluginOptions(pluginOpts);
|
|
92
|
+
currentSubscription = controller.subscribe(() => {
|
|
93
|
+
const state = controller.getState();
|
|
94
|
+
dataSignal.set(state.data);
|
|
95
|
+
errorSignal.set(state.error);
|
|
96
|
+
const entry = stateManager.getCache(queryKey);
|
|
97
|
+
const newMeta = entry?.meta ? Object.fromEntries(entry.meta) : {};
|
|
98
|
+
metaSignal.set(newMeta);
|
|
99
|
+
});
|
|
100
|
+
currentController = controller;
|
|
101
|
+
currentQueryKey = queryKey;
|
|
102
|
+
currentResolvedTags = resolvedTags;
|
|
103
|
+
return controller;
|
|
104
|
+
};
|
|
67
105
|
const executeWithTracking = async (controller, force = false) => {
|
|
68
106
|
const hasData = dataSignal() !== void 0;
|
|
69
107
|
loadingSignal.set(!hasData);
|
|
@@ -87,6 +125,34 @@ function createInjectRead(options) {
|
|
|
87
125
|
fetchingSignal.set(false);
|
|
88
126
|
}
|
|
89
127
|
};
|
|
128
|
+
const initialSelectorResult = captureSelector();
|
|
129
|
+
const initialCapturedCall = initialSelectorResult.call;
|
|
130
|
+
if (!initialCapturedCall) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
"injectRead requires calling an HTTP method ($get). Example: injectRead((api) => api.posts.$get())"
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const initialRequestOptions = initialCapturedCall.options;
|
|
136
|
+
const initialResolvedPath = (0, import_core2.resolvePath)(
|
|
137
|
+
initialCapturedCall.path,
|
|
138
|
+
initialRequestOptions?.params
|
|
139
|
+
);
|
|
140
|
+
const initialResolvedTags = (0, import_core2.resolveTags)(
|
|
141
|
+
{ tags, additionalTags },
|
|
142
|
+
initialResolvedPath
|
|
143
|
+
);
|
|
144
|
+
const initialQueryKey = stateManager.createQueryKey({
|
|
145
|
+
path: initialCapturedCall.path,
|
|
146
|
+
method: initialCapturedCall.method,
|
|
147
|
+
options: initialCapturedCall.options
|
|
148
|
+
});
|
|
149
|
+
createController(
|
|
150
|
+
initialCapturedCall,
|
|
151
|
+
initialResolvedPath,
|
|
152
|
+
initialResolvedTags,
|
|
153
|
+
initialQueryKey
|
|
154
|
+
);
|
|
155
|
+
loadingSignal.set(false);
|
|
90
156
|
let wasEnabled = false;
|
|
91
157
|
(0, import_core.effect)(
|
|
92
158
|
() => {
|
|
@@ -131,45 +197,20 @@ function createInjectRead(options) {
|
|
|
131
197
|
const enabledChanged = isEnabled !== wasEnabled;
|
|
132
198
|
wasEnabled = isEnabled;
|
|
133
199
|
if (queryKeyChanged) {
|
|
134
|
-
if (currentController
|
|
200
|
+
if (currentController) {
|
|
135
201
|
prevContext = currentController.getContext();
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
const controller = (0, import_core2.createOperationController)({
|
|
141
|
-
operationType: "read",
|
|
142
|
-
path: capturedCall.path,
|
|
143
|
-
method: capturedCall.method,
|
|
144
|
-
tags: resolvedTags,
|
|
145
|
-
requestOptions: capturedCall.options,
|
|
146
|
-
stateManager,
|
|
147
|
-
eventEmitter,
|
|
148
|
-
pluginExecutor,
|
|
149
|
-
hookId: `angular-${Math.random().toString(36).slice(2)}`,
|
|
150
|
-
fetchFn: async (fetchOpts) => {
|
|
151
|
-
let current = api;
|
|
152
|
-
for (const segment of resolvedPath) {
|
|
153
|
-
current = current[segment];
|
|
154
|
-
}
|
|
155
|
-
const method = current[capturedCall.method];
|
|
156
|
-
return method(fetchOpts);
|
|
202
|
+
if (isMounted) {
|
|
203
|
+
currentController.unmount();
|
|
204
|
+
isMounted = false;
|
|
157
205
|
}
|
|
158
|
-
}
|
|
159
|
-
controller
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
metaSignal.set(newMeta);
|
|
167
|
-
});
|
|
168
|
-
currentController = controller;
|
|
169
|
-
currentQueryKey = queryKey;
|
|
170
|
-
if (!initialized) {
|
|
171
|
-
initialized = true;
|
|
172
|
-
} else if (prevContext) {
|
|
206
|
+
}
|
|
207
|
+
const controller = createController(
|
|
208
|
+
capturedCall,
|
|
209
|
+
resolvedPath,
|
|
210
|
+
resolvedTags,
|
|
211
|
+
queryKey
|
|
212
|
+
);
|
|
213
|
+
if (prevContext) {
|
|
173
214
|
controller.update(prevContext);
|
|
174
215
|
prevContext = null;
|
|
175
216
|
}
|
|
@@ -212,7 +253,7 @@ function createInjectRead(options) {
|
|
|
212
253
|
"invalidate",
|
|
213
254
|
(invalidatedTags) => {
|
|
214
255
|
const hasMatch = invalidatedTags.some(
|
|
215
|
-
(tag) =>
|
|
256
|
+
(tag) => currentResolvedTags.includes(tag)
|
|
216
257
|
);
|
|
217
258
|
if (hasMatch && currentController) {
|
|
218
259
|
(0, import_core.untracked)(() => {
|
|
@@ -241,6 +282,10 @@ function createInjectRead(options) {
|
|
|
241
282
|
};
|
|
242
283
|
const refetch = () => {
|
|
243
284
|
if (currentController) {
|
|
285
|
+
if (!isMounted) {
|
|
286
|
+
currentController.mount();
|
|
287
|
+
isMounted = true;
|
|
288
|
+
}
|
|
244
289
|
return executeWithTracking(currentController, true);
|
|
245
290
|
}
|
|
246
291
|
return Promise.resolve({ data: void 0, error: void 0 });
|
|
@@ -268,81 +313,104 @@ function createInjectWrite(options) {
|
|
|
268
313
|
const { api, stateManager, pluginExecutor, eventEmitter } = options;
|
|
269
314
|
return function injectWrite(writeFn) {
|
|
270
315
|
const destroyRef = (0, import_core3.inject)(import_core3.DestroyRef);
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
);
|
|
281
|
-
writeFn(selectorProxy);
|
|
282
|
-
const selectedEndpoint = selectorResult.selector;
|
|
283
|
-
if (!selectedEndpoint) {
|
|
284
|
-
throw new Error(
|
|
285
|
-
"injectWrite requires selecting an HTTP method ($post, $put, $patch, $delete). Example: injectWrite((api) => api.posts.$post)"
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
const queryKey = stateManager.createQueryKey({
|
|
289
|
-
path: selectedEndpoint.path,
|
|
290
|
-
method: selectedEndpoint.method,
|
|
291
|
-
options: void 0
|
|
292
|
-
});
|
|
293
|
-
const controller = (0, import_core4.createOperationController)({
|
|
294
|
-
operationType: "write",
|
|
295
|
-
path: selectedEndpoint.path,
|
|
296
|
-
method: selectedEndpoint.method,
|
|
297
|
-
tags: [],
|
|
298
|
-
stateManager,
|
|
299
|
-
eventEmitter,
|
|
300
|
-
pluginExecutor,
|
|
301
|
-
hookId: `angular-${Math.random().toString(36).slice(2)}`,
|
|
302
|
-
fetchFn: async (fetchOpts) => {
|
|
303
|
-
const params = fetchOpts?.params;
|
|
304
|
-
const resolvedPath = (0, import_core4.resolvePath)(selectedEndpoint.path, params);
|
|
305
|
-
let current = api;
|
|
306
|
-
for (const segment of resolvedPath) {
|
|
307
|
-
current = current[segment];
|
|
316
|
+
const captureSelector = () => {
|
|
317
|
+
const selectorResult = {
|
|
318
|
+
call: null,
|
|
319
|
+
selector: null
|
|
320
|
+
};
|
|
321
|
+
const selectorProxy = (0, import_core4.createSelectorProxy)(
|
|
322
|
+
(result2) => {
|
|
323
|
+
selectorResult.call = result2.call;
|
|
324
|
+
selectorResult.selector = result2.selector;
|
|
308
325
|
}
|
|
309
|
-
|
|
310
|
-
|
|
326
|
+
);
|
|
327
|
+
writeFn(selectorProxy);
|
|
328
|
+
if (!selectorResult.selector) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
"injectWrite requires selecting an HTTP method ($post, $put, $patch, $delete). Example: injectWrite((api) => api.posts.$post)"
|
|
331
|
+
);
|
|
311
332
|
}
|
|
312
|
-
|
|
333
|
+
return selectorResult.selector;
|
|
334
|
+
};
|
|
335
|
+
const hookId = `angular-${Math.random().toString(36).slice(2)}`;
|
|
336
|
+
let currentQueryKey = null;
|
|
337
|
+
let currentController = null;
|
|
338
|
+
let currentSubscription = null;
|
|
313
339
|
const dataSignal = (0, import_core3.signal)(void 0);
|
|
314
340
|
const errorSignal = (0, import_core3.signal)(void 0);
|
|
315
341
|
const loadingSignal = (0, import_core3.signal)(false);
|
|
316
342
|
const lastTriggerOptionsSignal = (0, import_core3.signal)(void 0);
|
|
317
343
|
const metaSignal = (0, import_core3.signal)({});
|
|
318
|
-
const subscription = controller.subscribe(() => {
|
|
319
|
-
const state = controller.getState();
|
|
320
|
-
dataSignal.set(state.data);
|
|
321
|
-
errorSignal.set(state.error);
|
|
322
|
-
const entry = stateManager.getCache(queryKey);
|
|
323
|
-
const newMeta = entry?.pluginResult ? Object.fromEntries(entry.pluginResult) : {};
|
|
324
|
-
metaSignal.set(newMeta);
|
|
325
|
-
});
|
|
326
344
|
destroyRef.onDestroy(() => {
|
|
327
|
-
|
|
345
|
+
if (currentSubscription) {
|
|
346
|
+
currentSubscription();
|
|
347
|
+
}
|
|
328
348
|
});
|
|
329
349
|
const reset = () => {
|
|
330
|
-
|
|
350
|
+
if (currentQueryKey) {
|
|
351
|
+
stateManager.deleteCache(currentQueryKey);
|
|
352
|
+
}
|
|
353
|
+
dataSignal.set(void 0);
|
|
331
354
|
errorSignal.set(void 0);
|
|
332
355
|
loadingSignal.set(false);
|
|
333
356
|
};
|
|
334
357
|
const abort = () => {
|
|
335
|
-
|
|
358
|
+
currentController?.abort();
|
|
336
359
|
};
|
|
337
360
|
const trigger = async (triggerOptions) => {
|
|
338
|
-
|
|
339
|
-
loadingSignal.set(true);
|
|
361
|
+
const selectedEndpoint = captureSelector();
|
|
340
362
|
const params = triggerOptions?.params;
|
|
341
363
|
const resolvedPath = (0, import_core4.resolvePath)(selectedEndpoint.path, params);
|
|
342
364
|
const tags = (0, import_core4.resolveTags)(triggerOptions, resolvedPath);
|
|
343
|
-
|
|
365
|
+
const queryKey = stateManager.createQueryKey({
|
|
366
|
+
path: selectedEndpoint.path,
|
|
367
|
+
method: selectedEndpoint.method,
|
|
368
|
+
options: triggerOptions
|
|
369
|
+
});
|
|
370
|
+
const needsNewController = !currentController || currentQueryKey !== queryKey;
|
|
371
|
+
if (needsNewController) {
|
|
372
|
+
if (currentSubscription) {
|
|
373
|
+
currentSubscription();
|
|
374
|
+
}
|
|
375
|
+
const controller = (0, import_core4.createOperationController)({
|
|
376
|
+
operationType: "write",
|
|
377
|
+
path: selectedEndpoint.path,
|
|
378
|
+
method: selectedEndpoint.method,
|
|
379
|
+
tags,
|
|
380
|
+
stateManager,
|
|
381
|
+
eventEmitter,
|
|
382
|
+
pluginExecutor,
|
|
383
|
+
hookId,
|
|
384
|
+
fetchFn: async (fetchOpts) => {
|
|
385
|
+
const fetchParams = fetchOpts?.params;
|
|
386
|
+
const fetchResolvedPath = (0, import_core4.resolvePath)(
|
|
387
|
+
selectedEndpoint.path,
|
|
388
|
+
fetchParams
|
|
389
|
+
);
|
|
390
|
+
let current = api;
|
|
391
|
+
for (const segment of fetchResolvedPath) {
|
|
392
|
+
current = current[segment];
|
|
393
|
+
}
|
|
394
|
+
const method = current[selectedEndpoint.method];
|
|
395
|
+
return method(fetchOpts);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
currentSubscription = controller.subscribe(() => {
|
|
399
|
+
const state = controller.getState();
|
|
400
|
+
dataSignal.set(state.data);
|
|
401
|
+
errorSignal.set(state.error);
|
|
402
|
+
const entry = stateManager.getCache(queryKey);
|
|
403
|
+
const newMeta = entry?.meta ? Object.fromEntries(entry.meta) : {};
|
|
404
|
+
metaSignal.set(newMeta);
|
|
405
|
+
});
|
|
406
|
+
currentController = controller;
|
|
407
|
+
currentQueryKey = queryKey;
|
|
408
|
+
}
|
|
409
|
+
lastTriggerOptionsSignal.set(triggerOptions);
|
|
410
|
+
loadingSignal.set(true);
|
|
411
|
+
currentController.setPluginOptions({ ...triggerOptions, tags });
|
|
344
412
|
try {
|
|
345
|
-
const response = await
|
|
413
|
+
const response = await currentController.execute(triggerOptions, {
|
|
346
414
|
force: true
|
|
347
415
|
});
|
|
348
416
|
if (response.error) {
|
|
@@ -419,70 +487,26 @@ function createInjectInfiniteRead(options) {
|
|
|
419
487
|
prevPageRequest,
|
|
420
488
|
merger
|
|
421
489
|
};
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
);
|
|
432
|
-
readFn(selectorProxy);
|
|
433
|
-
const capturedCall = selectorResult.call;
|
|
434
|
-
if (!capturedCall) {
|
|
435
|
-
throw new Error(
|
|
436
|
-
"injectInfiniteRead requires calling an HTTP method ($get). Example: injectInfiniteRead((api) => api.posts.$get())"
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
const requestOptions = capturedCall.options;
|
|
440
|
-
const initialRequest = {
|
|
441
|
-
query: requestOptions?.query,
|
|
442
|
-
params: requestOptions?.params,
|
|
443
|
-
body: requestOptions?.body
|
|
444
|
-
};
|
|
445
|
-
const baseOptionsForKey = {
|
|
446
|
-
...capturedCall.options,
|
|
447
|
-
query: void 0,
|
|
448
|
-
params: void 0,
|
|
449
|
-
body: void 0
|
|
450
|
-
};
|
|
451
|
-
const resolvedPath = (0, import_core6.resolvePath)(capturedCall.path, requestOptions?.params);
|
|
452
|
-
const resolvedTags = (0, import_core6.resolveTags)({ tags, additionalTags }, resolvedPath);
|
|
453
|
-
const controller = (0, import_core6.createInfiniteReadController)({
|
|
454
|
-
path: capturedCall.path,
|
|
455
|
-
method: capturedCall.method,
|
|
456
|
-
tags: resolvedTags,
|
|
457
|
-
initialRequest,
|
|
458
|
-
baseOptionsForKey,
|
|
459
|
-
canFetchNext: (ctx) => callbackRefs.canFetchNext(ctx),
|
|
460
|
-
canFetchPrev: canFetchPrev ? (ctx) => callbackRefs.canFetchPrev?.(ctx) ?? false : void 0,
|
|
461
|
-
nextPageRequest: (ctx) => callbackRefs.nextPageRequest(ctx),
|
|
462
|
-
prevPageRequest: prevPageRequest ? (ctx) => callbackRefs.prevPageRequest?.(ctx) ?? {} : void 0,
|
|
463
|
-
merger: (responses) => callbackRefs.merger(responses),
|
|
464
|
-
stateManager,
|
|
465
|
-
eventEmitter,
|
|
466
|
-
pluginExecutor,
|
|
467
|
-
hookId: `angular-${Math.random().toString(36).slice(2)}`,
|
|
468
|
-
fetchFn: async (opts, abortSignal) => {
|
|
469
|
-
const fetchPath = (0, import_core6.resolvePath)(capturedCall.path, opts.params);
|
|
470
|
-
let current = api;
|
|
471
|
-
for (const segment of fetchPath) {
|
|
472
|
-
current = current[segment];
|
|
490
|
+
const captureSelector = () => {
|
|
491
|
+
const selectorResult = {
|
|
492
|
+
call: null,
|
|
493
|
+
selector: null
|
|
494
|
+
};
|
|
495
|
+
const selectorProxy = (0, import_core6.createSelectorProxy)(
|
|
496
|
+
(result2) => {
|
|
497
|
+
selectorResult.call = result2.call;
|
|
498
|
+
selectorResult.selector = result2.selector;
|
|
473
499
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
signal: abortSignal
|
|
481
|
-
};
|
|
482
|
-
return method(fetchOptions);
|
|
500
|
+
);
|
|
501
|
+
readFn(selectorProxy);
|
|
502
|
+
if (!selectorResult.call) {
|
|
503
|
+
throw new Error(
|
|
504
|
+
"injectInfiniteRead requires calling an HTTP method ($get). Example: injectInfiniteRead((api) => api.posts.$get())"
|
|
505
|
+
);
|
|
483
506
|
}
|
|
484
|
-
|
|
485
|
-
|
|
507
|
+
return selectorResult.call;
|
|
508
|
+
};
|
|
509
|
+
const hookId = `angular-${Math.random().toString(36).slice(2)}`;
|
|
486
510
|
const dataSignal = (0, import_core5.signal)(void 0);
|
|
487
511
|
const allResponsesSignal = (0, import_core5.signal)(void 0);
|
|
488
512
|
const errorSignal = (0, import_core5.signal)(void 0);
|
|
@@ -490,29 +514,18 @@ function createInjectInfiniteRead(options) {
|
|
|
490
514
|
const canFetchNextSignal = (0, import_core5.signal)(false);
|
|
491
515
|
const canFetchPrevSignal = (0, import_core5.signal)(false);
|
|
492
516
|
const metaSignal = (0, import_core5.signal)({});
|
|
493
|
-
const queryKey = stateManager.createQueryKey({
|
|
494
|
-
path: capturedCall.path,
|
|
495
|
-
method: capturedCall.method,
|
|
496
|
-
options: baseOptionsForKey
|
|
497
|
-
});
|
|
498
|
-
const subscription = controller.subscribe(() => {
|
|
499
|
-
const state = controller.getState();
|
|
500
|
-
dataSignal.set(state.data);
|
|
501
|
-
allResponsesSignal.set(state.allResponses);
|
|
502
|
-
errorSignal.set(state.error);
|
|
503
|
-
canFetchNextSignal.set(state.canFetchNext);
|
|
504
|
-
canFetchPrevSignal.set(state.canFetchPrev);
|
|
505
|
-
const entry = stateManager.getCache(queryKey);
|
|
506
|
-
const newMeta = entry?.pluginResult ? Object.fromEntries(entry.pluginResult) : {};
|
|
507
|
-
metaSignal.set(newMeta);
|
|
508
|
-
});
|
|
509
517
|
const fetchingNextSignal = (0, import_core5.signal)(false);
|
|
510
518
|
const fetchingPrevSignal = (0, import_core5.signal)(false);
|
|
519
|
+
let currentController = null;
|
|
520
|
+
let currentQueryKey = null;
|
|
521
|
+
let currentSubscription = null;
|
|
522
|
+
let currentResolvedTags = [];
|
|
511
523
|
let prevContext = null;
|
|
512
|
-
let hasDoneInitialFetch = false;
|
|
513
524
|
let isMounted = false;
|
|
525
|
+
let unsubInvalidate = null;
|
|
514
526
|
const updateSignalsFromState = () => {
|
|
515
|
-
|
|
527
|
+
if (!currentController) return;
|
|
528
|
+
const state = currentController.getState();
|
|
516
529
|
dataSignal.set(state.data);
|
|
517
530
|
allResponsesSignal.set(state.allResponses);
|
|
518
531
|
errorSignal.set(state.error);
|
|
@@ -520,14 +533,15 @@ function createInjectInfiniteRead(options) {
|
|
|
520
533
|
canFetchPrevSignal.set(state.canFetchPrev);
|
|
521
534
|
};
|
|
522
535
|
const triggerFetch = () => {
|
|
523
|
-
|
|
536
|
+
if (!currentController) return;
|
|
537
|
+
const currentState = currentController.getState();
|
|
524
538
|
const isFetching = (0, import_core5.untracked)(
|
|
525
539
|
() => fetchingNextSignal() || fetchingPrevSignal()
|
|
526
540
|
);
|
|
527
541
|
if (currentState.data === void 0 && !isFetching) {
|
|
528
542
|
loadingSignal.set(true);
|
|
529
543
|
fetchingNextSignal.set(true);
|
|
530
|
-
|
|
544
|
+
currentController.fetchNext().finally(() => {
|
|
531
545
|
updateSignalsFromState();
|
|
532
546
|
loadingSignal.set(false);
|
|
533
547
|
fetchingNextSignal.set(false);
|
|
@@ -536,92 +550,230 @@ function createInjectInfiniteRead(options) {
|
|
|
536
550
|
updateSignalsFromState();
|
|
537
551
|
}
|
|
538
552
|
};
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
);
|
|
546
|
-
if (hasMatch) {
|
|
547
|
-
loadingSignal.set(true);
|
|
548
|
-
controller.refetch().finally(() => {
|
|
549
|
-
updateSignalsFromState();
|
|
550
|
-
loadingSignal.set(false);
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
+
const createController = (capturedCall, resolvedTags, queryKey) => {
|
|
554
|
+
if (currentSubscription) {
|
|
555
|
+
currentSubscription();
|
|
556
|
+
}
|
|
557
|
+
if (unsubInvalidate) {
|
|
558
|
+
unsubInvalidate();
|
|
553
559
|
}
|
|
560
|
+
const requestOptions = capturedCall.options;
|
|
561
|
+
const baseOptionsForKey = {
|
|
562
|
+
...capturedCall.options,
|
|
563
|
+
query: void 0,
|
|
564
|
+
params: void 0,
|
|
565
|
+
body: void 0
|
|
566
|
+
};
|
|
567
|
+
const initialRequest = {
|
|
568
|
+
query: requestOptions?.query,
|
|
569
|
+
params: requestOptions?.params,
|
|
570
|
+
body: requestOptions?.body
|
|
571
|
+
};
|
|
572
|
+
const controller = (0, import_core6.createInfiniteReadController)({
|
|
573
|
+
path: capturedCall.path,
|
|
574
|
+
method: capturedCall.method,
|
|
575
|
+
tags: resolvedTags,
|
|
576
|
+
initialRequest,
|
|
577
|
+
baseOptionsForKey,
|
|
578
|
+
canFetchNext: (ctx) => callbackRefs.canFetchNext(ctx),
|
|
579
|
+
canFetchPrev: canFetchPrev ? (ctx) => callbackRefs.canFetchPrev?.(ctx) ?? false : void 0,
|
|
580
|
+
nextPageRequest: (ctx) => callbackRefs.nextPageRequest(ctx),
|
|
581
|
+
prevPageRequest: prevPageRequest ? (ctx) => callbackRefs.prevPageRequest?.(ctx) ?? {} : void 0,
|
|
582
|
+
merger: (responses) => callbackRefs.merger(responses),
|
|
583
|
+
stateManager,
|
|
584
|
+
eventEmitter,
|
|
585
|
+
pluginExecutor,
|
|
586
|
+
hookId,
|
|
587
|
+
fetchFn: async (opts, abortSignal) => {
|
|
588
|
+
const fetchPath = (0, import_core6.resolvePath)(capturedCall.path, opts.params);
|
|
589
|
+
let current = api;
|
|
590
|
+
for (const segment of fetchPath) {
|
|
591
|
+
current = current[segment];
|
|
592
|
+
}
|
|
593
|
+
const method = current[capturedCall.method];
|
|
594
|
+
const fetchOptions = {
|
|
595
|
+
...capturedCall.options,
|
|
596
|
+
query: opts.query,
|
|
597
|
+
params: opts.params,
|
|
598
|
+
body: opts.body,
|
|
599
|
+
signal: abortSignal
|
|
600
|
+
};
|
|
601
|
+
return method(fetchOptions);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
controller.setPluginOptions(pluginOpts);
|
|
605
|
+
currentSubscription = controller.subscribe(() => {
|
|
606
|
+
const state = controller.getState();
|
|
607
|
+
dataSignal.set(state.data);
|
|
608
|
+
allResponsesSignal.set(state.allResponses);
|
|
609
|
+
errorSignal.set(state.error);
|
|
610
|
+
canFetchNextSignal.set(state.canFetchNext);
|
|
611
|
+
canFetchPrevSignal.set(state.canFetchPrev);
|
|
612
|
+
const entry = stateManager.getCache(queryKey);
|
|
613
|
+
const newMeta = entry?.meta ? Object.fromEntries(entry.meta) : {};
|
|
614
|
+
metaSignal.set(newMeta);
|
|
615
|
+
});
|
|
616
|
+
currentController = controller;
|
|
617
|
+
currentQueryKey = queryKey;
|
|
618
|
+
currentResolvedTags = resolvedTags;
|
|
619
|
+
unsubInvalidate = eventEmitter.on(
|
|
620
|
+
"invalidate",
|
|
621
|
+
(invalidatedTags) => {
|
|
622
|
+
if (!getEnabled() || !currentController) return;
|
|
623
|
+
const hasMatch = invalidatedTags.some(
|
|
624
|
+
(tag) => currentResolvedTags.includes(tag)
|
|
625
|
+
);
|
|
626
|
+
if (hasMatch) {
|
|
627
|
+
loadingSignal.set(true);
|
|
628
|
+
currentController.refetch().finally(() => {
|
|
629
|
+
updateSignalsFromState();
|
|
630
|
+
loadingSignal.set(false);
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
return controller;
|
|
636
|
+
};
|
|
637
|
+
const initialCapturedCall = captureSelector();
|
|
638
|
+
const initialRequestOptions = initialCapturedCall.options;
|
|
639
|
+
const initialResolvedPath = (0, import_core6.resolvePath)(
|
|
640
|
+
initialCapturedCall.path,
|
|
641
|
+
initialRequestOptions?.params
|
|
642
|
+
);
|
|
643
|
+
const initialResolvedTags = (0, import_core6.resolveTags)(
|
|
644
|
+
{ tags, additionalTags },
|
|
645
|
+
initialResolvedPath
|
|
554
646
|
);
|
|
647
|
+
const initialBaseOptionsForKey = {
|
|
648
|
+
...initialCapturedCall.options,
|
|
649
|
+
query: void 0,
|
|
650
|
+
params: void 0,
|
|
651
|
+
body: void 0
|
|
652
|
+
};
|
|
653
|
+
const initialQueryKey = stateManager.createQueryKey({
|
|
654
|
+
path: initialCapturedCall.path,
|
|
655
|
+
method: initialCapturedCall.method,
|
|
656
|
+
options: initialBaseOptionsForKey
|
|
657
|
+
});
|
|
658
|
+
createController(initialCapturedCall, initialResolvedTags, initialQueryKey);
|
|
555
659
|
(0, import_core5.effect)(
|
|
556
660
|
() => {
|
|
557
661
|
const isEnabled = getEnabled();
|
|
662
|
+
const capturedCall = captureSelector();
|
|
663
|
+
const requestOptions = capturedCall.options;
|
|
664
|
+
const resolvedPath = (0, import_core6.resolvePath)(
|
|
665
|
+
capturedCall.path,
|
|
666
|
+
requestOptions?.params
|
|
667
|
+
);
|
|
668
|
+
const resolvedTags = (0, import_core6.resolveTags)(
|
|
669
|
+
{ tags, additionalTags },
|
|
670
|
+
resolvedPath
|
|
671
|
+
);
|
|
672
|
+
const baseOptionsForKey = {
|
|
673
|
+
...capturedCall.options,
|
|
674
|
+
query: void 0,
|
|
675
|
+
params: void 0,
|
|
676
|
+
body: void 0
|
|
677
|
+
};
|
|
678
|
+
const queryKey = stateManager.createQueryKey({
|
|
679
|
+
path: capturedCall.path,
|
|
680
|
+
method: capturedCall.method,
|
|
681
|
+
options: baseOptionsForKey
|
|
682
|
+
});
|
|
683
|
+
const queryKeyChanged = queryKey !== currentQueryKey;
|
|
558
684
|
if (!isEnabled) {
|
|
559
|
-
if (isMounted) {
|
|
560
|
-
|
|
685
|
+
if (isMounted && currentController) {
|
|
686
|
+
currentController.unmount();
|
|
561
687
|
isMounted = false;
|
|
562
688
|
}
|
|
689
|
+
loadingSignal.set(false);
|
|
563
690
|
return;
|
|
564
691
|
}
|
|
565
|
-
if (
|
|
692
|
+
if (queryKeyChanged) {
|
|
693
|
+
if (currentController && isMounted) {
|
|
694
|
+
prevContext = currentController.getContext();
|
|
695
|
+
currentController.unmount();
|
|
696
|
+
isMounted = false;
|
|
697
|
+
}
|
|
698
|
+
const controller = createController(
|
|
699
|
+
capturedCall,
|
|
700
|
+
resolvedTags,
|
|
701
|
+
queryKey
|
|
702
|
+
);
|
|
703
|
+
if (prevContext) {
|
|
704
|
+
controller.update(prevContext);
|
|
705
|
+
prevContext = null;
|
|
706
|
+
}
|
|
566
707
|
controller.mount();
|
|
567
708
|
isMounted = true;
|
|
568
|
-
}
|
|
569
|
-
if (!hasDoneInitialFetch) {
|
|
570
|
-
hasDoneInitialFetch = true;
|
|
571
709
|
(0, import_core5.untracked)(() => {
|
|
572
710
|
triggerFetch();
|
|
573
711
|
});
|
|
574
|
-
}
|
|
575
|
-
|
|
712
|
+
} else if (!isMounted && currentController) {
|
|
713
|
+
currentController.mount();
|
|
714
|
+
isMounted = true;
|
|
576
715
|
(0, import_core5.untracked)(() => {
|
|
577
|
-
|
|
578
|
-
prevContext = null;
|
|
716
|
+
triggerFetch();
|
|
579
717
|
});
|
|
580
718
|
}
|
|
581
719
|
},
|
|
582
720
|
{ allowSignalWrites: true }
|
|
583
721
|
);
|
|
584
722
|
destroyRef.onDestroy(() => {
|
|
585
|
-
unsubInvalidate
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
723
|
+
if (unsubInvalidate) {
|
|
724
|
+
unsubInvalidate();
|
|
725
|
+
}
|
|
726
|
+
if (currentSubscription) {
|
|
727
|
+
currentSubscription();
|
|
728
|
+
}
|
|
729
|
+
if (currentController && isMounted) {
|
|
730
|
+
currentController.unmount();
|
|
591
731
|
}
|
|
592
732
|
});
|
|
593
733
|
const fetchNext = async () => {
|
|
594
|
-
if (!
|
|
734
|
+
if (!currentController) return;
|
|
735
|
+
if (!isMounted) {
|
|
736
|
+
currentController.mount();
|
|
737
|
+
isMounted = true;
|
|
738
|
+
}
|
|
595
739
|
fetchingNextSignal.set(true);
|
|
596
740
|
try {
|
|
597
|
-
await
|
|
741
|
+
await currentController.fetchNext();
|
|
598
742
|
updateSignalsFromState();
|
|
599
743
|
} finally {
|
|
600
744
|
fetchingNextSignal.set(false);
|
|
601
745
|
}
|
|
602
746
|
};
|
|
603
747
|
const fetchPrev = async () => {
|
|
604
|
-
if (!
|
|
748
|
+
if (!currentController) return;
|
|
749
|
+
if (!isMounted) {
|
|
750
|
+
currentController.mount();
|
|
751
|
+
isMounted = true;
|
|
752
|
+
}
|
|
605
753
|
fetchingPrevSignal.set(true);
|
|
606
754
|
try {
|
|
607
|
-
await
|
|
755
|
+
await currentController.fetchPrev();
|
|
608
756
|
updateSignalsFromState();
|
|
609
757
|
} finally {
|
|
610
758
|
fetchingPrevSignal.set(false);
|
|
611
759
|
}
|
|
612
760
|
};
|
|
613
761
|
const refetch = async () => {
|
|
614
|
-
if (!
|
|
762
|
+
if (!currentController) return;
|
|
763
|
+
if (!isMounted) {
|
|
764
|
+
currentController.mount();
|
|
765
|
+
isMounted = true;
|
|
766
|
+
}
|
|
615
767
|
loadingSignal.set(true);
|
|
616
768
|
try {
|
|
617
|
-
await
|
|
769
|
+
await currentController.refetch();
|
|
618
770
|
updateSignalsFromState();
|
|
619
771
|
} finally {
|
|
620
772
|
loadingSignal.set(false);
|
|
621
773
|
}
|
|
622
774
|
};
|
|
623
775
|
const abort = () => {
|
|
624
|
-
|
|
776
|
+
currentController?.abort();
|
|
625
777
|
};
|
|
626
778
|
const fetchingSignal = (0, import_core5.computed)(
|
|
627
779
|
() => fetchingNextSignal() || fetchingPrevSignal()
|