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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +6 -15
  2. package/dist/adapters/local-state.js +15 -4
  3. package/dist/adapters/mock-api.js +244 -0
  4. package/dist/adapters/token-storage.js +335 -34
  5. package/dist/cli.js +7 -7
  6. package/dist/cli2.js +24 -5
  7. package/dist/commands/agent/index.js +60 -0
  8. package/dist/commands/app/index.js +91 -61
  9. package/dist/commands/auth/index.js +55 -2
  10. package/dist/commands/branch/index.js +2 -27
  11. package/dist/commands/bucket/index.js +123 -0
  12. package/dist/commands/build/index.js +29 -0
  13. package/dist/commands/database/index.js +249 -0
  14. package/dist/commands/env.js +8 -4
  15. package/dist/commands/feedback/index.js +20 -0
  16. package/dist/commands/git/index.js +1 -1
  17. package/dist/commands/init/index.js +33 -0
  18. package/dist/commands/project/index.js +54 -5
  19. package/dist/controllers/agent-setup.js +52 -0
  20. package/dist/controllers/agent.js +228 -0
  21. package/dist/controllers/app-env-api.js +55 -0
  22. package/dist/controllers/app-env-file.js +181 -0
  23. package/dist/controllers/app-env.js +227 -104
  24. package/dist/controllers/app.js +746 -306
  25. package/dist/controllers/auth.js +247 -3
  26. package/dist/controllers/branch.js +78 -48
  27. package/dist/controllers/bucket.js +278 -0
  28. package/dist/controllers/build.js +88 -0
  29. package/dist/controllers/database.js +567 -0
  30. package/dist/controllers/feedback.js +86 -0
  31. package/dist/controllers/init.js +753 -0
  32. package/dist/controllers/project.js +377 -22
  33. package/dist/controllers/select-prompt-port.js +1 -0
  34. package/dist/lib/agent/cli-command.js +20 -0
  35. package/dist/lib/agent/constants.js +12 -0
  36. package/dist/lib/agent/package-manager.js +99 -0
  37. package/dist/lib/agent/setup-status.js +83 -0
  38. package/dist/lib/app/{preview-provider.js → app-provider.js} +137 -88
  39. package/dist/lib/app/branch-database-api.js +102 -0
  40. package/dist/lib/app/branch-database-deploy.js +326 -0
  41. package/dist/lib/app/branch-database.js +216 -0
  42. package/dist/lib/app/build-settings.js +93 -0
  43. package/dist/lib/app/build.js +83 -0
  44. package/dist/lib/app/bun-project.js +3 -4
  45. package/dist/lib/app/compute-config.js +145 -0
  46. package/dist/lib/app/deploy-plan.js +59 -0
  47. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
  48. package/dist/lib/app/env-config.js +1 -1
  49. package/dist/lib/app/env-file.js +82 -0
  50. package/dist/lib/app/env-vars.js +28 -2
  51. package/dist/lib/app/local-dev.js +3 -60
  52. package/dist/lib/app/production-deploy-gate.js +162 -0
  53. package/dist/lib/app/read-branch.js +30 -0
  54. package/dist/lib/auth/auth-ops.js +10 -4
  55. package/dist/lib/auth/guard.js +4 -1
  56. package/dist/lib/auth/login.js +33 -26
  57. package/dist/lib/auth/recipient.js +42 -0
  58. package/dist/lib/bucket/provider.js +139 -0
  59. package/dist/lib/database/provider.js +378 -0
  60. package/dist/lib/diagnostics.js +15 -0
  61. package/dist/lib/fs/home-path.js +24 -0
  62. package/dist/lib/git/local-branch.js +53 -0
  63. package/dist/lib/git/local-status.js +57 -0
  64. package/dist/lib/project/interactive-setup.js +5 -4
  65. package/dist/lib/project/local-pin.js +171 -41
  66. package/dist/lib/project/provider.js +92 -0
  67. package/dist/lib/project/resolution.js +199 -48
  68. package/dist/lib/project/setup.js +67 -20
  69. package/dist/output/patterns.js +1 -1
  70. package/dist/presenters/agent.js +74 -0
  71. package/dist/presenters/app-env.js +149 -14
  72. package/dist/presenters/app.js +208 -27
  73. package/dist/presenters/auth.js +99 -2
  74. package/dist/presenters/branch.js +37 -102
  75. package/dist/presenters/bucket.js +174 -0
  76. package/dist/presenters/database.js +448 -0
  77. package/dist/presenters/feedback.js +26 -0
  78. package/dist/presenters/init.js +30 -0
  79. package/dist/presenters/project.js +139 -27
  80. package/dist/presenters/verbose-context.js +64 -0
  81. package/dist/shell/cli-command.js +12 -0
  82. package/dist/shell/command-arguments.js +7 -1
  83. package/dist/shell/command-meta.js +458 -17
  84. package/dist/shell/command-runner.js +58 -18
  85. package/dist/shell/diagnostics-output.js +57 -0
  86. package/dist/shell/errors.js +56 -1
  87. package/dist/shell/help.js +31 -20
  88. package/dist/shell/output.js +72 -1
  89. package/dist/shell/prompt.js +12 -5
  90. package/dist/shell/runtime.js +8 -4
  91. package/dist/shell/ui.js +42 -3
  92. package/dist/shell/update-check.js +2 -2
  93. package/dist/use-cases/auth.js +68 -1
  94. package/dist/use-cases/branch.js +20 -68
  95. package/dist/use-cases/create-cli-gateways.js +2 -17
  96. package/dist/use-cases/project.js +2 -1
  97. package/package.json +21 -4
  98. package/dist/lib/app/preview-build.js +0 -312
  99. package/dist/lib/app/preview-interaction.js +0 -5
