@spoosh/react 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.mts +120 -110
- package/dist/index.d.ts +120 -110
- package/dist/index.js +13 -4
- package/dist/index.mjs +13 -4
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
React hooks for Spoosh - `useRead`, `useWrite`, and `useInfiniteRead`.
|
|
4
4
|
|
|
5
|
-
**[Documentation](https://spoosh.dev/docs/
|
|
5
|
+
**[Documentation](https://spoosh.dev/docs/react)** · **Requirements:** TypeScript >= 5.0, React >= 18.0
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,101 +1,5 @@
|
|
|
1
|
-
import { ReadClient, TagMode, SpooshResponse,
|
|
1
|
+
import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteClient, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
|
|
2
2
|
|
|
3
|
-
type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
|
|
4
|
-
baseUrl: string;
|
|
5
|
-
defaultOptions?: SpooshOptions;
|
|
6
|
-
plugins: TPlugins;
|
|
7
|
-
};
|
|
8
|
-
type TagModeInArray = "all" | "self";
|
|
9
|
-
/**
|
|
10
|
-
* Base options for `useRead` hook.
|
|
11
|
-
*/
|
|
12
|
-
type BaseReadOptions = {
|
|
13
|
-
/** Whether to fetch automatically on mount. Default: true */
|
|
14
|
-
enabled?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Unified tag option
|
|
17
|
-
* - String: mode only ('all' | 'self' | 'none')
|
|
18
|
-
* - Array: custom tags only OR [mode keyword mixed with custom tags]
|
|
19
|
-
* - 'all' or 'self' can be used in arrays
|
|
20
|
-
* - 'none' should only be used as string (use `tags: 'none'` not in array)
|
|
21
|
-
*/
|
|
22
|
-
tags?: TagMode | (TagModeInArray | (string & {}))[];
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Result returned by `useRead` hook.
|
|
26
|
-
*
|
|
27
|
-
* @template TData - The response data type
|
|
28
|
-
* @template TError - The error type
|
|
29
|
-
* @template TMeta - Plugin-provided metadata fields
|
|
30
|
-
* @template TTriggerOptions - Options that can be passed to trigger()
|
|
31
|
-
*/
|
|
32
|
-
type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
|
|
33
|
-
force?: boolean;
|
|
34
|
-
}> = {
|
|
35
|
-
/** True during the initial load (no data yet) */
|
|
36
|
-
loading: boolean;
|
|
37
|
-
/** True during any fetch operation */
|
|
38
|
-
fetching: boolean;
|
|
39
|
-
/** Response data from the API */
|
|
40
|
-
data: TData | undefined;
|
|
41
|
-
/** Error from the last failed request */
|
|
42
|
-
error: TError | undefined;
|
|
43
|
-
/** Plugin-provided metadata */
|
|
44
|
-
meta: TMeta;
|
|
45
|
-
/** Abort the current fetch operation */
|
|
46
|
-
abort: () => void;
|
|
47
|
-
/**
|
|
48
|
-
* Manually trigger a fetch.
|
|
49
|
-
*
|
|
50
|
-
* @param options - Optional override options (query, body, params) to use for this specific request
|
|
51
|
-
*/
|
|
52
|
-
trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Result returned by `useWrite` hook.
|
|
56
|
-
*
|
|
57
|
-
* @template TData - The response data type
|
|
58
|
-
* @template TError - The error type
|
|
59
|
-
* @template TOptions - The trigger options type
|
|
60
|
-
* @template TMeta - Plugin-provided metadata fields
|
|
61
|
-
*/
|
|
62
|
-
type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> = {
|
|
63
|
-
/** Execute the mutation with optional options */
|
|
64
|
-
trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
65
|
-
/** True while the mutation is in progress */
|
|
66
|
-
loading: boolean;
|
|
67
|
-
/** Response data from the API */
|
|
68
|
-
data: TData | undefined;
|
|
69
|
-
/** Error from the last failed request */
|
|
70
|
-
error: TError | undefined;
|
|
71
|
-
/** Plugin-provided metadata */
|
|
72
|
-
meta: TMeta;
|
|
73
|
-
/** Abort the current mutation */
|
|
74
|
-
abort: () => void;
|
|
75
|
-
};
|
|
76
|
-
type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
77
|
-
query?: Exclude<TQuery, undefined>;
|
|
78
|
-
} : {
|
|
79
|
-
query: TQuery;
|
|
80
|
-
};
|
|
81
|
-
type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
82
|
-
body?: Exclude<TBody, undefined>;
|
|
83
|
-
} : {
|
|
84
|
-
body: TBody;
|
|
85
|
-
};
|
|
86
|
-
type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
|
|
87
|
-
never
|
|
88
|
-
] ? object : {
|
|
89
|
-
params: Record<TParamNames, string | number>;
|
|
90
|
-
};
|
|
91
|
-
type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
|
|
92
|
-
type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
|
|
93
|
-
input: InputFields<TQuery, TBody, TParamNames> | undefined;
|
|
94
|
-
};
|
|
95
|
-
type UseReadResult<TData, TError, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError, TMeta> & MergePluginResults<TPlugins>["read"];
|
|
96
|
-
type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
|
|
97
|
-
type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
|
|
98
|
-
type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
|
|
99
3
|
type SuccessResponse<T> = Extract<T, {
|
|
100
4
|
data: unknown;
|
|
101
5
|
error?: undefined;
|
|
@@ -111,14 +15,19 @@ type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResp
|
|
|
111
15
|
error: infer E;
|
|
112
16
|
} ? E : unknown : unknown;
|
|
113
17
|
type ExtractMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] : never;
|
|
18
|
+
type ExtractCoreMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "params" | "body">> : object : object;
|
|
19
|
+
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
20
|
+
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
21
|
+
type ExtractSuccessInput<T> = SuccessResponse<AwaitedReturnType<T>> extends {
|
|
22
|
+
input?: infer I;
|
|
23
|
+
} ? I : object;
|
|
24
|
+
type ExtractResponseRequestOptions<T> = ExtractSuccessInput<T>;
|
|
114
25
|
type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
|
|
115
26
|
query: infer Q;
|
|
116
27
|
} ? Q : never;
|
|
117
28
|
type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
|
|
118
29
|
body: infer B;
|
|
119
30
|
} ? B : never;
|
|
120
|
-
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
121
|
-
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
122
31
|
type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
|
|
123
32
|
input: {
|
|
124
33
|
query: infer Q;
|
|
@@ -134,6 +43,44 @@ type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
|
|
|
134
43
|
params: Record<infer K, unknown>;
|
|
135
44
|
};
|
|
136
45
|
} ? K extends string ? K : never : never;
|
|
46
|
+
|
|
47
|
+
type TagModeInArray$1 = "all" | "self";
|
|
48
|
+
/**
|
|
49
|
+
* Base options for `useRead` hook.
|
|
50
|
+
*/
|
|
51
|
+
type BaseReadOptions = {
|
|
52
|
+
/** Whether to fetch automatically on mount. Default: true */
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Unified tag option
|
|
56
|
+
* - String: mode only ('all' | 'self' | 'none')
|
|
57
|
+
* - Array: custom tags only OR [mode keyword mixed with custom tags]
|
|
58
|
+
* - 'all' or 'self' can be used in arrays
|
|
59
|
+
* - 'none' should only be used as string (use `tags: 'none'` not in array)
|
|
60
|
+
*/
|
|
61
|
+
tags?: TagMode | (TagModeInArray$1 | (string & {}))[];
|
|
62
|
+
};
|
|
63
|
+
type QueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
64
|
+
query?: Exclude<TQuery, undefined>;
|
|
65
|
+
} : {
|
|
66
|
+
query: TQuery;
|
|
67
|
+
};
|
|
68
|
+
type BodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
69
|
+
body?: Exclude<TBody, undefined>;
|
|
70
|
+
} : {
|
|
71
|
+
body: TBody;
|
|
72
|
+
};
|
|
73
|
+
type ParamsField<TParamNames extends string> = [TParamNames] extends [never] ? object : {
|
|
74
|
+
params: Record<TParamNames, string | number>;
|
|
75
|
+
};
|
|
76
|
+
type ReadInputFields<TQuery, TBody, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & ParamsField<TParamNames>;
|
|
77
|
+
type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
|
|
78
|
+
TQuery,
|
|
79
|
+
TBody,
|
|
80
|
+
TParamNames
|
|
81
|
+
] extends [never, never, never] ? object : {
|
|
82
|
+
input: ReadInputFields<TQuery, TBody, TParamNames>;
|
|
83
|
+
};
|
|
137
84
|
type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
138
85
|
type ExtractInputFromResponse<T> = T extends {
|
|
139
86
|
input: infer I;
|
|
@@ -161,27 +108,84 @@ type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> exten
|
|
|
161
108
|
} : {
|
|
162
109
|
force?: boolean;
|
|
163
110
|
};
|
|
164
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Result returned by `useRead` hook.
|
|
113
|
+
*
|
|
114
|
+
* @template TData - The response data type
|
|
115
|
+
* @template TError - The error type
|
|
116
|
+
* @template TMeta - Plugin-provided metadata fields
|
|
117
|
+
* @template TTriggerOptions - Options that can be passed to trigger()
|
|
118
|
+
*/
|
|
119
|
+
type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
|
|
120
|
+
force?: boolean;
|
|
121
|
+
}> = {
|
|
122
|
+
/** True during the initial load (no data yet) */
|
|
123
|
+
loading: boolean;
|
|
124
|
+
/** True during any fetch operation */
|
|
125
|
+
fetching: boolean;
|
|
126
|
+
/** Response data from the API */
|
|
127
|
+
data: TData | undefined;
|
|
128
|
+
/** Error from the last failed request */
|
|
129
|
+
error: TError | undefined;
|
|
130
|
+
/** Plugin-provided metadata */
|
|
131
|
+
meta: TMeta;
|
|
132
|
+
/** Abort the current fetch operation */
|
|
133
|
+
abort: () => void;
|
|
134
|
+
/**
|
|
135
|
+
* Manually trigger a fetch.
|
|
136
|
+
*
|
|
137
|
+
* @param options - Optional override options (query, body, params) to use for this specific request
|
|
138
|
+
*/
|
|
139
|
+
trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
140
|
+
};
|
|
141
|
+
type UseReadResult<TData, TError, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError, TMeta> & MergePluginResults<TPlugins>["read"];
|
|
142
|
+
type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
|
|
143
|
+
|
|
144
|
+
type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
165
145
|
query?: Exclude<TQuery, undefined>;
|
|
166
146
|
} : {
|
|
167
147
|
query: TQuery;
|
|
168
148
|
};
|
|
169
|
-
type
|
|
149
|
+
type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
170
150
|
body?: Exclude<TBody, undefined>;
|
|
171
151
|
} : {
|
|
172
152
|
body: TBody;
|
|
173
153
|
};
|
|
174
|
-
type
|
|
154
|
+
type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
|
|
155
|
+
never
|
|
156
|
+
] ? object : {
|
|
175
157
|
params: Record<TParamNames, string | number>;
|
|
176
158
|
};
|
|
177
|
-
type
|
|
178
|
-
type
|
|
179
|
-
TQuery,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
159
|
+
type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
|
|
160
|
+
type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
|
|
161
|
+
input: InputFields<TQuery, TBody, TParamNames> | undefined;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Result returned by `useWrite` hook.
|
|
165
|
+
*
|
|
166
|
+
* @template TData - The response data type
|
|
167
|
+
* @template TError - The error type
|
|
168
|
+
* @template TOptions - The trigger options type
|
|
169
|
+
* @template TMeta - Plugin-provided metadata fields
|
|
170
|
+
*/
|
|
171
|
+
type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> = {
|
|
172
|
+
/** Execute the mutation with optional options */
|
|
173
|
+
trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
174
|
+
/** True while the mutation is in progress */
|
|
175
|
+
loading: boolean;
|
|
176
|
+
/** Response data from the API */
|
|
177
|
+
data: TData | undefined;
|
|
178
|
+
/** Error from the last failed request */
|
|
179
|
+
error: TError | undefined;
|
|
180
|
+
/** Plugin-provided metadata */
|
|
181
|
+
meta: TMeta;
|
|
182
|
+
/** Abort the current mutation */
|
|
183
|
+
abort: () => void;
|
|
184
184
|
};
|
|
185
|
+
type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
|
|
186
|
+
type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
|
|
187
|
+
|
|
188
|
+
type TagModeInArray = "all" | "self";
|
|
185
189
|
type AnyInfiniteRequestOptions = {
|
|
186
190
|
query?: Record<string, unknown>;
|
|
187
191
|
params?: Record<string, string | number>;
|
|
@@ -448,4 +452,10 @@ declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends
|
|
|
448
452
|
readResult: infer R;
|
|
449
453
|
} ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never>;
|
|
450
454
|
|
|
451
|
-
|
|
455
|
+
type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
|
|
456
|
+
baseUrl: string;
|
|
457
|
+
defaultOptions?: SpooshOptions;
|
|
458
|
+
plugins: TPlugins;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export { type AnyInfiniteRequestOptions, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type InfiniteNextContext, type InfinitePrevContext, type InfiniteReadApiClient, type PluginHooksConfig, type ReadApiClient, type ResponseInputFields, type SpooshReactHooks, type TriggerOptions, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, createReactSpoosh, createUseInfiniteRead, createUseRead, createUseWrite };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,101 +1,5 @@
|
|
|
1
|
-
import { ReadClient, TagMode, SpooshResponse,
|
|
1
|
+
import { ReadClient, TagMode, SpooshResponse, SpooshPlugin, PluginTypeConfig, MergePluginResults, WriteClient, StateManager, EventEmitter, PluginExecutor, PluginArray, ResolveTypes, MergePluginOptions, ResolverContext, ResolveResultTypes, MergePluginInstanceApi, SpooshOptions } from '@spoosh/core';
|
|
2
2
|
|
|
3
|
-
type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
|
|
4
|
-
baseUrl: string;
|
|
5
|
-
defaultOptions?: SpooshOptions;
|
|
6
|
-
plugins: TPlugins;
|
|
7
|
-
};
|
|
8
|
-
type TagModeInArray = "all" | "self";
|
|
9
|
-
/**
|
|
10
|
-
* Base options for `useRead` hook.
|
|
11
|
-
*/
|
|
12
|
-
type BaseReadOptions = {
|
|
13
|
-
/** Whether to fetch automatically on mount. Default: true */
|
|
14
|
-
enabled?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Unified tag option
|
|
17
|
-
* - String: mode only ('all' | 'self' | 'none')
|
|
18
|
-
* - Array: custom tags only OR [mode keyword mixed with custom tags]
|
|
19
|
-
* - 'all' or 'self' can be used in arrays
|
|
20
|
-
* - 'none' should only be used as string (use `tags: 'none'` not in array)
|
|
21
|
-
*/
|
|
22
|
-
tags?: TagMode | (TagModeInArray | (string & {}))[];
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* Result returned by `useRead` hook.
|
|
26
|
-
*
|
|
27
|
-
* @template TData - The response data type
|
|
28
|
-
* @template TError - The error type
|
|
29
|
-
* @template TMeta - Plugin-provided metadata fields
|
|
30
|
-
* @template TTriggerOptions - Options that can be passed to trigger()
|
|
31
|
-
*/
|
|
32
|
-
type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
|
|
33
|
-
force?: boolean;
|
|
34
|
-
}> = {
|
|
35
|
-
/** True during the initial load (no data yet) */
|
|
36
|
-
loading: boolean;
|
|
37
|
-
/** True during any fetch operation */
|
|
38
|
-
fetching: boolean;
|
|
39
|
-
/** Response data from the API */
|
|
40
|
-
data: TData | undefined;
|
|
41
|
-
/** Error from the last failed request */
|
|
42
|
-
error: TError | undefined;
|
|
43
|
-
/** Plugin-provided metadata */
|
|
44
|
-
meta: TMeta;
|
|
45
|
-
/** Abort the current fetch operation */
|
|
46
|
-
abort: () => void;
|
|
47
|
-
/**
|
|
48
|
-
* Manually trigger a fetch.
|
|
49
|
-
*
|
|
50
|
-
* @param options - Optional override options (query, body, params) to use for this specific request
|
|
51
|
-
*/
|
|
52
|
-
trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Result returned by `useWrite` hook.
|
|
56
|
-
*
|
|
57
|
-
* @template TData - The response data type
|
|
58
|
-
* @template TError - The error type
|
|
59
|
-
* @template TOptions - The trigger options type
|
|
60
|
-
* @template TMeta - Plugin-provided metadata fields
|
|
61
|
-
*/
|
|
62
|
-
type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> = {
|
|
63
|
-
/** Execute the mutation with optional options */
|
|
64
|
-
trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
65
|
-
/** True while the mutation is in progress */
|
|
66
|
-
loading: boolean;
|
|
67
|
-
/** Response data from the API */
|
|
68
|
-
data: TData | undefined;
|
|
69
|
-
/** Error from the last failed request */
|
|
70
|
-
error: TError | undefined;
|
|
71
|
-
/** Plugin-provided metadata */
|
|
72
|
-
meta: TMeta;
|
|
73
|
-
/** Abort the current mutation */
|
|
74
|
-
abort: () => void;
|
|
75
|
-
};
|
|
76
|
-
type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
77
|
-
query?: Exclude<TQuery, undefined>;
|
|
78
|
-
} : {
|
|
79
|
-
query: TQuery;
|
|
80
|
-
};
|
|
81
|
-
type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
82
|
-
body?: Exclude<TBody, undefined>;
|
|
83
|
-
} : {
|
|
84
|
-
body: TBody;
|
|
85
|
-
};
|
|
86
|
-
type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
|
|
87
|
-
never
|
|
88
|
-
] ? object : {
|
|
89
|
-
params: Record<TParamNames, string | number>;
|
|
90
|
-
};
|
|
91
|
-
type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
|
|
92
|
-
type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
|
|
93
|
-
input: InputFields<TQuery, TBody, TParamNames> | undefined;
|
|
94
|
-
};
|
|
95
|
-
type UseReadResult<TData, TError, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError, TMeta> & MergePluginResults<TPlugins>["read"];
|
|
96
|
-
type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
|
|
97
|
-
type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
|
|
98
|
-
type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
|
|
99
3
|
type SuccessResponse<T> = Extract<T, {
|
|
100
4
|
data: unknown;
|
|
101
5
|
error?: undefined;
|
|
@@ -111,14 +15,19 @@ type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResp
|
|
|
111
15
|
error: infer E;
|
|
112
16
|
} ? E : unknown : unknown;
|
|
113
17
|
type ExtractMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] : never;
|
|
18
|
+
type ExtractCoreMethodOptions<T> = T extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "params" | "body">> : object : object;
|
|
19
|
+
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
20
|
+
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
21
|
+
type ExtractSuccessInput<T> = SuccessResponse<AwaitedReturnType<T>> extends {
|
|
22
|
+
input?: infer I;
|
|
23
|
+
} ? I : object;
|
|
24
|
+
type ExtractResponseRequestOptions<T> = ExtractSuccessInput<T>;
|
|
114
25
|
type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
|
|
115
26
|
query: infer Q;
|
|
116
27
|
} ? Q : never;
|
|
117
28
|
type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
|
|
118
29
|
body: infer B;
|
|
119
30
|
} ? B : never;
|
|
120
|
-
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
121
|
-
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
122
31
|
type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
|
|
123
32
|
input: {
|
|
124
33
|
query: infer Q;
|
|
@@ -134,6 +43,44 @@ type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
|
|
|
134
43
|
params: Record<infer K, unknown>;
|
|
135
44
|
};
|
|
136
45
|
} ? K extends string ? K : never : never;
|
|
46
|
+
|
|
47
|
+
type TagModeInArray$1 = "all" | "self";
|
|
48
|
+
/**
|
|
49
|
+
* Base options for `useRead` hook.
|
|
50
|
+
*/
|
|
51
|
+
type BaseReadOptions = {
|
|
52
|
+
/** Whether to fetch automatically on mount. Default: true */
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Unified tag option
|
|
56
|
+
* - String: mode only ('all' | 'self' | 'none')
|
|
57
|
+
* - Array: custom tags only OR [mode keyword mixed with custom tags]
|
|
58
|
+
* - 'all' or 'self' can be used in arrays
|
|
59
|
+
* - 'none' should only be used as string (use `tags: 'none'` not in array)
|
|
60
|
+
*/
|
|
61
|
+
tags?: TagMode | (TagModeInArray$1 | (string & {}))[];
|
|
62
|
+
};
|
|
63
|
+
type QueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
64
|
+
query?: Exclude<TQuery, undefined>;
|
|
65
|
+
} : {
|
|
66
|
+
query: TQuery;
|
|
67
|
+
};
|
|
68
|
+
type BodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
69
|
+
body?: Exclude<TBody, undefined>;
|
|
70
|
+
} : {
|
|
71
|
+
body: TBody;
|
|
72
|
+
};
|
|
73
|
+
type ParamsField<TParamNames extends string> = [TParamNames] extends [never] ? object : {
|
|
74
|
+
params: Record<TParamNames, string | number>;
|
|
75
|
+
};
|
|
76
|
+
type ReadInputFields<TQuery, TBody, TParamNames extends string> = QueryField<TQuery> & BodyField<TBody> & ParamsField<TParamNames>;
|
|
77
|
+
type ResponseInputFields<TQuery, TBody, TParamNames extends string> = [
|
|
78
|
+
TQuery,
|
|
79
|
+
TBody,
|
|
80
|
+
TParamNames
|
|
81
|
+
] extends [never, never, never] ? object : {
|
|
82
|
+
input: ReadInputFields<TQuery, TBody, TParamNames>;
|
|
83
|
+
};
|
|
137
84
|
type TriggerAwaitedReturn<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
138
85
|
type ExtractInputFromResponse<T> = T extends {
|
|
139
86
|
input: infer I;
|
|
@@ -161,27 +108,84 @@ type TriggerOptions<T> = ExtractInputFromResponse<TriggerAwaitedReturn<T>> exten
|
|
|
161
108
|
} : {
|
|
162
109
|
force?: boolean;
|
|
163
110
|
};
|
|
164
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Result returned by `useRead` hook.
|
|
113
|
+
*
|
|
114
|
+
* @template TData - The response data type
|
|
115
|
+
* @template TError - The error type
|
|
116
|
+
* @template TMeta - Plugin-provided metadata fields
|
|
117
|
+
* @template TTriggerOptions - Options that can be passed to trigger()
|
|
118
|
+
*/
|
|
119
|
+
type BaseReadResult<TData, TError, TMeta = Record<string, unknown>, TTriggerOptions = {
|
|
120
|
+
force?: boolean;
|
|
121
|
+
}> = {
|
|
122
|
+
/** True during the initial load (no data yet) */
|
|
123
|
+
loading: boolean;
|
|
124
|
+
/** True during any fetch operation */
|
|
125
|
+
fetching: boolean;
|
|
126
|
+
/** Response data from the API */
|
|
127
|
+
data: TData | undefined;
|
|
128
|
+
/** Error from the last failed request */
|
|
129
|
+
error: TError | undefined;
|
|
130
|
+
/** Plugin-provided metadata */
|
|
131
|
+
meta: TMeta;
|
|
132
|
+
/** Abort the current fetch operation */
|
|
133
|
+
abort: () => void;
|
|
134
|
+
/**
|
|
135
|
+
* Manually trigger a fetch.
|
|
136
|
+
*
|
|
137
|
+
* @param options - Optional override options (query, body, params) to use for this specific request
|
|
138
|
+
*/
|
|
139
|
+
trigger: (options?: TTriggerOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
140
|
+
};
|
|
141
|
+
type UseReadResult<TData, TError, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseReadResult<TData, TError, TMeta> & MergePluginResults<TPlugins>["read"];
|
|
142
|
+
type ReadApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
|
|
143
|
+
|
|
144
|
+
type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
165
145
|
query?: Exclude<TQuery, undefined>;
|
|
166
146
|
} : {
|
|
167
147
|
query: TQuery;
|
|
168
148
|
};
|
|
169
|
-
type
|
|
149
|
+
type OptionalBodyField<TBody> = [TBody] extends [never] ? object : undefined extends TBody ? {
|
|
170
150
|
body?: Exclude<TBody, undefined>;
|
|
171
151
|
} : {
|
|
172
152
|
body: TBody;
|
|
173
153
|
};
|
|
174
|
-
type
|
|
154
|
+
type OptionalParamsField<TParamNames extends string> = [TParamNames] extends [
|
|
155
|
+
never
|
|
156
|
+
] ? object : {
|
|
175
157
|
params: Record<TParamNames, string | number>;
|
|
176
158
|
};
|
|
177
|
-
type
|
|
178
|
-
type
|
|
179
|
-
TQuery,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
159
|
+
type InputFields<TQuery, TBody, TParamNames extends string> = OptionalQueryField<TQuery> & OptionalBodyField<TBody> & OptionalParamsField<TParamNames>;
|
|
160
|
+
type WriteResponseInputFields<TQuery, TBody, TParamNames extends string> = [TQuery, TBody, TParamNames] extends [never, never, never] ? object : {
|
|
161
|
+
input: InputFields<TQuery, TBody, TParamNames> | undefined;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* Result returned by `useWrite` hook.
|
|
165
|
+
*
|
|
166
|
+
* @template TData - The response data type
|
|
167
|
+
* @template TError - The error type
|
|
168
|
+
* @template TOptions - The trigger options type
|
|
169
|
+
* @template TMeta - Plugin-provided metadata fields
|
|
170
|
+
*/
|
|
171
|
+
type BaseWriteResult<TData, TError, TOptions, TMeta = Record<string, unknown>> = {
|
|
172
|
+
/** Execute the mutation with optional options */
|
|
173
|
+
trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
|
|
174
|
+
/** True while the mutation is in progress */
|
|
175
|
+
loading: boolean;
|
|
176
|
+
/** Response data from the API */
|
|
177
|
+
data: TData | undefined;
|
|
178
|
+
/** Error from the last failed request */
|
|
179
|
+
error: TError | undefined;
|
|
180
|
+
/** Plugin-provided metadata */
|
|
181
|
+
meta: TMeta;
|
|
182
|
+
/** Abort the current mutation */
|
|
183
|
+
abort: () => void;
|
|
184
184
|
};
|
|
185
|
+
type UseWriteResult<TData, TError, TOptions, TMeta, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = BaseWriteResult<TData, TError, TOptions, TMeta> & MergePluginResults<TPlugins>["write"];
|
|
186
|
+
type WriteApiClient<TSchema, TDefaultError> = WriteClient<TSchema, TDefaultError>;
|
|
187
|
+
|
|
188
|
+
type TagModeInArray = "all" | "self";
|
|
185
189
|
type AnyInfiniteRequestOptions = {
|
|
186
190
|
query?: Record<string, unknown>;
|
|
187
191
|
params?: Record<string, string | number>;
|
|
@@ -448,4 +452,10 @@ declare function createUseInfiniteRead<TSchema, TDefaultError, TPlugins extends
|
|
|
448
452
|
readResult: infer R;
|
|
449
453
|
} ? R : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never>;
|
|
450
454
|
|
|
451
|
-
|
|
455
|
+
type PluginHooksConfig<TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]> = {
|
|
456
|
+
baseUrl: string;
|
|
457
|
+
defaultOptions?: SpooshOptions;
|
|
458
|
+
plugins: TPlugins;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export { type AnyInfiniteRequestOptions, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type ExtractCoreMethodOptions, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type ExtractResponseRequestOptions, type InfiniteNextContext, type InfinitePrevContext, type InfiniteReadApiClient, type PluginHooksConfig, type ReadApiClient, type ResponseInputFields, type SpooshReactHooks, type TriggerOptions, type UseInfiniteReadResult, type UseReadResult, type UseWriteResult, type WriteApiClient, type WriteResponseInputFields, createReactSpoosh, createUseInfiniteRead, createUseRead, createUseWrite };
|
package/dist/index.js
CHANGED
|
@@ -128,7 +128,7 @@ function createUseRead(options) {
|
|
|
128
128
|
return response;
|
|
129
129
|
} catch (err) {
|
|
130
130
|
setRequestState({ isPending: false, error: err });
|
|
131
|
-
|
|
131
|
+
return { error: err };
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
134
|
[controller, capturedCall.options]
|
|
@@ -166,9 +166,13 @@ function createUseRead(options) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
);
|
|
169
|
+
const unsubRefetchAll = eventEmitter.on("refetchAll", () => {
|
|
170
|
+
executeWithTracking(true);
|
|
171
|
+
});
|
|
169
172
|
return () => {
|
|
170
173
|
unsubRefetch();
|
|
171
174
|
unsubInvalidate();
|
|
175
|
+
unsubRefetchAll();
|
|
172
176
|
};
|
|
173
177
|
}, [queryKey, enabled, tagsKey]);
|
|
174
178
|
(0, import_react.useEffect)(() => {
|
|
@@ -181,7 +185,7 @@ function createUseRead(options) {
|
|
|
181
185
|
}, []);
|
|
182
186
|
const trigger = (0, import_react.useCallback)(
|
|
183
187
|
async (triggerOptions) => {
|
|
184
|
-
const { force =
|
|
188
|
+
const { force = true, ...overrideOptions } = triggerOptions ?? {};
|
|
185
189
|
const hasOverrides = Object.keys(overrideOptions).length > 0;
|
|
186
190
|
if (!hasOverrides) {
|
|
187
191
|
return executeWithTracking(force, void 0);
|
|
@@ -239,7 +243,7 @@ function createUseRead(options) {
|
|
|
239
243
|
return response;
|
|
240
244
|
} catch (err) {
|
|
241
245
|
setRequestState({ isPending: false, error: err });
|
|
242
|
-
|
|
246
|
+
return { error: err };
|
|
243
247
|
}
|
|
244
248
|
},
|
|
245
249
|
[
|
|
@@ -368,7 +372,7 @@ function createUseWrite(options) {
|
|
|
368
372
|
return response;
|
|
369
373
|
} catch (err) {
|
|
370
374
|
setRequestState({ isPending: false, error: err });
|
|
371
|
-
|
|
375
|
+
return { error: err };
|
|
372
376
|
}
|
|
373
377
|
},
|
|
374
378
|
[selectedEndpoint.path]
|
|
@@ -540,8 +544,13 @@ function createUseInfiniteRead(options) {
|
|
|
540
544
|
}
|
|
541
545
|
}
|
|
542
546
|
);
|
|
547
|
+
const unsubRefetchAll = eventEmitter.on("refetchAll", () => {
|
|
548
|
+
setIsPending(true);
|
|
549
|
+
controller.refetch().finally(() => setIsPending(false));
|
|
550
|
+
});
|
|
543
551
|
return () => {
|
|
544
552
|
unsubInvalidate();
|
|
553
|
+
unsubRefetchAll();
|
|
545
554
|
};
|
|
546
555
|
}, [tagsKey]);
|
|
547
556
|
(0, import_react3.useEffect)(() => {
|
package/dist/index.mjs
CHANGED
|
@@ -112,7 +112,7 @@ function createUseRead(options) {
|
|
|
112
112
|
return response;
|
|
113
113
|
} catch (err) {
|
|
114
114
|
setRequestState({ isPending: false, error: err });
|
|
115
|
-
|
|
115
|
+
return { error: err };
|
|
116
116
|
}
|
|
117
117
|
},
|
|
118
118
|
[controller, capturedCall.options]
|
|
@@ -150,9 +150,13 @@ function createUseRead(options) {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
);
|
|
153
|
+
const unsubRefetchAll = eventEmitter.on("refetchAll", () => {
|
|
154
|
+
executeWithTracking(true);
|
|
155
|
+
});
|
|
153
156
|
return () => {
|
|
154
157
|
unsubRefetch();
|
|
155
158
|
unsubInvalidate();
|
|
159
|
+
unsubRefetchAll();
|
|
156
160
|
};
|
|
157
161
|
}, [queryKey, enabled, tagsKey]);
|
|
158
162
|
useEffect(() => {
|
|
@@ -165,7 +169,7 @@ function createUseRead(options) {
|
|
|
165
169
|
}, []);
|
|
166
170
|
const trigger = useCallback(
|
|
167
171
|
async (triggerOptions) => {
|
|
168
|
-
const { force =
|
|
172
|
+
const { force = true, ...overrideOptions } = triggerOptions ?? {};
|
|
169
173
|
const hasOverrides = Object.keys(overrideOptions).length > 0;
|
|
170
174
|
if (!hasOverrides) {
|
|
171
175
|
return executeWithTracking(force, void 0);
|
|
@@ -223,7 +227,7 @@ function createUseRead(options) {
|
|
|
223
227
|
return response;
|
|
224
228
|
} catch (err) {
|
|
225
229
|
setRequestState({ isPending: false, error: err });
|
|
226
|
-
|
|
230
|
+
return { error: err };
|
|
227
231
|
}
|
|
228
232
|
},
|
|
229
233
|
[
|
|
@@ -363,7 +367,7 @@ function createUseWrite(options) {
|
|
|
363
367
|
return response;
|
|
364
368
|
} catch (err) {
|
|
365
369
|
setRequestState({ isPending: false, error: err });
|
|
366
|
-
|
|
370
|
+
return { error: err };
|
|
367
371
|
}
|
|
368
372
|
},
|
|
369
373
|
[selectedEndpoint.path]
|
|
@@ -546,8 +550,13 @@ function createUseInfiniteRead(options) {
|
|
|
546
550
|
}
|
|
547
551
|
}
|
|
548
552
|
);
|
|
553
|
+
const unsubRefetchAll = eventEmitter.on("refetchAll", () => {
|
|
554
|
+
setIsPending(true);
|
|
555
|
+
controller.refetch().finally(() => setIsPending(false));
|
|
556
|
+
});
|
|
549
557
|
return () => {
|
|
550
558
|
unsubInvalidate();
|
|
559
|
+
unsubRefetchAll();
|
|
551
560
|
};
|
|
552
561
|
}, [tagsKey]);
|
|
553
562
|
useEffect2(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spoosh/react",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React hooks for Spoosh API client",
|
|
6
6
|
"keywords": [
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
],
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/
|
|
16
|
+
"url": "git+https://github.com/spooshdev/spoosh.git",
|
|
17
17
|
"directory": "packages/react"
|
|
18
18
|
},
|
|
19
19
|
"bugs": {
|
|
20
|
-
"url": "https://github.com/
|
|
20
|
+
"url": "https://github.com/spooshdev/spoosh/issues"
|
|
21
21
|
},
|
|
22
|
-
"homepage": "https://spoosh.dev/react
|
|
22
|
+
"homepage": "https://spoosh.dev/docs/react",
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
@@ -38,7 +38,10 @@
|
|
|
38
38
|
"react": "^18 || ^19"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@
|
|
41
|
+
"@testing-library/react": "^16.0.0",
|
|
42
|
+
"jsdom": "^26.0.0",
|
|
43
|
+
"@spoosh/core": "0.10.0",
|
|
44
|
+
"@spoosh/test-utils": "0.1.5"
|
|
42
45
|
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"dev": "tsup --watch",
|