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
package/cli/core/build.ts DELETED
@@ -1,187 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import { spawn } from "node:child_process";
4
- import {
5
- AppflareConfig,
6
- assertDirExists,
7
- assertFileExists,
8
- toImportPathFromGeneratedSrc,
9
- } from "../utils/utils";
10
- import { getSchemaTableNames, generateSchemaTypes } from "../schema/schema";
11
- import {
12
- generateDbHandlers,
13
- discoverHandlers,
14
- generateApiClient,
15
- generateHonoServer,
16
- generateWebsocketDurableObject,
17
- generateSchedulerHandlers,
18
- generateCronHandlers,
19
- } from "./handlers";
20
-
21
- export async function buildFromConfig(params: {
22
- config: AppflareConfig;
23
- configDirAbs: string;
24
- configPathAbs: string;
25
- emit: boolean;
26
- }): Promise<void> {
27
- const { config, configDirAbs, emit, configPathAbs } = params;
28
-
29
- const projectDirAbs = path.resolve(configDirAbs, config.dir);
30
- const schemaPathAbs = path.resolve(configDirAbs, config.schema);
31
- const outDirAbs = path.resolve(configDirAbs, config.outDir);
32
-
33
- await assertDirExists(
34
- projectDirAbs,
35
- `Project dir not found: ${projectDirAbs}`,
36
- );
37
- await assertFileExists(schemaPathAbs, `Schema not found: ${schemaPathAbs}`);
38
-
39
- await fs.mkdir(path.join(outDirAbs, "src"), { recursive: true });
40
- await fs.mkdir(path.join(outDirAbs, "server"), { recursive: true });
41
-
42
- // Re-export the user schema inside the generated output so downstream code can import it from the build directory.
43
- const schemaImportPathForGeneratedSrc = toImportPathFromGeneratedSrc(
44
- outDirAbs,
45
- schemaPathAbs,
46
- );
47
- const schemaReexport = `import schema from ${JSON.stringify(schemaImportPathForGeneratedSrc)};
48
- export type AppflareGeneratedSchema = typeof schema;
49
- export default schema;
50
- `;
51
- await fs.writeFile(path.join(outDirAbs, "src", "schema.ts"), schemaReexport);
52
-
53
- const schemaTypesTs = await generateSchemaTypes({
54
- schemaPathAbs,
55
- configPathAbs,
56
- outDirAbs,
57
- });
58
- await fs.writeFile(
59
- path.join(outDirAbs, "src", "schema-types.ts"),
60
- schemaTypesTs,
61
- );
62
-
63
- // (Re)generate built-in DB handlers based on the schema tables.
64
- const schemaTableNames = await getSchemaTableNames(schemaPathAbs);
65
- await generateDbHandlers({ outDirAbs, tableNames: schemaTableNames });
66
-
67
- const handlers = await discoverHandlers({
68
- projectDirAbs,
69
- schemaPathAbs,
70
- outDirAbs,
71
- configPathAbs,
72
- });
73
-
74
- const apiTs = generateApiClient({
75
- handlers,
76
- outDirAbs,
77
- authBasePath:
78
- config.auth && config.auth.enabled === false
79
- ? undefined
80
- : (config.auth?.basePath ?? "/auth"),
81
- authEnabled: config.auth?.enabled !== false,
82
- configPathAbs,
83
- });
84
- await fs.writeFile(path.join(outDirAbs, "src", "api.ts"), apiTs);
85
-
86
- const serverTs = generateHonoServer({
87
- handlers,
88
- outDirAbs,
89
- schemaPathAbs,
90
- configPathAbs,
91
- config,
92
- });
93
- await fs.writeFile(path.join(outDirAbs, "server", "server.ts"), serverTs);
94
-
95
- const websocketDoTs = generateWebsocketDurableObject({
96
- handlers,
97
- outDirAbs,
98
- schemaPathAbs,
99
- configPathAbs,
100
- config,
101
- });
102
- await fs.writeFile(
103
- path.join(outDirAbs, "server", "websocket-hibernation-server.ts"),
104
- websocketDoTs,
105
- );
106
-
107
- const schedulerTs = generateSchedulerHandlers({
108
- handlers,
109
- outDirAbs,
110
- schemaPathAbs,
111
- configPathAbs,
112
- });
113
- await fs.writeFile(
114
- path.join(outDirAbs, "server", "scheduler.ts"),
115
- schedulerTs,
116
- );
117
-
118
- const { code: cronTs } = generateCronHandlers({
119
- handlers,
120
- outDirAbs,
121
- schemaPathAbs,
122
- configPathAbs,
123
- });
124
- await fs.writeFile(path.join(outDirAbs, "server", "cron.ts"), cronTs);
125
-
126
- if (emit) {
127
- // Remove previous emit output to avoid stale files lingering.
128
- await fs.rm(path.join(outDirAbs, "dist"), { recursive: true, force: true });
129
-
130
- // Emit only the files that don't pull in user code outside rootDir.
131
- // This avoids TS rootDir issues and dist overwrite issues caused by user modules.
132
- const emitTsconfigAbs = await writeEmitTsconfig({
133
- configDirAbs,
134
- outDirAbs,
135
- });
136
- await runTscEmit(emitTsconfigAbs);
137
- }
138
- }
139
-
140
- async function writeEmitTsconfig(params: {
141
- configDirAbs: string;
142
- outDirAbs: string;
143
- }): Promise<string> {
144
- const outDirRel =
145
- path.relative(params.configDirAbs, params.outDirAbs).replace(/\\/g, "/") ||
146
- "./_generated";
147
- const tsconfigPathAbs = path.join(
148
- params.configDirAbs,
149
- ".appflare.tsconfig.emit.json",
150
- );
151
- const content = {
152
- compilerOptions: {
153
- noEmit: false,
154
- declaration: true,
155
- emitDeclarationOnly: false,
156
- outDir: `./${outDirRel}/dist`,
157
- rootDir: `.`,
158
- sourceMap: false,
159
- declarationMap: false,
160
- skipLibCheck: true,
161
- target: "ES2022",
162
- module: "ES2022",
163
- moduleResolution: "Bundler",
164
- types: ["node"],
165
- },
166
- include: [
167
- `./${outDirRel}/src/schema-types.ts`,
168
- `./${outDirRel}/src/schema.ts`,
169
- `./${outDirRel}/src/handlers/**/*`,
170
- ],
171
- };
172
- await fs.writeFile(tsconfigPathAbs, JSON.stringify(content, null, 2));
173
- return tsconfigPathAbs;
174
- }
175
-
176
- async function runTscEmit(tsconfigPathAbs: string): Promise<void> {
177
- await new Promise<void>((resolve, reject) => {
178
- const child = spawn("bunx", ["tsc", "-p", tsconfigPathAbs], {
179
- stdio: "inherit",
180
- });
181
- child.on("error", reject);
182
- child.on("exit", (code) => {
183
- if (code === 0) resolve();
184
- reject(new Error(`tsc exited with code ${code}`));
185
- });
186
- });
187
- }
@@ -1,92 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import { pathToFileURL } from "node:url";
4
- import { AppflareConfig, assertFileExists } from "../utils/utils";
5
-
6
- export async function loadConfig(
7
- configPathAbs: string,
8
- ): Promise<{ config: AppflareConfig; configDirAbs: string }> {
9
- await assertFileExists(configPathAbs, `Config not found: ${configPathAbs}`);
10
- const configDirAbs = path.dirname(configPathAbs);
11
-
12
- const mod = await import(pathToFileURL(configPathAbs).href);
13
- const config = (mod?.default ?? mod) as Partial<AppflareConfig>;
14
- if (!config || typeof config !== "object") {
15
- throw new Error(
16
- `Invalid config export in ${configPathAbs} (expected default export object)`,
17
- );
18
- }
19
- if (typeof config.dir !== "string" || !config.dir) {
20
- throw new Error(`Invalid config.dir in ${configPathAbs}`);
21
- }
22
- if (typeof config.schema !== "string" || !config.schema) {
23
- throw new Error(`Invalid config.schema in ${configPathAbs}`);
24
- }
25
- if (typeof config.outDir !== "string" || !config.outDir) {
26
- throw new Error(`Invalid config.outDir in ${configPathAbs}`);
27
- }
28
-
29
- const auth = (config as AppflareConfig).auth;
30
- if (auth !== undefined) {
31
- if (!auth || typeof auth !== "object") {
32
- throw new Error(`Invalid config.auth in ${configPathAbs}`);
33
- }
34
- if (auth.basePath !== undefined && typeof auth.basePath !== "string") {
35
- throw new Error(`Invalid config.auth.basePath in ${configPathAbs}`);
36
- }
37
- if (auth.enabled !== undefined && typeof auth.enabled !== "boolean") {
38
- throw new Error(`Invalid config.auth.enabled in ${configPathAbs}`);
39
- }
40
- if (auth.options !== undefined && typeof auth.options !== "object") {
41
- throw new Error(`Invalid config.auth.options in ${configPathAbs}`);
42
- }
43
- if (
44
- auth.clientOptions !== undefined &&
45
- typeof auth.clientOptions !== "object"
46
- ) {
47
- throw new Error(`Invalid config.auth.clientOptions in ${configPathAbs}`);
48
- }
49
- }
50
-
51
- const storage = (config as AppflareConfig).storage;
52
- if (storage !== undefined) {
53
- if (!storage || typeof storage !== "object") {
54
- throw new Error(`Invalid config.storage in ${configPathAbs}`);
55
- }
56
- if (!Array.isArray(storage.rules)) {
57
- throw new Error(`Invalid config.storage.rules in ${configPathAbs}`);
58
- }
59
- if (
60
- storage.basePath !== undefined &&
61
- typeof storage.basePath !== "string"
62
- ) {
63
- throw new Error(`Invalid config.storage.basePath in ${configPathAbs}`);
64
- }
65
- if (
66
- storage.bucketBinding !== undefined &&
67
- typeof storage.bucketBinding !== "string"
68
- ) {
69
- throw new Error(
70
- `Invalid config.storage.bucketBinding in ${configPathAbs}`,
71
- );
72
- }
73
- if (
74
- storage.defaultCacheControl !== undefined &&
75
- typeof storage.defaultCacheControl !== "string"
76
- ) {
77
- throw new Error(
78
- `Invalid config.storage.defaultCacheControl in ${configPathAbs}`,
79
- );
80
- }
81
- if (
82
- storage.kvBinding !== undefined &&
83
- typeof storage.kvBinding !== "string"
84
- ) {
85
- throw new Error(`Invalid config.storage.kvBinding in ${configPathAbs}`);
86
- }
87
- if (storage.kvId !== undefined && typeof storage.kvId !== "string") {
88
- throw new Error(`Invalid config.storage.kvId in ${configPathAbs}`);
89
- }
90
- }
91
- return { config: config as AppflareConfig, configDirAbs };
92
- }
@@ -1,143 +0,0 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import * as ts from "typescript";
4
- import {
5
- DiscoveredHandler,
6
- HandlerKind,
7
- walkTsFiles,
8
- groupBy,
9
- } from "../utils/utils";
10
-
11
- export async function discoverHandlers(params: {
12
- projectDirAbs: string;
13
- schemaPathAbs: string;
14
- outDirAbs: string;
15
- configPathAbs: string;
16
- }): Promise<DiscoveredHandler[]> {
17
- const ignoreDirs = new Set([
18
- "node_modules",
19
- ".git",
20
- "dist",
21
- "build",
22
- path.basename(params.outDirAbs),
23
- ]);
24
-
25
- const files = await walkTsFiles(params.projectDirAbs, ignoreDirs);
26
-
27
- const handlers: DiscoveredHandler[] = [];
28
- for (const fileAbs of files) {
29
- if (path.resolve(fileAbs) === path.resolve(params.schemaPathAbs)) continue;
30
- if (path.resolve(fileAbs) === path.resolve(params.configPathAbs)) continue;
31
-
32
- const relPathRaw = path.relative(params.projectDirAbs, fileAbs);
33
- const relPath = relPathRaw.replace(/\\/g, "/");
34
- const rawRoutePath = relPath.replace(/\.ts$/, "");
35
- const routePath = rawRoutePath.endsWith("/index")
36
- ? rawRoutePath.slice(0, -"/index".length) || "index"
37
- : rawRoutePath;
38
-
39
- const content = await fs.readFile(fileAbs, "utf8");
40
- const cronTriggersByHandler = extractCronTriggers(content);
41
- const regex =
42
- /export\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(query|mutation|internalQuery|internalMutation|scheduler|cron|http)\s*\(/g;
43
- let match: RegExpExecArray | null;
44
- while ((match = regex.exec(content)) !== null) {
45
- const kind = match[2] as HandlerKind;
46
- handlers.push({
47
- fileName: path.basename(fileAbs, ".ts"),
48
- routePath,
49
- name: match[1],
50
- kind,
51
- sourceFileAbs: fileAbs,
52
- cronTriggers:
53
- kind === "cron" ? cronTriggersByHandler.get(match[1]) : undefined,
54
- });
55
- }
56
- }
57
-
58
- // De-dupe: keep first occurrence
59
- const seen = new Set<string>();
60
- const unique = handlers.filter((h) => {
61
- const key = `${h.kind}:${h.routePath}:${h.name}`;
62
- if (seen.has(key)) return false;
63
- seen.add(key);
64
- return true;
65
- });
66
-
67
- unique.sort((a, b) => {
68
- if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
69
- if (a.routePath !== b.routePath)
70
- return a.routePath.localeCompare(b.routePath);
71
- if (a.fileName !== b.fileName) return a.fileName.localeCompare(b.fileName);
72
- return a.name.localeCompare(b.name);
73
- });
74
-
75
- return unique;
76
- }
77
-
78
- const cronPropertyNames = new Set(["cronTrigger", "cronTriggers"]);
79
-
80
- const isExported = (node: ts.Node): boolean => {
81
- return Boolean(
82
- ts.canHaveModifiers(node) &&
83
- node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)
84
- );
85
- };
86
-
87
- const extractCronTriggers = (sourceText: string): Map<string, string[]> => {
88
- const sourceFile = ts.createSourceFile(
89
- "cron-handlers.ts",
90
- sourceText,
91
- ts.ScriptTarget.Latest,
92
- true
93
- );
94
- const triggersByHandler = new Map<string, string[]>();
95
-
96
- const visit = (node: ts.Node): void => {
97
- if (ts.isVariableStatement(node) && isExported(node)) {
98
- for (const decl of node.declarationList.declarations) {
99
- if (!ts.isIdentifier(decl.name)) continue;
100
- const initializer = decl.initializer;
101
- if (!initializer || !ts.isCallExpression(initializer)) continue;
102
- const callee = initializer.expression;
103
- if (!ts.isIdentifier(callee) || callee.text !== "cron") continue;
104
- const cronTriggers = parseCronTriggerArg(initializer.arguments[0]);
105
- if (cronTriggers && cronTriggers.length > 0) {
106
- triggersByHandler.set(decl.name.text, cronTriggers);
107
- }
108
- }
109
- }
110
- ts.forEachChild(node, visit);
111
- };
112
-
113
- visit(sourceFile);
114
- return triggersByHandler;
115
- };
116
-
117
- const parseCronTriggerArg = (arg?: ts.Expression): string[] | undefined => {
118
- if (!arg || !ts.isObjectLiteralExpression(arg)) return undefined;
119
- const cronProp = arg.properties.find((prop) => {
120
- if (!ts.isPropertyAssignment(prop)) return false;
121
- if (ts.isIdentifier(prop.name))
122
- return cronPropertyNames.has(prop.name.text);
123
- if (ts.isStringLiteralLike(prop.name))
124
- return cronPropertyNames.has(prop.name.text);
125
- return false;
126
- });
127
-
128
- if (!cronProp || !ts.isPropertyAssignment(cronProp)) return undefined;
129
- const value = cronProp.initializer;
130
- const triggers: string[] = [];
131
- if (ts.isArrayLiteralExpression(value)) {
132
- for (const element of value.elements) {
133
- if (ts.isStringLiteralLike(element)) {
134
- triggers.push(element.text.trim());
135
- }
136
- }
137
- } else if (ts.isStringLiteralLike(value)) {
138
- triggers.push(value.text.trim());
139
- }
140
-
141
- const unique = Array.from(new Set(triggers.filter(Boolean)));
142
- return unique.length > 0 ? unique : undefined;
143
- };
@@ -1,7 +0,0 @@
1
- export { discoverHandlers } from "./discover-handlers";
2
- export { generateDbHandlers } from "../generators/generate-db-handlers";
3
- export { generateApiClient } from "../generators/generate-api-client";
4
- export { generateHonoServer } from "../generators/generate-hono-server";
5
- export { generateWebsocketDurableObject } from "../generators/generate-websocket-durable-object";
6
- export { generateSchedulerHandlers } from "../generators/generate-scheduler-handlers";
7
- export { generateCronHandlers } from "../generators/generate-cron-handlers";
package/cli/core/index.ts DELETED
@@ -1,205 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { Command } from "commander";
4
- import { promises as fs } from "node:fs";
5
- import path from "node:path";
6
- import { pathToFileURL } from "node:url";
7
- import {
8
- discoverHandlers,
9
- generateApiClient,
10
- generateDbHandlers,
11
- generateHonoServer,
12
- generateWebsocketDurableObject,
13
- generateSchedulerHandlers,
14
- } from "./handlers";
15
- import { generateSchemaTypes, getSchemaTableNames } from "../schema/schema";
16
- import { runTscEmit, writeEmitTsconfig } from "../utils/tsc";
17
- import {
18
- assertDirExists,
19
- assertFileExists,
20
- toImportPathFromGeneratedSrc,
21
- } from "../utils/utils";
22
-
23
- type AppflareConfig = {
24
- dir: string;
25
- schema: string;
26
- outDir: string;
27
- auth?: {
28
- enabled?: boolean;
29
- basePath?: string;
30
- clientOptions?: Record<string, unknown>;
31
- };
32
- };
33
-
34
- const program = new Command();
35
-
36
- program.name("appflare").description("Appflare CLI").version("0.0.0");
37
-
38
- program
39
- .command("build")
40
- .description(
41
- "Generate typed schema + query/mutation client/server into outDir",
42
- )
43
- .option(
44
- "-c, --config <path>",
45
- "Path to appflare.config.ts",
46
- "appflare.config.ts",
47
- )
48
- .option("--emit", "Also run tsc to emit JS + .d.ts into outDir/dist")
49
- .action(async (options: { config: string; emit?: boolean }) => {
50
- try {
51
- const configPath = path.resolve(process.cwd(), options.config);
52
- const { config, configDirAbs } = await loadConfig(configPath);
53
- await buildFromConfig({
54
- config,
55
- configDirAbs,
56
- configPathAbs: configPath,
57
- emit: Boolean(options.emit),
58
- });
59
- } catch (err) {
60
- const message = err instanceof Error ? err.message : String(err);
61
- console.error(message);
62
- process.exitCode = 1;
63
- }
64
- });
65
-
66
- void main();
67
-
68
- async function main(): Promise<void> {
69
- await program.parseAsync(process.argv);
70
- }
71
-
72
- async function loadConfig(
73
- configPathAbs: string,
74
- ): Promise<{ config: AppflareConfig; configDirAbs: string }> {
75
- await assertFileExists(configPathAbs, `Config not found: ${configPathAbs}`);
76
- const configDirAbs = path.dirname(configPathAbs);
77
-
78
- const mod = await import(pathToFileURL(configPathAbs).href);
79
- const config = (mod?.default ?? mod) as Partial<AppflareConfig>;
80
- if (!config || typeof config !== "object") {
81
- throw new Error(
82
- `Invalid config export in ${configPathAbs} (expected default export object)`,
83
- );
84
- }
85
- if (typeof config.dir !== "string" || !config.dir) {
86
- throw new Error(`Invalid config.dir in ${configPathAbs}`);
87
- }
88
- if (typeof config.schema !== "string" || !config.schema) {
89
- throw new Error(`Invalid config.schema in ${configPathAbs}`);
90
- }
91
- if (typeof config.outDir !== "string" || !config.outDir) {
92
- throw new Error(`Invalid config.outDir in ${configPathAbs}`);
93
- }
94
- return { config: config as AppflareConfig, configDirAbs };
95
- }
96
-
97
- async function buildFromConfig(params: {
98
- config: AppflareConfig;
99
- configDirAbs: string;
100
- configPathAbs: string;
101
- emit: boolean;
102
- }): Promise<void> {
103
- const { config, configDirAbs, emit, configPathAbs } = params;
104
-
105
- const projectDirAbs = path.resolve(configDirAbs, config.dir);
106
- const schemaPathAbs = path.resolve(configDirAbs, config.schema);
107
- const outDirAbs = path.resolve(configDirAbs, config.outDir);
108
-
109
- await assertDirExists(
110
- projectDirAbs,
111
- `Project dir not found: ${projectDirAbs}`,
112
- );
113
- await assertFileExists(schemaPathAbs, `Schema not found: ${schemaPathAbs}`);
114
-
115
- await fs.mkdir(path.join(outDirAbs, "src"), { recursive: true });
116
- await fs.mkdir(path.join(outDirAbs, "server"), { recursive: true });
117
-
118
- const schemaImportPathForGeneratedSrc = toImportPathFromGeneratedSrc(
119
- outDirAbs,
120
- schemaPathAbs,
121
- );
122
- const schemaReexport = `import schema from ${JSON.stringify(schemaImportPathForGeneratedSrc)};
123
- export type AppflareGeneratedSchema = typeof schema;
124
- export default schema;
125
- `;
126
- await fs.writeFile(path.join(outDirAbs, "src", "schema.ts"), schemaReexport);
127
-
128
- const schemaTypesTs = await generateSchemaTypes({
129
- schemaPathAbs,
130
- configPathAbs,
131
- outDirAbs,
132
- });
133
- await fs.writeFile(
134
- path.join(outDirAbs, "src", "schema-types.ts"),
135
- schemaTypesTs,
136
- );
137
-
138
- // (Re)generate built-in DB handlers based on the schema tables.
139
- const schemaTableNames = await getSchemaTableNames(schemaPathAbs);
140
- await generateDbHandlers({ outDirAbs, tableNames: schemaTableNames });
141
-
142
- const handlers = await discoverHandlers({
143
- projectDirAbs,
144
- schemaPathAbs,
145
- outDirAbs,
146
- configPathAbs,
147
- });
148
-
149
- const apiTs = generateApiClient({
150
- handlers,
151
- outDirAbs,
152
- authBasePath:
153
- config.auth && config.auth.enabled === false
154
- ? undefined
155
- : (config.auth?.basePath ?? "/auth"),
156
- authEnabled: config.auth?.enabled !== false,
157
- configPathAbs,
158
- });
159
- await fs.writeFile(path.join(outDirAbs, "src", "api.ts"), apiTs);
160
-
161
- const serverTs = generateHonoServer({
162
- handlers,
163
- outDirAbs,
164
- schemaPathAbs,
165
- configPathAbs,
166
- config,
167
- });
168
- await fs.writeFile(path.join(outDirAbs, "server", "server.ts"), serverTs);
169
-
170
- const websocketDoTs = generateWebsocketDurableObject({
171
- handlers,
172
- outDirAbs,
173
- schemaPathAbs,
174
- configPathAbs,
175
- config,
176
- });
177
- await fs.writeFile(
178
- path.join(outDirAbs, "server", "websocket-hibernation-server.ts"),
179
- websocketDoTs,
180
- );
181
-
182
- const schedulerTs = generateSchedulerHandlers({
183
- handlers,
184
- outDirAbs,
185
- schemaPathAbs,
186
- configPathAbs,
187
- });
188
- await fs.writeFile(
189
- path.join(outDirAbs, "server", "scheduler.ts"),
190
- schedulerTs,
191
- );
192
-
193
- if (emit) {
194
- // Remove previous emit output to avoid stale files lingering.
195
- await fs.rm(path.join(outDirAbs, "dist"), { recursive: true, force: true });
196
-
197
- // Emit only the files that don't pull in user code outside rootDir.
198
- // This avoids TS rootDir issues and dist overwrite issues caused by user modules.
199
- const emitTsconfigAbs = await writeEmitTsconfig({
200
- configDirAbs,
201
- outDirAbs,
202
- });
203
- await runTscEmit(emitTsconfigAbs);
204
- }
205
- }