@prisma/cli 3.0.0-dev.112.1 → 3.0.0-dev.115.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.
@@ -236,6 +236,180 @@ function renderDatabaseConnectionRemove(context, descriptor, result) {
236
236
  function serializeDatabaseConnectionRemove(result) {
237
237
  return { connection: result.connection };
238
238
  }
239
+ function renderDatabaseUsage(context, descriptor, result) {
240
+ const lines = renderShow({
241
+ title: "Showing database usage metrics.",
242
+ descriptor,
243
+ fields: [
244
+ {
245
+ key: "project",
246
+ value: result.projectName
247
+ },
248
+ {
249
+ key: "database",
250
+ value: result.database.name
251
+ },
252
+ {
253
+ key: "id",
254
+ value: result.database.id,
255
+ tone: "dim"
256
+ },
257
+ {
258
+ key: "period",
259
+ value: `${formatUsageTimestamp(result.period.start)} to ${formatUsageTimestamp(result.period.end)}`
260
+ },
261
+ {
262
+ key: "operations",
263
+ value: `${result.metrics.operations.used} ${result.metrics.operations.unit}`
264
+ },
265
+ {
266
+ key: "storage",
267
+ value: `${result.metrics.storage.used} ${result.metrics.storage.unit}`
268
+ },
269
+ {
270
+ key: "generated",
271
+ value: formatUsageTimestamp(result.generatedAt),
272
+ tone: "dim"
273
+ }
274
+ ]
275
+ }, context.ui);
276
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
277
+ return lines;
278
+ }
279
+ function serializeDatabaseUsage(result) {
280
+ return stripVerboseContext(result);
281
+ }
282
+ function renderDatabaseBackupList(context, descriptor, result) {
283
+ const ui = context.ui;
284
+ const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing platform-created database backups.")}`, ""];
285
+ const rail = ui.dim("│");
286
+ lines.push(`${rail} ${ui.accent("database:")} ${result.database.name}`);
287
+ if (result.retentionDays !== null) lines.push(`${rail} ${ui.accent("retention:")} ${result.retentionDays} days`);
288
+ lines.push(rail);
289
+ if (result.backups.length === 0) {
290
+ lines.push(`${rail} ${ui.dim("No backups found.")}`);
291
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
292
+ return lines;
293
+ }
294
+ const rows = result.backups.map((backup) => [
295
+ backup.id,
296
+ backup.backupType,
297
+ backup.status,
298
+ formatBackupSize(backup.size),
299
+ backup.createdAt
300
+ ]);
301
+ const widths = [
302
+ Math.max(2, ...rows.map((row) => row[0].length)),
303
+ Math.max(4, ...rows.map((row) => row[1].length)),
304
+ Math.max(6, ...rows.map((row) => row[2].length)),
305
+ Math.max(4, ...rows.map((row) => row[3].length)),
306
+ Math.max(7, ...rows.map((row) => row[4].length))
307
+ ];
308
+ lines.push(`${rail} ${ui.accent(formatColumns([
309
+ "Id",
310
+ "Type",
311
+ "Status",
312
+ "Size",
313
+ "Created"
314
+ ], widths))}`);
315
+ for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
316
+ if (result.hasMore) {
317
+ lines.push(rail);
318
+ lines.push(`${rail} ${ui.dim("More backups exist; raise --limit to see them.")}`);
319
+ }
320
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
321
+ return lines;
322
+ }
323
+ function serializeDatabaseBackupList(result) {
324
+ return {
325
+ ...serializeList({
326
+ context: {
327
+ project: result.projectName,
328
+ database: result.database.name
329
+ },
330
+ items: result.backups.map((backup) => ({
331
+ noun: "backup",
332
+ label: backup.id,
333
+ id: backup.id,
334
+ status: null
335
+ }))
336
+ }),
337
+ projectId: result.projectId,
338
+ database: result.database,
339
+ backups: result.backups,
340
+ retentionDays: result.retentionDays,
341
+ hasMore: result.hasMore
342
+ };
343
+ }
344
+ function renderDatabaseRestore(context, descriptor, result) {
345
+ const lines = renderMutate({
346
+ title: "Restoring database from backup.",
347
+ descriptor,
348
+ context: [
349
+ {
350
+ key: "project",
351
+ value: result.projectName
352
+ },
353
+ {
354
+ key: "database",
355
+ value: result.database.name
356
+ },
357
+ {
358
+ key: "id",
359
+ value: result.database.id,
360
+ tone: "dim"
361
+ },
362
+ {
363
+ key: "backup",
364
+ value: result.source.backupId
365
+ },
366
+ ...result.source.databaseId !== result.database.id ? [{
367
+ key: "source",
368
+ value: result.source.databaseId
369
+ }] : []
370
+ ],
371
+ operationDescription: "Restoring database",
372
+ operationCount: 1,
373
+ details: [`The restore is running; the database status is "${result.database.status ?? "recovering"}" until it completes.`, "Connections and credentials are preserved."]
374
+ }, context.ui);
375
+ lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
376
+ return lines;
377
+ }
378
+ function serializeDatabaseRestore(result) {
379
+ return stripVerboseContext(result);
380
+ }
381
+ function renderDatabaseConnectionRotateStdout(_context, _descriptor, result) {
382
+ return [result.connectionString];
383
+ }
384
+ function renderDatabaseConnectionRotate(context, _descriptor, result) {
385
+ const ui = context.ui;
386
+ const lines = [
387
+ "Rotating connection...",
388
+ renderSummaryLine(ui, "success", `Rotated credentials for ${result.database ? `"${result.database.name}"` : `connection ${result.connection.id}`}. The previous credentials no longer work.`),
389
+ " The connection URL below is shown once, so save it now."
390
+ ];
391
+ if (ui.verbose) {
392
+ lines.push("");
393
+ lines.push(...renderDatabaseConnectionRotateVerboseRows(context, result));
394
+ }
395
+ return lines;
396
+ }
397
+ function serializeDatabaseConnectionRotate(result) {
398
+ return result;
399
+ }
400
+ function renderDatabaseConnectionRotateVerboseRows(context, result) {
401
+ return renderMetadataRows([...result.database ? [["database", formatResourceWithId(context, result.database.name, result.database.id)]] : [], ["connection", formatResourceWithId(context, result.connection.name, result.connection.id)]]);
402
+ }
403
+ function formatBackupSize(size) {
404
+ if (size === null) return "unknown";
405
+ if (size < 1024) return `${size} B`;
406
+ if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KiB`;
407
+ if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)} MiB`;
408
+ return `${(size / (1024 * 1024 * 1024)).toFixed(1)} GiB`;
409
+ }
410
+ function formatUsageTimestamp(value) {
411
+ return value || "unknown";
412
+ }
239
413
  function formatStatus(database) {
240
414
  return database.status ?? (database.isDefault ? "default" : "unknown");
241
415
  }
@@ -271,4 +445,4 @@ function renderMetadataRows(rows) {
271
445
  return rows.map(([key, value]) => ` ${formatColumns([key, value], widths)}`);
272
446
  }
273
447
  //#endregion
274
- export { renderDatabaseConnectionCreate, renderDatabaseConnectionCreateStdout, renderDatabaseConnectionList, renderDatabaseConnectionRemove, renderDatabaseCreate, renderDatabaseCreateStdout, renderDatabaseList, renderDatabaseRemove, renderDatabaseShow, serializeDatabaseConnectionCreate, serializeDatabaseConnectionList, serializeDatabaseConnectionRemove, serializeDatabaseCreate, serializeDatabaseList, serializeDatabaseRemove, serializeDatabaseShow };
448
+ export { renderDatabaseBackupList, renderDatabaseConnectionCreate, renderDatabaseConnectionCreateStdout, renderDatabaseConnectionList, renderDatabaseConnectionRemove, renderDatabaseConnectionRotate, renderDatabaseConnectionRotateStdout, renderDatabaseCreate, renderDatabaseCreateStdout, renderDatabaseList, renderDatabaseRemove, renderDatabaseRestore, renderDatabaseShow, renderDatabaseUsage, serializeDatabaseBackupList, serializeDatabaseConnectionCreate, serializeDatabaseConnectionList, serializeDatabaseConnectionRemove, serializeDatabaseConnectionRotate, serializeDatabaseCreate, serializeDatabaseList, serializeDatabaseRemove, serializeDatabaseRestore, serializeDatabaseShow, serializeDatabaseUsage };
@@ -86,6 +86,95 @@ function renderProjectSetup(context, _descriptor, result) {
86
86
  function serializeProjectSetup(result) {
87
87
  return result;
88
88
  }
89
+ function renderProjectRename(context, descriptor, result) {
90
+ return renderMutate({
91
+ title: "Renaming project.",
92
+ descriptor,
93
+ context: [
94
+ {
95
+ key: "workspace",
96
+ value: result.workspace.name
97
+ },
98
+ {
99
+ key: "project",
100
+ value: result.previousName
101
+ },
102
+ {
103
+ key: "id",
104
+ value: result.project.id,
105
+ tone: "dim"
106
+ }
107
+ ],
108
+ operationDescription: "Renaming project",
109
+ operationCount: 1,
110
+ details: [`The project is now named "${result.project.name}". Directory bindings pin the project id, so they stay valid.`]
111
+ }, context.ui);
112
+ }
113
+ function serializeProjectRename(result) {
114
+ return result;
115
+ }
116
+ function renderProjectRemove(context, descriptor, result) {
117
+ return renderMutate({
118
+ title: "Removing project.",
119
+ descriptor,
120
+ context: [
121
+ {
122
+ key: "workspace",
123
+ value: result.workspace.name
124
+ },
125
+ {
126
+ key: "project",
127
+ value: result.project.name
128
+ },
129
+ {
130
+ key: "id",
131
+ value: result.project.id,
132
+ tone: "dim"
133
+ }
134
+ ],
135
+ operationDescription: "Removing project",
136
+ operationCount: 1,
137
+ details: ["The project, its databases, and its apps were removed.", ...result.localPin.cleared ? ["This directory's local project binding was cleared."] : []]
138
+ }, context.ui);
139
+ }
140
+ function serializeProjectRemove(result) {
141
+ return result;
142
+ }
143
+ function renderProjectTransfer(context, descriptor, result) {
144
+ return renderMutate({
145
+ title: "Transferring project.",
146
+ descriptor,
147
+ context: [
148
+ {
149
+ key: "workspace",
150
+ value: result.workspace.name
151
+ },
152
+ {
153
+ key: "project",
154
+ value: result.project.name
155
+ },
156
+ {
157
+ key: "id",
158
+ value: result.project.id,
159
+ tone: "dim"
160
+ },
161
+ {
162
+ key: "recipient",
163
+ value: result.recipient.workspaceName ?? result.recipient.workspaceId ?? "workspace of the provided recipient token"
164
+ }
165
+ ],
166
+ operationDescription: "Transferring project",
167
+ operationCount: 1,
168
+ details: [
169
+ "The project now belongs to the recipient workspace; this workspace no longer has access.",
170
+ ...result.localPin.action === "rewritten" ? ["This directory's local project binding now points at the recipient workspace."] : [],
171
+ ...result.localPin.action === "cleared" ? ["This directory's local project binding was cleared."] : []
172
+ ]
173
+ }, context.ui);
174
+ }
175
+ function serializeProjectTransfer(result) {
176
+ return result;
177
+ }
89
178
  function renderGitConnect(context, descriptor, result) {
90
179
  const connection = result.repositoryConnection;
91
180
  return renderMutate({
@@ -171,4 +260,4 @@ function formatGitConnectionDetail(status) {
171
260
  }
172
261
  }
173
262
  //#endregion
174
- export { renderGitConnect, renderGitDisconnect, renderProjectList, renderProjectSetup, renderProjectShow, serializeProjectList, serializeProjectSetup, serializeProjectShow };
263
+ export { renderGitConnect, renderGitDisconnect, renderProjectList, renderProjectRemove, renderProjectRename, renderProjectSetup, renderProjectShow, renderProjectTransfer, serializeProjectList, serializeProjectRemove, serializeProjectRename, serializeProjectSetup, serializeProjectShow, serializeProjectTransfer };
@@ -271,6 +271,36 @@ const DESCRIPTORS = [
271
271
  "prisma-cli project link \"Acme Dashboard\" --json"
272
272
  ]
273
273
  },
274
+ {
275
+ id: "project.rename",
276
+ path: [
277
+ "prisma",
278
+ "project",
279
+ "rename"
280
+ ],
281
+ description: "Rename the resolved Project",
282
+ examples: ["prisma-cli project rename \"Acme Dashboard v2\"", "prisma-cli project rename billing-api --project proj_123"]
283
+ },
284
+ {
285
+ id: "project.remove",
286
+ path: [
287
+ "prisma",
288
+ "project",
289
+ "remove"
290
+ ],
291
+ description: "Remove a Project permanently after exact id confirmation",
292
+ examples: ["prisma-cli project remove proj_123 --confirm proj_123"]
293
+ },
294
+ {
295
+ id: "project.transfer",
296
+ path: [
297
+ "prisma",
298
+ "project",
299
+ "transfer"
300
+ ],
301
+ description: "Transfer a Project to another workspace after exact id confirmation",
302
+ examples: ["prisma-cli project transfer proj_123 --to-workspace \"Prisma Labs\" --confirm proj_123", "prisma-cli project transfer proj_123 --recipient-token <token> --confirm proj_123"]
303
+ },
274
304
  {
275
305
  id: "git.connect",
276
306
  path: [
@@ -339,6 +369,26 @@ const DESCRIPTORS = [
339
369
  description: "Create a Prisma Postgres database and print its one-time connection URL",
340
370
  examples: ["prisma-cli database create my-db", "prisma-cli database create my-db --branch feature/foo --region eu-central-1"]
341
371
  },
372
+ {
373
+ id: "database.usage",
374
+ path: [
375
+ "prisma",
376
+ "database",
377
+ "usage"
378
+ ],
379
+ description: "Show usage metrics for a database",
380
+ examples: ["prisma-cli database usage db_123", "prisma-cli database usage acme-production --from 2026-06-01 --to 2026-06-30"]
381
+ },
382
+ {
383
+ id: "database.restore",
384
+ path: [
385
+ "prisma",
386
+ "database",
387
+ "restore"
388
+ ],
389
+ description: "Restore a database from a backup after exact id confirmation",
390
+ examples: ["prisma-cli database restore db_123 --backup bkp_456 --confirm db_123"]
391
+ },
342
392
  {
343
393
  id: "database.remove",
344
394
  path: [
@@ -349,6 +399,27 @@ const DESCRIPTORS = [
349
399
  description: "Remove a database after exact id confirmation",
350
400
  examples: ["prisma-cli database remove db_123 --confirm db_123"]
351
401
  },
402
+ {
403
+ id: "database.backup",
404
+ path: [
405
+ "prisma",
406
+ "database",
407
+ "backup"
408
+ ],
409
+ description: "Inspect platform-created database backups",
410
+ examples: ["prisma-cli database backup list db_123"]
411
+ },
412
+ {
413
+ id: "database.backup.list",
414
+ path: [
415
+ "prisma",
416
+ "database",
417
+ "backup",
418
+ "list"
419
+ ],
420
+ description: "List backups for a database",
421
+ examples: ["prisma-cli database backup list db_123", "prisma-cli database backup list acme-production --limit 50"]
422
+ },
352
423
  {
353
424
  id: "database.connection",
354
425
  path: [
@@ -385,6 +456,17 @@ const DESCRIPTORS = [
385
456
  description: "Create a database connection and print its one-time connection URL",
386
457
  examples: ["prisma-cli database connection create db_123", "prisma-cli database connection create db_123 --name readonly"]
387
458
  },
459
+ {
460
+ id: "database.connection.rotate",
461
+ path: [
462
+ "prisma",
463
+ "database",
464
+ "connection",
465
+ "rotate"
466
+ ],
467
+ description: "Rotate connection credentials and print the new one-time connection URL",
468
+ examples: ["prisma-cli database connection rotate conn_123 --confirm conn_123"]
469
+ },
388
470
  {
389
471
  id: "database.connection.remove",
390
472
  path: [
@@ -1,5 +1,6 @@
1
1
  import { CliError, authConfigInvalidError, authRequiredError, commandCanceledError } from "./errors.js";
2
2
  import { getCommandDescriptor } from "./command-meta.js";
3
+ import { renderSummaryLine } from "./ui.js";
3
4
  import { resolveGlobalFlags } from "./global-flags.js";
4
5
  import { createCommandContext } from "./runtime.js";
5
6
  import { collectCommandDiagnostics } from "../lib/diagnostics.js";
@@ -48,11 +49,16 @@ async function writeCommandSuccess(context, descriptor, success, presenter, dura
48
49
  return;
49
50
  }
50
51
  const rendered = presenter.renderHuman(context, descriptor, success.result);
52
+ const warningLines = success.warnings.map((warning) => renderSummaryLine(context.ui, "warning", warning));
51
53
  const diagnostics = await renderBestEffortCommandDiagnostics(context, {
52
54
  enabled: context.flags.verbose && rendered.length > 0,
53
55
  durationMs
54
56
  });
55
- const humanLines = [...rendered, ...diagnostics];
57
+ const humanLines = [
58
+ ...rendered,
59
+ ...warningLines,
60
+ ...diagnostics
61
+ ];
56
62
  if (stdout.length > 0 && humanLines.length > 0) humanLines.push("");
57
63
  writeHumanLines(context.output, humanLines);
58
64
  writeStdoutLines(context, stdout);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "3.0.0-dev.112.1",
3
+ "version": "3.0.0-dev.115.1",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {