Skip to content
Merged
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-prisma",
"version": "0.14.6",
"version": "0.14.7",
"private": false,
"description": "Create Prisma 8 projects with first-party templates and great DX.",
"homepage": "https://github.com/prisma/create-prisma",
Expand Down Expand Up @@ -37,7 +37,7 @@
"dev": "tsdown --watch",
"start": "bun run ./dist/cli.mjs",
"test": "bun run test:unit && bun run test:e2e",
"test:unit": "bun test ./tests/create-context.test.ts ./tests/dependencies.test.ts ./tests/deploy-with-composer.test.ts ./tests/initialize-git.test.ts ./tests/install.test.ts ./tests/json-output.test.ts ./tests/node-version.test.ts ./tests/package-manager-error-code.test.ts ./tests/setup-prisma.test.ts ./tests/telemetry-client.test.ts ./tests/telemetry.test.ts",
"test:unit": "bun test ./tests/create-context.test.ts ./tests/dependencies.test.ts ./tests/deploy-with-composer.test.ts ./tests/initialize-git.test.ts ./tests/install.test.ts ./tests/json-output.test.ts ./tests/node-version.test.ts ./tests/package-manager-error-code.test.ts ./tests/pin-problems.test.ts ./tests/setup-prisma.test.ts ./tests/telemetry-client.test.ts ./tests/telemetry.test.ts",
"test:e2e": "bun test --timeout 180000 ./tests/e2e/create-prisma.e2e.test.ts",
"check": "bun run format:check && bun run lint",
"lint": "oxlint . --deny-warnings",
Expand Down
105 changes: 25 additions & 80 deletions scripts/check-pins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,37 @@ import { execFile } from "node:child_process";
import { promisify } from "node:util";

import { dependencyVersionMap } from "../src/constants/dependencies";
import { findPinProblem } from "./pin-problems";

const execFileAsync = promisify(execFile);

async function npmViewJson(packageSpec: string, field: string): Promise<unknown> {
async function npmViewJson(packageSpec: string, field: string): Promise<Record<string, string>> {
const { stdout } = await execFileAsync("npm", ["view", packageSpec, field, "--json"]);
return JSON.parse(stdout) as unknown;
}

const cliVersion = dependencyVersionMap.prisma;
const composerVersion = dependencyVersionMap["@prisma/composer"];
const composerCloudVersion = dependencyVersionMap["@prisma/composer-prisma-cloud"];
const ormVersion = dependencyVersionMap["@prisma/orm-postgres"];
const mongoVersion = dependencyVersionMap["@prisma/orm-mongo"];

if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(cliVersion)) {
console.error(`prisma is pinned to "${cliVersion}", which is not an exact version.`);
process.exit(1);
}

if (composerVersion !== composerCloudVersion) {
console.error(
`@prisma/composer is pinned to ${composerVersion} but @prisma/composer-prisma-cloud to ${composerCloudVersion}.`,
);
process.exit(1);
}

if (mongoVersion !== ormVersion) {
console.error(
`@prisma/orm-mongo is pinned to ${mongoVersion} but @prisma/orm-postgres to ${ormVersion}.`,
);
process.exit(1);
}

const cliDependencies = (await npmViewJson(`prisma@${cliVersion}`, "dependencies")) as Record<
string,
string
>;
const composerCliVersion = cliDependencies["@prisma/composer-cli"];
const toolchainVersion = cliDependencies["@prisma/orm-toolchain"];

if (!composerCliVersion) {
console.error(`prisma@${cliVersion} does not depend on @prisma/composer-cli.`);
return JSON.parse(stdout) as Record<string, string>;
}

const [cliDependencies, composerDependencies, composerCloudPeerDependencies] = await Promise.all([
npmViewJson(`prisma@${dependencyVersionMap.prisma}`, "dependencies"),
npmViewJson(`@prisma/composer@${dependencyVersionMap["@prisma/composer"]}`, "dependencies"),
npmViewJson(
`@prisma/composer-prisma-cloud@${dependencyVersionMap["@prisma/composer-prisma-cloud"]}`,
"peerDependencies",
),
]);

