@prisma/cli 3.0.0-dev.127.1 → 3.0.0-dev.131.1

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.
package/README.md CHANGED
@@ -76,6 +76,8 @@ The beta package exposes `prisma-cli` so it can coexist with the existing
76
76
  | `project` | List projects, show the resolved project, and manage project environment variables. |
77
77
  | `git` | Connect or disconnect a project from a GitHub repository. |
78
78
  | `branch` | List Prisma branches for the resolved project. |
79
+ | `database` | Create, inspect, and remove Prisma Postgres databases and their connection strings. |
80
+ | `bucket` | Create, list, and delete Tigris object-store buckets and their access keys. |
79
81
  | `app` | Build, run, deploy, inspect, open, stream logs, promote, roll back, and remove apps. |
80
82
 
81
83
  Common examples:
@@ -227,6 +227,79 @@ var MockApi = class MockApi {
227
227
  connectionString
228
228
  };
229
229
  }
230
+ listBucketsForProject(projectId, branchName) {
231
+ return (this.data.buckets ?? []).filter((bucket) => bucket.projectId === projectId && (!branchName || this.data.branches.find((branch) => branch.id === bucket.branchId && branch.name === branchName)));
232
+ }
233
+ getBucket(bucketId) {
234
+ return (this.data.buckets ?? []).find((bucket) => bucket.id === bucketId);
235
+ }
236
+ createBucket(input) {
237
+ this.data.buckets ??= [];
238
+ let branchId = null;
239
+ if (input.branchGitName) {
240
+ const branch = this.data.branches.find((b) => b.projectId === input.projectId && b.name === input.branchGitName);
241
+ if (!branch) return;
242
+ branchId = branch.id;
243
+ }
244
+ const bucket = {
245
+ id: `bkt_${this.data.buckets.length + 1e3}`,
246
+ projectId: input.projectId,
247
+ branchId,
248
+ name: input.name ?? `bucket-${this.data.buckets.length + 1e3}`,
249
+ status: "ready",
250
+ createdAt: "2026-06-09T00:00:00.000Z"
251
+ };
252
+ this.data.buckets.push(bucket);
253
+ return bucket;
254
+ }
255
+ deleteBucket(bucketId) {
256
+ this.data.buckets ??= [];
257
+ this.data.bucketKeys ??= [];
258
+ const bucket = this.getBucket(bucketId);
259
+ if (!bucket) return;
260
+ this.data.buckets = this.data.buckets.filter((candidate) => candidate.id !== bucketId);
261
+ this.data.bucketKeys = this.data.bucketKeys.filter((key) => key.bucketId !== bucketId);
262
+ return bucket;
263
+ }
264
+ listBucketKeys(bucketId) {
265
+ return (this.data.bucketKeys ?? []).filter((key) => key.bucketId === bucketId);
266
+ }
267
+ createBucketKey(input) {
268
+ const bucket = this.getBucket(input.bucketId);
269
+ if (!bucket) return;
270
+ this.data.bucketKeys ??= [];
271
+ const secretAccessKey = `secret-${input.bucketId}-${this.data.bucketKeys.length + 1}`;
272
+ const accessKeyId = `AKIA${input.bucketId.toUpperCase().replace(/_/g, "")}${this.data.bucketKeys.length + 1}`;
273
+ const endpoint = `https://fly.storage.tigris.dev`;
274
+ const bucketName = bucket.name;
275
+ const key = {
276
+ id: `bkey_${this.data.bucketKeys.length + 1e3}`,
277
+ bucketId: input.bucketId,
278
+ name: input.name ?? `key-${this.data.bucketKeys.length + 1e3}`,
279
+ role: input.role,
280
+ valueHint: `${accessKeyId.slice(0, 8)}...`,
281
+ createdAt: "2026-06-09T00:00:00.000Z",
282
+ secretAccessKey,
283
+ accessKeyId,
284
+ endpoint,
285
+ bucketName
286
+ };
287
+ this.data.bucketKeys.push(key);
288
+ return {
289
+ key,
290
+ secretAccessKey,
291
+ accessKeyId,
292
+ endpoint,
293
+ bucketName
294
+ };
295
+ }
296
+ deleteBucketKey(bucketId, keyId) {
297
+ this.data.bucketKeys ??= [];
298
+ const key = (this.data.bucketKeys ?? []).find((candidate) => candidate.id === keyId && candidate.bucketId === bucketId);
299
+ if (!key) return;
300
+ this.data.bucketKeys = this.data.bucketKeys.filter((candidate) => candidate.id !== keyId);
301
+ return key;
302
+ }
230
303
  };
231
304
  //#endregion
232
305
  export { MockApi };
package/dist/cli2.js CHANGED
@@ -9,6 +9,7 @@ import "./shell/prompt.js";
9
9
  import { createAppCommand } from "./commands/app/index.js";
10
10
  import { createAuthCommand } from "./commands/auth/index.js";
11
11
  import { createBranchCommand } from "./commands/branch/index.js";
12
+ import { createBucketCommand } from "./commands/bucket/index.js";
12
13
  import { createBuildCommand } from "./commands/build/index.js";
13
14
  import { createDatabaseCommand } from "./commands/database/index.js";
14
15
  import { getCliName, getCliVersion } from "./lib/version.js";
@@ -67,6 +68,7 @@ function createProgram(runtime) {
67
68
  program.addCommand(createBranchCommand(runtime));
68
69
  program.addCommand(createBuildCommand(runtime));
69
70
  program.addCommand(createDatabaseCommand(runtime));
71
+ program.addCommand(createBucketCommand(runtime));
70
72
  program.addCommand(createAppCommand(runtime));
71
73
  return program;
72
74
  }
