@spoosh/core 0.15.1 → 0.17.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 CHANGED
@@ -51,10 +51,10 @@ type SpooshResponse<TData, TError, TRequestOptions = unknown, TQuery = never, TB
51
51
  * trigger({ body: urlencoded({ key: "value" }) });
52
52
  * ```
53
53
  */
54
- declare class SpooshBodyClass<T> {
55
- private __brand;
56
- }
57
- type SpooshBody<T = unknown> = SpooshBodyClass<T>;
54
+ declare const __spooshBodyBrand: unique symbol;
55
+ type SpooshBody<T = unknown> = {
56
+ readonly [__spooshBodyBrand]: T;
57
+ };
58
58
  declare function isSpooshBody(value: unknown): value is SpooshBody;
59
59
  declare function form<T>(value: T): SpooshBody<T>;
60
60
  declare function json<T>(value: T): SpooshBody<T>;
@@ -252,6 +252,7 @@ type StateManager = {
252
252
  declare function createStateManager(): StateManager;
253
253
 
254
254
  declare function createInitialState<TData, TError>(): OperationState<TData, TError>;
255
+ declare function generateSelfTagFromKey(key: string): string | undefined;
255
256
 
256
257
  /**
257
258
  * Devtool-related types for tracing and debugging.
@@ -412,6 +413,51 @@ interface RequestCompleteEvent {
412
413
  context: PluginContext;
413
414
  queryKey: string;
414
415
  }
416
+ /** Event emitted when a subscription starts connecting */
417
+ interface SubscriptionConnectEvent {
418
+ subscriptionId: string;
419
+ channel: string;
420
+ transport: string;
421
+ connectionUrl: string;
422
+ queryKey: string;
423
+ timestamp: number;
424
+ /** Event types being listened to. Empty or ["*"] means all events. */
425
+ listenedEvents?: string[];
426
+ }
427
+ /** Event emitted when a subscription successfully connects */
428
+ interface SubscriptionConnectedEvent {
429
+ subscriptionId: string;
430
+ timestamp: number;
431
+ }
432
+ /** Event emitted when a subscription receives a message */
433
+ interface SubscriptionMessageEvent {
434
+ subscriptionId: string;
435
+ messageId: string;
436
+ eventType: string;
437
+ rawData: unknown;
438
+ accumulatedData: Record<string, unknown>;
439
+ timestamp: number;
440
+ }
441
+ /** Event emitted when a subscription encounters an error */
442
+ interface SubscriptionErrorEvent {
443
+ subscriptionId: string;
444
+ error: Error;
445
+ retryCount: number;
446
+ timestamp: number;
447
+ }
448
+ /** Event emitted when a subscription disconnects */
449
+ interface SubscriptionDisconnectEvent {
450
+ subscriptionId: string;
451
+ reason: string;
452
+ timestamp: number;
453
+ }
454
+ /** Event emitted when hook-level accumulation updates data */
455
+ interface SubscriptionAccumulateEvent {
456
+ queryKey: string;
457
+ eventType: string;
458
+ accumulatedData: Record<string, unknown>;
459
+ timestamp: number;
460
+ }
415
461
  /**
416
462
  * Internal events used by core and devtools. Not for public use.
417
463
  * @internal
@@ -419,6 +465,12 @@ interface RequestCompleteEvent {
419
465
  interface DevtoolEvents {
420
466
  "spoosh:devtool-event": StandaloneEvent;
421
467
  "spoosh:request-complete": RequestCompleteEvent;
468
+ "spoosh:subscription:connect": SubscriptionConnectEvent;
469
+ "spoosh:subscription:connected": SubscriptionConnectedEvent;
470
+ "spoosh:subscription:message": SubscriptionMessageEvent;
471
+ "spoosh:subscription:error": SubscriptionErrorEvent;
472
+ "spoosh:subscription:disconnect": SubscriptionDisconnectEvent;
473
+ "spoosh:subscription:accumulate": SubscriptionAccumulateEvent;
422
474
  }
423
475
  /**
424
476
  * Event tracer API for standalone events not tied to a request lifecycle.
@@ -437,7 +489,42 @@ interface EventTracer {
437
489
  emit(msg: string, options?: EventOptions): void;
438
490
  }
439
491
 
440
- type OperationType = "read" | "write" | "pages" | "queue";
492
+ interface SpooshTransport<TOptions = unknown, TMessage = unknown> {
493
+ name: string;
494
+ operationType: OperationType;
495
+ connect(url: string, options?: TOptions): Promise<void>;
496
+ disconnect(): Promise<void>;
497
+ subscribe(channel: string, callback: (message: TMessage) => void): () => void;
498
+ send(channel: string, message: TMessage): Promise<void>;
499
+ isConnected(): boolean;
500
+ }
501
+ interface SpooshTransportRegistry {
502
+ }
503
+ type TransportName = keyof SpooshTransportRegistry;
504
+ interface SubscriptionContext<TData = unknown, TError = unknown> extends PluginContext {
505
+ channel: string;
506
+ message?: unknown;
507
+ onData?: (data: TData) => void;
508
+ onError?: (error: TError) => void;
509
+ onDisconnect?: () => void;
510
+ registerUnsubscribers?: (unsubscribers: Array<() => void>) => void;
511
+ }
512
+ interface SubscriptionAdapter<TData = unknown, TError = unknown> {
513
+ subscribe(context: SubscriptionContext<TData, TError>): Promise<SubscriptionHandle<TData, TError>>;
514
+ emit(context: SubscriptionContext<TData, TError>): Promise<{
515
+ success: boolean;
516
+ error?: TError;
517
+ }>;
518
+ }
519
+ interface SubscriptionHandle<TData = unknown, TError = unknown> {
520
+ unsubscribe(): void;
521
+ getData(): TData | undefined;
522
+ getError(): TError | undefined;
523
+ onData(callback: (data: TData) => void): () => void;
524
+ onError(callback: (error: TError) => void): () => void;
525
+ }
526
+
527
+ type OperationType = "read" | "write" | "pages" | "queue" | (string & {});
441
528
  type LifecyclePhase = "onMount" | "onUnmount" | "onUpdate";
442
529
  type OperationState<TData = unknown, TError = unknown> = {
443
530
  data: TData | undefined;
@@ -593,7 +680,7 @@ type PluginLifecycle = {
593
680
  *
594
681
  * // Plugin with instance-level API
595
682
  * SpooshPlugin<{
596
- * instanceApi: { prefetch: (selector: Selector) => Promise<void> };
683
+ * api: { prefetch: (selector: Selector) => Promise<void> };
597
684
  * }>
598
685
  * ```
