@prisma/cli 3.0.0-alpha.2 → 3.0.0-alpha.4
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/dist/adapters/git.js +49 -0
- package/dist/adapters/local-state.js +38 -0
- package/dist/cli2.js +3 -1
- package/dist/commands/app/index.js +31 -20
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/env.js +87 -0
- package/dist/commands/git/index.js +36 -0
- package/dist/commands/project/index.js +10 -13
- package/dist/controllers/app-env.js +223 -0
- package/dist/controllers/app.js +260 -86
- package/dist/controllers/auth.js +2 -2
- package/dist/controllers/branch.js +1 -1
- package/dist/controllers/project.js +451 -161
- package/dist/lib/app/env-config.js +57 -0
- package/dist/lib/app/preview-provider.js +15 -2
- package/dist/lib/auth/auth-ops.js +8 -10
- package/dist/lib/auth/client.js +1 -1
- package/dist/lib/project/resolution.js +148 -0
- package/dist/output/patterns.js +1 -2
- package/dist/presenters/app-env.js +129 -0
- package/dist/presenters/app.js +9 -1
- package/dist/presenters/auth.js +2 -2
- package/dist/presenters/branch.js +6 -6
- package/dist/presenters/project.js +84 -44
- package/dist/shell/command-meta.js +91 -9
- package/dist/shell/command-runner.js +32 -2
- package/dist/shell/errors.js +4 -1
- package/dist/shell/help.js +1 -1
- package/dist/shell/output.js +18 -12
- package/dist/shell/runtime.js +1 -1
- package/dist/shell/ui.js +19 -1
- package/dist/use-cases/auth.js +5 -8
- package/dist/use-cases/branch.js +20 -20
- package/dist/use-cases/create-cli-gateways.js +3 -13
- package/dist/use-cases/project.js +2 -48
- package/package.json +2 -2
- package/dist/adapters/config.js +0 -74
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { CliError, authRequiredError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
2
|
+
import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
3
|
+
import { resolveProjectTarget } from "../lib/project/resolution.js";
|
|
4
|
+
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
5
|
+
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
6
|
+
import { listRealWorkspaceProjects } from "./project.js";
|
|
7
|
+
import { formatScopeLabel, parseKeyValuePositional, resolveEnvScope } from "../lib/app/env-config.js";
|
|
8
|
+
//#region src/controllers/app-env.ts
|
|
9
|
+
function defaultRoleScope() {
|
|
10
|
+
return {
|
|
11
|
+
kind: "role",
|
|
12
|
+
role: "production"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async function runEnvAdd(context, rawAssignment, flags) {
|
|
16
|
+
const { key, value } = parseKeyValuePositional(rawAssignment, "add", context.runtime.env);
|
|
17
|
+
const scope = resolveEnvScope(flags, {
|
|
18
|
+
requireExplicit: true,
|
|
19
|
+
command: "add"
|
|
20
|
+
});
|
|
21
|
+
if (!scope) throw usageError(`prisma-cli project env add requires --role`, "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env add ${key}=${value} --role production`], "app");
|
|
22
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
23
|
+
const resolved = resolveScopeToApi(scope);
|
|
24
|
+
if (await findVariableByNaturalKey(client, projectId, key, resolved)) throw new CliError({
|
|
25
|
+
code: "ENV_VARIABLE_ALREADY_EXISTS",
|
|
26
|
+
domain: "app",
|
|
27
|
+
summary: `Variable "${key}" already exists in ${formatScopeLabel(scope)}`,
|
|
28
|
+
why: "A variable with this key already exists in the targeted scope.",
|
|
29
|
+
fix: "Use `prisma-cli project env update` to change an existing variable's value.",
|
|
30
|
+
exitCode: 1,
|
|
31
|
+
nextSteps: [`prisma-cli project env update ${key}=<new-value> --role ${scope.role}`]
|
|
32
|
+
});
|
|
33
|
+
const { data, error, response } = await client.POST("/v1/environment-variables", { body: {
|
|
34
|
+
projectId,
|
|
35
|
+
class: resolved.apiTarget.class,
|
|
36
|
+
key,
|
|
37
|
+
value
|
|
38
|
+
} });
|
|
39
|
+
if (error || !data) throw apiCallError(`Failed to add ${key}`, response, error);
|
|
40
|
+
return {
|
|
41
|
+
command: "project.env.add",
|
|
42
|
+
result: {
|
|
43
|
+
projectId,
|
|
44
|
+
scope: resolved.descriptor,
|
|
45
|
+
variable: toMetadata(data.data, resolved.descriptor)
|
|
46
|
+
},
|
|
47
|
+
warnings: [],
|
|
48
|
+
nextSteps: []
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function runEnvUpdate(context, rawAssignment, flags) {
|
|
52
|
+
const { key, value } = parseKeyValuePositional(rawAssignment, "update", context.runtime.env);
|
|
53
|
+
const scope = resolveEnvScope(flags, {
|
|
54
|
+
requireExplicit: true,
|
|
55
|
+
command: "update"
|
|
56
|
+
});
|
|
57
|
+
if (!scope) throw usageError(`prisma-cli project env update requires --role`, "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env update ${key}=${value} --role production`], "app");
|
|
58
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
59
|
+
const resolved = resolveScopeToApi(scope);
|
|
60
|
+
const existing = await findVariableByNaturalKey(client, projectId, key, resolved);
|
|
61
|
+
if (!existing) throw new CliError({
|
|
62
|
+
code: "ENV_VARIABLE_NOT_FOUND",
|
|
63
|
+
domain: "app",
|
|
64
|
+
summary: `Variable "${key}" not found in ${formatScopeLabel(scope)}`,
|
|
65
|
+
why: "No variable with this key exists in the targeted scope.",
|
|
66
|
+
fix: "Use `prisma-cli project env add` to create a new variable.",
|
|
67
|
+
exitCode: 1,
|
|
68
|
+
nextSteps: [`prisma-cli project env add ${key}=<value> --role ${scope.role}`]
|
|
69
|
+
});
|
|
70
|
+
const { data, error, response } = await client.PATCH("/v1/environment-variables/{envVarId}", {
|
|
71
|
+
params: { path: { envVarId: existing.id } },
|
|
72
|
+
body: { value }
|
|
73
|
+
});
|
|
74
|
+
if (error || !data) throw apiCallError(`Failed to update value for ${key}`, response, error);
|
|
75
|
+
return {
|
|
76
|
+
command: "project.env.update",
|
|
77
|
+
result: {
|
|
78
|
+
projectId,
|
|
79
|
+
scope: resolved.descriptor,
|
|
80
|
+
variable: toMetadata(data.data, resolved.descriptor)
|
|
81
|
+
},
|
|
82
|
+
warnings: [],
|
|
83
|
+
nextSteps: []
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async function runEnvList(context, flags) {
|
|
87
|
+
const scope = resolveEnvScope(flags, {
|
|
88
|
+
requireExplicit: false,
|
|
89
|
+
command: "list"
|
|
90
|
+
}) ?? defaultRoleScope();
|
|
91
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
92
|
+
const resolved = resolveScopeToApi(scope);
|
|
93
|
+
const variables = await listVariables(client, projectId, resolved);
|
|
94
|
+
return {
|
|
95
|
+
command: "project.env.list",
|
|
96
|
+
result: {
|
|
97
|
+
projectId,
|
|
98
|
+
scope: resolved.descriptor,
|
|
99
|
+
variables: variables.map((row) => toMetadata(row, resolved.descriptor))
|
|
100
|
+
},
|
|
101
|
+
warnings: [],
|
|
102
|
+
nextSteps: variables.length === 0 ? [`prisma-cli project env add KEY=value --role ${scope.role}`] : []
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function runEnvRm(context, key, flags) {
|
|
106
|
+
if (!key) throw usageError("prisma-cli project env rm requires KEY", "No KEY positional argument was supplied.", "Pass the variable name to remove, e.g. STRIPE_KEY.", ["prisma-cli project env rm STRIPE_KEY --role production"], "app");
|
|
107
|
+
const scope = resolveEnvScope(flags, {
|
|
108
|
+
requireExplicit: true,
|
|
109
|
+
command: "rm"
|
|
110
|
+
});
|
|
111
|
+
if (!scope) throw usageError("prisma-cli project env rm requires --role", "Writing without an explicit scope is rejected.", "Pass --role production or --role preview.", [`prisma-cli project env rm ${key} --role production`], "app");
|
|
112
|
+
const { client, projectId } = await requireClientAndProject(context, flags.projectRef);
|
|
113
|
+
const resolved = resolveScopeToApi(scope);
|
|
114
|
+
const existing = await findVariableByNaturalKey(client, projectId, key, resolved);
|
|
115
|
+
if (!existing) throw new CliError({
|
|
116
|
+
code: "ENV_VARIABLE_NOT_FOUND",
|
|
117
|
+
domain: "app",
|
|
118
|
+
summary: `Variable "${key}" not found in ${formatScopeLabel(scope)}`,
|
|
119
|
+
why: "No variable with this key exists in the targeted scope, so there is nothing to remove.",
|
|
120
|
+
fix: "Run prisma-cli project env list with the same scope to see the available variables.",
|
|
121
|
+
exitCode: 1,
|
|
122
|
+
nextSteps: [`prisma-cli project env list --role ${scope.role}`]
|
|
123
|
+
});
|
|
124
|
+
const { error, response } = await client.DELETE("/v1/environment-variables/{envVarId}", { params: { path: { envVarId: existing.id } } });
|
|
125
|
+
if (error) throw apiCallError(`Failed to remove ${key}`, response, error);
|
|
126
|
+
return {
|
|
127
|
+
command: "project.env.rm",
|
|
128
|
+
result: {
|
|
129
|
+
projectId,
|
|
130
|
+
scope: resolved.descriptor,
|
|
131
|
+
key
|
|
132
|
+
},
|
|
133
|
+
warnings: [],
|
|
134
|
+
nextSteps: []
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async function requireClientAndProject(context, explicitProject) {
|
|
138
|
+
const authState = await requireAuthenticatedAuthState(context);
|
|
139
|
+
const client = await requireComputeAuth(context.runtime.env);
|
|
140
|
+
if (!client) throw authRequiredError(["prisma-cli auth login"]);
|
|
141
|
+
if (!authState.workspace) throw workspaceRequiredError();
|
|
142
|
+
return {
|
|
143
|
+
client,
|
|
144
|
+
projectId: (await resolveProjectTarget({
|
|
145
|
+
context,
|
|
146
|
+
workspace: authState.workspace,
|
|
147
|
+
explicitProject,
|
|
148
|
+
listProjects: () => listRealWorkspaceProjects(client, authState.workspace),
|
|
149
|
+
prompt: createSelectPromptPort(context),
|
|
150
|
+
remember: true
|
|
151
|
+
})).project.id
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function resolveScopeToApi(scope) {
|
|
155
|
+
return {
|
|
156
|
+
scope,
|
|
157
|
+
descriptor: {
|
|
158
|
+
kind: "role",
|
|
159
|
+
role: scope.role
|
|
160
|
+
},
|
|
161
|
+
apiTarget: {
|
|
162
|
+
class: scope.role,
|
|
163
|
+
branchId: null
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function findVariableByNaturalKey(client, projectId, key, resolved) {
|
|
168
|
+
const { data, error, response } = await client.GET("/v1/environment-variables", { params: { query: {
|
|
169
|
+
projectId,
|
|
170
|
+
class: resolved.apiTarget.class,
|
|
171
|
+
key
|
|
172
|
+
} } });
|
|
173
|
+
if (error || !data) throw apiCallError(`Failed to look up ${key}`, response, error);
|
|
174
|
+
return data.data.filter((row) => rowMatchesScope(row, resolved))[0] ?? null;
|
|
175
|
+
}
|
|
176
|
+
async function listVariables(client, projectId, resolved) {
|
|
177
|
+
const collected = [];
|
|
178
|
+
let cursor;
|
|
179
|
+
while (true) {
|
|
180
|
+
const query = {
|
|
181
|
+
projectId,
|
|
182
|
+
class: resolved.apiTarget.class
|
|
183
|
+
};
|
|
184
|
+
if (cursor !== void 0) query.cursor = cursor;
|
|
185
|
+
const result = await client.GET("/v1/environment-variables", { params: { query } });
|
|
186
|
+
if (result.error || !result.data) throw apiCallError(`Failed to list environment variables`, result.response, result.error);
|
|
187
|
+
const page = result.data.data.filter((row) => rowMatchesScope(row, resolved));
|
|
188
|
+
collected.push(...page);
|
|
189
|
+
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
190
|
+
cursor = result.data.pagination.nextCursor;
|
|
191
|
+
}
|
|
192
|
+
return collected;
|
|
193
|
+
}
|
|
194
|
+
function rowMatchesScope(row, resolved) {
|
|
195
|
+
return row.branchId === null && row.class === resolved.apiTarget.class;
|
|
196
|
+
}
|
|
197
|
+
function toMetadata(row, scope) {
|
|
198
|
+
return {
|
|
199
|
+
id: row.id,
|
|
200
|
+
key: row.key,
|
|
201
|
+
scope,
|
|
202
|
+
isManagedBySystem: row.isManagedBySystem,
|
|
203
|
+
updatedAt: row.updatedAt
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function apiCallError(summary, response, error) {
|
|
207
|
+
const status = response?.status ?? 0;
|
|
208
|
+
const apiCode = error?.error?.code;
|
|
209
|
+
const apiMessage = error?.error?.message;
|
|
210
|
+
const apiHint = error?.error?.hint;
|
|
211
|
+
if (status === 401 || status === 403) return authRequiredError(["prisma auth login"]);
|
|
212
|
+
return new CliError({
|
|
213
|
+
code: apiCode ?? "ENV_API_ERROR",
|
|
214
|
+
domain: "app",
|
|
215
|
+
summary,
|
|
216
|
+
why: apiMessage ?? `The Management API returned status ${status || "unknown"}.`,
|
|
217
|
+
fix: apiHint ?? "Re-run with --trace for the underlying API response details.",
|
|
218
|
+
exitCode: 1,
|
|
219
|
+
nextSteps: []
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
export { runEnvAdd, runEnvList, runEnvRm, runEnvUpdate };
|