@@ -0,0 +1,121 @@
1
+ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../../shell/runtime.js";
4
+ import { runCommand } from "../../shell/command-runner.js";
5
+ import { runBucketCreate, runBucketDelete, runBucketKeyCreate, runBucketKeyDelete, runBucketKeyList, runBucketList } from "../../controllers/bucket.js";
6
+ import { renderBucketCreate, renderBucketDelete, renderBucketKeyCreate, renderBucketKeyCreateStdout, renderBucketKeyDelete, renderBucketKeyList, renderBucketList, serializeBucketCreate, serializeBucketDelete, serializeBucketKeyCreate, serializeBucketKeyDelete, serializeBucketKeyList, serializeBucketList } from "../../presenters/bucket.js";
7
+ import { Command, Option } from "commander";
8
+ //#region src/commands/bucket/index.ts
9
+ function createBucketCommand(runtime) {
10
+ const bucket = attachCommandDescriptor(configureRuntimeCommand(new Command("bucket"), runtime), "bucket");
11
+ addCompactGlobalFlags(bucket);
12
+ bucket.addCommand(createBucketListCommand(runtime));
13
+ bucket.addCommand(createBucketCreateCommand(runtime));
14
+ bucket.addCommand(createBucketDeleteCommand(runtime));
15
+ bucket.addCommand(createBucketKeyCommand(runtime));
16
+ return bucket;
17
+ }
18
+ function addProjectAndBranchOptions(command) {
19
+ return command.addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <git-name>", "Branch git name"));
20
+ }
21
+ function createBucketListCommand(runtime) {
22
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "bucket.list");
23
+ addProjectAndBranchOptions(command);
24
+ addGlobalFlags(command);
25
+ command.action(async (options) => {
26
+ const projectRef = options.project;
27
+ const branchName = options.branch;
28
+ await runCommand(runtime, "bucket.list", options, (context) => runBucketList(context, {
29
+ projectRef,
30
+ branchName
31
+ }), {
32
+ renderHuman: (context, descriptor, result) => renderBucketList(context, descriptor, result),
33
+ renderJson: (result) => serializeBucketList(result)
34
+ });
35
+ });
36
+ return command;
37
+ }
38
+ function createBucketCreateCommand(runtime) {
39
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "bucket.create");
40
+ command.addOption(new Option("--name <name>", "Bucket display name (auto-generated if omitted)"));
41
+ addProjectAndBranchOptions(command);
42
+ addGlobalFlags(command);
43
+ command.action(async (options) => {
44
+ const projectRef = options.project;
45
+ const branchName = options.branch;
46
+ const name = options.name;
47
+ await runCommand(runtime, "bucket.create", options, (context) => runBucketCreate(context, {
48
+ projectRef,
49
+ branchName,
50
+ name
51
+ }), {
52
+ renderHuman: (context, descriptor, result) => renderBucketCreate(context, descriptor, result),
53
+ renderJson: (result) => serializeBucketCreate(result)
54
+ });
55
+ });
56
+ return command;
57
+ }
58
+ function createBucketDeleteCommand(runtime) {
59
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("delete"), runtime), "bucket.delete");
60
+ command.argument("<bucketId>", "Bucket id");
61
+ addGlobalFlags(command);
62
+ command.action(async (bucketId, options) => {
63
+ await runCommand(runtime, "bucket.delete", options, (context) => runBucketDelete(context, bucketId), {
64
+ renderHuman: (context, descriptor, result) => renderBucketDelete(context, descriptor, result),
65
+ renderJson: (result) => serializeBucketDelete(result)
66
+ });
67
+ });
68
+ return command;
69
+ }
70
+ function createBucketKeyCommand(runtime) {
71
+ const key = attachCommandDescriptor(configureRuntimeCommand(new Command("key"), runtime), "bucket.key");
72
+ addCompactGlobalFlags(key);
73
+ key.addCommand(createBucketKeyListCommand(runtime));
74
+ key.addCommand(createBucketKeyCreateCommand(runtime));
75
+ key.addCommand(createBucketKeyDeleteCommand(runtime));
76
+ return key;
77
+ }
78
+ function createBucketKeyListCommand(runtime) {
79
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "bucket.key.list");
80
+ command.argument("<bucketId>", "Bucket id");
81
+ addGlobalFlags(command);
82
+ command.action(async (bucketId, options) => {
83
+ await runCommand(runtime, "bucket.key.list", options, (context) => runBucketKeyList(context, bucketId), {
84
+ renderHuman: (context, descriptor, result) => renderBucketKeyList(context, descriptor, result),
85
+ renderJson: (result) => serializeBucketKeyList(result)
86
+ });
87
+ });
88
+ return command;
89
+ }
90
+ function createBucketKeyCreateCommand(runtime) {
91
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "bucket.key.create");
92
+ command.argument("<bucketId>", "Bucket id").addOption(new Option("--role <role>", "Access role (default: read_write)").choices(["read", "read_write"])).addOption(new Option("--name <name>", "Key display name (auto-generated if omitted)"));
93
+ addGlobalFlags(command);
94
+ command.action(async (bucketId, options) => {
95
+ const role = options.role;
96
+ const name = options.name;
97
+ await runCommand(runtime, "bucket.key.create", options, (context) => runBucketKeyCreate(context, bucketId, {
98
+ role,
99
+ name
100
+ }), {
101
+ renderStdout: (context, descriptor, result) => renderBucketKeyCreateStdout(context, descriptor, result),
102
+ renderHuman: (context, descriptor, result) => renderBucketKeyCreate(context, descriptor, result),
103
+ renderJson: (result) => serializeBucketKeyCreate(result)
104
+ });
105
+ });
106
+ return command;
107
+ }
108
+ function createBucketKeyDeleteCommand(runtime) {
109
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("delete"), runtime), "bucket.key.delete");
110
+ command.argument("<bucketId>", "Bucket id").argument("<keyId>", "Key id");
111
+ addGlobalFlags(command);
112
+ command.action(async (bucketId, keyId, options) => {
113
+ await runCommand(runtime, "bucket.key.delete", options, (context) => runBucketKeyDelete(context, bucketId, keyId), {
114
+ renderHuman: (context, descriptor, result) => renderBucketKeyDelete(context, descriptor, result),
115
+ renderJson: (result) => serializeBucketKeyDelete(result)
116
+ });
117
+ });
118
+ return command;
119
+ }
120
+ //#endregion
121
+ export { createBucketCommand };
@@ -67,10 +67,11 @@ function createProjectTransferCommand(runtime) {
67
67
  }
68
68
  function createProjectCreateCommand(runtime) {
69
69
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "project.create");
70
- command.argument("<name>", "Project name");
70
+ command.argument("<name>", "Project name").addOption(new Option("--region <region>", "Prisma Compute region id"));
71
71
  addGlobalFlags(command);