const problem = findPinProblem(dependencyVersionMap, {
cliDependencies,
composerDependencies,
composerCloudPeerDependencies,
});

if (problem) {
console.error(problem);
process.exit(1);
}

if (composerCliVersion !== composerVersion) {
console.error(
`Version mismatch: prisma@${cliVersion} depends on @prisma/composer-cli@${composerCliVersion}, ` +
`but scaffolds pin @prisma/composer to ${composerVersion}.\n` +
`Bump the Composer pins to ${composerCliVersion}, or pin prisma to the release that depends on ${composerVersion}.`,
);
process.exit(1);
}

const cloudPeerDependencies = (await npmViewJson(
`@prisma/composer-prisma-cloud@${composerCloudVersion}`,
"peerDependencies",
)) as Record<string, string>;
const cloudOrmPeer = cloudPeerDependencies["@prisma/orm-postgres"];

if (!cloudOrmPeer) {
console.error(
`@prisma/composer-prisma-cloud@${composerCloudVersion} does not declare a peerDependency on @prisma/orm-postgres.`,
);
process.exit(1);
}

if (cloudOrmPeer !== ormVersion) {
console.error(
`Version mismatch: @prisma/composer-prisma-cloud@${composerCloudVersion} peers ` +
`@prisma/orm-postgres@${cloudOrmPeer}, but scaffolds pin it to ${ormVersion}.\n` +
`Bump the ORM pins to ${cloudOrmPeer}, or pin Composer to the release that peers ${ormVersion}.`,
);
process.exit(1);
}

if (toolchainVersion && toolchainVersion !== ormVersion) {
console.warn(
`Note: prisma@${cliVersion} bundles @prisma/orm-toolchain@${toolchainVersion}, ` +
`which differs from the pinned ORM ${ormVersion}. ` +
`The ORM pin follows @prisma/composer-prisma-cloud's peerDependency so npm install stays resolvable.`,
);
}

console.log(
`prisma@${cliVersion} depends on @prisma/composer-cli@${composerCliVersion}, ` +
`matching the pinned Composer ${composerVersion}; ` +
`@prisma/composer-prisma-cloud peers @prisma/orm-postgres@${cloudOrmPeer}, matching the ORM pins.`,
`prisma@${dependencyVersionMap.prisma} matches Composer ${dependencyVersionMap["@prisma/composer"]}, ` +
`and both use ORM ${dependencyVersionMap["@prisma/orm-postgres"]}, alchemy ${dependencyVersionMap.alchemy} ` +
`and effect ${dependencyVersionMap.effect}.`,
);
86 changes: 86 additions & 0 deletions scripts/pin-problems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { dependencyVersionMap } from "../src/constants/dependencies";

export type Pins = Pick<
typeof dependencyVersionMap,
| "prisma"
| "@prisma/composer"
| "@prisma/composer-prisma-cloud"
| "@prisma/orm-postgres"
| "@prisma/orm-mongo"
| "alchemy"
| "effect"
>;

type Dependencies = Record<string, string | undefined>;

export type RegistryMetadata = {
cliDependencies: Dependencies;
composerDependencies: Dependencies;
composerCloudPeerDependencies: Dependencies;
};

export function findPinProblem(pins: Pins, registry: RegistryMetadata): string | undefined {
const cliVersion = pins.prisma;
const composerVersion = pins["@prisma/composer"];
const composerCloudVersion = pins["@prisma/composer-prisma-cloud"];
const ormVersion = pins["@prisma/orm-postgres"];
const mongoVersion = pins["@prisma/orm-mongo"];

if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(cliVersion)) {
return `prisma is pinned to "${cliVersion}", which is not an exact version.`;
}
if (composerVersion !== composerCloudVersion) {
return `@prisma/composer is pinned to ${composerVersion} but @prisma/composer-prisma-cloud to ${composerCloudVersion}.`;
}
if (mongoVersion !== ormVersion) {
return `@prisma/orm-mongo is pinned to ${mongoVersion} but @prisma/orm-postgres to ${ormVersion}.`;
}

