@spoosh/core 0.8.2 → 0.9.1
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/README.md +13 -10
- package/dist/index.d.mts +215 -59
- package/dist/index.d.ts +215 -59
- package/dist/index.js +196 -35
- package/dist/index.mjs +196 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,9 @@ import { createClient } from "@spoosh/core";
|
|
|
50
50
|
const api = createClient<ApiSchema>({
|
|
51
51
|
baseUrl: "/api",
|
|
52
52
|
});
|
|
53
|
+
|
|
54
|
+
// Import body wrappers for explicit serialization
|
|
55
|
+
import { json, form, urlencoded } from "@spoosh/core";
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
### Make API Calls
|
|
@@ -79,14 +82,14 @@ const { data: updated } = await api("users/:id").PUT({
|
|
|
79
82
|
// DELETE /api/users/123
|
|
80
83
|
await api("users/:id").DELETE({ params: { id: 123 } });
|
|
81
84
|
|
|
82
|
-
// POST with file upload (
|
|
85
|
+
// POST with file upload (using form() wrapper for multipart/form-data)
|
|
83
86
|
const { data: uploaded } = await api("upload").POST({
|
|
84
|
-
body: { file: myFile },
|
|
87
|
+
body: form({ file: myFile }),
|
|
85
88
|
});
|
|
86
89
|
|
|
87
|
-
// POST with form data
|
|
90
|
+
// POST with form data (using urlencoded() wrapper)
|
|
88
91
|
const { data: payment } = await api("payments").POST({
|
|
89
|
-
body: { amount: 1000, currency: "usd" },
|
|
92
|
+
body: urlencoded({ amount: 1000, currency: "usd" }),
|
|
90
93
|
});
|
|
91
94
|
```
|
|
92
95
|
|
|
@@ -172,12 +175,12 @@ const updatedContext = await applyMiddlewares(context, middlewares, "before");
|
|
|
172
175
|
|
|
173
176
|
## Schema Types
|
|
174
177
|
|
|
175
|
-
| Field | Description
|
|
176
|
-
| ------- |
|
|
177
|
-
| `data` | Response data type
|
|
178
|
-
| `body` | Request body type
|
|
179
|
-
| `query` | Query parameters type
|
|
180
|
-
| `error` | Typed error type
|
|
178
|
+
| Field | Description | Example |
|
|
179
|
+
| ------- | --------------------- | ------------------------------------------------ |
|
|
180
|
+
| `data` | Response data type | `GET: { data: User[] }` |
|
|
181
|
+
| `body` | Request body type | `POST: { data: User; body: CreateUserBody }` |
|
|
182
|
+
| `query` | Query parameters type | `GET: { data: User[]; query: { page: number } }` |
|
|
183
|
+
| `error` | Typed error type | `GET: { data: User; error: ApiError }` |
|
|
181
184
|
|
|
182
185
|
Path parameters are defined using `:param` syntax in the path key (e.g., `"users/:id"`).
|
|
183
186
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
2
|
+
type WriteMethod = "POST" | "PUT" | "PATCH" | "DELETE";
|
|
3
|
+
type Simplify<T> = {
|
|
4
|
+
[K in keyof T]: T[K];
|
|
5
|
+
} & {};
|
|
2
6
|
|
|
3
7
|
type MiddlewarePhase = "before" | "after";
|
|
4
8
|
type MiddlewareContext<TData = unknown, TError = unknown> = {
|
|
@@ -62,6 +66,20 @@ type SpooshOptionsExtra<TData = unknown, TError = unknown> = {
|
|
|
62
66
|
middlewares?: SpooshMiddleware<TData, TError>[];
|
|
63
67
|
};
|
|
64
68
|
|
|
69
|
+
type SpooshBody<T = unknown> = {
|
|
70
|
+
readonly __spooshBody: true;
|
|
71
|
+
readonly kind: "form" | "json" | "urlencoded";
|
|
72
|
+
readonly value: T;
|
|
73
|
+
};
|
|
74
|
+
declare function isSpooshBody(value: unknown): value is SpooshBody;
|
|
75
|
+
declare function form<T>(value: T): SpooshBody<T>;
|
|
76
|
+
declare function json<T>(value: T): SpooshBody<T>;
|
|
77
|
+
declare function urlencoded<T>(value: T): SpooshBody<T>;
|
|
78
|
+
declare function resolveRequestBody(rawBody: unknown): {
|
|
79
|
+
body: BodyInit;
|
|
80
|
+
headers?: Record<string, string>;
|
|
81
|
+
} | undefined;
|
|
82
|
+
|
|
65
83
|
type RetryConfig = {
|
|
66
84
|
retries?: number | false;
|
|
67
85
|
retryDelay?: number;
|
|
@@ -76,9 +94,9 @@ type BaseRequestOptions$1 = {
|
|
|
76
94
|
signal?: AbortSignal;
|
|
77
95
|
};
|
|
78
96
|
type BodyOption$1<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
79
|
-
body?: Exclude<TBody, undefined
|
|
97
|
+
body?: Exclude<TBody, undefined> | SpooshBody<Exclude<TBody, undefined>>;
|
|
80
98
|
} : {
|
|
81
|
-
body: TBody
|
|
99
|
+
body: TBody | SpooshBody<TBody>;
|
|
82
100
|
};
|
|
83
101
|
type QueryOption$1<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
84
102
|
query?: Exclude<TQuery, undefined>;
|
|
@@ -106,7 +124,7 @@ type MethodOptionsMap<TQueryOptions = object, TMutationOptions = object> = {
|
|
|
106
124
|
DELETE: TMutationOptions;
|
|
107
125
|
};
|
|
108
126
|
type ExtractMethodOptions<TOptionsMap, TMethod extends HttpMethod> = TOptionsMap extends MethodOptionsMap<infer TQuery, infer TMutation> ? TMethod extends "GET" ? TQuery : TMutation : TOptionsMap;
|
|
109
|
-
type FetchExecutor<TOptions = SpooshOptions, TRequestOptions = AnyRequestOptions> = <TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: TOptions, requestOptions?: TRequestOptions, nextTags?: boolean) => Promise<SpooshResponse<TData, TError>>;
|
|
127
|
+
type FetchExecutor<TOptions = SpooshOptions, TRequestOptions = AnyRequestOptions> = <TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: TOptions, requestOptions?: TRequestOptions, nextTags?: boolean, tagPath?: string[]) => Promise<SpooshResponse<TData, TError>>;
|
|
110
128
|
type TypedParamsOption<TParamNames extends string> = [TParamNames] extends [
|
|
111
129
|
never
|
|
112
130
|
] ? object : {
|
|
@@ -233,6 +251,11 @@ type PluginContext<TData = unknown, TError = unknown> = {
|
|
|
233
251
|
readonly requestTimestamp: number;
|
|
234
252
|
/** Unique identifier for the hook instance. Persists across queryKey changes within the same hook. */
|
|
235
253
|
readonly hookId?: string;
|
|
254
|
+
/**
|
|
255
|
+
* Prefix to strip from tags. Configured at the Spoosh instance level.
|
|
256
|
+
* Plugins can use this to normalize tags before emitting events.
|
|
257
|
+
*/
|
|
258
|
+
readonly stripTagPrefix?: string;
|
|
236
259
|
requestOptions: AnyRequestOptions;
|
|
237
260
|
state: OperationState<TData, TError>;
|
|
238
261
|
response?: SpooshResponse<TData, TError>;
|
|
@@ -578,7 +601,10 @@ type PluginExecutor = {
|
|
|
578
601
|
/** Creates a full PluginContext with plugins accessor injected */
|
|
579
602
|
createContext: <TData, TError>(input: PluginContextInput<TData, TError>) => PluginContext<TData, TError>;
|
|
580
603
|
};
|
|
581
|
-
|
|
604
|
+
type PluginExecutorOptions = {
|
|
605
|
+
stripTagPrefix?: string;
|
|
606
|
+
};
|
|
607
|
+
declare function createPluginExecutor(initialPlugins?: SpooshPlugin[], options?: PluginExecutorOptions): PluginExecutor;
|
|
582
608
|
|
|
583
609
|
/**
|
|
584
610
|
* Resolves plugin option types based on the full context.
|
|
@@ -825,10 +851,54 @@ type ExtractParamNames<T extends string> = T extends `${string}:${infer Param}/$
|
|
|
825
851
|
* ```
|
|
826
852
|
*/
|
|
827
853
|
type HasParams<T extends string> = T extends `${string}:${string}` ? true : false;
|
|
854
|
+
/**
|
|
855
|
+
* Extract paths that have GET methods.
|
|
856
|
+
*/
|
|
857
|
+
type ReadPaths<TSchema> = {
|
|
858
|
+
[K in keyof TSchema & string]: "GET" extends keyof TSchema[K] ? K : never;
|
|
859
|
+
}[keyof TSchema & string];
|
|
860
|
+
/**
|
|
861
|
+
* Extract paths that have write methods (POST, PUT, PATCH, DELETE).
|
|
862
|
+
*/
|
|
863
|
+
type WritePaths<TSchema> = {
|
|
864
|
+
[K in keyof TSchema & string]: Extract<keyof TSchema[K], WriteMethod> extends never ? never : K;
|
|
865
|
+
}[keyof TSchema & string];
|
|
866
|
+
/**
|
|
867
|
+
* Check if a schema path has a GET method.
|
|
868
|
+
*/
|
|
869
|
+
type HasReadMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? "GET" extends keyof TSchema[TKey] ? true : false : false : false;
|
|
870
|
+
/**
|
|
871
|
+
* Check if a schema path has any write methods.
|
|
872
|
+
*/
|
|
873
|
+
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;
|
|
874
|
+
type NormalizePrefix<T extends string> = T extends `/${infer Rest}` ? NormalizePrefix<Rest> : T extends `${infer Rest}/` ? NormalizePrefix<Rest> : T;
|
|
875
|
+
type StripPrefixFromPath<TPath extends string, TPrefix extends string> = TPath extends TPrefix ? "" : TPath extends `${TPrefix}/${infer Rest}` ? Rest : TPath;
|
|
876
|
+
/**
|
|
877
|
+
* Strips a prefix from all path keys in a schema.
|
|
878
|
+
* Works with any schema (Elysia, Hono, or manual).
|
|
879
|
+
*
|
|
880
|
+
* @example
|
|
881
|
+
* ```ts
|
|
882
|
+
* type FullSchema = {
|
|
883
|
+
* "api": { GET: { data: string } };
|
|
884
|
+
* "api/users": { GET: { data: User[] } };
|
|
885
|
+
* "api/posts/:id": { GET: { data: Post } };
|
|
886
|
+
* "health": { GET: { data: { status: string } } };
|
|
887
|
+
* };
|
|
888
|
+
*
|
|
889
|
+
* type ApiSchema = StripPrefix<FullSchema, "api">;
|
|
890
|
+
* // {
|
|
891
|
+
* // "": { GET: { data: string } };
|
|
892
|
+
* // "users": { GET: { data: User[] } };
|
|
893
|
+
* // "posts/:id": { GET: { data: Post } };
|
|
894
|
+
* // "health": { GET: { data: { status: string } } };
|
|
895
|
+
* // }
|
|
896
|
+
* ```
|
|
897
|
+
*/
|
|
898
|
+
type StripPrefix<TSchema, TPrefix extends string> = TPrefix extends "" ? TSchema : {
|
|
899
|
+
[K in keyof TSchema as K extends string ? StripPrefixFromPath<K, NormalizePrefix<TPrefix>> : K]: TSchema[K];
|
|
900
|
+
};
|
|
828
901
|
|
|
829
|
-
type Simplify$1<T> = {
|
|
830
|
-
[K in keyof T]: T[K];
|
|
831
|
-
} & {};
|
|
832
902
|
type IsNever<T> = [T] extends [never] ? true : false;
|
|
833
903
|
type EndpointRequestOptions<TEndpoint, TPath extends string> = (IsNever<ExtractBody$1<TEndpoint>> extends true ? object : {
|
|
834
904
|
body: ExtractBody$1<TEndpoint>;
|
|
@@ -837,14 +907,10 @@ type EndpointRequestOptions<TEndpoint, TPath extends string> = (IsNever<ExtractB
|
|
|
837
907
|
}) & (HasParams<TPath> extends true ? {
|
|
838
908
|
params: Record<ExtractParamNames<TPath>, string | number>;
|
|
839
909
|
} : object);
|
|
840
|
-
type EndpointMethodFn<TEndpoint, TPath extends string> = (options?: Simplify
|
|
841
|
-
type
|
|
910
|
+
type EndpointMethodFn<TEndpoint, TPath extends string> = (options?: Simplify<EndpointRequestOptions<TEndpoint, TPath>>) => Promise<SpooshResponse<ExtractData<TEndpoint>, unknown, EndpointRequestOptions<TEndpoint, TPath>>>;
|
|
911
|
+
type ReadPathMethods$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? "GET" extends keyof TSchema[TKey] ? Simplify<{
|
|
842
912
|
GET: EndpointMethodFn<TSchema[TKey]["GET"], TPath>;
|
|
843
913
|
}> : never : never : never;
|
|
844
|
-
type ReadPaths$1<TSchema> = {
|
|
845
|
-
[K in keyof TSchema & string]: "GET" extends keyof TSchema[K] ? K : never;
|
|
846
|
-
}[keyof TSchema & string];
|
|
847
|
-
type HasGetMethod$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? "GET" extends keyof TSchema[TKey] ? true : false : false : false;
|
|
848
914
|
/**
|
|
849
915
|
* Schema navigation helper for plugins that need type-safe API schema access.
|
|
850
916
|
*
|
|
@@ -858,7 +924,7 @@ type HasGetMethod$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TP
|
|
|
858
924
|
* ```ts
|
|
859
925
|
* // Define your plugin's callback type
|
|
860
926
|
* type MyCallbackFn<TSchema = unknown> = (
|
|
861
|
-
* api:
|
|
927
|
+
* api: ReadSchemaHelper<TSchema>
|
|
862
928
|
* ) => unknown;
|
|
863
929
|
*
|
|
864
930
|
* // Usage in plugin options
|
|
@@ -886,25 +952,17 @@ type HasGetMethod$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TP
|
|
|
886
952
|
* });
|
|
887
953
|
* ```
|
|
888
954
|
*/
|
|
889
|
-
type
|
|
890
|
-
type
|
|
891
|
-
|
|
892
|
-
[M in MutationMethod$1 as M extends keyof TSchema[TKey] ? M : never]: M extends keyof TSchema[TKey] ? EndpointMethodFn<TSchema[TKey][M], TPath> : never;
|
|
955
|
+
type ReadSchemaHelper<TSchema> = <TPath extends ReadPaths<TSchema> | (string & {})>(path: TPath) => HasReadMethod<TSchema, TPath> extends true ? ReadPathMethods$1<TSchema, TPath> : never;
|
|
956
|
+
type WritePathMethods$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? Simplify<{
|
|
957
|
+
[M in WriteMethod as M extends keyof TSchema[TKey] ? M : never]: M extends keyof TSchema[TKey] ? EndpointMethodFn<TSchema[TKey][M], TPath> : never;
|
|
893
958
|
}> : never : never;
|
|
894
|
-
type WritePaths$1<TSchema> = {
|
|
895
|
-
[K in keyof TSchema & string]: Extract<keyof TSchema[K], MutationMethod$1> extends never ? never : K;
|
|
896
|
-
}[keyof TSchema & string];
|
|
897
|
-
type HasMutationMethod$1<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? MutationMethod$1 extends never ? false : Extract<keyof TSchema[TKey], MutationMethod$1> extends never ? false : true : false : false;
|
|
898
959
|
/**
|
|
899
960
|
* Schema navigation helper for plugins that need type-safe API schema access for mutations.
|
|
900
961
|
*
|
|
901
|
-
* Similar to
|
|
962
|
+
* Similar to ReadSchemaHelper but exposes write methods (POST, PUT, PATCH, DELETE).
|
|
902
963
|
*/
|
|
903
|
-
type
|
|
964
|
+
type WriteSchemaHelper<TSchema> = <TPath extends WritePaths<TSchema> | (string & {})>(path: TPath) => HasWriteMethod<TSchema, TPath> extends true ? WritePathMethods$1<TSchema, TPath> : never;
|
|
904
965
|
|
|
905
|
-
type Simplify<T> = {
|
|
906
|
-
[K in keyof T]: T[K];
|
|
907
|
-
} & {};
|
|
908
966
|
/**
|
|
909
967
|
* Base request options available on all methods.
|
|
910
968
|
*/
|
|
@@ -941,9 +999,9 @@ type IsQueryRequired<T> = T extends {
|
|
|
941
999
|
* Build the options type for a method.
|
|
942
1000
|
*/
|
|
943
1001
|
type BodyOption<T> = [ExtractBody<T>] extends [never] ? {} : IsBodyRequired<T> extends true ? {
|
|
944
|
-
body: ExtractBody<T
|
|
1002
|
+
body: ExtractBody<T> | SpooshBody<ExtractBody<T>>;
|
|
945
1003
|
} : {
|
|
946
|
-
body?: ExtractBody<T
|
|
1004
|
+
body?: ExtractBody<T> | SpooshBody<ExtractBody<T>>;
|
|
947
1005
|
};
|
|
948
1006
|
type QueryOption<T> = [ExtractQuery<T>] extends [never] ? {} : IsQueryRequired<T> extends true ? {
|
|
949
1007
|
query: ExtractQuery<T>;
|
|
@@ -1014,49 +1072,52 @@ type SpooshClient<TSchema, TDefaultError = unknown> = <TPath extends SchemaPaths
|
|
|
1014
1072
|
type ReadPathMethods<TSchema, TPath extends string, TDefaultError> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? "GET" extends keyof TSchema[TKey] ? Simplify<{
|
|
1015
1073
|
GET: MethodFn<TSchema[TKey]["GET"], TDefaultError, TPath>;
|
|
1016
1074
|
}> : never : never : never;
|
|
1017
|
-
/**
|
|
1018
|
-
* Check if a schema path has a GET method.
|
|
1019
|
-
*/
|
|
1020
|
-
type HasGetMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? "GET" extends keyof TSchema[TKey] ? true : false : false : false;
|
|
1021
|
-
/**
|
|
1022
|
-
* Extract paths that have GET methods.
|
|
1023
|
-
*/
|
|
1024
|
-
type ReadPaths<TSchema> = {
|
|
1025
|
-
[K in keyof TSchema & string]: "GET" extends keyof TSchema[K] ? K : never;
|
|
1026
|
-
}[keyof TSchema & string];
|
|
1027
1075
|
/**
|
|
1028
1076
|
* A read-only API client that only exposes GET methods.
|
|
1029
1077
|
* Used by useRead and injectRead hooks.
|
|
1030
1078
|
*/
|
|
1031
|
-
type ReadClient<TSchema, TDefaultError = unknown> = <TPath extends ReadPaths<TSchema> | (string & {})>(path: TPath) =>
|
|
1032
|
-
/**
|
|
1033
|
-
* Mutation methods (non-GET).
|
|
1034
|
-
*/
|
|
1035
|
-
type MutationMethod = "POST" | "PUT" | "PATCH" | "DELETE";
|
|
1079
|
+
type ReadClient<TSchema, TDefaultError = unknown> = <TPath extends ReadPaths<TSchema> | (string & {})>(path: TPath) => HasReadMethod<TSchema, TPath> extends true ? ReadPathMethods<TSchema, TPath, TDefaultError> : never;
|
|
1036
1080
|
/**
|
|
1037
1081
|
* Write-only client type that only exposes mutation methods (POST, PUT, PATCH, DELETE).
|
|
1038
1082
|
* Used by useWrite/injectWrite hooks to ensure only mutation operations are selected.
|
|
1039
1083
|
*/
|
|
1040
1084
|
type WritePathMethods<TSchema, TPath extends string, TDefaultError> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? Simplify<{
|
|
1041
|
-
[M in
|
|
1085
|
+
[M in WriteMethod as M extends keyof TSchema[TKey] ? M : never]: M extends keyof TSchema[TKey] ? MethodFn<TSchema[TKey][M], TDefaultError, TPath> : never;
|
|
1042
1086
|
}> : never : never;
|
|
1043
|
-
/**
|
|
1044
|
-
* Check if a schema path has any mutation methods.
|
|
1045
|
-
*/
|
|
1046
|
-
type HasMutationMethod<TSchema, TPath extends string> = FindMatchingKey<TSchema, TPath> extends infer TKey ? TKey extends keyof TSchema ? MutationMethod extends never ? false : Extract<keyof TSchema[TKey], MutationMethod> extends never ? false : true : false : false;
|
|
1047
|
-
/**
|
|
1048
|
-
* Extract paths that have mutation methods.
|
|
1049
|
-
*/
|
|
1050
|
-
type WritePaths<TSchema> = {
|
|
1051
|
-
[K in keyof TSchema & string]: Extract<keyof TSchema[K], MutationMethod> extends never ? never : K;
|
|
1052
|
-
}[keyof TSchema & string];
|
|
1053
1087
|
/**
|
|
1054
1088
|
* A write-only API client that only exposes mutation methods (POST, PUT, PATCH, DELETE).
|
|
1055
1089
|
* Used by useWrite and injectWrite hooks.
|
|
1056
1090
|
*/
|
|
1057
|
-
type WriteClient<TSchema, TDefaultError = unknown> = <TPath extends WritePaths<TSchema> | (string & {})>(path: TPath) =>
|
|
1091
|
+
type WriteClient<TSchema, TDefaultError = unknown> = <TPath extends WritePaths<TSchema> | (string & {})>(path: TPath) => HasWriteMethod<TSchema, TPath> extends true ? WritePathMethods<TSchema, TPath, TDefaultError> : never;
|
|
1058
1092
|
|
|
1059
1093
|
type PluginArray = readonly SpooshPlugin<PluginTypeConfig>[];
|
|
1094
|
+
/**
|
|
1095
|
+
* Configuration options for Spoosh runtime behavior.
|
|
1096
|
+
*/
|
|
1097
|
+
type SpooshConfigOptions = {
|
|
1098
|
+
/**
|
|
1099
|
+
* Prefix to strip from tag generation.
|
|
1100
|
+
*
|
|
1101
|
+
* URL prefix stripping always auto-detects from baseUrl.
|
|
1102
|
+
* This option only affects tag generation for cache invalidation.
|
|
1103
|
+
*
|
|
1104
|
+
* - `undefined`: Auto-detect from baseUrl (default)
|
|
1105
|
+
* - `string`: Explicit prefix to strip from tags
|
|
1106
|
+
*
|
|
1107
|
+
* @example
|
|
1108
|
+
* ```ts
|
|
1109
|
+
* // Default: auto-detect from baseUrl
|
|
1110
|
+
* // baseUrl="/api", schema="api/posts" → tags: ["posts"]
|
|
1111
|
+
* new Spoosh<Schema>('https://localhost:3000/api')
|
|
1112
|
+
*
|
|
1113
|
+
* // Explicit prefix (when baseUrl doesn't have it)
|
|
1114
|
+
* // baseUrl="/", schema="api/v1/posts" → tags: ["posts"]
|
|
1115
|
+
* new Spoosh<Schema>('http://localhost:3000')
|
|
1116
|
+
* .configure({ stripTagPrefix: "api/v1" })
|
|
1117
|
+
* ```
|
|
1118
|
+
*/
|
|
1119
|
+
stripTagPrefix?: string;
|
|
1120
|
+
};
|
|
1060
1121
|
interface SpooshConfig<TPlugins extends PluginArray = PluginArray> {
|
|
1061
1122
|
baseUrl: string;
|
|
1062
1123
|
defaultOptions?: SpooshOptions;
|
|
@@ -1070,6 +1131,8 @@ type SpooshInstance<TSchema = unknown, TDefaultError = unknown, TPlugins extends
|
|
|
1070
1131
|
config: {
|
|
1071
1132
|
baseUrl: string;
|
|
1072
1133
|
defaultOptions: SpooshOptions;
|
|
1134
|
+
/** Resolved prefix to strip from tags (used for cache invalidation matching) */
|
|
1135
|
+
stripTagPrefix?: string;
|
|
1073
1136
|
};
|
|
1074
1137
|
_types: {
|
|
1075
1138
|
schema: TSchema;
|
|
@@ -1121,12 +1184,14 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1121
1184
|
private baseUrl;
|
|
1122
1185
|
private defaultOptions;
|
|
1123
1186
|
private _plugins;
|
|
1187
|
+
private _config;
|
|
1124
1188
|
/**
|
|
1125
1189
|
* Creates a new Spoosh instance.
|
|
1126
1190
|
*
|
|
1127
1191
|
* @param baseUrl - The base URL for all API requests (e.g., '/api' or 'https://api.example.com')
|
|
1128
1192
|
* @param defaultOptions - Optional default options applied to all requests (headers, credentials, etc.)
|
|
1129
1193
|
* @param plugins - Internal parameter used by the `.use()` method. Do not pass directly.
|
|
1194
|
+
* @param configOptions - Internal parameter used by the `.config()` method. Do not pass directly.
|
|
1130
1195
|
*
|
|
1131
1196
|
* @example
|
|
1132
1197
|
* ```ts
|
|
@@ -1139,7 +1204,7 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1139
1204
|
* });
|
|
1140
1205
|
* ```
|
|
1141
1206
|
*/
|
|
1142
|
-
constructor(baseUrl: string, defaultOptions?: SpooshOptions, plugins?: TPlugins);
|
|
1207
|
+
constructor(baseUrl: string, defaultOptions?: SpooshOptions, plugins?: TPlugins, configOptions?: SpooshConfigOptions);
|
|
1143
1208
|
/**
|
|
1144
1209
|
* Adds plugins to the Spoosh instance.
|
|
1145
1210
|
*
|
|
@@ -1175,6 +1240,34 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1175
1240
|
* ```
|
|
1176
1241
|
*/
|
|
1177
1242
|
use<const TNewPlugins extends PluginArray>(plugins: TNewPlugins): Spoosh<TSchema, TError, TNewPlugins>;
|
|
1243
|
+
/**
|
|
1244
|
+
* Configures runtime options for the Spoosh instance.
|
|
1245
|
+
*
|
|
1246
|
+
* Returns a **new** Spoosh instance with the updated configuration (immutable pattern).
|
|
1247
|
+
* Configuration is preserved across `.use()` calls.
|
|
1248
|
+
*
|
|
1249
|
+
* URL prefix stripping always auto-detects from baseUrl.
|
|
1250
|
+
* Tag prefix stripping defaults to URL prefix but can be overridden.
|
|
1251
|
+
*
|
|
1252
|
+
* @param options - Configuration options
|
|
1253
|
+
* @returns A new Spoosh instance with the specified configuration
|
|
1254
|
+
*
|
|
1255
|
+
* @example Default behavior (auto-detect from baseUrl for both URL and tags)
|
|
1256
|
+
* ```ts
|
|
1257
|
+
* // baseUrl="/api", schema="api/posts"
|
|
1258
|
+
* // URL: /api/posts, Tags: ["posts"]
|
|
1259
|
+
* const client = new Spoosh<Schema, Error>('https://localhost:3000/api');
|
|
1260
|
+
* ```
|
|
1261
|
+
*
|
|
1262
|
+
* @example Override tag prefix (when baseUrl doesn't have the prefix you want to strip from tags)
|
|
1263
|
+
* ```ts
|
|
1264
|
+
* // baseUrl="/", schema="api/v1/posts"
|
|
1265
|
+
* // URL: /api/v1/posts, Tags: ["posts"] (strips "api/v1" from tags only)
|
|
1266
|
+
* const client = new Spoosh<Schema, Error>('http://localhost:3000')
|
|
1267
|
+
* .configure({ stripTagPrefix: "api/v1" });
|
|
1268
|
+
* ```
|
|
1269
|
+
*/
|
|
1270
|
+
configure(options: SpooshConfigOptions): Spoosh<TSchema, TError, TPlugins>;
|
|
1178
1271
|
/**
|
|
1179
1272
|
* Cached instance of the underlying SpooshInstance.
|
|
1180
1273
|
* Created lazily on first property access.
|
|
@@ -1274,6 +1367,7 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1274
1367
|
get config(): {
|
|
1275
1368
|
baseUrl: string;
|
|
1276
1369
|
defaultOptions: SpooshOptions;
|
|
1370
|
+
stripTagPrefix?: string;
|
|
1277
1371
|
};
|
|
1278
1372
|
/**
|
|
1279
1373
|
* Type information carrier for generic type inference.
|
|
@@ -1292,6 +1386,16 @@ type SpooshClientConfig = {
|
|
|
1292
1386
|
baseUrl: string;
|
|
1293
1387
|
defaultOptions?: SpooshOptions;
|
|
1294
1388
|
middlewares?: SpooshMiddleware[];
|
|
1389
|
+
/**
|
|
1390
|
+
* Prefix to strip from tag generation.
|
|
1391
|
+
*
|
|
1392
|
+
* URL prefix stripping always auto-detects from baseUrl.
|
|
1393
|
+
* This option only affects tag generation for cache invalidation.
|
|
1394
|
+
*
|
|
1395
|
+
* - `undefined`: Auto-detect from baseUrl (default, same as URL prefix)
|
|
1396
|
+
* - `string`: Explicit prefix to strip from tags
|
|
1397
|
+
*/
|
|
1398
|
+
stripTagPrefix?: string;
|
|
1295
1399
|
};
|
|
1296
1400
|
/**
|
|
1297
1401
|
* Creates a lightweight type-safe API client for vanilla JavaScript/TypeScript usage.
|
|
@@ -1334,6 +1438,8 @@ declare function createClient<TSchema, TDefaultError = unknown>(config: SpooshCl
|
|
|
1334
1438
|
|
|
1335
1439
|
declare function buildUrl(baseUrl: string, path: string[], query?: Record<string, string | number | boolean | undefined>): string;
|
|
1336
1440
|
|
|
1441
|
+
declare function __DEV__(): boolean;
|
|
1442
|
+
|
|
1337
1443
|
/**
|
|
1338
1444
|
* Generate cache tags from URL path segments.
|
|
1339
1445
|
* e.g., ['posts', '1'] → ['posts', 'posts/1']
|
|
@@ -1383,11 +1489,61 @@ type TagOptions = {
|
|
|
1383
1489
|
declare function resolveTags(options: TagOptions | undefined, resolvedPath: string[]): string[];
|
|
1384
1490
|
declare function resolvePath(path: string[], params: Record<string, string | number> | undefined): string[];
|
|
1385
1491
|
|
|
1492
|
+
/**
|
|
1493
|
+
* Extracts the path prefix from a base URL.
|
|
1494
|
+
*
|
|
1495
|
+
* @param baseUrl - The base URL (absolute or relative)
|
|
1496
|
+
* @returns The path portion without leading/trailing slashes
|
|
1497
|
+
*
|
|
1498
|
+
* @example
|
|
1499
|
+
* ```ts
|
|
1500
|
+
* extractPrefixFromBaseUrl("https://localhost:3000/api"); // "api"
|
|
1501
|
+
* extractPrefixFromBaseUrl("/api/v1"); // "api/v1"
|
|
1502
|
+
* extractPrefixFromBaseUrl("api"); // "api"
|
|
1503
|
+
* ```
|
|
1504
|
+
*/
|
|
1505
|
+
declare function extractPrefixFromBaseUrl(baseUrl: string): string;
|
|
1506
|
+
/**
|
|
1507
|
+
* Strips a prefix from path segments if the path starts with that prefix.
|
|
1508
|
+
*
|
|
1509
|
+
* @param pathSegments - Array of path segments
|
|
1510
|
+
* @param prefix - Prefix to strip (e.g., "api" or "api/v1")
|
|
1511
|
+
* @returns Path segments with prefix removed
|
|
1512
|
+
*
|
|
1513
|
+
* @example
|
|
1514
|
+
* ```ts
|
|
1515
|
+
* stripPrefixFromPath(["api", "posts"], "api"); // ["posts"]
|
|
1516
|
+
* stripPrefixFromPath(["api", "v1", "users"], "api/v1"); // ["users"]
|
|
1517
|
+
* stripPrefixFromPath(["posts"], "api"); // ["posts"] (no match, unchanged)
|
|
1518
|
+
* ```
|
|
1519
|
+
*/
|
|
1520
|
+
declare function stripPrefixFromPath(pathSegments: string[], prefix: string): string[];
|
|
1521
|
+
/**
|
|
1522
|
+
* Resolves the strip prefix value based on configuration.
|
|
1523
|
+
*
|
|
1524
|
+
* @param stripPathPrefix - Configuration value (boolean, string, or undefined)
|
|
1525
|
+
* @param baseUrl - The base URL to extract prefix from when true
|
|
1526
|
+
* @returns The resolved prefix string to strip
|
|
1527
|
+
*
|
|
1528
|
+
* @example
|
|
1529
|
+
* ```ts
|
|
1530
|
+
* resolveStripPrefix(true, "https://localhost:3000/api"); // "api"
|
|
1531
|
+
* resolveStripPrefix("api/v1", "https://localhost:3000/api"); // "api/v1"
|
|
1532
|
+
* resolveStripPrefix(false, "https://localhost:3000/api"); // ""
|
|
1533
|
+
* resolveStripPrefix(undefined, "https://localhost:3000/api"); // ""
|
|
1534
|
+
* ```
|
|
1535
|
+
*/
|
|
1536
|
+
declare function resolveStripPrefix(stripPathPrefix: boolean | string | undefined, baseUrl: string): string;
|
|
1537
|
+
|
|
1386
1538
|
type ProxyHandlerConfig<TOptions = SpooshOptions> = {
|
|
1387
1539
|
baseUrl: string;
|
|
1388
1540
|
defaultOptions: TOptions;
|
|
1389
1541
|
fetchExecutor?: FetchExecutor<TOptions, AnyRequestOptions>;
|
|
1390
1542
|
nextTags?: boolean;
|
|
1543
|
+
/** Prefix to strip from URL path (auto-detected from baseUrl, always applied) */
|
|
1544
|
+
urlPrefix?: string;
|
|
1545
|
+
/** Prefix to strip from tag generation (defaults to urlPrefix) */
|
|
1546
|
+
tagPrefix?: string;
|
|
1391
1547
|
};
|
|
1392
1548
|
/**
|
|
1393
1549
|
* Creates an API client proxy that uses path strings instead of chained property access.
|
|
@@ -1514,7 +1670,7 @@ declare function extractPathFromSelector(fn: unknown): string;
|
|
|
1514
1670
|
*/
|
|
1515
1671
|
declare function extractMethodFromSelector(fn: unknown): string | undefined;
|
|
1516
1672
|
|
|
1517
|
-
declare function executeFetch<TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: SpooshOptions & SpooshOptionsExtra, requestOptions?: AnyRequestOptions, nextTags?: boolean): Promise<SpooshResponse<TData, TError>>;
|
|
1673
|
+
declare function executeFetch<TData, TError>(baseUrl: string, path: string[], method: HttpMethod, defaultOptions: SpooshOptions & SpooshOptionsExtra, requestOptions?: AnyRequestOptions, nextTags?: boolean, tagPath?: string[]): Promise<SpooshResponse<TData, TError>>;
|
|
1518
1674
|
|
|
1519
1675
|
declare function createMiddleware<TData = unknown, TError = unknown>(name: string, phase: MiddlewarePhase, handler: SpooshMiddleware<TData, TError>["handler"]): SpooshMiddleware<TData, TError>;
|
|
1520
1676
|
declare function applyMiddlewares<TData = unknown, TError = unknown>(context: MiddlewareContext<TData, TError>, middlewares: SpooshMiddleware<TData, TError>[], phase: MiddlewarePhase): Promise<MiddlewareContext<TData, TError>>;
|
|
@@ -1608,4 +1764,4 @@ type CreateInfiniteReadOptions<TData, TItem, TError, TRequest> = {
|
|
|
1608
1764
|
};
|
|
1609
1765
|
declare function createInfiniteReadController<TData, TItem, TError, TRequest extends InfiniteRequestOptions = InfiniteRequestOptions>(options: CreateInfiniteReadOptions<TData, TItem, TError, TRequest>): InfiniteReadController<TData, TItem, TError>;
|
|
1610
1766
|
|
|
1611
|
-
export { type AnyRequestOptions, type ApiSchema, type BuiltInEvents, type CacheEntry, type CacheEntryWithKey, type CapturedCall, type SpooshClientConfig as ClientConfig, type ComputeRequestOptions, type CoreRequestOptionsBase, type CreateInfiniteReadOptions, type CreateOperationOptions, type DataAwareCallback, type DataAwareTransform, type EventEmitter, type ExtractBody$1 as ExtractBody, type ExtractData, type ExtractError, type ExtractMethodOptions, type ExtractParamNames, type ExtractQuery$1 as ExtractQuery, type FetchDirection, type FetchExecutor, type FindMatchingKey, HTTP_METHODS, type HasParams, type HeadersInitOrGetter, type HttpMethod, type HttpMethodKey, type InfiniteReadController, type InfiniteReadState, type InfiniteRequestOptions, type InstanceApiContext, type InstanceApiResolvers, type InstancePluginExecutor, type LifecyclePhase, type MergePluginInstanceApi, type MergePluginOptions, type MergePluginResults, type MethodOptionsMap, type MiddlewareContext, type MiddlewareHandler, type MiddlewarePhase, type
|
|
1767
|
+
export { type AnyRequestOptions, type ApiSchema, type BuiltInEvents, type CacheEntry, type CacheEntryWithKey, type CapturedCall, type SpooshClientConfig as ClientConfig, type ComputeRequestOptions, type CoreRequestOptionsBase, type CreateInfiniteReadOptions, type CreateOperationOptions, type DataAwareCallback, type DataAwareTransform, type EventEmitter, type ExtractBody$1 as ExtractBody, type ExtractData, type ExtractError, type ExtractMethodOptions, type ExtractParamNames, type ExtractQuery$1 as ExtractQuery, type FetchDirection, type FetchExecutor, type FindMatchingKey, HTTP_METHODS, type HasParams, type HasReadMethod, type HasWriteMethod, type HeadersInitOrGetter, type HttpMethod, type HttpMethodKey, type InfiniteReadController, type InfiniteReadState, type InfiniteRequestOptions, type InstanceApiContext, type InstanceApiResolvers, type InstancePluginExecutor, type LifecyclePhase, type MergePluginInstanceApi, type MergePluginOptions, type MergePluginResults, type MethodOptionsMap, type MiddlewareContext, type MiddlewareHandler, type MiddlewarePhase, type OperationController, type OperationState, type OperationType, type PageContext, type PluginAccessor, type PluginArray, type PluginContext, type PluginContextInput, type PluginExecutor, type PluginExecutorOptions, type PluginExportsRegistry, type PluginFactory, type PluginHandler, type PluginLifecycle, type PluginMiddleware, type PluginRegistry, type PluginResolvers, type PluginResponseHandler, type PluginResultResolvers, type PluginTypeConfig, type PluginUpdateHandler, type ReadClient, type ReadPaths, type ReadSchemaHelper, type RefetchEvent, type RequestOptions$1 as RequestOptions, type ResolveInstanceApi, type ResolveResultTypes, type ResolveSchemaTypes, type ResolveTypes, type ResolverContext, type RetryConfig, type RouteToPath, type SchemaPaths, type SelectedEndpoint, type SelectorFunction, type SelectorResult, type Simplify, Spoosh, type SpooshBody, type SpooshClient, type SpooshConfig, type SpooshConfigOptions, type SpooshInstance, type SpooshMiddleware, type SpooshOptions, type SpooshOptionsExtra, type SpooshPlugin, type SpooshResponse, type SpooshSchema, type StateManager, type StripPrefix, type TagMode, type TagOptions, type WriteClient, type WriteMethod, type WritePaths, type WriteSchemaHelper, __DEV__, applyMiddlewares, buildUrl, composeMiddlewares, containsFile, createClient, createEventEmitter, createInfiniteReadController, createInitialState, createMiddleware, createOperationController, createPluginExecutor, createPluginRegistry, createProxyHandler, createSelectorProxy, createStateManager, executeFetch, extractMethodFromSelector, extractPathFromSelector, extractPrefixFromBaseUrl, form, generateTags, getContentType, isJsonBody, isSpooshBody, json, mergeHeaders, objectToFormData, objectToUrlEncoded, resolveHeadersToRecord, resolvePath, resolveRequestBody, resolveStripPrefix, resolveTags, setHeaders, sortObjectKeys, stripPrefixFromPath, urlencoded };
|