appflare 0.2.3 → 0.2.4
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/Documentation.md +3 -7
- package/cli/templates/core/client/handlers/index.ts +25 -7
- package/cli/templates/core/client/types.ts +23 -10
- package/package.json +1 -1
- package/react/use-infinite-query.ts +79 -17
- package/react/use-mutation.ts +46 -11
- package/react/use-query.ts +65 -16
package/Documentation.md
CHANGED
|
@@ -604,13 +604,9 @@ import { useMutation } from "appflare/react";
|
|
|
604
604
|
import { appflare } from "./appflare-client";
|
|
605
605
|
|
|
606
606
|
export function CreatePostButton() {
|
|
607
|
-
const mutation = useMutation(
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
{
|
|
611
|
-
onSuccess: (data) => console.log("created", data),
|
|
612
|
-
},
|
|
613
|
-
);
|
|
607
|
+
const mutation = useMutation(appflare.mutations.test.newTest, {
|
|
608
|
+
onSuccess: (data) => console.log("created", data),
|
|
609
|
+
});
|
|
614
610
|
|
|
615
611
|
return (
|
|
616
612
|
<button onClick={() => mutation.mutate()} disabled={mutation.isPending}>
|
|
@@ -142,9 +142,9 @@ function renderRouteFactory(operation: HttpOperation): string {
|
|
|
142
142
|
runtime: RequestRuntime,
|
|
143
143
|
): AppflareQueryRouteClient<typeof ${operation.schemaConst}, ${outputType}> => {
|
|
144
144
|
const run: AppflareQueryRouteClient<typeof ${operation.schemaConst}, ${outputType}>["run"] = async (
|
|
145
|
-
|
|
146
|
-
options?: AppflareResultRouteCallOptions,
|
|
145
|
+
...params: AppflareRunParams<${inputType}>
|
|
147
146
|
) => {
|
|
147
|
+
const { args, options } = resolveRunParams<${inputType}>(params);
|
|
148
148
|
const mergedOptions = mergeRouteOptions(runtime.options, options);
|
|
149
149
|
const resultOptions: AppflareRouteCallOptions<"return"> = {
|
|
150
150
|
...(mergedOptions ?? {}),
|
|
@@ -168,9 +168,7 @@ function renderRouteFactory(operation: HttpOperation): string {
|
|
|
168
168
|
signal,
|
|
169
169
|
}: AppflareQuerySubscribeOptions<${inputType}, ${outputType}>): AppflareRealtimeSubscription => {
|
|
170
170
|
const mergedOptions = mergeRouteOptions(runtime.options, requestOptions);
|
|
171
|
-
const parsedArgs = ${operation.schemaConst}.parse(
|
|
172
|
-
(args ?? {}) as ${inputType},
|
|
173
|
-
) as ${inputType};
|
|
171
|
+
const parsedArgs = ${operation.schemaConst}.parse(normalizeRouteInput(args));
|
|
174
172
|
const requestAuthToken = resolveRealtimeAuthToken(authToken, mergedOptions?.headers);
|
|
175
173
|
|
|
176
174
|
let removed = false;
|
|
@@ -307,9 +305,9 @@ function renderRouteFactory(operation: HttpOperation): string {
|
|
|
307
305
|
runtime: RequestRuntime,
|
|
308
306
|
): AppflareRouteClient<typeof ${operation.schemaConst}, ${outputType}> => {
|
|
309
307
|
const run: AppflareRouteClient<typeof ${operation.schemaConst}, ${outputType}>["run"] = async (
|
|
310
|
-
|
|
311
|
-
options?: AppflareResultRouteCallOptions,
|
|
308
|
+
...params: AppflareRunParams<${inputType}>
|
|
312
309
|
) => {
|
|
310
|
+
const { args, options } = resolveRunParams<${inputType}>(params);
|
|
313
311
|
const mergedOptions = mergeRouteOptions(runtime.options, options);
|
|
314
312
|
const resultOptions: AppflareRouteCallOptions<"return"> = {
|
|
315
313
|
...(mergedOptions ?? {}),
|
|
@@ -385,6 +383,7 @@ import type {
|
|
|
385
383
|
AppflareResultRouteCallOptions,
|
|
386
384
|
AppflareRouteCallOptions,
|
|
387
385
|
AppflareRouteClient,
|
|
386
|
+
AppflareRunParams,
|
|
388
387
|
} from "./types";
|
|
389
388
|
${imports ? `\n${imports}` : ""}
|
|
390
389
|
|
|
@@ -429,6 +428,25 @@ function mergeRouteOptions(
|
|
|
429
428
|
};
|
|
430
429
|
}
|
|
431
430
|
|
|
431
|
+
function normalizeRouteInput<TInput extends Record<string, unknown>>(
|
|
432
|
+
input: TInput | undefined,
|
|
433
|
+
): TInput {
|
|
434
|
+
return (input ?? {}) as TInput;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function resolveRunParams<TInput extends Record<string, unknown>>(
|
|
438
|
+
params: AppflareRunParams<TInput>,
|
|
439
|
+
): {
|
|
440
|
+
args: TInput;
|
|
441
|
+
options?: AppflareResultRouteCallOptions;
|
|
442
|
+
} {
|
|
443
|
+
const [args, options] = params;
|
|
444
|
+
return {
|
|
445
|
+
args: normalizeRouteInput(args),
|
|
446
|
+
options,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
432
450
|
function readHeaderCaseInsensitive(
|
|
433
451
|
headers: HeadersInit | undefined,
|
|
434
452
|
headerName: string,
|
|
@@ -52,15 +52,30 @@ export type AppflareResultRouteCallOptions = Omit<
|
|
|
52
52
|
"errorMode"
|
|
53
53
|
>;
|
|
54
54
|
|
|
55
|
+
export type AppflareRouteInput<
|
|
56
|
+
TSchema extends import("zod").ZodObject<import("zod").ZodRawShape>,
|
|
57
|
+
> = import("zod").input<TSchema>;
|
|
58
|
+
|
|
59
|
+
type AppflareRequiredInputKeys<TInput extends Record<string, unknown>> = {
|
|
60
|
+
[K in keyof TInput]-?: undefined extends TInput[K] ? never : K;
|
|
61
|
+
}[keyof TInput];
|
|
62
|
+
|
|
63
|
+
type AppflareHasRequiredInputKeys<TInput extends Record<string, unknown>> =
|
|
64
|
+
[AppflareRequiredInputKeys<TInput>] extends [never] ? false : true;
|
|
65
|
+
|
|
66
|
+
export type AppflareRunParams<TInput extends Record<string, unknown>> =
|
|
67
|
+
AppflareHasRequiredInputKeys<TInput> extends true
|
|
68
|
+
? [args: TInput, options?: AppflareResultRouteCallOptions]
|
|
69
|
+
: [args?: TInput, options?: AppflareResultRouteCallOptions];
|
|
70
|
+
|
|
55
71
|
export type AppflareRouteClient<
|
|
56
72
|
TSchema extends import("zod").ZodObject<import("zod").ZodRawShape>,
|
|
57
73
|
TOutput,
|
|
58
74
|
> = {
|
|
59
75
|
schema: TSchema;
|
|
60
|
-
run(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
): Promise<AppflareRequestResult<TOutput>>;
|
|
76
|
+
run(...params: AppflareRunParams<AppflareRouteInput<TSchema>>): Promise<
|
|
77
|
+
AppflareRequestResult<TOutput>
|
|
78
|
+
>;
|
|
64
79
|
};
|
|
65
80
|
|
|
66
81
|
export type AppflareRealtimeSubscription = {
|
|
@@ -100,12 +115,10 @@ export type InferRouteSchema<TRoute> = TRoute extends {
|
|
|
100
115
|
? TSchema
|
|
101
116
|
: never;
|
|
102
117
|
|
|
103
|
-
export type InferRouteInput<TRoute> = TRoute extends
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
?
|
|
107
|
-
? TInput
|
|
108
|
-
: never
|
|
118
|
+
export type InferRouteInput<TRoute> = InferRouteSchema<TRoute> extends import("zod").ZodObject<
|
|
119
|
+
import("zod").ZodRawShape
|
|
120
|
+
>
|
|
121
|
+
? AppflareRouteInput<InferRouteSchema<TRoute>>
|
|
109
122
|
: never;
|
|
110
123
|
|
|
111
124
|
export type InferRouteResult<TRoute> = TRoute extends {
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
hashKey,
|
|
2
3
|
type InfiniteData,
|
|
3
4
|
type QueryKey,
|
|
4
5
|
type UseInfiniteQueryOptions,
|
|
@@ -6,7 +7,7 @@ import {
|
|
|
6
7
|
useInfiniteQuery as useTanstackInfiniteQuery,
|
|
7
8
|
useQueryClient,
|
|
8
9
|
} from "@tanstack/react-query";
|
|
9
|
-
import { useEffect, useMemo } from "react";
|
|
10
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
10
11
|
|
|
11
12
|
type AppflareRequestErrorLike = {
|
|
12
13
|
message: string;
|
|
@@ -31,10 +32,24 @@ type AppflareRealtimeQueryUpdateLike<TData> = {
|
|
|
31
32
|
};
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
type
|
|
35
|
+
type AppflareRequiredInputKeys<TInput extends Record<string, unknown>> = {
|
|
36
|
+
[K in keyof TInput]-?: undefined extends TInput[K] ? never : K;
|
|
37
|
+
}[keyof TInput];
|
|
38
|
+
|
|
39
|
+
type AppflareHasRequiredInputKeys<TInput extends Record<string, unknown>> = [
|
|
40
|
+
AppflareRequiredInputKeys<TInput>,
|
|
41
|
+
] extends [never]
|
|
42
|
+
? false
|
|
43
|
+
: true;
|
|
44
|
+
|
|
45
|
+
type AppflareRouteRunArgs<TInput extends Record<string, unknown>> =
|
|
46
|
+
AppflareHasRequiredInputKeys<TInput> extends true
|
|
47
|
+
? [args: TInput, options?: any]
|
|
48
|
+
: [args?: TInput, options?: any];
|
|
49
|
+
|
|
50
|
+
type AppflareQueryLike<TArgs extends Record<string, unknown>, TData> = {
|
|
35
51
|
run: (
|
|
36
|
-
|
|
37
|
-
options?: any,
|
|
52
|
+
...params: AppflareRouteRunArgs<TArgs>
|
|
38
53
|
) => Promise<AppflareRequestResultLike<TData>>;
|
|
39
54
|
subscribe?: (options: {
|
|
40
55
|
args?: TArgs;
|
|
@@ -50,7 +65,7 @@ type AppflareQueryLike<TArgs, TData> = {
|
|
|
50
65
|
};
|
|
51
66
|
|
|
52
67
|
export type UseAppflareInfiniteQueryOptions<
|
|
53
|
-
TArgs,
|
|
68
|
+
TArgs extends Record<string, unknown>,
|
|
54
69
|
TData,
|
|
55
70
|
TPageParam,
|
|
56
71
|
TSelected = InfiniteData<TData, TPageParam>,
|
|
@@ -76,6 +91,35 @@ export type UseAppflareInfiniteQueryOptions<
|
|
|
76
91
|
};
|
|
77
92
|
};
|
|
78
93
|
|
|
94
|
+
type UseInfiniteQueryCallParams<
|
|
95
|
+
TArgs extends Record<string, unknown>,
|
|
96
|
+
TData,
|
|
97
|
+
TPageParam,
|
|
98
|
+
TSelected,
|
|
99
|
+
TKey extends QueryKey,
|
|
100
|
+
> =
|
|
101
|
+
AppflareHasRequiredInputKeys<TArgs> extends true
|
|
102
|
+
? [
|
|
103
|
+
args: TArgs,
|
|
104
|
+
options?: UseAppflareInfiniteQueryOptions<
|
|
105
|
+
TArgs,
|
|
106
|
+
TData,
|
|
107
|
+
TPageParam,
|
|
108
|
+
TSelected,
|
|
109
|
+
TKey
|
|
110
|
+
>,
|
|
111
|
+
]
|
|
112
|
+
: [
|
|
113
|
+
args?: TArgs,
|
|
114
|
+
options?: UseAppflareInfiniteQueryOptions<
|
|
115
|
+
TArgs,
|
|
116
|
+
TData,
|
|
117
|
+
TPageParam,
|
|
118
|
+
TSelected,
|
|
119
|
+
TKey
|
|
120
|
+
>,
|
|
121
|
+
];
|
|
122
|
+
|
|
79
123
|
function toError(error: AppflareRequestErrorLike): Error {
|
|
80
124
|
const next = new Error(error.message);
|
|
81
125
|
if (error.status !== undefined) {
|
|
@@ -85,23 +129,32 @@ function toError(error: AppflareRequestErrorLike): Error {
|
|
|
85
129
|
}
|
|
86
130
|
|
|
87
131
|
export function useInfiniteQuery<
|
|
88
|
-
TArgs,
|
|
132
|
+
TArgs extends Record<string, unknown>,
|
|
89
133
|
TData,
|
|
90
134
|
TPageParam = unknown,
|
|
91
135
|
TSelected = InfiniteData<TData, TPageParam>,
|
|
92
136
|
TKey extends QueryKey = QueryKey,
|
|
93
137
|
>(
|
|
94
138
|
query: AppflareQueryLike<TArgs, TData>,
|
|
95
|
-
|
|
96
|
-
options?: UseAppflareInfiniteQueryOptions<
|
|
139
|
+
...params: UseInfiniteQueryCallParams<
|
|
97
140
|
TArgs,
|
|
98
141
|
TData,
|
|
99
142
|
TPageParam,
|
|
100
143
|
TSelected,
|
|
101
144
|
TKey
|
|
102
|
-
|
|
145
|
+
>
|
|
103
146
|
): UseInfiniteQueryResult<TSelected, Error> {
|
|
147
|
+
const args = (params[0] ?? {}) as TArgs;
|
|
148
|
+
const options = params[1];
|
|
104
149
|
const queryClient = useQueryClient();
|
|
150
|
+
const realtimeOnChangeRef = useRef(options?.realtime?.onChange);
|
|
151
|
+
const realtimeOnErrorRef = useRef(options?.realtime?.onError);
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
realtimeOnChangeRef.current = options?.realtime?.onChange;
|
|
155
|
+
realtimeOnErrorRef.current = options?.realtime?.onError;
|
|
156
|
+
}, [options?.realtime?.onChange, options?.realtime?.onError]);
|
|
157
|
+
|
|
105
158
|
const resolvedQueryKey = useMemo(() => {
|
|
106
159
|
return (
|
|
107
160
|
options?.queryOptions?.queryKey ??
|
|
@@ -109,6 +162,18 @@ export function useInfiniteQuery<
|
|
|
109
162
|
);
|
|
110
163
|
}, [args, options?.queryOptions?.queryKey, query]);
|
|
111
164
|
|
|
165
|
+
const resolvedQueryKeyHash = useMemo(
|
|
166
|
+
() => hashKey(resolvedQueryKey as QueryKey),
|
|
167
|
+
[resolvedQueryKey],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const realtimeArgsHash = useMemo(() => hashKey([args] as QueryKey), [args]);
|
|
171
|
+
|
|
172
|
+
const realtimeRequestOptionsHash = useMemo(
|
|
173
|
+
() => hashKey([options?.realtime?.requestOptions] as QueryKey),
|
|
174
|
+
[options?.realtime?.requestOptions],
|
|
175
|
+
);
|
|
176
|
+
|
|
112
177
|
const result = useTanstackInfiniteQuery<
|
|
113
178
|
TData,
|
|
114
179
|
Error,
|
|
@@ -159,13 +224,13 @@ export function useInfiniteQuery<
|
|
|
159
224
|
};
|
|
160
225
|
},
|
|
161
226
|
);
|
|
162
|
-
|
|
227
|
+
realtimeOnChangeRef.current?.(
|
|
163
228
|
data as TData,
|
|
164
229
|
update as AppflareRealtimeQueryUpdateLike<TData>,
|
|
165
230
|
);
|
|
166
231
|
},
|
|
167
232
|
onError: (error) => {
|
|
168
|
-
|
|
233
|
+
realtimeOnErrorRef.current?.(error);
|
|
169
234
|
},
|
|
170
235
|
});
|
|
171
236
|
|
|
@@ -174,16 +239,13 @@ export function useInfiniteQuery<
|
|
|
174
239
|
subscription.remove();
|
|
175
240
|
};
|
|
176
241
|
}, [
|
|
177
|
-
|
|
242
|
+
realtimeArgsHash,
|
|
178
243
|
options?.realtime?.authToken,
|
|
179
244
|
options?.realtime?.enabled,
|
|
180
|
-
|
|
181
|
-
options?.realtime?.onError,
|
|
182
|
-
options?.realtime?.requestOptions,
|
|
183
|
-
query,
|
|
245
|
+
realtimeRequestOptionsHash,
|
|
184
246
|
query.subscribe,
|
|
185
247
|
queryClient,
|
|
186
|
-
|
|
248
|
+
resolvedQueryKeyHash,
|
|
187
249
|
]);
|
|
188
250
|
|
|
189
251
|
return result;
|
package/react/use-mutation.ts
CHANGED
|
@@ -14,10 +14,27 @@ type AppflareRequestResultLike<TData> = {
|
|
|
14
14
|
error: AppflareRequestErrorLike | null;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
type
|
|
17
|
+
type AppflareRequiredInputKeys<TInput extends Record<string, unknown>> = {
|
|
18
|
+
[K in keyof TInput]-?: undefined extends TInput[K] ? never : K;
|
|
19
|
+
}[keyof TInput];
|
|
20
|
+
|
|
21
|
+
type AppflareHasRequiredInputKeys<TInput extends Record<string, unknown>> = [
|
|
22
|
+
AppflareRequiredInputKeys<TInput>,
|
|
23
|
+
] extends [never]
|
|
24
|
+
? false
|
|
25
|
+
: true;
|
|
26
|
+
|
|
27
|
+
type AppflareRouteRunArgs<TInput extends Record<string, unknown>> =
|
|
28
|
+
AppflareHasRequiredInputKeys<TInput> extends true
|
|
29
|
+
? [args: TInput, options?: any]
|
|
30
|
+
: [args?: TInput, options?: any];
|
|
31
|
+
|
|
32
|
+
type AppflareMutationVariables<TArgs extends Record<string, unknown>> =
|
|
33
|
+
AppflareHasRequiredInputKeys<TArgs> extends true ? TArgs : TArgs | void;
|
|
34
|
+
|
|
35
|
+
type AppflareMutationLike<TArgs extends Record<string, unknown>, TData> = {
|
|
18
36
|
run: (
|
|
19
|
-
|
|
20
|
-
options?: any,
|
|
37
|
+
...params: AppflareRouteRunArgs<TArgs>
|
|
21
38
|
) => Promise<AppflareRequestResultLike<TData>>;
|
|
22
39
|
};
|
|
23
40
|
|
|
@@ -29,21 +46,39 @@ function toError(error: AppflareRequestErrorLike): Error {
|
|
|
29
46
|
return next;
|
|
30
47
|
}
|
|
31
48
|
|
|
32
|
-
export function useMutation<
|
|
49
|
+
export function useMutation<
|
|
50
|
+
TArgs extends Record<string, unknown>,
|
|
51
|
+
TData,
|
|
52
|
+
TContext = unknown,
|
|
53
|
+
>(
|
|
33
54
|
mutation: AppflareMutationLike<TArgs, TData>,
|
|
34
|
-
args: TArgs,
|
|
35
55
|
mutationOptions?: Omit<
|
|
36
|
-
UseMutationOptions<
|
|
56
|
+
UseMutationOptions<
|
|
57
|
+
TData,
|
|
58
|
+
Error,
|
|
59
|
+
AppflareMutationVariables<TArgs>,
|
|
60
|
+
TContext
|
|
61
|
+
>,
|
|
37
62
|
"mutationFn"
|
|
38
63
|
>,
|
|
39
|
-
): UseMutationResult<TData, Error,
|
|
40
|
-
return useTanstackMutation<
|
|
64
|
+
): UseMutationResult<TData, Error, AppflareMutationVariables<TArgs>, TContext> {
|
|
65
|
+
return useTanstackMutation<
|
|
66
|
+
TData,
|
|
67
|
+
Error,
|
|
68
|
+
AppflareMutationVariables<TArgs>,
|
|
69
|
+
TContext
|
|
70
|
+
>({
|
|
41
71
|
...(mutationOptions as Omit<
|
|
42
|
-
UseMutationOptions<
|
|
72
|
+
UseMutationOptions<
|
|
73
|
+
TData,
|
|
74
|
+
Error,
|
|
75
|
+
AppflareMutationVariables<TArgs>,
|
|
76
|
+
TContext
|
|
77
|
+
>,
|
|
43
78
|
"mutationFn"
|
|
44
79
|
>),
|
|
45
|
-
mutationFn: async () => {
|
|
46
|
-
const response = await mutation.run(args);
|
|
80
|
+
mutationFn: async (args: AppflareMutationVariables<TArgs>) => {
|
|
81
|
+
const response = await mutation.run((args ?? {}) as TArgs);
|
|
47
82
|
if (response.error) {
|
|
48
83
|
throw toError(response.error);
|
|
49
84
|
}
|
package/react/use-query.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
hashKey,
|
|
2
3
|
type QueryKey,
|
|
3
4
|
type UseQueryOptions,
|
|
4
5
|
type UseQueryResult,
|
|
5
6
|
useQuery as useTanstackQuery,
|
|
6
7
|
useQueryClient,
|
|
7
8
|
} from "@tanstack/react-query";
|
|
8
|
-
import { useEffect, useMemo } from "react";
|
|
9
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
9
10
|
|
|
10
11
|
type AppflareRequestErrorLike = {
|
|
11
12
|
message: string;
|
|
@@ -30,10 +31,24 @@ type AppflareRealtimeQueryUpdateLike<TData> = {
|
|
|
30
31
|
};
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
type
|
|
34
|
+
type AppflareRequiredInputKeys<TInput extends Record<string, unknown>> = {
|
|
35
|
+
[K in keyof TInput]-?: undefined extends TInput[K] ? never : K;
|
|
36
|
+
}[keyof TInput];
|
|
37
|
+
|
|
38
|
+
type AppflareHasRequiredInputKeys<TInput extends Record<string, unknown>> = [
|
|
39
|
+
AppflareRequiredInputKeys<TInput>,
|
|
40
|
+
] extends [never]
|
|
41
|
+
? false
|
|
42
|
+
: true;
|
|
43
|
+
|
|
44
|
+
type AppflareRouteRunArgs<TInput extends Record<string, unknown>> =
|
|
45
|
+
AppflareHasRequiredInputKeys<TInput> extends true
|
|
46
|
+
? [args: TInput, options?: any]
|
|
47
|
+
: [args?: TInput, options?: any];
|
|
48
|
+
|
|
49
|
+
type AppflareQueryLike<TArgs extends Record<string, unknown>, TData> = {
|
|
34
50
|
run: (
|
|
35
|
-
|
|
36
|
-
options?: any,
|
|
51
|
+
...params: AppflareRouteRunArgs<TArgs>
|
|
37
52
|
) => Promise<AppflareRequestResultLike<TData>>;
|
|
38
53
|
subscribe?: (options: {
|
|
39
54
|
args?: TArgs;
|
|
@@ -49,7 +64,7 @@ type AppflareQueryLike<TArgs, TData> = {
|
|
|
49
64
|
};
|
|
50
65
|
|
|
51
66
|
export type UseAppflareQueryOptions<
|
|
52
|
-
TArgs,
|
|
67
|
+
TArgs extends Record<string, unknown>,
|
|
53
68
|
TData,
|
|
54
69
|
TSelected = TData,
|
|
55
70
|
TKey extends QueryKey = QueryKey,
|
|
@@ -73,6 +88,22 @@ export type UseAppflareQueryOptions<
|
|
|
73
88
|
};
|
|
74
89
|
};
|
|
75
90
|
|
|
91
|
+
type UseQueryCallParams<
|
|
92
|
+
TArgs extends Record<string, unknown>,
|
|
93
|
+
TData,
|
|
94
|
+
TSelected,
|
|
95
|
+
TKey extends QueryKey,
|
|
96
|
+
> =
|
|
97
|
+
AppflareHasRequiredInputKeys<TArgs> extends true
|
|
98
|
+
? [
|
|
99
|
+
args: TArgs,
|
|
100
|
+
options?: UseAppflareQueryOptions<TArgs, TData, TSelected, TKey>,
|
|
101
|
+
]
|
|
102
|
+
: [
|
|
103
|
+
args?: TArgs,
|
|
104
|
+
options?: UseAppflareQueryOptions<TArgs, TData, TSelected, TKey>,
|
|
105
|
+
];
|
|
106
|
+
|
|
76
107
|
function toError(error: AppflareRequestErrorLike): Error {
|
|
77
108
|
const next = new Error(error.message);
|
|
78
109
|
if (error.status !== undefined) {
|
|
@@ -82,16 +113,25 @@ function toError(error: AppflareRequestErrorLike): Error {
|
|
|
82
113
|
}
|
|
83
114
|
|
|
84
115
|
export function useQuery<
|
|
85
|
-
TArgs,
|
|
116
|
+
TArgs extends Record<string, unknown>,
|
|
86
117
|
TData,
|
|
87
118
|
TSelected = TData,
|
|
88
119
|
TKey extends QueryKey = QueryKey,
|
|
89
120
|
>(
|
|
90
121
|
query: AppflareQueryLike<TArgs, TData>,
|
|
91
|
-
|
|
92
|
-
options?: UseAppflareQueryOptions<TArgs, TData, TSelected, TKey>,
|
|
122
|
+
...params: UseQueryCallParams<TArgs, TData, TSelected, TKey>
|
|
93
123
|
): UseQueryResult<TSelected, Error> {
|
|
124
|
+
const args = (params[0] ?? {}) as TArgs;
|
|
125
|
+
const options = params[1];
|
|
94
126
|
const queryClient = useQueryClient();
|
|
127
|
+
const realtimeOnChangeRef = useRef(options?.realtime?.onChange);
|
|
128
|
+
const realtimeOnErrorRef = useRef(options?.realtime?.onError);
|
|
129
|
+
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
realtimeOnChangeRef.current = options?.realtime?.onChange;
|
|
132
|
+
realtimeOnErrorRef.current = options?.realtime?.onError;
|
|
133
|
+
}, [options?.realtime?.onChange, options?.realtime?.onError]);
|
|
134
|
+
|
|
95
135
|
const resolvedQueryKey = useMemo(() => {
|
|
96
136
|
return (
|
|
97
137
|
options?.queryOptions?.queryKey ??
|
|
@@ -99,6 +139,18 @@ export function useQuery<
|
|
|
99
139
|
);
|
|
100
140
|
}, [args, options?.queryOptions?.queryKey, query]);
|
|
101
141
|
|
|
142
|
+
const resolvedQueryKeyHash = useMemo(
|
|
143
|
+
() => hashKey(resolvedQueryKey as QueryKey),
|
|
144
|
+
[resolvedQueryKey],
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const realtimeArgsHash = useMemo(() => hashKey([args] as QueryKey), [args]);
|
|
148
|
+
|
|
149
|
+
const realtimeRequestOptionsHash = useMemo(
|
|
150
|
+
() => hashKey([options?.realtime?.requestOptions] as QueryKey),
|
|
151
|
+
[options?.realtime?.requestOptions],
|
|
152
|
+
);
|
|
153
|
+
|
|
102
154
|
const result = useTanstackQuery<TData, Error, TSelected, TKey>({
|
|
103
155
|
...(options?.queryOptions as Omit<
|
|
104
156
|
UseQueryOptions<TData, Error, TSelected, TKey>,
|
|
@@ -127,13 +179,13 @@ export function useQuery<
|
|
|
127
179
|
signal: controller.signal,
|
|
128
180
|
onChange: (data, update) => {
|
|
129
181
|
queryClient.setQueryData<TData>(resolvedQueryKey, data as TData);
|
|
130
|
-
|
|
182
|
+
realtimeOnChangeRef.current?.(
|
|
131
183
|
data as TData,
|
|
132
184
|
update as AppflareRealtimeQueryUpdateLike<TData>,
|
|
133
185
|
);
|
|
134
186
|
},
|
|
135
187
|
onError: (error) => {
|
|
136
|
-
|
|
188
|
+
realtimeOnErrorRef.current?.(error);
|
|
137
189
|
},
|
|
138
190
|
});
|
|
139
191
|
|
|
@@ -142,16 +194,13 @@ export function useQuery<
|
|
|
142
194
|
subscription.remove();
|
|
143
195
|
};
|
|
144
196
|
}, [
|
|
145
|
-
|
|
197
|
+
realtimeArgsHash,
|
|
146
198
|
options?.realtime?.authToken,
|
|
147
199
|
options?.realtime?.enabled,
|
|
148
|
-
|
|
149
|
-
options?.realtime?.onError,
|
|
150
|
-
options?.realtime?.requestOptions,
|
|
151
|
-
query,
|
|
200
|
+
realtimeRequestOptionsHash,
|
|
152
201
|
query.subscribe,
|
|
153
202
|
queryClient,
|
|
154
|
-
|
|
203
|
+
resolvedQueryKeyHash,
|
|
155
204
|
]);
|
|
156
205
|
|
|
157
206
|
return result;
|