@spoosh/angular 0.1.3 → 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.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 && initialized) {
185
+ if (currentController) {
120
186
  prevContext = currentController.getContext();
121
- }
122
- if (currentSubscription) {
123
- currentSubscription();
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.setPluginOptions(pluginOpts);
145
- currentSubscription = controller.subscribe(() => {
146
- const state = controller.getState();
147
- dataSignal.set(state.data);
148
- errorSignal.set(state.error);
149
- const entry = stateManager.getCache(queryKey);
150
- const newMeta = entry?.pluginResult ? Object.fromEntries(entry.pluginResult) : {};
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) => resolvedTags.includes(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 selectorResult = {
262
- call: null,
263
- selector: null
264
- };
265
- const selectorProxy = createSelectorProxy2(
266
- (result2) => {
267
- selectorResult.call = result2.call;
268
- selectorResult.selector = result2.selector;
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
- const method = current[selectedEndpoint.method];
300
- return method(fetchOpts);
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
- subscription();
335
+ if (currentSubscription) {
336
+ currentSubscription();
337
+ }
318
338
  });
319
339
  const reset = () => {
320
- stateManager.deleteCache(queryKey);
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
- controller.abort();
348
+ currentController?.abort();
326
349
  };
327
350
  const trigger = async (triggerOptions) => {
328
- lastTriggerOptionsSignal.set(triggerOptions);
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
- controller.setPluginOptions({ ...triggerOptions, tags });
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 controller.execute(triggerOptions, {
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 selectorResult = {
425
- call: null,
426
- selector: null
427
- };
428
- const selectorProxy = createSelectorProxy3(
429
- (result2) => {
430
- selectorResult.call = result2.call;
431
- selectorResult.selector = result2.selector;
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
- const method = current[capturedCall.method];
477
- const fetchOptions = {
478
- ...capturedCall.options,
479
- query: opts.query,
480
- params: opts.params,
481
- body: opts.body,
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
- controller.setPluginOptions(pluginOpts);
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
- const state = controller.getState();
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
- const currentState = controller.getState();
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
- controller.fetchNext().finally(() => {
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 unsubInvalidate = eventEmitter.on(
542
- "invalidate",
543
- (invalidatedTags) => {
544
- if (!getEnabled()) return;
545
- const hasMatch = invalidatedTags.some(
546
- (tag) => resolvedTags.includes(tag)
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
- controller.unmount();
687
+ if (isMounted && currentController) {
688
+ currentController.unmount();
563
689
  isMounted = false;
564
690
  }
691
+ loadingSignal.set(false);
565
692
  return;
566
693
  }
567
- if (!isMounted) {
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
- if (prevContext) {
714
+ } else if (!isMounted && currentController) {
715
+ currentController.mount();
716
+ isMounted = true;
578
717
  untracked2(() => {
579
- controller.update(prevContext);
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
- destroyRef.onDestroy(() => {
590
- subscription();
591
- if (isMounted) {
592
- controller.unmount();
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 (!getEnabled()) return;
736
+ if (!currentController) return;
737
+ if (!isMounted) {
738
+ currentController.mount();
739
+ isMounted = true;
740
+ }
597
741
  fetchingNextSignal.set(true);
598
742
  try {
599
- await controller.fetchNext();
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 (!getEnabled()) return;
750
+ if (!currentController) return;
751
+ if (!isMounted) {
752
+ currentController.mount();
753
+ isMounted = true;
754
+ }
607
755
  fetchingPrevSignal.set(true);
608
756
  try {
609
- await controller.fetchPrev();
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 (!getEnabled()) return;
764
+ if (!currentController) return;
765
+ if (!isMounted) {
766
+ currentController.mount();
767
+ isMounted = true;
768
+ }
617
769
  loadingSignal.set(true);
618
770
  try {
619
- await controller.refetch();
771
+ await currentController.refetch();
620
772
  updateSignalsFromState();
621
773
  } finally {
622
774
  loadingSignal.set(false);
623
775
  }
624
776
  };
625
777
  const abort = () => {
626
- controller.abort();
778
+ currentController?.abort();
627
779
  };
628
780
  const fetchingSignal = computed(
629
781
  () => fetchingNextSignal() || fetchingPrevSignal()