@prisma/cli 3.0.0-beta.3 → 3.0.0-beta.30

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 (99) hide show
  1. package/README.md +6 -15
  2. package/dist/adapters/local-state.js +15 -4
  3. package/dist/adapters/mock-api.js +244 -0
  4. package/dist/adapters/token-storage.js +335 -34
  5. package/dist/cli.js +7 -7
  6. package/dist/cli2.js +24 -5
  7. package/dist/commands/agent/index.js +60 -0
  8. package/dist/commands/app/index.js +91 -61
  9. package/dist/commands/auth/index.js +55 -2
  10. package/dist/commands/branch/index.js +2 -27
  11. package/dist/commands/bucket/index.js +123 -0
  12. package/dist/commands/build/index.js +29 -0
  13. package/dist/commands/database/index.js +249 -0
  14. package/dist/commands/env.js +8 -4
  15. package/dist/commands/feedback/index.js +20 -0
  16. package/dist/commands/git/index.js +1 -1
  17. package/dist/commands/init/index.js +33 -0
  18. package/dist/commands/project/index.js +54 -5
  19. package/dist/controllers/agent-setup.js +52 -0
  20. package/dist/controllers/agent.js +228 -0
  21. package/dist/controllers/app-env-api.js +55 -0
  22. package/dist/controllers/app-env-file.js +181 -0
  23. package/dist/controllers/app-env.js +227 -104
  24. package/dist/controllers/app.js +746 -306
  25. package/dist/controllers/auth.js +247 -3
  26. package/dist/controllers/branch.js +78 -48
  27. package/dist/controllers/bucket.js +278 -0
  28. package/dist/controllers/build.js +88 -0
  29. package/dist/controllers/database.js +567 -0
  30. package/dist/controllers/feedback.js +86 -0
  31. package/dist/controllers/init.js +753 -0
  32. package/dist/controllers/project.js +377 -22
  33. package/dist/controllers/select-prompt-port.js +1 -0
  34. package/dist/lib/agent/cli-command.js +20 -0
  35. package/dist/lib/agent/constants.js +12 -0
  36. package/dist/lib/agent/package-manager.js +99 -0
  37. package/dist/lib/agent/setup-status.js +83 -0
  38. package/dist/lib/app/{preview-provider.js → app-provider.js} +137 -88
  39. package/dist/lib/app/branch-database-api.js +102 -0
  40. package/dist/lib/app/branch-database-deploy.js +326 -0
  41. package/dist/lib/app/branch-database.js +216 -0
  42. package/dist/lib/app/build-settings.js +93 -0
  43. package/dist/lib/app/build.js +83 -0
  44. package/dist/lib/app/bun-project.js +3 -4
  45. package/dist/lib/app/compute-config.js +145 -0
  46. package/dist/lib/app/deploy-plan.js +59 -0
  47. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
  48. package/dist/lib/app/env-config.js +1 -1
  49. package/dist/lib/app/env-file.js +82 -0
  50. package/dist/lib/app/env-vars.js +28 -2
  51. package/dist/lib/app/local-dev.js +3 -60
  52. package/dist/lib/app/production-deploy-gate.js +162 -0
  53. package/dist/lib/app/read-branch.js +30 -0
  54. package/dist/lib/auth/auth-ops.js +10 -4
  55. package/dist/lib/auth/guard.js +4 -1
  56. package/dist/lib/auth/login.js +33 -26
  57. package/dist/lib/auth/recipient.js +42 -0
  58. package/dist/lib/bucket/provider.js +139 -0
  59. package/dist/lib/database/provider.js +378 -0
  60. package/dist/lib/diagnostics.js +15 -0
  61. package/dist/lib/fs/home-path.js +24 -0
  62. package/dist/lib/git/local-branch.js +53 -0
  63. package/dist/lib/git/local-status.js +57 -0
  64. package/dist/lib/project/interactive-setup.js +5 -4
  65. package/dist/lib/project/local-pin.js +171 -41
  66. package/dist/lib/project/provider.js +92 -0
  67. package/dist/lib/project/resolution.js +199 -48
  68. package/dist/lib/project/setup.js +67 -20
  69. package/dist/output/patterns.js +1 -1
  70. package/dist/presenters/agent.js +74 -0
  71. package/dist/presenters/app-env.js +149 -14
  72. package/dist/presenters/app.js +208 -27
  73. package/dist/presenters/auth.js +99 -2
  74. package/dist/presenters/branch.js +37 -102
  75. package/dist/presenters/bucket.js +174 -0
  76. package/dist/presenters/database.js +448 -0
  77. package/dist/presenters/feedback.js +26 -0
  78. package/dist/presenters/init.js +30 -0
  79. package/dist/presenters/project.js +139 -27
  80. package/dist/presenters/verbose-context.js +64 -0
  81. package/dist/shell/cli-command.js +12 -0
  82. package/dist/shell/command-arguments.js +7 -1
  83. package/dist/shell/command-meta.js +458 -17
  84. package/dist/shell/command-runner.js +58 -18
  85. package/dist/shell/diagnostics-output.js +57 -0
  86. package/dist/shell/errors.js +56 -1
  87. package/dist/shell/help.js +31 -20
  88. package/dist/shell/output.js +72 -1
  89. package/dist/shell/prompt.js +12 -5
  90. package/dist/shell/runtime.js +8 -4
  91. package/dist/shell/ui.js +42 -3
  92. package/dist/shell/update-check.js +2 -2
  93. package/dist/use-cases/auth.js +68 -1
  94. package/dist/use-cases/branch.js +20 -68
  95. package/dist/use-cases/create-cli-gateways.js +2 -17
  96. package/dist/use-cases/project.js +2 -1
  97. package/package.json +21 -4
  98. package/dist/lib/app/preview-build.js +0 -312
  99. package/dist/lib/app/preview-interaction.js +0 -5
@@ -0,0 +1,83 @@
1
+ import { PRISMA_SKILLS_LOCK_FILENAME } from "./constants.js";
2
+ import path from "node:path";
3
+ import { readFile, stat } from "node:fs/promises";
4
+ import { findComputeConfigDir } from "@prisma/compute-sdk/config";
5
+ //#region src/lib/agent/setup-status.ts
6
+ async function readPrismaAgentSetupStatus(options) {
7
+ const setupCwd = await resolvePrismaAgentSetupCwd(options);
8
+ const skillsLockPath = path.join(setupCwd, PRISMA_SKILLS_LOCK_FILENAME);
9
+ const [skillsInstalled, promptDismissedAt] = await Promise.all([hasPrismaSkillsLock(skillsLockPath, options.signal, options.requiredSkill), options.stateStore?.readAgentSetupPromptDismissedAt() ?? null]);
10
+ return {
11
+ skillsLockPath: path.basename(skillsLockPath),
12
+ skillsInstalled,
13
+ promptDismissedAt
14
+ };
15
+ }
16
+ async function resolvePrismaAgentSetupCwd(options) {
17
+ options.signal.throwIfAborted();
18
+ const configDir = await findComputeConfigDir(options.cwd, options.signal);
19
+ options.signal.throwIfAborted();
20
+ return configDir ?? options.cwd;
21
+ }
22
+ function isPrismaAgentSetupComplete(status) {
23
+ return status.skillsInstalled;
24
+ }
25
+ function shouldOfferPrismaAgentSetup(status) {
26
+ return !isPrismaAgentSetupComplete(status) && !status.promptDismissedAt;
27
+ }
28
+ async function isLikelyProjectDirectory(options) {
29
+ return (await Promise.all([
30
+ "package.json",
31
+ "prisma.compute.ts",
32
+ "prisma.config.ts",
33
+ ".git"
34
+ ].map((fileName) => pathExists(path.join(options.cwd, fileName), options.signal)))).some(Boolean);
35
+ }
36
+ async function hasPrismaSkillsLock(filePath, signal, requiredSkill) {
37
+ try {
38
+ const raw = await readFile(filePath, {
39
+ encoding: "utf8",
40
+ signal
41
+ });
42
+ return hasPrismaSkillsLockEntry(JSON.parse(raw), requiredSkill);
43
+ } catch (error) {
44
+ if (isNotFoundError(error) || error instanceof SyntaxError) return false;
45
+ throw error;
46
+ }
47
+ }
48
+ function hasPrismaSkillsLockEntry(value, requiredSkill) {
49
+ if (!isRecord(value)) return false;
50
+ if (requiredSkill) return skillLockEntryUsesPrismaSource(readSkillLockEntries(value)[requiredSkill]);
51
+ if (readLegacySources(value).includes("prisma/skills")) return true;
52
+ return Object.values(readSkillLockEntries(value)).some(skillLockEntryUsesPrismaSource);
53
+ }
54
+ function readLegacySources(value) {
55
+ return Array.isArray(value.sources) ? value.sources.filter((source) => typeof source === "string") : [];
56
+ }
57
+ function readSkillLockEntries(value) {
58
+ return isRecord(value.skills) ? value.skills : {};
59
+ }
60
+ function skillLockEntryUsesPrismaSource(value) {
61
+ return isRecord(value) && value.source === "prisma/skills";
62
+ }
63
+ function isRecord(value) {
64
+ return typeof value === "object" && value !== null;
65
+ }
66
+ async function pathExists(filePath, signal) {
67
+ signal.throwIfAborted();
68
+ try {
69
+ await stat(filePath);
70
+ signal.throwIfAborted();
71
+ return true;
72
+ } catch (error) {
73
+ if (signal.aborted) throw error;
74
+ if (isNotFoundError(error)) return false;
75
+ throw error;
76
+ }
77
+ }
78
+ function isNotFoundError(error) {
79
+ const code = error.code;
80
+ return code === "ENOENT" || code === "ENOTDIR";
81
+ }
82
+ //#endregion
83
+ export { isLikelyProjectDirectory, readPrismaAgentSetupStatus, resolvePrismaAgentSetupCwd, shouldOfferPrismaAgentSetup };
@@ -1,32 +1,35 @@
1
+ import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./branch-database-api.js";
2
+ import { AppBuildStrategy } from "./build.js";
1
3
  import { envVarNames } from "./env-vars.js";
