Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified cli/bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"dependencies": {
"@clack/prompts": "^0.8.1",
"chalk": "^5.3.0",
"picocolors": "^0.2.1",
"execa": "^9.5.2",
"fs-extra": "^11.2.0",
"hono": "^4.7.0",
Expand Down
9 changes: 5 additions & 4 deletions cli/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getUserPkgManager } from "@/utils/get-user-pkg-manager.js"

export interface CliResults {
projectName: string
orm: "none" | "drizzle" | undefined
orm: "none" | "drizzle" | "prisma" | undefined
dialect?: "postgres" | undefined
provider?: "neon" | "postgres" | "vercel-postgres" | "planetscale" | undefined
noInstall?: boolean
Expand Down Expand Up @@ -40,11 +40,12 @@ export async function runCli(): Promise<CliResults | undefined> {
return undefined
}

const orm = await select<"none" | "drizzle">({
const orm = await select<"none" | "drizzle" | "prisma">({
message: "Which database ORM would you like to use?",
options: [
{ value: "none", label: "None" },
{ value: "drizzle", label: "Drizzle ORM" },
{ value: "prisma", label: "Prisma ORM" },
],
})

Expand All @@ -57,7 +58,6 @@ export async function runCli(): Promise<CliResults | undefined> {
let provider = undefined
if (orm === "drizzle") {
dialect = "postgres" as const // Only offering postgres

provider = await select({
message: "Which Postgres provider would you like to use?",
options: [
Expand All @@ -66,11 +66,12 @@ export async function runCli(): Promise<CliResults | undefined> {
{ value: "vercel-postgres", label: "Vercel Postgres" },
],
})

if (isCancel(provider)) {
outro("Setup cancelled.")
return undefined
}
} else if (orm === "prisma") {
// Prisma CLI does not need a separate provider installer
}

let noInstall = noInstallFlag
Expand Down
10 changes: 10 additions & 0 deletions cli/src/helpers/install-base-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as p from "@clack/prompts"
import chalk from "chalk"
import fs from "fs-extra"
import ora from "ora"
import { execa } from "execa"

import { PKG_ROOT } from "@/constants.js"
import { type InstallerOptions } from "@/installers/index.js"
Expand Down Expand Up @@ -103,4 +104,13 @@ export const installBaseTemplate = async ({
spinner.succeed(
`${scaffoldedName} ${chalk.green("scaffolded successfully!")}\n`,
)
// Initialize a git repository and make initial commit
try {
await execa("git", ["init"], { cwd: projectDir })
await execa("git", ["add", "."], { cwd: projectDir })
await execa("git", ["commit", "-m", "Initial commit"], { cwd: projectDir })
logger.info("Initialized git repository")
} catch {
// ignore if git is not available
}
}
27 changes: 16 additions & 11 deletions cli/src/installers/dep-version-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,27 @@
*/
export const dependencyVersionMap = {
// neon
"@neondatabase/serverless": "^0.10.4",
"@neondatabase/serverless": "*",

// vercel postgres
"@vercel/postgres": "^0.10.0",
"@vercel/postgres": "*",

// Drizzle
"drizzle-kit": "^0.30.1",
"drizzle-orm": "^0.39.0",
"eslint-plugin-drizzle": "^0.2.3",
"@planetscale/database": "^1.19.0",
postgres: "^3.4.5",
"drizzle-kit": "*",
"drizzle-orm": "*",
"eslint-plugin-drizzle": "*",
"@planetscale/database": "*",
postgres: "*",

// TailwindCSS
tailwindcss: "^4.0.0",
postcss: "^8.5.1",
prettier: "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.11",
tailwindcss: "*",
postcss: "*",
prettier: "*",
"prettier-plugin-tailwindcss": "*",

// Prisma
prisma: "*",
"@prisma/client": "*",
"@prisma/extension-accelerate": "*",
} as const
export type AvailableDependencies = keyof typeof dependencyVersionMap
7 changes: 6 additions & 1 deletion cli/src/installers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PackageManager } from "@/utils/get-user-pkg-manager.js"
import { drizzleInstaller } from "./drizzle.js"
import { prismaInstaller } from "./prisma.js"
import { neonInstaller } from "./neon.js"
import { noOrmInstaller } from "./no-orm.js"
import { postgresInstaller } from "./postgres.js"
Expand All @@ -8,7 +9,7 @@ import { planetscaleInstaller } from "./planetscale.js"

// Turning this into a const allows the list to be iterated over for programmatically creating prompt options
// Should increase extensibility in the future
export const orms = ["none", "drizzle"] as const
export const orms = ["none", "drizzle", "prisma"] as const
export type Orm = (typeof orms)[number]

export const dialects = ["postgres"] as const
Expand Down Expand Up @@ -57,6 +58,10 @@ export const buildInstallerMap = (
inUse: selectedOrm === "drizzle",
installer: drizzleInstaller,
},
prisma: {
inUse: selectedOrm === "prisma",
installer: prismaInstaller,
},
},
provider: {
postgres: {
Expand Down
64 changes: 64 additions & 0 deletions cli/src/installers/prisma.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import fs from "fs-extra"
import path from "path"
import { type PackageJson } from "type-fest"

import { PKG_ROOT } from "@/constants.js"
import { addPackageDependency } from "@/utils/add-package-dep.js"
import { Installer } from "./index.js"

export const prismaInstaller: Installer = ({ projectDir }) => {
// Add Prisma CLI as a dev dependency and Prisma Client as a dependency
addPackageDependency({
projectDir,
dependencies: ["prisma"],
devDependencies: true,
})
// Add Prisma Accelerate for Edge support
addPackageDependency({
projectDir,
dependencies: ["@prisma/extension-accelerate"],
devDependencies: false,
})
addPackageDependency({
projectDir,
dependencies: ["@prisma/client"],
devDependencies: false,
})

const extrasDir = path.join(PKG_ROOT, "template/extras")

// Copy .env template
const envSrc = path.join(extrasDir, "config/_env-prisma")
const envDest = path.join(projectDir, ".env")

// Copy Prisma schema
const schemaSrc = path.join(extrasDir, "config/schema.prisma")
const schemaDest = path.join(projectDir, "prisma/schema.prisma")

// Copy Prisma client helper
const clientSrc = path.join(extrasDir, "src/lib/prisma.ts")
const clientDest = path.join(projectDir, "src/lib/prisma.ts")

fs.ensureDirSync(path.dirname(envDest))
fs.ensureDirSync(path.dirname(schemaDest))
fs.ensureDirSync(path.dirname(clientDest))

fs.copySync(envSrc, envDest)
fs.copySync(schemaSrc, schemaDest)
fs.copySync(clientSrc, clientDest)
// Copy JStack middleware for Prisma
const jstackSrc = path.join(extrasDir, "src/server/jstack/prisma.ts")
const jstackDest = path.join(projectDir, "src/server/jstack.ts")
fs.ensureDirSync(path.dirname(jstackDest))
fs.copySync(jstackSrc, jstackDest)

// Update package.json scripts
const pkgJsonPath = path.join(projectDir, "package.json")
const pkgJson = fs.readJSONSync(pkgJsonPath) as PackageJson
pkgJson.scripts = {
...pkgJson.scripts,
"prisma:migrate": "prisma migrate dev",
"prisma:generate": "prisma generate --no-engine",
}
fs.writeJSONSync(pkgJsonPath, pkgJson, { spaces: 2 })
}
46 changes: 24 additions & 22 deletions cli/template/base-assets/base-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,31 @@
"lint": "next lint"
},
"dependencies": {
"@tailwindcss/postcss": "^4.0.0",
"@tanstack/react-query": "^5.51.23",
"clsx": "^2.1.1",
"hono": "^4.7.0",
"jstack": "^1.1.1",
"next": "^15.1.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"superjson": "^2.2.1",
"tailwind-merge": "^2.5.2",
"zod": "^3.24.1"
"@tailwindcss/postcss": "*",
"@tanstack/react-query": "*",
"clsx": "*",
"drizzle-orm": "*",
"hono": "*",
"jstack": "*",
"next": "*",
"react": "*",
"react-dom": "*",
"superjson": "*",
"tailwind-merge": "*",
"zod": "*"
},
"devDependencies": {
"dotenv": "^16.4.5",
"@cloudflare/workers-types": "^4.20250214.0",
"@types/node": "^22.10.6",
"@types/react": "^19.0.7",
"@types/react-dom": "^19.0.3",
"eslint": "^9.18.0",
"eslint-config-next": "^15.1.4",
"postcss": "^8",
"tailwindcss": "^4.0.0",
"typescript": "^5",
"wrangler": "^4.0.0"
"dotenv": "*",
"@cloudflare/workers-types": "*",
"@types/node": "*",
"@types/react": "*",
"@types/react-dom": "*",
"drizzle-kit": "*",
"eslint": "*",
"eslint-config-next": "*",
"postcss": "*",
"tailwindcss": "*",
"typescript": "*",
"wrangler": "*"
}
}
30 changes: 30 additions & 0 deletions cli/template/base/wrangler.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "jstack-app",
"main": "src/server/index.ts",
"compatibility_date": "2025-03-22",
"compatibility_flags": [
"nodejs_compat",
"nodejs_als",
"no_handle_cross_request_promise_resolution"
],
// Add these in if you want to use a custom domain
// "routes": [
// {
// "pattern": "sub.domain.com",
// "custom_domain": true
// }
// ],
// "workers_dev": false,
// "preview_urls": false,
"observability": {
"enabled": true,
"head_sampling_rate": 1
},
"placement": {
"mode": "smart"
},
"dev": {
"port": 8080
}
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["jstack", "next.js", "typescript", "hono"],
"keywords": [
"jstack",
"next.js",
"typescript",
"hono"
],
"dependencies": {
"prettier": "^3.4.2"
}
Expand Down