appflare 0.0.28 → 0.1.1

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 (151) hide show
  1. package/cli/commands/index.ts +140 -0
  2. package/cli/generate.ts +149 -0
  3. package/cli/index.ts +56 -447
  4. package/cli/load-config.ts +182 -0
  5. package/cli/schema-compiler.ts +657 -0
  6. package/cli/templates/auth/README.md +156 -0
  7. package/cli/templates/auth/config.ts +61 -0
  8. package/cli/templates/auth/route-config.ts +18 -0
  9. package/cli/templates/auth/route-handler.ts +18 -0
  10. package/cli/templates/auth/route-request-utils.ts +55 -0
  11. package/cli/templates/auth/route.ts +14 -0
  12. package/cli/templates/core/README.md +266 -0
  13. package/cli/templates/core/app-creation.ts +19 -0
  14. package/cli/templates/core/client/appflare.ts +37 -0
  15. package/cli/templates/core/client/index.ts +6 -0
  16. package/cli/templates/core/client/storage.ts +100 -0
  17. package/cli/templates/core/client/types.ts +54 -0
  18. package/cli/templates/core/client-modules/appflare.ts +112 -0
  19. package/cli/templates/core/client-modules/handlers/index.ts +747 -0
  20. package/cli/templates/core/client-modules/handlers.ts +1 -0
  21. package/cli/templates/core/client-modules/index.ts +7 -0
  22. package/cli/templates/core/client-modules/storage.ts +180 -0
  23. package/cli/templates/core/client-modules/types.ts +145 -0
  24. package/cli/templates/core/client.ts +39 -0
  25. package/cli/templates/core/drizzle.ts +15 -0
  26. package/cli/templates/core/export.ts +14 -0
  27. package/cli/templates/core/handlers-route.ts +23 -0
  28. package/cli/templates/core/handlers.ts +1 -0
  29. package/cli/templates/core/imports.ts +8 -0
  30. package/cli/templates/core/server.ts +38 -0
  31. package/cli/templates/core/types.ts +6 -0
  32. package/cli/templates/core/wrangler.ts +109 -0
  33. package/cli/templates/handlers/README.md +353 -0
  34. package/cli/templates/handlers/auth.ts +37 -0
  35. package/cli/templates/handlers/execution.ts +39 -0
  36. package/cli/templates/handlers/generators/context/context-creation.ts +80 -0
  37. package/cli/templates/handlers/generators/context/error-helpers.ts +11 -0
  38. package/cli/templates/handlers/generators/context/scheduler.ts +24 -0
  39. package/cli/templates/handlers/generators/context/storage-api.ts +112 -0
  40. package/cli/templates/handlers/generators/context/storage-helpers.ts +59 -0
  41. package/cli/templates/handlers/generators/context/types.ts +18 -0
  42. package/cli/templates/handlers/generators/context.ts +43 -0
  43. package/cli/templates/handlers/generators/execution.ts +15 -0
  44. package/cli/templates/handlers/generators/handlers.ts +13 -0
  45. package/cli/templates/handlers/generators/registration/modules/cron.ts +30 -0
  46. package/cli/templates/handlers/generators/registration/modules/realtime.ts +631 -0
  47. package/cli/templates/handlers/generators/registration/modules/scheduler.ts +56 -0
  48. package/cli/templates/handlers/generators/registration/modules/storage.ts +194 -0
  49. package/cli/templates/handlers/generators/registration/sections.ts +210 -0
  50. package/cli/templates/handlers/generators/types/context.ts +64 -0
  51. package/cli/templates/handlers/generators/types/core.ts +101 -0
  52. package/cli/templates/handlers/generators/types/operations.ts +135 -0
  53. package/cli/templates/handlers/generators/types/query-definitions.ts +1029 -0
  54. package/cli/templates/handlers/generators/types/query-runtime.ts +417 -0
  55. package/cli/templates/handlers/index.ts +43 -0
  56. package/cli/templates/handlers/operations.ts +116 -0
  57. package/cli/templates/handlers/registration.ts +83 -0
  58. package/cli/templates/handlers/types.ts +15 -0
  59. package/cli/templates/handlers/utils.ts +48 -0
  60. package/cli/types.ts +108 -0
  61. package/cli/utils/handler-discovery.ts +366 -0
  62. package/cli/utils/json-utils.ts +24 -0
  63. package/cli/utils/path-utils.ts +19 -0
  64. package/cli/utils/schema-discovery.ts +390 -0
  65. package/index.ts +27 -4
  66. package/package.json +23 -20
  67. package/react/index.ts +5 -3
  68. package/react/use-infinite-query.ts +190 -0
  69. package/react/use-mutation.ts +54 -0
  70. package/react/use-query.ts +158 -0
  71. package/schema.ts +262 -0
  72. package/tsconfig.json +2 -4
  73. package/cli/README.md +0 -108
  74. package/cli/core/build.ts +0 -187
  75. package/cli/core/config.ts +0 -92
  76. package/cli/core/discover-handlers.ts +0 -143
  77. package/cli/core/handlers.ts +0 -7
  78. package/cli/core/index.ts +0 -205
  79. package/cli/generators/generate-api-client/client.ts +0 -163
  80. package/cli/generators/generate-api-client/extract-configuration.ts +0 -121
  81. package/cli/generators/generate-api-client/index.ts +0 -973
  82. package/cli/generators/generate-api-client/types.ts +0 -164
  83. package/cli/generators/generate-api-client/utils.ts +0 -22
  84. package/cli/generators/generate-api-client.ts +0 -1
  85. package/cli/generators/generate-cloudflare-worker/helpers.ts +0 -24
  86. package/cli/generators/generate-cloudflare-worker/index.ts +0 -2
  87. package/cli/generators/generate-cloudflare-worker/worker.ts +0 -148
  88. package/cli/generators/generate-cloudflare-worker/wrangler.ts +0 -108
  89. package/cli/generators/generate-cloudflare-worker.ts +0 -4
  90. package/cli/generators/generate-cron-handlers/cron-handlers-block.ts +0 -2
  91. package/cli/generators/generate-cron-handlers/handler-entries.ts +0 -29
  92. package/cli/generators/generate-cron-handlers/index.ts +0 -61
  93. package/cli/generators/generate-cron-handlers/runtime-block.ts +0 -49
  94. package/cli/generators/generate-cron-handlers/type-helpers-block.ts +0 -60
  95. package/cli/generators/generate-db-handlers/index.ts +0 -33
  96. package/cli/generators/generate-db-handlers/prepare.ts +0 -24
  97. package/cli/generators/generate-db-handlers/templates.ts +0 -189
  98. package/cli/generators/generate-db-handlers.ts +0 -1
  99. package/cli/generators/generate-hono-server/auth.ts +0 -97
  100. package/cli/generators/generate-hono-server/imports.ts +0 -55
  101. package/cli/generators/generate-hono-server/index.ts +0 -52
  102. package/cli/generators/generate-hono-server/routes.ts +0 -115
  103. package/cli/generators/generate-hono-server/template.ts +0 -371
  104. package/cli/generators/generate-hono-server.ts +0 -1
  105. package/cli/generators/generate-scheduler-handlers/constants.ts +0 -8
  106. package/cli/generators/generate-scheduler-handlers/handler-entries.ts +0 -22
  107. package/cli/generators/generate-scheduler-handlers/index.ts +0 -51
  108. package/cli/generators/generate-scheduler-handlers/runtime-block.ts +0 -68
  109. package/cli/generators/generate-scheduler-handlers/scheduler-handlers-block.ts +0 -2
  110. package/cli/generators/generate-scheduler-handlers/type-helpers-block.ts +0 -68
  111. package/cli/generators/generate-scheduler-handlers.ts +0 -1
  112. package/cli/generators/generate-websocket-durable-object/auth.ts +0 -30
  113. package/cli/generators/generate-websocket-durable-object/imports.ts +0 -55
  114. package/cli/generators/generate-websocket-durable-object/index.ts +0 -41
  115. package/cli/generators/generate-websocket-durable-object/query-handlers.ts +0 -18
  116. package/cli/generators/generate-websocket-durable-object/template.ts +0 -714
  117. package/cli/generators/generate-websocket-durable-object.ts +0 -1
  118. package/cli/schema/schema-static-types.ts +0 -702
  119. package/cli/schema/schema.ts +0 -151
  120. package/cli/utils/tsc.ts +0 -54
  121. package/cli/utils/utils.ts +0 -190
  122. package/cli/utils/zod-utils.ts +0 -121
  123. package/lib/README.md +0 -50
  124. package/lib/db.ts +0 -19
  125. package/lib/location.ts +0 -110
  126. package/lib/values.ts +0 -27
  127. package/react/README.md +0 -67
  128. package/react/hooks/useMutation.ts +0 -89
  129. package/react/hooks/usePaginatedQuery.ts +0 -213
  130. package/react/hooks/useQuery.ts +0 -106
  131. package/react/shared/queryShared.ts +0 -174
  132. package/server/README.md +0 -218
  133. package/server/auth.ts +0 -107
  134. package/server/database/builders.ts +0 -83
  135. package/server/database/context.ts +0 -327
  136. package/server/database/populate.ts +0 -234
  137. package/server/database/query-builder.ts +0 -161
  138. package/server/database/query-utils.ts +0 -25
  139. package/server/db.ts +0 -2
  140. package/server/storage/auth.ts +0 -16
  141. package/server/storage/bucket.ts +0 -22
  142. package/server/storage/context.ts +0 -34
  143. package/server/storage/index.ts +0 -38
  144. package/server/storage/operations.ts +0 -149
  145. package/server/storage/route-handler.ts +0 -60
  146. package/server/storage/types.ts +0 -55
  147. package/server/storage/utils.ts +0 -47
  148. package/server/storage.ts +0 -6
  149. package/server/types/schema-refs.ts +0 -66
  150. package/server/types/types.ts +0 -633
  151. package/server/utils/id-utils.ts +0 -230
