@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.
- package/README.md +6 -15
- package/dist/adapters/local-state.js +15 -4
- package/dist/adapters/mock-api.js +244 -0
- package/dist/adapters/token-storage.js +335 -34
- package/dist/cli.js +7 -7
- package/dist/cli2.js +24 -5
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +91 -61
- package/dist/commands/auth/index.js +55 -2
- package/dist/commands/branch/index.js +2 -27
- package/dist/commands/bucket/index.js +123 -0
- package/dist/commands/build/index.js +29 -0
- package/dist/commands/database/index.js +249 -0
- package/dist/commands/env.js +8 -4
- package/dist/commands/feedback/index.js +20 -0
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/init/index.js +33 -0
- package/dist/commands/project/index.js +54 -5
- package/dist/controllers/agent-setup.js +52 -0
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app-env-api.js +55 -0
- package/dist/controllers/app-env-file.js +181 -0
- package/dist/controllers/app-env.js +227 -104
- package/dist/controllers/app.js +746 -306
- package/dist/controllers/auth.js +247 -3
- package/dist/controllers/branch.js +78 -48
- package/dist/controllers/bucket.js +278 -0
- package/dist/controllers/build.js +88 -0
- package/dist/controllers/database.js +567 -0
- package/dist/controllers/feedback.js +86 -0
- package/dist/controllers/init.js +753 -0
- package/dist/controllers/project.js +377 -22
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/lib/agent/cli-command.js +20 -0
- package/dist/lib/agent/constants.js +12 -0
- package/dist/lib/agent/package-manager.js +99 -0
- package/dist/lib/agent/setup-status.js +83 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +137 -88
- package/dist/lib/app/branch-database-api.js +102 -0
- package/dist/lib/app/branch-database-deploy.js +326 -0
- package/dist/lib/app/branch-database.js +216 -0
- package/dist/lib/app/build-settings.js +93 -0
- package/dist/lib/app/build.js +83 -0
- package/dist/lib/app/bun-project.js +3 -4
- package/dist/lib/app/compute-config.js +145 -0
- package/dist/lib/app/deploy-plan.js +59 -0
- package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
- package/dist/lib/app/env-config.js +1 -1
- package/dist/lib/app/env-file.js +82 -0
- package/dist/lib/app/env-vars.js +28 -2
- package/dist/lib/app/local-dev.js +3 -60
- package/dist/lib/app/production-deploy-gate.js +162 -0
- package/dist/lib/app/read-branch.js +30 -0
- package/dist/lib/auth/auth-ops.js +10 -4
- package/dist/lib/auth/guard.js +4 -1
- package/dist/lib/auth/login.js +33 -26
- package/dist/lib/auth/recipient.js +42 -0
- package/dist/lib/bucket/provider.js +139 -0
- package/dist/lib/database/provider.js +378 -0
- package/dist/lib/diagnostics.js +15 -0
- package/dist/lib/fs/home-path.js +24 -0
- package/dist/lib/git/local-branch.js +53 -0
- package/dist/lib/git/local-status.js +57 -0
- package/dist/lib/project/interactive-setup.js +5 -4
- package/dist/lib/project/local-pin.js +171 -41
- package/dist/lib/project/provider.js +92 -0
- package/dist/lib/project/resolution.js +199 -48
- package/dist/lib/project/setup.js +67 -20
- package/dist/output/patterns.js +1 -1
- package/dist/presenters/agent.js +74 -0
- package/dist/presenters/app-env.js +149 -14
- package/dist/presenters/app.js +208 -27
- package/dist/presenters/auth.js +99 -2
- package/dist/presenters/branch.js +37 -102
- package/dist/presenters/bucket.js +174 -0
- package/dist/presenters/database.js +448 -0
- package/dist/presenters/feedback.js +26 -0
- package/dist/presenters/init.js +30 -0
- package/dist/presenters/project.js +139 -27
- package/dist/presenters/verbose-context.js +64 -0
- package/dist/shell/cli-command.js +12 -0
- package/dist/shell/command-arguments.js +7 -1
- package/dist/shell/command-meta.js +458 -17
- package/dist/shell/command-runner.js +58 -18
- package/dist/shell/diagnostics-output.js +57 -0
- package/dist/shell/errors.js +56 -1
- package/dist/shell/help.js +31 -20
- package/dist/shell/output.js +72 -1
- package/dist/shell/prompt.js +12 -5
- package/dist/shell/runtime.js +8 -4
- package/dist/shell/ui.js +42 -3
- package/dist/shell/update-check.js +2 -2
- package/dist/use-cases/auth.js +68 -1
- package/dist/use-cases/branch.js +20 -68
- package/dist/use-cases/create-cli-gateways.js +2 -17
- package/dist/use-cases/project.js +2 -1
- package/package.json +21 -4
- package/dist/lib/app/preview-build.js +0 -312
- package/dist/lib/app/preview-interaction.js +0 -5
|
@@ -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 };
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
2
|
+
import { formatColumns, renderSummaryLine } from "../shell/ui.js";
|
|
3
|
+
import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
|
|
4
|
+
import { renderResolvedProjectContextBlock, stripVerboseContext } from "./verbose-context.js";
|
|
5
|
+
//#region src/presenters/database.ts
|
|
6
|
+
function renderDatabaseList(context, descriptor, result) {
|
|
7
|
+
const ui = context.ui;
|
|
8
|
+
const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing databases 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.databases.length === 0) {
|
|
14
|
+
lines.push(`${rail} ${ui.dim("No databases found.")}`);
|
|
15
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
16
|
+
return lines;
|
|
17
|
+
}
|
|
18
|
+
const rows = result.databases.map((database) => [
|
|
19
|
+
database.name,
|
|
20
|
+
database.branchName ?? "unscoped",
|
|
21
|
+
database.region ?? "unknown",
|
|
22
|
+
formatStatus(database),
|
|
23
|
+
database.id
|
|
24
|
+
]);
|
|
25
|
+
const widths = [
|
|
26
|
+
Math.max(4, ...rows.map((row) => row[0].length)),
|
|
27
|
+
Math.max(6, ...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(2, ...rows.map((row) => row[4].length))
|
|
31
|
+
];
|
|
32
|
+
lines.push(`${rail} ${ui.accent(formatColumns([
|
|
33
|
+
"Name",
|
|
34
|
+
"Branch",
|
|
35
|
+
"Region",
|
|
36
|
+
"Status",
|
|
37
|
+
"Id"
|
|
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 serializeDatabaseList(result) {
|
|
44
|
+
return {
|
|
45
|
+
...serializeList({
|
|
46
|
+
context: {
|
|
47
|
+
project: result.projectName,
|
|
48
|
+
...result.branchName ? { branch: result.branchName } : {}
|
|
49
|
+
},
|
|
50
|
+
items: result.databases.map((database) => ({
|
|
51
|
+
noun: "database",
|
|
52
|
+
label: database.name,
|
|
53
|
+
id: database.id,
|
|
54
|
+
status: database.isDefault ? "default" : null
|
|
55
|
+
}))
|
|
56
|
+
}),
|
|
57
|
+
projectId: result.projectId,
|
|
58
|
+
branchName: result.branchName,
|
|
59
|
+
databases: result.databases
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function renderDatabaseShow(context, descriptor, result) {
|
|
63
|
+
const lines = renderShow({
|
|
64
|
+
title: "Showing database metadata.",
|
|
65
|
+
descriptor,
|
|
66
|
+
fields: [
|
|
67
|
+
{
|
|
68
|
+
key: "project",
|
|
69
|
+
value: result.projectName
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: "database",
|
|
73
|
+
value: result.database.name
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: "id",
|
|
77
|
+
value: result.database.id,
|
|
78
|
+
tone: "dim"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
key: "branch",
|
|
82
|
+
value: result.database.branchName ?? "unscoped",
|
|
83
|
+
tone: result.database.branchName ? "default" : "dim"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: "region",
|
|
87
|
+
value: result.database.region ?? "unknown",
|
|
88
|
+
tone: result.database.region ? "default" : "dim"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: "status",
|
|
92
|
+
value: formatStatus(result.database)
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
key: "connections",
|
|
96
|
+
value: String(result.connections.length)
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}, context.ui);
|
|
100
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
101
|
+
return lines;
|
|
102
|
+
}
|
|
103
|
+
function serializeDatabaseShow(result) {
|
|
104
|
+
return stripVerboseContext(result);
|
|
105
|
+
}
|
|
106
|
+
function renderDatabaseCreateStdout(_context, _descriptor, result) {
|
|
107
|
+
return [result.connectionString];
|
|
108
|
+
}
|
|
109
|
+
function renderDatabaseCreate(context, _descriptor, result) {
|
|
110
|
+
const ui = context.ui;
|
|
111
|
+
const lines = [
|
|
112
|
+
"Creating database...",
|
|
113
|
+
renderSummaryLine(ui, "success", `Created database "${result.database.name}" in ${formatDatabaseTarget(result.projectName, result.database.branchName)}.`),
|
|
114
|
+
" The connection URL below is shown once, so save it now."
|
|
115
|
+
];
|
|
116
|
+
if (ui.verbose) {
|
|
117
|
+
lines.push("");
|
|
118
|
+
lines.push(...renderDatabaseCreateVerboseRows(context, result));
|
|
119
|
+
}
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
function serializeDatabaseCreate(result) {
|
|
123
|
+
return stripVerboseContext(result);
|
|
124
|
+
}
|
|
125
|
+
function renderDatabaseRemove(context, descriptor, result) {
|
|
126
|
+
const lines = renderMutate({
|
|
127
|
+
title: "Removing database.",
|
|
128
|
+
descriptor,
|
|
129
|
+
context: [
|
|
130
|
+
{
|
|
131
|
+
key: "project",
|
|
132
|
+
value: result.projectName
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
key: "database",
|
|
136
|
+
value: result.database.name
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
key: "id",
|
|
140
|
+
value: result.database.id,
|
|
141
|
+
tone: "dim"
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
operationDescription: "Removing database",
|
|
145
|
+
operationCount: 1,
|
|
146
|
+
details: ["Database and its connection metadata were removed."]
|
|
147
|
+
}, context.ui);
|
|
148
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
149
|
+
return lines;
|
|
150
|
+
}
|
|
151
|
+
function serializeDatabaseRemove(result) {
|
|
152
|
+
return stripVerboseContext(result);
|
|
153
|
+
}
|
|
154
|
+
function renderDatabaseConnectionList(context, descriptor, result) {
|
|
155
|
+
const ui = context.ui;
|
|
156
|
+
const lines = [`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim("Listing database connection metadata.")}`, ""];
|
|
157
|
+
const rail = ui.dim("│");
|
|
158
|
+
lines.push(`${rail} ${ui.accent("database:")} ${result.database.name}`);
|
|
159
|
+
lines.push(rail);
|
|
160
|
+
if (result.connections.length === 0) {
|
|
161
|
+
lines.push(`${rail} ${ui.dim("No database connections found.")}`);
|
|
162
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
163
|
+
return lines;
|
|
164
|
+
}
|
|
165
|
+
const rows = result.connections.map((connection) => [
|
|
166
|
+
connection.name,
|
|
167
|
+
connection.id,
|
|
168
|
+
connection.createdAt ?? "unknown"
|
|
169
|
+
]);
|
|
170
|
+
const widths = [
|
|
171
|
+
Math.max(4, ...rows.map((row) => row[0].length)),
|
|
172
|
+
Math.max(2, ...rows.map((row) => row[1].length)),
|
|
173
|
+
Math.max(7, ...rows.map((row) => row[2].length))
|
|
174
|
+
];
|
|
175
|
+
lines.push(`${rail} ${ui.accent(formatColumns([
|
|
176
|
+
"Name",
|
|
177
|
+
"Id",
|
|
178
|
+
"Created"
|
|
179
|
+
], widths))}`);
|
|
180
|
+
for (const row of rows) lines.push(`${rail} ${formatColumns(row, widths)}`);
|
|
181
|
+
lines.push(...renderResolvedProjectContextBlock(context.ui, result.verboseContext));
|
|
182
|
+
return lines;
|
|
183
|
+
}
|
|
184
|
+
function serializeDatabaseConnectionList(result) {
|
|
185
|
+
return {
|
|
186
|
+
...serializeList({
|
|
187
|
+
context: {
|
|
188
|
+
project: result.projectName,
|
|
189
|
+
database: result.database.name
|
|
190
|
+
},
|
|
191
|
+
items: result.connections.map((connection) => ({
|
|
192
|
+
noun: "connection",
|
|
193
|
+
label: connection.name,
|
|
194
|
+
id: connection.id,
|
|
195
|
+
status: null
|
|
196
|
+
}))
|
|
197
|
+
}),
|
|
198
|
+
projectId: result.projectId,
|
|
199
|
+
database: result.database,
|
|
200
|
+
connections: result.connections
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function renderDatabaseConnectionCreateStdout(_context, _descriptor, result) {
|
|
204
|
+
return [result.connectionString];
|
|
205
|
+
}
|
|
206
|
+
function renderDatabaseConnectionCreate(context, _descriptor, result) {
|
|
207
|
+
const ui = context.ui;
|
|
208
|
+
const lines = [
|
|
209
|
+
"Creating connection...",
|
|
210
|
+
renderSummaryLine(ui, "success", `Added a connection to "${result.database.name}" in ${formatDatabaseTarget(result.projectName, result.database.branchName)}.`),
|
|
211
|
+
" The connection URL below is shown once, so save it now."
|
|
212
|
+
];
|
|
213
|
+
if (ui.verbose) {
|
|
214
|
+
lines.push("");
|
|
215
|
+
lines.push(...renderDatabaseConnectionCreateVerboseRows(context, result));
|
|
216
|
+
}
|
|
217
|
+
return lines;
|
|
218
|
+
}
|
|
219
|
+
function serializeDatabaseConnectionCreate(result) {
|
|
220
|
+
return stripVerboseContext(result);
|
|
221
|
+
}
|
|
222
|
+
function renderDatabaseConnectionRemove(context, descriptor, result) {
|
|
223
|
+
return renderMutate({
|
|
224
|
+
title: "Removing database connection.",
|
|
225
|
+
descriptor,
|
|
226
|
+
context: [{
|
|
227
|
+
key: "connection",
|
|
228
|
+
value: result.connection.id,
|
|
229
|
+
tone: "dim"
|
|
230
|
+
}],
|
|
231
|
+
operationDescription: "Removing database connection",
|
|
232
|
+
operationCount: 1,
|
|
233
|
+
details: ["The connection metadata was removed. Existing one-time secrets were not shown."]
|
|
234
|
+
}, context.ui);
|
|
235
|
+
}
|
|
236
|
+
function serializeDatabaseConnectionRemove(result) {
|
|
237
|
+
return { connection: result.connection };
|
|
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
|
+
}
|
|
413
|
+
function formatStatus(database) {
|
|
414
|
+
return database.status ?? (database.isDefault ? "default" : "unknown");
|
|
415
|
+
}
|
|
416
|
+
function formatDatabaseTarget(projectName, branchName) {
|
|
417
|
+
return branchName ? `${projectName} / ${branchName}` : projectName;
|
|
418
|
+
}
|
|
419
|
+
function renderDatabaseCreateVerboseRows(context, result) {
|
|
420
|
+
return renderMetadataRows([
|
|
421
|
+
...renderWorkspaceProjectRows(result),
|
|
422
|
+
["branch", result.database.branchName ?? "unscoped"],
|
|
423
|
+
["database", formatResourceWithId(context, result.database.name, result.database.id)],
|
|
424
|
+
["region", result.database.region ?? "unknown"],
|
|
425
|
+
["status", formatStatus(result.database)],
|
|
426
|
+
["connection", formatResourceWithId(context, result.connection.name, result.connection.id)]
|
|
427
|
+
]);
|
|
428
|
+
}
|
|
429
|
+
function renderDatabaseConnectionCreateVerboseRows(context, result) {
|
|
430
|
+
return renderMetadataRows([
|
|
431
|
+
...renderWorkspaceProjectRows(result),
|
|
432
|
+
["branch", result.database.branchName ?? "unscoped"],
|
|
433
|
+
["database", formatResourceWithId(context, result.database.name, result.database.id)],
|
|
434
|
+
["connection", formatResourceWithId(context, result.connection.name, result.connection.id)]
|
|
435
|
+
]);
|
|
436
|
+
}
|
|
437
|
+
function renderWorkspaceProjectRows(result) {
|
|
438
|
+
return [...result.verboseContext ? [["workspace", result.verboseContext.workspace.name]] : [], ["project", result.projectName]];
|
|
439
|
+
}
|
|
440
|
+
function formatResourceWithId(context, name, id) {
|
|
441
|
+
return `${name} ${context.ui.dim(`(${id})`)}`;
|
|
442
|
+
}
|
|
443
|
+
function renderMetadataRows(rows) {
|
|
444
|
+
const widths = [Math.max(...rows.map((row) => row[0].length)), 0];
|
|
445
|
+
return rows.map(([key, value]) => ` ${formatColumns([key, value], widths)}`);
|
|
446
|
+
}
|
|
447
|
+
//#endregion
|
|
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 };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { renderShow } from "../output/patterns.js";
|
|
2
|
+
//#region src/presenters/feedback.ts
|
|
3
|
+
function renderFeedbackSuccess(context, descriptor, result) {
|
|
4
|
+
return renderShow({
|
|
5
|
+
title: "Feedback sent. Thank you!",
|
|
6
|
+
descriptor,
|
|
7
|
+
fields: [
|
|
8
|
+
...result.id ? [{
|
|
9
|
+
key: "id",
|
|
10
|
+
value: result.id
|
|
11
|
+
}] : [],
|
|
12
|
+
{
|
|
13
|
+
key: "sent as",
|
|
14
|
+
value: result.email ?? "anonymous",
|
|
15
|
+
tone: result.email ? "default" : "dim"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: "included",
|
|
19
|
+
value: `CLI ${result.context.cliVersion}, node ${result.context.nodeVersion}, ${result.context.platform} ${result.context.arch}`,
|
|
20
|
+
tone: "dim"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}, context.ui);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { renderFeedbackSuccess };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { resolvePrismaCliPackageCommandFormatterSync } from "../lib/agent/cli-command.js";
|
|
2
|
+
import { renderNextSteps, renderSummaryLine } from "../shell/ui.js";
|
|
3
|
+
import { COMPUTE_CONFIG_JSON_FILENAME } from "@prisma/compute-sdk/config";
|
|
4
|
+
//#region src/presenters/init.ts
|
|
5
|
+
function renderInit(context, _descriptor, result) {
|
|
6
|
+
const ui = context.ui;
|
|
7
|
+
const formatCommand = resolvePrismaCliPackageCommandFormatterSync(context.runtime.cwd);
|
|
8
|
+
const lines = [renderSummaryLine(ui, "success", result.converted ? `Converted ${COMPUTE_CONFIG_JSON_FILENAME} to ${result.configPath}` : `Wrote ${result.configPath}`)];
|
|
9
|
+
if (result.types.status === "installed") lines.push(renderSummaryLine(ui, "success", `Installed ${result.types.package} (config types)`));
|
|
10
|
+
else if ((result.types.status === "skipped" || result.types.status === "declined") && result.types.installCommand) lines.push(` ${ui.dim(`For editor types: ${result.types.installCommand}`)}`);
|
|
11
|
+
switch (result.link.status) {
|
|
12
|
+
case "linked":
|
|
13
|
+
lines.push(renderSummaryLine(ui, "success", `Linked "${result.directory}" to Project "${result.link.project?.name ?? ""}"`));
|
|
14
|
+
break;
|
|
15
|
+
case "already-linked": break;
|
|
16
|
+
case "skipped":
|
|
17
|
+
case "declined":
|
|
18
|
+
lines.push(` ${ui.dim(`Not linked to a Project yet; link with ${formatCommand(["project", "link"])}.`)}`);
|
|
19
|
+
break;
|
|
20
|
+
case "failed": break;
|
|
21
|
+
}
|
|
22
|
+
const linked = result.link.status === "linked" || result.link.status === "already-linked";
|
|
23
|
+
lines.push(...renderNextSteps([formatCommand(["app", "deploy"]), ...linked ? [] : [formatCommand(["project", "link"])]]));
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
26
|
+
function serializeInit(result) {
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { renderInit, serializeInit };
|