@@ -0,0 +1,278 @@
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, flags) {
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
+ if (flags.confirm !== id) throw new CliError({
63
+ code: "CONFIRMATION_REQUIRED",
64
+ domain: "bucket",
65
+ summary: "Confirm bucket deletion",
66
+ why: "Deleting this bucket permanently removes all objects and access keys.",
67
+ fix: `Rerun with --confirm ${id}.`,
68
+ exitCode: 2,
69
+ nextSteps: [`prisma-cli bucket delete ${id} --confirm ${id}`],
70
+ meta: {
71
+ expectedConfirm: id,
72
+ receivedConfirm: flags.confirm ?? null
73
+ }
74
+ });
75
+ await (await requireBucketProviderOnly(context)).deleteBucket(id, { signal: context.runtime.signal });
76
+ return {
77
+ command: "bucket.delete",
78
+ result: { bucket: { id } },
79
+ warnings: [],
80
+ nextSteps: []
81
+ };
82
+ }
83
+ async function runBucketKeyList(context, bucketId) {
84
+ const id = bucketId.trim();
85
+ if (!id) throw new CliError({
86
+ code: "USAGE_ERROR",
87
+ domain: "bucket",
88
+ summary: "Bucket id required",
89
+ why: "Bucket key listing needs a bucket id.",
90
+ fix: "Pass the bucket id.",
91
+ exitCode: 2,
92
+ nextSteps: ["prisma-cli bucket list"]
93
+ });
94
+ return {
95
+ command: "bucket.key.list",
96
+ result: {
97
+ bucketId: id,
98
+ keys: await (await requireBucketProviderOnly(context)).listKeys(id, { signal: context.runtime.signal })
99
+ },
100
+ warnings: [],
101
+ nextSteps: []
102
+ };
103
+ }
104
+ async function runBucketKeyCreate(context, bucketId, flags) {
105
+ const id = bucketId.trim();
106
+ if (!id) throw new CliError({
107
+ code: "USAGE_ERROR",
108
+ domain: "bucket",
109
+ summary: "Bucket id required",
110
+ why: "Bucket key creation needs a bucket id.",
111
+ fix: "Pass the bucket id.",
112
+ exitCode: 2,
113
+ nextSteps: ["prisma-cli bucket list"]
114
+ });
115
+ const role = resolveKeyRole(flags.role);
116
+ const created = await (await requireBucketProviderOnly(context)).createKey({
117
+ bucketId: id,
118
+ name: flags.name?.trim() || void 0,
119
+ role,
120
+ signal: context.runtime.signal
121
+ });
122
+ return {
123
+ command: "bucket.key.create",
124
+ result: {
125
+ bucketId: id,
126
+ key: created.key,
127
+ secretAccessKey: created.secretAccessKey,
128
+ accessKeyId: created.accessKeyId,
129
+ endpoint: created.endpoint,
130
+ bucketName: created.bucketName
131
+ },
132
+ warnings: [],
133
+ nextSteps: []
134
+ };
135
+ }
136
+ async function runBucketKeyDelete(context, bucketId, keyId) {
137
+ const bktId = bucketId.trim();
138
+ const kId = keyId.trim();
139
+ if (!bktId || !kId) throw new CliError({
140
+ code: "USAGE_ERROR",
141
+ domain: "bucket",
142
+ summary: "Bucket id and key id required",
143
+ why: "Bucket key deletion needs both a bucket id and a key id.",
144
+ fix: "Pass the bucket id and key id.",
145
+ exitCode: 2,
146
+ nextSteps: ["prisma-cli bucket key list <bucketId>"]
147
+ });
148
+ await (await requireBucketProviderOnly(context)).deleteKey(bktId, kId, { signal: context.runtime.signal });
149
+ return {
150
+ command: "bucket.key.delete",
151
+ result: { key: { id: kId } },
152
+ warnings: [],
153
+ nextSteps: []
154
+ };
155
+ }
156
+ async function resolveBucketProvider(context) {
157
+ if (isRealMode(context)) {
158
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
159
+ if (!client) throw authRequiredError();
160
+ return createManagementBucketProvider(client);
161
+ }
162
+ return createFixtureBucketProvider(context);
163
+ }
164
+ async function requireBucketContext(context, flags, commandName) {
165
+ const workspace = (await requireAuthenticatedAuthState(context)).workspace;
166
+ if (!workspace) throw workspaceRequiredError();
167
+ if (isRealMode(context)) {
168
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
169
+ if (!client) throw authRequiredError();
170
+ const targetResult = await resolveProjectTarget({
171
+ context,
172
+ workspace,
173
+ explicitProject: flags.projectRef,
174
+ listProjects: () => listRealWorkspaceProjects(client, workspace, context.runtime.signal),
175
+ commandName
176
+ });
177
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
178
+ return {
179
+ provider: createManagementBucketProvider(client),
180
+ target: targetResult.value
181
+ };
182
+ }
183
+ const targetResult = await resolveProjectTarget({
184
+ context,
185
+ workspace,
186
+ explicitProject: flags.projectRef,
187
+ listProjects: async () => listFixtureWorkspaceProjects(context, workspace),
188
+ commandName
189
+ });
190
+ if (targetResult.isErr()) throw projectResolutionErrorToCliError(targetResult.error);
191
+ return {
192
+ provider: createFixtureBucketProvider(context),
193
+ target: targetResult.value
194
+ };
195
+ }
196
+ async function requireBucketProviderOnly(context) {
197
+ await requireAuthenticatedAuthState(context);
198
+ return resolveBucketProvider(context);
199
+ }
200
+ function createFixtureBucketProvider(context) {
201
+ return {
202
+ async listBuckets(options) {
203
+ return context.api.listBucketsForProject(options.projectId, options.branchName).map((bucket) => normalizeBucket(bucket));
204
+ },
205
+ async createBucket(options) {
206
+ const created = context.api.createBucket({
207
+ projectId: options.projectId,
208
+ name: options.name,
209
+ branchGitName: options.branchGitName
210
+ });
211
+ if (!created) throw branchNotFoundError(options.branchGitName ?? "");
212
+ return normalizeBucket(created);
213
+ },
214
+ async deleteBucket(bucketId) {
215
+ if (!context.api.deleteBucket(bucketId)) throw bucketNotFoundError(bucketId);
216
+ },
217
+ async listKeys(bucketId) {
218
+ if (!context.api.getBucket(bucketId)) throw bucketNotFoundError(bucketId);
219
+ return context.api.listBucketKeys(bucketId).map((key) => normalizeKey(key));
220
+ },
221
+ async createKey(options) {
222
+ const created = context.api.createBucketKey({
223
+ bucketId: options.bucketId,
224
+ name: options.name,
225
+ role: options.role
226
+ });
227
+ if (!created) throw bucketNotFoundError(options.bucketId);
228
+ return {
229
+ key: normalizeKey(created.key),
230
+ secretAccessKey: created.secretAccessKey,
231
+ accessKeyId: created.accessKeyId,
232
+ endpoint: created.endpoint,
233
+ bucketName: created.bucketName
234
+ };
235
+ },
236
+ async deleteKey(bucketId, keyId) {
237
+ if (!context.api.deleteBucketKey(bucketId, keyId)) throw keyNotFoundError(keyId, bucketId);
238
+ }
239
+ };
240
+ }
241
+ function resolveKeyRole(role) {
242
+ return role === "read" ? "read" : "read_write";
243
+ }
244
+ function branchNotFoundError(branchGitName) {
245
+ return new CliError({
246
+ code: "BRANCH_NOT_FOUND",
247
+ domain: "bucket",
248
+ summary: "Branch not found",
249
+ why: `No branch matched "${branchGitName}" in the resolved project.`,
250
+ fix: "Pass a branch git name from prisma-cli branch list.",
251
+ exitCode: 1,
252
+ nextSteps: ["prisma-cli branch list"]
253
+ });
254
+ }
255
+ function bucketNotFoundError(bucketId) {
256
+ return new CliError({
257
+ code: "BUCKET_NOT_FOUND",
258
+ domain: "bucket",
259
+ summary: "Bucket not found",
260
+ why: `No bucket matched "${bucketId}".`,
261
+ fix: "Pass a bucket id from prisma-cli bucket list.",
262
+ exitCode: 1,
263
+ nextSteps: ["prisma-cli bucket list"]
264
+ });
265
+ }
266
+ function keyNotFoundError(keyId, bucketId) {
267
+ return new CliError({
268
+ code: "BUCKET_KEY_NOT_FOUND",
269
+ domain: "bucket",
270
+ summary: "Bucket key not found",
271
+ why: `No key matched "${keyId}" for bucket "${bucketId}".`,
272
+ fix: "Pass a key id from prisma-cli bucket key list <bucketId>.",
273
+ exitCode: 1,
274
+ nextSteps: [`prisma-cli bucket key list ${bucketId}`]
275
+ });
276
+ }
277
+ //#endregion
278
+ export { runBucketCreate, runBucketDelete, runBucketKeyCreate, runBucketKeyDelete, runBucketKeyList, runBucketList };
@@ -0,0 +1,88 @@
1
+ import { CliError, authRequiredError } from "../shell/errors.js";
2
+ import { writeJsonEvent } from "../shell/output.js";
3
+ import { requireComputeAuth } from "../lib/auth/guard.js";
4
+ //#region src/controllers/build.ts
5
+ async function runBuildLogs(context, buildId, options = {}) {
6
+ const client = await requireComputeAuth(context.runtime.env, context.runtime.signal);
7
+ if (!client) throw authRequiredError(["prisma-cli auth login"]);
8
+ if (!context.flags.json && !context.flags.quiet) context.output.stderr.write(`build logs → Streaming logs for build ${buildId}\n\n`);
9
+ const { data, response } = await client.GET("/v1/builds/{buildId}/logs", {
10
+ params: {
11
+ path: { buildId },
12
+ query: {
13
+ ...options.follow ? { follow: "true" } : {},
14
+ ...options.cursor ? { cursor: options.cursor } : {}
15
+ }
16
+ },
17
+ parseAs: "stream",
18
+ signal: context.runtime.signal
19
+ });
20
+ const body = data;
21
+ if (!response.ok || !body) throw buildLogsRequestError(buildId, response.status);
22
+ let sawError = false;
23
+ await forEachNdjsonRecord(body, (record) => {
24
+ if (record.type === "terminal" && record.kind === "error") sawError = true;
25
+ writeBuildLogRecord(context, record);
26
+ });
27
+ if (sawError) process.exitCode = 1;
28
+ }
29
+ function writeBuildLogRecord(context, record) {
30
+ if (context.flags.json) {
31
+ writeJsonEvent(context.output, {
32
+ type: record.type,
33
+ command: "build.logs",
34
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
35
+ data: record
36
+ });
37
+ return;
38
+ }
39
+ if (record.type === "log") {
40
+ const stream = record.source === "stderr" || record.level === "error" ? context.output.stderr : context.output.stdout;
41
+ stream.write(record.text);
42
+ if (!record.text.endsWith("\n")) stream.write("\n");
43
+ return;
44
+ }
45
+ if (record.code !== "end") context.output.stderr.write(`${record.message}\n`);
46
+ }
47
+ /** Reads a newline-delimited JSON body line by line, parsing each into a record. */
48
+ async function forEachNdjsonRecord(body, onRecord) {
49
+ const reader = body.getReader();
50
+ const decoder = new TextDecoder();
51
+ let buffer = "";
52
+ for (;;) {
53
+ const { done, value } = await reader.read();
54
+ if (value) buffer += decoder.decode(value, { stream: true });
55
+ let newlineIndex = buffer.indexOf("\n");
56
+ while (newlineIndex !== -1) {
57
+ const line = buffer.slice(0, newlineIndex).trim();
58
+ buffer = buffer.slice(newlineIndex + 1);
59
+ if (line) onRecord(JSON.parse(line));
60
+ newlineIndex = buffer.indexOf("\n");
61
+ }
62
+ if (done) {
63
+ const tail = buffer.trim();
64
+ if (tail) onRecord(JSON.parse(tail));
65
+ return;
66
+ }
67
+ }
68
+ }
69
+ function buildLogsRequestError(buildId, status) {
70
+ if (status === 404) return new CliError({
71
+ code: "BUILD_NOT_FOUND",
72
+ domain: "app",
73
+ summary: `Build ${buildId} was not found`,
74
+ why: "The build does not exist, or your workspace does not have access to it.",
75
+ fix: "Check the build id, or run prisma-cli auth login to switch to the workspace that owns it.",
76
+ exitCode: 1
77
+ });
78
+ return new CliError({
79
+ code: "BUILD_LOGS_FAILED",
80
+ domain: "app",
81
+ summary: `Failed to read logs for build ${buildId}`,
82
+ why: `The Management API returned HTTP ${status}.`,
83
+ fix: "Retry the command, or rerun with --trace for more detail.",
84
+ exitCode: 1
85
+ });
86
+ }
87
+ //#endregion
88
+ export { runBuildLogs };