@prisma/cli 2.20.0 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/LICENSE +158 -0
  2. package/README.md +29 -28
  3. package/dist/adapters/config.js +74 -0
  4. package/dist/adapters/local-state.js +98 -0
  5. package/dist/adapters/mock-api.js +57 -0
  6. package/dist/adapters/token-storage.js +43 -0
  7. package/dist/cli.js +9 -0
  8. package/dist/cli2.js +59 -0
  9. package/dist/commands/app/index.js +223 -0
  10. package/dist/commands/auth/index.js +42 -0
  11. package/dist/commands/branch/index.js +51 -0
  12. package/dist/commands/project/index.js +45 -0
  13. package/dist/controllers/app.js +813 -0
  14. package/dist/controllers/auth.js +107 -0
  15. package/dist/controllers/branch.js +73 -0
  16. package/dist/controllers/project.js +214 -0
  17. package/dist/controllers/select-prompt-port.js +12 -0
  18. package/dist/lib/app/bun-project.js +39 -0
  19. package/dist/lib/app/env-vars.js +24 -0
  20. package/dist/lib/app/local-dev.js +149 -0
  21. package/dist/lib/app/preview-build.js +283 -0
  22. package/dist/lib/app/preview-interaction.js +38 -0
  23. package/dist/lib/app/preview-progress.js +139 -0
  24. package/dist/lib/app/preview-provider.js +232 -0
  25. package/dist/lib/auth/auth-ops.js +57 -0
  26. package/dist/lib/auth/client.js +22 -0
  27. package/dist/lib/auth/guard.js +34 -0
  28. package/dist/lib/auth/login.js +117 -0
  29. package/dist/output/patterns.js +93 -0
  30. package/dist/presenters/app.js +405 -0
  31. package/dist/presenters/auth.js +73 -0
  32. package/dist/presenters/branch.js +111 -0
  33. package/dist/presenters/project.js +84 -0
  34. package/dist/shell/command-meta.js +320 -0
  35. package/dist/shell/command-runner.js +33 -0
  36. package/dist/shell/errors.js +66 -0
  37. package/dist/shell/global-flags.js +25 -0
  38. package/dist/shell/help.js +78 -0
  39. package/dist/shell/output.js +54 -0
  40. package/dist/shell/prompt.js +31 -0
  41. package/dist/shell/runtime.js +51 -0
  42. package/dist/shell/ui.js +59 -0
  43. package/dist/use-cases/auth.js +70 -0
  44. package/dist/use-cases/branch.js +95 -0
  45. package/dist/use-cases/create-cli-gateways.js +93 -0
  46. package/dist/use-cases/project.js +75 -0
  47. package/package.json +49 -137
  48. package/build/child.js +0 -4110
  49. package/build/index.js +0 -104447
  50. package/build/public/demo.html +0 -17
  51. package/build/public/demoChunk.js +0 -2
  52. package/build/public/electron-darwin.html +0 -19
  53. package/build/public/electron-linux.html +0 -18
  54. package/build/public/electron-mac.html +0 -18
  55. package/build/public/electron-win.html +0 -17
  56. package/build/public/electron-win32.html +0 -18
  57. package/build/public/electron.html +0 -17
  58. package/build/public/electronBus.js +0 -2
  59. package/build/public/electronChunk.js +0 -2
  60. package/build/public/favicon/apple-touch-icon.png +0 -0
  61. package/build/public/favicon/favicon-16x16.png +0 -0
  62. package/build/public/favicon/favicon-32x32.png +0 -0
  63. package/build/public/favicon/prisma.png +0 -0
  64. package/build/public/fonts/Inter.ttf +0 -0
  65. package/build/public/fonts/RobotoMono.ttf +0 -0
  66. package/build/public/icons/.DS_Store +0 -0
  67. package/build/public/icons/alert.svg +0 -5
  68. package/build/public/icons/array.svg +0 -4
  69. package/build/public/icons/bin.svg +0 -37
  70. package/build/public/icons/boolean.svg +0 -4
  71. package/build/public/icons/check.svg +0 -3
  72. package/build/public/icons/chevron-down.svg +0 -3
  73. package/build/public/icons/code.svg +0 -4
  74. package/build/public/icons/cross.svg +0 -11
  75. package/build/public/icons/data-tool.svg +0 -5
  76. package/build/public/icons/database.svg +0 -4
  77. package/build/public/icons/datetime.svg +0 -4
  78. package/build/public/icons/double-arrow-right.svg +0 -4
  79. package/build/public/icons/download.svg +0 -4
  80. package/build/public/icons/ellipsis.svg +0 -10
  81. package/build/public/icons/enum.svg +0 -6
  82. package/build/public/icons/expand.svg +0 -4
  83. package/build/public/icons/eye.svg +0 -20
  84. package/build/public/icons/filters.svg +0 -5
  85. package/build/public/icons/folder.svg +0 -6
  86. package/build/public/icons/hamburger.svg +0 -4
  87. package/build/public/icons/icon.svg +0 -199
  88. package/build/public/icons/logo.svg +0 -199
  89. package/build/public/icons/logotype.svg +0 -4
  90. package/build/public/icons/number.svg +0 -7
  91. package/build/public/icons/object.svg +0 -5
  92. package/build/public/icons/play.svg +0 -6
  93. package/build/public/icons/plus.svg +0 -4
  94. package/build/public/icons/refresh.svg +0 -4
  95. package/build/public/icons/search.svg +0 -7
  96. package/build/public/icons/settings.svg +0 -8
  97. package/build/public/icons/string.svg +0 -4
  98. package/build/public/icons/tick-indeterminate.svg +0 -3
  99. package/build/public/icons/tick.svg +0 -4
  100. package/build/public/illustrations/.DS_Store +0 -0
  101. package/build/public/illustrations/empty.svg +0 -1
  102. package/build/public/illustrations/read.svg +0 -1
  103. package/build/public/illustrations/searching.svg +0 -1
  104. package/build/public/images/.DS_Store +0 -0
  105. package/build/public/images/icon-1024.png +0 -0
  106. package/build/public/index.html +0 -49
  107. package/build/public/main.31f688a6254e294d9128.css +0 -118
  108. package/build/public/main.31f688a6254e294d9128.css.map +0 -1
  109. package/build/public/main.364c712f32662ff0e43d.css +0 -116
  110. package/build/public/main.364c712f32662ff0e43d.css.map +0 -1
  111. package/build/public/main.42ef3fe7e97347765c91.css +0 -118
  112. package/build/public/main.42ef3fe7e97347765c91.css.map +0 -1
  113. package/build/public/main.503446defafe7aeca2f3.css +0 -116
  114. package/build/public/main.503446defafe7aeca2f3.css.map +0 -1
  115. package/build/public/main.c50a3b5980fe26f78b65.css +0 -118
  116. package/build/public/main.c50a3b5980fe26f78b65.css.map +0 -1
  117. package/build/public/main.cda25e5813776c2af295.css +0 -116
  118. package/build/public/main.cda25e5813776c2af295.css.map +0 -1
  119. package/build/public/main.dbac3b290f78404ff579.css +0 -116
  120. package/build/public/main.dbac3b290f78404ff579.css.map +0 -1
  121. package/build/public/main.f8ce44e122e5e2b8f778.css +0 -118
  122. package/build/public/main.f8ce44e122e5e2b8f778.css.map +0 -1
  123. package/build/public/main.fc9ea7521a4aecce1a77.css +0 -118
  124. package/build/public/main.fc9ea7521a4aecce1a77.css.map +0 -1
  125. package/build/public/main.js +0 -403
  126. package/build/public/main.js.map +0 -1
  127. package/build/public/mainChunk.0a84f3ba4d2ab481e877.css +0 -116
  128. package/build/public/mainChunk.1b327d58afbddc917bce.css +0 -118
  129. package/build/public/mainChunk.2cdf583b2bd51aa67587.css +0 -118
  130. package/build/public/mainChunk.544af00f7e9ffcbe782c.css +0 -118
  131. package/build/public/mainChunk.56f96a13868b2b4a53be.css +0 -118
  132. package/build/public/mainChunk.5cee429bfbf06e7ecb39.css +0 -118
  133. package/build/public/mainChunk.a862474ed4cdb421ffa2.css +0 -118
  134. package/build/public/mainChunk.ada34153c4911b5ac22b.css +0 -118
  135. package/build/public/mainChunk.c16a8d01b2c49b2f2751.css +0 -118
  136. package/build/public/mainChunk.ca4a878d5478b9320be8.css +0 -116
  137. package/build/public/mainChunk.e3adc8758b4395546cef.css +0 -116
  138. package/build/public/mainChunk.f2c59fcbfc455d8b9de5.css +0 -118
  139. package/build/public/mainChunk.js +0 -396
  140. package/build/public/preview.html +0 -16
  141. package/build/public/previewBus.js +0 -2
  142. package/build/public/previewChunk.js +0 -2
  143. package/build/public/projects.html +0 -86
  144. package/build/public/server.html +0 -16
  145. package/build/public/serverBus.js +0 -2
  146. package/build/public/serverChunk.js +0 -2
  147. package/build/public/splash.html +0 -17
  148. package/build/public/studioBundle.828f34b1781061528841.css +0 -118
  149. package/build/public/studioBundle.bfe9138b2e0293fcb7da.css +0 -118
  150. package/build/public/studioBundle.c5b256eede880e502aac.css +0 -118
  151. package/build/public/studioBundle.e43df511c8e2e368900a.css +0 -118
  152. package/build/public/studioBundle.e69382554c2a2942ae32.css +0 -118
  153. package/build/public/studioBundle.ee21aa56a3999a2b380b.css +0 -118
  154. package/build/public/studioBundle.js +0 -396
  155. package/build/public/vercel.html +0 -16
  156. package/build/public/vercelChunk.js +0 -2
  157. package/build/xdg-open +0 -1066
  158. package/install/index.js +0 -5
  159. package/preinstall/index.js +0 -71
  160. package/prisma-client/README.md +0 -27
  161. package/prisma-client/generator-build/.DS_Store +0 -0
  162. package/prisma-client/generator-build/index.js +0 -79697
  163. package/prisma-client/index-browser.js +0 -3
  164. package/prisma-client/index.d.ts +0 -1
  165. package/prisma-client/index.js +0 -11
  166. package/prisma-client/package.json +0 -138
  167. package/prisma-client/runtime/index-browser.d.ts +0 -267
  168. package/prisma-client/runtime/index-browser.js +0 -2273
  169. package/prisma-client/runtime/index.d.ts +0 -1018
  170. package/prisma-client/runtime/index.js +0 -35028
  171. package/prisma-client/scripts/backup-index-browser.js +0 -3
  172. package/prisma-client/scripts/backup-index.d.ts +0 -1
  173. package/prisma-client/scripts/backup-index.js +0 -11
  174. package/prisma-client/scripts/colors.js +0 -180
  175. package/prisma-client/scripts/default-index-browser.js +0 -12
  176. package/prisma-client/scripts/default-index.d.ts +0 -47
  177. package/prisma-client/scripts/default-index.js +0 -12
  178. package/prisma-client/scripts/get-packed-client.js +0 -12
  179. package/prisma-client/scripts/mock-fs.js +0 -14
  180. package/prisma-client/scripts/postinstall.d.ts +0 -5
  181. package/prisma-client/scripts/postinstall.js +0 -398
  182. package/scripts/install-entry.js +0 -8
  183. package/scripts/preinstall-entry.js +0 -9
