Prisma Integration + Scaffolding Fixes#22
Conversation
- Removed static compat.json validator - Added compat.test.ts powered by Bun’s built-in test runner - Tests import real data from src/data.ts for frameworks, DBs, ORMs, hosts, and auth providers - Added host↔engine and ORM↔engine subset checks - Skipped scaffold smoke tests pending e2e setup
…ed up eslint errors and added small fixes so all tests run smooth with bun test
- replace useless test with actual db host/engine checks - rename ok -> isAllowed to make eslint happy - add missing types and remove unused import
- Move host-engine validation to tests/utils/hostRules.ts - Update both test files to use shared logic - Remove duplicate export statement from compat.test.ts
…eScript's inference instead absolute/no-explicit-return-type
Updated logging functions to simplify output formatting.
tests: replace compat validator with bun:test suite using src/data.ts
Harness test
This file generates a Prisma client based on the specified database engine and host, and writes it to a specified directory.
Added graceful shutdown for Prisma (disconnect on SIGINT/SIGTERM) and aliased prisma client as 'db' so handlers work consistently across ORMs. Changes: - generateServer.ts: lifecycle cleanup block for prisma.() - generateDBBlock.ts: const db = prisma alias for handler compatibility
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThreads a new databaseDirectory option across scaffolding, adds Prisma schema/client generation and Prisma-aware handlers, integrates Docker orchestration for DBs, updates package/env scripts and dependency mappings, replaces shell Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as "Developer (CLI)"
participant CLI as "scaffold CLI"
participant Gen as "Generators (schema, client, handlers)"
participant Docker as "Docker / Compose"
participant FS as "Filesystem"
participant Git as "Git"
participant Prisma as "Prisma CLI"
rect rgba(200,230,255,0.5)
Dev->>CLI: run scaffold (includes databaseDirectory)
CLI->>Gen: generatePackageJson, generateEnv, generatePrismaSchema, generatePrismaClient
Gen->>FS: write schema.prisma, client.ts, package.json, env files
end
rect rgba(200,255,220,0.5)
CLI->>Docker: bring up per-databaseDirectory docker-compose (project name via toDockerProjectName)
Docker->>FS: write/read docker-compose.db.yml under databaseDirectory
end
rect rgba(255,230,200,0.5)
CLI->>Prisma: run prisma generate / migrate / db push via Bun.spawnSync
Prisma->>FS: write generated client artifacts
end
rect rgba(230,230,255,0.5)
CLI->>Git: checkGitInstalled -> initialize repo if available
Git->>FS: git init, add, commit
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@src/generators/configurations/generatePackageJson.ts`:
- Around line 208-228: The `@prisma/extension-accelerate` package is currently
being added from prismaDevDependencies but is required at runtime by the
generated Prisma client; move the entry for "@prisma/extension-accelerate" from
prismaDevDependencies into prismaRuntimeDependencies in the data source so that
when the code checks usesAccelerate and populates dependencies (the block using
prismaRuntimeDependencies, prismaDevDependencies, resolveVersion and the
usesAccelerate flag) the package is added to dependencies rather than
devDependencies; update the arrays accordingly and ensure the existing
conditional that skips adding the dev dependency for accelerate (the check for
dep.value === '@prisma/extension-accelerate' && !usesAccelerate) is removed or
adjusted since accelerate should now be handled as a runtime dependency.
In `@src/generators/db/generatePrismaSchema.ts`:
- Around line 61-64: The datasource builder buildDatasourceBlock currently
always emits provider and url but must conditionally add shadowDatabaseUrl for
MySQL/MariaDB; update buildDatasourceBlock(cfg: DialectConfig) to append
`shadowDatabaseUrl = env("SHADOW_DATABASE_URL")` when cfg.provider is "mysql" or
"mariadb", and update generatePrismaSchema to rely on that updated block; also
modify the .env generator to emit a SHADOW_DATABASE_URL entry for those engines
so prisma migrate dev can use the shadow DB when the main DB user lacks CREATE
DATABASE privileges.
In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 157-161: Replace the npx call with Bun-compatible invocation and
stop execution on failure: change the command in the try block that currently
runs await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd) to use
bunx (e.g., bunx prisma) so it resolves correctly in Bun projects, and when
catching errors in that block do not merely console.error — rethrow the error or
call process.exit(1) so execution does not continue to the subsequent migration
step (the code after the prisma generate try/catch). Ensure the change is
applied around the existing invocation and catch for prisma generate so the
migration step won't run when generation fails.
- Around line 190-205: The migration commands in the scaffold flow use "npx
prisma" but should use "bunx prisma" to match the runtime environment; update
the two invocations that build the shell commands (the branch where
databaseEngine === 'sqlite' and the else branch) to replace `npx prisma db push
--schema ${schemaArg}` and `npx prisma migrate dev --name init --skip-generate
--schema ${schemaArg}` with `bunx prisma ...`, preserving the use of schemaArg,
projectCwd, and the nothrow()/result.exitCode checks (look for the variables
`databaseEngine`, `schemaArg`, `projectCwd` in this file and the command
construction).
In `@src/generators/project/generateDBBlock.ts`:
- Around line 95-108: The generated code unconditionally injects a MySQL-only
"mode" into the drizzle constructor; update the return logic in
generateDBBlock.ts (the branch that builds the pool using expr and returns the
const pool / const db block) so that the mode option is only included when
databaseEngine indicates a MySQL-family engine (e.g., 'mysql' or 'mariadb') or
when databaseHost === 'planetscale' (mysqlMode variable), otherwise call
drizzle(pool, { schema }) with no mode; implement this by building the options
object conditionally (use mysqlMode only when appropriate) before returning the
template that creates db.
In `@src/generators/project/generateImportsBlock.ts`:
- Around line 215-221: The generated import statements in generateImportsBlock
(using rawImports) are producing invalid merged imports because lines push
`import type { Elysia }` and `import type { User }` which the merge logic treats
as default imports; update the pushes so Elysia is a value import (e.g., `import
{ Elysia }` not `import type`) since `new Elysia()` is used at runtime, and
ensure `@prisma/client` combines both PrismaClient and User as named imports
(push a single named-import string or push `import { PrismaClient, User }`
rather than a second `import type`), or alternatively adjust the import-merge
logic in the merge routine to treat `import type { ... }` as named imports
(preserving the type-only modifier) so named imports aren’t misclassified as
default imports.
🧹 Nitpick comments (9)
src/templates/svelte/composables/counter.svelte.ts (1)
1-1: Consider a narrower suppression instead of@ts-nocheck.
@ts-nocheckdisables TypeScript checking for the entire file. Since only$state()on line 3 is unrecognized by plaintsc, a targeted//@ts-expect-error`` comment above that line would preserve type-checking for the rest of the file (parameter types, return shape, etc.).That said, for a small scaffolded template where
svelte-checkhandles runes natively, this is a minor concern.♻️ Suggested narrower suppression
-// `@ts-nocheck` - Svelte 5 runes ($state) are processed at build time export const counter = (initialCount: number) => { + // `@ts-expect-error` - Svelte 5 rune processed at build time let count = $state(initialCount);src/versions.ts (1)
58-58: Prisma dependency versions should be centralized here too.The
drizzle-kitaddition follows the correct pattern of usingversions.tsas the single source of truth. However, the new Prisma dependencies insrc/data.ts(lines 172–188) hardcode their versions ('6.2.0','1.2.1') instead of referencing this registry. This is inconsistent with how every other dependency version is managed (e.g.,versions['drizzle-orm'],versions['elysia']).Consider adding
prisma,@prisma/client, and@prisma/extension-accelerateentries here and referencing them fromdata.ts.Proposed addition to versions.ts
/* ── ORM ──────────────────────────────────────────────── */ 'drizzle-kit': '0.31.8', 'drizzle-orm': '0.45.1', + '@prisma/client': '6.2.0', + '@prisma/extension-accelerate': '1.2.1', + prisma: '6.2.0',src/data.ts (1)
172-188: Hardcoded versions — useversions.tsfor consistency.As noted in the
versions.tsreview, these versions should reference the centralversionsmap rather than being hardcoded, matching the pattern used by all other dependencies in this file (e.g.,versions['elysia'],versions['drizzle-orm']).Proposed fix (after adding entries to versions.ts)
export const prismaRuntimeDependencies: AvailableDependency[] = [ { - latestVersion: '6.2.0', + latestVersion: versions['@prisma/client'], value: '@prisma/client' } ]; export const prismaDevDependencies: AvailableDependency[] = [ { - latestVersion: '6.2.0', + latestVersion: versions['prisma'], value: 'prisma' }, { - latestVersion: '1.2.1', + latestVersion: versions['@prisma/extension-accelerate'], value: '@prisma/extension-accelerate' } ];src/commands/initializeGit.ts (1)
27-32:abort()exits with code 0 despite an error condition.When Git is not installed,
abort()is called, which internally callsexit(0). This signals success to the shell/CI, even though the operation failed due to a missing prerequisite. If this tool is used in automated pipelines, a zero exit code would mask the failure.That said, this is the existing convention in
abort.tsand not introduced by this PR, so this is a minor observation for potential future improvement.src/generators/db/handlerTemplates.ts (1)
280-299: Inconsistent indentation in generated Prisma template code.The
returnstatements are indented with extra leading spaces relative to the preceding Prisma calls, which will produce oddly-formatted generated code. For example,insertHistoryhas thereturnat a different indent level than theawait db.countHistory.create(...)call.✏️ Suggested formatting fix
const prismaQueryOperations: QueryOperations = { - insertHistory: `const newHistory = await db.countHistory.create({ - data: { count } -}) - return newHistory`, - insertUser: `const newUser = await db.user.upsert({ - where: { auth_sub: authSub }, - update: { metadata: userIdentity }, - create: { auth_sub: authSub, metadata: userIdentity } -}) - return newUser`, - selectHistory: `const history = await db.countHistory.findUnique({ - where: { uid } -}) - return history`, - selectUser: `const user = await db.user.findUnique({ - where: { auth_sub: authSub } -}) - return user` + insertHistory: `const newHistory = await db.countHistory.create({ + data: { count } + }) + return newHistory`, + insertUser: `const newUser = await db.user.upsert({ + where: { auth_sub: authSub }, + update: { metadata: userIdentity }, + create: { auth_sub: authSub, metadata: userIdentity } + }) + return newUser`, + selectHistory: `const history = await db.countHistory.findUnique({ + where: { uid } + }) + return history`, + selectUser: `const user = await db.user.findUnique({ + where: { auth_sub: authSub } + }) + return user` };src/scaffold.ts (1)
113-128: Thevoid (... && await ...)pattern works but is non-obvious.This correctly awaits
scaffoldDatabasewhen conditions are met, but thevoid+ short-circuit&&chaining for conditional async execution is unusual. A plainifblock would be more readable.♻️ Suggested simplification
- void ( - databaseDirectory !== undefined && - databaseEngine !== 'none' && - databaseEngine !== undefined && - (await scaffoldDatabase({ - authOption, - backendDirectory, - databaseDirectory, - databaseEngine, - databaseHost, - databasePort, - orm, - projectName, - typesDirectory - })) - ); + if ( + databaseDirectory !== undefined && + databaseEngine !== 'none' && + databaseEngine !== undefined + ) { + await scaffoldDatabase({ + authOption, + backendDirectory, + databaseDirectory, + databaseEngine, + databaseHost, + databasePort, + orm, + projectName, + typesDirectory + }); + }src/generators/project/generateImportsBlock.ts (1)
223-232: Loose equality==instead of===.Line 224 uses
orm == 'drizzle'while every other comparison in this file uses strict equality (===). Not a bug here, but inconsistent.✏️ Fix
- if ( - orm == 'drizzle' && + if ( + orm === 'drizzle' &&src/generators/configurations/generateEnv.ts (1)
38-42: Hardcodeddb/path in SQLite URL may drift fromdatabaseDirectory.The SQLite
DATABASE_URLhardcodesfile:./db/database.sqlite, but other generators (e.g.,generateDrizzleConfig.ts) derive this path from thedatabaseDirectoryparameter. IfdatabaseDirectoryever differs from'db', the.envvalue will be inconsistent with the schema/config paths. Consider threadingdatabaseDirectoryintoGenerateEnvPropsand using it here.Proposed fix
type GenerateEnvProps = Pick< CreateConfiguration, 'databaseEngine' | 'databaseHost' | 'projectName' > & { + databaseDirectory?: string; databasePort?: number; envVariables?: string[]; };if ( databaseEngine === 'sqlite' && (databaseHost === 'none' || databaseHost === undefined) ) { - vars.push('DATABASE_URL=file:./db/database.sqlite'); + const dir = databaseDirectory ?? 'db'; + vars.push(`DATABASE_URL=file:./${dir}/database.sqlite`); }src/generators/db/scaffoldDatabase.ts (1)
18-31:databaseDirectoryis declared both in thePickand in the intersection.
databaseDirectoryappears in both thePick<CreateConfiguration, ...>(line 23) and the explicit& { ... }block (line 28). The explicitdatabaseDirectory: stringin the intersection shadows the picked type. If the intent is to make it required (stringinstead ofstring | undefined), this works but is confusing — consider removing it from thePickto make the intent clear.
| const usesAccelerate = | ||
| orm === 'prisma' && | ||
| (databaseHost === 'neon' || databaseHost === 'planetscale'); | ||
|
|
||
| switch (databaseHost) { | ||
| case 'neon': | ||
| dependencies['@neondatabase/serverless'] = resolveVersion( | ||
| '@neondatabase/serverless', | ||
| versions['@neondatabase/serverless'] | ||
| ); | ||
| break; | ||
| case 'planetscale': | ||
| dependencies['@planetscale/database'] = resolveVersion( | ||
| '@planetscale/database', | ||
| versions['@planetscale/database'] | ||
| if (orm === 'prisma') { | ||
| prismaRuntimeDependencies.forEach((dep) => { | ||
| dependencies[dep.value] = resolveVersion( | ||
| dep.value, | ||
| dep.latestVersion | ||
| ); | ||
| break; | ||
| case 'turso': | ||
| dependencies['@libsql/client'] = resolveVersion( | ||
| '@libsql/client', | ||
| versions['@libsql/client'] | ||
| }); | ||
|
|
||
| prismaDevDependencies.forEach((dep) => { | ||
| if (dep.value === '@prisma/extension-accelerate' && !usesAccelerate) | ||
| return; | ||
| devDependencies[dep.value] = resolveVersion( | ||
| dep.value, | ||
| dep.latestVersion | ||
| ); | ||
| break; | ||
| }); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
@prisma/extension-accelerate runtime dependency vs dev dependency documentation
💡 Result:
@prisma/extension-accelerate should be a runtime dependency (put it in dependencies), because it’s imported and used by your application code at runtime (e.g., import { withAccelerate } from "@prisma/extension-accelerate";). Prisma’s guides install it without --save-dev, while installing the Prisma CLI (prisma) with --save-dev. (prismagraphql.com)
Citations:
🏁 Script executed:
# Find and inspect src/data.ts to check where `@prisma/extension-accelerate` is defined
find . -name "data.ts" -type f | head -20Repository: absolutejs/create-absolutejs
Length of output: 85
🏁 Script executed:
# Search for `@prisma/extension-accelerate` in the codebase
rg "@prisma/extension-accelerate" -nRepository: absolutejs/create-absolutejs
Length of output: 383
🏁 Script executed:
# Check src/data.ts around line 186 to see which dependency array it's in
sed -n '170,200p' src/data.tsRepository: absolutejs/create-absolutejs
Length of output: 645
🏁 Script executed:
# Check the import in generatePrismaClient.ts to see how it's used
sed -n '15,25p' src/generators/configurations/generatePrismaClient.tsRepository: absolutejs/create-absolutejs
Length of output: 425
@prisma/extension-accelerate must be a runtime dependency, not a dev dependency.
According to Prisma's official documentation, @prisma/extension-accelerate is imported and used at runtime in the generated Prisma client code (see src/generators/configurations/generatePrismaClient.ts line 18). Placing it in devDependencies (currently in src/data.ts line 186) means it will not be installed in production environments when using npm install --production or equivalent flags, causing runtime failures when Accelerate is enabled.
Move @prisma/extension-accelerate from prismaDevDependencies to prismaRuntimeDependencies in src/data.ts.
🤖 Prompt for AI Agents
In `@src/generators/configurations/generatePackageJson.ts` around lines 208 - 228,
The `@prisma/extension-accelerate` package is currently being added from
prismaDevDependencies but is required at runtime by the generated Prisma client;
move the entry for "@prisma/extension-accelerate" from prismaDevDependencies
into prismaRuntimeDependencies in the data source so that when the code checks
usesAccelerate and populates dependencies (the block using
prismaRuntimeDependencies, prismaDevDependencies, resolveVersion and the
usesAccelerate flag) the package is added to dependencies rather than
devDependencies; update the arrays accordingly and ensure the existing
conditional that skips adding the dev dependency for accelerate (the check for
dep.value === '@prisma/extension-accelerate' && !usesAccelerate) is removed or
adjusted since accelerate should now be handled as a runtime dependency.
| try { | ||
| await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd); | ||
| } catch (error) { | ||
| console.error('Error generating Prisma client:', error); | ||
| } |
There was a problem hiding this comment.
npx in a Bun-based project; swallowed error allows broken continuation.
Two concerns:
-
The project uses Bun (imported from
'bun'on line 3,bun db:upon line 169). Usingnpx prismahere may fail or use a different package resolution path. Considerbunx prismafor consistency. -
If
prisma generatefails, thecatchonly logs and continues to the migration step (lines 163+), which will also fail. Consider bailing out early on failure.
Proposed fix
try {
- await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
+ await $`bunx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
} catch (error) {
console.error('Error generating Prisma client:', error);
+ return;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd); | |
| } catch (error) { | |
| console.error('Error generating Prisma client:', error); | |
| } | |
| try { | |
| await $`bunx prisma generate --schema ${schemaArg}`.cwd(projectCwd); | |
| } catch (error) { | |
| console.error('Error generating Prisma client:', error); | |
| return; | |
| } |
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 157 - 161, Replace the
npx call with Bun-compatible invocation and stop execution on failure: change
the command in the try block that currently runs await $`npx prisma generate
--schema ${schemaArg}`.cwd(projectCwd) to use bunx (e.g., bunx prisma) so it
resolves correctly in Bun projects, and when catching errors in that block do
not merely console.error — rethrow the error or call process.exit(1) so
execution does not continue to the subsequent migration step (the code after the
prisma generate try/catch). Ensure the change is applied around the existing
invocation and catch for prisma generate so the migration step won't run when
generation fails.
| if (databaseEngine === 'sqlite') { | ||
| const result = await $`npx prisma db push --schema ${schemaArg}` | ||
| .cwd(projectCwd) | ||
| .nothrow(); | ||
| if (result.exitCode !== 0) | ||
| console.error('Error running Prisma migrations:', result.stderr); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| const result = | ||
| await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}` | ||
| .cwd(projectCwd) | ||
| .nothrow(); | ||
| if (result.exitCode !== 0) | ||
| console.error('Error running Prisma migrations:', result.stderr); |
There was a problem hiding this comment.
SQLite and non-SQLite migration commands also use npx — same concern applies.
Consistent with the earlier comment on line 158, lines 191 and 201 also use npx prisma instead of bunx prisma.
Proposed fix
- const result = await $`npx prisma db push --schema ${schemaArg}`
+ const result = await $`bunx prisma db push --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();- const result = await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
+ const result = await $`bunx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (databaseEngine === 'sqlite') { | |
| const result = await $`npx prisma db push --schema ${schemaArg}` | |
| .cwd(projectCwd) | |
| .nothrow(); | |
| if (result.exitCode !== 0) | |
| console.error('Error running Prisma migrations:', result.stderr); | |
| return; | |
| } | |
| const result = | |
| await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}` | |
| .cwd(projectCwd) | |
| .nothrow(); | |
| if (result.exitCode !== 0) | |
| console.error('Error running Prisma migrations:', result.stderr); | |
| if (databaseEngine === 'sqlite') { | |
| const result = await $`bunx prisma db push --schema ${schemaArg}` | |
| .cwd(projectCwd) | |
| .nothrow(); | |
| if (result.exitCode !== 0) | |
| console.error('Error running Prisma migrations:', result.stderr); | |
| return; | |
| } | |
| const result = | |
| await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}` | |
| .cwd(projectCwd) | |
| .nothrow(); | |
| if (result.exitCode !== 0) | |
| console.error('Error running Prisma migrations:', result.stderr); |
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 190 - 205, The migration
commands in the scaffold flow use "npx prisma" but should use "bunx prisma" to
match the runtime environment; update the two invocations that build the shell
commands (the branch where databaseEngine === 'sqlite' and the else branch) to
replace `npx prisma db push --schema ${schemaArg}` and `npx prisma migrate dev
--name init --skip-generate --schema ${schemaArg}` with `bunx prisma ...`,
preserving the use of schemaArg, projectCwd, and the nothrow()/result.exitCode
checks (look for the variables `databaseEngine`, `schemaArg`, `projectCwd` in
this file and the command construction).
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/generators/db/scaffoldDocker.ts (1)
56-57:⚠️ Potential issue | 🔴 CriticalAlign
composeFilepath construction in scaffoldDocker.ts with generatePackageJson.ts.Line 76 constructs
composeFilewithout a fallback for falsydatabaseDirectory, while generatePackageJson.ts (line 274) usesdatabaseDirectory ?? 'db'to ensure consistency. IfdatabaseDirectoryis empty or undefined, the docker compose commands on lines 77-78 will reference a different file than thebun db:upandbun db:downscripts (which default todb/via generatePackageJson.ts), causing container lookup failures during teardown.Change line 76 to:
const composeFile = `${databaseDirectory ?? 'db'}/docker-compose.db.yml`;
🤖 Fix all issues with AI agents
In `@src/utils/toDockerProjectName.ts`:
- Around line 1-5: toDockerProjectName currently allows uppercase letters which
violate Docker Compose project name rules; update the function to call
.toLowerCase() on the input (e.g., use name.toLowerCase() before applying the
.replace chains in toDockerProjectName) so the subsequent regex replacements
produce a lowercase, valid project name while preserving the existing
collapsing/trimming behavior and the 'db' fallback.
🧹 Nitpick comments (9)
src/commands/formatProject.ts (2)
1-1: Inconsistent module specifier forprocess.This file imports from
'node:process'whilesrc/commands/installDependencies.ts(line 1) imports from'process'. Both resolve to the same module, but the inconsistency is a minor style nit. Consider aligning on one form across the codebase (preferably'node:process'as it's the explicit Node-prefixed convention).
19-38: Duplicated command-parsing and spawn logic — consider extracting a shared helper.The pattern of splitting a command string, validating the binary, calling
Bun.spawnSync, and checkingproc.success/ readingproc.stderris identical between this file andinstallDependencies.ts. Extracting a small utility (e.g.,runCommand(cmd: string, cwd: string)) would reduce duplication and centralize error handling.♻️ Example helper sketch
// src/utils/runCommand.ts export function runCommandSync(cmd: string, cwd: string): void { const parts = cmd.split(/\s+/); const bin = parts[0]; if (!bin) throw new Error(`Empty command: "${cmd}"`); const args = parts.slice(1); const proc = Bun.spawnSync([bin, ...args], { cwd, stderr: 'pipe', stdout: 'ignore', }); if (!proc.success) { const errMsg = proc.stderr?.toString().trim() || `Exit code ${proc.exitCode}`; throw new Error(errMsg); } }src/commands/installDependencies.ts (1)
20-29:stdout: 'ignore'may suppress package-manager warnings.Some package managers (notably
npm) emit deprecation and peer-dependency warnings to stdout. Withstdout: 'ignore', users won't see these during install. This is likely an acceptable tradeoff for a clean spinner UX, but worth noting in case debugging install issues becomes painful later. Considerstdout: 'pipe'and logging on failure if that becomes an issue.src/generators/db/handlerTemplates.ts (2)
280-299: Inconsistent indentation in generated template strings.The
returnstatements are indented with extra leading spaces relative to the Prisma API calls, which will produce oddly-indented generated code. For example,return newHistoryon line 284 is indented underdata: { count }rather than aligned with theconstdeclaration on line 281.♻️ Suggested indentation fix
const prismaQueryOperations: QueryOperations = { insertHistory: `const newHistory = await db.countHistory.create({ data: { count } }) - return newHistory`, +return newHistory`, insertUser: `const newUser = await db.user.upsert({ where: { auth_sub: authSub }, update: { metadata: userIdentity }, create: { auth_sub: authSub, metadata: userIdentity } }) - return newUser`, +return newUser`, selectHistory: `const history = await db.countHistory.findUnique({ where: { uid } }) - return history`, +return history`, selectUser: `const user = await db.user.findUnique({ where: { auth_sub: authSub } }) - return user` +return user` };Note: verify the expected indentation level in the generated output by checking how other
QueryOperations(e.g.,drizzleQueryOperations) format theirreturnstatements within the template.
391-395: All Prisma driver configs are identical — consider deduplication.Every
*:prisma:*entry indriverConfigurationsuses the exact same{ dbType, importLines, queries }object. This is a lot of copy-paste that could drift if the Prisma config ever changes.♻️ Extract a shared prisma config object
+const prismaDriverConfig = { + dbType: 'PrismaClient', + importLines: `import type { PrismaClient } from '@prisma/client'`, + queries: prismaQueryOperations +} as const; + const driverConfigurations = { - 'cockroachdb:prisma:local': { - dbType: 'PrismaClient', - importLines: `import type { PrismaClient } from '@prisma/client'`, - queries: prismaQueryOperations - }, + 'cockroachdb:prisma:local': prismaDriverConfig, // ... same for all other prisma entriesAlso applies to: 419-423, 429-433, 439-443, 461-470, 499-513, 535-539, 558-567
src/generators/db/scaffoldDatabase.ts (1)
19-32:databaseDirectoryis declared twice in the type — once viaPickand once in the intersection.
CreateConfiguration['databaseDirectory']isstring | undefined, but the& { databaseDirectory: string }intersection narrows it tostring. This works in TypeScript but is confusing and error-prone. Consider removing it from thePickto make the intent clear.Proposed fix
type ScaffoldDatabaseProps = Pick< CreateConfiguration, | 'projectName' | 'databaseHost' | 'orm' - | 'databaseDirectory' | 'authOption' | 'databaseEngine' > & { backendDirectory: string; databaseDirectory: string; databasePort?: number; typesDirectory: string; };src/generators/project/generateImportsBlock.ts (1)
270-320: Import merge refactor correctly handlesimport typevs value imports — nice improvement.The new
ImportEntrystructure withtypeOnlyNamesandvalueNamessets correctly addresses the original import-merge bug described in the PR objectives. When a module has both type-only and value imports, the emission logic (Lines 324-346) correctly producesimport { type Foo, bar } from '...'syntax, which is valid TypeScript.Two minor static analysis findings on Lines 296 and 316: the
forEachcallbacks implicitly return the result ofSet.add(). This is functionally harmless (the return value is ignored byforEach) but triggers the Biome lint ruleuseIterableCallbackReturn. A trivial fix:Proposed fix for linter warnings
- .forEach((name) => entry.typeOnlyNames.add(name)); + .forEach((name) => { entry.typeOnlyNames.add(name); });- .forEach((name) => entry.valueNames.add(name)); + .forEach((name) => { entry.valueNames.add(name); });src/generators/project/generateDBBlock.ts (1)
76-83: Path replacement assumes all expressions containdb/— fragile for non-sqlite engines.Line 80 does
hostCfg.expr.replace('db/',${databaseDirectory}/). Looking atconnectionMap, onlysqlite.nonecontainsdb/in its expression (new Database("db/database.sqlite")). For all other engines (e.g.,new SQL(getEnv("DATABASE_URL"))), the replace is a no-op. This works today, but the approach is fragile — if a future engine expression coincidentally containsdb/, it would be incorrectly replaced.src/generators/configurations/generatePackageJson.ts (1)
339-352: InconsistentdatabaseDirectoryfallback pattern across the file.Line 274 uses
databaseDirectory ?? 'db'(nullish coalescing — only catchesnull/undefined), while Line 340 usesdatabaseDirectory ? ... : 'db/...'(truthy check — also catches empty string). Similarly, Line 328 usesdatabaseDirectory ?? 'db'. Pick one pattern for consistency.Proposed fix — use nullish coalescing consistently
if (orm === 'prisma') { - const schemaPath = databaseDirectory - ? `${databaseDirectory}/schema.prisma` - : 'db/schema.prisma'; + const schemaPath = `${databaseDirectory ?? 'db'}/schema.prisma`; scripts['postinstall'] = `prisma generate --schema ${schemaPath}`;
| export const toDockerProjectName = (name: string): string => | ||
| name | ||
| .replace(/[^a-zA-Z0-9_-]/g, '-') | ||
| .replace(/-+/g, '-') | ||
| .replace(/^-|-$/g, '') || 'db'; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Docker Compose project name case sensitivity specification requirements
💡 Result:
Docker Compose project names are effectively lowercase-only, so case sensitivity is enforced by validation: any uppercase letters make the project name invalid.
Specification / requirements
- The Compose Specification defines the project name constraint as: only lowercase letters (
a-z), decimal digits (0-9), dashes (-), and underscores (_); and it must start with a lowercase letter or digit. This meansMyProjis invalid,myprojis valid. [1] - Docker’s Compose docs repeat the same rule and note that if the directory name (default source of the project name) violates the constraint, you must override the project name using another mechanism. [2]
How you set/override the project name (and where it matters)
- Precedence (highest → lowest):
-p/--project-name,COMPOSE_PROJECT_NAME, top-levelname:in the Compose file, then directory-based defaults. [2], [3] - The top-level
name:key is part of the Compose Specification (supported bydocker compose/ Compose v2), not the legacydocker-composev1 file formats—using it with v1 commonly triggers schema/validation errors. [2], [1]
Sources
- [1] Compose Specification (Project name section)
- [2] Docker Docs: “Specify a project name”
- [3] Docker Docs: Environment variables (
COMPOSE_PROJECT_NAME)
Add .toLowerCase() to ensure valid Docker Compose project names.
Docker Compose project names must match the pattern [a-z0-9][a-z0-9_-]* per the Compose Specification—uppercase letters are not permitted. The current implementation allows uppercase characters, producing invalid project names. Adding .toLowerCase() ensures the output complies with the specification.
♻️ Proposed fix
export const toDockerProjectName = (name: string): string =>
name
+ .toLowerCase()
.replace(/[^a-zA-Z0-9_-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '') || 'db';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export const toDockerProjectName = (name: string): string => | |
| name | |
| .replace(/[^a-zA-Z0-9_-]/g, '-') | |
| .replace(/-+/g, '-') | |
| .replace(/^-|-$/g, '') || 'db'; | |
| export const toDockerProjectName = (name: string): string => | |
| name | |
| .toLowerCase() | |
| .replace(/[^a-zA-Z0-9_-]/g, '-') | |
| .replace(/-+/g, '-') | |
| .replace(/^-|-$/g, '') || 'db'; |
🤖 Prompt for AI Agents
In `@src/utils/toDockerProjectName.ts` around lines 1 - 5, toDockerProjectName
currently allows uppercase letters which violate Docker Compose project name
rules; update the function to call .toLowerCase() on the input (e.g., use
name.toLowerCase() before applying the .replace chains in toDockerProjectName)
so the subsequent regex replacements produce a lowercase, valid project name
while preserving the existing collapsing/trimming behavior and the 'db'
fallback.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/generators/configurations/generateEnv.ts (1)
41-55:⚠️ Potential issue | 🔴 CriticalSHADOW_DATABASE_URL is not automatically generated; users must provide it via CLI flag if needed.
The function does not emit
SHADOW_DATABASE_URLfor MySQL/MariaDB. If this is required by the PR objective, it's currently missing. However, users can provide it manually via the--env SHADOW_DATABASE_URL=...CLI flag, which will be merged into.envthrough theenvVariablesparameter. If automatic generation for MySQL/MariaDB is intended, the code needs to be updated ingenerateEnv.tsto construct and add the shadow database URL alongside the primaryDATABASE_URL.
🧹 Nitpick comments (1)
src/generators/configurations/generatePackageJson.ts (1)
339-352: Inconsistent fallback pattern fordatabaseDirectory.Lines 274 and 328 use
databaseDirectory ?? 'db', but line 340 uses a ternarydatabaseDirectory ? ... : 'db/schema.prisma'. This means an empty string''would produce different results:??would keep'', while the ternary would fall back to'db/schema.prisma'. Consider using a consistent pattern, e.g.:♻️ Suggested normalization
- const schemaPath = databaseDirectory - ? `${databaseDirectory}/schema.prisma` - : 'db/schema.prisma'; + const schemaPath = `${databaseDirectory ?? 'db'}/schema.prisma`;
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/generators/db/scaffoldDatabase.ts (1)
61-75:⚠️ Potential issue | 🔴 CriticalSQLite block runs unconditionally — will break for Prisma + SQLite.
When
orm === 'prisma'anddatabaseEngine === 'sqlite':
- Line 62-65 skips the
checkSqliteInstalled()call (becauseormis notundefined/'none').- Lines 66-74 still execute, calling
sqlite3which may not be installed — this will throw.- Even if
sqlite3is installed, this pre-creates the DB with a hand-written SQL schema, then Prisma later runsprisma db push(line 178) with its own schema, causing a conflict or redundancy.Guard lines 66-74 so they only run when the ORM is not Prisma (or has no ORM):
Proposed fix
if (databaseEngine === 'sqlite') { void ( (orm === undefined || orm === 'none') && (await checkSqliteInstalled()) ); - const sqliteSchema = generateSqliteSchema(authOption); - writeFileSync( - join(projectDatabaseDirectory, 'schema.sql'), - sqliteSchema - ); - const schemaPath = `${databaseDirectory}/schema.sql`; - await $`sqlite3 ${databaseDirectory}/database.sqlite ".read ${schemaPath}"`.cwd( - projectName - ); + if (orm === undefined || orm === 'none') { + const sqliteSchema = generateSqliteSchema(authOption); + writeFileSync( + join(projectDatabaseDirectory, 'schema.sql'), + sqliteSchema + ); + const schemaPath = `${databaseDirectory}/schema.sql`; + await $`sqlite3 ${databaseDirectory}/database.sqlite ".read ${schemaPath}"`.cwd( + projectName + ); + } }
🤖 Fix all issues with AI agents
In `@src/generators/configurations/generatePackageJson.ts`:
- Around line 296-301: The generated package.json script scripts['db:init']
references init.sql which doesn't exist; update the scripts['db:init']
assignment in generatePackageJson (the block using isLocal, databaseEngine,
databaseDirectory and dbDir) to reference schema.sql instead of init.sql so it
matches the file written by your DB scaffold (schema.sql).
In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 155-174: Import resolveDockerExe from the module that exports
checkDockerInstalled (same place checkDockerInstalled is imported) and use it in
the database start sequence in scaffoldDatabase (e.g., call await
resolveDockerExe() to get dockerExe and replace the hardcoded "docker compose"
invocation with `${dockerExe} compose`) so the command uses the resolved Docker
executable; update the import list to include resolveDockerExe and change the
exec invocation that currently runs "docker compose -p ..." to use the resolved
dockerExe variable instead.
🧹 Nitpick comments (1)
src/generators/configurations/generatePackageJson.ts (1)
244-245: InconsistentdatabaseDirectoryfallback patterns across the file.Three different approaches are used for the same fallback:
- Line 244:
databaseDirectory ?? 'db'(nullish coalescing)- Line 297:
databaseDirectory ?? 'db'(nullish coalescing)- Line 309:
databaseDirectory ? \...` : 'db/schema.prisma'` (ternary)Consider normalizing to a single default at the top of the function (e.g.,
const dbDir = databaseDirectory ?? 'db') and reusing it everywhere, which would also eliminate the ad-hocconst dbDirat line 297.Proposed refactor
}: CreatePackageJsonProps) => { + const dbDir = databaseDirectory ?? 'db'; const s = spinner(); // ... - const composeFile = `${databaseDirectory ?? 'db'}/docker-compose.db.yml`; + const composeFile = `${dbDir}/docker-compose.db.yml`; // ... - const dbDir = databaseDirectory ?? 'db'; scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`; // ... - const schemaPath = databaseDirectory - ? `${databaseDirectory}/schema.prisma` - : 'db/schema.prisma'; + const schemaPath = `${dbDir}/schema.prisma`;Also applies to: 297-297, 309-311
| if (isLocal && databaseEngine === 'sqlite') { | ||
| scripts['db:sqlite'] = 'sqlite3 db/database.sqlite'; | ||
| scripts['db:init'] = 'sqlite3 db/database.sqlite < db/init.sql'; | ||
| const dbDir = databaseDirectory ?? 'db'; | ||
| scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`; | ||
| scripts['db:init'] = | ||
| `sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for both init.sql and schema.sql references in TypeScript files
rg -n "init\.sql|schema\.sql" --type=ts -C2Repository: absolutejs/create-absolutejs
Length of output: 1132
🏁 Script executed:
#!/bin/bash
# Search for all references to init.sql in the entire codebase
rg "init\.sql" -nRepository: absolutejs/create-absolutejs
Length of output: 187
Change db:init script to reference schema.sql instead of init.sql.
The generated db:init script references init.sql, but src/generators/db/scaffoldDatabase.ts line 68 writes the schema file as schema.sql. This causes the db:init script to fail at runtime because the referenced file doesn't exist.
Proposed fix
scripts['db:init'] =
- `sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`;
+ `sqlite3 ${dbDir}/database.sqlite < ${dbDir}/schema.sql`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (isLocal && databaseEngine === 'sqlite') { | |
| scripts['db:sqlite'] = 'sqlite3 db/database.sqlite'; | |
| scripts['db:init'] = 'sqlite3 db/database.sqlite < db/init.sql'; | |
| const dbDir = databaseDirectory ?? 'db'; | |
| scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`; | |
| scripts['db:init'] = | |
| `sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`; | |
| } | |
| if (isLocal && databaseEngine === 'sqlite') { | |
| const dbDir = databaseDirectory ?? 'db'; | |
| scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`; | |
| scripts['db:init'] = | |
| `sqlite3 ${dbDir}/database.sqlite < ${dbDir}/schema.sql`; | |
| } |
🤖 Prompt for AI Agents
In `@src/generators/configurations/generatePackageJson.ts` around lines 296 - 301,
The generated package.json script scripts['db:init'] references init.sql which
doesn't exist; update the scripts['db:init'] assignment in generatePackageJson
(the block using isLocal, databaseEngine, databaseDirectory and dbDir) to
reference schema.sql instead of init.sql so it matches the file written by your
DB scaffold (schema.sql).
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 192-206: Replace the ephemeral "node:20-slim npx prisma" approach
in scaffoldDatabase.ts: stop running npx inside throwaway containers (the block
using resolveDockerExe(), toDockerProjectName(), mongoUrl and the
result/.nothrow() flow) and instead either (A) run prisma from the host (reuse
the host-installed Prisma invoked earlier) against the docker network DB
address, or (B) build/use a cached Prisma-ready image (pin the Prisma CLI
version) and run that image so dependencies aren't downloaded on each scaffold;
also remove .nothrow() and explicitly check result.exitCode to log and surface
errors (currently only result.stderr is printed) and preserve returning
dockerFreshInstall. Ensure references to resolveDockerExe, projectPath, network,
mongoUrl, result, and dockerFreshInstall are updated accordingly.
- Around line 171-175: The Promise executor parameter name `resolve` shadows the
imported `resolve` from the `path` module; update the anonymous functions that
create the delays (the two new Promise((resolve) => setTimeout(resolve, ...))
calls in scaffoldDatabase.ts inside the scaffoldDatabase flow and the
databaseEngine === 'mongodb' branch) to use a different parameter name (e.g.,
`done`, `res`, or `resolveTimer`) so they no longer shadow `path.resolve`; keep
behavior unchanged and only rename the parameter in those Promise executors.
- Around line 156-179: The Docker startup block in scaffoldDatabase.ts currently
catches errors from commands like bun db:up and the waitCommand but only logs
them and allows execution to continue; modify the catch in the async block that
wraps the docker startup (the try/catch around bun db:reset, bun db:up, and
initTemplates waitCommand) to re-throw the caught error or return a rejected
promise so execution stops (e.g., throw error) instead of proceeding to the
migration steps; reference databaseEngine, projectCwd, toDockerProjectName,
projectName, databaseDirectory, initTemplates and waitCommand to locate the
block to change.
🧹 Nitpick comments (4)
src/generators/db/generateDockerContainer.ts (1)
139-141: Consider quoting environment values in the generated YAML.The env values are emitted bare (e.g.,
ACCEPT_EULA: Y). In YAML 1.1 — which some Docker Compose parser versions use — bareYis interpreted as booleantrue, and other values could be similarly misinterpreted. Wrapping values in quotes would make the output safe regardless of the YAML parser version.This is a pre-existing pattern so not blocking, but since this file is being touched, it's a good opportunity to harden it.
♻️ Suggested fix
const envLines = Object.entries(env) - .map(([key, value]) => ` ${key}: ${value}`) + .map(([key, value]) => ` ${key}: "${value}"`) .join('\n');src/generators/db/scaffoldDatabase.ts (3)
20-32:databaseDirectoryis declared twice in the type.It appears in the
Pick<…>on line 25 and in the& { … }block on line 29. If the intent is to make an optional field required, only the intersection override is needed (remove it fromPick). Otherwise the duplication is confusing.Proposed fix
type ScaffoldDatabaseProps = Pick< CreateConfiguration, | 'projectName' | 'databaseHost' | 'orm' - | 'databaseDirectory' | 'authOption' | 'databaseEngine' > & { databaseDirectory: string; backendDirectory: string; typesDirectory: string; };
6-8: Consolidate imports from the same module.
checkDockerInstalledandresolveDockerExeare imported from the same module in two separate statements.Proposed fix
-import { checkDockerInstalled } from '../../utils/checkDockerInstalled'; -import { resolveDockerExe } from '../../utils/checkDockerInstalled'; +import { checkDockerInstalled, resolveDockerExe } from '../../utils/checkDockerInstalled';
209-216: Hardcoded Docker-network DB URLs duplicate the credential constants ingenerateEnv.ts.
dockerNetworkUrlsredefines the same credentials (passwords, ports, DB names) that exist ingenerateEnv.ts'sdatabaseURLS. If credentials change in one place, they'll silently diverge. Consider extracting shared credential constants or deriving these URLs from a single source.
| if (databaseEngine !== 'sqlite') { | ||
| try { | ||
| await $`bun db:reset`.cwd(projectCwd).nothrow(); | ||
| await $`bun db:up`.cwd(projectCwd); | ||
| const { initTemplates } = await import('./dockerInitTemplates'); | ||
| if (databaseEngine in initTemplates) { | ||
| const waitCommand = | ||
| initTemplates[databaseEngine as keyof typeof initTemplates] | ||
| ?.wait; | ||
| if (waitCommand) { | ||
| await $`docker compose -p ${toDockerProjectName(projectName)} -f ${databaseDirectory}/docker-compose.db.yml exec -T db bash -lc '${waitCommand}'` | ||
| .cwd(projectCwd) | ||
| .nothrow(); | ||
| } | ||
| } else { | ||
| await new Promise((resolve) => setTimeout(resolve, 5000)); | ||
| } | ||
| // Brief delay for MongoDB to fully stabilize before Prisma connections | ||
| if (databaseEngine === 'mongodb') { | ||
| await new Promise((resolve) => setTimeout(resolve, 3000)); | ||
| } | ||
| } catch (error) { | ||
| console.error('Error starting database container:', error); | ||
| } |
There was a problem hiding this comment.
Error in Docker startup block is swallowed — scaffold silently continues with broken DB.
If bun db:up fails (line 159) or the wait command fails, the outer catch on line 177 logs the error but execution continues to the migration steps (lines 182+), which will also fail. Consider returning early or re-throwing so the user gets a clear signal that the database didn't start.
Proposed fix
} catch (error) {
console.error('Error starting database container:', error);
+ return { dockerFreshInstall };
}🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 156 - 179, The Docker
startup block in scaffoldDatabase.ts currently catches errors from commands like
bun db:up and the waitCommand but only logs them and allows execution to
continue; modify the catch in the async block that wraps the docker startup (the
try/catch around bun db:reset, bun db:up, and initTemplates waitCommand) to
re-throw the caught error or return a rejected promise so execution stops (e.g.,
throw error) instead of proceeding to the migration steps; reference
databaseEngine, projectCwd, toDockerProjectName, projectName, databaseDirectory,
initTemplates and waitCommand to locate the block to change.
| await new Promise((resolve) => setTimeout(resolve, 5000)); | ||
| } | ||
| // Brief delay for MongoDB to fully stabilize before Prisma connections | ||
| if (databaseEngine === 'mongodb') { | ||
| await new Promise((resolve) => setTimeout(resolve, 3000)); |
There was a problem hiding this comment.
resolve parameter shadows the path.resolve import.
The resolve callback parameter in the new Promise((resolve) => …) on lines 171 and 175 shadows the resolve import from 'path' on line 2. This is a latent bug risk — if someone adds path logic inside these callbacks, they'll accidentally call the Promise resolver instead.
Proposed fix
- await new Promise((resolve) => setTimeout(resolve, 5000));
+ await new Promise((r) => setTimeout(r, 5000));
}
// Brief delay for MongoDB to fully stabilize before Prisma connections
if (databaseEngine === 'mongodb') {
- await new Promise((resolve) => setTimeout(resolve, 3000));
+ await new Promise((r) => setTimeout(r, 3000));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await new Promise((resolve) => setTimeout(resolve, 5000)); | |
| } | |
| // Brief delay for MongoDB to fully stabilize before Prisma connections | |
| if (databaseEngine === 'mongodb') { | |
| await new Promise((resolve) => setTimeout(resolve, 3000)); | |
| await new Promise((r) => setTimeout(r, 5000)); | |
| } | |
| // Brief delay for MongoDB to fully stabilize before Prisma connections | |
| if (databaseEngine === 'mongodb') { | |
| await new Promise((r) => setTimeout(r, 3000)); |
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 171 - 175, The Promise
executor parameter name `resolve` shadows the imported `resolve` from the `path`
module; update the anonymous functions that create the delays (the two new
Promise((resolve) => setTimeout(resolve, ...)) calls in scaffoldDatabase.ts
inside the scaffoldDatabase flow and the databaseEngine === 'mongodb' branch) to
use a different parameter name (e.g., `done`, `res`, or `resolveTimer`) so they
no longer shadow `path.resolve`; keep behavior unchanged and only rename the
parameter in those Promise executors.
| if (databaseEngine === 'mongodb') { | ||
| const docker = resolveDockerExe(); | ||
| const projectPath = resolve(projectCwd); | ||
| const network = `${toDockerProjectName(projectName)}_default`; | ||
| const mongoUrl = | ||
| 'mongodb://root:rootpassword@db:27017/database?authSource=admin'; | ||
|
|
||
| const result = await $`${docker} run --rm --network ${network} -v ${projectPath}:/app -w /app -e "DATABASE_URL=${mongoUrl}" node:20-slim npx prisma db push --schema ${schemaArg}` | ||
| .nothrow(); | ||
|
|
||
| if (result.exitCode !== 0) | ||
| console.error('Error running Prisma migrations:', result.stderr); | ||
|
|
||
| return { dockerFreshInstall }; | ||
| } |
There was a problem hiding this comment.
Prisma migrations run via npx inside ephemeral node:20-slim containers — slow and fragile.
Lines 199 and 224 spin up a fresh node:20-slim container and run npx prisma …, which means Prisma is downloaded from npm on every scaffold invocation. This is:
- Slow — downloading Prisma + its binary engine each time adds significant latency.
- Fragile — network issues during scaffold will cause silent migration failures (
.nothrow()suppresses the exit code messaging tostderronly). - Inconsistent — the host already has Prisma installed (line 147 uses it), so running a different version inside the container could produce schema drift.
Consider building or caching a Prisma-ready image, or running migrations from the host with the Docker network's DB address exposed via port mapping (which is already configured in docker-compose).
Also, npx inside the containers should ideally be bunx or at minimum the Prisma version should be pinned to avoid version skew between host and container.
Also applies to: 219-235
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 192 - 206, Replace the
ephemeral "node:20-slim npx prisma" approach in scaffoldDatabase.ts: stop
running npx inside throwaway containers (the block using resolveDockerExe(),
toDockerProjectName(), mongoUrl and the result/.nothrow() flow) and instead
either (A) run prisma from the host (reuse the host-installed Prisma invoked
earlier) against the docker network DB address, or (B) build/use a cached
Prisma-ready image (pin the Prisma CLI version) and run that image so
dependencies aren't downloaded on each scaffold; also remove .nothrow() and
explicitly check result.exitCode to log and surface errors (currently only
result.stderr is printed) and preserve returning dockerFreshInstall. Ensure
references to resolveDockerExe, projectPath, network, mongoUrl, result, and
dockerFreshInstall are updated accordingly.
Prisma & Database Scaffold Fixes
Shadow database (MySQL/MariaDB)
Prisma Migrate requires a temporary shadow database; the restricted
useraccount couldn't create it. Added:shadowDatabaseUrl = env("SHADOW_DATABASE_URL")in the Prisma schema for MySQL/MariaDB with local DockerSHADOW_DATABASE_URLin.envpointing to root (mysql://root:rootpassword@localhost:${port}/)Migrations succeed while the app still uses the limited
useraccount.MariaDB connection string
Prisma's
provider = "mysql"expectsmysql://URLs. Switched MariaDB URLs frommariadb://tomysql://ingenerateEnv.ts.MongoDB support
migrate devfor MongoDB. Usedb pushinstead (same as SQLite).admin. AddedauthSource=adminto the MongoDB URL so SCRAM auth works.Stale database volumes
PostgreSQL (and others) failed when reusing volumes with leftover data. Run
bun db:resetbeforebun db:upduring scaffold to clear volumes and avoid initdb "directory exists but is not empty" errors.Project-specific Docker names
Switched Docker Compose project name from
-p ${databaseEngine}to-p ${toDockerProjectName(projectName)}. Each project gets its own containers and volumes, avoiding drift and conflicting migration history.Import merge for Prisma + Elysia
Fixed the import merge logic so
import type { Elysia }andimport { Elysia, t }fromelysiaare merged correctly. Previously this produced invalid syntax in generatedserver.tswith Prisma + auth/count, which broke Prettier and format.Summary by CodeRabbit