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.
- 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 +747 -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 +353 -0
- package/cli/templates/handlers/auth.ts +37 -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/generators/registration/modules/cron.ts +30 -0
- package/cli/templates/handlers/generators/registration/modules/realtime.ts +631 -0
- package/cli/templates/handlers/generators/registration/modules/scheduler.ts +56 -0
- package/cli/templates/handlers/generators/registration/modules/storage.ts +194 -0
- package/cli/templates/handlers/generators/registration/sections.ts +210 -0
- package/cli/templates/handlers/generators/types/context.ts +64 -0
- package/cli/templates/handlers/generators/types/core.ts +101 -0
- package/cli/templates/handlers/generators/types/operations.ts +135 -0
- package/cli/templates/handlers/generators/types/query-definitions.ts +1029 -0
- package/cli/templates/handlers/generators/types/query-runtime.ts +417 -0
- package/cli/templates/handlers/index.ts +43 -0
- package/cli/templates/handlers/operations.ts +116 -0
- package/cli/templates/handlers/registration.ts +83 -0
- package/cli/templates/handlers/types.ts +15 -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
|
@@ -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
|
+
}
|