const composerCliVersion = registry.cliDependencies["@prisma/composer-cli"];
if (!composerCliVersion) {
return `prisma@${cliVersion} does not depend on @prisma/composer-cli.`;
}
if (composerCliVersion !== composerVersion) {
return (
`Version mismatch: prisma@${cliVersion} depends on @prisma/composer-cli@${composerCliVersion}, ` +
`but scaffolds pin @prisma/composer to ${composerVersion}.\n` +
`Bump the Composer pins to ${composerCliVersion}, or pin prisma to the release that depends on ${composerVersion}.`
);
}

for (const name of ["alchemy", "effect"] as const) {
const composerPin = registry.composerDependencies[name];
if (composerPin !== pins[name]) {
return (
`Version mismatch: @prisma/composer@${composerVersion} depends on ${name}@${composerPin}, ` +
`but scaffolds pin it to ${pins[name]}.`
);
}
}

const cloudOrmPeer = registry.composerCloudPeerDependencies["@prisma/orm-postgres"];
if (!cloudOrmPeer) {
return `@prisma/composer-prisma-cloud@${composerCloudVersion} does not declare a peerDependency on @prisma/orm-postgres.`;
}
if (cloudOrmPeer !== ormVersion) {
return (
`Version mismatch: @prisma/composer-prisma-cloud@${composerCloudVersion} peers ` +
`@prisma/orm-postgres@${cloudOrmPeer}, but scaffolds pin it to ${ormVersion}.\n` +
`Bump the ORM pins to ${cloudOrmPeer}, or pin Composer to the release that peers ${ormVersion}.`
);
}

const toolchainVersion = registry.cliDependencies["@prisma/orm-toolchain"];
if (!toolchainVersion) {
return `prisma@${cliVersion} does not depend on @prisma/orm-toolchain.`;
}
if (toolchainVersion !== ormVersion) {
return (
`Version mismatch: prisma@${cliVersion} bundles @prisma/orm-toolchain@${toolchainVersion}, ` +
`but scaffolds pin the ORM to ${ormVersion}. \`prisma contract emit\` rejects ORM packages ` +
`from another release, so wait for a Composer and prisma release on the same ORM version.`
);
}

return undefined;
}
27 changes: 13 additions & 14 deletions src/constants/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,28 @@ import type { CreateTemplate, PackageManager } from "../types";
export const dependencyVersionMap = {
"@astrojs/node": "^11.1.9",
"@elysia/node": "^1.4.6",
"@prisma/composer": "0.35.0",
"@prisma/composer-prisma-cloud": "0.35.0",
"@prisma/composer": "0.38.0",
"@prisma/composer-prisma-cloud": "0.38.0",
"@prisma/dev": "0.25.2",
"@prisma/orm-mongo": "8.0.0-rc.20",
// Must match @prisma/composer-prisma-cloud's exact peerDependency, even when
// prisma bundles a newer @prisma/orm-toolchain, or npm install fails with
// ERESOLVE.
"@prisma/orm-postgres": "8.0.0-rc.20",
"@prisma/orm-mongo": "8.0.0-rc.23",
// Must match both @prisma/composer-prisma-cloud's exact peerDependency (or npm
// install fails with ERESOLVE) and the @prisma/orm-toolchain the prisma CLI
// bundles (or `prisma contract emit` rejects the ORM packages).
// `bun run check:pins` verifies both.
"@prisma/orm-postgres": "8.0.0-rc.23",
"@sveltejs/adapter-node": "^6.0.0",
"@types/node": "^26.6.5",
"@vitejs/devtools": "0.7.6",
alchemy: "2.0.0-beta.83",
alchemy: "2.0.0-beta.84",
arktype: "^2.2.9",
dotenv: "^18.0.9",
effect: "4.0.3",
effect: "4.0.5",
mongodb: "^7.7.0",
"mongodb-memory-server": "^11.3.0",
nitro: "^3.0.260903-beta",
// Must match the @prisma/composer-cli version this prisma release depends on.
// `bun run check:pins` verifies that against the Composer pins above.
prisma: "8.0.0-rc.28",
prisma: "8.0.0-rc.33",
// Node 22 needs a global Temporal for the ORM runtime's timestamp columns.
"temporal-polyfill": "^1.0.6",
tsdown: "^0.23.1",
Expand All @@ -33,15 +34,13 @@ export const dependencyVersionMap = {
} as const;

// Pinned to the effect version as a set: @effect/* siblings depend on each other with
// caret prerelease ranges, so a newer rc (e.g. platform-node-shared rc.118) floats in and
// imports effect modules the pinned effect lacks.
// caret ranges, so a newer sibling floats in and imports effect modules the pinned
// effect lacks.
export const effectPackages = [
"effect",
"@effect/platform-bun",
"@effect/platform-node",
"@effect/platform-node-shared",
"@effect/sql-d1",
"@effect/sql-sqlite-do",
"@effect/vitest",
] as const;

Expand Down
12 changes: 5 additions & 7 deletions templates/create/_package-manager/pnpm-workspace.yaml.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ allowBuilds:
minimumReleaseAgeExclude:
- "@prisma/*"
overrides:
effect: "4.0.3"
"@effect/platform-bun": "4.0.3"
"@effect/platform-node": "4.0.3"
"@effect/platform-node-shared": "4.0.3"
"@effect/sql-d1": "4.0.3"
"@effect/sql-sqlite-do": "4.0.3"
"@effect/vitest": "4.0.3"
effect: "4.0.5"
"@effect/platform-bun": "4.0.5"
"@effect/platform-node": "4.0.5"
"@effect/platform-node-shared": "4.0.5"
"@effect/vitest": "4.0.5"
{{#if (eq provider "mongo")}}
peerDependencyRules:
allowedVersions:
Expand Down
2 changes: 1 addition & 1 deletion templates/create/_shared/src/prisma/users.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export async function listUsers(limit = 10) {
email: user.email,
username: user.username ?? null,
name: user.name ?? null,
createdAt: user.createdAt,
createdAt: user.createdAt?.toISOString() ?? null,
}));
{{/if}}
}
Expand Down
14 changes: 7 additions & 7 deletions tests/dependencies.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { dependencyVersionMap, getDependencyVersion } from "../src/constants/dep

