appflare 0.2.30 → 0.2.32

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.
Files changed (140) hide show
  1. package/Documentation.md +758 -758
  2. package/cli/commands/index.ts +238 -238
  3. package/cli/generate.ts +243 -178
  4. package/cli/index.ts +120 -120
  5. package/cli/load-config.ts +184 -184
  6. package/cli/schema-compiler.ts +1183 -1183
  7. package/cli/templates/auth/README.md +156 -156
  8. package/cli/templates/auth/config.ts +61 -61
  9. package/cli/templates/auth/route-config.ts +1 -1
  10. package/cli/templates/auth/route-handler.ts +1 -1
  11. package/cli/templates/auth/route-request-utils.ts +5 -5
  12. package/cli/templates/auth/route.config.ts +18 -18
  13. package/cli/templates/auth/route.handler.ts +18 -18
  14. package/cli/templates/auth/route.request-utils.ts +55 -55
  15. package/cli/templates/auth/route.ts +14 -14
  16. package/cli/templates/core/README.md +266 -266
  17. package/cli/templates/core/app-creation.ts +19 -19
  18. package/cli/templates/core/client/appflare.ts +112 -112
  19. package/cli/templates/core/client/handlers/index.ts +748 -748
  20. package/cli/templates/core/client/handlers.ts +1 -1
  21. package/cli/templates/core/client/index.ts +7 -7
  22. package/cli/templates/core/client/storage.ts +195 -195
  23. package/cli/templates/core/client/types.ts +186 -186
  24. package/cli/templates/core/client-modules/appflare.ts +1 -1
  25. package/cli/templates/core/client-modules/handlers.ts +1 -1
  26. package/cli/templates/core/client-modules/index.ts +1 -1
  27. package/cli/templates/core/client-modules/storage.ts +1 -1
  28. package/cli/templates/core/client-modules/types.ts +1 -1
  29. package/cli/templates/core/client.artifacts.ts +39 -39
  30. package/cli/templates/core/client.ts +4 -4
  31. package/cli/templates/core/drizzle.ts +15 -15
  32. package/cli/templates/core/export.ts +14 -14
  33. package/cli/templates/core/handlers.route.ts +24 -24
  34. package/cli/templates/core/handlers.ts +1 -1
  35. package/cli/templates/core/imports.ts +9 -9
  36. package/cli/templates/core/server.ts +38 -38
  37. package/cli/templates/core/types.ts +6 -6
  38. package/cli/templates/core/wrangler.ts +109 -109
  39. package/cli/templates/dashboard/builders/functions/index.ts +17 -17
  40. package/cli/templates/dashboard/builders/functions/render-page/header.ts +20 -20
  41. package/cli/templates/dashboard/builders/functions/render-page/index.ts +33 -33
  42. package/cli/templates/dashboard/builders/functions/render-page/request-panel.ts +171 -171
  43. package/cli/templates/dashboard/builders/functions/render-page/result-panel.ts +85 -85
  44. package/cli/templates/dashboard/builders/functions/render-page/scripts.ts +554 -554
  45. package/cli/templates/dashboard/builders/navigation.ts +122 -122
  46. package/cli/templates/dashboard/builders/storage/index.ts +13 -13
  47. package/cli/templates/dashboard/builders/storage/routes/create-directory-route.ts +29 -29
  48. package/cli/templates/dashboard/builders/storage/routes/delete-route.ts +18 -18
  49. package/cli/templates/dashboard/builders/storage/routes/download-route.ts +23 -23
  50. package/cli/templates/dashboard/builders/storage/routes/index.ts +22 -22
  51. package/cli/templates/dashboard/builders/storage/routes/list-route.ts +25 -25
  52. package/cli/templates/dashboard/builders/storage/routes/preview-route.ts +21 -21
  53. package/cli/templates/dashboard/builders/storage/routes/upload-route.ts +21 -21
  54. package/cli/templates/dashboard/builders/storage/runtime/helpers.ts +72 -72
  55. package/cli/templates/dashboard/builders/storage/runtime/storage-page.ts +130 -130
  56. package/cli/templates/dashboard/builders/table-routes/common/drawer-panel.ts +27 -27
  57. package/cli/templates/dashboard/builders/table-routes/common/pagination.ts +30 -30
  58. package/cli/templates/dashboard/builders/table-routes/common/search-bar.ts +23 -23
  59. package/cli/templates/dashboard/builders/table-routes/fragments.ts +217 -217
  60. package/cli/templates/dashboard/builders/table-routes/helpers.ts +45 -45
  61. package/cli/templates/dashboard/builders/table-routes/index.ts +8 -8
  62. package/cli/templates/dashboard/builders/table-routes/table/actions-cell.ts +71 -71
  63. package/cli/templates/dashboard/builders/table-routes/table/get-route.ts +291 -291
  64. package/cli/templates/dashboard/builders/table-routes/table/index.ts +80 -80
  65. package/cli/templates/dashboard/builders/table-routes/table/post-routes.ts +163 -163
  66. package/cli/templates/dashboard/builders/table-routes/table-route.ts +7 -7
  67. package/cli/templates/dashboard/builders/table-routes/users/get-route.ts +69 -69
  68. package/cli/templates/dashboard/builders/table-routes/users/html/modals.ts +57 -57
  69. package/cli/templates/dashboard/builders/table-routes/users/html/page.ts +27 -27
  70. package/cli/templates/dashboard/builders/table-routes/users/html/table.ts +128 -128
  71. package/cli/templates/dashboard/builders/table-routes/users/index.ts +32 -32
  72. package/cli/templates/dashboard/builders/table-routes/users/post-routes.ts +150 -150
  73. package/cli/templates/dashboard/builders/table-routes/users/redirect.ts +14 -14
  74. package/cli/templates/dashboard/builders/table-routes/users-route.ts +10 -10
  75. package/cli/templates/dashboard/components/dashboard-home.ts +23 -23
  76. package/cli/templates/dashboard/components/layout.ts +388 -388
  77. package/cli/templates/dashboard/components/login-page.ts +65 -65
  78. package/cli/templates/dashboard/index.ts +61 -61
  79. package/cli/templates/dashboard/types.ts +9 -9
  80. package/cli/templates/handlers/README.md +353 -353
  81. package/cli/templates/handlers/auth.ts +37 -37
  82. package/cli/templates/handlers/execution.ts +42 -42
  83. package/cli/templates/handlers/generators/context/context-creation.ts +101 -101
  84. package/cli/templates/handlers/generators/context/error-helpers.ts +11 -11
  85. package/cli/templates/handlers/generators/context/scheduler.ts +24 -24
  86. package/cli/templates/handlers/generators/context/storage-api.ts +82 -82
  87. package/cli/templates/handlers/generators/context/storage-helpers.ts +59 -59
  88. package/cli/templates/handlers/generators/context/types.ts +40 -40
  89. package/cli/templates/handlers/generators/context.ts +43 -43
  90. package/cli/templates/handlers/generators/execution.ts +15 -15
  91. package/cli/templates/handlers/generators/handlers.ts +13 -13
  92. package/cli/templates/handlers/generators/registration/modules/cron.ts +26 -26
  93. package/cli/templates/handlers/generators/registration/modules/realtime/auth.ts +75 -75
  94. package/cli/templates/handlers/generators/registration/modules/realtime/durable-object.ts +144 -144
  95. package/cli/templates/handlers/generators/registration/modules/realtime/index.ts +14 -14
  96. package/cli/templates/handlers/generators/registration/modules/realtime/publisher.ts +102 -102
  97. package/cli/templates/handlers/generators/registration/modules/realtime/routes.ts +164 -164
  98. package/cli/templates/handlers/generators/registration/modules/realtime/types.ts +30 -30
  99. package/cli/templates/handlers/generators/registration/modules/realtime/utils.ts +516 -516
  100. package/cli/templates/handlers/generators/registration/modules/scheduler.ts +56 -56
  101. package/cli/templates/handlers/generators/registration/modules/storage.ts +199 -199
  102. package/cli/templates/handlers/generators/registration/sections.ts +210 -210
  103. package/cli/templates/handlers/generators/types/context.ts +92 -92
  104. package/cli/templates/handlers/generators/types/core.ts +106 -106
  105. package/cli/templates/handlers/generators/types/operations.ts +135 -135
  106. package/cli/templates/handlers/generators/types/query-definitions/filter-and-where-types.ts +281 -259
  107. package/cli/templates/handlers/generators/types/query-definitions/query-api-types.ts +135 -135
  108. package/cli/templates/handlers/generators/types/query-definitions/query-helper-functions.ts +1103 -1031
  109. package/cli/templates/handlers/generators/types/query-definitions/schema-and-table-types.ts +278 -246
  110. package/cli/templates/handlers/generators/types/query-definitions.ts +13 -13
  111. package/cli/templates/handlers/generators/types/query-runtime/handled-error.ts +13 -13
  112. package/cli/templates/handlers/generators/types/query-runtime/runtime-aggregate-and-footer.ts +174 -174
  113. package/cli/templates/handlers/generators/types/query-runtime/runtime-read.ts +157 -121
  114. package/cli/templates/handlers/generators/types/query-runtime/runtime-setup.ts +45 -45
  115. package/cli/templates/handlers/generators/types/query-runtime/runtime-write.ts +697 -697
  116. package/cli/templates/handlers/generators/types/query-runtime.ts +15 -15
  117. package/cli/templates/handlers/index.ts +43 -43
  118. package/cli/templates/handlers/operations.ts +116 -116
  119. package/cli/templates/handlers/registration.ts +91 -91
  120. package/cli/templates/handlers/types.ts +15 -15
  121. package/cli/templates/handlers/utils.ts +48 -48
  122. package/cli/types.ts +110 -110
  123. package/cli/utils/handler-discovery.ts +466 -466
  124. package/cli/utils/json-utils.ts +24 -24
  125. package/cli/utils/path-utils.ts +19 -19
  126. package/cli/utils/schema-discovery.ts +399 -399
  127. package/dist/cli/index.d.mts +2 -0
  128. package/dist/cli/index.d.ts +2 -0
  129. package/dist/cli/index.js +366 -203
  130. package/dist/cli/index.mjs +366 -203
  131. package/index.ts +18 -18
  132. package/package.json +58 -58
  133. package/react/index.ts +5 -5
  134. package/react/use-infinite-query.ts +252 -252
  135. package/react/use-mutation.ts +89 -89
  136. package/react/use-query.ts +207 -207
  137. package/schema.ts +415 -415
  138. package/test-better-auth-hash.ts +2 -2
  139. package/tsconfig.json +6 -6
  140. package/tsup.config.ts +82 -82
