@spoosh/react 0.15.0 → 0.15.2

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 CHANGED
@@ -71,6 +71,9 @@ type ExtractAllSubscriptionEvents<T> = SubscriptionReturnType<T> extends {
71
71
  type ExtractSubscriptionError<T> = SubscriptionReturnType<T> extends {
72
72
  error: infer E;
73
73
  } ? E : unknown;
74
+ type ExtractSubscriptionParamNames<T> = SubscriptionReturnType<T> extends {
75
+ params: infer P;
76
+ } ? P extends Record<infer K, string | number> ? K extends string ? K : never : never : never;
74
77
 
75
78
  /**
76
79
  * Base options for `useRead` hook.
@@ -476,7 +479,31 @@ interface UseSSEOptions extends UseSSEOptionsBase {
476
479
  /** Accumulate strategy for combining events. Defaults to 'replace'. */
477
480
  accumulate?: AccumulateStrategy | Record<string, AccumulateStrategy | AccumulatorFn>;
478
481
  }
479
- interface UseSSEResult<TEvents, TError> {
482
+ type SSEReturnType<T> = T extends (...args: never[]) => infer R ? R : never;
483
+ type ExtractSSETriggerQuery<R> = R extends {
484
+ query: infer Q;
485
+ } ? {
486
+ query?: Q;
487
+ } : unknown;
488
+ type ExtractSSETriggerBody<R> = R extends {
489
+ body: infer B;
490
+ } ? {
491
+ body?: B;
492
+ } : unknown;
493
+ type ExtractSSETriggerParams<R> = R extends {
494
+ params: infer P;
495
+ } ? {
496
+ params?: P;
497
+ } : unknown;
498
+ type SSETriggerOptionsFromFn<TSubFn> = SSEReturnType<TSubFn> extends infer R ? ExtractSSETriggerQuery<R> & ExtractSSETriggerBody<R> & ExtractSSETriggerParams<R> : object;
499
+ type SSETriggerOptions<TQuery, TBody, TParams> = (TQuery extends never ? unknown : {
500
+ query?: TQuery;
501
+ }) & (TBody extends never ? unknown : {
502
+ body?: TBody;
503
+ }) & (TParams extends never ? unknown : {
504
+ params?: TParams;
505
+ });
506
+ interface UseSSEResultBase<TEvents, TError> {
480
507
  /** Accumulated data keyed by event type */
481
508
  data: Partial<TEvents> | undefined;
482
509
  /** Connection or parse error */
@@ -487,19 +514,18 @@ interface UseSSEResult<TEvents, TError> {
487
514
  loading: boolean;
488
515
  /** Plugin metadata */
489
516
  meta: Record<string, never>;
490
- /**
491
- * Manually trigger connection with optional body/query overrides
492
- * @param options - Optional body and query parameters
493
- */
494
- trigger: (options?: {
495
- body?: unknown;
496
- query?: unknown;
497
- }) => Promise<void>;
498
517
  /** Disconnect from the SSE endpoint */
499
518
  disconnect: () => void;
500
519
  /** Reset accumulated data */
501
520
  reset: () => void;
502
521
  }
522
+ type UseSSEResult<TEvents, TError, TSubFn> = UseSSEResultBase<TEvents, TError> & {
523
+ /**
524
+ * Manually trigger connection with optional body/query/params overrides
525
+ * @param options - Optional body, query, and params parameters
526
+ */
527
+ trigger: (options?: SSETriggerOptionsFromFn<TSubFn>) => Promise<void>;
528
+ };
503
529
 
504
530
  type InferError<T, TDefaultError> = unknown extends T ? TDefaultError : T;
505
531
  type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>;
@@ -535,13 +561,13 @@ type UseSSEFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
535
561
  }>;
536
562
  }, const TSelectedEvents extends readonly Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>[]>(subFn: TSubFn, sseOptions: TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>, TSelectedEvents> & {
537
563
  events: TSelectedEvents;
538
- }): UseSSEResult<FilteredEvents<InferSSEEvents<TSubFn>, TSelectedEvents>, InferError<ExtractMethodError<TSubFn>, TDefaultError>>;
564
+ }): UseSSEResult<FilteredEvents<InferSSEEvents<TSubFn>, TSelectedEvents>, InferError<ExtractMethodError<TSubFn>, TDefaultError>, TSubFn>;
539
565
  <TSubFn extends (api: SubscriptionApiClient<TSchema, TDefaultError>) => {
540
566
  _subscription: true;
541
567
  events: Record<string, {
542
568
  data: unknown;
543
569
  }>;
544
- }>(subFn: TSubFn, sseOptions?: Omit<TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>>, "events">): UseSSEResult<InferSSEEvents<TSubFn>, InferError<ExtractMethodError<TSubFn>, TDefaultError>>;
570
+ }>(subFn: TSubFn, sseOptions?: Omit<TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>>, "events">): UseSSEResult<InferSSEEvents<TSubFn>, InferError<ExtractMethodError<TSubFn>, TDefaultError>, TSubFn>;
545
571
  };
