alepha 0.13.8 → 0.14.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 (112) hide show
  1. package/dist/api/audits/index.d.ts +2 -1
  2. package/dist/api/audits/index.d.ts.map +1 -0
  3. package/dist/api/files/index.d.ts +2 -1
  4. package/dist/api/files/index.d.ts.map +1 -0
  5. package/dist/api/jobs/index.d.ts +158 -157
  6. package/dist/api/jobs/index.d.ts.map +1 -0
  7. package/dist/api/notifications/index.d.ts.map +1 -0
  8. package/dist/api/parameters/index.d.ts +4 -4
  9. package/dist/api/parameters/index.d.ts.map +1 -0
  10. package/dist/api/users/index.d.ts +132 -131
  11. package/dist/api/users/index.d.ts.map +1 -0
  12. package/dist/api/verifications/index.d.ts.map +1 -0
  13. package/dist/batch/index.d.ts.map +1 -0
  14. package/dist/bucket/index.d.ts.map +1 -0
  15. package/dist/cache/core/index.d.ts.map +1 -0
  16. package/dist/cache/redis/index.d.ts.map +1 -0
  17. package/dist/cli/index.d.ts +44 -32
  18. package/dist/cli/index.d.ts.map +1 -0
  19. package/dist/cli/index.js +380 -109
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/command/index.d.ts +11 -1
  22. package/dist/command/index.d.ts.map +1 -0
  23. package/dist/command/index.js +45 -6
  24. package/dist/command/index.js.map +1 -1
  25. package/dist/core/index.browser.js +1334 -1318
  26. package/dist/core/index.browser.js.map +1 -1
  27. package/dist/core/index.d.ts +75 -71
  28. package/dist/core/index.d.ts.map +1 -0
  29. package/dist/core/index.js +1337 -1321
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/index.native.js +1337 -1321
  32. package/dist/core/index.native.js.map +1 -1
  33. package/dist/datetime/index.d.ts.map +1 -0
  34. package/dist/email/index.d.ts.map +1 -0
  35. package/dist/fake/index.d.ts.map +1 -0
  36. package/dist/file/index.d.ts.map +1 -0
  37. package/dist/lock/core/index.d.ts.map +1 -0
  38. package/dist/lock/redis/index.d.ts.map +1 -0
  39. package/dist/logger/index.d.ts +1 -0
  40. package/dist/logger/index.d.ts.map +1 -0
  41. package/dist/mcp/index.d.ts +820 -0
  42. package/dist/mcp/index.d.ts.map +1 -0
  43. package/dist/mcp/index.js +978 -0
  44. package/dist/mcp/index.js.map +1 -0
  45. package/dist/orm/index.d.ts +180 -107
  46. package/dist/orm/index.d.ts.map +1 -0
  47. package/dist/orm/index.js +260 -174
  48. package/dist/orm/index.js.map +1 -1
  49. package/dist/queue/core/index.d.ts +4 -4
  50. package/dist/queue/core/index.d.ts.map +1 -0
  51. package/dist/queue/redis/index.d.ts.map +1 -0
  52. package/dist/redis/index.d.ts.map +1 -0
  53. package/dist/retry/index.d.ts.map +1 -0
  54. package/dist/router/index.d.ts.map +1 -0
  55. package/dist/scheduler/index.d.ts.map +1 -0
  56. package/dist/security/index.d.ts.map +1 -0
  57. package/dist/server/auth/index.d.ts +155 -155
  58. package/dist/server/auth/index.d.ts.map +1 -0
  59. package/dist/server/cache/index.d.ts.map +1 -0
  60. package/dist/server/compress/index.d.ts.map +1 -0
  61. package/dist/server/cookies/index.d.ts.map +1 -0
  62. package/dist/server/core/index.d.ts.map +1 -0
  63. package/dist/server/cors/index.d.ts.map +1 -0
  64. package/dist/server/health/index.d.ts.map +1 -0
  65. package/dist/server/helmet/index.d.ts.map +1 -0
  66. package/dist/server/links/index.d.ts +33 -33
  67. package/dist/server/links/index.d.ts.map +1 -0
  68. package/dist/server/metrics/index.d.ts.map +1 -0
  69. package/dist/server/multipart/index.d.ts.map +1 -0
  70. package/dist/server/proxy/index.d.ts.map +1 -0
  71. package/dist/server/rate-limit/index.d.ts.map +1 -0
  72. package/dist/server/security/index.d.ts +9 -9
  73. package/dist/server/security/index.d.ts.map +1 -0
  74. package/dist/server/static/index.d.ts.map +1 -0
  75. package/dist/server/swagger/index.d.ts.map +1 -0
  76. package/dist/sms/index.d.ts.map +1 -0
  77. package/dist/thread/index.d.ts.map +1 -0
  78. package/dist/topic/core/index.d.ts.map +1 -0
  79. package/dist/topic/redis/index.d.ts.map +1 -0
  80. package/dist/vite/index.d.ts +10 -2
  81. package/dist/vite/index.d.ts.map +1 -0
  82. package/dist/vite/index.js +36 -14
  83. package/dist/vite/index.js.map +1 -1
  84. package/dist/websocket/index.d.ts.map +1 -0
  85. package/package.json +9 -4
  86. package/src/cli/apps/AlephaCli.ts +2 -0
  87. package/src/cli/apps/AlephaPackageBuilderCli.ts +12 -8
  88. package/src/cli/assets/mainTs.ts +9 -10
  89. package/src/cli/commands/ChangelogCommands.ts +389 -0
  90. package/src/cli/commands/DrizzleCommands.ts +204 -4
  91. package/src/cli/commands/ViteCommands.ts +26 -16
  92. package/src/cli/services/AlephaCliUtils.ts +23 -150
  93. package/src/command/providers/CliProvider.ts +76 -5
  94. package/src/core/providers/SchemaValidator.ts +23 -1
  95. package/src/mcp/errors/McpError.ts +72 -0
  96. package/src/mcp/helpers/jsonrpc.ts +163 -0
  97. package/src/mcp/index.ts +132 -0
  98. package/src/mcp/interfaces/McpTypes.ts +248 -0
  99. package/src/mcp/primitives/$prompt.ts +188 -0
  100. package/src/mcp/primitives/$resource.ts +171 -0
  101. package/src/mcp/primitives/$tool.ts +285 -0
  102. package/src/mcp/providers/McpServerProvider.ts +382 -0
  103. package/src/mcp/transports/SseMcpTransport.ts +172 -0
  104. package/src/mcp/transports/StdioMcpTransport.ts +126 -0
  105. package/src/orm/index.ts +12 -0
  106. package/src/orm/providers/drivers/CloudflareD1Provider.ts +164 -0
  107. package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -1
  108. package/src/vite/plugins/viteAlephaBuild.ts +8 -2
  109. package/src/vite/plugins/viteAlephaDev.ts +6 -2
  110. package/src/vite/tasks/buildServer.ts +1 -1
  111. package/src/vite/tasks/generateCloudflare.ts +43 -15
  112. package/src/vite/tasks/runAlepha.ts +1 -0