@@ -1,89 +1,89 @@
1
- import {
2
- type UseMutationOptions,
3
- type UseMutationResult,
4
- useMutation as useTanstackMutation,
5
- } from "@tanstack/react-query";
6
-
7
- type AppflareRequestErrorLike = {
8
- message: string;
9
- status?: number;
10
- };
11
-
12
- type AppflareRequestResultLike<TData> = {
13
- data: TData | null;
14
- error: AppflareRequestErrorLike | null;
15
- };
16
-
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> = {
36
- run: (
37
- ...params: AppflareRouteRunArgs<TArgs>
38
- ) => Promise<AppflareRequestResultLike<TData>>;
39
- };
40
-
41
- function toError(error: AppflareRequestErrorLike): Error {
42
- const next = new Error(error.message);
43
- if (error.status !== undefined) {
44
- (next as Error & { status?: number }).status = error.status;
45
- }
46
- return next;
47
- }
48
-
49
- export function useMutation<
50
- TArgs extends Record<string, unknown>,
51
- TData,
52
- TContext = unknown,
53
- >(
54
- mutation: AppflareMutationLike<TArgs, TData>,
55
- mutationOptions?: Omit<
56
- UseMutationOptions<
57
- TData,
58
- Error,
59
- AppflareMutationVariables<TArgs>,
60
- TContext
61
- >,
62
- "mutationFn"
63
- >,
64
- ): UseMutationResult<TData, Error, AppflareMutationVariables<TArgs>, TContext> {
65
- return useTanstackMutation<
66
- TData,
67
- Error,
68
- AppflareMutationVariables<TArgs>,
69
- TContext
70
- >({
71
- ...(mutationOptions as Omit<
72
- UseMutationOptions<
73
- TData,
74
- Error,
75
- AppflareMutationVariables<TArgs>,
76
- TContext
77
- >,
78
- "mutationFn"
79
- >),
80
- mutationFn: async (args: AppflareMutationVariables<TArgs>) => {
81
- const response = await mutation.run((args ?? {}) as TArgs);
82
- if (response.error) {
83
- throw toError(response.error);
84
- }
85
-
86
- return response.data as TData;
87
- },
88
- });
89
- }
1
+ import {
2
+ type UseMutationOptions,
3
+ type UseMutationResult,
4
+ useMutation as useTanstackMutation,
5
+ } from "@tanstack/react-query";
6
+
7
+ type AppflareRequestErrorLike = {
8
+ message: string;
9
+ status?: number;
10
+ };
11
+
12
+ type AppflareRequestResultLike<TData> = {
13
+ data: TData | null;
14
+ error: AppflareRequestErrorLike | null;
15
+ };
16
+
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> = {
36
+ run: (
37
+ ...params: AppflareRouteRunArgs<TArgs>
38
+ ) => Promise<AppflareRequestResultLike<TData>>;
39
+ };
40
+
41
+ function toError(error: AppflareRequestErrorLike): Error {
42
+ const next = new Error(error.message);
43
+ if (error.status !== undefined) {
44
+ (next as Error & { status?: number }).status = error.status;
45
+ }
46
+ return next;
47
+ }
48
+
49
+ export function useMutation<
50
+ TArgs extends Record<string, unknown>,
51
+ TData,
52
+ TContext = unknown,
53
+ >(
54
+ mutation: AppflareMutationLike<TArgs, TData>,
55
+ mutationOptions?: Omit<
56
+ UseMutationOptions<
57
+ TData,
58
+ Error,
59
+ AppflareMutationVariables<TArgs>,
60
+ TContext
61
+ >,
62
+ "mutationFn"
63
+ >,
64
+ ): UseMutationResult<TData, Error, AppflareMutationVariables<TArgs>, TContext> {
65
+ return useTanstackMutation<
66
+ TData,
67
+ Error,
68
+ AppflareMutationVariables<TArgs>,
69
+ TContext
70
+ >({
71
+ ...(mutationOptions as Omit<
72
+ UseMutationOptions<
73
+ TData,
74
+ Error,
75
+ AppflareMutationVariables<TArgs>,
76
+ TContext
77
+ >,
78
+ "mutationFn"
79
+ >),
80
+ mutationFn: async (args: AppflareMutationVariables<TArgs>) => {
81
+ const response = await mutation.run((args ?? {}) as TArgs);
82
+ if (response.error) {
83
+ throw toError(response.error);
84
+ }
85
+
86
+ return response.data as TData;
87
+ },
88
+ });
89
+ }
@@ -1,207 +1,207 @@
1
- import {
2
- hashKey,
3
- type QueryKey,
4
- type UseQueryOptions,
5
- type UseQueryResult,
6
- useQuery as useTanstackQuery,
7
- useQueryClient,
8
- } from "@tanstack/react-query";
9
- import { useEffect, useMemo, useRef } from "react";
10
-
11
- type AppflareRequestErrorLike = {
12
- message: string;
13
- status?: number;
14
- };
15
-
16
- type AppflareRequestResultLike<TData> = {
17
- data: TData | null;
18
- error: AppflareRequestErrorLike | null;
19
- };
20
-
21
- type AppflareRealtimeSubscriptionLike = {
22
- remove: () => void;
23
- };
24
-
25
- type AppflareRealtimeQueryUpdateLike<TData> = {
26
- event: "query:update";
27
- payload: {
28
- queryName: string;
29
- signature: string;
30
- data: TData;
31
- };
32
- };
33
-
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> = {
50
- run: (
51
- ...params: AppflareRouteRunArgs<TArgs>
52
- ) => Promise<AppflareRequestResultLike<TData>>;
53
- subscribe?: (options: {
54
- args?: TArgs;
55
- authToken?: string;
56
- requestOptions?: any;
57
- signal?: AbortSignal;
58
- onChange: (
59
- data: TData,
60
- update: AppflareRealtimeQueryUpdateLike<TData>,
61
- ) => void;
62
- onError?: (error: unknown) => void;
63
- }) => AppflareRealtimeSubscriptionLike;
64
- };
65
-
66
- export type UseAppflareQueryOptions<
67
- TArgs extends Record<string, unknown>,
68
- TData,
69
- TSelected = TData,
70
- TKey extends QueryKey = QueryKey,
71
- > = {
72
- realtime?: {
73
- enabled?: boolean;
74
- authToken?: string;
75
- requestOptions?: any;
76
- onChange?: (
77
- data: TData,
78
- update: AppflareRealtimeQueryUpdateLike<TData>,
79
- ) => void;
80
- onError?: (error: unknown) => void;
81
- };
82
- requestOptions?: any;
83
- queryOptions?: Omit<
84
- UseQueryOptions<TData, Error, TSelected, TKey>,
85
- "queryFn" | "queryKey"
86
- > & {
87
- queryKey?: TKey;
88
- };
89
- };
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
-
107
- function toError(error: AppflareRequestErrorLike): Error {
108
- const next = new Error(error.message);
109
- if (error.status !== undefined) {
110
- (next as Error & { status?: number }).status = error.status;
111
- }
112
- return next;
113
- }
114
-
115
- export function useQuery<
116
- TArgs extends Record<string, unknown>,
117
- TData,
118
- TSelected = TData,
119
- TKey extends QueryKey = QueryKey,
120
- >(
121
- query: AppflareQueryLike<TArgs, TData>,
122
- ...params: UseQueryCallParams<TArgs, TData, TSelected, TKey>
123
- ): UseQueryResult<TSelected, Error> {
124
- const args = (params[0] ?? {}) as TArgs;
125
- const options = params[1];
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
-
135
- const resolvedQueryKey = useMemo(() => {
136
- return (
137
- options?.queryOptions?.queryKey ??
138
- (["appflare", "query", query, args] as unknown as TKey)
139
- );
140
- }, [args, options?.queryOptions?.queryKey, query]);
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
-
154
- const result = useTanstackQuery<TData, Error, TSelected, TKey>({
155
- ...(options?.queryOptions as Omit<
156
- UseQueryOptions<TData, Error, TSelected, TKey>,
157
- "queryFn" | "queryKey"
158
- >),
159
- queryKey: resolvedQueryKey,
160
- queryFn: async () => {
161
- const response = await query.run(args, options?.requestOptions);
162
- if (response.error) {
163
- throw toError(response.error);
164
- }
165
- return response.data as TData;
166
- },
167
- });
168
-
169
- useEffect(() => {
170
- if (options?.realtime?.enabled === false || !query.subscribe) {
171
- return;
172
- }
173
-
174
- const controller = new AbortController();
175
- const subscription = query.subscribe({
176
- args,
177
- authToken: options.realtime?.authToken,
178
- requestOptions: options.realtime?.requestOptions,
179
- signal: controller.signal,
180
- onChange: (data, update) => {
181
- queryClient.setQueryData<TData>(resolvedQueryKey, data as TData);
182
- realtimeOnChangeRef.current?.(
183
- data as TData,
184
- update as AppflareRealtimeQueryUpdateLike<TData>,
185
- );
186
- },
187
- onError: (error) => {
188
- realtimeOnErrorRef.current?.(error);
189
- },
190
- });
191
-
192
- return () => {
193
- controller.abort();
194
- subscription.remove();
195
- };
196
- }, [
197
- realtimeArgsHash,
198
- options?.realtime?.authToken,
199
- options?.realtime?.enabled,
200
- realtimeRequestOptionsHash,
201
- query.subscribe,
202
- queryClient,
203
- resolvedQueryKeyHash,
204
- ]);
205
-
206
- return result;
207
- }
1
+ import {
2
+ hashKey,
3
+ type QueryKey,
4
+ type UseQueryOptions,
5
+ type UseQueryResult,
6
+ useQuery as useTanstackQuery,
7
+ useQueryClient,
8
+ } from "@tanstack/react-query";
9
+ import { useEffect, useMemo, useRef } from "react";
10
+
11
+ type AppflareRequestErrorLike = {
12
+ message: string;
13
+ status?: number;
14
+ };
15
+
16
+ type AppflareRequestResultLike<TData> = {
17
+ data: TData | null;
18
+ error: AppflareRequestErrorLike | null;
19
+ };
20
+
21
+ type AppflareRealtimeSubscriptionLike = {
22
+ remove: () => void;
23
+ };
24
+
25
+ type AppflareRealtimeQueryUpdateLike<TData> = {
26
+ event: "query:update";
27
+ payload: {
28
+ queryName: string;
29
+ signature: string;
30
+ data: TData;
31
+ };
32
+ };
33
+
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> = {
50
+ run: (
51
+ ...params: AppflareRouteRunArgs<TArgs>
52
+ ) => Promise<AppflareRequestResultLike<TData>>;
53
+ subscribe?: (options: {
54
+ args?: TArgs;
55
+ authToken?: string;
56
+ requestOptions?: any;
57
+ signal?: AbortSignal;
58
+ onChange: (
59
+ data: TData,
60
+ update: AppflareRealtimeQueryUpdateLike<TData>,
61
+ ) => void;
62
+ onError?: (error: unknown) => void;
63
+ }) => AppflareRealtimeSubscriptionLike;
64
+ };
65
+
66
+ export type UseAppflareQueryOptions<
67
+ TArgs extends Record<string, unknown>,
68
+ TData,
69
+ TSelected = TData,
70
+ TKey extends QueryKey = QueryKey,
71
+ > = {
72
+ realtime?: {
73
+ enabled?: boolean;
74
+ authToken?: string;
75
+ requestOptions?: any;
76
+ onChange?: (
77
+ data: TData,
78
+ update: AppflareRealtimeQueryUpdateLike<TData>,
79
+ ) => void;
80
+ onError?: (error: unknown) => void;
81
+ };
82
+ requestOptions?: any;
83
+ queryOptions?: Omit<
84
+ UseQueryOptions<TData, Error, TSelected, TKey>,
85
+ "queryFn" | "queryKey"
86
+ > & {
87
+ queryKey?: TKey;
88
+ };
89
+ };
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
+
107
+ function toError(error: AppflareRequestErrorLike): Error {
108
+ const next = new Error(error.message);
109
+ if (error.status !== undefined) {
110
+ (next as Error & { status?: number }).status = error.status;
111
+ }
112
+ return next;
113
+ }
114
+
115
+ export function useQuery<
116
+ TArgs extends Record<string, unknown>,
117
+ TData,
118
+ TSelected = TData,
119
+ TKey extends QueryKey = QueryKey,
120
+ >(
121
+ query: AppflareQueryLike<TArgs, TData>,
122
+ ...params: UseQueryCallParams<TArgs, TData, TSelected, TKey>
123
+ ): UseQueryResult<TSelected, Error> {
124
+ const args = (params[0] ?? {}) as TArgs;
125
+ const options = params[1];
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
+
135
+ const resolvedQueryKey = useMemo(() => {
136
+ return (
137
+ options?.queryOptions?.queryKey ??
138
+ (["appflare", "query", query, args] as unknown as TKey)
139
+ );
140
+ }, [args, options?.queryOptions?.queryKey, query]);
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
+
154
+ const result = useTanstackQuery<TData, Error, TSelected, TKey>({
155
+ ...(options?.queryOptions as Omit<
156
+ UseQueryOptions<TData, Error, TSelected, TKey>,
157
+ "queryFn" | "queryKey"
158
+ >),
159
+ queryKey: resolvedQueryKey,
160
+ queryFn: async () => {
161
+ const response = await query.run(args, options?.requestOptions);
162
+ if (response.error) {
163
+ throw toError(response.error);
164
+ }
165
+ return response.data as TData;
166
+ },
167
+ });
168
+
169
+ useEffect(() => {
170
+ if (options?.realtime?.enabled === false || !query.subscribe) {
171
+ return;
172
+ }
173
+
174
+ const controller = new AbortController();
175
+ const subscription = query.subscribe({
176
+ args,
177
+ authToken: options.realtime?.authToken,
178
+ requestOptions: options.realtime?.requestOptions,
179
+ signal: controller.signal,
180
+ onChange: (data, update) => {
181
+ queryClient.setQueryData<TData>(resolvedQueryKey, data as TData);
182
+ realtimeOnChangeRef.current?.(
183
+ data as TData,
184
+ update as AppflareRealtimeQueryUpdateLike<TData>,
185
+ );
186
+ },
187
+ onError: (error) => {
188
+ realtimeOnErrorRef.current?.(error);
189
+ },
190
+ });
191
+
192
+ return () => {
193
+ controller.abort();
194
+ subscription.remove();
195
+ };
196
+ }, [
197
+ realtimeArgsHash,
198
+ options?.realtime?.authToken,
199
+ options?.realtime?.enabled,
200
+ realtimeRequestOptionsHash,
201
+ query.subscribe,
202
+ queryClient,
203
+ resolvedQueryKeyHash,
204
+ ]);
205
+
206
+ return result;
207
+ }