2
- import { PreviewBuildStrategy } from "./preview-build.js";
3
4
  import path from "node:path";
4
5
  import { ApiError, CancelledError, ComputeClient, streamLogs } from "@prisma/compute-sdk";
5
- //#region src/lib/app/preview-provider.ts
6
- var PreviewDomainApiError = class extends Error {
6
+ //#region src/lib/app/app-provider.ts
7
+ var DomainApiError = class extends Error {
7
8
  status;
8
9
  code;
9
10
  hint;
10
11
  constructor(options) {
11
12
  super(`${options.summary}: ${options.message}${options.hint ? ` ${options.hint}` : ""}`);
12
- this.name = "PreviewDomainApiError";
13
+ this.name = "DomainApiError";
13
14
  this.status = options.status;
14
15
  this.code = options.code ?? null;
15
16
  this.hint = options.hint ?? null;
16
17
  }
17
18
  };
18
- function createPreviewAppProvider(client, options) {
19
+ function createAppProvider(client, options) {
19
20
  const sdk = new ComputeClient(client);
20
21
  return {
21
22
  async createProject(options) {
22
23
  const projectResult = await sdk.createProject({
23
24
  name: options.name,
25
+ region: options.region,
24
26
  signal: options.signal
25
27
  });
26
28
  if (projectResult.isErr()) throw new Error(projectResult.error.message);
27
29
  return {
28
30
  id: projectResult.value.id,
29
- name: projectResult.value.name
31
+ name: projectResult.value.name,
32
+ defaultRegion: projectResult.value.defaultRegion
30
33
  };
31
34
  },
32
35
  async listApps(projectId, options) {
@@ -36,15 +39,45 @@ function createPreviewAppProvider(client, options) {
36
39
  signal: options?.signal
37
40
  });
38
41
  },
42
+ async resolveBranch(projectId, options) {
43
+ const branch = await resolveOrCreateBranch(client, {
44
+ projectId,
45
+ gitName: options.branchName,
46
+ signal: options.signal
47
+ });
48
+ return {
49
+ id: branch.id,
50
+ name: branch.gitName,
51
+ role: branch.role
52
+ };
53
+ },
54
+ async createBranchDatabase(options) {
55
+ return createBranchDatabase(client, options);
56
+ },
57
+ async deleteBranchDatabase(options) {
58
+ return deleteBranchDatabase(client, options);
59
+ },
60
+ async listEnvironmentVariables(options) {
61
+ return listEnvironmentVariables(client, options);
62
+ },
63
+ async createEnvironmentVariable(options) {
64
+ return createEnvironmentVariable(client, options);
65
+ },
66
+ async updateEnvironmentVariable(options) {
67
+ return updateEnvironmentVariable(client, options);
68
+ },
69
+ async deleteEnvironmentVariable(options) {
70
+ return deleteEnvironmentVariable(client, options);
71
+ },
39
72
  async removeApp(appId, options) {
40
- const appResult = await sdk.showService({
41
- serviceId: appId,
73
+ const appResult = await sdk.showApp({
74
+ appId,
42
75
  signal: options?.signal
43
76
  });
44
77
  if (appResult.isErr()) throw new Error(appResult.error.message);
45
- const destroyResult = await sdk.destroyService({
46
- serviceId: appId,
47
- keepService: false,
78
+ const destroyResult = await sdk.destroyApp({
79
+ appId,
80
+ keepApp: false,
48
81
  timeoutSeconds: 120,
49
82
  pollIntervalMs: 2e3,
50
83
  signal: options?.signal
@@ -59,8 +92,8 @@ function createPreviewAppProvider(client, options) {
59
92
  return listComputeServiceDomains(client, appId, options?.signal);
60
93
  },
61
94
  async addDomain(options) {
62
- const result = await client.POST("/v1/compute-services/{computeServiceId}/domains", {
63
- params: { path: { computeServiceId: options.appId } },
95
+ const result = await client.POST("/v1/apps/{appId}/domains", {
96
+ params: { path: { appId: options.appId } },
64
97
  body: { hostname: options.hostname },
65
98
  signal: options.signal
66
99
  });
@@ -104,8 +137,8 @@ function createPreviewAppProvider(client, options) {
104
137
  },
105
138
  async promoteDeployment(options) {
106
139
  const promoteResult = await sdk.promote({
107
- serviceId: options.appId,
108
- versionId: options.deploymentId,
140
+ appId: options.appId,
141
+ deploymentId: options.deploymentId,
109
142
  timeoutSeconds: 120,
110
143
  pollIntervalMs: 2e3,
111
144
  signal: options.signal,
@@ -130,18 +163,20 @@ function createPreviewAppProvider(client, options) {
130
163
  region: options.region
131
164
  };
132
165
  const deployResult = await sdk.deploy({
133
- strategy: new PreviewBuildStrategy({
166
+ strategy: new AppBuildStrategy({
134
167
  appPath: path.resolve(options.cwd),
135
168
  entrypoint: options.entrypoint,
136
169
  buildType: options.buildType,
137
- signal: options.signal
170
+ signal: options.signal,
171
+ buildSettings: options.buildSettings
138
172
  }),
139
173
  projectId: options.projectId,
140
- serviceId: resolvedApp.appId,
141
- serviceName: resolvedApp.appName,
174
+ appId: resolvedApp.appId,
175
+ appName: resolvedApp.appName,
142
176
  region: resolvedApp.region,
143
177
  portMapping: options.portMapping,
144
178
  envVars: options.envVars,
179
+ skipPromote: options.skipPromote,
145
180
  timeoutSeconds: 120,
146
181
  pollIntervalMs: 2e3,
147
182
  interaction: options.interaction,
@@ -153,22 +188,24 @@ function createPreviewAppProvider(client, options) {
153
188
  return {
154
189
  projectId: deployed.projectId,
155
190
  app: {
156
- id: deployed.serviceId,
157
- name: deployed.serviceName,
191
+ id: deployed.appId,
192
+ name: deployed.appName,
158
193
  region: deployed.region ?? null,
159
- liveDeploymentId: deployed.versionId,
160
- liveUrl: toAbsoluteUrl(deployed.serviceEndpointDomain ?? null)
194
+ liveDeploymentId: deployed.promoted ? deployed.deploymentId : deployed.previousDeploymentId,
195
+ liveUrl: toAbsoluteUrl(deployed.appEndpointDomain ?? null)
161
196
  },
162
197
  deployment: {
163
- id: deployed.versionId,
198
+ id: deployed.deploymentId,
164
199
  status: "running",
165
- url: toAbsoluteUrl(deployed.serviceEndpointDomain ?? deployed.versionEndpointDomain ?? null)
166
- }
200
+ url: toAbsoluteUrl(deployed.appEndpointDomain ?? deployed.deploymentEndpointDomain ?? null),
201
+ live: deployed.promoted
202
+ },
203
+ promoted: deployed.promoted
167
204
  };
168
205
  },
169
206
  async updateAppEnv(options) {
170
207
  const updateResult = await sdk.updateEnv({
171
- serviceId: options.appId,
208
+ appId: options.appId,
172
209
  envVars: options.envVars,
173
210
  timeoutSeconds: 120,
174
211
  pollIntervalMs: 2e3,
@@ -177,19 +214,19 @@ function createPreviewAppProvider(client, options) {
177
214
  });
178
215
  if (updateResult.isErr()) throw new Error(updateResult.error.message);
179
216
  const promoteResult = await sdk.promote({
180
- serviceId: options.appId,
181
- versionId: updateResult.value.versionId,
217
+ appId: options.appId,
218
+ deploymentId: updateResult.value.deploymentId,
182
219
  timeoutSeconds: 120,
183
220
  pollIntervalMs: 2e3,
184
221
  signal: options.signal,
185
222
  progress: options.promoteProgress
186
223
  });
187
224
  if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
188
- const [serviceResult, versionResult] = await Promise.all([sdk.showService({
189
- serviceId: options.appId,
225
+ const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
226
+ appId: options.appId,
190
227
  signal: options.signal
191
- }), sdk.showVersion({
192
- versionId: updateResult.value.versionId,
228
+ }), sdk.showDeployment({
229
+ deploymentId: updateResult.value.deploymentId,
193
230
  signal: options.signal
194
231
  })]);
195
232
  if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
@@ -200,25 +237,25 @@ function createPreviewAppProvider(client, options) {
200
237
  id: serviceResult.value.id,
201
238
  name: serviceResult.value.name,
202
239
  region: serviceResult.value.region ?? null,
203
- liveDeploymentId: serviceResult.value.latestVersionId ?? null,
204
- liveUrl: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? null)
240
+ liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
241
+ liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
205
242
  },
206
243
  deployment: {
207
244
  id: versionResult.value.id,
208
245
  status: versionResult.value.status,
209
246
  createdAt: versionResult.value.createdAt,
210
- url: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? versionResult.value.previewDomain ?? null),
247
+ url: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? versionResult.value.previewDomain ?? null),
211
248
  live: true
212
249
  },
213
250
  variables: envVarNames(versionResult.value.envVars)
214
251
  };
215
252
  },
216
253
  async listAppEnvNames(options) {
217
- const [serviceResult, versionResult] = await Promise.all([sdk.showService({
218
- serviceId: options.appId,
254
+ const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
255
+ appId: options.appId,
219
256
  signal: options.signal
220
- }), sdk.showVersion({
221
- versionId: options.deploymentId,
257
+ }), sdk.showDeployment({
258
+ deploymentId: options.deploymentId,
222
259
  signal: options.signal
223
260
  })]);
224
261
  if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
@@ -229,25 +266,25 @@ function createPreviewAppProvider(client, options) {
229
266
  id: serviceResult.value.id,
230
267
  name: serviceResult.value.name,
231
268
  region: serviceResult.value.region ?? null,
232
- liveDeploymentId: serviceResult.value.latestVersionId ?? null,
233
- liveUrl: toAbsoluteUrl(serviceResult.value.serviceEndpointDomain ?? null)
269
+ liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
270
+ liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
234
271
  },
235
272
  deployment: {
236
273
  id: versionResult.value.id,
237
274
  status: versionResult.value.status,
238
275
  createdAt: versionResult.value.createdAt,
239
276
  url: toAbsoluteUrl(versionResult.value.previewDomain ?? null),
240
- live: serviceResult.value.latestVersionId === versionResult.value.id
277
+ live: serviceResult.value.latestDeploymentId === versionResult.value.id
241
278
  },
242
279
  variables: envVarNames(versionResult.value.envVars)
243
280
  };
244
281
  },
245
282
  async listDeployments(appId, options) {
246
- const [appResult, versionsResult] = await Promise.all([sdk.showService({
247
- serviceId: appId,
283
+ const [appResult, versionsResult] = await Promise.all([sdk.showApp({
284
+ appId,
248
285
  signal: options?.signal
249
- }), sdk.listVersions({
250
- serviceId: appId,
286
+ }), sdk.listDeployments({
287
+ appId,
251
288
  signal: options?.signal
252
289
  })]);
253
290
  if (appResult.isErr()) throw new Error(appResult.error.message);
@@ -257,8 +294,8 @@ function createPreviewAppProvider(client, options) {
257
294
  id: appResult.value.id,
258
295
  name: appResult.value.name,
259
296
  region: appResult.value.region ?? null,
260
- liveDeploymentId: appResult.value.latestVersionId ?? null,
261
- liveUrl: toAbsoluteUrl(appResult.value.serviceEndpointDomain ?? null)
297
+ liveDeploymentId: appResult.value.latestDeploymentId ?? null,
298
+ liveUrl: toAbsoluteUrl(appResult.value.appEndpointDomain ?? null)
262
299
  },
263
300
  deployments: versionsResult.value.slice().sort((left, right) => {
264
301
  const byDate = right.createdAt.localeCompare(left.createdAt);
@@ -273,8 +310,8 @@ function createPreviewAppProvider(client, options) {
273
310
  };
274
311
  },
275
312
  async showDeployment(deploymentId, options) {
276
- const deploymentResult = await sdk.showVersion({
277
- versionId: deploymentId,
313
+ const deploymentResult = await sdk.showDeployment({
314
+ deploymentId,
278
315
  signal: options?.signal
279
316
  });
280
317
  if (deploymentResult.isErr()) {
@@ -297,7 +334,7 @@ function createPreviewAppProvider(client, options) {
297
334
  const result = await streamLogs({
298
335
  baseUrl: options.baseUrl,
299
336
  token: await options.getToken(),
300
- versionId: streamOptions.deploymentId,
337
+ deploymentId: streamOptions.deploymentId,
301
338
  signal: streamOptions.signal
302
339
  }, streamOptions.onRecord);
303
340
  if (result.isErr()) {
@@ -316,17 +353,19 @@ async function listBranches(client, options) {
316
353
  signal: options.signal
317
354
  });
318
355
  if (result.error || !result.data) throw apiCallError("Failed to list branches", result.response, result.error);
319
- return result.data.data;
356
+ return result.data.data.map((branch) => ({
357
+ id: branch.id,
358
+ gitName: branch.gitName,
359
+ isDefault: branch.isDefault,
360
+ role: branch.role
361
+ }));
320
362
  }
321
363
  async function resolveOrCreateBranch(client, options) {
322
364
  const existing = (await listBranches(client, options))[0];
323
365
  if (existing) return existing;
324
366
  const result = await client.POST("/v1/projects/{projectId}/branches", {
325
367
  params: { path: { projectId: options.projectId } },
326
- body: {
327
- gitName: options.gitName,
328
- isDefault: options.gitName === "main"
329
- },
368
+ body: { gitName: options.gitName },
330
369
  signal: options.signal
331
370
  });
332
371
  if (result.error || !result.data) {
@@ -336,13 +375,19 @@ async function resolveOrCreateBranch(client, options) {
336
375
  }
337
376
  throw apiCallError(`Failed to create branch "${options.gitName}"`, result.response, result.error);
338
377
  }
339
- return result.data.data;
378
+ const branch = result.data.data;
379
+ return {
380
+ id: branch.id,
381
+ gitName: branch.gitName,
382
+ isDefault: branch.isDefault,
383
+ role: branch.role
384
+ };
340
385
  }
341
386
  async function listComputeServices(client, options) {
342
387
  const services = [];
343
388
  let cursor;
344
389
  while (true) {
345
- const result = await client.GET("/v1/compute-services", {
390
+ const result = await client.GET("/v1/apps", {
346
391
  params: { query: {
347
392
  projectId: options.projectId,
348
393
  branchGitName: options.branchGitName,
@@ -360,13 +405,13 @@ async function listComputeServices(client, options) {
360
405
  name: service.name,
361
406
  region: service.region.id ?? null,
362
407
  branchId: service.branchId,
363
- liveDeploymentId: service.latestVersionId ?? null,
364
- liveUrl: toAbsoluteUrl(service.serviceEndpointDomain ?? null)
408
+ liveDeploymentId: service.latestDeploymentId ?? null,
409
+ liveUrl: toAbsoluteUrl(service.appEndpointDomain ?? null)
365
410
  }));
366
411
  }
367
- async function listComputeServiceDomains(client, computeServiceId, signal) {
368
- const result = await client.GET("/v1/compute-services/{computeServiceId}/domains", {
369
- params: { path: { computeServiceId } },
412
+ async function listComputeServiceDomains(client, appId, signal) {
413
+ const result = await client.GET("/v1/apps/{appId}/domains", {
414
+ params: { path: { appId } },
370
415
  signal
371
416
  });
372
417
  if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
@@ -378,7 +423,7 @@ function normalizeDomainRecord(domain) {
378
423
  type: domain.type,
379
424
  url: domain.url,
380
425
  hostname: domain.hostname,
381
- computeServiceId: domain.computeServiceId,
426
+ appId: domain.appId,
382
427
  status: domain.status,
383
428
  foundryStatus: domain.foundryStatus,
384
429
  failureReason: domain.failureReason,
@@ -413,7 +458,7 @@ async function createBranchApp(client, options) {
413
458
  gitName: options.branchName,
414
459
  signal: options.signal
415
460
  });
416
- const result = await client.POST("/v1/compute-services", {
461
+ const result = await client.POST("/v1/apps", {
417
462
  body: {
418
463
  projectId: options.projectId,
419
464
  branchId: branch.id,
@@ -451,7 +496,7 @@ function apiCallError(summary, response, error) {
451
496
  return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
452
497
  }
453
498
  function domainApiCallError(summary, response, error) {
454
- return new PreviewDomainApiError({
499
+ return new DomainApiError({
455
500
  summary,
456
501
  status: response.status,
457
502
  code: error.error?.code ?? null,
@@ -463,38 +508,42 @@ async function findAppForDeployment(sdk, deploymentId, signal) {
463
508
  const projectsResult = await sdk.listProjects({ signal });
464
509
  if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
465
510
  for (const project of projectsResult.value) {
466
- const servicesResult = await sdk.listServices({
511
+ const servicesResult = await sdk.listApps({
467
512
  projectId: project.id,
468
513
  signal
469
514
  });
470
515
  if (servicesResult.isErr()) throw new Error(servicesResult.error.message);
471
516
  for (const service of servicesResult.value) {
472
- const detailResult = await sdk.showService({
473
- serviceId: service.id,
474
- signal
475
- });
476
- if (detailResult.isErr()) throw new Error(detailResult.error.message);
477
- const app = {
478
- id: detailResult.value.id,
479
- name: detailResult.value.name,
480
- region: detailResult.value.region ?? null,
481
- liveDeploymentId: detailResult.value.latestVersionId ?? null,
482
- liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
483
- };
484
- if (app.liveDeploymentId === deploymentId) return app;
485
- const versionsResult = await sdk.listVersions({
486
- serviceId: service.id,
487
- signal
488
- });
489
- if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
490
- if (versionsResult.value.some((version) => version.id === deploymentId)) return app;
517
+ const app = await findServiceAppForDeployment(sdk, service.id, deploymentId, signal);
518
+ if (app) return app;
491
519
  }
492
520
  }
493
521
  return null;
494
522
  }
523
+ async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal) {
524
+ const detailResult = await sdk.showApp({
525
+ appId: serviceId,
526
+ signal
527
+ });
528
+ if (detailResult.isErr()) throw new Error(detailResult.error.message);
529
+ const app = {
530
+ id: detailResult.value.id,
531
+ name: detailResult.value.name,
532
+ region: detailResult.value.region ?? null,
533
+ liveDeploymentId: detailResult.value.latestDeploymentId ?? null,
534
+ liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null)
535
+ };
536
+ if (app.liveDeploymentId === deploymentId) return app;
537
+ const versionsResult = await sdk.listDeployments({
538
+ appId: serviceId,
539
+ signal
540
+ });
541
+ if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
542
+ return versionsResult.value.some((version) => version.id === deploymentId) ? app : null;
543
+ }
495
544
  function toAbsoluteUrl(url) {
496
545
  if (!url) return null;
497
546
  return url.startsWith("https://") || url.startsWith("http://") ? url : `https://${url}`;
498
547
  }
499
548
  //#endregion
500
- export { PreviewDomainApiError, createPreviewAppProvider };
549
+ export { DomainApiError, createAppProvider };
@@ -0,0 +1,102 @@
1
+ //#region src/lib/app/branch-database-api.ts
2
+ async function createBranchDatabase(client, options) {
3
+ const result = await client.POST("/v1/databases", {
4
+ body: {
5
+ projectId: options.projectId,
6
+ branchId: options.branchId,
7
+ name: options.branchName,
8
+ source: { type: "empty" }
9
+ },
10
+ signal: options.signal
11
+ });
12
+ if (result.error || !result.data) throw apiCallError(`Failed to create database for branch "${options.branchName}"`, result.response, result.error);
13
+ return normalizeBranchDatabaseRecord(result.data.data);
14
+ }
15
+ async function listEnvironmentVariables(client, options) {
16
+ const variables = [];
17
+ let cursor;
18
+ while (true) {
19
+ const result = await client.GET("/v1/environment-variables", {
20
+ params: { query: {
21
+ projectId: options.projectId,
22
+ class: options.className,
23
+ key: options.key,
24
+ branchId: options.branchId,
25
+ cursor
26
+ } },
27
+ signal: options.signal
28
+ });
29
+ if (result.error || !result.data) throw apiCallError("Failed to list environment variables", result.response, result.error);
30
+ variables.push(...result.data.data);
31
+ if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
32
+ cursor = result.data.pagination.nextCursor;
33
+ }
34
+ return variables.map((variable) => normalizeEnvironmentVariable(variable));
35
+ }
36
+ async function createEnvironmentVariable(client, options) {
37
+ const result = await client.POST("/v1/environment-variables", {
38
+ body: {
39
+ projectId: options.projectId,
40
+ class: options.className,
41
+ key: options.key,
42
+ value: options.value,
43
+ ...options.branchId ? { branchId: options.branchId } : {}
44
+ },
45
+ signal: options.signal
46
+ });
47
+ if (result.error || !result.data) throw apiCallError(`Failed to add ${options.key}`, result.response, result.error);
48
+ return normalizeEnvironmentVariable(result.data.data);
49
+ }
50
+ async function deleteBranchDatabase(client, options) {
51
+ const result = await client.DELETE("/v1/databases/{databaseId}", {
52
+ params: { path: { databaseId: options.databaseId } },
53
+ signal: options.signal
54
+ });
55
+ if (result.error) throw apiCallError("Failed to delete branch database", result.response, result.error);
56
+ }
57
+ async function updateEnvironmentVariable(client, options) {
58
+ const result = await client.PATCH("/v1/environment-variables/{envVarId}", {
59
+ params: { path: { envVarId: options.envVarId } },
60
+ body: { value: options.value },
61
+ signal: options.signal
62
+ });
63
+ if (result.error || !result.data) throw apiCallError("Failed to update environment variable", result.response, result.error);
64
+ return normalizeEnvironmentVariable(result.data.data);
65
+ }
66
+ async function deleteEnvironmentVariable(client, options) {
67
+ const result = await client.DELETE("/v1/environment-variables/{envVarId}", {
68
+ params: { path: { envVarId: options.envVarId } },
69
+ signal: options.signal
70
+ });
71
+ if (result.error) throw apiCallError("Failed to delete environment variable", result.response, result.error);
72
+ }
73
+ function normalizeEnvironmentVariable(variable) {
74
+ return {
75
+ id: variable.id,
76
+ key: variable.key,
77
+ branchId: variable.branchId,
78
+ className: variable.class,
79
+ isManagedBySystem: variable.isManagedBySystem
80
+ };
81
+ }
82
+ function normalizeBranchDatabaseRecord(database) {
83
+ const connection = database.connections?.[0];
84
+ const databaseUrl = connection?.endpoints?.pooled?.connectionString;
85
+ const directUrl = connection?.endpoints?.direct?.connectionString ?? null;
86
+ if (!databaseUrl) throw new Error("Created database did not return a pooled connection string.");
87
+ return {
88
+ id: database.id,
89
+ name: database.name,
90
+ branchId: database.branchId,
91
+ databaseUrl,
92
+ directUrl
93
+ };
94
+ }
95
+ function apiCallError(summary, response, error) {
96
+ if (response.status === 404) return /* @__PURE__ */ new Error("Resource Not Found");
97
+ const message = error.error?.message ?? `Management API returned HTTP ${response.status}.`;
98
+ const hint = error.error?.hint ? ` ${error.error.hint}` : "";
99
+ return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
100
+ }
101
+ //#endregion
102
+ export { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable };