@spoosh/core 0.3.0 → 0.4.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/README.md +28 -29
- package/dist/index.d.mts +6 -9
- package/dist/index.d.ts +6 -9
- package/dist/index.js +4 -6
- package/dist/index.mjs +4 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,10 @@ type ApiSchema = {
|
|
|
36
36
|
$post: Endpoint<{ data: { url: string }; formData: { file: File } }>;
|
|
37
37
|
};
|
|
38
38
|
payments: {
|
|
39
|
-
$post: Endpoint<{
|
|
39
|
+
$post: Endpoint<{
|
|
40
|
+
data: { id: string };
|
|
41
|
+
urlEncoded: { amount: number; currency: string };
|
|
42
|
+
}>;
|
|
40
43
|
};
|
|
41
44
|
};
|
|
42
45
|
```
|
|
@@ -173,16 +176,16 @@ const updatedContext = await applyMiddlewares(context, middlewares, "before");
|
|
|
173
176
|
|
|
174
177
|
## Schema Types
|
|
175
178
|
|
|
176
|
-
| Type
|
|
177
|
-
|
|
|
178
|
-
| `Endpoint<{ data }>`
|
|
179
|
-
| `Endpoint<{ data; body }>`
|
|
180
|
-
| `Endpoint<{ data; query }>`
|
|
181
|
-
| `Endpoint<{ data; formData }>`
|
|
182
|
-
| `Endpoint<{ data; urlEncoded }>`
|
|
183
|
-
| `Endpoint<{ data; error }>`
|
|
184
|
-
| `void`
|
|
185
|
-
| `_`
|
|
179
|
+
| Type | Description | Example |
|
|
180
|
+
| -------------------------------- | ---------------------------- | ------------------------------------------------------------------- |
|
|
181
|
+
| `Endpoint<{ data }>` | Endpoint with data only | `$get: Endpoint<{ data: User[] }>` |
|
|
182
|
+
| `Endpoint<{ data; body }>` | Endpoint with JSON body | `$post: Endpoint<{ data: User; body: CreateUserBody }>` |
|
|
183
|
+
| `Endpoint<{ data; query }>` | Endpoint with query params | `$get: Endpoint<{ data: User[]; query: { page: number } }>` |
|
|
184
|
+
| `Endpoint<{ data; formData }>` | Endpoint with multipart form | `$post: Endpoint<{ data: Result; formData: { file: File } }>` |
|
|
185
|
+
| `Endpoint<{ data; urlEncoded }>` | Endpoint with URL-encoded | `$post: Endpoint<{ data: Result; urlEncoded: { amount: number } }>` |
|
|
186
|
+
| `Endpoint<{ data; error }>` | Endpoint with typed error | `$get: Endpoint<{ data: User; error: ApiError }>` |
|
|
187
|
+
| `void` | No response body | `$delete: void` |
|
|
188
|
+
| `_` | Dynamic path segment | `users: { _: { $get: Endpoint<{ data: User }> } }` |
|
|
186
189
|
|
|
187
190
|
## API Reference
|
|
188
191
|
|
|
@@ -206,11 +209,8 @@ import { cachePlugin } from "@spoosh/plugin-cache";
|
|
|
206
209
|
import { retryPlugin } from "@spoosh/plugin-retry";
|
|
207
210
|
|
|
208
211
|
const client = new Spoosh<ApiSchema, Error>("/api", {
|
|
209
|
-
headers: { Authorization: "Bearer token" }
|
|
210
|
-
}).use([
|
|
211
|
-
cachePlugin({ staleTime: 5000 }),
|
|
212
|
-
retryPlugin({ retries: 3 })
|
|
213
|
-
]);
|
|
212
|
+
headers: { Authorization: "Bearer token" },
|
|
213
|
+
}).use([cachePlugin({ staleTime: 5000 }), retryPlugin({ retries: 3 })]);
|
|
214
214
|
|
|
215
215
|
const { api } = client;
|
|
216
216
|
const { data } = await api.users.$get();
|
|
@@ -218,26 +218,25 @@ const { data } = await api.users.$get();
|
|
|
218
218
|
|
|
219
219
|
**Constructor Parameters:**
|
|
220
220
|
|
|
221
|
-
| Parameter | Type
|
|
222
|
-
| ---------------- |
|
|
223
|
-
| `baseUrl` | `string`
|
|
224
|
-
| `defaultOptions` | `RequestInit`
|
|
221
|
+
| Parameter | Type | Description |
|
|
222
|
+
| ---------------- | ------------- | -------------------------------- |
|
|
223
|
+
| `baseUrl` | `string` | Base URL for all API requests |
|
|
224
|
+
| `defaultOptions` | `RequestInit` | (Optional) Default fetch options |
|
|
225
225
|
|
|
226
226
|
**Methods:**
|
|
227
227
|
|
|
228
|
-
| Method
|
|
229
|
-
|
|
|
228
|
+
| Method | Description |
|
|
229
|
+
| --------------- | --------------------------------------------------------------------- |
|
|
230
230
|
| `.use(plugins)` | Add plugins to the client. Returns a new instance with updated types. |
|
|
231
231
|
|
|
232
232
|
**Properties:**
|
|
233
233
|
|
|
234
|
-
| Property
|
|
235
|
-
|
|
|
236
|
-
| `.api`
|
|
237
|
-
| `.stateManager`
|
|
238
|
-
| `.eventEmitter`
|
|
239
|
-
| `.pluginExecutor` | Plugin lifecycle management
|
|
240
|
-
|
|
234
|
+
| Property | Description |
|
|
235
|
+
| ----------------- | ---------------------------------------- |
|
|
236
|
+
| `.api` | Type-safe API client for making requests |
|
|
237
|
+
| `.stateManager` | Cache and state management |
|
|
238
|
+
| `.eventEmitter` | Event system for refetch/invalidation |
|
|
239
|
+
| `.pluginExecutor` | Plugin lifecycle management |
|
|
241
240
|
|
|
242
241
|
## Creating Plugins
|
|
243
242
|
|
package/dist/index.d.mts
CHANGED
|
@@ -801,7 +801,6 @@ type HttpMethods<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamN
|
|
|
801
801
|
[K in SchemaMethod as K extends keyof TSchema ? K : never]: MethodFn<TSchema, K, TDefaultError, TOptionsMap, TParamNames>;
|
|
802
802
|
};
|
|
803
803
|
type DynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = ExtractDynamicSchema<TSchema> extends never ? object : {
|
|
804
|
-
[key: number]: SpooshClient<ExtractDynamicSchema<TSchema>, TDefaultError, TOptionsMap, TParamNames | string, TRootSchema>;
|
|
805
804
|
/**
|
|
806
805
|
* Dynamic path segment with typed param name.
|
|
807
806
|
* Use `:paramName` format to get typed params in the response.
|
|
@@ -844,7 +843,6 @@ type ExtractParamName<S> = S extends `:${infer P}` ? P : never;
|
|
|
844
843
|
type QueryDynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = TSchema extends {
|
|
845
844
|
_: infer D;
|
|
846
845
|
} ? HasQueryMethods<D> extends true ? {
|
|
847
|
-
[key: number]: QueryOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | string, TRootSchema>;
|
|
848
846
|
<TKey extends string | number>(key: TKey): QueryOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | ExtractParamName<TKey>, TRootSchema>;
|
|
849
847
|
} : object : object;
|
|
850
848
|
type QueryOnlyClient<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = QueryHttpMethods<TSchema, TDefaultError, TOptionsMap, TParamNames> & QueryDynamicAccess<TSchema, TDefaultError, TOptionsMap, TParamNames, TRootSchema> & {
|
|
@@ -856,7 +854,6 @@ type MutationHttpMethods<TSchema, TDefaultError = unknown, TOptionsMap = object,
|
|
|
856
854
|
type MutationDynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never> = TSchema extends {
|
|
857
855
|
_: infer D;
|
|
858
856
|
} ? HasMutationMethods<D> extends true ? {
|
|
859
|
-
[key: number]: MutationOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | string>;
|
|
860
857
|
<TKey extends string | number>(key: TKey): MutationOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | ExtractParamName<TKey>>;
|
|
861
858
|
} : object : object;
|
|
862
859
|
type MutationOnlyClient<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never> = MutationHttpMethods<TSchema, TDefaultError, TOptionsMap, TParamNames> & MutationDynamicAccess<TSchema, TDefaultError, TOptionsMap, TParamNames> & {
|
|
@@ -906,7 +903,7 @@ type EndpointToMethod<T> = (options?: ExtractEndpointRequestOptions<T>) => Promi
|
|
|
906
903
|
* trigger({
|
|
907
904
|
* myCallback: (api) => [
|
|
908
905
|
* api.posts.$get, // ✓ Valid
|
|
909
|
-
* api.users
|
|
906
|
+
* api.users(1).$get, // ✓ Dynamic segment
|
|
910
907
|
* api.nonexistent.$get, // ✗ Type error
|
|
911
908
|
* ],
|
|
912
909
|
* });
|
|
@@ -919,7 +916,7 @@ type QuerySchemaHelper<TSchema> = {
|
|
|
919
916
|
} & (TSchema extends {
|
|
920
917
|
_: infer D;
|
|
921
918
|
} ? HasQueryMethods<D> extends true ? {
|
|
922
|
-
|
|
919
|
+
<TKey extends string | number>(key: TKey): QuerySchemaHelper<D>;
|
|
923
920
|
} : object : object);
|
|
924
921
|
|
|
925
922
|
type PluginArray = readonly SpooshPlugin<PluginTypeConfig>[];
|
|
@@ -1066,7 +1063,7 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1066
1063
|
* const { data } = await api.posts.$post({ body: { title: 'Hello' } });
|
|
1067
1064
|
*
|
|
1068
1065
|
* // Dynamic path parameters
|
|
1069
|
-
* const { data } = await api.posts
|
|
1066
|
+
* const { data } = await api.posts(postId).$get();
|
|
1070
1067
|
* ```
|
|
1071
1068
|
*/
|
|
1072
1069
|
get api(): SpooshClient<TSchema, TError, CoreRequestOptionsBase>;
|
|
@@ -1187,7 +1184,7 @@ type SpooshClientConfig = {
|
|
|
1187
1184
|
*
|
|
1188
1185
|
* // Type-safe API calls
|
|
1189
1186
|
* const { data } = await api.posts.$get();
|
|
1190
|
-
* const { data: post } = await api.posts
|
|
1187
|
+
* const { data: post } = await api.posts(123).$get();
|
|
1191
1188
|
* ```
|
|
1192
1189
|
*/
|
|
1193
1190
|
declare function createClient<TSchema, TDefaultError = unknown>(config: SpooshClientConfig): SpooshClient<TSchema, TDefaultError>;
|
|
@@ -1260,9 +1257,9 @@ type ProxyHandlerConfig<TOptions = SpooshOptions> = {
|
|
|
1260
1257
|
* await api.posts.$get();
|
|
1261
1258
|
*
|
|
1262
1259
|
* // Dynamic segments via function call:
|
|
1263
|
-
* // api.posts
|
|
1260
|
+
* // api.posts(123).$get() or api.posts('123').$get()
|
|
1264
1261
|
* // Executes: GET /api/posts/123
|
|
1265
|
-
* await api.posts
|
|
1262
|
+
* await api.posts(123).$get();
|
|
1266
1263
|
* ```
|
|
1267
1264
|
*/
|
|
1268
1265
|
declare function createProxyHandler<TSchema extends object, TOptions = SpooshOptions>(config: ProxyHandlerConfig<TOptions>): TSchema;
|
package/dist/index.d.ts
CHANGED
|
@@ -801,7 +801,6 @@ type HttpMethods<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamN
|
|
|
801
801
|
[K in SchemaMethod as K extends keyof TSchema ? K : never]: MethodFn<TSchema, K, TDefaultError, TOptionsMap, TParamNames>;
|
|
802
802
|
};
|
|
803
803
|
type DynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = ExtractDynamicSchema<TSchema> extends never ? object : {
|
|
804
|
-
[key: number]: SpooshClient<ExtractDynamicSchema<TSchema>, TDefaultError, TOptionsMap, TParamNames | string, TRootSchema>;
|
|
805
804
|
/**
|
|
806
805
|
* Dynamic path segment with typed param name.
|
|
807
806
|
* Use `:paramName` format to get typed params in the response.
|
|
@@ -844,7 +843,6 @@ type ExtractParamName<S> = S extends `:${infer P}` ? P : never;
|
|
|
844
843
|
type QueryDynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = TSchema extends {
|
|
845
844
|
_: infer D;
|
|
846
845
|
} ? HasQueryMethods<D> extends true ? {
|
|
847
|
-
[key: number]: QueryOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | string, TRootSchema>;
|
|
848
846
|
<TKey extends string | number>(key: TKey): QueryOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | ExtractParamName<TKey>, TRootSchema>;
|
|
849
847
|
} : object : object;
|
|
850
848
|
type QueryOnlyClient<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never, TRootSchema = TSchema> = QueryHttpMethods<TSchema, TDefaultError, TOptionsMap, TParamNames> & QueryDynamicAccess<TSchema, TDefaultError, TOptionsMap, TParamNames, TRootSchema> & {
|
|
@@ -856,7 +854,6 @@ type MutationHttpMethods<TSchema, TDefaultError = unknown, TOptionsMap = object,
|
|
|
856
854
|
type MutationDynamicAccess<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never> = TSchema extends {
|
|
857
855
|
_: infer D;
|
|
858
856
|
} ? HasMutationMethods<D> extends true ? {
|
|
859
|
-
[key: number]: MutationOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | string>;
|
|
860
857
|
<TKey extends string | number>(key: TKey): MutationOnlyClient<D, TDefaultError, TOptionsMap, TParamNames | ExtractParamName<TKey>>;
|
|
861
858
|
} : object : object;
|
|
862
859
|
type MutationOnlyClient<TSchema, TDefaultError = unknown, TOptionsMap = object, TParamNames extends string = never> = MutationHttpMethods<TSchema, TDefaultError, TOptionsMap, TParamNames> & MutationDynamicAccess<TSchema, TDefaultError, TOptionsMap, TParamNames> & {
|
|
@@ -906,7 +903,7 @@ type EndpointToMethod<T> = (options?: ExtractEndpointRequestOptions<T>) => Promi
|
|
|
906
903
|
* trigger({
|
|
907
904
|
* myCallback: (api) => [
|
|
908
905
|
* api.posts.$get, // ✓ Valid
|
|
909
|
-
* api.users
|
|
906
|
+
* api.users(1).$get, // ✓ Dynamic segment
|
|
910
907
|
* api.nonexistent.$get, // ✗ Type error
|
|
911
908
|
* ],
|
|
912
909
|
* });
|
|
@@ -919,7 +916,7 @@ type QuerySchemaHelper<TSchema> = {
|
|
|
919
916
|
} & (TSchema extends {
|
|
920
917
|
_: infer D;
|
|
921
918
|
} ? HasQueryMethods<D> extends true ? {
|
|
922
|
-
|
|
919
|
+
<TKey extends string | number>(key: TKey): QuerySchemaHelper<D>;
|
|
923
920
|
} : object : object);
|
|
924
921
|
|
|
925
922
|
type PluginArray = readonly SpooshPlugin<PluginTypeConfig>[];
|
|
@@ -1066,7 +1063,7 @@ declare class Spoosh<TSchema = unknown, TError = unknown, TPlugins extends Plugi
|
|
|
1066
1063
|
* const { data } = await api.posts.$post({ body: { title: 'Hello' } });
|
|
1067
1064
|
*
|
|
1068
1065
|
* // Dynamic path parameters
|
|
1069
|
-
* const { data } = await api.posts
|
|
1066
|
+
* const { data } = await api.posts(postId).$get();
|
|
1070
1067
|
* ```
|
|
1071
1068
|
*/
|
|
1072
1069
|
get api(): SpooshClient<TSchema, TError, CoreRequestOptionsBase>;
|
|
@@ -1187,7 +1184,7 @@ type SpooshClientConfig = {
|
|
|
1187
1184
|
*
|
|
1188
1185
|
* // Type-safe API calls
|
|
1189
1186
|
* const { data } = await api.posts.$get();
|
|
1190
|
-
* const { data: post } = await api.posts
|
|
1187
|
+
* const { data: post } = await api.posts(123).$get();
|
|
1191
1188
|
* ```
|
|
1192
1189
|
*/
|
|
1193
1190
|
declare function createClient<TSchema, TDefaultError = unknown>(config: SpooshClientConfig): SpooshClient<TSchema, TDefaultError>;
|
|
@@ -1260,9 +1257,9 @@ type ProxyHandlerConfig<TOptions = SpooshOptions> = {
|
|
|
1260
1257
|
* await api.posts.$get();
|
|
1261
1258
|
*
|
|
1262
1259
|
* // Dynamic segments via function call:
|
|
1263
|
-
* // api.posts
|
|
1260
|
+
* // api.posts(123).$get() or api.posts('123').$get()
|
|
1264
1261
|
* // Executes: GET /api/posts/123
|
|
1265
|
-
* await api.posts
|
|
1262
|
+
* await api.posts(123).$get();
|
|
1266
1263
|
* ```
|
|
1267
1264
|
*/
|
|
1268
1265
|
declare function createProxyHandler<TSchema extends object, TOptions = SpooshOptions>(config: ProxyHandlerConfig<TOptions>): TSchema;
|
package/dist/index.js
CHANGED
|
@@ -476,11 +476,9 @@ function createProxyHandler(config) {
|
|
|
476
476
|
nextTags
|
|
477
477
|
});
|
|
478
478
|
},
|
|
479
|
-
// Handles function call syntax for dynamic segments: api.posts(
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
// Eg. api.posts[":id"].$get() <-- TypeScript sees this as bracket notation with a string literal, can't infer param types
|
|
483
|
-
// But api.posts(":id").$get() <-- TypeScript can capture ":id" as a template literal type, enabling params: { id: string } inference
|
|
479
|
+
// Handles function call syntax for dynamic segments: api.posts(123), api.posts(":id"), api.users(userId)
|
|
480
|
+
// This is the only way to access dynamic segments in Spoosh.
|
|
481
|
+
// The function call syntax allows TypeScript to capture the literal type, enabling params: { id: string } inference.
|
|
484
482
|
apply(_target, _thisArg, args) {
|
|
485
483
|
const [segment] = args;
|
|
486
484
|
return createProxyHandler({
|
|
@@ -989,7 +987,7 @@ var Spoosh = class _Spoosh {
|
|
|
989
987
|
* const { data } = await api.posts.$post({ body: { title: 'Hello' } });
|
|
990
988
|
*
|
|
991
989
|
* // Dynamic path parameters
|
|
992
|
-
* const { data } = await api.posts
|
|
990
|
+
* const { data } = await api.posts(postId).$get();
|
|
993
991
|
* ```
|
|
994
992
|
*/
|
|
995
993
|
get api() {
|
package/dist/index.mjs
CHANGED
|
@@ -421,11 +421,9 @@ function createProxyHandler(config) {
|
|
|
421
421
|
nextTags
|
|
422
422
|
});
|
|
423
423
|
},
|
|
424
|
-
// Handles function call syntax for dynamic segments: api.posts(
|
|
425
|
-
//
|
|
426
|
-
//
|
|
427
|
-
// Eg. api.posts[":id"].$get() <-- TypeScript sees this as bracket notation with a string literal, can't infer param types
|
|
428
|
-
// But api.posts(":id").$get() <-- TypeScript can capture ":id" as a template literal type, enabling params: { id: string } inference
|
|
424
|
+
// Handles function call syntax for dynamic segments: api.posts(123), api.posts(":id"), api.users(userId)
|
|
425
|
+
// This is the only way to access dynamic segments in Spoosh.
|
|
426
|
+
// The function call syntax allows TypeScript to capture the literal type, enabling params: { id: string } inference.
|
|
429
427
|
apply(_target, _thisArg, args) {
|
|
430
428
|
const [segment] = args;
|
|
431
429
|
return createProxyHandler({
|
|
@@ -934,7 +932,7 @@ var Spoosh = class _Spoosh {
|
|
|
934
932
|
* const { data } = await api.posts.$post({ body: { title: 'Hello' } });
|
|
935
933
|
*
|
|
936
934
|
* // Dynamic path parameters
|
|
937
|
-
* const { data } = await api.posts
|
|
935
|
+
* const { data } = await api.posts(postId).$get();
|
|
938
936
|
* ```
|
|
939
937
|
*/
|
|
940
938
|
get api() {
|