Skip to content

fix: codegen + cms relations#117

Merged
olliethedev merged 7 commits intomainfrom
fix/cogegen-cli-prisma
Apr 16, 2026
Merged

fix: codegen + cms relations#117
olliethedev merged 7 commits intomainfrom
fix/cogegen-cli-prisma

Conversation

@olliethedev
Copy link
Copy Markdown
Collaborator

@olliethedev olliethedev commented Apr 15, 2026

Summary

  • fix codegen cli issues for prisma adapter
  • add relation support to cms plugin api mutator functions

Type of change

  • Bug fix
  • New plugin
  • Feature / enhancement to an existing plugin
  • Documentation
  • Chore / refactor / tooling

Checklist

  • pnpm build passes
  • pnpm typecheck passes
  • pnpm lint passes
  • Tests added or updated (unit and/or E2E)
  • Docs updated (docs/content/docs/) if consumer-facing types or behavior changed
  • All three codegen-projects create successfully and pass E2E tests
  • New plugin: submission checklist in CONTRIBUTING.md completed

Screenshots


Note

Medium Risk
CLI scaffolding changes affect Prisma project setup and codegen invocation (dependencies, generated client import path, and generate args), which could break new-project initialization if paths/configs are off. CMS adds an optional write-path to the contentRelation table; it’s gated by a flag but touches persistence logic.

Overview
CLI init/scaffolding now better supports Prisma by installing required extra packages (e.g. @prisma/adapter-pg, pg), generating prisma/schema.prisma (with explicit client output) + prisma.config.ts, updating the Prisma adapter template to use the generated Prisma client + PrismaPg, and passing an explicit --output path when delegating to generate.

CMS server-side createContentItem gains an optional { syncRelations: true } to also populate the contentRelation junction table from relation fields in the payload (reusing new shared helpers in api/relations.ts), and docs are updated to clarify authorization/validation bypass and relation limitations/behavior.

Reviewed by Cursor Bugbot for commit 7ce1721. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
better-stack-docs Ready Ready Preview, Comment Apr 16, 2026 8:14pm
better-stack-playground Ready Ready Preview, Comment Apr 16, 2026 8:14pm

Request Review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review — No High-Confidence Vulnerabilities Found

The diff introduces two focused changes: a hardcoded --output path for Prisma codegen and updated Prisma scaffold templates. After reviewing each change against the threat checklist, no exploitable security vulnerabilities were identified.

Analysis

Injection risks (CLI argument building)
getOutputForAdapter returns one of three hardcoded literal strings ("prisma/schema.prisma", "src/db/schema.ts", "migrations/schema.sql"). The adapter and orm values are resolved through a constant allowlist (ADAPTERS), so no user-controlled data flows into the constructed argument array. runCliPassthrough calls execa in array mode (not a shell string), which fully eliminates shell-injection risk regardless of argument content.

Path traversal
The new --output argument value is derived from a hardcoded lookup, not from user or filesystem input. No traversal vector exists.

Secrets / credential handling
The scaffolded stack.ts uses process.env.DATABASE_URL! and the prisma.config.ts uses process.env.DATABASE_URL ?? ''. Both are standard environment-variable references in generated template code. Neither logs nor leaks credentials.

Supply-chain
The only new dependency introduced in generated code is @prisma/adapter-pg, a first-party Prisma package. No novel or unknown third-party packages are added.

Functional notes (not security findings)

  • The generated prisma/schema.prisma omits a url field in datasource db; Prisma will refuse to run without it. This is a misconfiguration bug, not a vulnerability.
  • DATABASE_URL ?? '' in prisma.config.ts silently passes an empty string when the env var is unset, causing a confusing runtime failure rather than an early error. Consider failing loudly instead.
  • The non-null assertion process.env.DATABASE_URL! in stack.ts passes undefined at runtime if the variable is missing; a guard or explicit error would be safer ergonomically, though not exploitable.
Open in Web View Automation 

Sent by Cursor Automation: Find vulnerabilities

Comment thread packages/cli/src/utils/scaffold-plan.ts Outdated
…k file depth

Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
Comment thread packages/cli/src/utils/scaffold-plan.ts
Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Missing pg dependency in Prisma adapter extra packages
    • Added "pg" to the extraPackages array for the prisma adapter in constants.ts so it gets installed alongside @prisma/adapter-pg.
Preview (1a6c772ba3)
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -321,8 +321,13 @@
 						const orm = ADAPTERS.find(
 							(item) => item.key === adapter,
 						)?.ormForGenerate;
+						const outputPath = getOutputForAdapter(adapter);
 						const args = orm
-							? [`--orm=${orm}`, `--config=${stackPath}`]
+							? [
+									`--orm=${orm}`,
+									`--config=${stackPath}`,
+									...(outputPath ? [`--output=${outputPath}`] : []),
+								]
 							: [`--config=${stackPath}`];
 						const exitCode = await runCliPassthrough({
 							cwd,

diff --git a/packages/cli/src/utils/constants.ts b/packages/cli/src/utils/constants.ts
--- a/packages/cli/src/utils/constants.ts
+++ b/packages/cli/src/utils/constants.ts
@@ -5,6 +5,8 @@
 	label: string;
 	packageName: string;
 	ormForGenerate?: "prisma" | "drizzle" | "kysely";
+	/** Additional npm packages that must be installed when this adapter is selected. */
+	extraPackages?: string[];
 }
 
 export interface PluginMeta {
@@ -33,6 +35,7 @@
 		label: "Prisma",
 		packageName: "@btst/adapter-prisma",
 		ormForGenerate: "prisma",
+		extraPackages: ["@prisma/adapter-pg", "pg"],
 	},
 	{
 		key: "drizzle",

diff --git a/packages/cli/src/utils/package-installer.ts b/packages/cli/src/utils/package-installer.ts
--- a/packages/cli/src/utils/package-installer.ts
+++ b/packages/cli/src/utils/package-installer.ts
@@ -39,6 +39,7 @@
 		"@btst/yar",
 		"@tanstack/react-query",
 		adapterMeta.packageName,
+		...(adapterMeta.extraPackages ?? []),
 		...pluginExtraPackages,
 	];
 	const { command, args } = getInstallCommand(input.packageManager, packages);

diff --git a/packages/cli/src/utils/passthrough.ts b/packages/cli/src/utils/passthrough.ts
--- a/packages/cli/src/utils/passthrough.ts
+++ b/packages/cli/src/utils/passthrough.ts
@@ -7,6 +7,15 @@
 	return Boolean(ADAPTERS.find((item) => item.key === adapter)?.ormForGenerate);
 }
 