599
686
  */
@@ -604,10 +691,13 @@ type PluginTypeConfig = {
604
691
  writeTriggerOptions?: object;
605
692
  queueOptions?: object;
606
693
  queueTriggerOptions?: object;
694
+ subscribeOptions?: object;
695
+ subscribeTriggerOptions?: object;
607
696
  readResult?: object;
608
697
  writeResult?: object;
609
698
  queueResult?: object;
610
- instanceApi?: object;
699
+ subscribeResult?: object;
700
+ api?: object;
611
701
  };
612
702
  /**
613
703
  * Base interface for Spoosh plugins.
@@ -616,7 +706,7 @@ type PluginTypeConfig = {
616
706
  * - `middleware`: Wraps the fetch flow for full control (intercept, transform, modify)
617
707
  * - `afterResponse`: Called after every response, regardless of early returns
618
708
  * - `lifecycle`: Component lifecycle hooks (onMount, onUpdate, onUnmount)
619
- * - `exports`: Functions/variables accessible to other plugins
709
+ * - `internal`: Functions/variables accessible to other plugins
620
710
  *
621
711
  * @typeParam T - Plugin type configuration object. Specify only the types your plugin needs.
622
712
  *
@@ -659,11 +749,11 @@ interface SpooshPlugin<T extends PluginTypeConfig = PluginTypeConfig> {
659
749
  /** Component lifecycle hooks (setup, cleanup, option changes) */
660
750
  lifecycle?: PluginLifecycle;
661
751
  /** Expose functions/variables for other plugins to access via `context.plugins.get(name)` */
662
- exports?: (context: PluginContext) => object;
752
+ internal?: (context: PluginContext) => object;
663
753
  /**
664
754
  * One-time initialization when the Spoosh instance is created.
665
755
  * Use for setting up timers, event listeners, or other side effects.
666
- * Runs before instanceApi is called.
756
+ * Runs before api is called.
667
757
  *
668
758
  * @example
669
759
  * ```ts
@@ -688,20 +778,36 @@ interface SpooshPlugin<T extends PluginTypeConfig = PluginTypeConfig> {
688
778
  setup?: (context: SetupContext) => void;
689
779
  /**
690
780
  * Expose functions/properties on the framework adapter return value (e.g., create).
691
- * Unlike `exports`, these are accessible directly from the instance, not just within plugin context.
781
+ * Unlike `internal`, these are accessible directly from the adapter, not just within plugin context.
692
782
  * Should be pure - use `setup` for side effects like timers or event listeners.
693
783
  *
694
784
  * @example
695
785
  * ```ts
696
- * instanceApi: ({ api, stateManager }) => ({
786
+ * api: ({ spopiosh, stateManager }) => ({
697
787
  * prefetch: async (selector) => { ... },
698
788
  * invalidateAll: () => { ... },
699
789
  * })
700
790
  * ```
701
791
  */