describe("Prisma 8 dependency versions", () => {
test("uses the selected Prisma 8 and Composer releases", () => {
expect(getDependencyVersion("@prisma/orm-postgres")).toBe("8.0.0-rc.20");
expect(getDependencyVersion("@prisma/orm-mongo")).toBe("8.0.0-rc.20");
expect(getDependencyVersion("@prisma/composer")).toBe("0.35.0");
expect(getDependencyVersion("@prisma/composer-prisma-cloud")).toBe("0.35.0");
expect(getDependencyVersion("prisma")).toBe("8.0.0-rc.28");
expect(getDependencyVersion("alchemy")).toBe("2.0.0-beta.83");
expect(getDependencyVersion("effect")).toBe("4.0.3");
expect(getDependencyVersion("@prisma/orm-postgres")).toBe("8.0.0-rc.23");
expect(getDependencyVersion("@prisma/orm-mongo")).toBe("8.0.0-rc.23");
expect(getDependencyVersion("@prisma/composer")).toBe("0.38.0");
expect(getDependencyVersion("@prisma/composer-prisma-cloud")).toBe("0.38.0");
expect(getDependencyVersion("prisma")).toBe("8.0.0-rc.33");
expect(getDependencyVersion("alchemy")).toBe("2.0.0-beta.84");
expect(getDependencyVersion("effect")).toBe("4.0.5");
expect(getDependencyVersion("turbo")).toBe("2.11.10");
expect(getDependencyVersion("typescript")).toBe("^6.0.3");
});
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/create-prisma.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ describe("create-prisma e2e", () => {
expect(packageJson.devDependencies.prisma).toBe(dependencyVersionMap.prisma);
expect(packageJson.scripts.postinstall).toBe("prisma skills sync || exit 0");
expect(packageJson.scripts.deploy).toContain("bun run composer:deploy");
expect(packageJson.overrides.effect).toBe("4.0.3");
expect(packageJson.overrides.effect).toBe(dependencyVersionMap.effect);
expect(moduleSource).toContain("postgres({");
expect(dbSource).toContain("service.load().database.client");

Expand Down
Loading
Loading