+export function getOutputForAdapter(adapter: Adapter): string | null {
+	const meta = ADAPTERS.find((item) => item.key === adapter);
+	if (!meta?.ormForGenerate) return null;
+
+	if (meta.ormForGenerate === "prisma") return "prisma/schema.prisma";
+	if (meta.ormForGenerate === "drizzle") return "src/db/schema.ts";
+	return "migrations/schema.sql";
+}
+
 export function getGenerateHintForAdapter(
 	adapter: Adapter,
 	configPath: string,
@@ -14,12 +23,8 @@
 	const meta = ADAPTERS.find((item) => item.key === adapter);
 	if (!meta?.ormForGenerate) return null;
 
-	const output =
-		meta.ormForGenerate === "prisma"
-			? "schema.prisma"
-			: meta.ormForGenerate === "drizzle"
-				? "src/db/schema.ts"
-				: "migrations/schema.sql";
+	const output = getOutputForAdapter(adapter);
+	if (!output) return null;
 
 	return `npx @btst/codegen generate --orm=${meta.ormForGenerate} --config=${configPath} --output=${output}`;
 }

diff --git a/packages/cli/src/utils/scaffold-plan.ts b/packages/cli/src/utils/scaffold-plan.ts
--- a/packages/cli/src/utils/scaffold-plan.ts
+++ b/packages/cli/src/utils/scaffold-plan.ts
@@ -322,7 +322,7 @@
 	};
 }
 
-function buildAdapterTemplateContext(adapter: Adapter) {
+function buildAdapterTemplateContext(adapter: Adapter, stackPath: string) {
 	const meta = ADAPTERS.find((item) => item.key === adapter);
 	if (!meta) {
 		throw new Error(`Unsupported adapter: ${adapter}`);
@@ -337,15 +337,19 @@
 	}
 
 	if (adapter === "prisma") {
+		const depth = stackPath.split("/").length - 1;
+		const prismaClientPath = `${"../".repeat(depth)}generated/prisma/client`;
 		return {
 			adapterImport: `import { createPrismaAdapter } from "${meta.packageName}"
-import { PrismaClient } from "@prisma/client"`,
-			adapterSetup: `const prisma = new PrismaClient()
+import { PrismaClient } from "${prismaClientPath}"
+import { PrismaPg } from "@prisma/adapter-pg"`,
+			adapterSetup: `const pgAdapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! })
+const prisma = new PrismaClient({ adapter: pgAdapter })
 
-const provider = process.env.BTST_PRISMA_PROVIDER ?? "postgresql"
+const provider = (process.env.BTST_PRISMA_PROVIDER ?? "postgresql") as "postgresql" | "sqlite" | "cockroachdb" | "mysql" | "sqlserver" | "mongodb"
 `,
 			adapterStackLine:
-				"adapter: (db) => createPrismaAdapter(prisma, db, { provider }),",
+				"adapter: (db) => createPrismaAdapter(prisma, db, { provider })({}),",
 		};
 	}
 
@@ -385,7 +389,10 @@
 		input.plugins,
 		input.framework,
 	);
-	const adapterContext = buildAdapterTemplateContext(input.adapter);
+	const adapterContext = buildAdapterTemplateContext(
+		input.adapter,
+		frameworkPaths.stackPath,
+	);
 
 	const sharedContext = {
 		alias: input.alias,
@@ -402,6 +409,20 @@
 			content: await renderTemplate("shared/lib/stack.ts.hbs", sharedContext),
 			description: "BTST backend stack configuration",
 		},
+		...(input.adapter === "prisma"
+			? [
+					{
+						path: "prisma/schema.prisma",
+						content: `generator client {\n  provider = "prisma-client"\n  output   = "../generated/prisma"\n}\n\ndatasource db {\n  provider = "postgresql"\n}\n`,
+						description: "Prisma schema with explicit client output path",
+					},
+					{
+						path: "prisma.config.ts",
+						content: `import { defineConfig } from 'prisma/config'\n\nexport default defineConfig({\n  schema: 'prisma/schema.prisma',\n  datasource: {\n    url: process.env.DATABASE_URL ?? '',\n  },\n})\n`,
+						description: "Prisma configuration file",
+					},
+				]
+			: []),
 		{
 			path: frameworkPaths.stackClientPath,
 			content: await renderTemplate(

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit c112ecd. Configure here.

Comment thread packages/cli/src/utils/constants.ts Outdated
Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Shadcn registry validated — no registry changes detected.

@olliethedev olliethedev merged commit 9406c1d into main Apr 16, 2026
10 checks passed
@olliethedev olliethedev deleted the fix/cogegen-cli-prisma branch April 16, 2026 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants