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.
- package/cli/commands/index.ts +140 -0
- package/cli/generate.ts +149 -0
- package/cli/index.ts +56 -447
- package/cli/load-config.ts +182 -0
- package/cli/schema-compiler.ts +657 -0
- package/cli/templates/auth/README.md +156 -0
- package/cli/templates/auth/config.ts +61 -0
- package/cli/templates/auth/route-config.ts +18 -0
- package/cli/templates/auth/route-handler.ts +18 -0
- package/cli/templates/auth/route-request-utils.ts +55 -0
- package/cli/templates/auth/route.ts +14 -0
- package/cli/templates/core/README.md +266 -0
- package/cli/templates/core/app-creation.ts +19 -0
- package/cli/templates/core/client/appflare.ts +37 -0
- package/cli/templates/core/client/index.ts +6 -0
- package/cli/templates/core/client/storage.ts +100 -0
- package/cli/templates/core/client/types.ts +54 -0
- package/cli/templates/core/client-modules/appflare.ts +112 -0
- package/cli/templates/core/client-modules/handlers/index.ts +740 -0
- package/cli/templates/core/client-modules/handlers.ts +1 -0
- package/cli/templates/core/client-modules/index.ts +7 -0
- package/cli/templates/core/client-modules/storage.ts +180 -0
- package/cli/templates/core/client-modules/types.ts +145 -0
- package/cli/templates/core/client.ts +39 -0
- package/cli/templates/core/drizzle.ts +15 -0
- package/cli/templates/core/export.ts +14 -0
- package/cli/templates/core/handlers-route.ts +23 -0
- package/cli/templates/core/handlers.ts +1 -0
- package/cli/templates/core/imports.ts +8 -0
- package/cli/templates/core/server.ts +38 -0
- package/cli/templates/core/types.ts +6 -0
- package/cli/templates/core/wrangler.ts +109 -0
- package/cli/templates/handlers/README.md +265 -0
- package/cli/templates/handlers/auth.ts +36 -0
- package/cli/templates/handlers/execution.ts +39 -0
- package/cli/templates/handlers/generators/context/context-creation.ts +80 -0
- package/cli/templates/handlers/generators/context/error-helpers.ts +11 -0
- package/cli/templates/handlers/generators/context/scheduler.ts +24 -0
- package/cli/templates/handlers/generators/context/storage-api.ts +112 -0
- package/cli/templates/handlers/generators/context/storage-helpers.ts +59 -0
- package/cli/templates/handlers/generators/context/types.ts +18 -0
- package/cli/templates/handlers/generators/context.ts +43 -0
- package/cli/templates/handlers/generators/execution.ts +15 -0
- package/cli/templates/handlers/generators/handlers.ts +13 -0
- package/cli/templates/handlers/index.ts +43 -0
- package/cli/templates/handlers/operations.ts +116 -0
- package/cli/templates/handlers/registration.ts +1114 -0
- package/cli/templates/handlers/types.ts +960 -0
- package/cli/templates/handlers/utils.ts +48 -0
- package/cli/types.ts +108 -0
- package/cli/utils/handler-discovery.ts +366 -0
- package/cli/utils/json-utils.ts +24 -0
- package/cli/utils/path-utils.ts +19 -0
- package/cli/utils/schema-discovery.ts +390 -0
- package/index.ts +27 -4
- package/package.json +23 -20
- package/react/index.ts +5 -3
- package/react/use-infinite-query.ts +190 -0
- package/react/use-mutation.ts +54 -0
- package/react/use-query.ts +158 -0
- package/schema.ts +262 -0
- package/tsconfig.json +2 -4
- package/cli/README.md +0 -108
- package/cli/core/build.ts +0 -187
- package/cli/core/config.ts +0 -92
- package/cli/core/discover-handlers.ts +0 -143
- package/cli/core/handlers.ts +0 -7
- package/cli/core/index.ts +0 -205
- package/cli/generators/generate-api-client/client.ts +0 -163
- package/cli/generators/generate-api-client/extract-configuration.ts +0 -121
- package/cli/generators/generate-api-client/index.ts +0 -973
- package/cli/generators/generate-api-client/types.ts +0 -164
- package/cli/generators/generate-api-client/utils.ts +0 -22
- package/cli/generators/generate-api-client.ts +0 -1
- package/cli/generators/generate-cloudflare-worker/helpers.ts +0 -24
- package/cli/generators/generate-cloudflare-worker/index.ts +0 -2
- package/cli/generators/generate-cloudflare-worker/worker.ts +0 -148
- package/cli/generators/generate-cloudflare-worker/wrangler.ts +0 -108
- package/cli/generators/generate-cloudflare-worker.ts +0 -4
- package/cli/generators/generate-cron-handlers/cron-handlers-block.ts +0 -2
- package/cli/generators/generate-cron-handlers/handler-entries.ts +0 -29
- package/cli/generators/generate-cron-handlers/index.ts +0 -61
- package/cli/generators/generate-cron-handlers/runtime-block.ts +0 -49
- package/cli/generators/generate-cron-handlers/type-helpers-block.ts +0 -60
- package/cli/generators/generate-db-handlers/index.ts +0 -33
- package/cli/generators/generate-db-handlers/prepare.ts +0 -24
- package/cli/generators/generate-db-handlers/templates.ts +0 -189
- package/cli/generators/generate-db-handlers.ts +0 -1
- package/cli/generators/generate-hono-server/auth.ts +0 -97
- package/cli/generators/generate-hono-server/imports.ts +0 -55
- package/cli/generators/generate-hono-server/index.ts +0 -52
- package/cli/generators/generate-hono-server/routes.ts +0 -115
- package/cli/generators/generate-hono-server/template.ts +0 -371
- package/cli/generators/generate-hono-server.ts +0 -1
- package/cli/generators/generate-scheduler-handlers/constants.ts +0 -8
- package/cli/generators/generate-scheduler-handlers/handler-entries.ts +0 -22
- package/cli/generators/generate-scheduler-handlers/index.ts +0 -51
- package/cli/generators/generate-scheduler-handlers/runtime-block.ts +0 -68
- package/cli/generators/generate-scheduler-handlers/scheduler-handlers-block.ts +0 -2
- package/cli/generators/generate-scheduler-handlers/type-helpers-block.ts +0 -68
- package/cli/generators/generate-scheduler-handlers.ts +0 -1
- package/cli/generators/generate-websocket-durable-object/auth.ts +0 -30
- package/cli/generators/generate-websocket-durable-object/imports.ts +0 -55
- package/cli/generators/generate-websocket-durable-object/index.ts +0 -41
- package/cli/generators/generate-websocket-durable-object/query-handlers.ts +0 -18
- package/cli/generators/generate-websocket-durable-object/template.ts +0 -714
- package/cli/generators/generate-websocket-durable-object.ts +0 -1
- package/cli/schema/schema-static-types.ts +0 -702
- package/cli/schema/schema.ts +0 -151
- package/cli/utils/tsc.ts +0 -54
- package/cli/utils/utils.ts +0 -190
- package/cli/utils/zod-utils.ts +0 -121
- package/lib/README.md +0 -50
- package/lib/db.ts +0 -19
- package/lib/location.ts +0 -110
- package/lib/values.ts +0 -27
- package/react/README.md +0 -67
- package/react/hooks/useMutation.ts +0 -89
- package/react/hooks/usePaginatedQuery.ts +0 -213
- package/react/hooks/useQuery.ts +0 -106
- package/react/shared/queryShared.ts +0 -174
- package/server/README.md +0 -218
- package/server/auth.ts +0 -107
- package/server/database/builders.ts +0 -83
- package/server/database/context.ts +0 -327
- package/server/database/populate.ts +0 -234
- package/server/database/query-builder.ts +0 -161
- package/server/database/query-utils.ts +0 -25
- package/server/db.ts +0 -2
- package/server/storage/auth.ts +0 -16
- package/server/storage/bucket.ts +0 -22
- package/server/storage/context.ts +0 -34
- package/server/storage/index.ts +0 -38
- package/server/storage/operations.ts +0 -149
- package/server/storage/route-handler.ts +0 -60
- package/server/storage/types.ts +0 -55
- package/server/storage/utils.ts +0 -47
- package/server/storage.ts +0 -6
- package/server/types/schema-refs.ts +0 -66
- package/server/types/types.ts +0 -633
- 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,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,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
|
-
}
|