@@ -0,0 +1,389 @@
1
+ import { exec } from "node:child_process";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { t } from "alepha";
6
+ import { $command } from "alepha/command";
7
+
8
+ const execAsync = promisify(exec);
9
+
10
+ interface Commit {
11
+ hash: string;
12
+ type: string;
13
+ scope: string | null;
14
+ description: string;
15
+ breaking: boolean;
16
+ }
17
+
18
+ interface ChangelogEntry {
19
+ version: string;
20
+ date: string;
21
+ features: Commit[];
22
+ fixes: Commit[];
23
+ docs: Commit[];
24
+ improvements: Commit[];
25
+ breaking: Commit[];
26
+ }
27
+
28
+ interface ChangelogConfig {
29
+ /**
30
+ * Commit prefixes to ignore (e.g., "project", "release", "chore")
31
+ */
32
+ ignore?: string[];
33
+ /**
34
+ * Module scopes to recognize (e.g., "ui", "cli", "core")
35
+ * If not provided, all non-ignored scopes are included
36
+ */
37
+ scopes?: string[];
38
+ }
39
+
40
+ const DEFAULT_IGNORE = [
41
+ "project",
42
+ "release",
43
+ "starter",
44
+ "example",
45
+ "chore",
46
+ "ci",
47
+ "build",
48
+ "test",
49
+ "style",
50
+ ];
51
+
52
+ function parseCommit(line: string, config: ChangelogConfig): Commit | null {
53
+ const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
54
+ if (!match) return null;
55
+
56
+ const [, hash, message] = match;
57
+ const breaking =
58
+ message.includes("!:") || message.toLowerCase().includes("breaking");
59
+ const ignore = config.ignore ?? DEFAULT_IGNORE;
60
+
61
+ // Conventional commit: feat(scope): description or feat!: description
62
+ const conventionalMatch = message.match(
63
+ /^(feat|fix|docs|refactor|perf|revert)(?:\(([^)]+)\))?!?:\s*(.+)$/i,
64
+ );
65
+ if (conventionalMatch) {
66
+ const [, type, scope, description] = conventionalMatch;
67
+
68
+ // Skip if scope matches ignore list
69
+ if (scope) {
70
+ const baseScope = scope.split("/")[0];
71
+ if (ignore.includes(baseScope) || ignore.includes(scope)) {
72
+ return null;
73
+ }
74
+ }
75
+
76
+ // Skip if type (without scope) matches ignore list (e.g., "docs" in ignore)
77
+ if (!scope && ignore.includes(type.toLowerCase())) {
78
+ return null;
79
+ }
80
+
81
+ return {
82
+ hash: hash.substring(0, 8),
83
+ type: type.toLowerCase(),
84
+ scope: scope || null,
85
+ description: description.trim(),
86
+ breaking,
87
+ };
88
+ }
89
+
90
+ // Module-specific commit: module: description or module/submodule: description
91
+ const moduleMatch = message.match(
92
+ /^([a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?):\s*(.+)$/i,
93
+ );
94
+ if (moduleMatch) {
95
+ const [, module, description] = moduleMatch;
96
+ const baseModule = module.split("/")[0];
97
+
98
+ // Skip ignored prefixes
99
+ if (ignore.includes(baseModule)) {
100
+ return null;
101
+ }
102
+
103
+ // If scopes are defined, check if this is a known scope
104
+ if (config.scopes && !config.scopes.includes(baseModule)) {
105
+ return null;
106
+ }
107
+
108
+ // Determine type based on description keywords
109
+ const desc = description.toLowerCase();
110
+ let type = "improve";
111
+ if (
112
+ desc.includes("fix") ||
113
+ desc.includes("bug") ||
114
+ desc.includes("issue")
115
+ ) {
116
+ type = "fix";
117
+ } else if (
118
+ desc.includes("add") ||
119
+ desc.includes("new") ||
120
+ desc.includes("implement")
121
+ ) {
122
+ type = "feat";
123
+ }
124
+
125
+ return {
126
+ hash: hash.substring(0, 8),
127
+ type,
128
+ scope: module,
129
+ description: description.trim(),
130
+ breaking,
131
+ };
132
+ }
133
+
134
+ return null;
135
+ }
136
+
137
+ function formatCommit(commit: Commit): string {
138
+ const scope = commit.scope ? `**${commit.scope}**: ` : "";
139
+ return `- ${scope}${commit.description} (\`${commit.hash}\`)`;
140
+ }
141
+
142
+ function generateChangelog(entries: ChangelogEntry[]): string {
143
+ let output = "# Changelog\n\n";
144
+ output +=
145
+ "All notable changes to this project will be documented in this file.\n\n";
146
+
147
+ for (const entry of entries) {
148
+ output += `## [${entry.version}] - ${entry.date}\n\n`;
149
+ output += formatEntry(entry);
150
+ }
151
+
152
+ return output;
153
+ }
154
+
155
+ function formatEntry(entry: ChangelogEntry): string {
156
+ let output = "";
157
+
158
+ if (entry.breaking.length > 0) {
159
+ output += "### Breaking Changes\n\n";
160
+ for (const commit of entry.breaking) {
161
+ output += `${formatCommit(commit)}\n`;
162
+ }
163
+ output += "\n";
164
+ }
165
+
166
+ if (entry.features.length > 0) {
167
+ output += "### Features\n\n";
168
+ for (const commit of entry.features) {
169
+ output += `${formatCommit(commit)}\n`;
170
+ }
171
+ output += "\n";
172
+ }
173
+
174
+ if (entry.fixes.length > 0) {
175
+ output += "### Bug Fixes\n\n";
176
+ for (const commit of entry.fixes) {
177
+ output += `${formatCommit(commit)}\n`;
178
+ }
179
+ output += "\n";
180
+ }
181
+
182
+ return output;
183
+ }
184
+
185
+ async function loadConfig(root: string): Promise<ChangelogConfig> {
186
+ try {
187
+ const pkgPath = join(root, "package.json");
188
+ const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
189
+ return pkg.changelog ?? {};
190
+ } catch {
191
+ return {};
192
+ }
193
+ }
194
+
195
+ export class ChangelogCommands {
196
+ public readonly changelog = $command({
197
+ name: "changelog",
198
+ description: "Generate CHANGELOG.md from git commits",
199
+ flags: t.object({
200
+ release: t.optional(
201
+ t.boolean({
202
+ when: ["--release", "-r"],
203
+ description:
204
+ "Output release notes for the latest version only (for GitHub Release)",
205
+ }),
206
+ ),
207
+ preview: t.optional(
208
+ t.boolean({
209
+ when: ["--preview", "-p"],
210
+ description: "Preview unreleased changes (commits since last tag)",
211
+ }),
212
+ ),
213
+ output: t.optional(
214
+ t.string({
215
+ when: ["--output", "-o"],
216
+ description:
217
+ "Output file path (defaults to CHANGELOG.md, use - for stdout)",
218
+ }),
219
+ ),
220
+ limit: t.optional(
221
+ t.number({
222
+ when: ["--limit", "-l"],
223
+ description: "Limit number of versions to include",
224
+ }),
225
+ ),
226
+ }),
227
+ handler: async ({ flags, run, root }) => {
228
+ const config = await loadConfig(root);
229
+
230
+ const git = async (cmd: string) => {
231
+ const { stdout } = await execAsync(`git ${cmd}`, { cwd: root });
232
+ return stdout;
233
+ };
234
+
235
+ // Get all tags sorted by version
236
+ const tagsOutput = await git("tag --sort=-version:refname");
237
+ const tags = tagsOutput
238
+ .trim()
239
+ .split("\n")
240
+ .filter((tag) => tag.match(/^\d+\.\d+\.\d+$/));
241
+
242
+ if (tags.length === 0) {
243
+ throw new Error("No version tags found");
244
+ }
245
+
246
+ // Preview mode: show unreleased changes
247
+ if (flags.preview) {
248
+ const latestTag = tags[0];
249
+ const commitsOutput = await git(`log ${latestTag}..HEAD --oneline`);
250
+
251
+ if (!commitsOutput.trim()) {
252
+ console.log("No unreleased changes since", latestTag);
253
+ return;
254
+ }
255
+
256
+ const entry: ChangelogEntry = {
257
+ version: "Unreleased",
258
+ date: new Date().toISOString().split("T")[0],
259
+ features: [],
260
+ fixes: [],
261
+ docs: [],
262
+ improvements: [],
263
+ breaking: [],
264
+ };
265
+
266
+ for (const line of commitsOutput.trim().split("\n")) {
267
+ if (!line.trim()) continue;
268
+ const commit = parseCommit(line, config);
269
+ if (!commit) continue;
270
+
271
+ if (commit.breaking) entry.breaking.push(commit);
272
+
273
+ switch (commit.type) {
274
+ case "feat":
275
+ entry.features.push(commit);
276
+ break;
277
+ case "fix":
278
+ entry.fixes.push(commit);
279
+ break;
280
+ case "docs":
281
+ entry.docs.push(commit);
282
+ break;
283
+ case "refactor":
284
+ case "perf":
285
+ case "improve":
286
+ entry.improvements.push(commit);
287
+ break;
288
+ }
289
+ }
290
+
291
+ const hasCommits =
292
+ entry.features.length > 0 ||
293
+ entry.fixes.length > 0 ||
294
+ entry.breaking.length > 0;
295
+
296
+ if (!hasCommits) {
297
+ console.log("No public changes since", latestTag);
298
+ return;
299
+ }
300
+
301
+ console.log(`## [Unreleased] - since ${latestTag}\n`);
302
+ console.log(formatEntry(entry));
303
+ return;
304
+ }
305
+
306
+ const entries: ChangelogEntry[] = [];
307
+ const limit = flags.limit || (flags.release ? 1 : tags.length);
308
+
309
+ for (let i = 0; i < Math.min(limit, tags.length); i++) {
310
+ const tag = tags[i];
311
+ const prevTag = tags[i + 1];
312
+
313
+ // Get tag date
314
+ const dateOutput = await git(`log -1 --format=%ci ${tag}`);
315
+ const date = dateOutput.trim().split(" ")[0];
316
+
317
+ // Get commits between tags
318
+ const range = prevTag ? `${prevTag}..${tag}` : tag;
319
+ const commitsOutput = await git(`log ${range} --oneline`);
320
+
321
+ const entry: ChangelogEntry = {
322
+ version: tag,
323
+ date,
324
+ features: [],
325
+ fixes: [],
326
+ docs: [],
327
+ improvements: [],
328
+ breaking: [],
329
+ };
330
+
331
+ for (const line of commitsOutput.trim().split("\n")) {
332
+ if (!line.trim()) continue;
333
+ const commit = parseCommit(line, config);
334
+ if (!commit) continue;
335
+
336
+ if (commit.breaking) entry.breaking.push(commit);
337
+
338
+ switch (commit.type) {
339
+ case "feat":
340
+ entry.features.push(commit);
341
+ break;
342
+ case "fix":
343
+ entry.fixes.push(commit);
344
+ break;
345
+ case "docs":
346
+ entry.docs.push(commit);
347
+ break;
348
+ case "refactor":
349
+ case "perf":
350
+ case "improve":
351
+ entry.improvements.push(commit);
352
+ break;
353
+ }
354
+ }
355
+
356
+ // Only add entry if it has any commits
357
+ const hasCommits =
358
+ entry.features.length > 0 ||
359
+ entry.fixes.length > 0 ||
360
+ entry.breaking.length > 0;
361
+
362
+ if (hasCommits) {
363
+ entries.push(entry);
364
+ }
365
+ }
366
+
367
+ if (entries.length === 0) {
368
+ console.log("No public commits found");
369
+ return;
370
+ }
371
+
372
+ let output: string;
373
+ if (flags.release) {
374
+ output = formatEntry(entries[0]);
375
+ } else {
376
+ output = generateChangelog(entries);
377
+ }
378
+
379
+ const outputPath = flags.output ?? "CHANGELOG.md";
380
+ if (outputPath === "-") {
381
+ console.log(output);
382
+ } else {
383
+ await run(`Writing ${outputPath}`, () =>
384
+ writeFile(join(root, outputPath), output, "utf8"),
385
+ );
386
+ }
387
+ },
388
+ });
389
+ }
@@ -13,6 +13,12 @@ const drizzleCommandFlags = t.object({
13
13
  "Database provider name to target (e.g., 'postgres', 'sqlite')",
14
14
  }),
