appflare 0.0.28 → 0.1.0

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 (141) 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 +740 -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 +265 -0
  34. package/cli/templates/handlers/auth.ts +36 -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/index.ts +43 -0
  46. package/cli/templates/handlers/operations.ts +116 -0
  47. package/cli/templates/handlers/registration.ts +1114 -0
  48. package/cli/templates/handlers/types.ts +960 -0
  49. package/cli/templates/handlers/utils.ts +48 -0
  50. package/cli/types.ts +108 -0
  51. package/cli/utils/handler-discovery.ts +366 -0
  52. package/cli/utils/json-utils.ts +24 -0
  53. package/cli/utils/path-utils.ts +19 -0
  54. package/cli/utils/schema-discovery.ts +390 -0
  55. package/index.ts +27 -4
  56. package/package.json +23 -20
  57. package/react/index.ts +5 -3
  58. package/react/use-infinite-query.ts +190 -0
  59. package/react/use-mutation.ts +54 -0
  60. package/react/use-query.ts +158 -0
  61. package/schema.ts +262 -0
  62. package/tsconfig.json +2 -4
  63. package/cli/README.md +0 -108
  64. package/cli/core/build.ts +0 -187
  65. package/cli/core/config.ts +0 -92
  66. package/cli/core/discover-handlers.ts +0 -143
  67. package/cli/core/handlers.ts +0 -7
  68. package/cli/core/index.ts +0 -205
  69. package/cli/generators/generate-api-client/client.ts +0 -163
  70. package/cli/generators/generate-api-client/extract-configuration.ts +0 -121
  71. package/cli/generators/generate-api-client/index.ts +0 -973
  72. package/cli/generators/generate-api-client/types.ts +0 -164
  73. package/cli/generators/generate-api-client/utils.ts +0 -22
  74. package/cli/generators/generate-api-client.ts +0 -1
  75. package/cli/generators/generate-cloudflare-worker/helpers.ts +0 -24
  76. package/cli/generators/generate-cloudflare-worker/index.ts +0 -2
  77. package/cli/generators/generate-cloudflare-worker/worker.ts +0 -148
  78. package/cli/generators/generate-cloudflare-worker/wrangler.ts +0 -108
  79. package/cli/generators/generate-cloudflare-worker.ts +0 -4
  80. package/cli/generators/generate-cron-handlers/cron-handlers-block.ts +0 -2
  81. package/cli/generators/generate-cron-handlers/handler-entries.ts +0 -29
  82. package/cli/generators/generate-cron-handlers/index.ts +0 -61
  83. package/cli/generators/generate-cron-handlers/runtime-block.ts +0 -49
  84. package/cli/generators/generate-cron-handlers/type-helpers-block.ts +0 -60
  85. package/cli/generators/generate-db-handlers/index.ts +0 -33
  86. package/cli/generators/generate-db-handlers/prepare.ts +0 -24
  87. package/cli/generators/generate-db-handlers/templates.ts +0 -189
  88. package/cli/generators/generate-db-handlers.ts +0 -1
  89. package/cli/generators/generate-hono-server/auth.ts +0 -97
  90. package/cli/generators/generate-hono-server/imports.ts +0 -55
  91. package/cli/generators/generate-hono-server/index.ts +0 -52
  92. package/cli/generators/generate-hono-server/routes.ts +0 -115
  93. package/cli/generators/generate-hono-server/template.ts +0 -371
  94. package/cli/generators/generate-hono-server.ts +0 -1
  95. package/cli/generators/generate-scheduler-handlers/constants.ts +0 -8
  96. package/cli/generators/generate-scheduler-handlers/handler-entries.ts +0 -22
  97. package/cli/generators/generate-scheduler-handlers/index.ts +0 -51
  98. package/cli/generators/generate-scheduler-handlers/runtime-block.ts +0 -68
  99. package/cli/generators/generate-scheduler-handlers/scheduler-handlers-block.ts +0 -2
  100. package/cli/generators/generate-scheduler-handlers/type-helpers-block.ts +0 -68
  101. package/cli/generators/generate-scheduler-handlers.ts +0 -1
  102. package/cli/generators/generate-websocket-durable-object/auth.ts +0 -30
  103. package/cli/generators/generate-websocket-durable-object/imports.ts +0 -55
  104. package/cli/generators/generate-websocket-durable-object/index.ts +0 -41
  105. package/cli/generators/generate-websocket-durable-object/query-handlers.ts +0 -18
  106. package/cli/generators/generate-websocket-durable-object/template.ts +0 -714
  107. package/cli/generators/generate-websocket-durable-object.ts +0 -1
  108. package/cli/schema/schema-static-types.ts +0 -702
  109. package/cli/schema/schema.ts +0 -151
  110. package/cli/utils/tsc.ts +0 -54
  111. package/cli/utils/utils.ts +0 -190
  112. package/cli/utils/zod-utils.ts +0 -121
  113. package/lib/README.md +0 -50
  114. package/lib/db.ts +0 -19
  115. package/lib/location.ts +0 -110
  116. package/lib/values.ts +0 -27
  117. package/react/README.md +0 -67
  118. package/react/hooks/useMutation.ts +0 -89
  119. package/react/hooks/usePaginatedQuery.ts +0 -213
  120. package/react/hooks/useQuery.ts +0 -106
  121. package/react/shared/queryShared.ts +0 -174
  122. package/server/README.md +0 -218
  123. package/server/auth.ts +0 -107
  124. package/server/database/builders.ts +0 -83
  125. package/server/database/context.ts +0 -327
  126. package/server/database/populate.ts +0 -234
  127. package/server/database/query-builder.ts +0 -161
  128. package/server/database/query-utils.ts +0 -25
  129. package/server/db.ts +0 -2
  130. package/server/storage/auth.ts +0 -16
  131. package/server/storage/bucket.ts +0 -22
  132. package/server/storage/context.ts +0 -34
  133. package/server/storage/index.ts +0 -38
  134. package/server/storage/operations.ts +0 -149
  135. package/server/storage/route-handler.ts +0 -60
  136. package/server/storage/types.ts +0 -55
  137. package/server/storage/utils.ts +0 -47
  138. package/server/storage.ts +0 -6
  139. package/server/types/schema-refs.ts +0 -66
  140. package/server/types/types.ts +0 -633
  141. package/server/utils/id-utils.ts +0 -230