@@ -0,0 +1,813 @@
1
+ import { UnsafeConfigWriteError, assertLinkedProjectIdWritable, readLinkedProjectId, writeLinkedProjectId } from "../adapters/config.js";
2
+ import { CliError, authRequiredError, featureUnavailableError, usageError } from "../shell/errors.js";
3
+ import { canPrompt } from "../shell/runtime.js";
4
+ import { textPrompt } from "../shell/prompt.js";
5
+ import { requireComputeAuth } from "../lib/auth/guard.js";
6
+ import { parseEnvAssignments } from "../lib/app/env-vars.js";
7
+ import { DEFAULT_LOCAL_DEV_PORT, resolveLocalBuildType, runLocalApp } from "../lib/app/local-dev.js";
8
+ import { projectNotFoundError } from "../use-cases/project.js";
9
+ import { executePreviewBuild } from "../lib/app/preview-build.js";
10
+ import { PREVIEW_DEFAULT_REGION, createPreviewDeployInteraction } from "../lib/app/preview-interaction.js";
11
+ import { createPreviewDeployProgress, createPreviewPromoteProgress, createPreviewUpdateEnvProgress } from "../lib/app/preview-progress.js";
12
+ import { createPreviewAppProvider } from "../lib/app/preview-provider.js";
13
+ import { createSelectPromptPort } from "./select-prompt-port.js";
14
+ import path from "node:path";
15
+ import open from "open";
16
+ //#region src/controllers/app.ts
17
+ function isRealMode(context) {
18
+ return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
19
+ }
20
+ async function runAppBuild(context, entrypoint, requestedBuildType) {
21
+ const buildType = normalizeBuildType(requestedBuildType);
22
+ assertSupportedEntrypoint(buildType, entrypoint, "build");
23
+ const resolvedBuildType = await requireLocalBuildType(context, buildType, "build");
24
+ try {
25
+ const { artifact, buildType: actualBuildType } = await executePreviewBuild({
26
+ appPath: context.runtime.cwd,
27
+ entrypoint,
28
+ buildType: resolvedBuildType
29
+ });
30
+ return {
31
+ command: "app.build",
32
+ result: {
33
+ directory: artifact.directory,
34
+ entrypoint: artifact.entrypoint,
35
+ buildType: actualBuildType
36
+ },
37
+ warnings: [],
38
+ nextSteps: ["prisma app deploy"]
39
+ };
40
+ } catch (error) {
41
+ throw buildFailedError("Local app build failed", error);
42
+ }
43
+ }
44
+ async function runAppRun(context, entrypoint, requestedBuildType, requestedPort) {
45
+ if (context.flags.json) throw usageError("App run does not support --json", "This command streams the framework dev server directly and cannot return structured JSON.", "Rerun without --json to pass framework logs through directly.", ["prisma app run"], "app");
46
+ const buildType = normalizeBuildType(requestedBuildType);
47
+ assertSupportedEntrypoint(buildType, entrypoint, "run");
48
+ const port = parseLocalPort(requestedPort);
49
+ const resolvedBuildType = await requireLocalBuildType(context, buildType, "run");
50
+ let runResult;
51
+ try {
52
+ runResult = await runLocalApp({
53
+ appPath: context.runtime.cwd,
54
+ buildType: resolvedBuildType,
55
+ entrypoint,
56
+ port,
57
+ env: context.runtime.env
58
+ });
59
+ } catch (error) {
60
+ throw runFailedError("Local app run failed", error);
61
+ }
62
+ if (runResult.signal === "SIGINT" || runResult.signal === "SIGTERM") process.exitCode = runResult.signal === "SIGINT" ? 130 : 143;
63
+ else if (runResult.exitCode !== 0) throw runFailedError("Local app run failed", `The ${formatFrameworkName(runResult.framework)} process exited with code ${runResult.exitCode}.`, runResult.exitCode);
64
+ return {
65
+ command: "app.run",
66
+ result: {
67
+ framework: runResult.framework,
68
+ entrypoint: runResult.entrypoint,
69
+ port: runResult.port,
70
+ command: runResult.command
71
+ },
72
+ warnings: [],
73
+ nextSteps: []
74
+ };
75
+ }
76
+ async function runAppDeploy(context, appName, options) {
77
+ ensurePreviewAppMode(context);
78
+ const buildType = normalizeBuildType(options?.buildType);
79
+ assertSupportedEntrypoint(buildType, options?.entrypoint, "deploy");
80
+ const portMapping = parseDeployPortMapping(options?.httpPort);
81
+ const envVars = toOptionalEnvVars(parseEnvAssignments(options?.envAssignments, { commandName: "deploy" }));
82
+ const provider = await requirePreviewAppProvider(context);
83
+ const projectId = await resolveProjectIdForDeploy(context, provider);
84
+ const selectedApp = await resolveDeploySelection(context, projectId, await listApps(context, provider, projectId), appName);
85
+ const deployResult = await provider.deployApp({
86
+ cwd: context.runtime.cwd,
87
+ projectId,
88
+ appId: selectedApp.appId,
89
+ appName: selectedApp.appName,
90
+ region: selectedApp.region,
91
+ entrypoint: options?.entrypoint,
92
+ buildType,
93
+ portMapping,
94
+ envVars,
95
+ interaction: selectedApp.useInteractiveSelection ? createPreviewDeployInteraction(context) : void 0,
96
+ progress: createPreviewDeployProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
97
+ }).catch((error) => {
98
+ throw deployFailedError("App deploy failed", error, ["prisma app list-deploys"]);
99
+ });
100
+ await context.stateStore.setSelectedApp(projectId, {
101
+ id: deployResult.app.id,
102
+ name: deployResult.app.name
103
+ });
104
+ await context.stateStore.setKnownLiveDeployment(projectId, deployResult.app.id, deployResult.deployment.id);
105
+ return {
106
+ command: "app.deploy",
107
+ result: {
108
+ projectId: deployResult.projectId,
109
+ app: {
110
+ id: deployResult.app.id,
111
+ name: deployResult.app.name
112
+ },
113
+ deployment: deployResult.deployment
114
+ },
115
+ warnings: [],
116
+ nextSteps: ["prisma app list-deploys", `prisma app show-deploy ${deployResult.deployment.id}`]
117
+ };
118
+ }
119
+ async function runAppUpdateEnv(context, appName, envAssignments) {
120
+ ensurePreviewAppMode(context);
121
+ const envVars = parseEnvAssignments(envAssignments, {
122
+ commandName: "update-env",
123
+ requireAtLeastOne: true
124
+ });
125
+ const projectId = await requireLinkedProjectId(context);
126
+ const provider = await requirePreviewAppProvider(context);
127
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
128
+ if (!selectedApp) throw noDeploymentsError("No deployments available to update environment variables", "The linked project does not have any deployed app yet.");
129
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
130
+ throw deployFailedError("Failed to inspect app deployments", error, ["prisma app list-deploys"]);
131
+ });
132
+ if (deploymentsResult.deployments.length === 0) throw noDeploymentsError("No deployments available to update environment variables", `The selected app "${deploymentsResult.app.name}" does not have any deployments yet.`);
133
+ const updateResult = await provider.updateAppEnv({
134
+ appId: deploymentsResult.app.id,
135
+ envVars,
136
+ progress: createPreviewUpdateEnvProgress(context.output.stderr, !context.flags.json && !context.flags.quiet),
137
+ promoteProgress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
138
+ }).catch((error) => {
139
+ throw deployFailedError("Failed to update app environment variables", error, ["prisma app list-env"]);
140
+ });
141
+ await context.stateStore.setSelectedApp(projectId, {
142
+ id: updateResult.app.id,
143
+ name: updateResult.app.name
144
+ });
145
+ await context.stateStore.setKnownLiveDeployment(projectId, updateResult.app.id, updateResult.deployment.id);
146
+ return {
147
+ command: "app.update-env",
148
+ result: {
149
+ projectId: updateResult.projectId,
150
+ app: {
151
+ id: updateResult.app.id,
152
+ name: updateResult.app.name
153
+ },
154
+ deployment: updateResult.deployment,
155
+ variables: updateResult.variables
156
+ },
157
+ warnings: [],
158
+ nextSteps: ["prisma app list-env", `prisma app show-deploy ${updateResult.deployment.id}`]
159
+ };
160
+ }
161
+ async function runAppListEnv(context, appName) {
162
+ ensurePreviewAppMode(context);
163
+ const projectId = await requireLinkedProjectId(context);
164
+ const provider = await requirePreviewAppProvider(context);
165
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
166
+ if (!selectedApp) return {
167
+ command: "app.list-env",
168
+ result: {
169
+ projectId,
170
+ app: null,
171
+ deployment: null,
172
+ variables: []
173
+ },
174
+ warnings: [],
175
+ nextSteps: ["prisma app deploy"]
176
+ };
177
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
178
+ throw deployFailedError("Failed to inspect app deployments", error, ["prisma app list-deploys"]);
179
+ });
180
+ const knownLiveDeploymentId = await context.stateStore.readKnownLiveDeployment(projectId, deploymentsResult.app.id);
181
+ const missingKnownLiveDeploymentId = knownLiveDeploymentId && !deploymentsResult.deployments.some((candidate) => candidate.id === knownLiveDeploymentId) ? knownLiveDeploymentId : null;
182
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
183
+ const deployments = applyLiveDeploymentHint(deploymentsResult.deployments, currentLiveDeploymentId).slice().sort((left, right) => right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id));
184
+ const deployment = currentLiveDeploymentId ? deployments.find((candidate) => candidate.id === currentLiveDeploymentId) ?? null : null;
185
+ await context.stateStore.setSelectedApp(projectId, {
186
+ id: deploymentsResult.app.id,
187
+ name: deploymentsResult.app.name
188
+ });
189
+ if (missingKnownLiveDeploymentId) {
190
+ const envResult = await provider.listAppEnvNames({
191
+ appId: deploymentsResult.app.id,
192
+ deploymentId: missingKnownLiveDeploymentId
193
+ }).catch((error) => {
194
+ throw deployFailedError("Failed to inspect app environment variables", error, ["prisma app list-deploys"]);
195
+ });
196
+ return {
197
+ command: "app.list-env",
198
+ result: {
199
+ projectId,
200
+ app: {
201
+ id: envResult.app.id,
202
+ name: envResult.app.name
203
+ },
204
+ deployment: envResult.deployment,
205
+ variables: envResult.variables
206
+ },
207
+ warnings: [],
208
+ nextSteps: [`prisma app show-deploy ${envResult.deployment.id}`]
209
+ };
210
+ }
211
+ if (!deployment) return {
212
+ command: "app.list-env",
213
+ result: {
214
+ projectId,
215
+ app: {
216
+ id: deploymentsResult.app.id,
217
+ name: deploymentsResult.app.name
218
+ },
219
+ deployment: null,
220
+ variables: []
221
+ },
222
+ warnings: [],
223
+ nextSteps: ["prisma app deploy"]
224
+ };
225
+ const envResult = await provider.listAppEnvNames({
226
+ appId: deploymentsResult.app.id,
227
+ deploymentId: deployment.id
228
+ }).catch((error) => {
229
+ throw deployFailedError("Failed to inspect app environment variables", error, ["prisma app list-deploys"]);
230
+ });
231
+ return {
232
+ command: "app.list-env",
233
+ result: {
234
+ projectId,
235
+ app: {
236
+ id: envResult.app.id,
237
+ name: envResult.app.name
238
+ },
239
+ deployment: {
240
+ ...deployment,
241
+ live: deployment.live ?? envResult.deployment.live
242
+ },
243
+ variables: envResult.variables
244
+ },
245
+ warnings: [],
246
+ nextSteps: deployment.id ? [`prisma app show-deploy ${deployment.id}`] : ["prisma app deploy"]
247
+ };
248
+ }
249
+ async function runAppListDeploys(context, appName) {
250
+ ensurePreviewAppMode(context);
251
+ const projectId = await requireLinkedProjectId(context);
252
+ const provider = await requirePreviewAppProvider(context);
253
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
254
+ if (!selectedApp) return {
255
+ command: "app.list-deploys",
256
+ result: {
257
+ projectId,
258
+ app: null,
259
+ deployments: []
260
+ },
261
+ warnings: [],
262
+ nextSteps: ["prisma app deploy"]
263
+ };
264
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
265
+ throw deployFailedError("Failed to list app deployments", error, ["prisma app deploy"]);
266
+ });
267
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
268
+ const deployments = applyLiveDeploymentHint(deploymentsResult.deployments, currentLiveDeploymentId).slice().sort((left, right) => right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id));
269
+ await context.stateStore.setSelectedApp(projectId, {
270
+ id: deploymentsResult.app.id,
271
+ name: deploymentsResult.app.name
272
+ });
273
+ return {
274
+ command: "app.list-deploys",
275
+ result: {
276
+ projectId,
277
+ app: {
278
+ id: deploymentsResult.app.id,
279
+ name: deploymentsResult.app.name
280
+ },
281
+ deployments
282
+ },
283
+ warnings: [],
284
+ nextSteps: deployments.length > 0 ? [`prisma app show-deploy ${deployments[0]?.id}`] : ["prisma app deploy"]
285
+ };
286
+ }
287
+ async function runAppShow(context, appName) {
288
+ ensurePreviewAppMode(context);
289
+ const projectId = await requireLinkedProjectId(context);
290
+ const provider = await requirePreviewAppProvider(context);
291
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
292
+ if (!selectedApp) return {
293
+ command: "app.show",
294
+ result: {
295
+ projectId,
296
+ app: null,
297
+ liveDeployment: null,
298
+ liveUrl: null,
299
+ recentDeployments: []
300
+ },
301
+ warnings: [],
302
+ nextSteps: ["prisma app deploy"]
303
+ };
304
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
305
+ throw deployFailedError("Failed to inspect app", error, ["prisma app list-deploys"]);
306
+ });
307
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
308
+ const deployments = applyLiveDeploymentHint(deploymentsResult.deployments, currentLiveDeploymentId).slice().sort((left, right) => right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id));
309
+ const liveDeployment = currentLiveDeploymentId ? deployments.find((deployment) => deployment.id === currentLiveDeploymentId) ?? null : null;
310
+ await context.stateStore.setSelectedApp(projectId, {
311
+ id: deploymentsResult.app.id,
312
+ name: deploymentsResult.app.name
313
+ });
314
+ return {
315
+ command: "app.show",
316
+ result: {
317
+ projectId,
318
+ app: {
319
+ id: deploymentsResult.app.id,
320
+ name: deploymentsResult.app.name
321
+ },
322
+ liveDeployment,
323
+ liveUrl: deploymentsResult.app.liveUrl,
324
+ recentDeployments: deployments.slice(0, 5)
325
+ },
326
+ warnings: [],
327
+ nextSteps: buildAppShowNextSteps(deploymentsResult.app.liveUrl, liveDeployment, deployments)
328
+ };
329
+ }
330
+ async function runAppShowDeploy(context, deploymentId) {
331
+ ensurePreviewAppMode(context);
332
+ const deployment = await (await requirePreviewAppProvider(context)).showDeployment(deploymentId).catch((error) => {
333
+ throw deployFailedError("Failed to show deployment", error, ["prisma app list-deploys"]);
334
+ });
335
+ if (!deployment) throw new CliError({
336
+ code: "DEPLOYMENT_NOT_FOUND",
337
+ domain: "app",
338
+ summary: `Deployment "${deploymentId}" not found`,
339
+ why: "The requested deployment does not exist or is no longer available.",
340
+ fix: "Run prisma app list-deploys to choose an available deployment id.",
341
+ exitCode: 1,
342
+ nextSteps: ["prisma app list-deploys"]
343
+ });
344
+ const linkedProjectId = deployment?.app ? await readLinkedProjectId(context.runtime.cwd) : null;
345
+ const knownLiveDeploymentId = deployment?.app && linkedProjectId ? await context.stateStore.readKnownLiveDeployment(linkedProjectId, deployment.app.id) : null;
346
+ const providerLiveDeploymentId = deployment.app?.liveDeploymentId ?? null;
347
+ return {
348
+ command: "app.show-deploy",
349
+ result: {
350
+ app: deployment.app ? {
351
+ id: deployment.app.id,
352
+ name: deployment.app.name
353
+ } : null,
354
+ deployment: {
355
+ ...deployment.deployment,
356
+ live: providerLiveDeploymentId ? deployment.deployment.id === providerLiveDeploymentId : knownLiveDeploymentId ? deployment.deployment.id === knownLiveDeploymentId : deployment.deployment.live
357
+ }
358
+ },
359
+ warnings: [],
360
+ nextSteps: []
361
+ };
362
+ }
363
+ async function runAppOpen(context, appName) {
364
+ ensurePreviewAppMode(context);
365
+ const projectId = await requireLinkedProjectId(context);
366
+ const provider = await requirePreviewAppProvider(context);
367
+ const selectedApp = await resolveExistingAppSelection(context, projectId, await listApps(context, provider, projectId), appName);
368
+ if (!selectedApp) throw noDeploymentsError("No deployments available to open", "The linked project does not have any deployed app yet.");
369
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
370
+ throw deployFailedError("Failed to resolve app URL", error, ["prisma app show"]);
371
+ });
372
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
373
+ const deployments = applyLiveDeploymentHint(deploymentsResult.deployments, currentLiveDeploymentId).slice().sort((left, right) => right.createdAt.localeCompare(left.createdAt) || right.id.localeCompare(left.id));
374
+ const liveDeployment = currentLiveDeploymentId ? deployments.find((deployment) => deployment.id === currentLiveDeploymentId) ?? null : null;
375
+ await context.stateStore.setSelectedApp(projectId, {
376
+ id: deploymentsResult.app.id,
377
+ name: deploymentsResult.app.name
378
+ });
379
+ if (!liveDeployment) throw noDeploymentsError("No deployments available to open", `The selected app "${deploymentsResult.app.name}" does not have any deployments yet.`);
380
+ if (!deploymentsResult.app.liveUrl) throw featureUnavailableError("Live URL is not available for the selected app", "Deployments exist, but the provider does not expose a stable live service URL for this app yet.", "Run prisma app show to inspect the current deployment state and try again after the app reports a live URL.", ["prisma app show"], "app");
381
+ const shouldOpen = canPrompt(context);
382
+ if (shouldOpen) await open(deploymentsResult.app.liveUrl);
383
+ return {
384
+ command: "app.open",
385
+ result: {
386
+ projectId,
387
+ app: {
388
+ id: deploymentsResult.app.id,
389
+ name: deploymentsResult.app.name
390
+ },
391
+ url: deploymentsResult.app.liveUrl,
392
+ opened: shouldOpen
393
+ },
394
+ warnings: [],
395
+ nextSteps: ["prisma app show", `prisma app show-deploy ${liveDeployment.id}`]
396
+ };
397
+ }
398
+ async function runAppLogs(context, _appName, _deploymentId) {
399
+ ensurePreviewAppMode(context);
400
+ throw blockedPreviewAppCommandError("App logs are not available in this preview", "The current preview cannot stream app logs yet.");
401
+ }
402
+ async function runAppPromote(context, deploymentId, appName) {
403
+ ensurePreviewAppMode(context);
404
+ const projectId = await requireLinkedProjectId(context);
405
+ const provider = await requirePreviewAppProvider(context);
406
+ const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "promote");
407
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
408
+ throw deployFailedError("Failed to list app deployments", error, ["prisma app list-deploys"]);
409
+ });
410
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
411
+ const targetDeployment = requireDeploymentForApp(deploymentsResult.deployments, deploymentId, selectedApp.name);
412
+ const targetAlreadyLive = currentLiveDeploymentId === targetDeployment.id;
413
+ await context.stateStore.setSelectedApp(projectId, {
414
+ id: deploymentsResult.app.id,
415
+ name: deploymentsResult.app.name
416
+ });
417
+ if (!targetAlreadyLive) await provider.promoteDeployment({
418
+ appId: selectedApp.id,
419
+ deploymentId: targetDeployment.id,
420
+ progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
421
+ }).catch((error) => {
422
+ throw deployFailedError("Failed to promote deployment", error, ["prisma app list-deploys"]);
423
+ });
424
+ await context.stateStore.setKnownLiveDeployment(projectId, deploymentsResult.app.id, targetDeployment.id);
425
+ return {
426
+ command: "app.promote",
427
+ result: {
428
+ projectId,
429
+ app: {
430
+ id: deploymentsResult.app.id,
431
+ name: deploymentsResult.app.name
432
+ },
433
+ deployment: {
434
+ ...targetDeployment,
435
+ status: "running",
436
+ live: true
437
+ }
438
+ },
439
+ warnings: targetAlreadyLive ? ["The selected deployment is already live for this app."] : [],
440
+ nextSteps: ["prisma app list-deploys", `prisma app show-deploy ${targetDeployment.id}`]
441
+ };
442
+ }
443
+ async function runAppRollback(context, appName, deploymentId) {
444
+ ensurePreviewAppMode(context);
445
+ const projectId = await requireLinkedProjectId(context);
446
+ const provider = await requirePreviewAppProvider(context);
447
+ const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "rollback");
448
+ const deploymentsResult = await provider.listDeployments(selectedApp.id).catch((error) => {
449
+ throw deployFailedError("Failed to list app deployments", error, ["prisma app list-deploys"]);
450
+ });
451
+ const currentLiveDeploymentId = await resolveCurrentLiveDeploymentId(context, projectId, deploymentsResult.app, deploymentsResult.deployments);
452
+ const currentLiveDeployment = currentLiveDeploymentId ? deploymentsResult.deployments.find((deployment) => deployment.id === currentLiveDeploymentId) ?? null : null;
453
+ const targetDeployment = deploymentId ? requireDeploymentForApp(deploymentsResult.deployments, deploymentId, selectedApp.name) : resolveRollbackTarget(deploymentsResult.deployments, currentLiveDeploymentId);
454
+ const targetAlreadyLive = currentLiveDeploymentId === targetDeployment.id;
455
+ await context.stateStore.setSelectedApp(projectId, {
456
+ id: deploymentsResult.app.id,
457
+ name: deploymentsResult.app.name
458
+ });
459
+ if (!targetAlreadyLive) await provider.promoteDeployment({
460
+ appId: selectedApp.id,
461
+ deploymentId: targetDeployment.id,
462
+ progress: createPreviewPromoteProgress(context.output.stderr, !context.flags.json && !context.flags.quiet)
463
+ }).catch((error) => {
464
+ throw deployFailedError("Failed to roll back deployment", error, ["prisma app list-deploys"]);
465
+ });
466
+ await context.stateStore.setKnownLiveDeployment(projectId, deploymentsResult.app.id, targetDeployment.id);
467
+ return {
468
+ command: "app.rollback",
469
+ result: {
470
+ projectId,
471
+ app: {
472
+ id: deploymentsResult.app.id,
473
+ name: deploymentsResult.app.name
474
+ },
475
+ deployment: {
476
+ ...targetDeployment,
477
+ status: "running",
478
+ live: true
479
+ },
480
+ previousLiveDeploymentId: currentLiveDeployment?.id ?? null
481
+ },
482
+ warnings: targetAlreadyLive ? ["The selected deployment is already live for this app."] : [],
483
+ nextSteps: ["prisma app list-deploys", `prisma app show-deploy ${targetDeployment.id}`]
484
+ };
485
+ }
486
+ async function runAppRemove(context, appName) {
487
+ ensurePreviewAppMode(context);
488
+ const projectId = await requireLinkedProjectId(context);
489
+ const provider = await requirePreviewAppProvider(context);
490
+ const selectedApp = await requireReleaseAppSelection(context, projectId, await listApps(context, provider, projectId), appName, "remove");
491
+ await confirmAppRemoval(context, selectedApp);
492
+ const removedApp = await provider.removeApp(selectedApp.id).catch((error) => {
493
+ throw removeFailedError("Failed to remove app", error, ["prisma app show", "prisma app list-deploys"]);
494
+ });
495
+ const warnings = await cleanupRemovedAppState(context, projectId, removedApp.id);
496
+ return {
497
+ command: "app.remove",
498
+ result: {
499
+ projectId,
500
+ app: {
501
+ id: removedApp.id,
502
+ name: removedApp.name
503
+ },
504
+ removed: true
505
+ },
506
+ warnings,
507
+ nextSteps: ["prisma app deploy", "prisma app list-deploys"]
508
+ };
509
+ }
510
+ async function resolveDeploySelection(context, projectId, apps, explicitAppName) {
511
+ if (explicitAppName) {
512
+ const matched = findAppByName(apps, explicitAppName);
513
+ if (matched) return {
514
+ appId: matched.id,
515
+ useInteractiveSelection: false
516
+ };
517
+ return {
518
+ appName: explicitAppName,
519
+ region: PREVIEW_DEFAULT_REGION,
520
+ useInteractiveSelection: false
521
+ };
522
+ }
523
+ const savedSelection = await context.stateStore.readSelectedApp(projectId);
524
+ if (savedSelection) {
525
+ const matched = apps.find((app) => app.id === savedSelection.id) ?? findAppByName(apps, savedSelection.name);
526
+ if (matched) return {
527
+ appId: matched.id,
528
+ useInteractiveSelection: false
529
+ };
530
+ if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the linked project.", "Pass --app <name>, or rerun prisma app deploy in a TTY to choose or create an app again.", ["prisma app deploy"], "app");
531
+ }
532
+ if (!canPrompt(context)) throw usageError("App deploy requires an app selection in non-interactive mode", "This command cannot choose or create an app in the current mode.", "Pass --app <name>, or rerun prisma app deploy in a TTY to choose or create an app.", ["prisma app deploy --app hello-world"], "app");
533
+ return { useInteractiveSelection: true };
534
+ }
535
+ async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
536
+ if (explicitAppName) {
537
+ const matched = findAppByName(apps, explicitAppName);
538
+ if (!matched) throw usageError("Selected app does not exist in the linked project", `The app "${explicitAppName}" could not be found in linked project "${projectId}".`, "Pass the name of an existing app, or rerun prisma app list-deploys in a TTY to choose one.", ["prisma app list-deploys"], "app");
539
+ return matched;
540
+ }
541
+ const savedSelection = await context.stateStore.readSelectedApp(projectId);
542
+ if (savedSelection) {
543
+ const matched = apps.find((app) => app.id === savedSelection.id) ?? findAppByName(apps, savedSelection.name);
544
+ if (matched) return matched;
545
+ if (!canPrompt(context)) throw usageError("Saved app selection is no longer available", "The locally selected app could not be found in the linked project.", "Pass --app <name>, or rerun prisma app list-deploys in a TTY to choose an available app.", ["prisma app list-deploys"], "app");
546
+ }
547
+ if (apps.length === 0) return null;
548
+ if (!canPrompt(context)) throw usageError("App selection required in non-interactive mode", "This command cannot choose an app in the current mode.", "Pass --app <name>, or rerun prisma app list-deploys in a TTY to choose an app.", ["prisma app list-deploys"], "app");
549
+ const selectedId = await createSelectPromptPort(context).select({
550
+ message: "Select an app",
551
+ choices: sortApps(apps).map((app) => ({
552
+ label: app.name,
553
+ value: app.id
554
+ }))
555
+ });
556
+ return apps.find((app) => app.id === selectedId) ?? null;
557
+ }
558
+ async function requireReleaseAppSelection(context, projectId, apps, explicitAppName, commandName) {
559
+ const selectedApp = await resolveExistingAppSelection(context, projectId, apps, explicitAppName);
560
+ if (selectedApp) return selectedApp;
561
+ throw usageError(`App ${commandName} requires an existing app`, "The linked project does not have an app that can be selected for this command.", `Deploy an app first, or rerun prisma app ${commandName} with --app <name> after an app exists.`, ["prisma app deploy", "prisma app list-deploys"], "app");
562
+ }
563
+ async function confirmAppRemoval(context, app) {
564
+ if (context.flags.yes) return;
565
+ if (!canPrompt(context)) throw new CliError({
566
+ code: "CONFIRMATION_REQUIRED",
567
+ domain: "app",
568
+ summary: "App remove requires confirmation in the current mode",
569
+ why: "This command is destructive and cannot prompt for confirmation in the current mode.",
570
+ fix: `Pass --yes to confirm removal of "${app.name}", or rerun prisma app remove in an interactive TTY.`,
571
+ exitCode: 1,
572
+ nextSteps: [`prisma app remove --app ${app.name} --yes`]
573
+ });
574
+ await textPrompt({
575
+ input: context.runtime.stdin,
576
+ output: context.output.stderr,
577
+ message: `Type ${app.name} to confirm app removal`,
578
+ placeholder: app.name,
579
+ validate: (value) => value === app.name ? void 0 : `Type "${app.name}" to confirm removal.`
580
+ });
581
+ }
582
+ async function cleanupRemovedAppState(context, projectId, appId) {
583
+ const warnings = [];
584
+ try {
585
+ await context.stateStore.clearSelectedApp(projectId, appId);
586
+ } catch (error) {
587
+ warnings.push(localStateCleanupWarning("selected app", error));
588
+ }
589
+ try {
590
+ await context.stateStore.clearKnownLiveDeployment(projectId, appId);
591
+ } catch (error) {
592
+ warnings.push(localStateCleanupWarning("known live deployment", error));
593
+ }
594
+ return warnings;
595
+ }
596
+ function requireDeploymentForApp(deployments, deploymentId, appName) {
597
+ const deployment = deployments.find((candidate) => candidate.id === deploymentId);
598
+ if (deployment) return deployment;
599
+ throw new CliError({
600
+ code: "DEPLOYMENT_NOT_FOUND",
601
+ domain: "app",
602
+ summary: `Deployment "${deploymentId}" not found for app "${appName}"`,
603
+ why: "The requested deployment does not belong to the resolved app or is no longer available.",
604
+ fix: "Run prisma app list-deploys to choose an available deployment id for this app.",
605
+ exitCode: 1,
606
+ nextSteps: ["prisma app list-deploys"]
607
+ });
608
+ }
609
+ async function resolveCurrentLiveDeploymentId(context, projectId, app, deployments) {
610
+ if (app.liveDeploymentId && deployments.some((deployment) => deployment.id === app.liveDeploymentId)) return app.liveDeploymentId;
611
+ const providerLiveDeployment = deployments.find((deployment) => deployment.live === true);
612
+ if (providerLiveDeployment) return providerLiveDeployment.id;
613
+ const knownLiveDeploymentId = await context.stateStore.readKnownLiveDeployment(projectId, app.id);
614
+ if (knownLiveDeploymentId && deployments.some((deployment) => deployment.id === knownLiveDeploymentId)) return knownLiveDeploymentId;
615
+ return deployments[0]?.id ?? null;
616
+ }
617
+ function buildAppShowNextSteps(liveUrl, liveDeployment, deployments) {
618
+ const nextSteps = [];
619
+ if (liveUrl) nextSteps.push("prisma app open");
620
+ if (liveDeployment) nextSteps.push(`prisma app show-deploy ${liveDeployment.id}`);
621
+ else if (deployments[0]) nextSteps.push(`prisma app show-deploy ${deployments[0].id}`);
622
+ else nextSteps.push("prisma app deploy");
623
+ return nextSteps;
624
+ }
625
+ function applyLiveDeploymentHint(deployments, currentLiveDeploymentId) {
626
+ if (!currentLiveDeploymentId) return deployments.map((deployment) => ({
627
+ ...deployment,
628
+ live: deployment.live ?? null
629
+ }));
630
+ return deployments.map((deployment) => ({
631
+ ...deployment,
632
+ live: deployment.id === currentLiveDeploymentId
633
+ }));
634
+ }
635
+ function resolveRollbackTarget(deployments, currentLiveDeploymentId) {
636
+ const previousDeployment = deployments.find((deployment) => deployment.id !== currentLiveDeploymentId);
637
+ if (previousDeployment) return previousDeployment;
638
+ throw new CliError({
639
+ code: "NO_PREVIOUS_DEPLOYMENT",
640
+ domain: "app",
641
+ summary: "No previous deployment available for rollback",
642
+ why: "The selected app does not have an earlier deployment to switch back to.",
643
+ fix: "Deploy a second version first, or rerun prisma app rollback --to <deployment-id> for a specific earlier deployment.",
644
+ exitCode: 1,
645
+ nextSteps: ["prisma app deploy", "prisma app list-deploys"]
646
+ });
647
+ }
648
+ async function listApps(context, provider, projectId) {
649
+ return provider.listApps(projectId).then(sortApps).catch((error) => {
650
+ if (isMissingProjectError(error)) throw projectNotFoundError(`The linked project "${projectId}" does not exist in the authenticated workspace or is no longer accessible.`, "Run prisma project show to inspect the current link, then relink the repo or rerun prisma app deploy to bootstrap a new project.", [
651
+ "prisma project show",
652
+ "prisma project link",
653
+ "prisma app deploy"
654
+ ]);
655
+ throw deployFailedError("Failed to list apps", error, ["prisma project show"]);
656
+ });
657
+ }
658
+ async function requirePreviewAppProvider(context) {
659
+ const client = await requireComputeAuth(context.runtime.env);
660
+ if (!client) throw authRequiredError(["prisma auth login"]);
661
+ return createPreviewAppProvider(client);
662
+ }
663
+ async function requireLinkedProjectId(context) {
664
+ const projectId = await readLinkedProjectId(context.runtime.cwd);
665
+ if (!projectId) throw new CliError({
666
+ code: "PROJECT_NOT_LINKED",
667
+ domain: "project",
668
+ summary: "Project link required",
669
+ why: "This command needs a linked project for the current repo.",
670
+ fix: "Run prisma project link before deploying or inspecting app deployments.",
671
+ exitCode: 1,
672
+ nextSteps: ["prisma project link"]
673
+ });
674
+ return projectId;
675
+ }
676
+ async function resolveProjectIdForDeploy(context, provider) {
677
+ const linkedProjectId = await readLinkedProjectId(context.runtime.cwd);
678
+ if (linkedProjectId) return linkedProjectId;
679
+ await assertProjectLinkWritableForDeploy(context);
680
+ const projectName = path.basename(context.runtime.cwd);
681
+ const project = await provider.createProject({ name: projectName }).catch((error) => {
682
+ throw deployFailedError("Failed to create project for first deploy", error, ["prisma app deploy"]);
683
+ });
684
+ try {
685
+ await writeLinkedProjectId(context.runtime.cwd, project.id);
686
+ } catch (error) {
687
+ const cause = error instanceof Error ? error.message : String(error);
688
+ throw deployFailedError("Failed to link created project", `Project "${project.name}" (${project.id}) was created remotely but could not be linked locally: ${cause}`, ["prisma project show", "prisma app deploy"]);
689
+ }
690
+ return project.id;
691
+ }
692
+ async function assertProjectLinkWritableForDeploy(context) {
693
+ try {
694
+ await assertLinkedProjectIdWritable(context.runtime.cwd);
695
+ } catch (error) {
696
+ if (error instanceof UnsafeConfigWriteError) throw usageError("Project bootstrap requires a writable Prisma config", error.message, "Update prisma.config.ts to use a recognizable project field, or remove it and rerun prisma app deploy.", ["prisma app deploy --app hello-world"], "app");
697
+ throw error;
698
+ }
699
+ }
700
+ function normalizeBuildType(requestedBuildType) {
701
+ if (!requestedBuildType) return "auto";
702
+ if (requestedBuildType === "auto" || requestedBuildType === "bun" || requestedBuildType === "nextjs") return requestedBuildType;
703
+ throw usageError(`Unsupported build type "${requestedBuildType}"`, "Only auto, bun, and nextjs are supported in the current preview.", "Pass --build-type auto, --build-type bun, or --build-type nextjs.", ["prisma app build --build-type nextjs", "prisma app build --build-type bun --entry server.ts"], "app");
704
+ }
705
+ function assertSupportedEntrypoint(buildType, entrypoint, commandName) {
706
+ if (buildType === "nextjs" && entrypoint) throw usageError(`App ${commandName} does not accept --entry with --build-type nextjs`, "Next.js apps do not use an entrypoint flag in the current preview.", `Remove --entry, or rerun prisma app ${commandName} with --build-type bun when you want to target a Bun entrypoint directly.`, [`prisma app ${commandName} --build-type nextjs`, `prisma app ${commandName} --build-type bun --entry server.ts`], "app");
707
+ }
708
+ async function requireLocalBuildType(context, buildType, commandName) {
709
+ const resolvedBuildType = await resolveLocalBuildType(context.runtime.cwd, buildType);
710
+ if (resolvedBuildType) return resolvedBuildType;
711
+ throw usageError(`App ${commandName} requires an explicit framework when detection is ambiguous`, "This preview only auto-detects clear Next.js or Bun project shapes.", "Pass --build-type nextjs for a Next.js app, or pass --build-type bun with --entry <path> for a Bun app.", [`prisma app ${commandName} --build-type nextjs`, `prisma app ${commandName} --build-type bun --entry server.ts`], "app");
712
+ }
713
+ function parseLocalPort(requestedPort) {
714
+ if (!requestedPort) return DEFAULT_LOCAL_DEV_PORT;
715
+ const port = Number.parseInt(requestedPort, 10);
716
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) throw usageError(`Invalid port "${requestedPort}"`, "Port must be an integer between 1 and 65535.", "Pass --port <number> with a valid local port value.", ["prisma app run --port 3000"], "app");
717
+ return port;
718
+ }
719
+ function parseDeployPortMapping(requestedPort) {
720
+ if (!requestedPort) return;
721
+ const port = Number.parseInt(requestedPort, 10);
722
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) throw usageError(`Invalid HTTP port "${requestedPort}"`, "HTTP port must be an integer between 1 and 65535.", "Pass --http-port <number> with a valid port value.", ["prisma app deploy --http-port 3000"], "app");
723
+ return { http: port };
724
+ }
725
+ function ensurePreviewAppMode(context) {
726
+ if (isRealMode(context)) return;
727
+ throw featureUnavailableError("App commands are not available in fixture mode", "Preview app commands require live app deployment integration.", "Rerun without fixture mode enabled to use preview app deployment workflows.", ["prisma auth login", "prisma project link"], "app");
728
+ }
729
+ function blockedPreviewAppCommandError(summary, why) {
730
+ return featureUnavailableError(summary, why, "Use prisma app show, prisma app open, prisma app deploy, or prisma app list-deploys in the current preview.", ["prisma app show", "prisma app list-deploys"], "app");
731
+ }
732
+ function deployFailedError(summary, error, nextSteps) {
733
+ return new CliError({
734
+ code: "DEPLOY_FAILED",
735
+ domain: "app",
736
+ summary,
737
+ why: error instanceof Error ? error.message : String(error),
738
+ fix: "Retry the command, or rerun with --trace for more detailed diagnostics.",
739
+ debug: formatDebugDetails(error),
740
+ exitCode: 1,
741
+ nextSteps
742
+ });
743
+ }
744
+ function noDeploymentsError(summary, why) {
745
+ return new CliError({
746
+ code: "NO_DEPLOYMENTS",
747
+ domain: "app",
748
+ summary,
749
+ why,
750
+ fix: "Run prisma app deploy first, or use prisma app show to inspect the current app state.",
751
+ exitCode: 1,
752
+ nextSteps: ["prisma app deploy", "prisma app show"]
753
+ });
754
+ }
755
+ function buildFailedError(summary, error) {
756
+ return new CliError({
757
+ code: "BUILD_FAILED",
758
+ domain: "app",
759
+ summary,
760
+ why: error instanceof Error ? error.message : String(error),
761
+ fix: "Inspect the framework output, fix the build issue, and rerun prisma app build.",
762
+ debug: formatDebugDetails(error),
763
+ exitCode: 1,
764
+ nextSteps: ["prisma app build", "prisma app deploy"]
765
+ });
766
+ }
767
+ function runFailedError(summary, error, exitCode = 1) {
768
+ return new CliError({
769
+ code: "RUN_FAILED",
770
+ domain: "app",
771
+ summary,
772
+ why: error instanceof Error ? error.message : String(error),
773
+ fix: "Inspect the framework output above, fix the issue, and rerun prisma app run.",
774
+ exitCode,
775
+ nextSteps: ["prisma app run"]
776
+ });
777
+ }
778
+ function formatFrameworkName(framework) {
779
+ return framework === "nextjs" ? "Next.js" : "Bun";
780
+ }
781
+ function removeFailedError(summary, error, nextSteps) {
782
+ return new CliError({
783
+ code: "REMOVE_FAILED",
784
+ domain: "app",
785
+ summary,
786
+ why: error instanceof Error ? error.message : String(error),
787
+ fix: "Retry the command, or rerun with --trace for more detailed diagnostics.",
788
+ debug: formatDebugDetails(error),
789
+ exitCode: 1,
790
+ nextSteps
791
+ });
792
+ }
793
+ function localStateCleanupWarning(target, error) {
794
+ return `The app was removed remotely, but the local ${target} state could not be cleared: ${error instanceof Error ? error.message : String(error)}`;
795
+ }
796
+ function formatDebugDetails(error) {
797
+ if (error instanceof Error) return error.stack ?? error.message;
798
+ return typeof error === "string" ? error : null;
799
+ }
800
+ function isMissingProjectError(error) {
801
+ return error instanceof Error && error.message === "Resource Not Found";
802
+ }
803
+ function findAppByName(apps, name) {
804
+ return apps.find((app) => app.name === name);
805
+ }
806
+ function sortApps(apps) {
807
+ return apps.slice().sort((left, right) => left.name.localeCompare(right.name) || left.id.localeCompare(right.id));
808
+ }
809
+ function toOptionalEnvVars(envVars) {
810
+ return Object.keys(envVars).length > 0 ? envVars : void 0;
811
+ }
812
+ //#endregion
813
+ export { runAppBuild, runAppDeploy, runAppListDeploys, runAppListEnv, runAppLogs, runAppOpen, runAppPromote, runAppRemove, runAppRollback, runAppRun, runAppShow, runAppShowDeploy, runAppUpdateEnv };