15
15
  ),
16
+ mode: t.optional(
17
+ t.text({
18
+ description:
19
+ "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode",
20
+ }),
21
+ ),
16
22
  });
17
23
 
18
24
  export class DrizzleCommands {
@@ -149,12 +155,14 @@ export class DrizzleCommands {
149
155
  const commandFlags = flags.custom
150
156
  ? `--custom=${flags.custom}`
151
157
  : undefined;
152
- await this.utils.runDrizzleKitCommand({
158
+
159
+ await this.runDrizzleKitCommand({
153
160
  root,
154
161
  args,
155
162
  command: "generate",
156
163
  commandFlags,
157
164
  provider: flags.provider,
165
+ env: flags.mode,
158
166
  logMessage: (providerName, dialect) =>
159
167
  `Generate '${providerName}' migrations (${dialect}) ...`,
160
168
  });
@@ -181,11 +189,12 @@ export class DrizzleCommands {
181
189
  ),
182
190
  flags: drizzleCommandFlags,
183
191
  handler: async ({ root, args, flags }) => {
184
- await this.utils.runDrizzleKitCommand({
192
+ await this.runDrizzleKitCommand({
185
193
  root,
186
194
  args,
187
195
  command: "push",
188
196
  provider: flags.provider,
197
+ env: flags.mode,
189
198
  logMessage: (providerName, dialect) =>
190
199
  `Push '${providerName}' schema (${dialect}) ...`,
191
200
  });
@@ -212,11 +221,12 @@ export class DrizzleCommands {
212
221
  ),
213
222
  flags: drizzleCommandFlags,
214
223
  handler: async ({ root, args, flags }) => {
215
- await this.utils.runDrizzleKitCommand({
224
+ await this.runDrizzleKitCommand({
216
225
  root,
217
226
  args,
218
227
  command: "migrate",
219
228
  provider: flags.provider,
229
+ env: flags.mode,
220
230
  logMessage: (providerName, dialect) =>
221
231
  `Migrate '${providerName}' database (${dialect}) ...`,
222
232
  });
@@ -243,17 +253,207 @@ export class DrizzleCommands {
243
253
  ),
244
254
  flags: drizzleCommandFlags,
245
255
  handler: async ({ root, args, flags }) => {
246
- await this.utils.runDrizzleKitCommand({
256
+ await this.runDrizzleKitCommand({
247
257
  root,
248
258
  args,
249
259
  command: "studio",
250
260
  provider: flags.provider,
261
+ env: flags.mode,
251
262
  logMessage: (providerName, dialect) =>
252
263
  `Launch Studio for '${providerName}' (${dialect}) ...`,
253
264
  });
254
265
  },
255
266
  });
256
267
 
268
+ /**
269
+ * Run a drizzle-kit command for all database providers in an Alepha instance.
270
+ *
271
+ * Iterates through all repository providers, prepares Drizzle config for each,
272
+ * and executes the specified drizzle-kit command.
273
+ *
274
+ * @param options - Configuration including command to run, flags, and logging
275
+ */
276
+ public async runDrizzleKitCommand(options: {
277
+ root: string;
278
+ args?: string;
279
+ command: string;
280
+ commandFlags?: string;
281
+ provider?: string;
282
+ logMessage: (providerName: string, dialect: string) => string;
283
+ env?: string;
284
+ }): Promise<void> {
285
+ const rootDir = options.root;
286
+
287
+ const envFiles = [".env"];
288
+ if (options.env) {
289
+ envFiles.push(`.env.${options.env}`);
290
+ }
291
+
292
+ await this.utils.loadEnvFile(rootDir, envFiles);
293
+
294
+ this.log.debug(`Using project root: ${rootDir}`);
295
+
296
+ const { alepha, entry } = await this.utils.loadAlephaFromServerEntryFile(
297
+ rootDir,
298
+ options.args,
299
+ );
300
+
301
+ const drizzleKitProvider =
302
+ alepha.inject<DrizzleKitProvider>("DrizzleKitProvider");
303
+ const repositoryProvider =
304
+ alepha.inject<RepositoryProvider>("RepositoryProvider");
305
+ const accepted = new Set<string>([]);
306
+
307
+ for (const primitive of repositoryProvider.getRepositories()) {
308
+ const provider = primitive.provider;
309
+ const providerName = provider.name;
310
+ const dialect = provider.dialect;
311
+
312
+ if (accepted.has(providerName)) {
313
+ continue;
314
+ }
315
+ accepted.add(providerName);
316
+
317
+ // Skip if provider filter is set and doesn't match
318
+ if (options.provider && options.provider !== providerName) {
319
+ this.log.debug(
320
+ `Skipping provider '${providerName}' (filter: ${options.provider})`,
321
+ );
322
+ continue;
323
+ }
324
+
325
+ this.log.info("");
326
+ this.log.info(options.logMessage(providerName, dialect));
327
+
328
+ const drizzleConfigJsPath = await this.prepareDrizzleConfig({
329
+ kit: drizzleKitProvider,
330
+ provider,
331
+ providerName,
332
+ providerUrl: provider.url,
333
+ dialect,
334
+ entry,
335
+ rootDir,
336
+ });
337
+
338
+ const flags = options.commandFlags ? ` ${options.commandFlags}` : "";
339
+ await this.utils.exec(
340
+ `drizzle-kit ${options.command} --config=${drizzleConfigJsPath}${flags}`,
341
+ {
342
+ env: {
343
+ NODE_OPTIONS: "--import tsx",
344
+ },
345
+ },
346
+ );
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Prepare Drizzle configuration files for a database provider.
352
+ *
353
+ * Creates temporary entities.js and drizzle.config.js files needed
354
+ * for Drizzle Kit commands to run properly.
355
+ *
356
+ * @param options - Configuration options including kit, provider info, and paths
357
+ * @returns Path to the generated drizzle.config.js file
358
+ */
359
+ public async prepareDrizzleConfig(options: {
360
+ kit: any;
361
+ provider: any;
362
+ providerName: string;
363
+ providerUrl: string;
364
+ dialect: string;
365
+ entry: string;
366
+ rootDir: string;
367
+ }): Promise<string> {
368
+ const models = Object.keys(options.kit.getModels(options.provider));
369
+ const entitiesJs = this.utils.generateEntitiesJs(
370
+ options.entry,
371
+ options.providerName,
372
+ models,
373
+ );
374
+
375
+ const entitiesJsPath = await this.utils.writeConfigFile(
376
+ "entities.js",
377
+ entitiesJs,
378
+ options.rootDir,
379
+ );
380
+
381
+ const config: Record<string, any> = {
382
+ schema: entitiesJsPath,
383
+ out: `./migrations/${options.providerName}`,
384
+ dialect: options.dialect,
385
+ dbCredentials: {
386
+ url: options.providerUrl,
387
+ },
388
+ };
389
+
390
+ if (options.providerName === "d1") {
391
+ config.driver = "d1-http";
392
+ }
393
+
394
+ if (options.providerName === "pglite") {
395
+ config.driver = "pglite";
396
+ }
397
+
398
+ if (options.dialect === "sqlite") {
399
+ if (options.providerName === "d1") {
400
+ const token = process.env.CLOUDFLARE_API_TOKEN;
401
+ if (!token) {
402
+ throw new AlephaError(
403
+ "CLOUDFLARE_API_TOKEN environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit",
404
+ );
405
+ }
406
+
407
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
408
+ if (!accountId) {
409
+ throw new AlephaError(
410
+ "CLOUDFLARE_ACCOUNT_ID environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit",
411
+ );
412
+ }
413
+
414
+ const url = options.providerUrl;
415
+ if (!url.startsWith("cloudflare-d1://")) {
416
+ throw new AlephaError(
417
+ "D1 provider URL must start with 'cloudflare-d1://'.",
418
+ );
419
+ }
420
+
421
+ const [, databaseId] = url
422
+ .replace("cloudflare-d1://", "")
423
+ .replace("cloudflare-d1:", "")
424
+ .split(":");
425
+
426
+ if (!databaseId) {
427
+ throw new AlephaError(
428
+ "Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: cloudflare-d1://<database_name>:<database_id>",
429
+ );
430
+ }
431
+
432
+ config.dbCredentials = {
433
+ accountId,
434
+ databaseId,
435
+ token,
436
+ };
437
+ } else {
438
+ let url = options.providerUrl;
439
+ url = url.replace("sqlite://", "").replace("file://", "");
440
+ url = join(options.rootDir, url);
441
+
442
+ config.dbCredentials = {
443
+ url,
444
+ };
445
+ }
446
+ }
447
+
448
+ const drizzleConfigJs = `export default ${JSON.stringify(config, null, 2)}`;
449
+
450
+ return await this.utils.writeConfigFile(
451
+ "drizzle.config.js",
452
+ drizzleConfigJs,
453
+ options.rootDir,
454
+ );
455
+ }
456
+
257
457
  // /**
258
458
  // * Drop database schema (development only)
259
459
  // *