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,194 @@
1
+ export const storageModule = `
2
+ function parseExpiresIn(value: string | undefined): number | undefined {
3
+ if (!value) {
4
+ return undefined;
5
+ }
6
+
7
+ const parsed = Number(value);
8
+ if (!Number.isFinite(parsed) || parsed <= 0) {
9
+ return undefined;
10
+ }
11
+
12
+ return Math.floor(parsed);
13
+ }
14
+
15
+ function toStoragePath(path: string): string {
16
+ const trimmed = path.trim();
17
+ if (!trimmed) {
18
+ throw new Error("Storage path is required");
19
+ }
20
+
21
+ return trimmed.startsWith("/") ? trimmed : "/" + trimmed;
22
+ }
23
+
24
+ function readStoragePath(c: { req: { query: (name: string) => string | undefined } }): string {
25
+ const path = c.req.query("path") ?? "";
26
+ return toStoragePath(path);
27
+ }
28
+
29
+ export function registerGeneratedStorageRoutes(
30
+ app: Hono<WorkerEnv>,
31
+ options: RegisterHandlersOptions,
32
+ ): void {
33
+ app.post("/storage/upload", async (c) => {
34
+ const ctx = await createExecutionContext(c, options);
35
+ try {
36
+ const body = await c.req.json().catch(() => ({} as Record<string, unknown>));
37
+ const path = toStoragePath(String(body.path ?? ""));
38
+ const contentType =
39
+ typeof body.contentType === "string" ? body.contentType : undefined;
40
+ const expiresIn =
41
+ typeof body.expiresIn === "number" && body.expiresIn > 0
42
+ ? Math.floor(body.expiresIn)
43
+ : undefined;
44
+
45
+ const url = await ctx.storage.signedUrl({
46
+ path,
47
+ method: "PUT",
48
+ expiresIn,
49
+ contentType,
50
+ });
51
+
52
+ return c.json({
53
+ url,
54
+ method: "PUT",
55
+ path,
56
+ expiresIn: expiresIn ?? 300,
57
+ }, 200);
58
+ } catch (error) {
59
+ if (error instanceof AppflareHandledError) {
60
+ return c.json(error.payload, error.status);
61
+ }
62
+
63
+ return c.json(
64
+ { message: (error as Error).message ?? "Unable to create upload URL" },
65
+ 400,
66
+ );
67
+ }
68
+ });
69
+
70
+ app.get("/storage/download", async (c) => {
71
+ const ctx = await createExecutionContext(c, options);
72
+ try {
73
+ const path = readStoragePath(c);
74
+ const fileName = c.req.query("fileName") ?? undefined;
75
+ const expiresIn = parseExpiresIn(c.req.query("expiresIn"));
76
+ const url = await ctx.storage.signedUrl({
77
+ path,
78
+ method: "GET",
79
+ expiresIn,
80
+ downloadAsAttachment: true,
81
+ fileName,
82
+ });
83
+
84
+ return c.json({
85
+ url,
86
+ method: "GET",
87
+ path,
88
+ disposition: "attachment",
89
+ }, 200);
90
+ } catch (error) {
91
+ if (error instanceof AppflareHandledError) {
92
+ return c.json(error.payload, error.status);
93
+ }
94
+
95
+ return c.json(
96
+ { message: (error as Error).message ?? "Unable to create download URL" },
97
+ 400,
98
+ );
99
+ }
100
+ });
101
+
102
+ app.get("/storage/preview", async (c) => {
103
+ const ctx = await createExecutionContext(c, options);
104
+ try {
105
+ const path = readStoragePath(c);
106
+ const expiresIn = parseExpiresIn(c.req.query("expiresIn"));
107
+ const url = await ctx.storage.signedUrl({
108
+ path,
109
+ method: "GET",
110
+ expiresIn,
111
+ downloadAsAttachment: false,
112
+ });
113
+
114
+ return c.json({
115
+ url,
116
+ method: "GET",
117
+ path,
118
+ disposition: "inline",
119
+ }, 200);
120
+ } catch (error) {
121
+ if (error instanceof AppflareHandledError) {
122
+ return c.json(error.payload, error.status);
123
+ }
124
+
125
+ return c.json(
126
+ { message: (error as Error).message ?? "Unable to create preview URL" },
127
+ 400,
128
+ );
129
+ }
130
+ });
131
+
132
+ app.delete("/storage/object", async (c) => {
133
+ const ctx = await createExecutionContext(c, options);
134
+ try {
135
+ const path = readStoragePath(c);
136
+ await ctx.storage.delete({ path });
137
+ return c.json({ ok: true, path }, 200);
138
+ } catch (error) {
139
+ if (error instanceof AppflareHandledError) {
140
+ return c.json(error.payload, error.status);
141
+ }
142
+
143
+ return c.json(
144
+ { message: (error as Error).message ?? "Unable to delete object" },
145
+ 400,
146
+ );
147
+ }
148
+ });
149
+
150
+ app.get("/storage/list", async (c) => {
151
+ const ctx = await createExecutionContext(c, options);
152
+ try {
153
+ const prefix = c.req.query("prefix") ?? undefined;
154
+ const cursor = c.req.query("cursor") ?? undefined;
155
+ const delimiter = c.req.query("delimiter") ?? undefined;
156
+ const limitValue = c.req.query("limit");
157
+ const parsedLimit = limitValue ? Number(limitValue) : undefined;
158
+ const limit =
159
+ typeof parsedLimit === "number" && Number.isFinite(parsedLimit) && parsedLimit > 0
160
+ ? Math.floor(parsedLimit)
161
+ : undefined;
162
+ const methodValue = c.req.query("method");
163
+ const method: StorageMethod | undefined =
164
+ methodValue === "download" ||
165
+ methodValue === "get" ||
166
+ methodValue === "delete" ||
167
+ methodValue === "list" ||
168
+ methodValue === "put" ||
169
+ methodValue === "preview"
170
+ ? methodValue
171
+ : undefined;
172
+
173
+ const result = await ctx.storage.list({
174
+ prefix,
175
+ cursor,
176
+ delimiter,
177
+ limit,
178
+ method,
179
+ });
180
+
181
+ return c.json(result, 200);
182
+ } catch (error) {
183
+ if (error instanceof AppflareHandledError) {
184
+ return c.json(error.payload, error.status);
185
+ }
186
+
187
+ return c.json(
188
+ { message: (error as Error).message ?? "Unable to list storage objects" },
189
+ 400,
190
+ );
191
+ }
192
+ });
193
+ }
194
+ `;
@@ -0,0 +1,210 @@
1
+ import type { DiscoveredHandlerOperation } from "../../../../utils/handler-discovery";
2
+
3
+ type IndexedOperation = {
4
+ operation: DiscoveredHandlerOperation;
5
+ index: number;
6
+ alias: string;
7
+ };
8
+
9
+ export type RegistrationTemplateSections = {
10
+ imports: string;
11
+ operationSchemas: string;
12
+ schedulerSchemas: string;
13
+ queryRoutes: string;
14
+ mutationRoutes: string;
15
+ queryRegistryEntries: string;
16
+ schedulerEntries: string;
17
+ schedulerPayloadMapEntries: string;
18
+ cronEntries: string;
19
+ storageHandlersEntries: string;
20
+ };
21
+
22
+ function toSafeIdentifier(value: string): string {
23
+ const sanitized = value.replace(/[^A-Za-z0-9_]/g, "_");
24
+ if (/^[0-9]/.test(sanitized)) {
25
+ return `_${sanitized}`;
26
+ }
27
+ return sanitized;
28
+ }
29
+
30
+ function buildImportAlias(
31
+ operation: DiscoveredHandlerOperation,
32
+ index: number,
33
+ ): string {
34
+ const routeName = operation.routePath.replace(/^\//, "").replace(/\//g, "_");
35
+ return toSafeIdentifier(`op_${index}_${routeName}`);
36
+ }
37
+
38
+ function indexOperations(
39
+ operations: DiscoveredHandlerOperation[],
40
+ ): IndexedOperation[] {
41
+ return operations.map((operation, index) => ({
42
+ operation,
43
+ index,
44
+ alias: buildImportAlias(operation, index),
45
+ }));
46
+ }
47
+
48
+ function buildImports(operations: IndexedOperation[]): string {
49
+ return operations
50
+ .map(({ operation, alias }) => {
51
+ return `import { ${operation.exportName} as ${alias} } from "${operation.importPath}";`;
52
+ })
53
+ .join("\n");
54
+ }
55
+
56
+ function buildOperationSchemas(operations: IndexedOperation[]): string {
57
+ return operations
58
+ .filter(
59
+ ({ operation }) =>
60
+ operation.kind === "query" || operation.kind === "mutation",
61
+ )
62
+ .map(({ alias }) => {
63
+ const schemaName = `${alias}Schema`;
64
+ return `const ${schemaName} = z.object(${alias}.definition.args);`;
65
+ })
66
+ .join("\n");
67
+ }
68
+
69
+ function buildSchedulerSchemas(operations: IndexedOperation[]): string {
70
+ return operations
71
+ .filter(({ operation }) => operation.kind === "scheduler")
72
+ .map(({ alias }) => {
73
+ const schemaName = `${alias}SchedulerSchema`;
74
+ return `const ${schemaName} = ${alias}.definition.args ? z.object(${alias}.definition.args) : z.undefined();`;
75
+ })
76
+ .join("\n");
77
+ }
78
+
79
+ function buildQueryRoutes(operations: IndexedOperation[]): string {
80
+ return operations
81
+ .filter(({ operation }) => operation.kind === "query")
82
+ .map(({ operation, alias }) => {
83
+ const schemaName = `${alias}Schema`;
84
+ return `
85
+ app.get(
86
+ "${operation.routePath}",
87
+ sValidator("query", ${schemaName}),
88
+ async (c) => {
89
+ const ctx = await createExecutionContext(c, options);
90
+ try {
91
+ return await executeOperation(c, ${alias}, c.req.valid("query"), ctx);
92
+ } catch (error) {
93
+ return handleOperationError(c, error, "Invalid query arguments");
94
+ }
95
+ },
96
+ );`;
97
+ })
98
+ .join("\n");
99
+ }
100
+
101
+ function buildMutationRoutes(operations: IndexedOperation[]): string {
102
+ return operations
103
+ .filter(({ operation }) => operation.kind === "mutation")
104
+ .map(({ operation, alias }) => {
105
+ const schemaName = `${alias}Schema`;
106
+ return `
107
+ app.post(
108
+ "${operation.routePath}",
109
+ sValidator("json", ${schemaName}),
110
+ async (c) => {
111
+ const ctx = await createExecutionContext(c, options);
112
+ try {
113
+ const response = await executeOperation(c, ${alias}, c.req.valid("json"), ctx);
114
+ await publishMutationEvents(c, options, ctx.mutationEvents);
115
+ return response;
116
+ } catch (error) {
117
+ return handleOperationError(c, error, "Invalid mutation arguments");
118
+ }
119
+ },
120
+ );`;
121
+ })
122
+ .join("\n");
123
+ }
124
+
125
+ function buildQueryRegistryEntries(operations: IndexedOperation[]): string {
126
+ return operations
127
+ .filter(({ operation }) => operation.kind === "query")
128
+ .map(({ operation, alias }) => {
129
+ const schemaName = `${alias}Schema`;
130
+ const queryName = operation.handlerName ?? operation.routePath;
131
+ return `
132
+ ${JSON.stringify(queryName)}: {
133
+ definition: ${alias}.definition,
134
+ schema: ${schemaName},
135
+ },`;
136
+ })
137
+ .join("\n");
138
+ }
139
+
140
+ function buildSchedulerEntries(operations: IndexedOperation[]): string {
141
+ return operations
142
+ .filter(({ operation }) => operation.kind === "scheduler")
143
+ .map(({ operation, alias }) => {
144
+ const schemaName = `${alias}SchedulerSchema`;
145
+ const taskName = operation.taskName ?? `${operation.routePath}`;
146
+ return `
147
+ ${JSON.stringify(taskName)}: {
148
+ definition: ${alias}.definition,
149
+ schema: ${schemaName},
150
+ },`;
151
+ })
152
+ .join("\n");
153
+ }
154
+
155
+ function buildSchedulerPayloadMapEntries(
156
+ operations: IndexedOperation[],
157
+ ): string {
158
+ return operations
159
+ .filter(({ operation }) => operation.kind === "scheduler")
160
+ .map(({ operation, alias }) => {
161
+ const taskName = operation.taskName ?? `${operation.routePath}`;
162
+ return `\t${JSON.stringify(taskName)}: Parameters<typeof ${alias}.definition.handler>[1];`;
163
+ })
164
+ .join("\n");
165
+ }
166
+
167
+ function buildCronEntries(operations: IndexedOperation[]): string {
168
+ return operations
169
+ .filter(({ operation }) => operation.kind === "cron")
170
+ .map(({ operation, alias }) => {
171
+ const taskName = operation.taskName ?? `${operation.routePath}`;
172
+ const cronTriggers = operation.cronTriggers ?? [];
173
+ return `
174
+ {
175
+ taskName: ${JSON.stringify(taskName)},
176
+ cronTriggers: ${JSON.stringify(cronTriggers)},
177
+ definition: ${alias}.definition,
178
+ },`;
179
+ })
180
+ .join("\n");
181
+ }
182
+
183
+ function buildStorageHandlersEntries(operations: IndexedOperation[]): string {
184
+ return operations
185
+ .filter(({ operation }) => operation.kind === "storage")
186
+ .map(({ alias }) => {
187
+ return `\n\t${alias}.definition.handler,`;
188
+ })
189
+ .join("\n");
190
+ }
191
+
192
+ export function buildRegistrationTemplateSections(
193
+ operations: DiscoveredHandlerOperation[],
194
+ ): RegistrationTemplateSections {
195
+ const indexedOperations = indexOperations(operations);
196
+
197
+ return {
198
+ imports: buildImports(indexedOperations),
199
+ operationSchemas: buildOperationSchemas(indexedOperations),
200
+ schedulerSchemas: buildSchedulerSchemas(indexedOperations),
201
+ queryRoutes: buildQueryRoutes(indexedOperations),
202
+ mutationRoutes: buildMutationRoutes(indexedOperations),
203
+ queryRegistryEntries: buildQueryRegistryEntries(indexedOperations),
204
+ schedulerEntries: buildSchedulerEntries(indexedOperations),
205
+ schedulerPayloadMapEntries:
206
+ buildSchedulerPayloadMapEntries(indexedOperations),
207
+ cronEntries: buildCronEntries(indexedOperations),
208
+ storageHandlersEntries: buildStorageHandlersEntries(indexedOperations),
209
+ };
210
+ }
@@ -0,0 +1,64 @@
1
+ export function generateTypesContextSection(): string {
2
+ return `type AuthSession = typeof auth.$Infer.Session;
3
+ type User = AuthSession['user']
4
+ type Session = AuthSession['session']
5
+
6
+ export type StoragePutArgs = {
7
+ path: string;
8
+ body: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob;
9
+ contentType?: string;
10
+ httpMetadata?: Record<string, unknown>;
11
+ customMetadata?: Record<string, string>;
12
+ };
13
+
14
+ export type StorageGetArgs = {
15
+ path: string;
16
+ method?: StorageMethod;
17
+ onlyIf?: unknown;
18
+ range?: unknown;
19
+ includeBody?: boolean;
20
+ };
21
+
22
+ export type StorageDeleteArgs = {
23
+ path: string;
24
+ };
25
+
26
+ export type StorageListArgs = {
27
+ prefix?: string;
28
+ cursor?: string;
29
+ limit?: number;
30
+ delimiter?: string;
31
+ include?: Array<"httpMetadata" | "customMetadata">;
32
+ method?: StorageMethod;
33
+ };
34
+
35
+ export type StorageSignedUrlArgs = {
36
+ path: string;
37
+ method?: "GET" | "PUT" | "DELETE";
38
+ expiresIn?: number;
39
+ contentType?: string;
40
+ downloadAsAttachment?: boolean;
41
+ fileName?: string;
42
+ };
43
+
44
+ export type AppflareStorage = {
45
+ put: (args: StoragePutArgs) => Promise<unknown>;
46
+ get: (args: StorageGetArgs) => Promise<unknown | null>;
47
+ delete: (args: StorageDeleteArgs) => Promise<void>;
48
+ list: (args?: StorageListArgs) => Promise<unknown>;
49
+ signedUrl: (args: StorageSignedUrlArgs) => Promise<string>;
50
+ };
51
+
52
+ export type AppflareContext = {
53
+ $db: AppflareDb;
54
+ db: AppflareQueryDb;
55
+ mutationEvents: DbMutationEvent[];
56
+ user: User;
57
+ session: Session;
58
+ context: Context<WorkerEnv>;
59
+ scheduler: Scheduler;
60
+ storage: AppflareStorage;
61
+ error: (status: number, message: string, details?: unknown) => never;
62
+ };
63
+ `;
64
+ }
@@ -0,0 +1,101 @@
1
+ export function generateTypesCoreSection(): string {
2
+ return `import { betterAuth } from "better-auth";
3
+ import { auth } from "./auth.config";
4
+ import {
5
+ and,
6
+ eq,
7
+ ne,
8
+ inArray,
9
+ notInArray,
10
+ gt,
11
+ gte,
12
+ lt,
13
+ lte,
14
+ isNull,
15
+ isNotNull,
16
+ getTableColumns,
17
+ sql,
18
+ type InferInsertModel,
19
+ type InferSelectModel,
20
+ type SQL,
21
+ } from "drizzle-orm";
22
+
23
+ export type WorkerEnv = {
24
+ Bindings: Record<string, unknown>;
25
+ };
26
+
27
+ export type RegisterHandlersOptions = {
28
+ databaseBinding: string;
29
+ kvBinding?: string;
30
+ schedulerBinding?: string;
31
+ r2Binding?: string;
32
+ realtimeBinding?: string;
33
+ realtimeObjectName?: string;
34
+ realtimeSubscribePath?: string;
35
+ realtimeWebsocketPath?: string;
36
+ realtimeProtocol?: string;
37
+ };
38
+
39
+ export type StorageMethod =
40
+ | "download"
41
+ | "get"
42
+ | "delete"
43
+ | "list"
44
+ | "put"
45
+ | "preview";
46
+
47
+ export type StorageAuthorizationArgs = {
48
+ path: string;
49
+ method: StorageMethod;
50
+ headers?: Headers;
51
+ query?: Record<string, string>;
52
+ contentType?: string;
53
+ };
54
+
55
+ export type StorageHandler = (
56
+ ctx: AppflareContext,
57
+ args: StorageAuthorizationArgs,
58
+ ) => boolean | Promise<boolean>;
59
+
60
+ export type RegisteredStorageHandler = {
61
+ kind: "storage-manager";
62
+ definition: {
63
+ handler: StorageHandler;
64
+ };
65
+ };
66
+
67
+ export function storageManager(definition: {
68
+ handler: StorageHandler;
69
+ }): RegisteredStorageHandler {
70
+ return {
71
+ kind: "storage-manager",
72
+ definition,
73
+ };
74
+ }
75
+
76
+ const storageHandlers: StorageHandler[] = [];
77
+
78
+ export function setStorageHandlers(handlers: StorageHandler[]): void {
79
+ storageHandlers.length = 0;
80
+ storageHandlers.push(...handlers);
81
+ }
82
+
83
+ export async function isStorageAllowed(
84
+ ctx: AppflareContext,
85
+ args: StorageAuthorizationArgs,
86
+ ): Promise<boolean> {
87
+ if (storageHandlers.length === 0) {
88
+ return false;
89
+ }
90
+
91
+ for (const handler of storageHandlers) {
92
+ const allowed = await handler(ctx, args);
93
+ if (allowed) {
94
+ return true;
95
+ }
96
+ }
97
+
98
+ return false;
99
+ }
100
+ `;
101
+ }
@@ -0,0 +1,135 @@
1
+ export function generateTypesOperationsSection(): string {
2
+ return `type InferOperationArgs<TShape extends ZodRawShape> = z.output<z.ZodObject<TShape>>;
3
+
4
+ export type SchedulerEnqueueOptions = {
5
+ delaySeconds?: number;
6
+ };
7
+
8
+ declare global {
9
+ interface AppflareSchedulerHandlerMap {}
10
+ }
11
+
12
+ export type SchedulerTaskName = keyof AppflareSchedulerHandlerMap extends never
13
+ ? string
14
+ : Extract<keyof AppflareSchedulerHandlerMap, string>;
15
+
16
+ export type SchedulerTaskPayload<TTask extends SchedulerTaskName> =
17
+ TTask extends keyof AppflareSchedulerHandlerMap
18
+ ? AppflareSchedulerHandlerMap[TTask]
19
+ : unknown;
20
+
21
+ export type SchedulerEnqueue = {
22
+ <TTask extends SchedulerTaskName>(
23
+ task: TTask,
24
+ ...args: undefined extends SchedulerTaskPayload<TTask>
25
+ ? [
26
+ payload?: SchedulerTaskPayload<TTask>,
27
+ options?: SchedulerEnqueueOptions,
28
+ ]
29
+ : [
30
+ payload: SchedulerTaskPayload<TTask>,
31
+ options?: SchedulerEnqueueOptions,
32
+ ]
33
+ ): Promise<void>;
34
+ };
35
+
36
+ export type Scheduler = {
37
+ enqueue: SchedulerEnqueue;
38
+ };
39
+
40
+ type OperationDefinition<
41
+ TShape extends ZodRawShape,
42
+ TResult,
43
+ > = {
44
+ args: TShape;
45
+ authRequired: boolean;
46
+ middleware?: (
47
+ ctx: AppflareContext,
48
+ index: InferOperationArgs<TShape>,
49
+ request: Request,
50
+ ) => void | Promise<void>;
51
+ handler: (
52
+ ctx: AppflareContext,
53
+ args: InferOperationArgs<TShape>,
54
+ ) => TResult | Promise<TResult>;
55
+ };
56
+
57
+ type OperationDefinitionInput<
58
+ TShape extends ZodRawShape,
59
+ TResult,
60
+ > = Omit<OperationDefinition<TShape, TResult>, "authRequired"> & {
61
+ authRequired?: boolean;
62
+ };
63
+
64
+ export type RegisteredOperation<
65
+ TShape extends ZodRawShape,
66
+ TResult,
67
+ > = {
68
+ kind: "query" | "mutation";
69
+ definition: OperationDefinition<TShape, TResult>;
70
+ };
71
+
72
+ type SchedulerDefinition<TShape extends ZodRawShape | undefined> = {
73
+ args?: TShape;
74
+ handler: (
75
+ ctx: AppflareContext,
76
+ args: TShape extends ZodRawShape ? InferOperationArgs<TShape> : undefined,
77
+ ) => void | Promise<void>;
78
+ };
79
+
80
+ export type RegisteredScheduler<TShape extends ZodRawShape | undefined> = {
81
+ kind: "scheduler";
82
+ definition: SchedulerDefinition<TShape>;
83
+ };
84
+
85
+ type CronDefinition = {
86
+ cronTrigger: string | string[];
87
+ handler: (ctx: AppflareContext) => void | Promise<void>;
88
+ };
89
+
90
+ export type RegisteredCron = {
91
+ kind: "cron";
92
+ definition: CronDefinition;
93
+ };
94
+
95
+ export function query<TShape extends ZodRawShape, TResult>(
96
+ definition: OperationDefinitionInput<TShape, TResult>,
97
+ ): RegisteredOperation<TShape, TResult> {
98
+ return {
99
+ kind: "query",
100
+ definition: {
101
+ authRequired: false,
102
+ ...definition,
103
+ },
104
+ };
105
+ }
106
+
107
+ export function mutation<TShape extends ZodRawShape, TResult>(
108
+ definition: OperationDefinitionInput<TShape, TResult>,
109
+ ): RegisteredOperation<TShape, TResult> {
110
+ return {
111
+ kind: "mutation",
112
+ definition: {
113
+ authRequired: false,
114
+ ...definition,
115
+ },
116
+ };
117
+ }
118
+
119
+ export function scheduler<TShape extends ZodRawShape | undefined = undefined>(
120
+ definition: SchedulerDefinition<TShape>,
121
+ ): RegisteredScheduler<TShape> {
122
+ return {
123
+ kind: "scheduler",
124
+ definition,
125
+ };
126
+ }
127
+
128
+ export function cron(definition: CronDefinition): RegisteredCron {
129
+ return {
130
+ kind: "cron",
131
+ definition,
132
+ };
133
+ }
134
+ `;
135
+ }