@ethlete/query 6.0.0-next.51 → 6.0.0-next.53
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/CHANGELOG.md +78 -0
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs +393 -0
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs.map +1 -0
- package/fesm2022/ethlete-query-testing.mjs +67 -25
- package/fesm2022/ethlete-query-testing.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +7895 -7226
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/generators.json +5 -0
- package/generators/migrate-from-ngrx-toolkit/args-assignability.js +140 -0
- package/generators/migrate-from-ngrx-toolkit/consumers.js +521 -0
- package/generators/migrate-from-ngrx-toolkit/creators.js +301 -0
- package/generators/migrate-from-ngrx-toolkit/facade.js +295 -0
- package/generators/migrate-from-ngrx-toolkit/feature.js +513 -0
- package/generators/migrate-from-ngrx-toolkit/migration.js +140 -0
- package/generators/migrate-from-ngrx-toolkit/report.js +154 -0
- package/generators/migrate-from-ngrx-toolkit/schema.json +42 -0
- package/generators/migrate-from-ngrx-toolkit/store-removal.js +633 -0
- package/generators/migrate-from-ngrx-toolkit/ts-edits.js +128 -0
- package/generators/migrate-query-opt-in-features/migration.js +10 -9
- package/generators/migrate-to-query-v3/auth-provider-scaffold.js +29 -2
- package/generators/migrate-to-query-v3/cleanup-migration.js +163 -53
- package/generators/migrate-to-query-v3/legacy-query-creator-migration.js +39 -2
- package/generators/migrate-to-query-v3/migration-scope.js +2 -0
- package/generators/migrate-to-query-v3/migration.js +5 -4
- package/generators/migrate-to-query-v3/module-graph.js +41 -29
- package/generators/migrate-to-query-v3/query-client-migration.js +209 -126
- package/generators/migrate-to-query-v3/rename-symbols.js +38 -11
- package/generators/migrate-to-query-v3/report.js +40 -7
- package/generators/migrate-to-query-v3/shared.js +46 -1
- package/generators/prep-for-query-v3/migration.js +400 -57
- package/migrations/query-field-default-types.md +43 -0
- package/migrations/search-query-field-string.md +43 -0
- package/migrations.json +16 -0
- package/package.json +5 -1
- package/types/ethlete-query-ngrx-toolkit.d.ts +143 -0
- package/types/ethlete-query-testing.d.ts +28 -11
- package/types/ethlete-query.d.ts +789 -584
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { PipeTransform, Injector } from '@angular/core';
|
|
3
|
+
import { Observable, Subject } from 'rxjs';
|
|
4
|
+
import { AnyQueryCreator, QueryArgsOf, QueryHeaders, ResponseType } from '@ethlete/query';
|
|
5
|
+
|
|
6
|
+
/** The call state of a toolkit handle, as `@tomtomb/ngrx-toolkit` names it. */
|
|
7
|
+
declare const CallState: {
|
|
8
|
+
readonly INIT: "INIT";
|
|
9
|
+
readonly LOADING: "LOADING";
|
|
10
|
+
readonly SUCCESS: "SUCCESS";
|
|
11
|
+
readonly ERROR: "ERROR";
|
|
12
|
+
};
|
|
13
|
+
type CallState = (typeof CallState)[keyof typeof CallState];
|
|
14
|
+
/** The error shape of `@tomtomb/ngrx-toolkit`: the HTTP status, the error message and the response body. */
|
|
15
|
+
type ToolkitError<T = unknown> = {
|
|
16
|
+
status: number | string;
|
|
17
|
+
message: string;
|
|
18
|
+
data: T | null;
|
|
19
|
+
};
|
|
20
|
+
type ToolkitActionOptions = {
|
|
21
|
+
headers?: QueryHeaders;
|
|
22
|
+
extras?: {
|
|
23
|
+
skipCache?: boolean;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The toolkit-shaped args of a query creator: `queryParams` holds the path params, `params` the query string and
|
|
28
|
+
* `body` the body, the way `@tomtomb/ngrx-toolkit` action groups named them.
|
|
29
|
+
*/
|
|
30
|
+
type ActionCallArgs<TCreator extends AnyQueryCreator> = {
|
|
31
|
+
[K in keyof QueryArgsOf<TCreator> as K extends 'pathParams' ? 'queryParams' : K extends 'queryParams' ? 'params' : K extends 'body' ? 'body' : never]: QueryArgsOf<TCreator>[K];
|
|
32
|
+
} & {
|
|
33
|
+
actionOptions?: ToolkitActionOptions;
|
|
34
|
+
};
|
|
35
|
+
type ToolkitPollingOptions = {
|
|
36
|
+
intervalDuration: number;
|
|
37
|
+
killSwitch: Subject<boolean>;
|
|
38
|
+
};
|
|
39
|
+
/** The handle `toolkitCall` returns, shaped like the `MappedEntityState` of `@tomtomb/ngrx-toolkit`. */
|
|
40
|
+
type MappedEntityState<TCreator extends AnyQueryCreator> = {
|
|
41
|
+
response$: Observable<ResponseType<QueryArgsOf<TCreator>> | null>;
|
|
42
|
+
cachedResponse$: Observable<ResponseType<QueryArgsOf<TCreator>>>;
|
|
43
|
+
error$: Observable<ToolkitError | null>;
|
|
44
|
+
args$: Observable<ActionCallArgs<TCreator> | null>;
|
|
45
|
+
isInit$: Observable<boolean | null>;
|
|
46
|
+
isLoading$: Observable<boolean | null>;
|
|
47
|
+
isSuccess$: Observable<boolean | null>;
|
|
48
|
+
isError$: Observable<boolean | null>;
|
|
49
|
+
timestamp$: Observable<number | null>;
|
|
50
|
+
callState$: Observable<CallState | null>;
|
|
51
|
+
refresh: () => void;
|
|
52
|
+
remove: () => void;
|
|
53
|
+
startPolling: (options: ToolkitPollingOptions) => void;
|
|
54
|
+
stopPolling: () => void;
|
|
55
|
+
};
|
|
56
|
+
type AnyMappedEntityState = MappedEntityState<any>;
|
|
57
|
+
|
|
58
|
+
type ExtractFrom<T> = T extends Observable<infer U> ? U : never;
|
|
59
|
+
/** What `suspense` and `suspenseMulti` render for a handle: every stream's current value, plus the handle's methods. */
|
|
60
|
+
type ToolkitSuspenseState<T extends AnyMappedEntityState | null | undefined> = T extends AnyMappedEntityState ? {
|
|
61
|
+
args: ExtractFrom<T['args$']>;
|
|
62
|
+
cachedResponse: ExtractFrom<T['cachedResponse$']> | null;
|
|
63
|
+
callState: ExtractFrom<T['callState$']>;
|
|
64
|
+
error: ExtractFrom<T['error$']>;
|
|
65
|
+
isError: ExtractFrom<T['isError$']>;
|
|
66
|
+
isInit: ExtractFrom<T['isInit$']>;
|
|
67
|
+
isLoading: ExtractFrom<T['isLoading$']>;
|
|
68
|
+
isSuccess: ExtractFrom<T['isSuccess$']>;
|
|
69
|
+
response: ExtractFrom<T['response$']>;
|
|
70
|
+
timestamp: ExtractFrom<T['timestamp$']>;
|
|
71
|
+
refresh: () => void;
|
|
72
|
+
remove: () => void;
|
|
73
|
+
startPolling: (options: ToolkitPollingOptions) => void;
|
|
74
|
+
stopPolling: () => void;
|
|
75
|
+
} : T;
|
|
76
|
+
/** Subscribes to a toolkit handle and renders its current state, like the `suspense` pipe of `@tomtomb/ngrx-toolkit`. */
|
|
77
|
+
declare class SuspensePipe implements PipeTransform {
|
|
78
|
+
transform: <T extends AnyMappedEntityState>(value: T | null | undefined) => ToolkitSuspenseState<T>;
|
|
79
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SuspensePipe, never>;
|
|
80
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<SuspensePipe, "suspense", true>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
type AnyHandleRecord = Record<string, AnyMappedEntityState | null | undefined>;
|
|
84
|
+
type ToolkitSuspenseMultiState<T extends AnyHandleRecord> = {
|
|
85
|
+
[K in keyof T]: ToolkitSuspenseState<T[K]>;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Subscribes to a record of toolkit handles and renders each one's current state, like the `suspenseMulti` pipe of
|
|
89
|
+
* `@tomtomb/ngrx-toolkit`. Nothing renders until every non-null handle has emitted.
|
|
90
|
+
*/
|
|
91
|
+
declare class SuspenseMultiPipe implements PipeTransform {
|
|
92
|
+
transform: <T extends AnyHandleRecord>(value: T | null | undefined) => ToolkitSuspenseMultiState<T>;
|
|
93
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SuspenseMultiPipe, never>;
|
|
94
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<SuspenseMultiPipe, "suspenseMulti", true>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Exports the `suspense` and `suspenseMulti` pipes, like the `NgRxToolkitModule` of `@tomtomb/ngrx-toolkit`. */
|
|
98
|
+
declare class NgRxToolkitModule {
|
|
99
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgRxToolkitModule, never>;
|
|
100
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<NgRxToolkitModule, never, [typeof SuspensePipe, typeof SuspenseMultiPipe], [typeof SuspensePipe, typeof SuspenseMultiPipe]>;
|
|
101
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<NgRxToolkitModule>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
type ToolkitCallOptions = {
|
|
105
|
+
/**
|
|
106
|
+
* The injector the handle's query lives in. Required outside an injection context, which is where a
|
|
107
|
+
* `providedIn: 'root'` facade calls from; pass the facade's `inject(Injector)`.
|
|
108
|
+
*/
|
|
109
|
+
injector?: Injector;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Returns the handle for a creator and args without executing it - the `FacadeBase.select(group, actionId)` of
|
|
113
|
+
* `@tomtomb/ngrx-toolkit`. Args that build the same request (in any key order, other keys ignored) give the same
|
|
114
|
+
* handle `toolkitCall` returns, so `toolkitSelect(getTeam, args, { injector }).refresh()` re-runs a request another
|
|
115
|
+
* component started.
|
|
116
|
+
*/
|
|
117
|
+
declare const toolkitSelect: <TCreator extends AnyQueryCreator>(creator: TCreator, args: ActionCallArgs<TCreator>, options?: ToolkitCallOptions) => MappedEntityState<TCreator>;
|
|
118
|
+
/**
|
|
119
|
+
* Executes a query creator with toolkit-shaped args and returns its handle - the `FacadeBase.call(group, args)` of
|
|
120
|
+
* `@tomtomb/ngrx-toolkit`. Every call sends the request again; equal args return the same handle, which lives as
|
|
121
|
+
* long as the injector.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* @Injectable({ providedIn: 'root' })
|
|
126
|
+
* export class TeamFacade {
|
|
127
|
+
* private injector = inject(Injector);
|
|
128
|
+
*
|
|
129
|
+
* getTeam(args: ActionCallArgs<typeof getTeam>) {
|
|
130
|
+
* return toolkitCall(getTeam, args, { injector: this.injector });
|
|
131
|
+
* }
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare const toolkitCall: <TCreator extends AnyQueryCreator>(creator: TCreator, args: ActionCallArgs<TCreator>, options?: ToolkitCallOptions) => MappedEntityState<TCreator>;
|
|
136
|
+
|
|
137
|
+
/** Emits `true` while any of the given loading streams is `true`. Nullish entries are skipped. */
|
|
138
|
+
declare const joinLoading: (observables: (Observable<boolean | null> | null | undefined)[]) => Observable<boolean>;
|
|
139
|
+
/** Emits every non-null error of the given error streams, or `null` when there is none. Nullish entries are skipped. */
|
|
140
|
+
declare const joinErrors: (observables: (Observable<ToolkitError | null> | null | undefined)[]) => Observable<ToolkitError[] | null>;
|
|
141
|
+
|
|
142
|
+
export { CallState, NgRxToolkitModule, SuspenseMultiPipe, SuspensePipe, joinErrors, joinLoading, toolkitCall, toolkitSelect };
|
|
143
|
+
export type { ActionCallArgs, AnyMappedEntityState, MappedEntityState, ToolkitActionOptions, ToolkitCallOptions, ToolkitError, ToolkitPollingOptions, ToolkitSuspenseMultiState, ToolkitSuspenseState };
|
|
@@ -124,7 +124,7 @@ type AuthTestSetup<TLoginArgs extends {
|
|
|
124
124
|
], TFeatures, TBearerData>;
|
|
125
125
|
/** Helper to login a user and flush the HTTP request */
|
|
126
126
|
login: (credentials: TLoginArgs['body'], response: TLoginArgs['response']) => void;
|
|
127
|
-
/** Helper to trigger a refresh and flush the HTTP request */
|
|
127
|
+
/** Helper to trigger a refresh and flush the HTTP request. Sends `buildRefreshArgs(token)` when configured, else `{ body: { token } }` */
|
|
128
128
|
refresh: (token: string, response: TRefreshArgs['response']) => void;
|
|
129
129
|
/** Helper to make a secure request that requires authentication */
|
|
130
130
|
makeSecureRequest: (route: string) => void;
|
|
@@ -184,9 +184,9 @@ type FakeBroadcastChannelHandle = {
|
|
|
184
184
|
* Replaces `globalThis.BroadcastChannel` with an in-memory bus.
|
|
185
185
|
*
|
|
186
186
|
* Messages are structured-cloned at post time (so a non-cloneable payload throws exactly like the
|
|
187
|
-
* real API does), delivered
|
|
188
|
-
* channel that posted them - all three matching browser behavior.
|
|
189
|
-
*
|
|
187
|
+
* real API does), delivered as a task (never synchronously, and after every pending microtask), and
|
|
188
|
+
* never delivered back to the channel that posted them - all three matching browser behavior. Delivery
|
|
189
|
+
* does not depend on fake timers; `await flushMultiTabSync()` in a spec flushes it.
|
|
190
190
|
*/
|
|
191
191
|
declare const installFakeBroadcastChannel: () => FakeBroadcastChannelHandle;
|
|
192
192
|
type FakeWebLocksHandle = {
|
|
@@ -211,9 +211,9 @@ type FakeWebLocksHandle = {
|
|
|
211
211
|
*/
|
|
212
212
|
declare const installFakeWebLocks: () => FakeWebLocksHandle;
|
|
213
213
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* tab's release needs one await per hop.
|
|
214
|
+
* Waits for the fakes' pending work - message delivery (a task) and lock grants (a microtask) - even
|
|
215
|
+
* under fake timers. Awaiting it once is enough for a single hop; a grant that has to wait for another
|
|
216
|
+
* tab's release, or a reply to a delivered message, needs one await per hop.
|
|
217
217
|
*/
|
|
218
218
|
declare const flushMultiTabSync: () => Promise<void>;
|
|
219
219
|
|
|
@@ -247,7 +247,7 @@ type FakeQueryPersistenceStoreHandle = {
|
|
|
247
247
|
/**
|
|
248
248
|
* Holds every subsequent `read` pending until {@link flushReads} is called, for testing the window
|
|
249
249
|
* between a cold mount and its hydration (a slow disk, or a mount that happened before startup
|
|
250
|
-
* finished).
|
|
250
|
+
* finished). Each held read returns what the store held when it started, as `loadIndex` does.
|
|
251
251
|
*/
|
|
252
252
|
deferReads: () => void;
|
|
253
253
|
/** Settles the reads held by {@link deferReads} and stops deferring. */
|
|
@@ -295,10 +295,16 @@ type WebSocketTestDouble = {
|
|
|
295
295
|
event: string;
|
|
296
296
|
data: unknown;
|
|
297
297
|
}[];
|
|
298
|
-
/**
|
|
298
|
+
/**
|
|
299
|
+
* Whether the client asked the socket to connect, and whether it has since disconnected it. `active` is
|
|
300
|
+
* socket.io's own flag - `false` after a server disconnect or a rejected handshake, until the next
|
|
301
|
+
* `connect()`; `connectCalls` counts every `connect()`.
|
|
302
|
+
*/
|
|
299
303
|
state: () => {
|
|
300
304
|
connectRequested: boolean;
|
|
301
305
|
disconnected: boolean;
|
|
306
|
+
active: boolean;
|
|
307
|
+
connectCalls: number;
|
|
302
308
|
};
|
|
303
309
|
/**
|
|
304
310
|
* Complete the handshake: flush every buffered emit, then turn the client's `isConnected` true. Pass
|
|
@@ -307,8 +313,19 @@ type WebSocketTestDouble = {
|
|
|
307
313
|
serverConnect: (options?: {
|
|
308
314
|
recovered?: boolean;
|
|
309
315
|
}) => void;
|
|
310
|
-
/**
|
|
311
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Drop the connection, so `isConnected` turns false. The default reason, `'transport close'`, is one
|
|
318
|
+
* socket.io recovers from itself; `'io server disconnect'` is the server kicking the socket, after which
|
|
319
|
+
* socket.io only reconnects when `connect()` is called again.
|
|
320
|
+
*/
|
|
321
|
+
serverDisconnect: (options?: {
|
|
322
|
+
reason?: 'transport close' | 'io server disconnect';
|
|
323
|
+
}) => void;
|
|
324
|
+
/**
|
|
325
|
+
* Reject the handshake the way a server middleware does: the `auth` payload is recorded in
|
|
326
|
+
* {@link handshakes}, `connect_error` fires and the socket stops reconnecting on its own.
|
|
327
|
+
*/
|
|
328
|
+
serverRejectHandshake: (message?: string) => void;
|
|
312
329
|
/**
|
|
313
330
|
* Let the ping expire: the socket still reports itself connected, but buffers every emit like socket.io
|
|
314
331
|
* does until it notices and closes. Follow it with {@link serverDisconnect}.
|