From a1618f13e2ad5cd46d84b825a47826598bcafe06 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Thu, 27 Aug 2026 22:37:03 +0530 Subject: [PATCH] fix(local): resolve prisma dev through package manifest Signed-off-by: Aman Varshney --- .../postgres-module-resolution.test.ts | 24 ++++++++++++++----- .../0-lowering/local-target/src/postgres.ts | 18 +++++++------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/postgres-module-resolution.test.ts b/packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/postgres-module-resolution.test.ts index 6021e210d..1709e28a6 100644 --- a/packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/postgres-module-resolution.test.ts +++ b/packages/1-prisma-cloud/0-lowering/local-target/src/__tests__/postgres-module-resolution.test.ts @@ -7,10 +7,10 @@ import { resolvePrismaDevModulePath } from '../postgres.ts'; /** * `resolvePrismaDevModulePath`'s two-step resolution (local-dev spec § 4, * REVISED — operator review of #162): resolve `@prisma/dev` directly from - * the app's own node_modules first; on failure, resolve `prisma` (which - * apps typically depend on, and which carries `@prisma/dev` as its own - * dependency) and resolve `@prisma/dev` from there; both failing throws the - * pinned error. + * the app's own node_modules first; on failure, resolve the exported + * `prisma/package.json` (the package has no root export) and resolve + * `@prisma/dev` from its dependency tree; both failing throws the pinned + * error. */ describe('resolvePrismaDevModulePath', () => { let cwd: string; @@ -35,6 +35,18 @@ describe('resolvePrismaDevModulePath', () => { fs.writeFileSync(path.join(modDir, 'index.js'), 'module.exports = {};\n'); } + function writePrismaPackage(): void { + const modDir = path.join(cwd, 'node_modules', 'prisma'); + fs.mkdirSync(modDir, { recursive: true }); + fs.writeFileSync( + path.join(modDir, 'package.json'), + JSON.stringify({ + name: 'prisma', + exports: { './package.json': './package.json' }, + }), + ); + } + test('resolves @prisma/dev directly when the app depends on it', () => { writeModule(path.join(cwd, 'node_modules'), '@prisma/dev'); @@ -44,7 +56,7 @@ describe('resolvePrismaDevModulePath', () => { }); test("falls back to resolving @prisma/dev from prisma's own dependency tree", () => { - writeModule(path.join(cwd, 'node_modules'), 'prisma'); + writePrismaPackage(); writeModule(path.join(cwd, 'node_modules', 'prisma', 'node_modules'), '@prisma/dev'); const resolved = resolvePrismaDevModulePath(cwd); @@ -61,7 +73,7 @@ describe('resolvePrismaDevModulePath', () => { }); test('prisma installed but without @prisma/dev throws the pinned error', () => { - writeModule(path.join(cwd, 'node_modules'), 'prisma'); + writePrismaPackage(); expect(() => resolvePrismaDevModulePath(cwd)).toThrow( 'local dev needs @prisma/dev for its local Postgres emulator — add "prisma" to your app\'s devDependencies.', diff --git a/packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts b/packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts index 1c62c7b8b..38e50f3df 100644 --- a/packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts +++ b/packages/1-prisma-cloud/0-lowering/local-target/src/postgres.ts @@ -39,12 +39,14 @@ function noPrismaDevError(): Error { /** * Two-step resolution, pinned (local-dev spec § 4): (1) resolve * `@prisma/dev` directly from the app's own `node_modules`; (2) on failure, - * resolve `prisma` (the CLI apps typically depend on, which itself carries - * `@prisma/dev`) and resolve `@prisma/dev` from THERE. The daemon imports - * the returned path dynamically, so the app stays in charge of its own - * Prisma version. `cwd` is the one place a local provider legitimately - * reads `process.cwd()` — finding the app's own installed version is - * inherently cwd-relative. + * resolve `prisma/package.json` (the exported manifest of the CLI apps + * typically depend on, which itself carries `@prisma/dev`) and resolve + * `@prisma/dev` from THERE. Resolving the manifest is deliberate: the + * consolidated `prisma` package has no root export. The daemon imports the + * returned path dynamically, so the app stays in charge of its own Prisma + * version. `cwd` is the one place a local provider legitimately reads + * `process.cwd()` — finding the app's own installed version is inherently + * cwd-relative. */ export function resolvePrismaDevModulePath(cwd: string): string { const appRequire = createRequire(path.join(cwd, 'package.json')); @@ -54,8 +56,8 @@ export function resolvePrismaDevModulePath(cwd: string): string { // fall through to the prisma-CLI-relative resolution } try { - const prismaEntry = appRequire.resolve('prisma'); - return createRequire(prismaEntry).resolve('@prisma/dev'); + const prismaManifest = appRequire.resolve('prisma/package.json'); + return createRequire(prismaManifest).resolve('@prisma/dev'); } catch { throw noPrismaDevError(); }