546
572
  /**
547
573
  * Base hooks that are always available.
@@ -737,4 +763,4 @@ type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[
737
763
  plugins: TPlugins;
738
764
  };
739
765
 
740
- export { type ApiClient, type BasePagesOptions, type BasePagesResult, type BaseReadOptions, type BaseReadResult, type BaseSubscriptionOptions, type BaseSubscriptionResult, type BaseWriteResult, type ExtractAllSubscriptionEventKeys, type ExtractAllSubscriptionEvents, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type ExtractSubscriptionBody, type ExtractSubscriptionError, type ExtractSubscriptionEvents, type ExtractSubscriptionQuery, type PagesApiClient, type PagesTriggerOptions, type PluginHooksConfig, type QueueApiClient, type QueueTriggerInput, type ReactOptionsMap, type ReadApiClient, type ResponseInputFields, type SpooshReactHooks, type SubscriptionApiClient, type SubscriptionTriggerInput, type TriggerOptions, type TypedAccumulateConfig, type TypedParseConfig, type TypedUseSSEOptions, type UsePagesResult, type UseQueueOptions, type UseQueueResult, type UseReadResult, type UseSSEOptions, type UseSSEOptionsBase, type UseSSEResult, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, type WriteTriggerInput, create };
766
+ export { type ApiClient, type BasePagesOptions, type BasePagesResult, type BaseReadOptions, type BaseReadResult, type BaseSubscriptionOptions, type BaseSubscriptionResult, type BaseWriteResult, type ExtractAllSubscriptionEventKeys, type ExtractAllSubscriptionEvents, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type ExtractSubscriptionBody, type ExtractSubscriptionError, type ExtractSubscriptionEvents, type ExtractSubscriptionParamNames, type ExtractSubscriptionQuery, type PagesApiClient, type PagesTriggerOptions, type PluginHooksConfig, type QueueApiClient, type QueueTriggerInput, type ReactOptionsMap, type ReadApiClient, type ResponseInputFields, type SSETriggerOptions, type SSETriggerOptionsFromFn, type SpooshReactHooks, type SubscriptionApiClient, type SubscriptionTriggerInput, type TriggerOptions, type TypedAccumulateConfig, type TypedParseConfig, type TypedUseSSEOptions, type UsePagesResult, type UseQueueOptions, type UseQueueResult, type UseReadResult, type UseSSEOptions, type UseSSEOptionsBase, type UseSSEResult, type UseSSEResultBase, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, type WriteTriggerInput, create };
package/dist/index.d.ts CHANGED
@@ -71,6 +71,9 @@ type ExtractAllSubscriptionEvents<T> = SubscriptionReturnType<T> extends {
71
71
  type ExtractSubscriptionError<T> = SubscriptionReturnType<T> extends {
72
72
  error: infer E;
73
73
  } ? E : unknown;
74
+ type ExtractSubscriptionParamNames<T> = SubscriptionReturnType<T> extends {
75
+ params: infer P;
76
+ } ? P extends Record<infer K, string | number> ? K extends string ? K : never : never : never;
74
77
 
75
78
  /**
76
79
  * Base options for `useRead` hook.
@@ -476,7 +479,31 @@ interface UseSSEOptions extends UseSSEOptionsBase {
476
479
  /** Accumulate strategy for combining events. Defaults to 'replace'. */
