@spoosh/angular 0.9.0 → 0.10.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 +64 -51
- package/dist/index.d.mts +307 -86
- package/dist/index.d.ts +307 -86
- package/dist/index.js +112 -47
- package/dist/index.mjs +115 -47
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @spoosh/angular
|
|
2
2
|
|
|
3
|
-
Angular signals integration for Spoosh - `injectRead`, `injectWrite`, and `
|
|
3
|
+
Angular signals integration for Spoosh - `injectRead`, `injectWrite`, and `injectPages`.
|
|
4
4
|
|
|
5
5
|
**[Documentation](https://spoosh.dev/docs/angular)** · **Requirements:** TypeScript >= 5.0, Angular >= 16.0
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
|
|
|
23
23
|
cachePlugin({ staleTime: 5000 }),
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
|
-
export const { injectRead, injectWrite,
|
|
26
|
+
export const { injectRead, injectWrite, injectPages } = create(spoosh);
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
### injectRead
|
|
@@ -115,7 +115,7 @@ async updateUserName(userId: number, name: string) {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
###
|
|
118
|
+
### injectPages
|
|
119
119
|
|
|
120
120
|
Bidirectional paginated data fetching with infinite scroll support.
|
|
121
121
|
|
|
@@ -140,29 +140,26 @@ Bidirectional paginated data fetching with infinite scroll support.
|
|
|
140
140
|
`,
|
|
141
141
|
})
|
|
142
142
|
export class PostListComponent {
|
|
143
|
-
posts =
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
// Required: Check if next page exists
|
|
147
|
-
canFetchNext: ({ response }) => response?.meta.hasMore ?? false,
|
|
143
|
+
posts = injectPages((api) => api("posts").GET({ query: { page: 1 } }), {
|
|
144
|
+
// Required: Check if next page exists
|
|
145
|
+
canFetchNext: ({ lastPage }) => lastPage?.data?.meta.hasMore ?? false,
|
|
148
146
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
// Required: Build request for next page
|
|
148
|
+
nextPageRequest: ({ lastPage }) => ({
|
|
149
|
+
query: { page: (lastPage?.data?.meta.page ?? 0) + 1 },
|
|
150
|
+
}),
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
// Required: Merge all pages into items
|
|
153
|
+
merger: (pages) => pages.flatMap((p) => p.data?.items ?? []),
|
|
156
154
|
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
// Optional: Check if previous page exists
|
|
156
|
+
canFetchPrev: ({ firstPage }) => (firstPage?.data?.meta.page ?? 1) > 1,
|
|
159
157
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
);
|
|
158
|
+
// Optional: Build request for previous page
|
|
159
|
+
prevPageRequest: ({ firstPage }) => ({
|
|
160
|
+
query: { page: (firstPage?.data?.meta.page ?? 2) - 1 },
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
166
163
|
}
|
|
167
164
|
```
|
|
168
165
|
|
|
@@ -203,42 +200,58 @@ export class PostListComponent {
|
|
|
203
200
|
| `input` | `TriggerOptions \| undefined` | Last trigger input |
|
|
204
201
|
| `abort` | `() => void` | Abort current request |
|
|
205
202
|
|
|
206
|
-
###
|
|
203
|
+
### injectPages(readFn, options)
|
|
207
204
|
|
|
208
|
-
| Option | Type | Required | Description
|
|
209
|
-
| ----------------- | --------------------------------------------- | -------- |
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `canFetchPrev` | `(ctx) => boolean` | No | Check if previous page exists
|
|
214
|
-
| `prevPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for previous page
|
|
215
|
-
| `enabled` | `boolean \| Signal<boolean> \| () => boolean` | No | Whether to fetch automatically
|
|
205
|
+
| Option | Type | Required | Description |
|
|
206
|
+
| ----------------- | --------------------------------------------- | -------- | ------------------------------------------------- |
|
|
207
|
+
| `merger` | `(pages) => TItem[]` | Yes | Merge all pages into items |
|
|
208
|
+
| `canFetchNext` | `(ctx) => boolean` | No | Check if next page exists. Default: `() => false` |
|
|
209
|
+
| `nextPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for next page |
|
|
210
|
+
| `canFetchPrev` | `(ctx) => boolean` | No | Check if previous page exists |
|
|
211
|
+
| `prevPageRequest` | `(ctx) => Partial<TRequest>` | No | Build request for previous page |
|
|
212
|
+
| `enabled` | `boolean \| Signal<boolean> \| () => boolean` | No | Whether to fetch automatically |
|
|
216
213
|
|
|
217
214
|
**Context object passed to callbacks:**
|
|
218
215
|
|
|
219
216
|
```typescript
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
217
|
+
// For canFetchNext and nextPageRequest
|
|
218
|
+
type NextContext<TData, TRequest> = {
|
|
219
|
+
lastPage: InfinitePage<TData> | undefined;
|
|
220
|
+
pages: InfinitePage<TData>[];
|
|
221
|
+
request: TRequest;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// For canFetchPrev and prevPageRequest
|
|
225
|
+
type PrevContext<TData, TRequest> = {
|
|
226
|
+
firstPage: InfinitePage<TData> | undefined;
|
|
227
|
+
pages: InfinitePage<TData>[];
|
|
228
|
+
request: TRequest;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// Each page in the pages array
|
|
232
|
+
type InfinitePage<TData> = {
|
|
233
|
+
status: "pending" | "loading" | "success" | "error" | "stale";
|
|
234
|
+
data?: TData;
|
|
235
|
+
error?: TError;
|
|
236
|
+
meta?: TMeta;
|
|
237
|
+
input?: { query?; params?; body? };
|
|
224
238
|
};
|
|
225
239
|
```
|
|
226
240
|
|
|
227
241
|
**Returns:**
|
|
228
242
|
|
|
229
|
-
| Property | Type
|
|
230
|
-
| -------------- |
|
|
231
|
-
| `data` | `Signal<TItem[] \| undefined>`
|
|
232
|
-
| `
|
|
233
|
-
| `loading` | `Signal<boolean>`
|
|
234
|
-
| `fetching` | `Signal<boolean>`
|
|
235
|
-
| `fetchingNext` | `Signal<boolean>`
|
|
236
|
-
| `fetchingPrev` | `Signal<boolean>`
|
|
237
|
-
| `canFetchNext` | `Signal<boolean>`
|
|
238
|
-
| `canFetchPrev` | `Signal<boolean>`
|
|
239
|
-
| `
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
| `
|
|
244
|
-
| `error` | `Signal<TError \| undefined>` | Error if request failed |
|
|
243
|
+
| Property | Type | Description |
|
|
244
|
+
| -------------- | ------------------------------- | ----------------------------------------------- |
|
|
245
|
+
| `data` | `Signal<TItem[] \| undefined>` | Merged items from all pages |
|
|
246
|
+
| `pages` | `Signal<InfinitePage<TData>[]>` | Array of all pages with status, data, and meta |
|
|
247
|
+
| `loading` | `Signal<boolean>` | True during initial load |
|
|
248
|
+
| `fetching` | `Signal<boolean>` | True during any fetch |
|
|
249
|
+
| `fetchingNext` | `Signal<boolean>` | True while fetching next page |
|
|
250
|
+
| `fetchingPrev` | `Signal<boolean>` | True while fetching previous |
|
|
251
|
+
| `canFetchNext` | `Signal<boolean>` | Whether next page exists |
|
|
252
|
+
| `canFetchPrev` | `Signal<boolean>` | Whether previous page exists |
|
|
253
|
+
| `fetchNext` | `() => Promise<void>` | Fetch the next page |
|
|
254
|
+
| `fetchPrev` | `() => Promise<void>` | Fetch the previous page |
|
|
255
|
+
| `trigger` | `(options?) => Promise<void>` | Trigger fetch with optional new request options |
|
|
256
|
+
| `abort` | `() => void` | Abort current request |
|
|
257
|
+
| `error` | `Signal<TError \| undefined>` | Error if request failed |
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,115 @@
|
|
|
1
1
|
import * as _spoosh_core from '@spoosh/core';
|
|
2
|
-
import { PluginArray, StateManager, EventEmitter, PluginExecutor, MethodOptionsMap, CoreRequestOptionsBase, ReadClient, TagOptions,
|
|
2
|
+
import { QueueSelectorClient, SpooshResponse, QueueItem, QueueStats, SpooshBody, PluginArray, StateManager, EventEmitter, PluginExecutor, MethodOptionsMap, CoreRequestOptionsBase, SpooshPlugin, PluginTypeConfig, ResolveTypes, ResolverContext, ResolveResultTypes, ReadClient, TagOptions, InfiniteNextContext, InfinitePrevContext, InfinitePage, ExtractTriggerQuery as ExtractTriggerQuery$2, ExtractTriggerBody as ExtractTriggerBody$2, ExtractTriggerParams as ExtractTriggerParams$2, InfiniteRequestOptions, WriteSelectorClient, MergePluginInstanceApi } from '@spoosh/core';
|
|
3
3
|
import { Signal } from '@angular/core';
|
|
4
4
|
|
|
5
|
+
type TriggerAwaitedReturn$2<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
|
|
6
|
+
type ExtractInputFromResponse$3<T> = T extends {
|
|
7
|
+
input: infer I;
|
|
8
|
+
} ? I : never;
|
|
9
|
+
type ExtractTriggerQuery$1<I> = I extends {
|
|
10
|
+
query: infer Q;
|
|
11
|
+
} ? undefined extends Q ? {
|
|
12
|
+
query?: Exclude<Q, undefined>;
|
|
13
|
+
} : {
|
|
14
|
+
query: Q;
|
|
15
|
+
} : unknown;
|
|
16
|
+
type ExtractTriggerBody$1<I> = I extends {
|
|
17
|
+
body: infer B;
|
|
18
|
+
} ? undefined extends B ? {
|
|
19
|
+
body?: Exclude<B, undefined> | SpooshBody<Exclude<B, undefined>>;
|
|
20
|
+
} : {
|
|
21
|
+
body: B | SpooshBody<B>;
|
|
22
|
+
} : unknown;
|
|
23
|
+
type ExtractTriggerParams$1<I> = I extends {
|
|
24
|
+
params: infer P;
|
|
25
|
+
} ? {
|
|
26
|
+
params: P;
|
|
27
|
+
} : unknown;
|
|
28
|
+
type QueueTriggerBase = {
|
|
29
|
+
/** Custom ID for this queue item. If not provided, one will be auto-generated. */
|
|
30
|
+
id?: string;
|
|
31
|
+
};
|
|
32
|
+
type QueueTriggerInput<T> = ExtractInputFromResponse$3<TriggerAwaitedReturn$2<T>> extends infer I ? [I] extends [never] ? QueueTriggerBase : QueueTriggerBase & ExtractTriggerQuery$1<I> & ExtractTriggerBody$1<I> & ExtractTriggerParams$1<I> : QueueTriggerBase;
|
|
33
|
+
/**
|
|
34
|
+
* Options for injectQueue.
|
|
35
|
+
*/
|
|
36
|
+
interface InjectQueueOptions {
|
|
37
|
+
/** Maximum concurrent operations. Defaults to 3. */
|
|
38
|
+
concurrency?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Result returned by injectQueue.
|
|
42
|
+
*
|
|
43
|
+
* @template TData - The response data type
|
|
44
|
+
* @template TError - The error type
|
|
45
|
+
* @template TTriggerInput - The trigger input type
|
|
46
|
+
* @template TMeta - Plugin-contributed metadata on queue items
|
|
47
|
+
*/
|
|
48
|
+
interface BaseQueueResult<TData, TError, TTriggerInput, TMeta = object> {
|
|
49
|
+
/** Add item to queue and execute. Returns promise for this item. */
|
|
50
|
+
trigger: (input?: TTriggerInput) => Promise<SpooshResponse<TData, TError>>;
|
|
51
|
+
/** All tasks in queue with their current status */
|
|
52
|
+
tasks: Signal<QueueItem<TData, TError, TMeta>[]>;
|
|
53
|
+
/** Queue statistics (pending/running/settled/success/failed/total/percentage) */
|
|
54
|
+
stats: Signal<QueueStats>;
|
|
55
|
+
/** Abort task by ID, or all tasks if no ID */
|
|
56
|
+
abort: (id?: string) => void;
|
|
57
|
+
/** Retry failed task by ID, or all failed if no ID */
|
|
58
|
+
retry: (id?: string) => Promise<void>;
|
|
59
|
+
/** Remove specific task by ID (aborts if active) */
|
|
60
|
+
remove: (id: string) => void;
|
|
61
|
+
/** Remove all settled tasks (success, error, aborted). Keeps pending/running. */
|
|
62
|
+
removeSettled: () => void;
|
|
63
|
+
/** Abort all and clear queue */
|
|
64
|
+
clear: () => void;
|
|
65
|
+
/** Update concurrency limit */
|
|
66
|
+
setConcurrency: (concurrency: number) => void;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* API client type for queue selector.
|
|
70
|
+
* Supports all HTTP methods (GET, POST, PUT, PATCH, DELETE).
|
|
71
|
+
*/
|
|
72
|
+
type QueueApiClient<TSchema, TDefaultError> = QueueSelectorClient<TSchema, TDefaultError>;
|
|
73
|
+
|
|
74
|
+
type SuccessResponse<T> = Extract<T, {
|
|
75
|
+
data: unknown;
|
|
76
|
+
error?: undefined;
|
|
77
|
+
}>;
|
|
78
|
+
type ErrorResponse<T> = Extract<T, {
|
|
79
|
+
error: unknown;
|
|
80
|
+
data?: undefined;
|
|
81
|
+
}>;
|
|
82
|
+
type ExtractMethodData<T> = T extends (...args: never[]) => infer R ? SuccessResponse<Awaited<R>> extends {
|
|
83
|
+
data: infer D;
|
|
84
|
+
} ? D : unknown : unknown;
|
|
85
|
+
type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResponse<Awaited<R>> extends {
|
|
86
|
+
error: infer E;
|
|
87
|
+
} ? E : unknown : unknown;
|
|
88
|
+
type ExtractMethodOptions<T> = T extends (options?: infer O) => Promise<unknown> ? O : never;
|
|
89
|
+
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
90
|
+
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
91
|
+
type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
|
|
92
|
+
input: {
|
|
93
|
+
query: infer Q;
|
|
94
|
+
};
|
|
95
|
+
} ? Q : never;
|
|
96
|
+
type ExtractResponseBody<T> = SuccessReturnType<T> extends {
|
|
97
|
+
input: {
|
|
98
|
+
body: infer B;
|
|
99
|
+
};
|
|
100
|
+
} ? B : never;
|
|
101
|
+
type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
|
|
102
|
+
input: {
|
|
103
|
+
params: Record<infer K, unknown>;
|
|
104
|
+
};
|
|
105
|
+
} ? K extends string ? K : never : never;
|
|
106
|
+
type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
|
|
107
|
+
query: infer Q;
|
|
108
|
+
} ? Q : never;
|
|
109
|
+
type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
|
|
110
|
+
body: infer B;
|
|
111
|
+
} ? B : never;
|
|
112
|
+
|
|
5
113
|
interface SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins extends PluginArray> {
|
|
6
114
|
api: TApi;
|
|
7
115
|
stateManager: StateManager;
|
|
@@ -18,48 +126,214 @@ type QueryRequestOptions = CoreRequestOptionsBase;
|
|
|
18
126
|
type MutationRequestOptions = CoreRequestOptionsBase;
|
|
19
127
|
type AngularOptionsMap = MethodOptionsMap<QueryRequestOptions, MutationRequestOptions>;
|
|
20
128
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
129
|
+
declare function createInjectQueue<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TQueueFn extends (api: QueueApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>>(queueFn: TQueueFn, queueOptions?: ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
130
|
+
queueOptions: infer Q;
|
|
131
|
+
} ? Q : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
132
|
+
queueOptions: infer Q;
|
|
133
|
+
} ? Q : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TQueueFn extends (...args: any[]) => infer R ? Extract<Awaited<R>, {
|
|
134
|
+
data: unknown;
|
|
135
|
+
error?: undefined;
|
|
136
|
+
}> extends {
|
|
137
|
+
data: infer D;
|
|
138
|
+
} ? D : unknown : unknown, [TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
139
|
+
error: unknown;
|
|
140
|
+
data?: undefined;
|
|
141
|
+
}> extends {
|
|
142
|
+
error: infer E;
|
|
143
|
+
} ? E : unknown : unknown] extends [unknown] ? TDefaultError : TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
144
|
+
error: unknown;
|
|
145
|
+
data?: undefined;
|
|
146
|
+
}> extends {
|
|
147
|
+
error: infer E;
|
|
148
|
+
} ? E : unknown : unknown, ExtractMethodQuery<TQueueFn>, ExtractMethodBody<TQueueFn>, ExtractResponseParamNames<TQueueFn> extends never ? never : Record<ExtractResponseParamNames<TQueueFn>, string | number>>> & InjectQueueOptions) => BaseQueueResult<TQueueFn extends (...args: any[]) => infer R ? Extract<Awaited<R>, {
|
|
149
|
+
data: unknown;
|
|
150
|
+
error?: undefined;
|
|
151
|
+
}> extends {
|
|
152
|
+
data: infer D;
|
|
153
|
+
} ? D : unknown : unknown, [TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
154
|
+
error: unknown;
|
|
155
|
+
data?: undefined;
|
|
156
|
+
}> extends {
|
|
157
|
+
error: infer E;
|
|
158
|
+
} ? E : unknown : unknown] extends [unknown] ? TDefaultError : TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
159
|
+
error: unknown;
|
|
160
|
+
data?: undefined;
|
|
161
|
+
}> extends {
|
|
162
|
+
error: infer E;
|
|
163
|
+
} ? E : unknown : unknown, QueueTriggerInput<TQueueFn> & ResolveTypes<((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
|
|
164
|
+
queueTriggerOptions: infer Q_1;
|
|
165
|
+
} ? Q_1 : object : object : never : never) extends infer T_4 ? T_4 extends (TPlugins[number] extends infer T_5 ? T_5 extends TPlugins[number] ? T_5 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
|
|
166
|
+
queueTriggerOptions: infer Q_1;
|
|
167
|
+
} ? Q_1 : object : object : never : never) ? T_4 extends unknown ? (x: T_4) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TQueueFn extends (...args: any[]) => infer R ? Extract<Awaited<R>, {
|
|
168
|
+
data: unknown;
|
|
169
|
+
error?: undefined;
|
|
170
|
+
}> extends {
|
|
171
|
+
data: infer D;
|
|
172
|
+
} ? D : unknown : unknown, [TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
173
|
+
error: unknown;
|
|
174
|
+
data?: undefined;
|
|
175
|
+
}> extends {
|
|
176
|
+
error: infer E;
|
|
177
|
+
} ? E : unknown : unknown] extends [unknown] ? TDefaultError : TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
178
|
+
error: unknown;
|
|
179
|
+
data?: undefined;
|
|
180
|
+
}> extends {
|
|
181
|
+
error: infer E;
|
|
182
|
+
} ? E : unknown : unknown, ExtractMethodQuery<TQueueFn>, ExtractMethodBody<TQueueFn>, ExtractResponseParamNames<TQueueFn> extends never ? never : Record<ExtractResponseParamNames<TQueueFn>, string | number>>>, ResolveResultTypes<((TPlugins[number] extends infer T_6 ? T_6 extends TPlugins[number] ? T_6 extends SpooshPlugin<infer Types_2 extends PluginTypeConfig> ? Types_2 extends {
|
|
183
|
+
queueResult: infer Q_2;
|
|
184
|
+
} ? Q_2 : object : object : never : never) extends infer T_7 ? T_7 extends (TPlugins[number] extends infer T_8 ? T_8 extends TPlugins[number] ? T_8 extends SpooshPlugin<infer Types_2 extends PluginTypeConfig> ? Types_2 extends {
|
|
185
|
+
queueResult: infer Q_2;
|
|
186
|
+
} ? Q_2 : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolveTypes<((TPlugins[number] extends infer T_9 ? T_9 extends TPlugins[number] ? T_9 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
187
|
+
queueOptions: infer Q;
|
|
188
|
+
} ? Q : object : object : never : never) extends infer T_10 ? T_10 extends (TPlugins[number] extends infer T_11 ? T_11 extends TPlugins[number] ? T_11 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
189
|
+
queueOptions: infer Q;
|
|
190
|
+
} ? Q : object : object : never : never) ? T_10 extends unknown ? (x: T_10) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TQueueFn extends (...args: any[]) => infer R ? Extract<Awaited<R>, {
|
|
191
|
+
data: unknown;
|
|
192
|
+
error?: undefined;
|
|
193
|
+
}> extends {
|
|
194
|
+
data: infer D;
|
|
195
|
+
} ? D : unknown : unknown, [TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
196
|
+
error: unknown;
|
|
197
|
+
data?: undefined;
|
|
198
|
+
}> extends {
|
|
199
|
+
error: infer E;
|
|
200
|
+
} ? E : unknown : unknown] extends [unknown] ? TDefaultError : TQueueFn extends (...args: any[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
201
|
+
error: unknown;
|
|
202
|
+
data?: undefined;
|
|
203
|
+
}> extends {
|
|
204
|
+
error: infer E;
|
|
205
|
+
} ? E : unknown : unknown, ExtractMethodQuery<TQueueFn>, ExtractMethodBody<TQueueFn>, ExtractResponseParamNames<TQueueFn> extends never ? never : Record<ExtractResponseParamNames<TQueueFn>, string | number>>> & InjectQueueOptions>>;
|
|
206
|
+
|
|
207
|
+
type TriggerAwaitedReturn$1<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
208
|
+
type ExtractInputFromResponse$2<T> = T extends {
|
|
209
|
+
input: infer I;
|
|
210
|
+
} ? I : never;
|
|
211
|
+
type BaseTriggerOptions = {
|
|
212
|
+
/** Bypass cache and force refetch. Default: true */
|
|
213
|
+
force?: boolean;
|
|
25
214
|
};
|
|
26
|
-
|
|
215
|
+
type PagesTriggerOptions<TReadFn> = ExtractInputFromResponse$2<TriggerAwaitedReturn$1<TReadFn>> extends infer I ? [I] extends [never] ? BaseTriggerOptions : ExtractTriggerQuery$2<I> & ExtractTriggerBody$2<I> & ExtractTriggerParams$2<I> & BaseTriggerOptions : BaseTriggerOptions;
|
|
216
|
+
/**
|
|
217
|
+
* Options for `injectPages`.
|
|
218
|
+
*
|
|
219
|
+
* @template TData - The response data type for each page
|
|
220
|
+
* @template TItem - The item type after merging all pages
|
|
221
|
+
* @template TError - The error type
|
|
222
|
+
* @template TRequest - The request options type
|
|
223
|
+
* @template TMeta - Plugin metadata type
|
|
224
|
+
*/
|
|
225
|
+
interface BasePagesOptions<TData, TItem, TError = unknown, TRequest = object, TMeta = Record<string, unknown>> extends TagOptions {
|
|
27
226
|
enabled?: EnabledOption;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Callback to determine if there's a next page to fetch.
|
|
229
|
+
* Receives the last page to check for pagination indicators.
|
|
230
|
+
* Default: `() => false` (no next page fetching)
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```ts
|
|
234
|
+
* canFetchNext: ({ lastPage }) => lastPage?.data?.nextCursor != null
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
canFetchNext?: (ctx: InfiniteNextContext<TData, TError, TRequest, TMeta>) => boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Callback to determine if there's a previous page to fetch.
|
|
240
|
+
* Receives the first page to check for pagination indicators.
|
|
241
|
+
* Default: `() => false` (no previous page fetching)
|
|
242
|
+
*/
|
|
243
|
+
canFetchPrev?: (ctx: InfinitePrevContext<TData, TError, TRequest, TMeta>) => boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Callback to build the request options for the next page.
|
|
246
|
+
* Return only the fields that change - they will be **merged** with the initial request.
|
|
247
|
+
* Default: `() => ({})` (no changes to request)
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* // Initial: { query: { cursor: 0, limit: 10 } }
|
|
252
|
+
* // Only return cursor - limit is preserved automatically
|
|
253
|
+
* nextPageRequest: ({ lastPage }) => ({
|
|
254
|
+
* query: { cursor: lastPage?.data?.nextCursor }
|
|
255
|
+
* })
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
nextPageRequest?: (ctx: InfiniteNextContext<TData, TError, TRequest, TMeta>) => Partial<TRequest>;
|
|
259
|
+
/**
|
|
260
|
+
* Callback to build the request options for the previous page.
|
|
261
|
+
* Return only the fields that change - they will be **merged** with the initial request.
|
|
262
|
+
*/
|
|
263
|
+
prevPageRequest?: (ctx: InfinitePrevContext<TData, TError, TRequest, TMeta>) => Partial<TRequest>;
|
|
264
|
+
/**
|
|
265
|
+
* Callback to merge all pages into a single array of items.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* merger: (pages) => pages.flatMap(p => p.data?.items ?? [])
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
merger: (pages: InfinitePage<TData, TError, TMeta>[]) => TItem[];
|
|
33
273
|
}
|
|
34
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Result returned by `injectPages`.
|
|
276
|
+
*
|
|
277
|
+
* @template TData - The response data type for each page
|
|
278
|
+
* @template TError - The error type
|
|
279
|
+
* @template TItem - The item type after merging all pages
|
|
280
|
+
* @template TPluginResult - Plugin-provided result fields
|
|
281
|
+
* @template TTriggerOptions - Options that can be passed to trigger()
|
|
282
|
+
*/
|
|
283
|
+
interface BasePagesResult<TData, TError, TItem, TPluginResult = Record<string, unknown>, TTriggerOptions = object> {
|
|
284
|
+
/** Merged items from all fetched pages */
|
|
35
285
|
data: Signal<TItem[] | undefined>;
|
|
36
|
-
|
|
286
|
+
/** Array of all pages with status, data, error, and meta per page */
|
|
287
|
+
pages: Signal<InfinitePage<TData, TError, TPluginResult>[]>;
|
|
288
|
+
/** Error from the last failed request */
|
|
37
289
|
error: Signal<TError | undefined>;
|
|
290
|
+
/** True during the initial load (no data yet) */
|
|
38
291
|
loading: Signal<boolean>;
|
|
292
|
+
/** True during any fetch operation */
|
|
39
293
|
fetching: Signal<boolean>;
|
|
294
|
+
/** True while fetching the next page */
|
|
40
295
|
fetchingNext: Signal<boolean>;
|
|
296
|
+
/** True while fetching the previous page */
|
|
41
297
|
fetchingPrev: Signal<boolean>;
|
|
298
|
+
/** Whether there's a next page available to fetch */
|
|
42
299
|
canFetchNext: Signal<boolean>;
|
|
300
|
+
/** Whether there's a previous page available to fetch */
|
|
43
301
|
canFetchPrev: Signal<boolean>;
|
|
44
|
-
|
|
302
|
+
/** Fetch the next page */
|
|
45
303
|
fetchNext: () => Promise<void>;
|
|
304
|
+
/** Fetch the previous page */
|
|
46
305
|
fetchPrev: () => Promise<void>;
|
|
47
|
-
|
|
306
|
+
/** Trigger refetch of all pages from the beginning, optionally with new request options */
|
|
307
|
+
trigger: (options?: TTriggerOptions) => Promise<void>;
|
|
308
|
+
/** Abort the current fetch operation */
|
|
48
309
|
abort: () => void;
|
|
49
310
|
}
|
|
50
|
-
type
|
|
311
|
+
type PagesApiClient<TSchema, TDefaultError> = ReadClient<TSchema, TDefaultError>;
|
|
51
312
|
|
|
52
|
-
|
|
53
|
-
declare function createInjectInfiniteRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: InfiniteReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions, TItem = unknown>(readFn: TReadFn, readOptions: BaseInfiniteReadOptions<TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
|
|
313
|
+
declare function createInjectPages<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: PagesApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TRequest extends InfiniteRequestOptions = InfiniteRequestOptions, TItem = unknown>(readFn: TReadFn, readOptions: BasePagesOptions<TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
|
|
54
314
|
data: unknown;
|
|
55
315
|
error?: undefined;
|
|
56
316
|
}> extends {
|
|
57
317
|
data: infer D;
|
|
58
|
-
} ? D : unknown : unknown, TItem,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
318
|
+
} ? D : unknown : unknown, TItem, [TReadFn extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
319
|
+
error: unknown;
|
|
320
|
+
data?: undefined;
|
|
321
|
+
}> extends {
|
|
322
|
+
error: infer E;
|
|
323
|
+
} ? E : unknown : unknown] extends [unknown] ? TDefaultError : TReadFn extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
|
|
324
|
+
error: unknown;
|
|
325
|
+
data?: undefined;
|
|
326
|
+
}> extends {
|
|
327
|
+
error: infer E;
|
|
328
|
+
} ? E : unknown : unknown, TRequest, ((TPlugins[number] extends infer T_3 ? T_3 extends TPlugins[number] ? T_3 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
329
|
+
readResult: infer R_2;
|
|
330
|
+
} ? R_2 : object : object : never : never) extends infer T_4 ? T_4 extends (TPlugins[number] extends infer T_5 ? T_5 extends TPlugins[number] ? T_5 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
331
|
+
readResult: infer R_2;
|
|
332
|
+
} ? R_2 : object : object : never : never) ? T_4 extends unknown ? (x: T_4) => void : never : never : never) extends (x: infer I) => void ? I : never> & ResolveTypes<((TPlugins[number] extends infer T_6 ? T_6 extends TPlugins[number] ? T_6 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
|
|
333
|
+
pagesOptions: infer I_1;
|
|
334
|
+
} ? I_1 : object : object : never : never) extends infer T_7 ? T_7 extends (TPlugins[number] extends infer T_8 ? T_8 extends TPlugins[number] ? T_8 extends SpooshPlugin<infer Types_1 extends PluginTypeConfig> ? Types_1 extends {
|
|
335
|
+
pagesOptions: infer I_1;
|
|
336
|
+
} ? I_1 : object : object : never : never) ? T_7 extends unknown ? (x: T_7) => void : never : never : never) extends (x: infer I) => void ? I : never, ResolverContext<TSchema, TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
|
|
63
337
|
data: unknown;
|
|
64
338
|
error?: undefined;
|
|
65
339
|
}> extends {
|
|
@@ -74,7 +348,7 @@ declare function createInjectInfiniteRead<TSchema, TDefaultError, TPlugins exten
|
|
|
74
348
|
data?: undefined;
|
|
75
349
|
}> extends {
|
|
76
350
|
error: infer E;
|
|
77
|
-
} ? E : unknown : unknown>>) =>
|
|
351
|
+
} ? E : unknown : unknown>>) => BasePagesResult<TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
|
|
78
352
|
data: unknown;
|
|
79
353
|
error?: undefined;
|
|
80
354
|
}> extends {
|
|
@@ -93,7 +367,7 @@ declare function createInjectInfiniteRead<TSchema, TDefaultError, TPlugins exten
|
|
|
93
367
|
readResult: infer R_2;
|
|
94
368
|
} ? R_2 : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
95
369
|
readResult: infer R_2;
|
|
96
|
-
} ? R_2 : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never
|
|
370
|
+
} ? R_2 : object : object : never : never) ? T_1 extends unknown ? (x: T_1) => void : never : never : never) extends (x: infer I) => void ? I : never, PagesTriggerOptions<TReadFn>>;
|
|
97
371
|
|
|
98
372
|
type OptionalQueryField<TQuery> = [TQuery] extends [never] ? object : undefined extends TQuery ? {
|
|
99
373
|
query?: Exclude<TQuery, undefined>;
|
|
@@ -126,67 +400,28 @@ type TriggerAwaitedReturn<T> = T extends (...args: any[]) => infer R ? Awaited<R
|
|
|
126
400
|
type ExtractInputFromResponse$1<T> = T extends {
|
|
127
401
|
input: infer I;
|
|
128
402
|
} ? I : never;
|
|
129
|
-
type ExtractTriggerQuery
|
|
403
|
+
type ExtractTriggerQuery<I> = I extends {
|
|
130
404
|
query: infer Q;
|
|
131
405
|
} ? undefined extends Q ? {
|
|
132
406
|
query?: Exclude<Q, undefined>;
|
|
133
407
|
} : {
|
|
134
408
|
query: Q;
|
|
135
409
|
} : unknown;
|
|
136
|
-
type ExtractTriggerBody
|
|
410
|
+
type ExtractTriggerBody<I> = I extends {
|
|
137
411
|
body: infer B;
|
|
138
412
|
} ? undefined extends B ? {
|
|
139
413
|
body?: Exclude<B, undefined> | SpooshBody<Exclude<B, undefined>>;
|
|
140
414
|
} : {
|
|
141
415
|
body: B | SpooshBody<B>;
|
|
142
416
|
} : unknown;
|
|
143
|
-
type ExtractTriggerParams
|
|
417
|
+
type ExtractTriggerParams<I> = I extends {
|
|
144
418
|
params: infer P;
|
|
145
419
|
} ? {
|
|
146
420
|
params: P;
|
|
147
421
|
} : unknown;
|
|
148
|
-
type WriteTriggerInput<T> = ExtractInputFromResponse$1<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? object : ExtractTriggerQuery
|
|
422
|
+
type WriteTriggerInput<T> = ExtractInputFromResponse$1<TriggerAwaitedReturn<T>> extends infer I ? [I] extends [never] ? object : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> : object;
|
|
149
423
|
type WriteApiClient<TSchema, TDefaultError> = WriteSelectorClient<TSchema, TDefaultError>;
|
|
150
424
|
|
|
151
|
-
type SuccessResponse<T> = Extract<T, {
|
|
152
|
-
data: unknown;
|
|
153
|
-
error?: undefined;
|
|
154
|
-
}>;
|
|
155
|
-
type ErrorResponse<T> = Extract<T, {
|
|
156
|
-
error: unknown;
|
|
157
|
-
data?: undefined;
|
|
158
|
-
}>;
|
|
159
|
-
type ExtractMethodData<T> = T extends (...args: never[]) => infer R ? SuccessResponse<Awaited<R>> extends {
|
|
160
|
-
data: infer D;
|
|
161
|
-
} ? D : unknown : unknown;
|
|
162
|
-
type ExtractMethodError<T> = T extends (...args: never[]) => infer R ? ErrorResponse<Awaited<R>> extends {
|
|
163
|
-
error: infer E;
|
|
164
|
-
} ? E : unknown : unknown;
|
|
165
|
-
type ExtractMethodOptions<T> = T extends (options?: infer O) => Promise<unknown> ? O : never;
|
|
166
|
-
type AwaitedReturnType<T> = T extends (...args: never[]) => infer R ? Awaited<R> : never;
|
|
167
|
-
type SuccessReturnType<T> = SuccessResponse<AwaitedReturnType<T>>;
|
|
168
|
-
type ExtractResponseQuery<T> = SuccessReturnType<T> extends {
|
|
169
|
-
input: {
|
|
170
|
-
query: infer Q;
|
|
171
|
-
};
|
|
172
|
-
} ? Q : never;
|
|
173
|
-
type ExtractResponseBody<T> = SuccessReturnType<T> extends {
|
|
174
|
-
input: {
|
|
175
|
-
body: infer B;
|
|
176
|
-
};
|
|
177
|
-
} ? B : never;
|
|
178
|
-
type ExtractResponseParamNames<T> = SuccessReturnType<T> extends {
|
|
179
|
-
input: {
|
|
180
|
-
params: Record<infer K, unknown>;
|
|
181
|
-
};
|
|
182
|
-
} ? K extends string ? K : never : never;
|
|
183
|
-
type ExtractMethodQuery<T> = ExtractMethodOptions<T> extends {
|
|
184
|
-
query: infer Q;
|
|
185
|
-
} ? Q : never;
|
|
186
|
-
type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
|
|
187
|
-
body: infer B;
|
|
188
|
-
} ? B : never;
|
|
189
|
-
|
|
190
425
|
declare function createInjectWrite<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TWriteFn extends (api: WriteApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TWriteOpts extends _spoosh_core.ResolveTypes<((TPlugins[number] extends infer T ? T extends TPlugins[number] ? T extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
191
426
|
writeOptions: infer W;
|
|
192
427
|
} ? W : object : object : never : never) extends infer T_1 ? T_1 extends (TPlugins[number] extends infer T_2 ? T_2 extends TPlugins[number] ? T_2 extends SpooshPlugin<infer Types extends PluginTypeConfig> ? Types extends {
|
|
@@ -293,24 +528,9 @@ type AwaitedReturnTypeTrigger<T> = T extends (...args: never[]) => infer R ? Awa
|
|
|
293
528
|
type ExtractInputFromResponse<T> = T extends {
|
|
294
529
|
input: infer I;
|
|
295
530
|
} ? I : never;
|
|
296
|
-
type ExtractTriggerQuery<I> = I extends {
|
|
297
|
-
query: infer Q;
|
|
298
|
-
} ? {
|
|
299
|
-
query?: Q;
|
|
300
|
-
} : unknown;
|
|
301
|
-
type ExtractTriggerBody<I> = I extends {
|
|
302
|
-
body: infer B;
|
|
303
|
-
} ? {
|
|
304
|
-
body?: B;
|
|
305
|
-
} : unknown;
|
|
306
|
-
type ExtractTriggerParams<I> = I extends {
|
|
307
|
-
params: infer P;
|
|
308
|
-
} ? {
|
|
309
|
-
params?: P;
|
|
310
|
-
} : unknown;
|
|
311
531
|
type TriggerOptions<T> = ExtractInputFromResponse<AwaitedReturnTypeTrigger<T>> extends infer I ? [I] extends [never] ? {
|
|
312
532
|
force?: boolean;
|
|
313
|
-
} : ExtractTriggerQuery<I> & ExtractTriggerBody<I> & ExtractTriggerParams<I> & {
|
|
533
|
+
} : ExtractTriggerQuery$2<I> & ExtractTriggerBody$2<I> & ExtractTriggerParams$2<I> & {
|
|
314
534
|
/** Force refetch even if data is cached */
|
|
315
535
|
force?: boolean;
|
|
316
536
|
} : {
|
|
@@ -399,9 +619,10 @@ declare function createInjectRead<TSchema, TDefaultError, TPlugins extends reado
|
|
|
399
619
|
type SpooshAngularFunctions<TDefaultError, TSchema, TPlugins extends PluginArray> = {
|
|
400
620
|
injectRead: ReturnType<typeof createInjectRead<TSchema, TDefaultError, TPlugins>>;
|
|
401
621
|
injectWrite: ReturnType<typeof createInjectWrite<TSchema, TDefaultError, TPlugins>>;
|
|
402
|
-
|
|
622
|
+
injectPages: ReturnType<typeof createInjectPages<TSchema, TDefaultError, TPlugins>>;
|
|
623
|
+
injectQueue: ReturnType<typeof createInjectQueue<TSchema, TDefaultError, TPlugins>>;
|
|
403
624
|
} & MergePluginInstanceApi<TPlugins, TSchema>;
|
|
404
625
|
|
|
405
626
|
declare function create<TSchema, TDefaultError, TPlugins extends PluginArray, TApi>(instance: SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins>): SpooshAngularFunctions<TDefaultError, TSchema, TPlugins>;
|
|
406
627
|
|
|
407
|
-
export { type AngularOptionsMap, type
|
|
628
|
+
export { type AngularOptionsMap, type BasePagesOptions, type BasePagesResult, type BaseQueueResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type EnabledOption, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type InjectQueueOptions, type PagesApiClient, type PagesTriggerOptions, type QueueApiClient, type QueueTriggerInput, type ReadApiClient, type ResponseInputFields, type SpooshInstanceShape, type TriggerOptions, type WriteApiClient, type WriteResponseInputFields, create };
|