72
72
  command.action(async (name, options) => {
73
- await runCommand(runtime, "project.create", options, (context) => runProjectCreate(context, String(name)), {
73
+ const region = options.region;
74
+ await runCommand(runtime, "project.create", options, (context) => runProjectCreate(context, String(name), { region }), {
74
75
  renderHuman: (context, descriptor, result) => renderProjectSetup(context, descriptor, result),
75
76
  renderJson: (result) => serializeProjectSetup(result)
76
77
  });
@@ -5,12 +5,11 @@ import { canPrompt } from "../shell/runtime.js";
5
5
  import { writeJsonEvent } from "../shell/output.js";
6
6
  import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
7
7
  import { FileTokenStorage } from "../adapters/token-storage.js";
8
- import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
9
- import "../lib/app/app-interaction.js";
10
8
  import { PRISMA_APP_CONFIG_FILENAME, detectLegacyBuildSettings, resolveConfiguredAppBuildSettings, resolveInferredAppBuildSettings } from "../lib/app/build-settings.js";
11
9
  import { APP_BUILD_TYPES, APP_BUILD_TYPE_LABELS, RESOLVED_APP_BUILD_TYPES, executeAppBuild } from "../lib/app/build.js";
12
10
  import { envVarNames, parseEnvInputs } from "../lib/app/env-vars.js";
13
11
  import { DomainApiError, createAppProvider } from "../lib/app/app-provider.js";
12
+ import { confirmPrompt, selectPrompt, textPrompt } from "../shell/prompt.js";
14
13
  import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "../lib/project/local-pin.js";
15
14
  import { buildProjectSetupNextActions, inferTargetName, localProjectWorkspaceMismatchError, projectNotFoundError, projectResolutionErrorToCliError, resolveDurablePlatformMapping, resolveProjectTarget, sortProjects } from "../lib/project/resolution.js";
16
15
  import { bindProjectToDirectory, projectCreateFailedError, projectDirectoryBindingErrorToCliError, projectSetupNameRequiredError, resolveProjectForSetup, toProjectSummary } from "../lib/project/setup.js";
@@ -281,6 +280,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
281
280
  const { provider, target, projectId } = await requireProviderAndDeployProjectContext(context, options?.projectRef, {
282
281
  branch,
283
282
  createProjectName: options?.createProjectName,
283
+ createProjectRegion: deployRegion?.value,
284
284
  envProjectId,
285
285
  localPin
286
286
  });
@@ -416,6 +416,7 @@ async function runSingleAppDeploy(context, appName, options, preloadedConfig) {
416
416
  entrypoint: entrypoint ?? buildSettingsResolution.settings.entrypoint ?? null,
417
417
  httpPort: runtime.port,
418
418
  region: deployResult.app.region ?? selectedApp.region ?? null,
419
+ regionSource: deployRegion?.annotation ?? null,
419
420
  envVars: envVarNames(envVars)
420
421
  },
421
422
  durationMs: deployDurationMs,
@@ -1424,7 +1425,7 @@ async function resolveAmbiguousDeployApp(context, matches, targetName, requested
1424
1425
  });
1425
1426
  }
1426
1427
  function deployNewAppRegion(configRegion) {
1427
- return configRegion?.value ?? "eu-central-1";
1428
+ return configRegion?.value;
1428
1429
  }
1429
1430
  async function resolveExistingAppSelection(context, projectId, apps, explicitAppName) {
1430
1431
  if (explicitAppName) {
@@ -1654,7 +1655,7 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
1654
1655
  if (!projectName) throw projectSetupNameRequiredError("app deploy --create-project");
1655
1656
  return withRemoteDeployBranch(provider, {
1656
1657
  workspace,
1657
- project: toProjectSummary(await createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal)),
1658
+ project: toProjectSummary(await createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal, options.createProjectRegion)),
1658
1659
  resolution: {
1659
1660
  projectSource: "created",
1660
1661
  targetName: projectName,
@@ -1705,14 +1706,14 @@ async function resolveDeployProjectContext(context, client, provider, explicitPr
1705
1706
  targetNameSource: "platform-mapping"
1706
1707
  }
1707
1708
  }, branch, context.runtime.signal);
1708
- if (canPrompt(context) && !context.flags.yes) return withRemoteDeployBranch(provider, await resolveInteractiveDeployProjectSetup(context, provider, workspace, projects), branch, context.runtime.signal);
1709
+ if (canPrompt(context) && !context.flags.yes) return withRemoteDeployBranch(provider, await resolveInteractiveDeployProjectSetup(context, provider, workspace, projects, options.createProjectRegion), branch, context.runtime.signal);
1709
1710
  throw projectSetupRequiredError(projects, await inferTargetName(context.runtime.cwd, context.runtime.signal));
1710
1711
  }
1711
- async function resolveInteractiveDeployProjectSetup(context, provider, workspace, projects) {
1712
+ async function resolveInteractiveDeployProjectSetup(context, provider, workspace, projects, createProjectRegion) {
1712
1713
  const setup = await promptForProjectSetupChoice({
1713
1714
  context,
1714
1715
  projects,
1715
- createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal),
1716
+ createProject: (projectName) => createProjectForDeploySetup(provider, projectName, workspace, context.runtime.signal, createProjectRegion),
1716
1717
  cancel: {
1717
1718
  why: "Deploy needs a Project before it can continue.",
1718
1719
  fix: "Choose an existing Project or create a new one, then rerun deploy.",
@@ -1730,9 +1731,10 @@ async function resolveInteractiveDeployProjectSetup(context, provider, workspace
1730
1731
  localPinAction: setup.action
1731
1732
  };
1732
1733
  }
1733
- async function createProjectForDeploySetup(provider, projectName, workspace, signal) {
1734
+ async function createProjectForDeploySetup(provider, projectName, workspace, signal, region) {
1734
1735
  const created = await provider.createProject({
1735
1736
  name: projectName,
1737
+ region,
1736
1738
  signal
1737
1739
  }).catch((error) => {
1738
1740
  throw projectCreateFailedError(error, projectName, workspace, {
@@ -1748,6 +1750,7 @@ async function createProjectForDeploySetup(provider, projectName, workspace, sig
1748
1750
  return {
1749
1751
  id: created.id,
1750
1752
  name: created.name,
1753
+ ...created.defaultRegion != null ? { defaultRegion: created.defaultRegion } : {},
1751
1754
  workspace
1752
1755
  };
1753
1756
  }
@@ -0,0 +1,265 @@
1
+ import { CliError, authRequiredError, workspaceRequiredError } from "../shell/errors.js";
2
+ import { projectResolutionErrorToCliError, resolveProjectTarget } from "../lib/project/resolution.js";
3
+ import { requireComputeAuth } from "../lib/auth/guard.js";
4
+ import { requireAuthenticatedAuthState } from "./auth.js";
5
+ import { listFixtureWorkspaceProjects, listRealWorkspaceProjects } from "./project.js";
6
+ import { createManagementBucketProvider, normalizeBucket, normalizeKey } from "../lib/bucket/provider.js";
7
+ //#region src/controllers/bucket.ts
8
+ function isRealMode(context) {
9
+ return !context.runtime.fixturePath && !context.runtime.env.PRISMA_CLI_MOCK_FIXTURE_PATH;
10
+ }
11
+ async function runBucketList(context, flags) {
12
+ const { provider, target } = await requireBucketContext(context, flags, "bucket list");
13
+ const buckets = await provider.listBuckets({
14
+ projectId: target.project.id,
15
+ branchName: flags.branchName,
16
+ signal: context.runtime.signal
17
+ });
18
+ return {
19
+ command: "bucket.list",
20
+ result: {
21
+ projectId: target.project.id,
22
+ projectName: target.project.name,
23
+ branchName: flags.branchName ?? null,
24
+ verboseContext: target,
25
+ buckets
26
+ },
27
+ warnings: [],
28
+ nextSteps: []
29
+ };
30
+ }
31
+ async function runBucketCreate(context, flags) {
32
+ const { provider, target } = await requireBucketContext(context, flags, "bucket create");
33
+ const bucket = await provider.createBucket({
34
+ projectId: target.project.id,
35
+ name: flags.name?.trim() || void 0,
36
+ branchGitName: flags.branchName,
37
+ signal: context.runtime.signal
38
+ });
39
+ return {
40
+ command: "bucket.create",
41
+ result: {
42
+ projectId: target.project.id,
43
+ projectName: target.project.name,
44
+ verboseContext: target,
45
+ bucket
46
+ },
47
+ warnings: [],
48
+ nextSteps: []
49
+ };
50
+ }
51
+ async function runBucketDelete(context, bucketId) {
52
+ const id = bucketId.trim();
53
+ if (!id) throw new CliError({
54
+ code: "USAGE_ERROR",
55
+ domain: "bucket",
56
+ summary: "Bucket id required",
57
+ why: "Bucket deletion needs a bucket id.",
58
+ fix: "Pass the bucket id to delete.",
59
+ exitCode: 2,
60
+ nextSteps: ["prisma-cli bucket list"]
61
+ });
62
+ await (await requireBucketProviderOnly(context)).deleteBucket(id, { signal: context.runtime.signal });
63
+ return {
64
+ command: "bucket.delete",
65
+ result: { bucket: { id } },
66
+ warnings: [],
67
+ nextSteps: []
68
+ };
69
+ }
70
+ async function runBucketKeyList(context, bucketId) {
71
+ const id = bucketId.trim();
72
+ if (!id) throw new CliError({
73
+ code: "USAGE_ERROR",
74
+ domain: "bucket",
75
+ summary: "Bucket id required",
76
+ why: "Bucket key listing needs a bucket id.",
77
+ fix: "Pass the bucket id.",
78
+ exitCode: 2,
79
+ nextSteps: ["prisma-cli bucket list"]
80
+ });
81
+ return {
82
+ command: "bucket.key.list",
83
+ result: {
84
+ bucketId: id,
85
+ keys: await (await requireBucketProviderOnly(context)).listKeys(id, { signal: context.runtime.signal })
86
+ },
87
+ warnings: [],
88
+ nextSteps: []
89
+ };
90
+ }
91
+ async function runBucketKeyCreate(context, bucketId, flags) {
92
+ const id = bucketId.trim();
93
+ if (!id) throw new CliError({
94
+ code: "USAGE_ERROR",
95
+ domain: "bucket",
96
+ summary: "Bucket id required",
97
+ why: "Bucket key creation needs a bucket id.",
98
+ fix: "Pass the bucket id.",
99
+ exitCode: 2,
100
+ nextSteps: ["prisma-cli bucket list"]
101
+ });
102
+ const role = resolveKeyRole(flags.role);
103
+ const created = await (await requireBucketProviderOnly(context)).createKey({
104
+ bucketId: id,
105
+ name: flags.name?.trim() || void 0,
106
+ role,
107
+ signal: context.runtime.signal
108
+ });
109
+ return {
110
+ command: "bucket.key.create",
111
+ result: {
112
+ bucketId: id,
113
+ key: created.key,
114
+ secretAccessKey: created.secretAccessKey,
115
+ accessKeyId: created.accessKeyId,
116
+ endpoint: created.endpoint,
117
+ bucketName: created.bucketName
118
+ },
119
+ warnings: [],
120
+ nextSteps: []
121
+ };
122
+ }
123
+ async function runBucketKeyDelete(context, bucketId, keyId) {
124
+ const bktId = bucketId.trim();
125
+ const kId = keyId.trim();
126
+ if (!bktId || !kId) throw new CliError({
127
+ code: "USAGE_ERROR",
128
+ domain: "bucket",
129
+ summary: "Bucket id and key id required",
130
+ why: "Bucket key deletion needs both a bucket id and a key id.",
131
+ fix: "Pass the bucket id and key id.",
132
+ exitCode: 2,
133
+ nextSteps: ["prisma-cli bucket key list <bucketId>"]
134
+ });
135
+ await (await requireBucketProviderOnly(context)).deleteKey(bktId, kId, { signal: context.runtime.signal });
136
+ return {
137
+ command: "bucket.key.delete",
138
+ result: { key: { id: kId } },
139
+ warnings: [],
140
+ nextSteps: []
141
+ };
142
+ }
143
+ async function resolveBucketProvider(context) {
144
+ if (isRealMode(context)) {
145
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
146
+ if (!client) throw authRequiredError();
147
+ return createManagementBucketProvider(client);
148
+ }
149
+ return createFixtureBucketProvider(context);
150
+ }
151
+ async function requireBucketContext(context, flags, commandName) {
152
+ const workspace = (await requireAuthenticatedAuthState(context)).workspace;
153
+ if (!workspace) throw workspaceRequiredError();
154
+ if (isRealMode(context)) {
155
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
156
+ if (!client) throw authRequiredError();
157
+ const targetResult = await resolveProjectTarget({
158
+ context,
159
+ workspace,
160
+ explicitProject: flags.projectRef,
161
+ listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
162
+ commandName
163
+ });
164
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
165
+ return {
166
+ provider: createManagementBucketProvider(client),
167
+ target: targetResult.value
168
+ };
169
+ }
170
+ const targetResult = await resolveProjectTarget({
171
+ context,
172
+ workspace,
173
+ explicitProject: flags.projectRef,
174
+ listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
175
+ commandName
176
+ });
177
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
178
+ return {
179
+ provider: createFixtureBucketProvider(context),
180
+ target: targetResult.value
181
+ };
182
+ }
183
+ async function requireBucketProviderOnly(context) {
184
+ await requireAuthenticatedAuthState(context);
185
+ return resolveBucketProvider(context);
186
+ }
187
+ function createFixtureBucketProvider(context) {
188
+ return {
189
+ async listBuckets(options) {
190
+ return context.api.listBucketsForProject(options.projectId, options.branchName).map((bucket) => normalizeBucket(bucket));
191
+ },
192
+ async createBucket(options) {
193
+ const created = context.api.createBucket({
194
+ projectId: options.projectId,
195
+ name: options.name,
196
+ branchGitName: options.branchGitName
197
+ });
198
+ if (!created) throw branchNotFoundError(options.branchGitName ?? "");
199
+ return normalizeBucket(created);
200
+ },
201
+ async deleteBucket(bucketId) {
202
+ if (!context.api.deleteBucket(bucketId)) throw bucketNotFoundError(bucketId);
203
+ },
204
+ async listKeys(bucketId) {
205
+ if (!context.api.getBucket(bucketId)) throw bucketNotFoundError(bucketId);
206
+ return context.api.listBucketKeys(bucketId).map((key) => normalizeKey(key));
207
+ },
208
+ async createKey(options) {
209
+ const created = context.api.createBucketKey({
210
+ bucketId: options.bucketId,
211
+ name: options.name,
212
+ role: options.role
213
+ });
214
+ if (!created) throw bucketNotFoundError(options.bucketId);
215
+ return {
216
+ key: normalizeKey(created.key),
217
+ secretAccessKey: created.secretAccessKey,
218
+ accessKeyId: created.accessKeyId,
219
+ endpoint: created.endpoint,
220
+ bucketName: created.bucketName
221
+ };
222
+ },
223
+ async deleteKey(bucketId, keyId) {
224
+ if (!context.api.deleteBucketKey(bucketId, keyId)) throw keyNotFoundError(keyId, bucketId);
225
+ }
226
+ };
227
+ }
228
+ function resolveKeyRole(role) {
229
+ return role === "read" ? "read" : "read_write";
230
+ }
231
+ function branchNotFoundError(branchGitName) {
232
+ return new CliError({
233
+ code: "BRANCH_NOT_FOUND",
234
+ domain: "bucket",
235
+ summary: "Branch not found",
236
+ why: `No branch matched "${branchGitName}" in the resolved project.`,
237
+ fix: "Pass a branch git name from prisma-cli branch list.",
238
+ exitCode: 1,
239
+ nextSteps: ["prisma-cli branch list"]
240
+ });
241
+ }
242
+ function bucketNotFoundError(bucketId) {
243
+ return new CliError({
244
+ code: "BUCKET_NOT_FOUND",
245
+ domain: "bucket",
246
+ summary: "Bucket not found",
247
+ why: `No bucket matched "${bucketId}".`,
248
+ fix: "Pass a bucket id from prisma-cli bucket list.",
249
+ exitCode: 1,
250
+ nextSteps: ["prisma-cli bucket list"]
251
+ });
252
+ }
253
+ function keyNotFoundError(keyId, bucketId) {
254
+ return new CliError({
255
+ code: "BUCKET_KEY_NOT_FOUND",
256
+ domain: "bucket",
257
+ summary: "Bucket key not found",
258
+ why: `No key matched "${keyId}" for bucket "${bucketId}".`,
259
+ fix: "Pass a key id from prisma-cli bucket key list <bucketId>.",
260
+ exitCode: 1,
261
+ nextSteps: [`prisma-cli bucket key list ${bucketId}`]
262
+ });
263
+ }
264
+ //#endregion
265
+ export { runBucketCreate, runBucketDelete, runBucketKeyCreate, runBucketKeyDelete, runBucketKeyList, runBucketList };
@@ -104,7 +104,7 @@ async function runProjectShow(context, explicitProject) {
104
104
  }) : []
105
105
  };
106
106
  }
107
- async function runProjectCreate(context, projectName) {
107
+ async function runProjectCreate(context, projectName, options) {
108
108
  const workspace = (await requireAuthenticatedAuthState(context)).workspace;
109
109
  if (!workspace) throw workspaceRequiredError();
110
110
  if (!isValidProjectSetupName(projectName)) throw projectSetupNameRequiredError("project create");
@@ -115,6 +115,7 @@ async function runProjectCreate(context, projectName) {
115
115
  const name = projectName.trim();
116
116
  const created = await provider.createProject({
117
117
  name,
118
+ region: options?.region,
118
119
  signal: context.runtime.signal
119
120
  }).catch((error) => {
120
121
  throw projectCreateFailedError(error, name, workspace, {
@@ -125,7 +126,8 @@ async function runProjectCreate(context, projectName) {
125
126
  });
126
127
  const bindResult = await bindProjectToDirectory(context, workspace, {
127
128
  id: created.id,
128
- name: created.name
129
+ name: created.name,
130
+ ...created.defaultRegion != null ? { defaultRegion: created.defaultRegion } : {}
129
131
  }, "created");
130
132
  if (bindResult.isErr()) throw projectDirectoryBindingErrorToCliError(bindResult.error);
131
133
  return {
@@ -704,6 +706,7 @@ async function listRealWorkspaceProjects(client, workspace, signal) {
704
706
  id: project.id,
705
707
  name: project.name,
706
708
  ..."url" in project && typeof project.url === "string" ? { url: project.url } : {},
709
+ ..."defaultRegion" in project ? { defaultRegion: project.defaultRegion } : {},
707
710
  slug: "slug" in project && typeof project.slug === "string" ? project.slug : null,
708
711
  workspace: {
709
712
  id: project.workspace.id,
@@ -22,12 +22,14 @@ function createAppProvider(client, options) {
22
22
  async createProject(options) {
23
23
  const projectResult = await sdk.createProject({
24
24
  name: options.name,
25
+ region: options.region,
25
26
  signal: options.signal
26
27
  });
27
28
  if (projectResult.isErr()) throw new Error(projectResult.error.message);
28
29
  return {
29
30
  id: projectResult.value.id,
30
- name: projectResult.value.name
31
+ name: projectResult.value.name,
32
+ defaultRegion: projectResult.value.defaultRegion
31
33
  };
32
34
  },
33
35
  async listApps(projectId, options) {
@@ -0,0 +1,139 @@
1
+ import { CliError } from "../../shell/errors.js";
2
+ //#region src/lib/bucket/provider.ts
3
+ function createManagementBucketProvider(client) {
4
+ return {
5
+ async listBuckets(options) {
6
+ const buckets = [];
7
+ let cursor;
8
+ while (true) {
9
+ const result = await client.GET("/v1/buckets", {
10
+ params: { query: {
11
+ projectId: options.projectId,
12
+ branchGitName: options.branchName,
13
+ cursor
14
+ } },
15
+ signal: options.signal
16
+ });
17
+ if (result.error || !result.data) throw bucketApiError("Failed to list buckets", result.response, result.error);
18
+ const data = result.data;
19
+ buckets.push(...data.data);
20
+ if (!data.pagination.hasMore || !data.pagination.nextCursor) break;
21
+ cursor = data.pagination.nextCursor;
22
+ }
23
+ return buckets.map(normalizeBucket);
24
+ },
25
+ async createBucket(options) {
26
+ const result = await client.POST("/v1/buckets", {
27
+ body: {
28
+ projectId: options.projectId,
29
+ ...options.name ? { name: options.name } : {},
30
+ ...options.branchGitName ? { branchGitName: options.branchGitName } : {}
31
+ },
32
+ signal: options.signal
33
+ });
34
+ if (result.error || !result.data) throw bucketApiError("Failed to create bucket", result.response, result.error);
35
+ const data = result.data;
36
+ return normalizeBucket(data.data);
37
+ },
38
+ async deleteBucket(bucketId, options) {
39
+ const result = await client.DELETE("/v1/buckets/{bucketId}", {
40
+ params: { path: { bucketId } },
41
+ signal: options?.signal
42
+ });
43
+ if (result.error) throw bucketApiError("Failed to delete bucket", result.response, result.error);
44
+ },
45
+ async listKeys(bucketId, options) {
46
+ const keys = [];
47
+ let cursor;
48
+ while (true) {
49
+ const result = await client.GET("/v1/buckets/{bucketId}/keys", {
50
+ params: {
51
+ path: { bucketId },
52
+ query: { cursor }
53
+ },
54
+ signal: options?.signal
55
+ });
56
+ if (result.error || !result.data) throw bucketApiError("Failed to list bucket keys", result.response, result.error);
57
+ const data = result.data;
58
+ keys.push(...data.data);
59
+ if (!data.pagination.hasMore || !data.pagination.nextCursor) break;
60
+ cursor = data.pagination.nextCursor;
61
+ }
62
+ return keys.map(normalizeKey);
63
+ },
64
+ async createKey(options) {
65
+ const result = await client.POST("/v1/buckets/{bucketId}/keys", {
66
+ params: { path: { bucketId: options.bucketId } },
67
+ body: {
68
+ role: options.role,
69
+ ...options.name ? { name: options.name } : {}
70
+ },
71
+ signal: options.signal
72
+ });
73
+ if (result.error || !result.data) throw bucketApiError("Failed to create bucket key", result.response, result.error);
74
+ const raw = result.data.data;
75
+ const secretAccessKey = raw.secretAccessKey;
76
+ const accessKeyId = raw.accessKeyId;
77
+ const endpoint = raw.endpoint;
78
+ const bucketName = raw.bucketName;
79
+ if (!secretAccessKey || !accessKeyId || !endpoint || !bucketName) throw new CliError({
80
+ code: "BUCKET_KEY_SECRET_MISSING",
81
+ domain: "bucket",
82
+ summary: "Created bucket key did not return credentials",
83
+ why: "Bucket key credentials are one-time-view secrets, but the Management API did not include them in this create response.",
84
+ fix: "Create another bucket key and store the returned credentials immediately.",
85
+ exitCode: 1,
86
+ nextSteps: [`prisma-cli bucket key create ${options.bucketId}`]
87
+ });
88
+ return {
89
+ key: normalizeKey(raw),
90
+ secretAccessKey,
91
+ accessKeyId,
92
+ endpoint,
93
+ bucketName
94
+ };
95
+ },
96
+ async deleteKey(bucketId, keyId, options) {
97
+ const result = await client.DELETE("/v1/buckets/{bucketId}/keys/{keyId}", {
98
+ params: { path: {
99
+ bucketId,
100
+ keyId
101
+ } },
102
+ signal: options?.signal
103
+ });
104
+ if (result.error) throw bucketApiError("Failed to delete bucket key", result.response, result.error);
105
+ }
106
+ };
107
+ }
108
+ function normalizeBucket(raw) {
109
+ return {
110
+ id: raw.id,
111
+ name: raw.name,
112
+ status: raw.status,
113
+ branchId: raw.branchId,
114
+ createdAt: raw.createdAt
115
+ };
116
+ }
117
+ function normalizeKey(raw) {
118
+ return {
119
+ id: raw.id,
120
+ name: raw.name,
121
+ role: raw.role,
122
+ valueHint: raw.valueHint,
123
+ createdAt: raw.createdAt
124
+ };
125
+ }
126
+ function bucketApiError(summary, response, error) {
127
+ const status = response?.status ?? 0;
128
+ return new CliError({
129
+ code: error?.error?.code ?? "BUCKET_API_ERROR",
130
+ domain: "bucket",
131
+ summary,
132
+ why: error?.error?.message ?? `The Management API returned status ${status || "unknown"}.`,
133
+ fix: error?.error?.hint ?? "Re-run with --trace for the underlying API response details.",
134
+ exitCode: 1,
135
+ nextSteps: []
136
+ });
137
+ }
138
+ //#endregion
139
+ export { createManagementBucketProvider, normalizeBucket, normalizeKey };
@@ -379,7 +379,8 @@ function toProjectSummary(project) {
379
379
  return {
380
380
  id: project.id,
381
381
  name: project.name,
382
- ...project.url ? { url: project.url } : {}
382
+ ...project.url ? { url: project.url } : {},
383
+ ...project.defaultRegion != null ? { defaultRegion: project.defaultRegion } : {}
383
384
  };
384
385
  }
385
386
  //#endregion
@@ -82,7 +82,8 @@ function toProjectSummary(project) {
82
82
  return {
83
83
  id: project.id,
84
84
  name: project.name,
85
- ...project.url ? { url: project.url } : {}
85
+ ...project.url ? { url: project.url } : {},
86
+ ...project.defaultRegion != null ? { defaultRegion: project.defaultRegion } : {}
86
87
  };
87
88
  }
88
89
  function projectSetupNameRequiredError(command) {
@@ -48,6 +48,11 @@ function renderAppDeploy(context, descriptor, result, options) {
48
48
  label: "Logs",
49
49
  value: logsCommand
50
50
  },
51
+ ...result.deploySettings.region && result.deploySettings.regionSource === null ? [{
52
+ label: "Region",
53
+ value: result.deploySettings.region,
54
+ origin: result.project.defaultRegion != null ? "project default" : "platform default — pass --region to choose"
55
+ }] : [],
51
56
  ...deployUsedComputeConfig(result) ? [] : [{
52
57
  label: "Config",
53
58
  value: resolvePrismaCliPackageCommandSync(context.runtime.cwd, ["init"])
@@ -0,0 +1,174 @@
1
+ import { formatDescriptorLabel } from "../shell/command-meta.js";
2
+ import { formatColumns, renderSummaryLine } from "../shell/ui.js";
3
+ import { renderMutate, serializeList } from "../output/patterns.js";
4
+ import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
5
+ //#region src/presenters/bucket.ts
6
+ function renderBucketList(context, descriptor, result) {
7
+ const ui = context.ui;
8
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing object-store buckets for the resolved project.")}`, ""];
9
+ const rail = ui.dim("│");
10
+ lines.push(`${rail} ${ui.accent("project:")} ${result.projectName}`);
11
+ if (result.branchName) lines.push(`${rail} ${ui.accent("branch:")} ${result.branchName}`);
12
+ lines.push(rail);
13
+ if (result.buckets.length === 0) {
14
+ lines.push(`${rail} ${ui.dim("No buckets found.")}`);
15
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
16
+ return lines;
17
+ }
18
+ const rows = result.buckets.map((bucket) => [
19
+ bucket.name,
20
+ bucket.id,
21
+ bucket.status,
22
+ bucket.branchId ?? "unscoped",
23
+ bucket.createdAt
24
+ ]);
25
+ const widths = [
26
+ Math.max(4, ...rows.map((row) => row[0].length)),
27
+ Math.max(2, ...rows.map((row) => row[1].length)),
28
+ Math.max(6, ...rows.map((row) => row[2].length)),
29
+ Math.max(6, ...rows.map((row) => row[3].length)),
30
+ Math.max(7, ...rows.map((row) => row[4].length))
31
+ ];
32
+ lines.push(`${rail} ${ui.accent(formatColumns([
33
+ "Name",
34
+ "Id",
35
+ "Status",
36
+ "Branch",
37
+ "Created"
38
+ ], widths))}`);
39
+ for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
40
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
41
+ return lines;
42
+ }
43
+ function serializeBucketList(result) {
44
+ return {
45
+ context: {
46
+ project: result.projectName,
47
+ ...result.branchName ? { branch: result.branchName } : {}
48
+ },
49
+ items: result.buckets.map((bucket) => ({
50
+ name: bucket.name,
51
+ id: bucket.id,
52
+ status: bucket.status
53
+ })),
54
+ count: result.buckets.length,
55
+ projectId: result.projectId,
56
+ branchName: result.branchName,
57
+ buckets: result.buckets
58
+ };
59
+ }
60
+ function renderBucketCreate(context, _descriptor, result) {
61
+ const ui = context.ui;
62
+ return ["Creating bucket...", renderSummaryLine(ui, "success", `Created bucket "${result.bucket.name}" in ${formatBucketTarget(result.projectName, result.bucket.branchId)}.`)];
63
+ }
64
+ function serializeBucketCreate(result) {
65
+ return stripVerboseContext(result);
66
+ }
67
+ function renderBucketDelete(context, descriptor, result) {
68
+ return renderMutate({
69
+ title: "Deleting object-store bucket.",
70
+ descriptor,
71
+ context: [{
72
+ key: "bucket",
73
+ value: result.bucket.id,
74
+ tone: "dim"
75
+ }],
76
+ operationDescription: "Deleting bucket",
77
+ operationCount: 1,
78
+ details: ["Bucket and all its access keys were removed."]
79
+ }, context.ui);
80
+ }
81
+ function serializeBucketDelete(result) {
82
+ return { bucket: result.bucket };
83
+ }
84
+ function renderBucketKeyList(context, descriptor, result) {
85
+ const ui = context.ui;
86
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing access keys for bucket.")}`, ""];
87
+ const rail = ui.dim("│");
88
+ lines.push(`${rail} ${ui.accent("bucket:")} ${result.bucketId}`);
89
+ lines.push(rail);
90
+ if (result.keys.length === 0) {
91
+ lines.push(`${rail} ${ui.dim("No keys found.")}`);
92
+ return lines;
93
+ }
94
+ const rows = result.keys.map((key) => [
95
+ key.name,
96
+ key.id,
97
+ key.role,
98
+ key.valueHint,
99
+ key.createdAt
100
+ ]);
101
+ const widths = [
102
+ Math.max(4, ...rows.map((row) => row[0].length)),
103
+ Math.max(2, ...rows.map((row) => row[1].length)),
104
+ Math.max(4, ...rows.map((row) => row[2].length)),
105
+ Math.max(4, ...rows.map((row) => row[3].length)),
106
+ Math.max(7, ...rows.map((row) => row[4].length))
107
+ ];
108
+ lines.push(`${rail} ${ui.accent(formatColumns([
109
+ "Name",
110
+ "Id",
111
+ "Role",
112
+ "Hint",
113
+ "Created"
114
+ ], widths))}`);
115
+ for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
116
+ return lines;
117
+ }
118
+ function serializeBucketKeyList(result) {
119
+ return {
120
+ ...serializeList({
121
+ context: { bucket: result.bucketId },
122
+ items: result.keys.map((key) => ({
123
+ noun: "key",
124
+ label: key.name,
125
+ id: key.id,
126
+ status: null
127
+ }))
128
+ }),
129
+ bucketId: result.bucketId,
130
+ keys: result.keys
131
+ };
132
+ }
133
+ function renderBucketKeyCreateStdout(_context, _descriptor, result) {
134
+ return [
135
+ `S3_ENDPOINT=${result.endpoint}`,
136
+ `S3_ACCESS_KEY_ID=${result.accessKeyId}`,
137
+ `S3_SECRET_ACCESS_KEY=${result.secretAccessKey}`,
138
+ `S3_BUCKET=${result.bucketName}`
139
+ ];
140
+ }
141
+ function renderBucketKeyCreate(context, _descriptor, result) {
142
+ const ui = context.ui;
143
+ return [
144
+ "Creating bucket key...",
145
+ renderSummaryLine(ui, "success", `Created key "${result.key.name}" for bucket "${result.bucketName}".`),
146
+ " The credentials below are shown once — copy them now.",
147
+ " Set these environment variables to use this bucket:"
148
+ ];
149
+ }
150
+ function serializeBucketKeyCreate(result) {
151
+ return result;
152
+ }
153
+ function renderBucketKeyDelete(context, descriptor, result) {
154
+ return renderMutate({
155
+ title: "Deleting bucket access key.",
156
+ descriptor,
157
+ context: [{
158
+ key: "key",
159
+ value: result.key.id,
160
+ tone: "dim"
161
+ }],
162
+ operationDescription: "Deleting bucket key",
163
+ operationCount: 1,
164
+ details: ["The access key was revoked and removed."]
165
+ }, context.ui);
166
+ }
167
+ function serializeBucketKeyDelete(result) {
168
+ return { key: result.key };
169
+ }
170
+ function formatBucketTarget(projectName, branchId) {
171
+ return branchId ? `${projectName} / ${branchId}` : projectName;
172
+ }
173
+ //#endregion
174
+ export { renderBucketCreate, renderBucketDelete, renderBucketKeyCreate, renderBucketKeyCreateStdout, renderBucketKeyDelete, renderBucketKeyList, renderBucketList, serializeBucketCreate, serializeBucketDelete, serializeBucketKeyCreate, serializeBucketKeyDelete, serializeBucketKeyList, serializeBucketList };
@@ -17,9 +17,13 @@ function renderProjectList(context, descriptor, result) {
17
17
  return lines;
18
18
  }
19
19
  const nameWidth = Math.max(4, ...result.projects.map((project) => stringWidth(project.name)));
20
+ const idWidth = Math.max(2, ...result.projects.map((project) => project.id.length));
20
21
  lines.push(rail);
21
- lines.push(`${rail} ${ui.accent(padDisplay("name", nameWidth))} ${ui.accent("id")}`);
22
- for (const project of result.projects) lines.push(`${rail} ${padDisplay(project.name, nameWidth)} ${project.id}`);
22
+ lines.push(`${rail} ${ui.accent(padDisplay("name", nameWidth))} ${ui.accent(padDisplay("id", idWidth))} ${ui.accent("region")}`);
23
+ for (const project of result.projects) {
24
+ const region = project.defaultRegion ? project.defaultRegion : ui.dim("none");
25
+ lines.push(`${rail} ${padDisplay(project.name, nameWidth)} ${padDisplay(project.id, idWidth)} ${region}`);
26
+ }
23
27
  if (result.localBinding?.status === "not-linked" || result.localBinding?.status === "invalid") lines.push(...renderNextSteps(["Link an existing Project you choose: prisma-cli project link <id-or-name>", "Create a new Project: prisma-cli project create <name>"]));
24
28
  return lines;
25
29
  }
@@ -241,6 +245,7 @@ function renderBoundProjectShow(context, descriptor, result) {
241
245
  lines.push(rail);
242
246
  lines.push(`${rail} ${ui.dim("→")} ${ui.link(result.project.url)}`);
243
247
  }
248
+ if (result.project.defaultRegion) lines.push(`${rail} ${ui.accent(padDisplay("region", keyWidth))} ${ui.dim(result.project.defaultRegion)}`);
244
249
  lines.push(...renderResolvedProjectContextBlock(context.ui, {
245
250
  workspace: result.workspace,
246
251
  project: result.project,
@@ -249,6 +249,105 @@ const DESCRIPTORS = [
249
249
  "prisma-cli database connection create db_123"
250
250
  ]
251
251
  },
252
+ {
253
+ id: "bucket",
254
+ path: ["prisma", "bucket"],
255
+ description: "Manage object-store buckets for a project",
256
+ examples: [
257
+ "prisma-cli bucket list",
258
+ "prisma-cli bucket create",
259
+ "prisma-cli bucket key create bkt_123"
260
+ ]
261
+ },
262
+ {
263
+ id: "bucket.list",
264
+ path: [
265
+ "prisma",
266
+ "bucket",
267
+ "list"
268
+ ],
269
+ description: "List object-store buckets for the resolved project",
270
+ examples: [
271
+ "prisma-cli bucket list",
272
+ "prisma-cli bucket list --branch preview",
273
+ "prisma-cli bucket list --json"
274
+ ]
275
+ },
276
+ {
277
+ id: "bucket.create",
278
+ path: [
279
+ "prisma",
280
+ "bucket",
281
+ "create"
282
+ ],
283
+ description: "Create an object-store bucket",
284
+ examples: [
285
+ "prisma-cli bucket create",
286
+ "prisma-cli bucket create --name my-store",
287
+ "prisma-cli bucket create --branch preview --json"
288
+ ]
289
+ },
290
+ {
291
+ id: "bucket.delete",
292
+ path: [
293
+ "prisma",
294
+ "bucket",
295
+ "delete"
296
+ ],
297
+ description: "Delete a bucket and all its access keys",
298
+ examples: ["prisma-cli bucket delete bkt_123"]
299
+ },
300
+ {
301
+ id: "bucket.key",
302
+ path: [
303
+ "prisma",
304
+ "bucket",
305
+ "key"
306
+ ],
307
+ description: "Manage access keys for an object-store bucket",
308
+ examples: [
309
+ "prisma-cli bucket key list bkt_123",
310
+ "prisma-cli bucket key create bkt_123",
311
+ "prisma-cli bucket key delete bkt_123 bkey_456"
312
+ ]
313
+ },
314
+ {
315
+ id: "bucket.key.list",
316
+ path: [
317
+ "prisma",
318
+ "bucket",
319
+ "key",
320
+ "list"
321
+ ],
322
+ description: "List access keys for a bucket",
323
+ examples: ["prisma-cli bucket key list bkt_123", "prisma-cli bucket key list bkt_123 --json"]
324
+ },
325
+ {
326
+ id: "bucket.key.create",
327
+ path: [
328
+ "prisma",
329
+ "bucket",
330
+ "key",
331
+ "create"
332
+ ],
333
+ description: "Create a bucket access key and print its one-time credentials",
334
+ examples: [
335
+ "prisma-cli bucket key create bkt_123",
336
+ "prisma-cli bucket key create bkt_123 --role read",
337
+ "prisma-cli bucket key create bkt_123 --name ci-key --role read_write"
338
+ ]
339
+ },
340
+ {
341
+ id: "bucket.key.delete",
342
+ path: [
343
+ "prisma",
344
+ "bucket",
345
+ "key",
346
+ "delete"
347
+ ],
348
+ description: "Revoke and delete a bucket access key",
349
+ examples: ["prisma-cli bucket key delete bkt_123 bkey_456"]
350
+ },
252
351
  {
253
352
  id: "git",
254
353
  path: ["prisma", "git"],
@@ -23,7 +23,8 @@ function toProjectSummary(project) {
23
23
  return {
24
24
  id: project.id,
25
25
  name: project.name,
26
- ...project.url ? { url: project.url } : {}
26
+ ...project.url ? { url: project.url } : {},
27
+ ...project.defaultRegion != null ? { defaultRegion: project.defaultRegion } : {}
27
28
  };
28
29
  }
29
30
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.127.1",
3
+ "version": "3.0.0-dev.131.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,7 +46,7 @@
46
46
  "@clack/prompts": "^1.5.0",
47
47
  "@prisma/compute-sdk": "0.34.0",
48
48
  "@prisma/credentials-store": "^7.8.0",
49
- "@prisma/management-api-sdk": "^1.46.0",
49
+ "@prisma/management-api-sdk": "^1.50.0",
50
50
  "better-result": "^2.9.2",
51
51
  "colorette": "^2.0.20",
52
52
  "commander": "^14.0.3",
@@ -1,5 +0,0 @@
1
- import "../../shell/prompt.js";
2
- //#region src/lib/app/app-interaction.ts
3
- const DEFAULT_REGION = "eu-central-1";
4
- //#endregion
5
- export { DEFAULT_REGION };