477
480
  accumulate?: AccumulateStrategy | Record<string, AccumulateStrategy | AccumulatorFn>;
478
481
  }
479
- interface UseSSEResult<TEvents, TError> {
482
+ type SSEReturnType<T> = T extends (...args: never[]) => infer R ? R : never;
483
+ type ExtractSSETriggerQuery<R> = R extends {
484
+ query: infer Q;
485
+ } ? {
486
+ query?: Q;
487
+ } : unknown;
488
+ type ExtractSSETriggerBody<R> = R extends {
489
+ body: infer B;
490
+ } ? {
491
+ body?: B;
492
+ } : unknown;
493
+ type ExtractSSETriggerParams<R> = R extends {
494
+ params: infer P;
495
+ } ? {
496
+ params?: P;
497
+ } : unknown;
498
+ type SSETriggerOptionsFromFn<TSubFn> = SSEReturnType<TSubFn> extends infer R ? ExtractSSETriggerQuery<R> & ExtractSSETriggerBody<R> & ExtractSSETriggerParams<R> : object;
499
+ type SSETriggerOptions<TQuery, TBody, TParams> = (TQuery extends never ? unknown : {
500
+ query?: TQuery;
501
+ }) & (TBody extends never ? unknown : {
502
+ body?: TBody;
503
+ }) & (TParams extends never ? unknown : {
504
+ params?: TParams;
505
+ });
506
+ interface UseSSEResultBase<TEvents, TError> {
480
507
  /** Accumulated data keyed by event type */
481
508
  data: Partial<TEvents> | undefined;
482
509
  /** Connection or parse error */
@@ -487,19 +514,18 @@ interface UseSSEResult<TEvents, TError> {
487
514
  loading: boolean;
488
515
  /** Plugin metadata */
489
516
  meta: Record<string, never>;
490
- /**
491
- * Manually trigger connection with optional body/query overrides
492
- * @param options - Optional body and query parameters
493
- */
494
- trigger: (options?: {
495
- body?: unknown;
496
- query?: unknown;
497
- }) => Promise<void>;
498
517
  /** Disconnect from the SSE endpoint */
499
518
  disconnect: () => void;
500
519
  /** Reset accumulated data */
501
520
  reset: () => void;
502
521
  }
522
+ type UseSSEResult<TEvents, TError, TSubFn> = UseSSEResultBase<TEvents, TError> & {
523
+ /**
524
+ * Manually trigger connection with optional body/query/params overrides
525
+ * @param options - Optional body, query, and params parameters
526
+ */
527
+ trigger: (options?: SSETriggerOptionsFromFn<TSubFn>) => Promise<void>;
528
+ };
503
529
 
504
530
  type InferError<T, TDefaultError> = unknown extends T ? TDefaultError : T;
505
531
  type WriteResolverContext<TSchema, TMethod, TDefaultError> = ResolverContext<TSchema, ExtractMethodData<TMethod>, InferError<ExtractMethodError<TMethod>, TDefaultError>, ExtractMethodQuery<TMethod>, ExtractMethodBody<TMethod>, ExtractResponseParamNames<TMethod> extends never ? never : Record<ExtractResponseParamNames<TMethod>, string | number>>;
@@ -535,13 +561,13 @@ type UseSSEFn<TDefaultError, TSchema, TPlugins extends PluginArray> = {
535
561
  }>;
536
562
  }, const TSelectedEvents extends readonly Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>[]>(subFn: TSubFn, sseOptions: TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>, TSelectedEvents> & {
537
563
  events: TSelectedEvents;
538
- }): UseSSEResult<FilteredEvents<InferSSEEvents<TSubFn>, TSelectedEvents>, InferError<ExtractMethodError<TSubFn>, TDefaultError>>;
564
+ }): UseSSEResult<FilteredEvents<InferSSEEvents<TSubFn>, TSelectedEvents>, InferError<ExtractMethodError<TSubFn>, TDefaultError>, TSubFn>;
539
565
  <TSubFn extends (api: SubscriptionApiClient<TSchema, TDefaultError>) => {
540
566
  _subscription: true;
541
567
  events: Record<string, {
542
568
  data: unknown;
543
569
  }>;
544
- }>(subFn: TSubFn, sseOptions?: Omit<TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>>, "events">): UseSSEResult<InferSSEEvents<TSubFn>, InferError<ExtractMethodError<TSubFn>, TDefaultError>>;
570
+ }>(subFn: TSubFn, sseOptions?: Omit<TypedUseSSEOptions<Extract<ExtractAllSubscriptionEventKeys<TSubFn>, string>, InferSSEEvents<TSubFn>>, "events">): UseSSEResult<InferSSEEvents<TSubFn>, InferError<ExtractMethodError<TSubFn>, TDefaultError>, TSubFn>;
545
571
  };
546
572
  /**
547
573
  * Base hooks that are always available.
@@ -737,4 +763,4 @@ type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[
737
763
  plugins: TPlugins;
738
764
  };
739
765
 
740
- export { type ApiClient, type BasePagesOptions, type BasePagesResult, type BaseReadOptions, type BaseReadResult, type BaseSubscriptionOptions, type BaseSubscriptionResult, type BaseWriteResult, type ExtractAllSubscriptionEventKeys, type ExtractAllSubscriptionEvents, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type ExtractSubscriptionBody, type ExtractSubscriptionError, type ExtractSubscriptionEvents, type ExtractSubscriptionQuery, type PagesApiClient, type PagesTriggerOptions, type PluginHooksConfig, type QueueApiClient, type QueueTriggerInput, type ReactOptionsMap, type ReadApiClient, type ResponseInputFields, type SpooshReactHooks, type SubscriptionApiClient, type SubscriptionTriggerInput, type TriggerOptions, type TypedAccumulateConfig, type TypedParseConfig, type TypedUseSSEOptions, type UsePagesResult, type UseQueueOptions, type UseQueueResult, type UseReadResult, type UseSSEOptions, type UseSSEOptionsBase, type UseSSEResult, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, type WriteTriggerInput, create };
766
+ export { type ApiClient, type BasePagesOptions, type BasePagesResult, type BaseReadOptions, type BaseReadResult, type BaseSubscriptionOptions, type BaseSubscriptionResult, type BaseWriteResult, type ExtractAllSubscriptionEventKeys, type ExtractAllSubscriptionEvents, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type ExtractSubscriptionBody, type ExtractSubscriptionError, type ExtractSubscriptionEvents, type ExtractSubscriptionParamNames, type ExtractSubscriptionQuery, type PagesApiClient, type PagesTriggerOptions, type PluginHooksConfig, type QueueApiClient, type QueueTriggerInput, type ReactOptionsMap, type ReadApiClient, type ResponseInputFields, type SSETriggerOptions, type SSETriggerOptionsFromFn, type SpooshReactHooks, type SubscriptionApiClient, type SubscriptionTriggerInput, type TriggerOptions, type TypedAccumulateConfig, type TypedParseConfig, type TypedUseSSEOptions, type UsePagesResult, type UseQueueOptions, type UseQueueResult, type UseReadResult, type UseSSEOptions, type UseSSEOptionsBase, type UseSSEResult, type UseSSEResultBase, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, type WriteTriggerInput, create };
package/dist/index.js CHANGED
@@ -553,8 +553,7 @@ function createUsePages(options) {
553
553
  (tag) => (0, import_core3.matchTags)(tag, invalidatePatterns)
554
554
  );
555
555
  if (hasMatch) {
556
- setIsPending(true);
557
- controller.trigger().finally(() => setIsPending(false));
556
+ controller.refetch();
558
557
  }
559
558
  }
560
559
  );
@@ -689,11 +688,9 @@ function createUseSubscription(options) {
689
688
  });
690
689
  const controllerRef = (0, import_react5.useRef)(null);
691
690
  const subscriptionVersionRef = (0, import_react5.useRef)(0);
692
- const getOrCreateController = (0, import_react5.useCallback)(() => {
693
- if (controllerRef.current) {
694
- return controllerRef.current;
695
- }
696
- const controller = (0, import_core5.createSubscriptionController)({
691
+ const queryKeyChanged = controllerRef.current && controllerRef.current.queryKey !== queryKey;
692
+ if (!controllerRef.current || queryKeyChanged) {
693
+ const controller2 = (0, import_core5.createSubscriptionController)({
697
694
  channel: capturedCall.path,
698
695
  baseAdapter: adapter,
699
696
  stateManager,
@@ -704,33 +701,18 @@ function createUseSubscription(options) {
704
701
  path: capturedCall.path,
705
702
  method: capturedCall.method
706
703
  });
707
- controllerRef.current = controller;
708
- return controller;
709
- }, [
710
- queryKey,
711
- adapter,
712
- operationType,
713
- capturedCall.path,
714
- capturedCall.method
715
- ]);
704
+ controllerRef.current = { controller: controller2, queryKey };
705
+ }
706
+ const controller = controllerRef.current.controller;
716
707
  const subscribe = (0, import_react5.useCallback)(
717
708
  (callback) => {
718
- const controller = getOrCreateController();
719
709
  return controller.subscribe(callback);
720
710
  },
721
- [getOrCreateController]
711
+ [controller]
722
712
  );
723
- const emptyStateRef = (0, import_react5.useRef)({
724
- data: void 0,
725
- error: void 0,
726
- isConnected: false
727
- });
728
713
  const getSnapshot = (0, import_react5.useCallback)(() => {
729
- if (!controllerRef.current) {
730
- return emptyStateRef.current;
731
- }
732
- return controllerRef.current.getState();
733
- }, []);
714
+ return controller.getState();
715
+ }, [controller]);
734
716
  const state = (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
735
717
  const [isPending, setIsPending] = (0, import_react5.useState)(enabled);
736
718
  (0, import_react5.useEffect)(() => {
@@ -738,14 +720,13 @@ function createUseSubscription(options) {
738
720
  return;
739
721
  }
740
722
  setIsPending(true);
741
- const controller = getOrCreateController();
742
723
  controller.mount();
743
724
  controller.subscribe();
744
725
  return () => {
745
726
  subscriptionVersionRef.current++;
746
727
  controller.unsubscribe();
747
728
  };
748
- }, [queryKey, enabled, getOrCreateController]);
729
+ }, [queryKey, enabled, controller]);
749
730
  (0, import_react5.useEffect)(() => {
750
731
  if (state.isConnected || state.data !== void 0 || state.error !== void 0) {
751
732
  setIsPending(false);
@@ -753,18 +734,15 @@ function createUseSubscription(options) {
753
734
  }, [state.isConnected, state.data, state.error]);
754
735
  const disconnect = (0, import_react5.useCallback)(() => {
755
736
  subscriptionVersionRef.current++;
756
- if (controllerRef.current) {
757
- controllerRef.current.unsubscribe();
758
- }
759
- }, []);
737
+ controller.unsubscribe();
738
+ }, [controller]);
760
739
  const trigger = (0, import_react5.useCallback)(async () => {
761
740
  setIsPending(true);
762
741
  subscriptionVersionRef.current++;
763
- const controller = getOrCreateController();
764
742
  controller.unsubscribe();
765
743
  controller.mount();
766
744
  await controller.subscribe();
767
- }, [getOrCreateController]);
745
+ }, [controller]);
768
746
  const loading = isPending;
769
747
  return {
770
748
  meta: {},
@@ -823,12 +801,19 @@ function createUseSSE(options) {
823
801
  if (!capturedCall) {
824
802
  throw new Error("useSSE requires calling a method");
825
803
  }
804
+ const requestOptions = capturedCall.options;
805
+ const resolvedPath = (0, import_core6.resolvePathString)(
806
+ capturedCall.path,
807
+ requestOptions?.params
808
+ );
809
+ const paramsKey = requestOptions?.params ? JSON.stringify(requestOptions.params) : "";
826
810
  const currentOptionsRef = (0, import_react6.useRef)(
827
811
  capturedCall.options
828
812
  );
813
+ currentOptionsRef.current = capturedCall.options;
829
814
  const adapter = (0, import_react6.useMemo)(
830
815
  () => transport.createSubscriptionAdapter({
831
- channel: capturedCall.path,
816
+ channel: resolvedPath,
832
817
  method: capturedCall.method,
833
818
  baseUrl: config.baseUrl,
834
819
  globalHeaders: config.defaultOptions.headers,
@@ -836,7 +821,7 @@ function createUseSSE(options) {
836
821
  eventEmitter,
837
822
  devtoolMeta: events ? { listenedEvents: events } : void 0
838
823
  }),
839
- [capturedCall.path, capturedCall.method]
824
+ [resolvedPath, capturedCall.method, paramsKey]
840
825
  );
841
826
  const [accumulatedData, setAccumulatedData] = (0, import_react6.useState)({});
842
827
  const eventSet = (0, import_react6.useMemo)(
@@ -929,6 +914,7 @@ function createUseSSE(options) {
929
914
  setAccumulatedData({});
930
915
  }, []);
931
916
  const trigger = (0, import_react6.useCallback)(
917
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
932
918
  async (opts) => {
933
919
  reset();
934
920
  const triggerOpts = {
package/dist/index.mjs CHANGED
@@ -565,8 +565,7 @@ function createUsePages(options) {
565
565
  (tag) => matchTags2(tag, invalidatePatterns)
566
566
  );
567
567
  if (hasMatch) {
568
- setIsPending(true);
569
- controller.trigger().finally(() => setIsPending(false));
568
+ controller.refetch();
570
569
  }
571
570
  }
572
571
  );
@@ -713,11 +712,9 @@ function createUseSubscription(options) {
713
712
  });
714
713
  const controllerRef = useRef5(null);
715
714
  const subscriptionVersionRef = useRef5(0);
716
- const getOrCreateController = useCallback4(() => {
717
- if (controllerRef.current) {
718
- return controllerRef.current;
719
- }
720
- const controller = createSubscriptionController({
715
+ const queryKeyChanged = controllerRef.current && controllerRef.current.queryKey !== queryKey;
716
+ if (!controllerRef.current || queryKeyChanged) {
717
+ const controller2 = createSubscriptionController({
721
718
  channel: capturedCall.path,
722
719
  baseAdapter: adapter,
723
720
  stateManager,
@@ -728,33 +725,18 @@ function createUseSubscription(options) {
728
725
  path: capturedCall.path,
729
726
  method: capturedCall.method
730
727
  });
731
- controllerRef.current = controller;
732
- return controller;
733
- }, [
734
- queryKey,
735
- adapter,
736
- operationType,
737
- capturedCall.path,
738
- capturedCall.method
739
- ]);
728
+ controllerRef.current = { controller: controller2, queryKey };
729
+ }
730
+ const controller = controllerRef.current.controller;
740
731
  const subscribe = useCallback4(
741
732
  (callback) => {
742
- const controller = getOrCreateController();
743
733
  return controller.subscribe(callback);
744
734
  },
745
- [getOrCreateController]
735
+ [controller]
746
736
  );
747
- const emptyStateRef = useRef5({
748
- data: void 0,
749
- error: void 0,
750
- isConnected: false
751
- });
752
737
  const getSnapshot = useCallback4(() => {
753
- if (!controllerRef.current) {
754
- return emptyStateRef.current;
755
- }
756
- return controllerRef.current.getState();
757
- }, []);
738
+ return controller.getState();
739
+ }, [controller]);
758
740
  const state = useSyncExternalStore5(subscribe, getSnapshot, getSnapshot);
759
741
  const [isPending, setIsPending] = useState4(enabled);
760
742
  useEffect4(() => {
@@ -762,14 +744,13 @@ function createUseSubscription(options) {
762
744
  return;
763
745
  }
764
746
  setIsPending(true);
765
- const controller = getOrCreateController();
766
747
  controller.mount();
767
748
  controller.subscribe();
768
749
  return () => {
769
750
  subscriptionVersionRef.current++;
770
751
  controller.unsubscribe();
771
752
  };
772
- }, [queryKey, enabled, getOrCreateController]);
753
+ }, [queryKey, enabled, controller]);
773
754
  useEffect4(() => {
774
755
  if (state.isConnected || state.data !== void 0 || state.error !== void 0) {
775
756
  setIsPending(false);
@@ -777,18 +758,15 @@ function createUseSubscription(options) {
777
758
  }, [state.isConnected, state.data, state.error]);
778
759
  const disconnect = useCallback4(() => {
779
760
  subscriptionVersionRef.current++;
780
- if (controllerRef.current) {
781
- controllerRef.current.unsubscribe();
782
- }
783
- }, []);
761
+ controller.unsubscribe();
762
+ }, [controller]);
784
763
  const trigger = useCallback4(async () => {
785
764
  setIsPending(true);
786
765
  subscriptionVersionRef.current++;
787
- const controller = getOrCreateController();
788
766
  controller.unsubscribe();
789
767
  controller.mount();
790
768
  await controller.subscribe();
791
- }, [getOrCreateController]);
769
+ }, [controller]);
792
770
  const loading = isPending;
793
771
  return {
794
772
  meta: {},
@@ -807,7 +785,7 @@ function createUseSubscription(options) {
807
785
 
808
786
  // src/useSSE/index.ts
809
787
  import { useState as useState5, useRef as useRef6, useEffect as useEffect5, useCallback as useCallback5, useMemo } from "react";
810
- import { createSelectorProxy as createSelectorProxy6 } from "@spoosh/core";
788
+ import { createSelectorProxy as createSelectorProxy6, resolvePathString } from "@spoosh/core";
811
789
  function isSSETransport(transport) {
812
790
  const t = transport;
813
791
  return typeof t.createSubscriptionAdapter === "function" && typeof t.utils?.resolveParser === "function" && typeof t.utils?.resolveAccumulator === "function";
@@ -847,12 +825,19 @@ function createUseSSE(options) {
847
825
  if (!capturedCall) {
848
826
  throw new Error("useSSE requires calling a method");
849
827
  }
828
+ const requestOptions = capturedCall.options;
829
+ const resolvedPath = resolvePathString(
830
+ capturedCall.path,
831
+ requestOptions?.params
832
+ );
833
+ const paramsKey = requestOptions?.params ? JSON.stringify(requestOptions.params) : "";
850
834
  const currentOptionsRef = useRef6(
851
835
  capturedCall.options
852
836
  );
837
+ currentOptionsRef.current = capturedCall.options;
853
838
  const adapter = useMemo(
854
839
  () => transport.createSubscriptionAdapter({
855
- channel: capturedCall.path,
840
+ channel: resolvedPath,
856
841
  method: capturedCall.method,
857
842
  baseUrl: config.baseUrl,
858
843
  globalHeaders: config.defaultOptions.headers,
@@ -860,7 +845,7 @@ function createUseSSE(options) {
860
845
  eventEmitter,
861
846
  devtoolMeta: events ? { listenedEvents: events } : void 0
862
847
  }),
863
- [capturedCall.path, capturedCall.method]
848
+ [resolvedPath, capturedCall.method, paramsKey]
864
849
  );
865
850
  const [accumulatedData, setAccumulatedData] = useState5({});
866
851
  const eventSet = useMemo(
@@ -953,6 +938,7 @@ function createUseSSE(options) {
953
938
  setAccumulatedData({});
954
939
  }, []);
955
940
  const trigger = useCallback5(
941
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
956
942
  async (opts) => {
957
943
  reset();
958
944
  const triggerOpts = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/react",
3
- "version": "0.15.0",
3
+ "version": "0.15.2",
4
4
  "license": "MIT",
5
5
  "description": "React hooks for Spoosh API toolkit",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "@spoosh/core": ">=0.18.0",
37
+ "@spoosh/core": ">=0.18.2",
38
38
  "@spoosh/transport-sse": ">=0.1.0",
39
39
  "react": "^18 || ^19"
40
40
  },
@@ -46,8 +46,8 @@
46
46
  "devDependencies": {
47
47
  "@testing-library/react": "^16.0.0",
48
48
  "jsdom": "^26.0.0",
49
- "@spoosh/core": "0.18.0",
50
- "@spoosh/transport-sse": "0.1.1",
49
+ "@spoosh/core": "0.18.2",
50
+ "@spoosh/transport-sse": "0.1.2",
51
51
  "@spoosh/test-utils": "0.3.0"
52
52
  },
53
53
  "scripts": {