@@ -0,0 +1,390 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import type { LoadedAppflareConfig } from "../types";
4
+
5
+ export type DiscoveredColumn = {
6
+ name: string;
7
+ expression: string;
8
+ type: "string" | "number" | "boolean" | "unknown";
9
+ optional: boolean;
10
+ primaryKey: boolean;
11
+ autoIncrement: boolean;
12
+ };
13
+
14
+ export type DiscoveredTable = {
15
+ exportName: string;
16
+ tableName: string;
17
+ columns: DiscoveredColumn[];
18
+ };
19
+
20
+ export type DiscoveredSchema = {
21
+ schemaPath: string;
22
+ tables: DiscoveredTable[];
23
+ };
24
+
25
+ function splitTopLevel(value: string): string[] {
26
+ const result: string[] = [];
27
+ let current = "";
28
+ let depthParen = 0;
29
+ let depthBrace = 0;
30
+ let depthBracket = 0;
31
+ let inSingleQuote = false;
32
+ let inDoubleQuote = false;
33
+ let inTemplateString = false;
34
+ let escaped = false;
35
+
36
+ for (let i = 0; i < value.length; i += 1) {
37
+ const char = value[i];
38
+
39
+ if (escaped) {
40
+ current += char;
41
+ escaped = false;
42
+ continue;
43
+ }
44
+
45
+ if (char === "\\") {
46
+ current += char;
47
+ escaped = true;
48
+ continue;
49
+ }
50
+
51
+ if (!inDoubleQuote && !inTemplateString && char === "'") {
52
+ inSingleQuote = !inSingleQuote;
53
+ current += char;
54
+ continue;
55
+ }
56
+
57
+ if (!inSingleQuote && !inTemplateString && char === '"') {
58
+ inDoubleQuote = !inDoubleQuote;
59
+ current += char;
60
+ continue;
61
+ }
62
+
63
+ if (!inSingleQuote && !inDoubleQuote && char === "`") {
64
+ inTemplateString = !inTemplateString;
65
+ current += char;
66
+ continue;
67
+ }
68
+
69
+ if (inSingleQuote || inDoubleQuote || inTemplateString) {
70
+ current += char;
71
+ continue;
72
+ }
73
+
74
+ if (char === "(") {
75
+ depthParen += 1;
76
+ } else if (char === ")") {
77
+ depthParen -= 1;
78
+ } else if (char === "{") {
79
+ depthBrace += 1;
80
+ } else if (char === "}") {
81
+ depthBrace -= 1;
82
+ } else if (char === "[") {
83
+ depthBracket += 1;
84
+ } else if (char === "]") {
85
+ depthBracket -= 1;
86
+ }
87
+
88
+ if (
89
+ char === "," &&
90
+ depthParen === 0 &&
91
+ depthBrace === 0 &&
92
+ depthBracket === 0
93
+ ) {
94
+ const segment = current.trim();
95
+ if (segment.length > 0) {
96
+ result.push(segment);
97
+ }
98
+ current = "";
99
+ continue;
100
+ }
101
+
102
+ current += char;
103
+ }
104
+
105
+ const trailing = current.trim();
106
+ if (trailing.length > 0) {
107
+ result.push(trailing);
108
+ }
109
+
110
+ return result;
111
+ }
112
+
113
+ function getTopLevelColonIndex(entry: string): number {
114
+ let depthParen = 0;
115
+ let depthBrace = 0;
116
+ let depthBracket = 0;
117
+ let inSingleQuote = false;
118
+ let inDoubleQuote = false;
119
+ let inTemplateString = false;
120
+ let escaped = false;
121
+
122
+ for (let i = 0; i < entry.length; i += 1) {
123
+ const char = entry[i];
124
+
125
+ if (escaped) {
126
+ escaped = false;
127
+ continue;
128
+ }
129
+
130
+ if (char === "\\") {
131
+ escaped = true;
132
+ continue;
133
+ }
134
+
135
+ if (!inDoubleQuote && !inTemplateString && char === "'") {
136
+ inSingleQuote = !inSingleQuote;
137
+ continue;
138
+ }
139
+
140
+ if (!inSingleQuote && !inTemplateString && char === '"') {
141
+ inDoubleQuote = !inDoubleQuote;
142
+ continue;
143
+ }
144
+
145
+ if (!inSingleQuote && !inDoubleQuote && char === "`") {
146
+ inTemplateString = !inTemplateString;
147
+ continue;
148
+ }
149
+
150
+ if (inSingleQuote || inDoubleQuote || inTemplateString) {
151
+ continue;
152
+ }
153
+
154
+ if (char === "(") {
155
+ depthParen += 1;
156
+ continue;
157
+ }
158
+ if (char === ")") {
159
+ depthParen -= 1;
160
+ continue;
161
+ }
162
+ if (char === "{") {
163
+ depthBrace += 1;
164
+ continue;
165
+ }
166
+ if (char === "}") {
167
+ depthBrace -= 1;
168
+ continue;
169
+ }
170
+ if (char === "[") {
171
+ depthBracket += 1;
172
+ continue;
173
+ }
174
+ if (char === "]") {
175
+ depthBracket -= 1;
176
+ continue;
177
+ }
178
+
179
+ if (
180
+ char === ":" &&
181
+ depthParen === 0 &&
182
+ depthBrace === 0 &&
183
+ depthBracket === 0
184
+ ) {
185
+ return i;
186
+ }
187
+ }
188
+
189
+ return -1;
190
+ }
191
+
192
+ function inferColumnType(expression: string): DiscoveredColumn["type"] {
193
+ const lowered = expression.toLowerCase();
194
+ if (/\.(int|integer|real|numeric|decimal|float|double)\s*\(/.test(lowered)) {
195
+ return "number";
196
+ }
197
+ if (/\.(text|varchar|char)\s*\(/.test(lowered)) {
198
+ return "string";
199
+ }
200
+ if (/\.(boolean|bool)\s*\(/.test(lowered)) {
201
+ return "boolean";
202
+ }
203
+ return "unknown";
204
+ }
205
+
206
+ function discoverColumns(rawColumns: string): DiscoveredColumn[] {
207
+ const entries = splitTopLevel(rawColumns);
208
+ const columns: DiscoveredColumn[] = [];
209
+
210
+ for (const entry of entries) {
211
+ const colonIndex = getTopLevelColonIndex(entry);
212
+ if (colonIndex === -1) {
213
+ continue;
214
+ }
215
+
216
+ const key = entry
217
+ .slice(0, colonIndex)
218
+ .trim()
219
+ .replace(/^['"]|['"]$/g, "");
220
+ if (!key) {
221
+ continue;
222
+ }
223
+
224
+ const expression = entry.slice(colonIndex + 1).trim();
225
+ const primaryKey = /\.primarykey\s*\(/i.test(expression);
226
+ const autoIncrement = /autoincrement\s*:\s*true/i.test(expression);
227
+ const hasDefault = /\.default\s*\(/i.test(expression);
228
+ const notNull = /\.notnull\s*\(/i.test(expression);
229
+ const optional = !notNull || hasDefault || autoIncrement;
230
+
231
+ columns.push({
232
+ name: key,
233
+ expression,
234
+ type: inferColumnType(expression),
235
+ optional,
236
+ primaryKey,
237
+ autoIncrement,
238
+ });
239
+ }
240
+
241
+ return columns;
242
+ }
243
+
244
+ function discoverTables(schemaSource: string): DiscoveredTable[] {
245
+ const tablePattern =
246
+ /export\s+const\s+(\w+)\s*=\s*table\s*\(\s*["'`]([^"'`]+)["'`]/g;
247
+ const tables: DiscoveredTable[] = [];
248
+
249
+ const findMatchingBrace = (source: string, startIndex: number): number => {
250
+ let depth = 0;
251
+ let inSingleQuote = false;
252
+ let inDoubleQuote = false;
253
+ let inTemplateString = false;
254
+ let escaped = false;
255
+
256
+ for (let i = startIndex; i < source.length; i += 1) {
257
+ const char = source[i];
258
+
259
+ if (escaped) {
260
+ escaped = false;
261
+ continue;
262
+ }
263
+
264
+ if (char === "\\") {
265
+ escaped = true;
266
+ continue;
267
+ }
268
+
269
+ if (!inDoubleQuote && !inTemplateString && char === "'") {
270
+ inSingleQuote = !inSingleQuote;
271
+ continue;
272
+ }
273
+
274
+ if (!inSingleQuote && !inTemplateString && char === '"') {
275
+ inDoubleQuote = !inDoubleQuote;
276
+ continue;
277
+ }
278
+
279
+ if (!inSingleQuote && !inDoubleQuote && char === "`") {
280
+ inTemplateString = !inTemplateString;
281
+ continue;
282
+ }
283
+
284
+ if (inSingleQuote || inDoubleQuote || inTemplateString) {
285
+ continue;
286
+ }
287
+
288
+ if (char === "{") {
289
+ depth += 1;
290
+ continue;
291
+ }
292
+
293
+ if (char === "}") {
294
+ depth -= 1;
295
+ if (depth === 0) {
296
+ return i;
297
+ }
298
+ }
299
+ }
300
+
301
+ return -1;
302
+ };
303
+
304
+ let match = tablePattern.exec(schemaSource);
305
+ while (match) {
306
+ const exportName = match[1];
307
+ const tableName = match[2];
308
+ const objectStart = schemaSource.indexOf("{", tablePattern.lastIndex);
309
+ if (objectStart === -1) {
310
+ match = tablePattern.exec(schemaSource);
311
+ continue;
312
+ }
313
+
314
+ const objectEnd = findMatchingBrace(schemaSource, objectStart);
315
+ if (objectEnd === -1) {
316
+ match = tablePattern.exec(schemaSource);
317
+ continue;
318
+ }
319
+
320
+ const rawColumns = schemaSource.slice(objectStart + 1, objectEnd);
321
+ tables.push({
322
+ exportName,
323
+ tableName,
324
+ columns: discoverColumns(rawColumns),
325
+ });
326
+ match = tablePattern.exec(schemaSource);
327
+ }
328
+
329
+ return tables;
330
+ }
331
+
332
+ async function findSchemaCandidates(dirPath: string): Promise<string[]> {
333
+ const entries = await readdir(dirPath, { withFileTypes: true });
334
+ const discovered: string[] = [];
335
+
336
+ for (const entry of entries) {
337
+ if (entry.name.startsWith(".")) {
338
+ continue;
339
+ }
340
+ if (entry.name === "node_modules" || entry.name === "_generated") {
341
+ continue;
342
+ }
343
+
344
+ const entryPath = resolve(dirPath, entry.name);
345
+ if (entry.isDirectory()) {
346
+ discovered.push(...(await findSchemaCandidates(entryPath)));
347
+ continue;
348
+ }
349
+
350
+ if (entry.isFile() && entry.name === "schema.ts") {
351
+ discovered.push(entryPath);
352
+ }
353
+ }
354
+
355
+ return discovered;
356
+ }
357
+
358
+ export async function discoverSchema(
359
+ loadedConfig: LoadedAppflareConfig,
360
+ prioritySchemaPaths: string[] = [],
361
+ ): Promise<DiscoveredSchema> {
362
+ const scanCandidates = await findSchemaCandidates(
363
+ loadedConfig.scanDirAbs,
364
+ ).catch(() => []);
365
+
366
+ const fallbackCandidate = resolve(loadedConfig.configDir, "schema.ts");
367
+ const candidates = [
368
+ ...prioritySchemaPaths,
369
+ ...(scanCandidates.length ? scanCandidates : [fallbackCandidate]),
370
+ ];
371
+
372
+ for (const schemaPath of candidates) {
373
+ const file = Bun.file(schemaPath);
374
+ if (!(await file.exists())) {
375
+ continue;
376
+ }
377
+ const source = await file.text();
378
+ const tables = discoverTables(source);
379
+ if (tables.length > 0) {
380
+ return {
381
+ schemaPath,
382
+ tables,
383
+ };
384
+ }
385
+ }
386
+
387
+ throw new Error(
388
+ `Unable to discover schema.ts under scanDir (${loadedConfig.scanDirAbs}) or fallback (${fallbackCandidate}).`,
389
+ );
390
+ }
package/index.ts CHANGED
@@ -1,4 +1,27 @@
1
- export * from "./lib/db";
2
- export * from "./lib/values";
3
- export * from "./lib/location";
4
- export { AppflareConfig } from "./cli/utils/utils";
1
+ export type {
2
+ AppflareConfig,
3
+ AppflareDatabaseBinding,
4
+ AppflareKVNamespace,
5
+ AppflareR2Bucket,
6
+ LoadedAppflareConfig,
7
+ NormalizedAppflareConfig,
8
+ } from "./cli/types";
9
+ export { loadConfig } from "./cli/load-config";
10
+ export { generateArtifacts } from "./cli/generate";
11
+ export {
12
+ schema,
13
+ table,
14
+ v,
15
+ isSchemaDefinition,
16
+ type ColumnDefinition,
17
+ type RelationDefinition,
18
+ type SchemaDefinition,
19
+ type TableDefinition,
20
+ } from "./schema";
21
+ export { useQuery } from "./react";
22
+ export { useInfiniteQuery } from "./react";
23
+ export { useMutation } from "./react";
24
+ export type {
25
+ UseAppflareQueryOptions,
26
+ UseAppflareInfiniteQueryOptions,
27
+ } from "./react";
package/package.json CHANGED
@@ -1,38 +1,41 @@
1
1
  {
2
2
  "name": "appflare",
3
- "version": "0.0.28",
3
+ "version": "0.1.1",
4
4
  "bin": {
5
5
  "appflare": "./cli/index.ts"
6
6
  },
7
7
  "exports": {
8
8
  ".": "./index.ts",
9
- "./db": "./lib/db.ts",
10
- "./values": "./lib/values.ts",
11
- "./location": "./lib/location.ts",
12
- "./*": "./*.ts",
13
- "./react/*": "./react/*.ts",
14
9
  "./react": "./react/index.ts",
15
- "./server/db": "./server/db.ts",
16
- "./server/storage": "./server/storage.ts",
17
- "./server/auth": "./server/auth.ts"
10
+ "./*": "./*.ts"
18
11
  },
19
12
  "scripts": {},
13
+ "peerDependencies": {
14
+ "@tanstack/react-query": "^5.90.21",
15
+ "react": ">=18"
16
+ },
20
17
  "devDependencies": {
21
- "@cloudflare/workers-types": "^4.20241112.0",
22
- "@types/react": "^18.3.12",
23
- "typescript": "^5.9.3",
24
- "@tanstack/react-query": "^5.90.12",
25
- "react": "^18.3.1"
18
+ "@cloudflare/workers-types": "^4.20260219.0",
19
+ "@types/react": "^19.2.0",
20
+ "@tanstack/react-query": "^5.90.21",
21
+ "@types/bun": "^1.3.9",
22
+ "@types/node": "^25.3.0",
23
+ "npm-check-updates": "^19.4.0",
24
+ "typescript": "^5.9.3"
26
25
  },
27
26
  "dependencies": {
28
- "@hono/standard-validator": "^0.2.1",
27
+ "@better-auth/cli": "^1.4.18",
28
+ "@hono/standard-validator": "^0.2.2",
29
29
  "better-auth": "^1.4.18",
30
+ "better-auth-cloudflare": "^0.2.9",
30
31
  "better-fetch": "^1.1.2",
32
+ "bun": "^1.3.9",
31
33
  "chokidar": "^5.0.0",
32
- "cloudflare-do-mongo": "^0.1.2",
33
- "commander": "^14.0.1",
34
- "hono": "^4.6.8",
35
- "mongodb": "^7.0.0",
36
- "zod": "^4.1.13"
34
+ "commander": "^14.0.3",
35
+ "drizzle-kit": "^0.31.9",
36
+ "drizzle-orm": "^0.45.1",
37
+ "hono": "^4.12.0",
38
+ "wrangler": "^4.67.0",
39
+ "zod": "^4.3.6"
37
40
  }
38
41
  }
package/react/index.ts CHANGED
@@ -1,3 +1,5 @@
1
- export * from "./hooks/useMutation";
2
- export * from "./hooks/usePaginatedQuery";
3
- export * from "./hooks/useQuery";
1
+ export { useQuery } from "./use-query";
2
+ export type { UseAppflareQueryOptions } from "./use-query";
3
+ export { useInfiniteQuery } from "./use-infinite-query";
4
+ export type { UseAppflareInfiniteQueryOptions } from "./use-infinite-query";
5
+ export { useMutation } from "./use-mutation";
@@ -0,0 +1,190 @@
1
+ import {
2
+ type InfiniteData,
3
+ type QueryKey,
4
+ type UseInfiniteQueryOptions,
5
+ type UseInfiniteQueryResult,
6
+ useInfiniteQuery as useTanstackInfiniteQuery,
7
+ useQueryClient,
8
+ } from "@tanstack/react-query";
9
+ import { useEffect, useMemo } 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 AppflareQueryLike<TArgs, TData> = {
35
+ run: (
36
+ args: TArgs,
37
+ options?: any,
38
+ ) => Promise<AppflareRequestResultLike<TData>>;
39
+ subscribe?: (options: {
40
+ args?: TArgs;
41
+ authToken?: string;
42
+ requestOptions?: any;
43
+ signal?: AbortSignal;
44
+ onChange: (
45
+ data: TData,
46
+ update: AppflareRealtimeQueryUpdateLike<TData>,
47
+ ) => void;
48
+ onError?: (error: unknown) => void;
49
+ }) => AppflareRealtimeSubscriptionLike;
50
+ };
51
+
52
+ export type UseAppflareInfiniteQueryOptions<
53
+ TArgs,
54
+ TData,
55
+ TPageParam,
56
+ TSelected = InfiniteData<TData, TPageParam>,
57
+ TKey extends QueryKey = QueryKey,
58
+ > = {
59
+ realtime?: {
60
+ enabled?: boolean;
61
+ authToken?: string;
62
+ requestOptions?: any;
63
+ onChange?: (
64
+ data: TData,
65
+ update: AppflareRealtimeQueryUpdateLike<TData>,
66
+ ) => void;
67
+ onError?: (error: unknown) => void;
68
+ };
69
+ requestOptions?: any;
70
+ pageParamToArgs?: (baseArgs: TArgs, pageParam: TPageParam) => TArgs;
71
+ queryOptions?: Omit<
72
+ UseInfiniteQueryOptions<TData, Error, TSelected, TKey, TPageParam>,
73
+ "queryFn" | "queryKey"
74
+ > & {
75
+ queryKey?: TKey;
76
+ };
77
+ };
78
+
79
+ function toError(error: AppflareRequestErrorLike): Error {
80
+ const next = new Error(error.message);
81
+ if (error.status !== undefined) {
82
+ (next as Error & { status?: number }).status = error.status;
83
+ }
84
+ return next;
85
+ }
86
+
87
+ export function useInfiniteQuery<
88
+ TArgs,
89
+ TData,
90
+ TPageParam = unknown,
91
+ TSelected = InfiniteData<TData, TPageParam>,
92
+ TKey extends QueryKey = QueryKey,
93
+ >(
94
+ query: AppflareQueryLike<TArgs, TData>,
95
+ args: TArgs,
96
+ options?: UseAppflareInfiniteQueryOptions<
97
+ TArgs,
98
+ TData,
99
+ TPageParam,
100
+ TSelected,
101
+ TKey
102
+ >,
103
+ ): UseInfiniteQueryResult<TSelected, Error> {
104
+ const queryClient = useQueryClient();
105
+ const resolvedQueryKey = useMemo(() => {
106
+ return (
107
+ options?.queryOptions?.queryKey ??
108
+ (["appflare", "infinite-query", query, args] as unknown as TKey)
109
+ );
110
+ }, [args, options?.queryOptions?.queryKey, query]);
111
+
112
+ const result = useTanstackInfiniteQuery<
113
+ TData,
114
+ Error,
115
+ TSelected,
116
+ TKey,
117
+ TPageParam
118
+ >({
119
+ ...(options?.queryOptions as Omit<
120
+ UseInfiniteQueryOptions<TData, Error, TSelected, TKey, TPageParam>,
121
+ "queryFn" | "queryKey"
122
+ >),
123
+ queryKey: resolvedQueryKey,
124
+ queryFn: async ({ pageParam }) => {
125
+ const nextArgs =
126
+ pageParam === undefined || !options?.pageParamToArgs
127
+ ? args
128
+ : options.pageParamToArgs(args, pageParam as TPageParam);
129
+ const response = await query.run(nextArgs, options?.requestOptions);
130
+ if (response.error) {
131
+ throw toError(response.error);
132
+ }
133
+ return response.data as TData;
134
+ },
135
+ });
136
+
137
+ useEffect(() => {
138
+ if (options?.realtime?.enabled === false || !query.subscribe) {
139
+ return;
140
+ }
141
+
142
+ const controller = new AbortController();
143
+ const subscription = query.subscribe({
144
+ args,
145
+ authToken: options.realtime?.authToken,
146
+ requestOptions: options.realtime?.requestOptions,
147
+ signal: controller.signal,
148
+ onChange: (data, update) => {
149
+ queryClient.setQueryData<InfiniteData<TData, TPageParam>>(
150
+ resolvedQueryKey,
151
+ (previous) => {
152
+ if (!previous || previous.pages.length === 0) {
153
+ return previous;
154
+ }
155
+
156
+ return {
157
+ ...previous,
158
+ pages: [data as TData, ...previous.pages.slice(1)],
159
+ };
160
+ },
161
+ );
162
+ options.realtime?.onChange?.(
163
+ data as TData,
164
+ update as AppflareRealtimeQueryUpdateLike<TData>,
165
+ );
166
+ },
167
+ onError: (error) => {
168
+ options.realtime?.onError?.(error);
169
+ },
170
+ });
171
+
172
+ return () => {
173
+ controller.abort();
174
+ subscription.remove();
175
+ };
176
+ }, [
177
+ args,
178
+ options?.realtime?.authToken,
179
+ options?.realtime?.enabled,
180
+ options?.realtime?.onChange,
181
+ options?.realtime?.onError,
182
+ options?.realtime?.requestOptions,
183
+ query,
184
+ query.subscribe,
185
+ queryClient,
186
+ resolvedQueryKey,
187
+ ]);
188
+
189
+ return result;
190
+ }