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