702
- instanceApi?: (context: InstanceApiContext) => T extends {
703
- instanceApi: infer A;
792
+ api?: (context: ApiContext) => T extends {
793
+ api: infer A;
704
794
  } ? A : object;
795
+ /**
796
+ * Wrap a subscription adapter to add plugin behavior (e.g., caching, retry, logging).
797
+ * Called for subscription operations to compose adapter functionality.
798
+ *
799
+ * @example
800
+ * ```ts
801
+ * wrapAdapter: (inner) => ({
802
+ * subscribe: async (ctx) => {
803
+ * // Add caching logic
804
+ * return inner.subscribe(ctx);
805
+ * },
806
+ * emit: inner.emit,
807
+ * })
808
+ * ```
809
+ */
810
+ wrapAdapter?: (inner: SubscriptionAdapter) => SubscriptionAdapter;
705
811
  /**
706
812
  * Plugin execution priority. Lower numbers run first, higher numbers run last.
707
813
  * Default: 0
@@ -834,7 +940,7 @@ interface PluginResolvers<TContext extends ResolverContext> {
834
940
  interface PluginResultResolvers<TOptions> {
835
941
  }
836
942
  /**
837
- * Registry for plugin exports. Extend via declaration merging for type-safe access.
943
+ * Registry for plugin internal APIs. Extend via declaration merging for type-safe access.
838
944
  *
839
945
  * Plugins can expose functions and variables that other plugins can access
840
946
  * via `context.plugins.get("plugin-name")`.
@@ -843,38 +949,38 @@ interface PluginResultResolvers<TOptions> {
843
949
  * ```ts
844
950
  * // In your plugin's types file:
845
951
  * declare module '@spoosh/core' {
846
- * interface PluginExportsRegistry {
952
+ * interface PluginInternalRegistry {
847
953
  * "my-plugin": { myMethod: () => void }
848
954
  * }
849
955
  * }
850
956
  * ```
851
957
  */
852
- interface PluginExportsRegistry {
958
+ interface PluginInternalRegistry {
853
959
  }
854
960
  /**
855
- * Registry for instance API type resolution. Extend via declaration merging.
961
+ * Registry for public API type resolution. Extend via declaration merging.
856
962
  *
857
- * Plugins that expose schema-aware instance APIs should extend this interface
963
+ * Plugins that expose schema-aware public APIs should extend this interface
858
964
  * to get proper type inference when the API is used.
859
965
  *
860
966
  * @example
861
967
  * ```ts
862
968
  * // In your plugin's types file:
863
969
  * declare module '@spoosh/core' {
864
- * interface InstanceApiResolvers<TSchema> {
970
+ * interface ApiResolvers<TSchema> {
865
971
  * myFunction: MyFn<TSchema>;
866
972
  * }
867
973
  * }
868
974
  * ```
869
975
  */
870
- interface InstanceApiResolvers<TSchema> {
976
+ interface ApiResolvers<TSchema> {
871
977
  }
872
978
  /**
873
- * Accessor for plugin exports with type-safe lookup.
979
+ * Accessor for plugin internal APIs with type-safe lookup.
874
980
  */
875
981
  type PluginAccessor = {
876
- /** Get a plugin's exported API by name. Returns undefined if plugin not found. */
877
- get<K extends keyof PluginExportsRegistry>(name: K): PluginExportsRegistry[K] | undefined;
982
+ /** Get a plugin's internal API by name. Returns undefined if plugin not found. */
983
+ get<K extends keyof PluginInternalRegistry>(name: K): PluginInternalRegistry[K] | undefined;
878
984
  get(name: string): unknown;
879
985
  };
880
986
  type RefetchEventReason = "focus" | "reconnect" | "polling" | "invalidate";
@@ -887,10 +993,10 @@ type RefetchEvent = {
887
993
  reason: RefetchEventReason | Omit<string, RefetchEventReason>;
888
994
  };
889
995
  /**
890
- * Minimal PluginExecutor interface for InstanceApiContext.
996
+ * Minimal PluginExecutor interface for ApiContext.
891
997
  * Avoids circular dependency with executor.ts.
892
998
  */
893
- type InstancePluginExecutor = {
999
+ type ApiPluginExecutor = {
894
1000
  executeMiddleware: <TData, TError>(operationType: OperationType, context: PluginContext, coreFetch: () => Promise<SpooshResponse<any, any>>) => Promise<SpooshResponse<TData, TError>>;
895
1001
  createContext: (input: PluginContextInput) => PluginContext;
896
1002
  getPlugins: () => readonly SpooshPlugin[];
@@ -901,14 +1007,14 @@ type InstancePluginExecutor = {
901
1007
  registerContextEnhancer: (enhancer: (context: PluginContext) => void) => void;
902
1008
  };
903
1009
  /**
904
- * Context provided to plugin's instanceApi function.
905
- * Used for creating framework-agnostic APIs exposed on the Spoosh instance.
1010
+ * Context provided to plugin's api function.
1011
+ * Used for creating framework-agnostic APIs exposed on the adapter.
906
1012
  */
907
- type InstanceApiContext<TApi = unknown> = {
908
- api: TApi;
1013
+ type ApiContext<TApi = unknown> = {
1014
+ spoosh: TApi;
909
1015
  stateManager: StateManager;
910
1016
  eventEmitter: EventEmitter;
911
- pluginExecutor: InstancePluginExecutor;
1017
+ pluginExecutor: ApiPluginExecutor;
912
1018
  /**
913
1019
  * Creates an event tracer for standalone events.
914
1020
  * Only available when devtools plugin is active.
@@ -922,7 +1028,7 @@ type InstanceApiContext<TApi = unknown> = {
922
1028
  type SetupContext = {
923
1029
  stateManager: StateManager;
924
1030
  eventEmitter: EventEmitter;
925
- pluginExecutor: InstancePluginExecutor;
1031
+ pluginExecutor: ApiPluginExecutor;
926
1032
  /**
927
1033
  * Creates an event tracer for standalone events.
928
1034
  * Only available when devtools plugin is active.
@@ -937,6 +1043,8 @@ type PluginExecutor = {
937
1043
  executeUpdateLifecycle: (operationType: OperationType, context: PluginContext, previousContext: PluginContext) => Promise<void>;
938
1044
  executeMiddleware: (operationType: OperationType, context: PluginContext, coreFetch: () => Promise<SpooshResponse<any, any>>) => Promise<SpooshResponse<any, any>>;
939
1045
  getPlugins: () => readonly SpooshPlugin[];
1046
+ /** Get plugins that support a specific operation type */
1047
+ getPluginsForOperation: (operationType: OperationType) => readonly SpooshPlugin[];
940
1048
  /** Creates a full PluginContext with plugins accessor */
941
1049
  createContext: (input: PluginContextInput) => PluginContext;
942
1050
  /**
@@ -1003,24 +1111,24 @@ type ResolveSchemaTypes<TOptions, TSchema> = ResolveTypes<TOptions, ResolverCont
1003
1111
  */
1004
1112
  type ResolveResultTypes<TResults, TOptions> = TResults & PluginResultResolvers<TOptions>;
1005
1113
  /**
1006
- * Resolves instance API types with schema awareness.
1007
- * Maps each key in TInstanceApi to its resolved type from resolvers.
1114
+ * Resolves public API types with schema awareness.
1115
+ * Maps each key in TApi to its resolved type from resolvers.
1008
1116
  *
1009
- * Plugins extend InstanceApiResolvers via declaration merging to add their own
1010
- * resolved instance API types.
1117
+ * Plugins extend ApiResolvers via declaration merging to add their own
1118
+ * resolved API types.
1011
1119
  *
1012
1120
  * @example
1013
1121
  * ```ts
1014
1122
  * // In your plugin's types.ts:
1015
1123
  * declare module "@spoosh/core" {
1016
- * interface InstanceApiResolvers<TSchema> {
1124
+ * interface ApiResolvers<TSchema> {
1017
1125
  * prefetch: PrefetchFn<TSchema>;
1018
1126
  * }
1019
1127
  * }
1020
1128
  * ```
1021
1129
  */
1022
- type ResolveInstanceApi<TInstanceApi, TSchema, TReadOptions = object> = {
1023
- [K in keyof TInstanceApi]: K extends keyof InstanceApiResolvers<TSchema> ? InstanceApiResolvers<TSchema>[K] : TInstanceApi[K];
1130
+ type ResolveApi<TApi, TSchema, TReadOptions = object> = {
1131
+ [K in keyof TApi]: K extends keyof ApiResolvers<TSchema> ? ApiResolvers<TSchema>[K] : TApi[K];
1024
1132
  };
1025
1133
 
1026
1134
  type ExtractReadOptions<T> = T extends SpooshPlugin<infer Types> ? Types extends {
@@ -1044,14 +1152,17 @@ type ExtractQueueTriggerOptions<T> = T extends SpooshPlugin<infer Types> ? Types
1044
1152
  type ExtractQueueResult<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1045
1153
  queueResult: infer Q;
1046
1154
  } ? Q : object : object;
1155
+ type ExtractSubscribeResult<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1156
+ subscribeResult: infer S;
1157
+ } ? S : object : object;
1047
1158
  type ExtractReadResult<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1048
1159
  readResult: infer R;
1049
1160
  } ? R : object : object;
1050
1161
  type ExtractWriteResult<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1051
1162
  writeResult: infer W;
1052
1163
  } ? W : object : object;
1053
- type ExtractInstanceApi<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1054
- instanceApi: infer A;
1164
+ type ExtractApi<T> = T extends SpooshPlugin<infer Types> ? Types extends {
1165
+ api: infer A;
1055
1166
  } ? A : object : object;
1056
1167
  type UnionToIntersection$1<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
1057
1168
  type MergePluginOptions<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
@@ -1066,18 +1177,29 @@ type MergePluginResults<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>
1066
1177
  read: UnionToIntersection$1<ExtractReadResult<TPlugins[number]>>;
1067
1178
  write: UnionToIntersection$1<ExtractWriteResult<TPlugins[number]>>;
1068
1179
  queue: UnionToIntersection$1<ExtractQueueResult<TPlugins[number]>>;
1180
+ subscribe: UnionToIntersection$1<ExtractSubscribeResult<TPlugins[number]>>;
1069
1181
  };
1070
- type MergePluginInstanceApi<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[], TSchema = unknown> = ResolveInstanceApi<UnionToIntersection$1<ExtractInstanceApi<TPlugins[number]>>, TSchema, MergePluginOptions<TPlugins>["read"]>;
1182
+ type MergePluginApi<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[], TSchema = unknown> = ResolveApi<UnionToIntersection$1<ExtractApi<TPlugins[number]>>, TSchema, MergePluginOptions<TPlugins>["read"]>;
1071
1183
  type PluginRegistry<TPlugins extends SpooshPlugin<PluginTypeConfig>[]> = {
1072
1184
  plugins: TPlugins;
1073
1185
  _options: MergePluginOptions<TPlugins>;
1074
1186
  };
1075
1187
  declare function createPluginRegistry<TPlugins extends SpooshPlugin<PluginTypeConfig>[]>(plugins: [...TPlugins]): PluginRegistry<TPlugins>;
1076
1188
 
1189
+ /**
1190
+ * Registry for subscription methods. Transports extend via module augmentation.
1191
+ */
1192
+ interface SpooshSubscriptionMethodRegistry {
1193
+ }
1194
+ type SubscriptionMethod = keyof SpooshSubscriptionMethodRegistry;
1195
+ type AnyMethod = HttpMethod | SubscriptionMethod;
1077
1196
  /**
1078
1197
  * An API schema where routes are defined as string keys with path patterns.
1079
1198
  * Define data, body, query, and error directly on each method.
1080
1199
  *
1200
+ * For subscription endpoints (SSE, WebSocket), define the `events` field instead of `data`.
1201
+ * The transport to use is determined by the hook (useSSE, useWebSocket), not the path.
1202
+ *
1081
1203
  * @example
1082
1204
  * ```ts
1083
1205
  * type ApiSchema = {
@@ -1090,22 +1212,69 @@ declare function createPluginRegistry<TPlugins extends SpooshPlugin<PluginTypeCo
1090
1212
  * PUT: { data: Post; body: UpdatePostBody };
1091
1213
  * DELETE: { data: void };
1092
1214
  * };
1093
- * "posts/:id/comments": {
1094
- * GET: { data: Comment[]; query: { page?: number } };
1215
+ * "notifications": {
1216
+ * GET: {
1217
+ * events: {
1218
+ * alert: { data: Alert };
1219
+ * message: { data: Message };
1220
+ * };
1221
+ * query?: { userId: string };
1222
+ * };
1095
1223
  * };
1096
1224
  * };
1097
1225
  * ```
1098
1226
  */
1227
+ /**
1228
+ * HTTP endpoint method config.
1229
+ */
1230
+ type HttpMethodConfig = {
1231
+ data?: unknown;
1232
+ body?: unknown;
1233
+ query?: unknown;
1234
+ error?: unknown;
1235
+ };
1236
+ /**
1237
+ * Subscription endpoint method config (SSE, WebSocket, etc.).
1238
+ * Has events field instead of data.
1239
+ */
1240
+ type SubscriptionMethodConfig = {
1241
+ events?: Record<string, {
1242
+ data: unknown;
1243
+ }>;
1244
+ body?: unknown;
1245
+ query?: unknown;
1246
+ error?: unknown;
1247
+ };
1248
+ /**
1249
+ * Endpoint config - supports both HTTP and subscription methods.
1250
+ * Subscription endpoints are those with an `events` field, HTTP endpoints have `data`.
1251
+ */
1252
+ type EndpointConfig = {
1253
+ [M in HttpMethod | SubscriptionMethod]?: HttpMethodConfig | SubscriptionMethodConfig;
1254
+ };
1255
+ /**
1256
+ * Base API schema type.
1257
+ */
1099
1258
  type ApiSchema = {
1100
1259
  [path: string]: {
1101
- [method in HttpMethod]?: {
1102
- data?: unknown;
1103
- body?: unknown;
1104
- query?: unknown;
1105
- error?: unknown;
1106
- };
1260
+ [method: string]: unknown;
1107
1261
  };
1108
1262
  };
1263
+ /**
1264
+ * Helper type for defining API schemas with proper autocomplete.
1265
+ * Use `events` field for subscription endpoints, `data` field for HTTP endpoints.
1266
+ *
1267
+ * @example
1268
+ * ```ts
1269
+ * type MyApi = SpooshSchema<{
1270
+ * "posts": { GET: { data: Post[] } };
1271
+ * "chat": { GET: { events: { message: { data: string } } } };
1272
+ * }>;
1273
+ * ```
1274
+ */
1275
+ type SpooshSchema<T extends {
1276
+ [K in keyof T]: EndpointConfig;
1277
+ }> = T;
1109
1278
  /**
1110
1279
  * Extract data type from an endpoint.
1111
1280
  */
@@ -1130,28 +1299,6 @@ type ExtractQuery$1<T> = T extends {
1130
1299
  type ExtractError<T, TDefault = unknown> = T extends {
1131
1300
  error: infer E;
1132
1301
  } ? E : TDefault;
1133
- /**
1134
- * Helper type to define a type-safe API schema.
1135
- * Use this to get type checking on your schema definition.
1136
- *
1137
- * @example
1138
- * ```ts
1139
- * type ApiSchema = SpooshSchema<{
1140
- * "posts": {
1141
- * GET: { data: Post[] };
1142
- * POST: { data: Post; body: CreatePostBody };
1143
- * };
1144
- * "posts/:id": {
1145
- * GET: { data: Post };
1146
- * PUT: { data: Post; body: UpdatePostBody };
1147
- * DELETE: { data: void };
1148
- * };
1149
- * }>;
1150
- *
1151
- * const api = createClient<ApiSchema>({ baseUrl: "/api" });
1152
- * ```
1153
- */
1154
- type SpooshSchema<T extends ApiSchema> = T;
1155
1302
  /**
1156
1303
  * Convert a route pattern like "posts/:id" to a path matcher pattern like `posts/${string}`.
1157
1304
  * This enables TypeScript to match actual paths like "posts/123" to their schema definitions.
@@ -1219,6 +1366,24 @@ type HasReadMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPa
1219
1366
  * Check if a schema path has any write methods.
1220
1367
  */
1221
1368
  type HasWriteMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? WriteMethod extends never ? false : Extract<keyof TSchema[TKey], WriteMethod> extends never ? false : true : false : false;
1369
+ /**
1370
+ * Extract paths that have methods with events (subscription endpoints).
1371
+ */
1372
+ type SubscriptionPaths<TSchema> = {
1373
+ [K in keyof TSchema & string]: {
1374
+ [M in keyof TSchema[K]]: TSchema[K][M] extends {
1375
+ events: unknown;
1376
+ } ? K : never;
1377
+ }[keyof TSchema[K]] extends never ? never : K;
1378
+ }[keyof TSchema & string];
1379
+ /**
1380
+ * Check if a schema path has any method with events field.
1381
+ */
1382
+ type HasSubscriptionMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? {
1383
+ [M in keyof TSchema[TKey]]: TSchema[TKey][M] extends {
1384
+ events: unknown;
1385
+ } ? true : never;
1386
+ }[keyof TSchema[TKey]] extends never ? false : true : false : false;
1222
1387
  type NormalizePrefix<T extends string> = T extends `/${infer Rest}` ? NormalizePrefix<Rest> : T extends `${infer Rest}/` ? NormalizePrefix<Rest> : T;
1223
1388
  type StripPrefixFromPath<TPath extends string, TPrefix extends string> = TPath extends TPrefix ? "" : TPath extends `${TPrefix}/${infer Rest}` ? Rest : TPath;
1224
1389
  /**
@@ -1560,6 +1725,79 @@ type QueueSelectorPathMethods<TSchema, TPath extends string, TDefaultError> = Fi
1560
1725
  * Used by useQueue for selecting endpoints. All input goes to trigger().
1561
1726
  */
1562
1727
  type QueueSelectorClient<TSchema, TDefaultError = unknown> = <TPath extends SchemaPaths<TSchema> | (string & {})>(path: TPath) => QueueSelectorPathMethods<TSchema, TPath, TDefaultError>;
1728
+ /**
1729
+ * Extract events type from a method config.
1730
+ */
1731
+ type ExtractEvents<T> = T extends {
1732
+ events: infer E;
1733
+ } ? E : never;
1734
+ /**
1735
+ * Transport-specific options for subscriptions.
1736
+ */
1737
+ type SubscriptionTransportOptions = {
1738
+ /** Keep connection alive when browser tab is hidden. Defaults to true. */
1739
+ openWhenHidden?: boolean;
1740
+ };
1741
+ /**
1742
+ * Strict subscription request options (for GET method).
1743
+ * Body/query are required if schema requires them.
1744
+ * Note: Transport options (maxRetries, retryDelay, events, parse, accumulate)
1745
+ * are now configured at the hook level (useSSE).
1746
+ */
1747
+ type StrictSubscriptionRequestOptions<TMethodConfig, TUserPath extends string, TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[] = readonly (keyof ExtractEvents<TMethodConfig>)[]> = Simplify<BaseRequestOptions & QueryOption<TMethodConfig> & BodyOption<TMethodConfig> & ParamsOption<TUserPath> & SubscriptionTransportOptions>;
1748
+ /**
1749
+ * Loose subscription request options (for POST/PUT/etc methods).
1750
+ * Body/query are always optional since they're provided via trigger().
1751
+ * Note: Transport options (maxRetries, retryDelay, events, parse, accumulate)
1752
+ * are now configured at the hook level (useSSE).
1753
+ */
1754
+ type LooseSubscriptionRequestOptions<TMethodConfig, TUserPath extends string, TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[] = readonly (keyof ExtractEvents<TMethodConfig>)[]> = Simplify<BaseRequestOptions & {
1755
+ query?: ExtractQuery<TMethodConfig>;
1756
+ } & {
1757
+ body?: ExtractBody<TMethodConfig> | SpooshBody<ExtractBody<TMethodConfig>>;
1758
+ } & ParamsOption<TUserPath> & SubscriptionTransportOptions>;
1759
+ /**
1760
+ * Check if strict subscription options are required (for GET method).
1761
+ */
1762
+ type IsStrictSubscriptionOptionsRequired<TMethodConfig, TUserPath extends string> = IsBodyRequired<TMethodConfig> extends true ? true : IsQueryRequired<TMethodConfig> extends true ? true : HasParams<TUserPath> extends true ? true : false;
1763
+ /**
1764
+ * Subscription response type that carries event types.
1765
+ */
1766
+ type SubscriptionResponse<TMethodConfig, TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[] = readonly (keyof ExtractEvents<TMethodConfig>)[]> = {
1767
+ _subscription: true;
1768
+ events: ExtractEvents<TMethodConfig>;
1769
+ requestedEvents: TRequestedEvents;
1770
+ query: ExtractQuery<TMethodConfig>;
1771
+ body: ExtractBody<TMethodConfig>;
1772
+ error: ExtractError<TMethodConfig>;
1773
+ };
1774
+ type BaseSubscriptionResponse<TEvents extends Record<string, unknown> = Record<string, unknown>, TError = unknown> = {
1775
+ _subscription: true;
1776
+ events: TEvents;
1777
+ requestedEvents: readonly string[];
1778
+ query: unknown;
1779
+ body: unknown;
1780
+ error: TError;
1781
+ };
1782
+ /**
1783
+ * Subscription method function type - methods with events field.
1784
+ * GET: Strict typing (body/query required if schema requires)
1785
+ * POST/PUT/etc: Loose typing (body/query always optional, passed to trigger)
1786
+ */
1787
+ type SubscriptionMethodFn<TMethodConfig, TUserPath extends string, TMethod extends string> = TMethod extends "GET" ? IsStrictSubscriptionOptionsRequired<TMethodConfig, TUserPath> extends true ? <TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[]>(options: StrictSubscriptionRequestOptions<TMethodConfig, TUserPath, TRequestedEvents>) => SubscriptionResponse<TMethodConfig, TRequestedEvents> : <TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[]>(options?: StrictSubscriptionRequestOptions<TMethodConfig, TUserPath, TRequestedEvents>) => SubscriptionResponse<TMethodConfig, TRequestedEvents> : <TRequestedEvents extends readonly (keyof ExtractEvents<TMethodConfig>)[]>(options?: LooseSubscriptionRequestOptions<TMethodConfig, TUserPath, TRequestedEvents>) => SubscriptionResponse<TMethodConfig, TRequestedEvents>;
1788
+ /**
1789
+ * Subscription path methods - only methods with events field.
1790
+ */
1791
+ type SubscriptionPathMethods<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? Simplify<{
1792
+ [M in HttpMethod as M extends keyof TSchema[TKey] ? TSchema[TKey][M] extends {
1793
+ events: unknown;
1794
+ } ? M : never : never]: M extends keyof TSchema[TKey] ? SubscriptionMethodFn<TSchema[TKey][M], TPath, M> : never;
1795
+ }> : never : never;
1796
+ /**
1797
+ * A subscription API interface that only exposes methods with events field.
1798
+ * Used by useSubscription hook for real-time data streams.
1799
+ */
1800
+ type SubscriptionClient<TSchema, TDefaultError = unknown> = <TPath extends SubscriptionPaths<TSchema> | (string & {})>(path: TPath) => HasSubscriptionMethod<TSchema, TPath> extends true ? SubscriptionPathMethods<TSchema, TPath> : never;
1563
1801
 
1564
1802
  type PluginArray = readonly SpooshPlugin<PluginTypeConfig>[];
1565
1803
  interface SpooshConfig<TPlugins extends PluginArray = PluginArray> {
@@ -1567,11 +1805,12 @@ interface SpooshConfig<TPlugins extends PluginArray = PluginArray> {
1567
1805
  defaultOptions?: SpooshOptions;
1568
1806
  plugins?: TPlugins;
1569
1807
  }
1570
- type SpooshInstance<TSchema = unknown, TDefaultError = unknown, TPlugins extends PluginArray = PluginArray> = {
1808
+ type SpooshInstance<TSchema = unknown, TDefaultError = unknown, TPlugins extends PluginArray = PluginArray, TTransports extends string = never> = {
1571
1809
  api: SpooshClient<TSchema, TDefaultError>;
1572
1810
  stateManager: StateManager;
1573
1811
  eventEmitter: EventEmitter;
1574
1812
  pluginExecutor: PluginExecutor;
1813
+ transports: Map<string, SpooshTransport>;
1575
1814
  config: {
1576
1815
  baseUrl: string;
1577
1816
  defaultOptions: SpooshOptions;
@@ -1580,6 +1819,7 @@ type SpooshInstance<TSchema = unknown, TDefaultError = unknown, TPlugins extends
1580
1819
  schema: TSchema;
1581
1820
  defaultError: TDefaultError;
1582
1821
  plugins: TPlugins;
1822
+ transports: TTransports;
1583
1823
  };
1584
1824
  };
1585
1825
 
@@ -1638,10 +1878,11 @@ type ExtractTriggerParams<I> = I extends {
1638
1878
  *
1639
1879
  * @since 0.1.0
1640
1880
  */
1641
- declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends PluginArray = []> {
1881
+ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends PluginArray = [], TTransports extends string = never> {
1642
1882
  private baseUrl;
1643
1883
  private defaultOptions;
1644
1884
  private _plugins;
1885
+ private _transports;
1645
1886
  /**
1646
1887
  * Creates a new Spoosh instance.
1647
1888
  *
@@ -1666,7 +1907,7 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
1666
1907
  * });
1667
1908
  * ```
1668
1909
  */
1669
- constructor(baseUrl: string, defaultOptions?: SpooshOptionsInput, plugins?: TPlugins);
1910
+ constructor(baseUrl: string, defaultOptions?: SpooshOptionsInput, plugins?: TPlugins, transports?: Map<string, SpooshTransport>);
1670
1911
  /**
1671
1912
  * Adds plugins to the Spoosh instance.
1672
1913
  *
@@ -1685,7 +1926,23 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
1685
1926
  * ]);
1686
1927
  * ```
1687
1928
  */
1688
- use<const TNewPlugins extends PluginArray>(plugins: TNewPlugins): Omit<Spoosh<TSchema, TError, TNewPlugins>, "use">;
1929
+ use<const TNewPlugins extends PluginArray>(plugins: TNewPlugins): Omit<Spoosh<TSchema, TError, TNewPlugins, TTransports>, "use">;
1930
+ /**
1931
+ * Registers transport implementations for real-time operations.
1932
+ *
1933
+ * @param transports - Array of transport instances to register
1934
+ * @returns This Spoosh instance for method chaining
1935
+ *
1936
+ * @example
1937
+ * ```ts
1938
+ * import { sse } from '@spoosh/transport-sse';
1939
+ *
1940
+ * const spoosh = new Spoosh<Schema, Error>('/api')
1941
+ * .withTransports([sse()])
1942
+ * .use([...]);
1943
+ * ```
1944
+ */
1945
+ withTransports<const T extends SpooshTransport[]>(transports: T): Spoosh<TSchema, TError, TPlugins, TTransports | T[number]["name"]>;
1689
1946
  /**
1690
1947
  * Cached instance of the underlying SpooshInstance.
1691
1948
  * Created lazily on first property access.
@@ -1796,7 +2053,18 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
1796
2053
  schema: TSchema;
1797
2054
  defaultError: TError;
1798
2055
  plugins: TPlugins;
2056
+ transports: TTransports;
1799
2057
  };
2058
+ /**
2059
+ * Map of registered transport implementations.
2060
+ *
2061
+ * @example
2062
+ * ```ts
2063
+ * const { transports } = client;
2064
+ * const sseTransport = transports.get('sse');
2065
+ * ```
2066
+ */
2067
+ get transports(): Map<string, SpooshTransport<unknown, unknown>>;
1800
2068
  }
1801
2069
 
1802
2070
  /**
@@ -2075,6 +2343,8 @@ declare module "./types" {
2075
2343
  }
2076
2344
  declare const xhrTransport: Transport<XhrTransportOptions>;
2077
2345
 
2346
+ declare function composeAdapter(baseAdapter: SubscriptionAdapter, plugins: readonly SpooshPlugin[]): SubscriptionAdapter;
2347
+
2078
2348
  declare function executeFetch<TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: SpooshOptions, requestOptions?: AnyRequestOptions, nextTags?: boolean): Promise<SpooshResponse<TData, TError>>;
2079
2349
 
2080
2350
  type ExecuteOptions = {
@@ -2282,7 +2552,7 @@ interface QueueControllerContext {
2282
2552
  api: unknown;
2283
2553
  stateManager: StateManager;
2284
2554
  eventEmitter: EventEmitter;
2285
- pluginExecutor: InstancePluginExecutor;
2555
+ pluginExecutor: ApiPluginExecutor;
2286
2556
  }
2287
2557
  declare function createQueueController<TData, TError, TMeta = Record<string, unknown>>(config: QueueControllerConfig, context: QueueControllerContext): QueueController<TData, TError, TMeta>;
2288
2558
 
@@ -2303,4 +2573,36 @@ declare class Semaphore {
2303
2573
  getWaitingCount(): number;
2304
2574
  }
2305
2575
 
2306
- export { type AnyRequestOptions, type ApiSchema, type BuiltInEvents, type CacheEntry, type CacheEntryWithKey, type CapturedCall, type ComputeRequestOptions, type CoreRequestOptionsBase, type CreateInfiniteReadOptions, type CreateOperationOptions, type DataAwareCallback, type DataAwareTransform, type DataChangeCallback, type DevtoolEvents, type EventEmitter, type EventListener, type EventOptions, type EventTracer, type ExecuteOptions, type ExtractBody$1 as ExtractBody, type ExtractData, type ExtractError, type ExtractMethodOptions, type ExtractParamNames, type ExtractQuery$1 as ExtractQuery, type ExtractTriggerBody, type ExtractTriggerParams, type ExtractTriggerQuery, type FetchDirection, type FetchExecutor, type FindMatchingKey, HTTP_METHODS, type HasParams, type HasReadMethod, type HasWriteMethod, type HeadersInitOrGetter, type HttpMethod, type HttpMethodKey, type InfiniteNextContext, type InfinitePage, type InfinitePageStatus, type InfinitePrevContext, type InfiniteReadController, type InfiniteReadState, type InfiniteRequestOptions, type InfiniteTriggerOptions, type InstanceApiContext, type InstanceApiResolvers, type InstancePluginExecutor, type LifecyclePhase, type MergePluginInstanceApi, type MergePluginOptions, type MergePluginResults, type MethodOptionsMap, type OperationController, type OperationState, type OperationType, type PluginAccessor, type PluginArray, type PluginContext, type PluginContextBase, type PluginContextExtensions, type PluginContextInput, type PluginExecutor, type PluginExportsRegistry, type PluginFactory, type PluginHandler, type PluginLifecycle, type PluginMiddleware, type PluginRegistry, type PluginRequestOptions, type PluginResolvers, type PluginResponseHandler, type PluginResultResolvers, type PluginTypeConfig, type PluginUpdateHandler, type QueueController, type QueueControllerConfig, type QueueControllerContext, type QueueItem, type QueueItemStatus, type QueueSelectorClient, type QueueStats, type QueueTriggerInput, type ReadClient, type ReadPaths, type ReadSchemaHelper, type RefetchEvent, type RequestCompleteEvent, type RequestOptions$1 as RequestOptions, type RequestTracer, type ResolveInstanceApi, type ResolveResultTypes, type ResolveSchemaTypes, type ResolveTypes, type ResolverContext, type SchemaPaths, type SelectedEndpoint, type SelectorFunction, type SelectorResult, Semaphore, type SetupContext, type Simplify, Spoosh, type SpooshBody, type SpooshClient, type SpooshConfig, type SpooshInstance, type SpooshOptions, type SpooshOptionsInput, type SpooshPlugin, type SpooshResponse, type SpooshSchema, type StandaloneEvent, type StateManager, type StripPrefix, type Subscriber, type TagMode, type TagOptions, type Trace, type TraceColor, type TraceEvent, type TraceInfo, type TraceListener, type TraceOptions, type TraceStage, type Transport, type TransportOption, type TransportOptionsMap, type TransportResponse, type TypedPluginContext, type TypedPluginDefinition, type WriteClient, type WriteMethod, type WritePaths, type WriteSchemaHelper, type WriteSelectorClient, __DEV__, buildUrl, clone, containsFile, createClient, createEventEmitter, createInfiniteReadController, createInitialState, createOperationController, createPluginExecutor, createPluginRegistry, createProxyHandler, createQueueController, createSelectorProxy, createSpooshPlugin, createStateManager, createTracer, executeFetch, extractMethodFromSelector, extractPathFromSelector, fetchTransport, form, generateTags, getContentType, isAbortError, isJsonBody, isNetworkError, isSpooshBody, json, mergeHeaders, objectToFormData, objectToUrlEncoded, removeHeaderKeys, resolveHeadersToRecord, resolvePath, resolvePathString, resolveRequestBody, resolveTags, setHeaders, sortObjectKeys, urlencoded, xhrTransport };
2576
+ interface SubscriptionController<TData = unknown, TError = unknown> {
2577
+ subscribe(): Promise<SubscriptionHandle<TData, TError>>;
2578
+ subscribe(callback: () => void): () => void;
2579
+ emit(message: unknown): Promise<{
2580
+ success: boolean;
2581
+ error?: TError;
2582
+ }>;
2583
+ unsubscribe(): void;
2584
+ getState(): {
2585
+ data: TData | undefined;
2586
+ error: TError | undefined;
2587
+ isConnected: boolean;
2588
+ };
2589
+ mount(): void;
2590
+ unmount(): void;
2591
+ setDisconnected(): void;
2592
+ }
2593
+
2594
+ interface CreateSubscriptionControllerOptions<TData, TError> {
2595
+ channel: string;
2596
+ baseAdapter: SubscriptionAdapter<TData, TError>;
2597
+ stateManager: StateManager;
2598
+ eventEmitter: EventEmitter;
2599
+ pluginExecutor: PluginExecutor;
2600
+ queryKey: string;
2601
+ operationType: OperationType;
2602
+ path: string;
2603
+ method: string;
2604
+ instanceId?: string;
2605
+ }
2606
+ declare function createSubscriptionController<TData, TError>(options: CreateSubscriptionControllerOptions<TData, TError>): SubscriptionController<TData, TError>;
2607
+
2608
+ export { type AnyMethod, type AnyRequestOptions, type ApiContext, type ApiPluginExecutor, type ApiResolvers, type ApiSchema, type BaseSubscriptionResponse, type BuiltInEvents, type CacheEntry, type CacheEntryWithKey, type CapturedCall, type ComputeRequestOptions, type CoreRequestOptionsBase, type CreateInfiniteReadOptions, type CreateOperationOptions, type CreateSubscriptionControllerOptions, type DataAwareCallback, type DataAwareTransform, type DataChangeCallback, type DevtoolEvents, type EventEmitter, type EventListener, type EventOptions, type EventTracer, type ExecuteOptions, type ExtractBody$1 as ExtractBody, type ExtractData, type ExtractError, type ExtractMethodOptions, type ExtractParamNames, type ExtractQuery$1 as ExtractQuery, type ExtractTriggerBody, type ExtractTriggerParams, type ExtractTriggerQuery, type FetchDirection, type FetchExecutor, type FindMatchingKey, HTTP_METHODS, type HasParams, type HasReadMethod, type HasSubscriptionMethod, type HasWriteMethod, type HeadersInitOrGetter, type HttpMethod, type HttpMethodKey, type InfiniteNextContext, type InfinitePage, type InfinitePageStatus, type InfinitePrevContext, type InfiniteReadController, type InfiniteReadState, type InfiniteRequestOptions, type InfiniteTriggerOptions, type LifecyclePhase, type MergePluginApi, type MergePluginOptions, type MergePluginResults, type MethodOptionsMap, type OperationController, type OperationState, type OperationType, type PluginAccessor, type PluginArray, type PluginContext, type PluginContextBase, type PluginContextExtensions, type PluginContextInput, type PluginExecutor, type PluginFactory, type PluginHandler, type PluginInternalRegistry, type PluginLifecycle, type PluginMiddleware, type PluginRegistry, type PluginRequestOptions, type PluginResolvers, type PluginResponseHandler, type PluginResultResolvers, type PluginTypeConfig, type PluginUpdateHandler, type QueueController, type QueueControllerConfig, type QueueControllerContext, type QueueItem, type QueueItemStatus, type QueueSelectorClient, type QueueStats, type QueueTriggerInput, type ReadClient, type ReadPaths, type ReadSchemaHelper, type RefetchEvent, type RequestCompleteEvent, type RequestOptions$1 as RequestOptions, type RequestTracer, type ResolveApi, type ResolveResultTypes, type ResolveSchemaTypes, type ResolveTypes, type ResolverContext, type SchemaPaths, type SelectedEndpoint, type SelectorFunction, type SelectorResult, Semaphore, type SetupContext, type Simplify, Spoosh, type SpooshBody, type SpooshClient, type SpooshConfig, type SpooshInstance, type SpooshOptions, type SpooshOptionsInput, type SpooshPlugin, type SpooshResponse, type SpooshSchema, type SpooshSubscriptionMethodRegistry, type SpooshTransport, type SpooshTransportRegistry, type StandaloneEvent, type StateManager, type StripPrefix, type Subscriber, type SubscriptionAccumulateEvent, type SubscriptionAdapter, type SubscriptionClient, type SubscriptionConnectEvent, type SubscriptionConnectedEvent, type SubscriptionContext, type SubscriptionController, type SubscriptionDisconnectEvent, type SubscriptionErrorEvent, type SubscriptionHandle, type SubscriptionMessageEvent, type SubscriptionMethod, type SubscriptionPaths, type TagMode, type TagOptions, type Trace, type TraceColor, type TraceEvent, type TraceInfo, type TraceListener, type TraceOptions, type TraceStage, type Transport, type TransportName, type TransportOption, type TransportOptionsMap, type TransportResponse, type TypedPluginContext, type TypedPluginDefinition, type WriteClient, type WriteMethod, type WritePaths, type WriteSchemaHelper, type WriteSelectorClient, __DEV__, buildUrl, clone, composeAdapter, containsFile, createClient, createEventEmitter, createInfiniteReadController, createInitialState, createOperationController, createPluginExecutor, createPluginRegistry, createProxyHandler, createQueueController, createSelectorProxy, createSpooshPlugin, createStateManager, createSubscriptionController, createTracer, executeFetch, extractMethodFromSelector, extractPathFromSelector, fetchTransport, form, generateSelfTagFromKey, generateTags, getContentType, isAbortError, isJsonBody, isNetworkError, isSpooshBody, json, mergeHeaders, objectToFormData, objectToUrlEncoded, removeHeaderKeys, resolveHeadersToRecord, resolvePath, resolvePathString, resolveRequestBody, resolveTags, setHeaders, sortObjectKeys, urlencoded, xhrTransport };