@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,83 @@
|
|
|
1
|
+
import { PRISMA_SKILLS_LOCK_FILENAME } from "./constants.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { findComputeConfigDir } from "@prisma/compute-sdk/config";
|
|
5
|
+
//#region src/lib/agent/setup-status.ts
|
|
6
|
+
async function readPrismaAgentSetupStatus(options) {
|
|
7
|
+
const setupCwd = await resolvePrismaAgentSetupCwd(options);
|
|
8
|
+
const skillsLockPath = path.join(setupCwd, PRISMA_SKILLS_LOCK_FILENAME);
|
|
9
|
+
const [skillsInstalled, promptDismissedAt] = await Promise.all([hasPrismaSkillsLock(skillsLockPath, options.signal, options.requiredSkill), options.stateStore?.readAgentSetupPromptDismissedAt() ?? null]);
|
|
10
|
+
return {
|
|
11
|
+
skillsLockPath: path.basename(skillsLockPath),
|
|
12
|
+
skillsInstalled,
|
|
13
|
+
promptDismissedAt
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function resolvePrismaAgentSetupCwd(options) {
|
|
17
|
+
options.signal.throwIfAborted();
|
|
18
|
+
const configDir = await findComputeConfigDir(options.cwd, options.signal);
|
|
19
|
+
options.signal.throwIfAborted();
|
|
20
|
+
return configDir ?? options.cwd;
|
|
21
|
+
}
|
|
22
|
+
function isPrismaAgentSetupComplete(status) {
|
|
23
|
+
return status.skillsInstalled;
|
|
24
|
+
}
|
|
25
|
+
function shouldOfferPrismaAgentSetup(status) {
|
|
26
|
+
return !isPrismaAgentSetupComplete(status) && !status.promptDismissedAt;
|
|
27
|
+
}
|
|
28
|
+
async function isLikelyProjectDirectory(options) {
|
|
29
|
+
return (await Promise.all([
|
|
30
|
+
"package.json",
|
|
31
|
+
"prisma.compute.ts",
|
|
32
|
+
"prisma.config.ts",
|
|
33
|
+
".git"
|
|
34
|
+
].map((fileName) => pathExists(path.join(options.cwd, fileName), options.signal)))).some(Boolean);
|
|
35
|
+
}
|
|
36
|
+
async function hasPrismaSkillsLock(filePath, signal, requiredSkill) {
|
|
37
|
+
try {
|
|
38
|
+
const raw = await readFile(filePath, {
|
|
39
|
+
encoding: "utf8",
|
|
40
|
+
signal
|
|
41
|
+
});
|
|
42
|
+
return hasPrismaSkillsLockEntry(JSON.parse(raw), requiredSkill);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (isNotFoundError(error) || error instanceof SyntaxError) return false;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function hasPrismaSkillsLockEntry(value, requiredSkill) {
|
|
49
|
+
if (!isRecord(value)) return false;
|
|
50
|
+
if (requiredSkill) return skillLockEntryUsesPrismaSource(readSkillLockEntries(value)[requiredSkill]);
|
|
51
|
+
if (readLegacySources(value).includes("prisma/skills")) return true;
|
|
52
|
+
return Object.values(readSkillLockEntries(value)).some(skillLockEntryUsesPrismaSource);
|
|
53
|
+
}
|
|
54
|
+
function readLegacySources(value) {
|
|
55
|
+
return Array.isArray(value.sources) ? value.sources.filter((source) => typeof source === "string") : [];
|
|
56
|
+
}
|
|
57
|
+
function readSkillLockEntries(value) {
|
|
58
|
+
return isRecord(value.skills) ? value.skills : {};
|
|
59
|
+
}
|
|
60
|
+
function skillLockEntryUsesPrismaSource(value) {
|
|
61
|
+
return isRecord(value) && value.source === "prisma/skills";
|
|
62
|
+
}
|
|
63
|
+
function isRecord(value) {
|
|
64
|
+
return typeof value === "object" && value !== null;
|
|
65
|
+
}
|
|
66
|
+
async function pathExists(filePath, signal) {
|
|
67
|
+
signal.throwIfAborted();
|
|
68
|
+
try {
|
|
69
|
+
await stat(filePath);
|
|
70
|
+
signal.throwIfAborted();
|
|
71
|
+
return true;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (signal.aborted) throw error;
|
|
74
|
+
if (isNotFoundError(error)) return false;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isNotFoundError(error) {
|
|
79
|
+
const code = error.code;
|
|
80
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { isLikelyProjectDirectory, readPrismaAgentSetupStatus, resolvePrismaAgentSetupCwd, shouldOfferPrismaAgentSetup };
|
|
@@ -1,32 +1,35 @@
|
|
|
1
|
+
import { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable } from "./branch-database-api.js";
|
|
2
|
+
import { AppBuildStrategy } from "./build.js";
|
|
1
3
|
import { envVarNames } from "./env-vars.js";
|
|
2
|
-
import { PreviewBuildStrategy } from "./preview-build.js";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { ApiError, CancelledError, ComputeClient, streamLogs } from "@prisma/compute-sdk";
|
|
5
|
-
//#region src/lib/app/
|
|
6
|
-
var
|
|
6
|
+
//#region src/lib/app/app-provider.ts
|
|
7
|
+
var DomainApiError = class extends Error {
|
|
7
8
|
status;
|
|
8
9
|
code;
|
|
9
10
|
hint;
|
|
10
11
|
constructor(options) {
|
|
11
12
|
super(`${options.summary}: ${options.message}${options.hint ? ` ${options.hint}` : ""}`);
|
|
12
|
-
this.name = "
|
|
13
|
+
this.name = "DomainApiError";
|
|
13
14
|
this.status = options.status;
|
|
14
15
|
this.code = options.code ?? null;
|
|
15
16
|
this.hint = options.hint ?? null;
|
|
16
17
|
}
|
|
17
18
|
};
|
|
18
|
-
function
|
|
19
|
+
function createAppProvider(client, options) {
|
|
19
20
|
const sdk = new ComputeClient(client);
|
|
20
21
|
return {
|
|
21
22
|
async createProject(options) {
|
|
22
23
|
const projectResult = await sdk.createProject({
|
|
23
24
|
name: options.name,
|
|
25
|
+
region: options.region,
|
|
24
26
|
signal: options.signal
|
|
25
27
|
});
|
|
26
28
|
if (projectResult.isErr()) throw new Error(projectResult.error.message);
|
|
27
29
|
return {
|
|
28
30
|
id: projectResult.value.id,
|
|
29
|
-
name: projectResult.value.name
|
|
31
|
+
name: projectResult.value.name,
|
|
32
|
+
defaultRegion: projectResult.value.defaultRegion
|
|
30
33
|
};
|
|
31
34
|
},
|
|
32
35
|
async listApps(projectId, options) {
|
|
@@ -36,15 +39,45 @@ function createPreviewAppProvider(client, options) {
|
|
|
36
39
|
signal: options?.signal
|
|
37
40
|
});
|
|
38
41
|
},
|
|
42
|
+
async resolveBranch(projectId, options) {
|
|
43
|
+
const branch = await resolveOrCreateBranch(client, {
|
|
44
|
+
projectId,
|
|
45
|
+
gitName: options.branchName,
|
|
46
|
+
signal: options.signal
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
id: branch.id,
|
|
50
|
+
name: branch.gitName,
|
|
51
|
+
role: branch.role
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
async createBranchDatabase(options) {
|
|
55
|
+
return createBranchDatabase(client, options);
|
|
56
|
+
},
|
|
57
|
+
async deleteBranchDatabase(options) {
|
|
58
|
+
return deleteBranchDatabase(client, options);
|
|
59
|
+
},
|
|
60
|
+
async listEnvironmentVariables(options) {
|
|
61
|
+
return listEnvironmentVariables(client, options);
|
|
62
|
+
},
|
|
63
|
+
async createEnvironmentVariable(options) {
|
|
64
|
+
return createEnvironmentVariable(client, options);
|
|
65
|
+
},
|
|
66
|
+
async updateEnvironmentVariable(options) {
|
|
67
|
+
return updateEnvironmentVariable(client, options);
|
|
68
|
+
},
|
|
69
|
+
async deleteEnvironmentVariable(options) {
|
|
70
|
+
return deleteEnvironmentVariable(client, options);
|
|
71
|
+
},
|
|
39
72
|
async removeApp(appId, options) {
|
|
40
|
-
const appResult = await sdk.
|
|
41
|
-
|
|
73
|
+
const appResult = await sdk.showApp({
|
|
74
|
+
appId,
|
|
42
75
|
signal: options?.signal
|
|
43
76
|
});
|
|
44
77
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
45
|
-
const destroyResult = await sdk.
|
|
46
|
-
|
|
47
|
-
|
|
78
|
+
const destroyResult = await sdk.destroyApp({
|
|
79
|
+
appId,
|
|
80
|
+
keepApp: false,
|
|
48
81
|
timeoutSeconds: 120,
|
|
49
82
|
pollIntervalMs: 2e3,
|
|
50
83
|
signal: options?.signal
|
|
@@ -59,8 +92,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
59
92
|
return listComputeServiceDomains(client, appId, options?.signal);
|
|
60
93
|
},
|
|
61
94
|
async addDomain(options) {
|
|
62
|
-
const result = await client.POST("/v1/
|
|
63
|
-
params: { path: {
|
|
95
|
+
const result = await client.POST("/v1/apps/{appId}/domains", {
|
|
96
|
+
params: { path: { appId: options.appId } },
|
|
64
97
|
body: { hostname: options.hostname },
|
|
65
98
|
signal: options.signal
|
|
66
99
|
});
|
|
@@ -104,8 +137,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
104
137
|
},
|
|
105
138
|
async promoteDeployment(options) {
|
|
106
139
|
const promoteResult = await sdk.promote({
|
|
107
|
-
|
|
108
|
-
|
|
140
|
+
appId: options.appId,
|
|
141
|
+
deploymentId: options.deploymentId,
|
|
109
142
|
timeoutSeconds: 120,
|
|
110
143
|
pollIntervalMs: 2e3,
|
|
111
144
|
signal: options.signal,
|
|
@@ -130,18 +163,20 @@ function createPreviewAppProvider(client, options) {
|
|
|
130
163
|
region: options.region
|
|
131
164
|
};
|
|
132
165
|
const deployResult = await sdk.deploy({
|
|
133
|
-
strategy: new
|
|
166
|
+
strategy: new AppBuildStrategy({
|
|
134
167
|
appPath: path.resolve(options.cwd),
|
|
135
168
|
entrypoint: options.entrypoint,
|
|
136
169
|
buildType: options.buildType,
|
|
137
|
-
signal: options.signal
|
|
170
|
+
signal: options.signal,
|
|
171
|
+
buildSettings: options.buildSettings
|
|
138
172
|
}),
|
|
139
173
|
projectId: options.projectId,
|
|
140
|
-
|
|
141
|
-
|
|
174
|
+
appId: resolvedApp.appId,
|
|
175
|
+
appName: resolvedApp.appName,
|
|
142
176
|
region: resolvedApp.region,
|
|
143
177
|
portMapping: options.portMapping,
|
|
144
178
|
envVars: options.envVars,
|
|
179
|
+
skipPromote: options.skipPromote,
|
|
145
180
|
timeoutSeconds: 120,
|
|
146
181
|
pollIntervalMs: 2e3,
|
|
147
182
|
interaction: options.interaction,
|
|
@@ -153,22 +188,24 @@ function createPreviewAppProvider(client, options) {
|
|
|
153
188
|
return {
|
|
154
189
|
projectId: deployed.projectId,
|
|
155
190
|
app: {
|
|
156
|
-
id: deployed.
|
|
157
|
-
name: deployed.
|
|
191
|
+
id: deployed.appId,
|
|
192
|
+
name: deployed.appName,
|
|
158
193
|
region: deployed.region ?? null,
|
|
159
|
-
liveDeploymentId: deployed.
|
|
160
|
-
liveUrl: toAbsoluteUrl(deployed.
|
|
194
|
+
liveDeploymentId: deployed.promoted ? deployed.deploymentId : deployed.previousDeploymentId,
|
|
195
|
+
liveUrl: toAbsoluteUrl(deployed.appEndpointDomain ?? null)
|
|
161
196
|
},
|
|
162
197
|
deployment: {
|
|
163
|
-
id: deployed.
|
|
198
|
+
id: deployed.deploymentId,
|
|
164
199
|
status: "running",
|
|
165
|
-
url: toAbsoluteUrl(deployed.
|
|
166
|
-
|
|
200
|
+
url: toAbsoluteUrl(deployed.appEndpointDomain ?? deployed.deploymentEndpointDomain ?? null),
|
|
201
|
+
live: deployed.promoted
|
|
202
|
+
},
|
|
203
|
+
promoted: deployed.promoted
|
|
167
204
|
};
|
|
168
205
|
},
|
|
169
206
|
async updateAppEnv(options) {
|
|
170
207
|
const updateResult = await sdk.updateEnv({
|
|
171
|
-
|
|
208
|
+
appId: options.appId,
|
|
172
209
|
envVars: options.envVars,
|
|
173
210
|
timeoutSeconds: 120,
|
|
174
211
|
pollIntervalMs: 2e3,
|
|
@@ -177,19 +214,19 @@ function createPreviewAppProvider(client, options) {
|
|
|
177
214
|
});
|
|
178
215
|
if (updateResult.isErr()) throw new Error(updateResult.error.message);
|
|
179
216
|
const promoteResult = await sdk.promote({
|
|
180
|
-
|
|
181
|
-
|
|
217
|
+
appId: options.appId,
|
|
218
|
+
deploymentId: updateResult.value.deploymentId,
|
|
182
219
|
timeoutSeconds: 120,
|
|
183
220
|
pollIntervalMs: 2e3,
|
|
184
221
|
signal: options.signal,
|
|
185
222
|
progress: options.promoteProgress
|
|
186
223
|
});
|
|
187
224
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
188
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
189
|
-
|
|
225
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
226
|
+
appId: options.appId,
|
|
190
227
|
signal: options.signal
|
|
191
|
-
}), sdk.
|
|
192
|
-
|
|
228
|
+
}), sdk.showDeployment({
|
|
229
|
+
deploymentId: updateResult.value.deploymentId,
|
|
193
230
|
signal: options.signal
|
|
194
231
|
})]);
|
|
195
232
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
@@ -200,25 +237,25 @@ function createPreviewAppProvider(client, options) {
|
|
|
200
237
|
id: serviceResult.value.id,
|
|
201
238
|
name: serviceResult.value.name,
|
|
202
239
|
region: serviceResult.value.region ?? null,
|
|
203
|
-
liveDeploymentId: serviceResult.value.
|
|
204
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
240
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
241
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
205
242
|
},
|
|
206
243
|
deployment: {
|
|
207
244
|
id: versionResult.value.id,
|
|
208
245
|
status: versionResult.value.status,
|
|
209
246
|
createdAt: versionResult.value.createdAt,
|
|
210
|
-
url: toAbsoluteUrl(serviceResult.value.
|
|
247
|
+
url: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? versionResult.value.previewDomain ?? null),
|
|
211
248
|
live: true
|
|
212
249
|
},
|
|
213
250
|
variables: envVarNames(versionResult.value.envVars)
|
|
214
251
|
};
|
|
215
252
|
},
|
|
216
253
|
async listAppEnvNames(options) {
|
|
217
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
218
|
-
|
|
254
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
255
|
+
appId: options.appId,
|
|
219
256
|
signal: options.signal
|
|
220
|
-
}), sdk.
|
|
221
|
-
|
|
257
|
+
}), sdk.showDeployment({
|
|
258
|
+
deploymentId: options.deploymentId,
|
|
222
259
|
signal: options.signal
|
|
223
260
|
})]);
|
|
224
261
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
@@ -229,25 +266,25 @@ function createPreviewAppProvider(client, options) {
|
|
|
229
266
|
id: serviceResult.value.id,
|
|
230
267
|
name: serviceResult.value.name,
|
|
231
268
|
region: serviceResult.value.region ?? null,
|
|
232
|
-
liveDeploymentId: serviceResult.value.
|
|
233
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
269
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
270
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
234
271
|
},
|
|
235
272
|
deployment: {
|
|
236
273
|
id: versionResult.value.id,
|
|
237
274
|
status: versionResult.value.status,
|
|
238
275
|
createdAt: versionResult.value.createdAt,
|
|
239
276
|
url: toAbsoluteUrl(versionResult.value.previewDomain ?? null),
|
|
240
|
-
live: serviceResult.value.
|
|
277
|
+
live: serviceResult.value.latestDeploymentId === versionResult.value.id
|
|
241
278
|
},
|
|
242
279
|
variables: envVarNames(versionResult.value.envVars)
|
|
243
280
|
};
|
|
244
281
|
},
|
|
245
282
|
async listDeployments(appId, options) {
|
|
246
|
-
const [appResult, versionsResult] = await Promise.all([sdk.
|
|
247
|
-
|
|
283
|
+
const [appResult, versionsResult] = await Promise.all([sdk.showApp({
|
|
284
|
+
appId,
|
|
248
285
|
signal: options?.signal
|
|
249
|
-
}), sdk.
|
|
250
|
-
|
|
286
|
+
}), sdk.listDeployments({
|
|
287
|
+
appId,
|
|
251
288
|
signal: options?.signal
|
|
252
289
|
})]);
|
|
253
290
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
@@ -257,8 +294,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
257
294
|
id: appResult.value.id,
|
|
258
295
|
name: appResult.value.name,
|
|
259
296
|
region: appResult.value.region ?? null,
|
|
260
|
-
liveDeploymentId: appResult.value.
|
|
261
|
-
liveUrl: toAbsoluteUrl(appResult.value.
|
|
297
|
+
liveDeploymentId: appResult.value.latestDeploymentId ?? null,
|
|
298
|
+
liveUrl: toAbsoluteUrl(appResult.value.appEndpointDomain ?? null)
|
|
262
299
|
},
|
|
263
300
|
deployments: versionsResult.value.slice().sort((left, right) => {
|
|
264
301
|
const byDate = right.createdAt.localeCompare(left.createdAt);
|
|
@@ -273,8 +310,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
273
310
|
};
|
|
274
311
|
},
|
|
275
312
|
async showDeployment(deploymentId, options) {
|
|
276
|
-
const deploymentResult = await sdk.
|
|
277
|
-
|
|
313
|
+
const deploymentResult = await sdk.showDeployment({
|
|
314
|
+
deploymentId,
|
|
278
315
|
signal: options?.signal
|
|
279
316
|
});
|
|
280
317
|
if (deploymentResult.isErr()) {
|
|
@@ -297,7 +334,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
297
334
|
const result = await streamLogs({
|
|
298
335
|
baseUrl: options.baseUrl,
|
|
299
336
|
token: await options.getToken(),
|
|
300
|
-
|
|
337
|
+
deploymentId: streamOptions.deploymentId,
|
|
301
338
|
signal: streamOptions.signal
|
|
302
339
|
}, streamOptions.onRecord);
|
|
303
340
|
if (result.isErr()) {
|
|
@@ -316,17 +353,19 @@ async function listBranches(client, options) {
|
|
|
316
353
|
signal: options.signal
|
|
317
354
|
});
|
|
318
355
|
if (result.error || !result.data) throw apiCallError("Failed to list branches", result.response, result.error);
|
|
319
|
-
return result.data.data
|
|
356
|
+
return result.data.data.map((branch) => ({
|
|
357
|
+
id: branch.id,
|
|
358
|
+
gitName: branch.gitName,
|
|
359
|
+
isDefault: branch.isDefault,
|
|
360
|
+
role: branch.role
|
|
361
|
+
}));
|
|
320
362
|
}
|
|
321
363
|
async function resolveOrCreateBranch(client, options) {
|
|
322
364
|
const existing = (await listBranches(client, options))[0];
|
|
323
365
|
if (existing) return existing;
|
|
324
366
|
const result = await client.POST("/v1/projects/{projectId}/branches", {
|
|
325
367
|
params: { path: { projectId: options.projectId } },
|
|
326
|
-
body: {
|
|
327
|
-
gitName: options.gitName,
|
|
328
|
-
isDefault: options.gitName === "main"
|
|
329
|
-
},
|
|
368
|
+
body: { gitName: options.gitName },
|
|
330
369
|
signal: options.signal
|
|
331
370
|
});
|
|
332
371
|
if (result.error || !result.data) {
|
|
@@ -336,13 +375,19 @@ async function resolveOrCreateBranch(client, options) {
|
|
|
336
375
|
}
|
|
337
376
|
throw apiCallError(`Failed to create branch "${options.gitName}"`, result.response, result.error);
|
|
338
377
|
}
|
|
339
|
-
|
|
378
|
+
const branch = result.data.data;
|
|
379
|
+
return {
|
|
380
|
+
id: branch.id,
|
|
381
|
+
gitName: branch.gitName,
|
|
382
|
+
isDefault: branch.isDefault,
|
|
383
|
+
role: branch.role
|
|
384
|
+
};
|
|
340
385
|
}
|
|
341
386
|
async function listComputeServices(client, options) {
|
|
342
387
|
const services = [];
|
|
343
388
|
let cursor;
|
|
344
389
|
while (true) {
|
|
345
|
-
const result = await client.GET("/v1/
|
|
390
|
+
const result = await client.GET("/v1/apps", {
|
|
346
391
|
params: { query: {
|
|
347
392
|
projectId: options.projectId,
|
|
348
393
|
branchGitName: options.branchGitName,
|
|
@@ -360,13 +405,13 @@ async function listComputeServices(client, options) {
|
|
|
360
405
|
name: service.name,
|
|
361
406
|
region: service.region.id ?? null,
|
|
362
407
|
branchId: service.branchId,
|
|
363
|
-
liveDeploymentId: service.
|
|
364
|
-
liveUrl: toAbsoluteUrl(service.
|
|
408
|
+
liveDeploymentId: service.latestDeploymentId ?? null,
|
|
409
|
+
liveUrl: toAbsoluteUrl(service.appEndpointDomain ?? null)
|
|
365
410
|
}));
|
|
366
411
|
}
|
|
367
|
-
async function listComputeServiceDomains(client,
|
|
368
|
-
const result = await client.GET("/v1/
|
|
369
|
-
params: { path: {
|
|
412
|
+
async function listComputeServiceDomains(client, appId, signal) {
|
|
413
|
+
const result = await client.GET("/v1/apps/{appId}/domains", {
|
|
414
|
+
params: { path: { appId } },
|
|
370
415
|
signal
|
|
371
416
|
});
|
|
372
417
|
if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
|
|
@@ -378,7 +423,7 @@ function normalizeDomainRecord(domain) {
|
|
|
378
423
|
type: domain.type,
|
|
379
424
|
url: domain.url,
|
|
380
425
|
hostname: domain.hostname,
|
|
381
|
-
|
|
426
|
+
appId: domain.appId,
|
|
382
427
|
status: domain.status,
|
|
383
428
|
foundryStatus: domain.foundryStatus,
|
|
384
429
|
failureReason: domain.failureReason,
|
|
@@ -413,7 +458,7 @@ async function createBranchApp(client, options) {
|
|
|
413
458
|
gitName: options.branchName,
|
|
414
459
|
signal: options.signal
|
|
415
460
|
});
|
|
416
|
-
const result = await client.POST("/v1/
|
|
461
|
+
const result = await client.POST("/v1/apps", {
|
|
417
462
|
body: {
|
|
418
463
|
projectId: options.projectId,
|
|
419
464
|
branchId: branch.id,
|
|
@@ -451,7 +496,7 @@ function apiCallError(summary, response, error) {
|
|
|
451
496
|
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
452
497
|
}
|
|
453
498
|
function domainApiCallError(summary, response, error) {
|
|
454
|
-
return new
|
|
499
|
+
return new DomainApiError({
|
|
455
500
|
summary,
|
|
456
501
|
status: response.status,
|
|
457
502
|
code: error.error?.code ?? null,
|
|
@@ -463,38 +508,42 @@ async function findAppForDeployment(sdk, deploymentId, signal) {
|
|
|
463
508
|
const projectsResult = await sdk.listProjects({ signal });
|
|
464
509
|
if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
|
|
465
510
|
for (const project of projectsResult.value) {
|
|
466
|
-
const servicesResult = await sdk.
|
|
511
|
+
const servicesResult = await sdk.listApps({
|
|
467
512
|
projectId: project.id,
|
|
468
513
|
signal
|
|
469
514
|
});
|
|
470
515
|
if (servicesResult.isErr()) throw new Error(servicesResult.error.message);
|
|
471
516
|
for (const service of servicesResult.value) {
|
|
472
|
-
const
|
|
473
|
-
|
|
474
|
-
signal
|
|
475
|
-
});
|
|
476
|
-
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
477
|
-
const app = {
|
|
478
|
-
id: detailResult.value.id,
|
|
479
|
-
name: detailResult.value.name,
|
|
480
|
-
region: detailResult.value.region ?? null,
|
|
481
|
-
liveDeploymentId: detailResult.value.latestVersionId ?? null,
|
|
482
|
-
liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
|
|
483
|
-
};
|
|
484
|
-
if (app.liveDeploymentId === deploymentId) return app;
|
|
485
|
-
const versionsResult = await sdk.listVersions({
|
|
486
|
-
serviceId: service.id,
|
|
487
|
-
signal
|
|
488
|
-
});
|
|
489
|
-
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
490
|
-
if (versionsResult.value.some((version) => version.id === deploymentId)) return app;
|
|
517
|
+
const app = await findServiceAppForDeployment(sdk, service.id, deploymentId, signal);
|
|
518
|
+
if (app) return app;
|
|
491
519
|
}
|
|
492
520
|
}
|
|
493
521
|
return null;
|
|
494
522
|
}
|
|
523
|
+
async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal) {
|
|
524
|
+
const detailResult = await sdk.showApp({
|
|
525
|
+
appId: serviceId,
|
|
526
|
+
signal
|
|
527
|
+
});
|
|
528
|
+
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
529
|
+
const app = {
|
|
530
|
+
id: detailResult.value.id,
|
|
531
|
+
name: detailResult.value.name,
|
|
532
|
+
region: detailResult.value.region ?? null,
|
|
533
|
+
liveDeploymentId: detailResult.value.latestDeploymentId ?? null,
|
|
534
|
+
liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null)
|
|
535
|
+
};
|
|
536
|
+
if (app.liveDeploymentId === deploymentId) return app;
|
|
537
|
+
const versionsResult = await sdk.listDeployments({
|
|
538
|
+
appId: serviceId,
|
|
539
|
+
signal
|
|
540
|
+
});
|
|
541
|
+
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
542
|
+
return versionsResult.value.some((version) => version.id === deploymentId) ? app : null;
|
|
543
|
+
}
|
|
495
544
|
function toAbsoluteUrl(url) {
|
|
496
545
|
if (!url) return null;
|
|
497
546
|
return url.startsWith("https://") || url.startsWith("http://") ? url : `https://${url}`;
|
|
498
547
|
}
|
|
499
548
|
//#endregion
|
|
500
|
-
export {
|
|
549
|
+
export { DomainApiError, createAppProvider };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
//#region src/lib/app/branch-database-api.ts
|
|
2
|
+
async function createBranchDatabase(client, options) {
|
|
3
|
+
const result = await client.POST("/v1/databases", {
|
|
4
|
+
body: {
|
|
5
|
+
projectId: options.projectId,
|
|
6
|
+
branchId: options.branchId,
|
|
7
|
+
name: options.branchName,
|
|
8
|
+
source: { type: "empty" }
|
|
9
|
+
},
|
|
10
|
+
signal: options.signal
|
|
11
|
+
});
|
|
12
|
+
if (result.error || !result.data) throw apiCallError(`Failed to create database for branch "${options.branchName}"`, result.response, result.error);
|
|
13
|
+
return normalizeBranchDatabaseRecord(result.data.data);
|
|
14
|
+
}
|
|
15
|
+
async function listEnvironmentVariables(client, options) {
|
|
16
|
+
const variables = [];
|
|
17
|
+
let cursor;
|
|
18
|
+
while (true) {
|
|
19
|
+
const result = await client.GET("/v1/environment-variables", {
|
|
20
|
+
params: { query: {
|
|
21
|
+
projectId: options.projectId,
|
|
22
|
+
class: options.className,
|
|
23
|
+
key: options.key,
|
|
24
|
+
branchId: options.branchId,
|
|
25
|
+
cursor
|
|
26
|
+
} },
|
|
27
|
+
signal: options.signal
|
|
28
|
+
});
|
|
29
|
+
if (result.error || !result.data) throw apiCallError("Failed to list environment variables", result.response, result.error);
|
|
30
|
+
variables.push(...result.data.data);
|
|
31
|
+
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
32
|
+
cursor = result.data.pagination.nextCursor;
|
|
33
|
+
}
|
|
34
|
+
return variables.map((variable) => normalizeEnvironmentVariable(variable));
|
|
35
|
+
}
|
|
36
|
+
async function createEnvironmentVariable(client, options) {
|
|
37
|
+
const result = await client.POST("/v1/environment-variables", {
|
|
38
|
+
body: {
|
|
39
|
+
projectId: options.projectId,
|
|
40
|
+
class: options.className,
|
|
41
|
+
key: options.key,
|
|
42
|
+
value: options.value,
|
|
43
|
+
...options.branchId ? { branchId: options.branchId } : {}
|
|
44
|
+
},
|
|
45
|
+
signal: options.signal
|
|
46
|
+
});
|
|
47
|
+
if (result.error || !result.data) throw apiCallError(`Failed to add ${options.key}`, result.response, result.error);
|
|
48
|
+
return normalizeEnvironmentVariable(result.data.data);
|
|
49
|
+
}
|
|
50
|
+
async function deleteBranchDatabase(client, options) {
|
|
51
|
+
const result = await client.DELETE("/v1/databases/{databaseId}", {
|
|
52
|
+
params: { path: { databaseId: options.databaseId } },
|
|
53
|
+
signal: options.signal
|
|
54
|
+
});
|
|
55
|
+
if (result.error) throw apiCallError("Failed to delete branch database", result.response, result.error);
|
|
56
|
+
}
|
|
57
|
+
async function updateEnvironmentVariable(client, options) {
|
|
58
|
+
const result = await client.PATCH("/v1/environment-variables/{envVarId}", {
|
|
59
|
+
params: { path: { envVarId: options.envVarId } },
|
|
60
|
+
body: { value: options.value },
|
|
61
|
+
signal: options.signal
|
|
62
|
+
});
|
|
63
|
+
if (result.error || !result.data) throw apiCallError("Failed to update environment variable", result.response, result.error);
|
|
64
|
+
return normalizeEnvironmentVariable(result.data.data);
|
|
65
|
+
}
|
|
66
|
+
async function deleteEnvironmentVariable(client, options) {
|
|
67
|
+
const result = await client.DELETE("/v1/environment-variables/{envVarId}", {
|
|
68
|
+
params: { path: { envVarId: options.envVarId } },
|
|
69
|
+
signal: options.signal
|
|
70
|
+
});
|
|
71
|
+
if (result.error) throw apiCallError("Failed to delete environment variable", result.response, result.error);
|
|
72
|
+
}
|
|
73
|
+
function normalizeEnvironmentVariable(variable) {
|
|
74
|
+
return {
|
|
75
|
+
id: variable.id,
|
|
76
|
+
key: variable.key,
|
|
77
|
+
branchId: variable.branchId,
|
|
78
|
+
className: variable.class,
|
|
79
|
+
isManagedBySystem: variable.isManagedBySystem
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function normalizeBranchDatabaseRecord(database) {
|
|
83
|
+
const connection = database.connections?.[0];
|
|
84
|
+
const databaseUrl = connection?.endpoints?.pooled?.connectionString;
|
|
85
|
+
const directUrl = connection?.endpoints?.direct?.connectionString ?? null;
|
|
86
|
+
if (!databaseUrl) throw new Error("Created database did not return a pooled connection string.");
|
|
87
|
+
return {
|
|
88
|
+
id: database.id,
|
|
89
|
+
name: database.name,
|
|
90
|
+
branchId: database.branchId,
|
|
91
|
+
databaseUrl,
|
|
92
|
+
directUrl
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function apiCallError(summary, response, error) {
|
|
96
|
+
if (response.status === 404) return /* @__PURE__ */ new Error("Resource Not Found");
|
|
97
|
+
const message = error.error?.message ?? `Management API returned HTTP ${response.status}.`;
|
|
98
|
+
const hint = error.error?.hint ? ` ${error.error.hint}` : "";
|
|
99
|
+
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
export { createBranchDatabase, createEnvironmentVariable, deleteBranchDatabase, deleteEnvironmentVariable, listEnvironmentVariables, updateEnvironmentVariable };
|