diff --git a/.drive/projects/prisma-cli-v8/deferred.md b/.drive/projects/prisma-cli-v8/deferred.md index fcbeec03..5f744ddf 100644 --- a/.drive/projects/prisma-cli-v8/deferred.md +++ b/.drive/projects/prisma-cli-v8/deferred.md @@ -6,6 +6,23 @@ Nothing here is tracked outside this file. ## After the latest cutover (2026-08-25, PR #230) +- **compute-sdk 0.42.0 asks for a `@prisma/management-api-sdk` this repo + does not install.** Its peer range is `^1.69.0`; all three manifests + here pin `1.55.0`, so `pnpm peers check` reports one unmet peer. Left + that way deliberately: the SDK version is a shared type surface, so + moving it in `packages/cli` and `packages/prisma` alone makes the + engine's `ManagementApiClient` a second, incompatible copy and every + command that hands the engine's client to a CLI function stops + typechecking. Moving all three means `packages/cli-engine` changed, + which needs a new engine version, which both families peer-pin + exactly — the three-repo release sequence. Nothing is broken in the + meantime: the field is declared by compute-sdk's own types and the + server sends it whatever the client was generated from. Two ways out, + operator's call: move the SDK with the next engine version train, or + relax compute-sdk's floor back to `^1.44.0`, which is arguably where + it belongs — the floor protects a build-time concern of compute-sdk's + own that no consumer shares. + - **A stale product `dev` dist-tag can block a release publish.** The publish run checks the dev channel before the release leg, and the dev channel resolves each product's `dev` tag with no fallback — so @@ -481,7 +498,7 @@ The cleanup PR removed the compute config and `init`, made service commands para - ~~**`PRISMA_PROJECT_ID` is honoured only by the domain commands**~~ Closed on the PR branch (2026-08-21, operator ruling): the env var served the deleted `app deploy` headless flow and survived only in the domain commands by accident; it is removed entirely. Project targeting is `--project` and the link file. - ~~**orm-toolchain's shipped help examples name retired spellings.**~~ Closed (2026-08-22) by prisma#30102: the family keys are the mount paths and the examples follow; `tests/orm-mount.test.ts` now asserts upstream stays clean. - ~~**The deployment-id targeting asymmetry is undocumented.**~~ Closed on the PR branch (2026-08-21): every deployment-id command (`promote|start|stop|delete|show`, `logs --deployment`) now resolves the id globally with no service parameter, per the "Subjects are positional" ruling. -- **`GET /v1/deployments/{id}` omits the parent `appId`.** Verified against `@prisma/management-api-sdk@1.55.0`: the response carries id/status/url/previewDomain/envVars/createdAt and no owning-app pointer, so `showDeployment` finds the owner via `findAppForDeployment` — a scan of every project's service list and each service's deployments — and every id-targeted command pays it per run. The fix is in pdp-control-plane: include `appId` in the deployment representation; the CLI then swaps the scan for one `GET /v1/apps/{appId}`. +- ~~**`GET /v1/deployments/{id}` omits the parent `appId`.**~~ Closed on this branch (2026-08-25): pdp-control-plane#4983 added the owner to the deployment representation as `serviceId` (ADR-012 vocabulary, not `appId`), compute-sdk 0.42.0 exposes it as `DeploymentDetail.serviceId`, and `showDeployment` now resolves the owner with one `GET /v1/apps/{id}` — `findAppForDeployment` and its per-service scan are deleted. ## From the agent-skills delivery (project closed 2026-08-22) diff --git a/packages/cli/package.json b/packages/cli/package.json index 35b7c702..980b8fed 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -51,7 +51,7 @@ "@manypkg/tools": "^2.1.2", "@prisma/cli-engine": "workspace:0.2.3", "@prisma/composer-cli": "0.14.0", - "@prisma/compute-sdk": "0.39.0", + "@prisma/compute-sdk": "0.42.0", "@prisma/management-api-sdk": "1.55.0", "@prisma/orm-toolchain": "8.0.0-rc.7", "@vercel/detect-agent": "^1.2.3", diff --git a/packages/cli/src/lib/app/app-provider.ts b/packages/cli/src/lib/app/app-provider.ts index b2d98224..bc1176cc 100644 --- a/packages/cli/src/lib/app/app-provider.ts +++ b/packages/cli/src/lib/app/app-provider.ts @@ -1,4 +1,4 @@ -// biome-ignore-all lint/performance/noAwaitInLoops: API pagination and deployment lookup scans are intentionally sequential. +// biome-ignore-all lint/performance/noAwaitInLoops: API pagination walks pages in order. // biome-ignore-all lint/performance/useTopLevelRegex: Existing hostname normalization regexes are kept inline for readability. // biome-ignore-all lint/style/noNestedTernary: Existing app resolution expression is intentionally compact. import type { StreamRecord } from "@prisma/compute-sdk"; @@ -697,9 +697,9 @@ export function createAppProvider( throw new Error(deploymentResult.error.message); } - const app = await findAppForDeployment( + const app = await owningService( sdk, - deploymentId, + deploymentResult.value.serviceId, options?.signal, ); @@ -920,6 +920,29 @@ async function listComputeServices( return services.map(toAppRecord); } +async function owningService( + sdk: ComputeClient, + serviceId: string, + signal?: AbortSignal, +): Promise { + const result = await sdk.showApp({ appId: serviceId, signal }); + if (result.isErr()) { + // Only a deleted service reads as ownerless; any other failure is real + // and must not be reported as a version with no service. + if (ApiError.is(result.error) && result.error.statusCode === 404) { + return null; + } + throw new Error(result.error.message); + } + return { + id: result.value.id, + name: result.value.name, + region: result.value.region ?? null, + liveDeploymentId: result.value.latestDeploymentId ?? null, + liveUrl: toAbsoluteUrl(result.value.appEndpointDomain ?? null), + }; +} + function toAppRecord(service: RawAppRecord): AppRecord { return { id: service.id, @@ -1100,80 +1123,6 @@ function domainApiCallError( }); } -async function findAppForDeployment( - sdk: ComputeClient, - deploymentId: string, - signal?: AbortSignal, -): Promise { - const projectsResult = await sdk.listProjects({ signal }); - if (projectsResult.isErr()) { - throw new Error(projectsResult.error.message); - } - - for (const project of projectsResult.value) { - const servicesResult = await sdk.listApps({ - projectId: project.id, - signal, - }); - if (servicesResult.isErr()) { - throw new Error(servicesResult.error.message); - } - - for (const service of servicesResult.value) { - const app = await findServiceAppForDeployment( - sdk, - service.id, - deploymentId, - signal, - ); - if (app) { - return app; - } - } - } - - return null; -} - -async function findServiceAppForDeployment( - sdk: ComputeClient, - serviceId: string, - deploymentId: string, - signal?: AbortSignal, -): Promise { - const detailResult = await sdk.showApp({ - appId: serviceId, - signal, - }); - if (detailResult.isErr()) { - throw new Error(detailResult.error.message); - } - - const app: AppRecord = { - id: detailResult.value.id, - name: detailResult.value.name, - region: detailResult.value.region ?? null, - liveDeploymentId: detailResult.value.latestDeploymentId ?? null, - liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null), - }; - - if (app.liveDeploymentId === deploymentId) { - return app; - } - - const versionsResult = await sdk.listDeployments({ - appId: serviceId, - signal, - }); - if (versionsResult.isErr()) { - throw new Error(versionsResult.error.message); - } - - return versionsResult.value.some((version) => version.id === deploymentId) - ? app - : null; -} - function toAbsoluteUrl(url: string | null): string | null { if (!url) { return null; diff --git a/packages/cli/tests/service-testkit.ts b/packages/cli/tests/service-testkit.ts index 908baf83..c1b3c4b2 100644 --- a/packages/cli/tests/service-testkit.ts +++ b/packages/cli/tests/service-testkit.ts @@ -67,6 +67,7 @@ export interface RawServiceDetail { export interface RawDeployment { id: string; + serviceId: string; status: string; createdAt: string; previewDomain: string | null; @@ -178,12 +179,14 @@ export const SERVICE_DETAIL: RawServiceDetail = { export const DEPLOYMENTS: RawDeployment[] = [ { id: "dep_1", + serviceId: "svc_1", status: "stopped", createdAt: "2026-08-01T00:00:00.000Z", previewDomain: "dep1.prisma.app", }, { id: "dep_2", + serviceId: "svc_1", status: "running", createdAt: "2026-08-02T00:00:00.000Z", previewDomain: "dep2.prisma.app", @@ -261,6 +264,7 @@ export function releaseRoutes(overrides: Routes = {}): Routes { data: { data: { id, + serviceId: "svc_1", status, createdAt: "2026-08-01T00:00:00.000Z", previewDomain: `${id}.prisma.app`, diff --git a/packages/cli/tests/service-version-promote.test.ts b/packages/cli/tests/service-version-promote.test.ts index b7ee6e15..865ad0ae 100644 --- a/packages/cli/tests/service-version-promote.test.ts +++ b/packages/cli/tests/service-version-promote.test.ts @@ -4,7 +4,6 @@ import { describe, expect, it } from "vitest"; import { makeServiceCli, - page, presentedSummary, releaseRoutes, } from "./service-testkit"; @@ -188,7 +187,12 @@ describe("prisma service version promote", () => { it("settles a deployment with no owning service as SERVICE.VERSION_DETACHED", async () => { const harness = await makeServiceCli({ - routes: releaseRoutes({ "GET /v1/apps": () => ({ data: page([]) }) }), + routes: releaseRoutes({ + "GET /v1/apps/{appId}": () => ({ + error: { error: { message: "not found" } }, + status: 404, + }), + }), }); const result = await harness.cli.run( diff --git a/packages/prisma/package.json b/packages/prisma/package.json index 5a07e63d..2de00e16 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -51,7 +51,7 @@ "@manypkg/tools": "^2.1.2", "@prisma/cli-engine": "workspace:0.2.3", "@prisma/composer-cli": "0.14.0", - "@prisma/compute-sdk": "0.39.0", + "@prisma/compute-sdk": "0.42.0", "@prisma/management-api-sdk": "1.55.0", "@prisma/orm-toolchain": "8.0.0-rc.7", "@vercel/detect-agent": "^1.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe390a9c..eaca8eab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,8 +33,8 @@ importers: specifier: 0.14.0 version: 0.14.0(@prisma/cli-engine@packages+cli-engine)(@types/node@22.19.19)(@vercel/nft@1.10.2(rollup@4.62.2))(magicast@0.5.3)(mongodb@6.21.0(@aws-sdk/credential-providers@3.1107.0))(mysql2@3.23.3(@types/node@22.19.19))(pg@8.23.0)(typescript@6.0.3)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vitest@4.1.8(@types/node@22.19.19)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(ws@8.21.0) '@prisma/compute-sdk': - specifier: 0.39.0 - version: 0.39.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2) + specifier: 0.42.0 + version: 0.42.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2) '@prisma/management-api-sdk': specifier: 1.55.0 version: 1.55.0 @@ -207,8 +207,8 @@ importers: specifier: 0.14.0 version: 0.14.0(@prisma/cli-engine@packages+cli-engine)(@types/node@22.19.19)(@vercel/nft@1.10.2(rollup@4.62.2))(magicast@0.5.3)(mongodb@6.21.0(@aws-sdk/credential-providers@3.1107.0))(mysql2@3.23.3(@types/node@22.19.19))(pg@8.23.0)(typescript@6.0.3)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vitest@4.1.8(@types/node@22.19.19)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(ws@8.21.0) '@prisma/compute-sdk': - specifier: 0.39.0 - version: 0.39.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2) + specifier: 0.42.0 + version: 0.42.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2) '@prisma/management-api-sdk': specifier: 1.55.0 version: 1.55.0 @@ -1340,11 +1340,11 @@ packages: resolution: {integrity: sha512-XRXadDM5+zpEDZIW602asV7YFfwbC+BU2cWLXQw0l1QddOTlvSquvZKB20n8Sg9x1pRm279Pmo0eGuB0I/VLPg==} engines: {node: '>=22.18.0'} - '@prisma/compute-sdk@0.39.0': - resolution: {integrity: sha512-Ir4yuCiqyv7XjhqsqolKZjXzzMCFiZJ4vvk1jl0dn6MjZx1j6puojD+1BLbCE8ty0NakaOyhWmXWyO63YeUf/Q==} + '@prisma/compute-sdk@0.42.0': + resolution: {integrity: sha512-Rtgjd5tX/5mWp+wzcar+NiyKRPTpPaPhGtvq4WtkTnJaYKGO6cH5a/P51JQ3GapTE3hnFPDWfA33QiUwFtkPHQ==} engines: {node: '>=18.0.0'} peerDependencies: - '@prisma/management-api-sdk': ^1.44.0 + '@prisma/management-api-sdk': ^1.69.0 '@prisma/credentials-store@7.8.0': resolution: {integrity: sha512-T9yp5uYSowV2ZRkBeCZrqWFP4REUlxd5WEYgOFJDjZBRRV+zx3VFCBf0zJI7Z3/PYFF9o3+ZzLwokQ9nY5EbqA==} @@ -1361,8 +1361,8 @@ packages: '@prisma/management-api-sdk@1.55.0': resolution: {integrity: sha512-WuDDOhxOHfROGY7QAU6wtlbWR0diNwfsQw1epQkhalvgOUe/JzIjxqpBpQzMA54zFVlMmcnT6OEiQfwCIKiRjA==} - '@prisma/management-api-sdk@1.62.0': - resolution: {integrity: sha512-XJjNcsMEmvXA2vE88cBSwCQBKiWx3ArGQ00MIFePP653ZdY0Uiaodoyw++WnwewvHqOvpzgSC3XsijjRUuveHQ==} + '@prisma/management-api-sdk@1.69.0': + resolution: {integrity: sha512-z3zBWvOjFSWqUwkJcsdkBZzkUaUMEEcKy4QiMfo7n1GqNQvRYkzxzaNRTqmxTjw3thOjmdq+UegIqOU57i7jiA==} '@prisma/orm-framework@8.0.0-rc.7': resolution: {integrity: sha512-yl3giEt14nuHkxBQjXlzfstXdYxQPjbnJJ9lyA+5oNRgqIPdwwJiEUUxhASnAyhfrENZMJhtiwSqJPPxCGp4+A==} @@ -4229,7 +4229,7 @@ snapshots: https-proxy-agent: 7.0.6 node-fetch: 2.7.0 nopt: 8.1.0 - semver: 7.8.1 + semver: 7.8.5 tar: 7.5.19 transitivePeerDependencies: - encoding @@ -4413,7 +4413,7 @@ snapshots: '@prisma/composer@0.14.0(@types/node@22.19.19)(@vercel/nft@1.10.2(rollup@4.62.2))(magicast@0.5.3)(mongodb@6.21.0(@aws-sdk/credential-providers@3.1107.0))(mysql2@3.23.3(@types/node@22.19.19))(pg@8.23.0)(typescript@6.0.3)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vitest@4.1.8(@types/node@22.19.19)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(ws@8.21.0)': dependencies: - '@prisma/management-api-sdk': 1.62.0 + '@prisma/management-api-sdk': 1.69.0 '@standard-schema/spec': 1.1.0 alchemy: 2.0.0-beta.74(@types/node@22.19.19)(@vercel/nft@1.10.2(rollup@4.62.2))(effect@4.0.0-rc.111)(mongodb@6.21.0(@aws-sdk/credential-providers@3.1107.0))(mysql2@3.23.3(@types/node@22.19.19))(pg@8.23.0)(typescript@6.0.3)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vitest@4.1.8(@types/node@22.19.19)(vite@7.3.5(@types/node@22.19.19)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(ws@8.21.0) arktype: 2.2.3 @@ -4445,7 +4445,7 @@ snapshots: - vitest - ws - '@prisma/compute-sdk@0.39.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2)': + '@prisma/compute-sdk@0.42.0(@prisma/management-api-sdk@1.55.0)(rollup@4.62.2)': dependencies: '@prisma/management-api-sdk': 1.55.0 '@vercel/nft': 1.10.2(rollup@4.62.2) @@ -4503,7 +4503,7 @@ snapshots: dependencies: openapi-fetch: 0.14.0 - '@prisma/management-api-sdk@1.62.0': + '@prisma/management-api-sdk@1.69.0': dependencies: openapi-fetch: 0.14.0