@@ -1,371 +0,0 @@
1
- export type ServerTemplateParams = {
2
- schemaImportPath: string;
3
- configImportLine: string;
4
- handlerImports: string[];
5
- authImports: string;
6
- authSetupBlock: string;
7
- authMountBlock: string;
8
- authResolverBlock: string;
9
- routeLines: string[];
10
- httpLines: string[];
11
- };
12
-
13
- export function renderServerTemplate(params: ServerTemplateParams): string {
14
- const authImportBlock = params.authImports ? `\n${params.authImports}\n` : "";
15
- const handlerImportBlock = params.handlerImports.join("\n");
16
-
17
- return `/* eslint-disable */
18
- /**
19
- * This file is auto-generated by appflare/handler-build.ts.
20
- * Do not edit directly.
21
- */
22
-
23
- import { Hono } from "hono";
24
- import type { Context as HonoContext } from "hono";
25
- import { sValidator } from "@hono/standard-validator";
26
- import { z } from "zod";
27
- import { cors } from "hono/cors";
28
- import schema from ${JSON.stringify(params.schemaImportPath)};
29
- ${params.configImportLine}
30
- import {
31
- \tcreateMongoDbContext,
32
- \ttype MongoDbContext,
33
- } from "appflare/server/db";
34
- import {
35
- \tcreateR2StorageManager,
36
- \ttype StorageManagerOptions,
37
- } from "appflare/server/storage";${authImportBlock}
38
- import type {
39
- \tAppflareAuthContext,
40
- \tAppflareAuthSession,
41
- \tAppflareAuthUser,
42
- \tTableDocMap,
43
- \tTableNames,
44
- \tScheduler,
45
- } from "../src/schema-types";
46
-
47
- ${handlerImportBlock}
48
-
49
- export type AppflareDbContext = MongoDbContext<TableNames, TableDocMap>;
50
-
51
- export type AppflareServerContext = AppflareAuthContext & {
52
- db: AppflareDbContext;
53
- scheduler?: Scheduler;
54
- error: AppflareErrorFactory;
55
- };
56
-
57
- export type AppflareHandlerError = Error & {
58
- status: number;
59
- details?: unknown;
60
- __appflareHandlerError: true;
61
- };
62
-
63
- export type AppflareErrorFactory = (
64
- status: number,
65
- message?: string,
66
- details?: unknown
67
- ) => AppflareHandlerError;
68
-
69
- const createHandlerError: AppflareErrorFactory = (
70
- status,
71
- message,
72
- details
73
- ) => {
74
- const err = new Error(message ?? \`HTTP \${status}\`);
75
- err.name = "AppflareHandlerError";
76
- const typed = err as AppflareHandlerError;
77
- typed.status = status;
78
- typed.details = details;
79
- typed.__appflareHandlerError = true;
80
- return typed;
81
- };
82
-
83
- const isHandlerError = (value: unknown): value is AppflareHandlerError =>
84
- !!value &&
85
- typeof value === "object" &&
86
- (value as any).__appflareHandlerError === true &&
87
- Number.isFinite((value as any).status);
88
-
89
- const handlerErrorBody = (
90
- err: AppflareHandlerError
91
- ): { error: string; details?: unknown } => {
92
- const includeDetails =
93
- err.details !== undefined &&
94
- (err.details && typeof err.details === "object"
95
- ? !(err.details instanceof Error) && !Array.isArray(err.details)
96
- : true);
97
- return includeDetails
98
- ? { error: err.message, details: err.details }
99
- : { error: err.message };
100
- };
101
-
102
- async function runHandlerWithMiddleware<TArgs, TResult>(
103
- handler: {
104
- handler: (ctx: AppflareServerContext, args: TArgs) => Promise<TResult>;
105
- middleware?: (
106
- ctx: AppflareServerContext,
107
- args: TArgs
108
- ) => Promise<TResult | void>;
109
- },
110
- ctx: AppflareServerContext,
111
- args: TArgs
112
- ): Promise<TResult> {
113
- if (handler.middleware) {
114
- const middlewareResult = await handler.middleware(ctx, args);
115
- if (typeof middlewareResult !== "undefined") {
116
- return middlewareResult as TResult;
117
- }
118
- }
119
- return handler.handler(ctx, args);
120
- }
121
-
122
- export function createAppflareDbContext(params: {
123
- \tdb: import("mongodb").Db;
124
- \tcollectionName?: (table: TableNames) => string;
125
- }): AppflareDbContext {
126
- \treturn createMongoDbContext<TableNames, TableDocMap>({
127
- \t\tdb: params.db,
128
- \t\tschema,
129
- \t\tcollectionName: params.collectionName,
130
- \t});
131
- }
132
-
133
- export type MutationNotification = {
134
- \ttable: TableNames;
135
- \thandler: { file: string; name: string };
136
- \targs: unknown;
137
- \tresult: unknown;
138
- };
139
-
140
- type DurableObjectNamespaceLike = {
141
- \tidFromName(name: string): any;
142
- \tget(id: any): { fetch(input: any, init?: RequestInit): Promise<Response> };
143
- };
144
-
145
- type MutationNotifier = (payload: MutationNotification) => Promise<void>;
146
-
147
- type RealtimeOptions = {
148
- \tnotify?: MutationNotifier;
149
- \tdurableObject?: DurableObjectNamespaceLike;
150
- \tdurableObjectName?: string;
151
- };
152
-
153
- type StorageOptions<Env = unknown, Principal = unknown> =
154
- \tPartial<StorageManagerOptions<Env, Principal>> & {
155
- \t\tenabled?: boolean;
156
- \t\tcorsOrigin?: string | string[];
157
- \t\tcorsAllowHeaders?: string[];
158
- \t\tcorsAllowMethods?: string[];
159
- \t};
160
-
161
- export type AppflareHonoServerOptions = {
162
- \t/** Provide a static Mongo Db instance. If omitted, set getDb instead. */
163
- \tdb?: import("mongodb").Db;
164
- \t/** Provide a per-request Mongo Db instance (e.g. from Cloudflare env bindings). */
165
- \tgetDb?: (c: HonoContext) => import("mongodb").Db | Promise<import("mongodb").Db>;
166
- /** Provide a scheduler instance for enqueueing background work. */
167
- scheduler?: Scheduler;
168
- /** Provide a per-request scheduler instance (e.g. derived from env bindings). */
169
- getScheduler?: (c: HonoContext) => Scheduler | Promise<Scheduler>;
170
- \t/** Optionally extend the context beyond the db wrapper. */
171
- createContext?: (
172
- c: HonoContext,
173
- db: AppflareDbContext,
174
- auth: AppflareAuthContext,
175
- scheduler?: Scheduler,
176
- error?: AppflareErrorFactory
177
- ) => AppflareServerContext | Promise<AppflareServerContext>;
178
- \tcollectionName?: (table: TableNames) => string;
179
- \tcorsOrigin?: string | string[];
180
- \trealtime?: RealtimeOptions;
181
- \tstorage?: StorageOptions;
182
- };
183
-
184
- function normalizeTableName(table: string): TableNames {
185
- \tconst tables = schema as Record<string, unknown>;
186
- \tif (tables[table]) return table as TableNames;
187
- \tconst plural = table + "s";
188
- \tif (tables[plural]) return plural as TableNames;
189
- \tthrow new Error("Unknown table: " + table);
190
- }
191
-
192
- function normalizeStorageBasePath(basePath?: string): string {
193
- \tif (!basePath) return "/storage";
194
- \tconst withLeadingSlash = basePath.startsWith("/")
195
- \t\t? basePath
196
- \t\t: "/" + basePath;
197
- \treturn withLeadingSlash.endsWith("/")
198
- \t\t? withLeadingSlash.slice(0, -1) || "/"
199
- \t\t: withLeadingSlash;
200
- }
201
-
202
- function formatHandlerError(err: unknown): {
203
- \tstatus: number;
204
- \tbody: { error: string; details?: unknown };
205
- } {
206
- if (isHandlerError(err)) {
207
- return { status: err.status, body: handlerErrorBody(err) };
208
- }
209
- \tconst statusCandidate =
210
- \t\ttypeof err === "object" && err !== null
211
- \t\t\t? Number((err as any).status ?? (err as any).statusCode)
212
- \t\t\t: undefined;
213
- \tconst status = Number.isFinite(statusCandidate)
214
- \t\t? Number(statusCandidate)
215
- \t\t: 500;
216
-
217
- \tconst message =
218
- \t\terr instanceof Error
219
- \t\t\t? err.message
220
- \t\t\t: typeof err === "string"
221
- \t\t\t\t? err
222
- \t\t\t\t: "Unknown error";
223
- \tconst includeDetails =
224
- \t\terr && typeof err === "object" && !(err instanceof Error) && !Array.isArray(err);
225
-
226
- \treturn {
227
- \t\tstatus,
228
- \t\tbody: includeDetails ? { error: message, details: err } : { error: message },
229
- \t};
230
- }
231
-
232
- export function createAppflareHonoServer(options: AppflareHonoServerOptions): Hono {
233
- \tconst fixedDb =
234
- \t\toptions.db &&
235
- \t\tcreateAppflareDbContext({
236
- \t\t\tdb: options.db,
237
- \t\t\tcollectionName: options.collectionName,
238
- \t\t});
239
-
240
- \tif (!fixedDb && !options.getDb) {
241
- \t\tthrow new Error(
242
- \t\t "AppflareHonoServer requires either options.db or options.getDb to initialize the database context."
243
- \t\t);
244
- \t}
245
-
246
- const resolveDb = async (c: HonoContext): Promise<AppflareDbContext> => {
247
- if (fixedDb) return fixedDb;
248
- const db = await options.getDb!(c);
249
- return createAppflareDbContext({
250
- db,
251
- collectionName: options.collectionName,
252
- });
253
- };
254
-
255
- const fixedScheduler = options.scheduler;
256
- const resolveScheduler = async (
257
- c: HonoContext
258
- ): Promise<Scheduler | undefined> => {
259
- if (fixedScheduler) return fixedScheduler;
260
- if (!options.getScheduler) return undefined;
261
- return options.getScheduler(c);
262
- };
263
-
264
- const createContext =
265
- options.createContext ??
266
- ((_c, db, auth, scheduler, error) =>
267
- ({
268
- db,
269
- scheduler,
270
- error: error ?? createHandlerError,
271
- ...auth,
272
- } as AppflareServerContext));
273
- \tconst notifyMutation = createMutationNotifier(options.realtime);
274
- \tconst app = new Hono();
275
- \tapp.use(
276
- \t\tcors({
277
- \t\t\torigin: options.corsOrigin ?? "*",
278
- \t\t})
279
- \t);
280
-
281
- \tconst storageOptions = options.storage ?? {};
282
- \tconst storageConfig = (appflareConfig as any).storage;
283
- \tconst storageRules = storageOptions.rules ?? storageConfig?.rules;
284
- \tconst storageEnabled =
285
- \t\t(storageOptions.enabled ?? true) && !!storageRules && storageRules.length > 0;
286
-
287
- \tif (storageEnabled) {
288
- \t\tconst storageBasePath = normalizeStorageBasePath(
289
- \t\t\tstorageOptions.basePath ?? storageConfig?.basePath
290
- \t\t);
291
- \t\tconst storageManager = createR2StorageManager({
292
- \t\t\tbasePath: storageBasePath,
293
- \t\t\tbucketBinding:
294
- \t\t\t\tstorageOptions.bucketBinding ??
295
- \t\t\t\tstorageConfig?.bucketBinding ??
296
- \t\t\t\t"APPFLARE_STORAGE",
297
- \t\t\tdefaultCacheControl:
298
- \t\t\t\tstorageOptions.defaultCacheControl ??
299
- \t\t\t\tstorageConfig?.defaultCacheControl,
300
- \t\t\tgetBucket: storageOptions.getBucket ?? storageConfig?.getBucket,
301
- \t\t\trules: storageRules!,
302
- \t\t});
303
-
304
- \t\tapp.use(
305
- \t\t\tstorageBasePath + "/*",
306
- \t\t\tcors({
307
- \t\t\t\torigin: storageOptions.corsOrigin ?? "*",
308
- \t\t\t\tallowHeaders: storageOptions.corsAllowHeaders ?? ["*"],
309
- \t\t\t\tallowMethods:
310
- \t\t\t\t\tstorageOptions.corsAllowMethods ?? [
311
- \t\t\t\t\t\t"GET",
312
- \t\t\t\t\t\t"HEAD",
313
- \t\t\t\t\t\t"PUT",
314
- \t\t\t\t\t\t"POST",
315
- \t\t\t\t\t\t"DELETE",
316
- \t\t\t\t\t\t"OPTIONS",
317
- \t\t\t\t\t],
318
- \t\t\t}),
319
- \t\t);
320
-
321
- \t\tapp.route("/", storageManager);
322
- \t}
323
- ${params.authSetupBlock}${params.authMountBlock}${params.authResolverBlock}\tconst resolveContext = async (
324
- c: HonoContext
325
- ): Promise<AppflareServerContext> => {
326
- const db = await resolveDb(c);
327
- const auth = await resolveAuthContext(c);
328
- const scheduler = await resolveScheduler(c);
329
- const error = createHandlerError;
330
- const ctx = await createContext(c, db, auth, scheduler, error);
331
- const merged = {
332
- db,
333
- scheduler,
334
- error,
335
- ...auth,
336
- ...(ctx ?? {}),
337
- error: (ctx as any)?.error ?? error,
338
- };
339
- return merged as AppflareServerContext;
340
- };
341
-
342
- ${params.routeLines.join("\n\n\t")}
343
-
344
- ${params.httpLines.join("\n\n\t")}
345
-
346
- return app;
347
- }
348
-
349
- function createMutationNotifier(
350
- options?: RealtimeOptions
351
- ): MutationNotifier | undefined {
352
- \tif (!options) return undefined;
353
- \tif (options.notify) return options.notify;
354
- \tif (options.durableObject) {
355
- \t\treturn async (payload: MutationNotification) => {
356
- \t\t\tconst id = options.durableObject!.idFromName(
357
- \t\t\t\toptions.durableObjectName ?? "primary"
358
- \t\t\t);
359
- \t\t\tconst stub = options.durableObject!.get(id);
360
- \t\t\tawait stub.fetch("http://appflare-realtime/notify", {
361
- \t\t\t\tmethod: "POST",
362
- \t\t\t\theaders: { "content-type": "application/json" },
363
- \t\t\t\tbody: JSON.stringify(payload),
364
- \t\t\t});
365
- \t\t};
366
- \t}
367
- \treturn undefined;
368
- }
369
-
370
- `;
371
- }
@@ -1 +0,0 @@
1
- export { generateHonoServer } from "./generate-hono-server/index";
@@ -1,8 +0,0 @@
1
- export const schemaTypesImportPath = "../src/schema-types";
2
- export const serverImportPath = "./server";
3
-
4
- export const filePreamble = `/* eslint-disable */
5
- /**
6
- * This file is auto-generated by appflare/handler-build.ts.
7
- * Do not edit directly.
8
- */`;
@@ -1,22 +0,0 @@
1
- import type { DiscoveredHandler } from "../../utils/utils";
2
-
3
- export const buildHandlerEntries = (params: {
4
- handlers: DiscoveredHandler[];
5
- localNameFor: (handler: DiscoveredHandler) => string;
6
- }): string => {
7
- if (params.handlers.length === 0) return "";
8
-
9
- return params.handlers
10
- .map((handler) => {
11
- const local = params.localNameFor(handler);
12
- const task = `${handler.routePath}/${handler.name}`;
13
- return (
14
- `\t${JSON.stringify(task)}: {\n` +
15
- ` \tfile: ${JSON.stringify(handler.routePath)},\n` +
16
- `\t\tname: ${JSON.stringify(handler.name)},\n` +
17
- `\t\trun: ${local}.handler,\n` +
18
- `\t},`
19
- );
20
- })
21
- .join("\n");
22
- };
@@ -1,51 +0,0 @@
1
- import { buildImportSection } from "../generate-hono-server/imports";
2
- import type { DiscoveredHandler } from "../../utils/utils";
3
- import {
4
- schemaTypesImportPath,
5
- serverImportPath,
6
- filePreamble,
7
- } from "./constants";
8
- import { buildHandlerEntries } from "./handler-entries";
9
- import { buildSchedulerHandlersBlock } from "./scheduler-handlers-block";
10
- import { buildTypeHelpersBlock } from "./type-helpers-block";
11
- import { buildRuntimeBlock } from "./runtime-block";
12
-
13
- export function generateSchedulerHandlers(params: {
14
- handlers: DiscoveredHandler[];
15
- outDirAbs: string;
16
- schemaPathAbs: string;
17
- configPathAbs: string;
18
- }): string {
19
- const schedulerHandlers = params.handlers.filter(
20
- (handler) => handler.kind === "scheduler"
21
- );
22
-
23
- const imports = buildImportSection({
24
- handlers: schedulerHandlers,
25
- outDirAbs: params.outDirAbs,
26
- schemaPathAbs: params.schemaPathAbs,
27
- configPathAbs: params.configPathAbs,
28
- });
29
-
30
- const handlerImportBlock =
31
- imports.handlerImports.length > 0
32
- ? `${imports.handlerImports.join("\n")}\n\n`
33
- : "";
34
-
35
- const handlerEntries = buildHandlerEntries({
36
- handlers: schedulerHandlers,
37
- localNameFor: imports.localNameFor,
38
- });
39
-
40
- const importsBlock = `import { createAppflareDbContext, type AppflareDbContext } from ${JSON.stringify(serverImportPath)};\nimport type {\n\tScheduler,\n\tSchedulerEnqueueOptions,\n\tAppflareAuthContext,\n\tAppflareAuthSession,\n\tAppflareAuthUser,\n} from ${JSON.stringify(schemaTypesImportPath)};\nimport { getDatabase } from "cloudflare-do-mongo";\nimport { Db } from "mongodb";\n${handlerImportBlock}`;
41
-
42
- return [
43
- filePreamble,
44
- "",
45
- importsBlock,
46
- buildSchedulerHandlersBlock(handlerEntries),
47
- buildTypeHelpersBlock(),
48
- buildRuntimeBlock(),
49
- "export type { SchedulerTaskName };\n",
50
- ].join("\n");
51
- }
@@ -1,68 +0,0 @@
1
- export const buildRuntimeBlock = (): string => `
2
- export const createScheduler = (
3
- queue?: Env["APPFLARE_SCHEDULER_QUEUE"]
4
- ): TypedScheduler => {
5
- const enqueue: SchedulerEnqueue = async (task, ...args) => {
6
- const [payload, options] = args;
7
- if (!queue) {
8
- throw new Error("Scheduler queue binding is not configured");
9
- }
10
-
11
- await queue.send({ task, payload }, options);
12
- };
13
-
14
- return { enqueue };
15
- };
16
-
17
- export async function handleSchedulerBatch(params: {
18
- batch: { messages: Array<{ body: unknown }> };
19
- env: Env;
20
- }): Promise<void> {
21
- const { env, batch } = params;
22
- if (!env.APPFLARE_SCHEDULER_QUEUE) {
23
- console.warn("Scheduler queue binding missing; skipping batch");
24
- return;
25
- }
26
-
27
- const db = createAppflareDbContext({
28
- db: getDatabase(env.MONGO_DB) as unknown as Db,
29
- });
30
- const scheduler = createScheduler(env.APPFLARE_SCHEDULER_QUEUE);
31
- const baseContext: SchedulerHandlerContext = {
32
- ...emptyAuthContext,
33
- db,
34
- scheduler,
35
- env,
36
- };
37
-
38
- const handlerLookup =
39
- schedulerHandlers as unknown as SchedulerHandlerLookup;
40
-
41
- for (const message of batch.messages ?? []) {
42
- const body = (message ?? {}).body as Partial<
43
- SchedulerQueueMessage
44
- >;
45
- const task = body?.task;
46
- if (!task || !(task in schedulerHandlers)) {
47
- console.warn("Skipping scheduler task", task);
48
- continue;
49
- }
50
-
51
- const schedulerTask = task as SchedulerTaskName;
52
- const handler = handlerLookup[schedulerTask as string];
53
- if (!handler) {
54
- console.warn("Skipping scheduler task", schedulerTask);
55
- continue;
56
- }
57
-
58
- try {
59
- await handler.run(
60
- baseContext,
61
- body?.payload as SchedulerPayload<SchedulerTaskName>
62
- );
63
- } catch (err) {
64
- console.error("Scheduler task failed", schedulerTask, err);
65
- }
66
- }
67
- }
68
- `;
@@ -1,2 +0,0 @@
1
- export const buildSchedulerHandlersBlock = (handlerEntries: string): string =>
2
- `const schedulerHandlers = {\n${handlerEntries}\n} as const;`;
@@ -1,68 +0,0 @@
1
- export const buildTypeHelpersBlock = (): string => `
2
- type SchedulerHandlers = typeof schedulerHandlers;
3
-
4
- type SchedulerHandlerPayloads = {
5
- [Task in keyof SchedulerHandlers]: SchedulerHandlers[Task] extends {
6
- run: (ctx: unknown, payload: infer TPayload) => Promise<void>;
7
- }
8
- ? TPayload
9
- : unknown;
10
- };
11
-
12
- declare global {
13
- interface AppflareSchedulerHandlerMap extends SchedulerHandlerPayloads {}
14
- }
15
-
16
- type SchedulerTaskName = keyof SchedulerHandlers extends never
17
- ? string
18
- : keyof SchedulerHandlers;
19
-
20
- type SchedulerPayload<TTask extends SchedulerTaskName> = TTask extends keyof SchedulerHandlers
21
- ? SchedulerHandlers[TTask] extends {
22
- run: (ctx: unknown, payload: infer TPayload) => Promise<void>;
23
- }
24
- ? TPayload
25
- : unknown
26
- : unknown;
27
-
28
- type SchedulerQueueMessage<TTask extends SchedulerTaskName = SchedulerTaskName> = {
29
- task: TTask;
30
- payload?: SchedulerPayload<TTask>;
31
- };
32
-
33
- type Env = {
34
- MONGO_DB: unknown;
35
- APPFLARE_SCHEDULER_QUEUE?: {
36
- send: (body: unknown, options?: { delaySeconds?: number }) => Promise<void>;
37
- };
38
- } & Record<string, unknown>;
39
-
40
- const emptyAuthContext: AppflareAuthContext = {
41
- session: null as AppflareAuthSession,
42
- user: null as AppflareAuthUser,
43
- };
44
-
45
- type SchedulerHandlerContext = AppflareAuthContext & {
46
- db: AppflareDbContext;
47
- scheduler: TypedScheduler;
48
- env: Env;
49
- };
50
-
51
- type SchedulerEnqueue = {
52
- <TTask extends SchedulerTaskName>(
53
- task: TTask,
54
- ...args: SchedulerPayload<TTask> extends undefined
55
- ? [payload?: SchedulerPayload<TTask>, options?: SchedulerEnqueueOptions]
56
- : [payload: SchedulerPayload<TTask>, options?: SchedulerEnqueueOptions]
57
- ): Promise<void>;
58
- };
59
-
60
- type TypedScheduler = Omit<Scheduler, "enqueue"> & {
61
- enqueue: SchedulerEnqueue;
62
- };
63
-
64
- type SchedulerHandlerLookup = Record<
65
- string,
66
- { run: (ctx: SchedulerHandlerContext, payload: unknown) => Promise<void> }
67
- >;
68
- `;
@@ -1 +0,0 @@
1
- export { generateSchedulerHandlers } from "./generate-scheduler-handlers/index";
@@ -1,30 +0,0 @@
1
- import type { AppflareConfig } from "../../utils/utils";
2
-
3
- export type WebsocketDoAuthSection = {
4
- importLine: string;
5
- setupBlock: string;
6
- };
7
-
8
- export function buildAuthSection(
9
- config: AppflareConfig
10
- ): WebsocketDoAuthSection {
11
- const hasAuth = Boolean(config.auth && config.auth.enabled !== false);
12
-
13
- const importLine = hasAuth
14
- ? 'import { initBetterAuth } from "appflare/server/auth";'
15
- : "";
16
-
17
- const setupBlock = hasAuth
18
- ? [
19
- "const __appflareAuthConfig = (appflareConfig as any).auth;",
20
- "const __appflareAuth =",
21
- "\t__appflareAuthConfig &&",
22
- "\t__appflareAuthConfig.enabled !== false &&",
23
- "\t__appflareAuthConfig.options",
24
- "\t\t? initBetterAuth(__appflareAuthConfig.options as any)",
25
- "\t\t: undefined;",
26
- ].join("\n")
27
- : "const __appflareAuth = undefined;";
28
-
29
- return { importLine, setupBlock };
30
- }
@@ -1,55 +0,0 @@
1
- import {
2
- DiscoveredHandler,
3
- groupBy,
4
- pascalCase,
5
- toImportPathFromGeneratedServer,
6
- } from "../../utils/utils";
7
-
8
- export type WebsocketDoImportSection = {
9
- schemaImportPath: string;
10
- configImportPath: string;
11
- handlerImports: string[];
12
- localNameFor: (handler: DiscoveredHandler) => string;
13
- };
14
-
15
- export function buildImportSection(params: {
16
- queries: DiscoveredHandler[];
17
- outDirAbs: string;
18
- schemaPathAbs: string;
19
- configPathAbs: string;
20
- }): WebsocketDoImportSection {
21
- const schemaImportPath = toImportPathFromGeneratedServer(
22
- params.outDirAbs,
23
- params.schemaPathAbs
24
- );
25
- const configImportPath = toImportPathFromGeneratedServer(
26
- params.outDirAbs,
27
- params.configPathAbs
28
- );
29
-
30
- const localNameFor = (handler: DiscoveredHandler): string =>
31
- `__appflare_${pascalCase(handler.routePath)}_${handler.name}`;
32
-
33
- const grouped = groupBy(params.queries, (handler) => handler.sourceFileAbs);
34
- const handlerImports: string[] = [];
35
- for (const [fileAbs, list] of Array.from(grouped.entries())) {
36
- const specifiers = list
37
- .slice()
38
- .sort((a, b) => a.name.localeCompare(b.name))
39
- .map((handler) => `${handler.name} as ${localNameFor(handler)}`);
40
- const importPath = toImportPathFromGeneratedServer(
41
- params.outDirAbs,
42
- fileAbs
43
- );
44
- handlerImports.push(
45
- `import { ${specifiers.join(", ")} } from ${JSON.stringify(importPath)};`
46
- );
47
- }
48
-
49
- return {
50
- schemaImportPath,
51
- configImportPath,
52
- handlerImports,
53
- localNameFor,
54
- };
55
- }