@prisma/cli 3.0.0-beta.2 → 3.0.0-beta.20
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 +5 -16
- package/dist/adapters/git.js +8 -3
- package/dist/adapters/local-state.js +26 -7
- package/dist/adapters/mock-api.js +81 -2
- package/dist/adapters/token-storage.js +344 -25
- package/dist/cli.js +18 -3
- package/dist/cli2.js +12 -4
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +90 -61
- package/dist/commands/auth/index.js +55 -2
- package/dist/commands/branch/index.js +2 -27
- package/dist/commands/build/index.js +29 -0
- package/dist/commands/database/index.js +159 -0
- package/dist/commands/env.js +8 -4
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/project/index.js +1 -1
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app-env-api.js +54 -0
- package/dist/controllers/app-env-file.js +181 -0
- package/dist/controllers/app-env.js +286 -131
- package/dist/controllers/app.js +849 -309
- package/dist/controllers/auth.js +255 -11
- package/dist/controllers/branch.js +78 -48
- package/dist/controllers/build.js +88 -0
- package/dist/controllers/database.js +318 -0
- package/dist/controllers/project.js +156 -87
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/lib/agent/cli-command.js +17 -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/app-interaction.js +5 -0
- package/dist/lib/app/{preview-provider.js → app-provider.js} +220 -104
- 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 +82 -0
- package/dist/lib/app/bun-project.js +15 -9
- 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 +8 -49
- 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 +38 -23
- package/dist/lib/auth/guard.js +6 -2
- package/dist/lib/auth/login.js +117 -15
- package/dist/lib/database/provider.js +167 -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 +2 -1
- package/dist/lib/project/local-pin.js +183 -34
- package/dist/lib/project/resolution.js +206 -50
- package/dist/lib/project/setup.js +64 -18
- 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 +187 -26
- package/dist/presenters/auth.js +99 -2
- package/dist/presenters/branch.js +37 -102
- package/dist/presenters/database.js +274 -0
- package/dist/presenters/project.js +44 -26
- 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 +243 -15
- package/dist/shell/command-runner.js +60 -21
- package/dist/shell/diagnostics-output.js +57 -0
- package/dist/shell/errors.js +61 -1
- package/dist/shell/help.js +31 -20
- package/dist/shell/output.js +10 -1
- package/dist/shell/prompt.js +7 -3
- package/dist/shell/runtime.js +10 -6
- package/dist/shell/ui.js +42 -3
- package/dist/shell/update-check.js +247 -0
- 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/package.json +27 -10
- package/dist/lib/app/preview-build.js +0 -284
- 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,25 +1,29 @@
|
|
|
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
|
-
const projectResult = await sdk.createProject({
|
|
23
|
+
const projectResult = await sdk.createProject({
|
|
24
|
+
name: options.name,
|
|
25
|
+
signal: options.signal
|
|
26
|
+
});
|
|
23
27
|
if (projectResult.isErr()) throw new Error(projectResult.error.message);
|
|
24
28
|
return {
|
|
25
29
|
id: projectResult.value.id,
|
|
@@ -29,17 +33,52 @@ function createPreviewAppProvider(client, options) {
|
|
|
29
33
|
async listApps(projectId, options) {
|
|
30
34
|
return listComputeServices(client, {
|
|
31
35
|
projectId,
|
|
32
|
-
branchGitName: options?.branchName
|
|
36
|
+
branchGitName: options?.branchName,
|
|
37
|
+
signal: options?.signal
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
async resolveBranch(projectId, options) {
|
|
41
|
+
const branch = await resolveOrCreateBranch(client, {
|
|
42
|
+
projectId,
|
|
43
|
+
gitName: options.branchName,
|
|
44
|
+
signal: options.signal
|
|
33
45
|
});
|
|
46
|
+
return {
|
|
47
|
+
id: branch.id,
|
|
48
|
+
name: branch.gitName,
|
|
49
|
+
role: branch.role
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
async createBranchDatabase(options) {
|
|
53
|
+
return createBranchDatabase(client, options);
|
|
54
|
+
},
|
|
55
|
+
async deleteBranchDatabase(options) {
|
|
56
|
+
return deleteBranchDatabase(client, options);
|
|
57
|
+
},
|
|
58
|
+
async listEnvironmentVariables(options) {
|
|
59
|
+
return listEnvironmentVariables(client, options);
|
|
60
|
+
},
|
|
61
|
+
async createEnvironmentVariable(options) {
|
|
62
|
+
return createEnvironmentVariable(client, options);
|
|
63
|
+
},
|
|
64
|
+
async updateEnvironmentVariable(options) {
|
|
65
|
+
return updateEnvironmentVariable(client, options);
|
|
66
|
+
},
|
|
67
|
+
async deleteEnvironmentVariable(options) {
|
|
68
|
+
return deleteEnvironmentVariable(client, options);
|
|
34
69
|
},
|
|
35
|
-
async removeApp(appId) {
|
|
36
|
-
const appResult = await sdk.
|
|
70
|
+
async removeApp(appId, options) {
|
|
71
|
+
const appResult = await sdk.showApp({
|
|
72
|
+
appId,
|
|
73
|
+
signal: options?.signal
|
|
74
|
+
});
|
|
37
75
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
38
|
-
const destroyResult = await sdk.
|
|
39
|
-
|
|
40
|
-
|
|
76
|
+
const destroyResult = await sdk.destroyApp({
|
|
77
|
+
appId,
|
|
78
|
+
keepApp: false,
|
|
41
79
|
timeoutSeconds: 120,
|
|
42
|
-
pollIntervalMs: 2e3
|
|
80
|
+
pollIntervalMs: 2e3,
|
|
81
|
+
signal: options?.signal
|
|
43
82
|
});
|
|
44
83
|
if (destroyResult.isErr()) throw new Error(destroyResult.error.message);
|
|
45
84
|
return {
|
|
@@ -47,17 +86,18 @@ function createPreviewAppProvider(client, options) {
|
|
|
47
86
|
name: appResult.value.name
|
|
48
87
|
};
|
|
49
88
|
},
|
|
50
|
-
async listDomains(appId) {
|
|
51
|
-
return listComputeServiceDomains(client, appId);
|
|
89
|
+
async listDomains(appId, options) {
|
|
90
|
+
return listComputeServiceDomains(client, appId, options?.signal);
|
|
52
91
|
},
|
|
53
92
|
async addDomain(options) {
|
|
54
|
-
const result = await client.POST("/v1/
|
|
55
|
-
params: { path: {
|
|
56
|
-
body: { hostname: options.hostname }
|
|
93
|
+
const result = await client.POST("/v1/apps/{appId}/domains", {
|
|
94
|
+
params: { path: { appId: options.appId } },
|
|
95
|
+
body: { hostname: options.hostname },
|
|
96
|
+
signal: options.signal
|
|
57
97
|
});
|
|
58
98
|
if (result.error || !result.data) {
|
|
59
99
|
if (result.response.status === 409) {
|
|
60
|
-
const existing = (await listComputeServiceDomains(client, options.appId)).find((domain) => sameHostname(domain.hostname, options.hostname));
|
|
100
|
+
const existing = (await listComputeServiceDomains(client, options.appId, options.signal)).find((domain) => sameHostname(domain.hostname, options.hostname));
|
|
61
101
|
if (existing) return {
|
|
62
102
|
domain: existing,
|
|
63
103
|
existing: true
|
|
@@ -70,26 +110,36 @@ function createPreviewAppProvider(client, options) {
|
|
|
70
110
|
existing: false
|
|
71
111
|
};
|
|
72
112
|
},
|
|
73
|
-
async showDomain(domainId) {
|
|
74
|
-
const result = await client.GET("/v1/domains/{domainId}", {
|
|
113
|
+
async showDomain(domainId, options) {
|
|
114
|
+
const result = await client.GET("/v1/domains/{domainId}", {
|
|
115
|
+
params: { path: { domainId } },
|
|
116
|
+
signal: options?.signal
|
|
117
|
+
});
|
|
75
118
|
if (result.error || !result.data) throw domainApiCallError("Failed to show custom domain", result.response, result.error);
|
|
76
119
|
return normalizeDomainRecord(result.data.data);
|
|
77
120
|
},
|
|
78
|
-
async removeDomain(domainId) {
|
|
79
|
-
const result = await client.DELETE("/v1/domains/{domainId}", {
|
|
121
|
+
async removeDomain(domainId, options) {
|
|
122
|
+
const result = await client.DELETE("/v1/domains/{domainId}", {
|
|
123
|
+
params: { path: { domainId } },
|
|
124
|
+
signal: options?.signal
|
|
125
|
+
});
|
|
80
126
|
if (result.error) throw domainApiCallError("Failed to remove custom domain", result.response, result.error);
|
|
81
127
|
},
|
|
82
|
-
async retryDomain(domainId) {
|
|
83
|
-
const result = await client.POST("/v1/domains/{domainId}/retry", {
|
|
128
|
+
async retryDomain(domainId, options) {
|
|
129
|
+
const result = await client.POST("/v1/domains/{domainId}/retry", {
|
|
130
|
+
params: { path: { domainId } },
|
|
131
|
+
signal: options?.signal
|
|
132
|
+
});
|
|
84
133
|
if (result.error || !result.data) throw domainApiCallError("Failed to retry custom domain", result.response, result.error);
|
|
85
134
|
return normalizeDomainRecord(result.data.data);
|
|
86
135
|
},
|
|
87
136
|
async promoteDeployment(options) {
|
|
88
137
|
const promoteResult = await sdk.promote({
|
|
89
|
-
|
|
90
|
-
|
|
138
|
+
appId: options.appId,
|
|
139
|
+
deploymentId: options.deploymentId,
|
|
91
140
|
timeoutSeconds: 120,
|
|
92
141
|
pollIntervalMs: 2e3,
|
|
142
|
+
signal: options.signal,
|
|
93
143
|
progress: options.progress
|
|
94
144
|
});
|
|
95
145
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
@@ -103,27 +153,32 @@ function createPreviewAppProvider(client, options) {
|
|
|
103
153
|
projectId: options.projectId,
|
|
104
154
|
branchName: options.branchName,
|
|
105
155
|
appName: options.appName,
|
|
106
|
-
region: options.region
|
|
156
|
+
region: options.region,
|
|
157
|
+
signal: options.signal
|
|
107
158
|
}) : {
|
|
108
159
|
appId: void 0,
|
|
109
160
|
appName: options.appName,
|
|
110
161
|
region: options.region
|
|
111
162
|
};
|
|
112
163
|
const deployResult = await sdk.deploy({
|
|
113
|
-
strategy: new
|
|
164
|
+
strategy: new AppBuildStrategy({
|
|
114
165
|
appPath: path.resolve(options.cwd),
|
|
115
166
|
entrypoint: options.entrypoint,
|
|
116
|
-
buildType: options.buildType
|
|
167
|
+
buildType: options.buildType,
|
|
168
|
+
signal: options.signal,
|
|
169
|
+
buildSettings: options.buildSettings
|
|
117
170
|
}),
|
|
118
171
|
projectId: options.projectId,
|
|
119
|
-
|
|
120
|
-
|
|
172
|
+
appId: resolvedApp.appId,
|
|
173
|
+
appName: resolvedApp.appName,
|
|
121
174
|
region: resolvedApp.region,
|
|
122
175
|
portMapping: options.portMapping,
|
|
123
176
|
envVars: options.envVars,
|
|
177
|
+
skipPromote: options.skipPromote,
|
|
124
178
|
timeoutSeconds: 120,
|
|
125
179
|
pollIntervalMs: 2e3,
|
|
126
180
|
interaction: options.interaction,
|
|
181
|
+
signal: options.signal,
|
|
127
182
|
progress: options.progress
|
|
128
183
|
});
|
|
129
184
|
if (deployResult.isErr()) throw new Error(deployResult.error.message);
|
|
@@ -131,37 +186,47 @@ function createPreviewAppProvider(client, options) {
|
|
|
131
186
|
return {
|
|
132
187
|
projectId: deployed.projectId,
|
|
133
188
|
app: {
|
|
134
|
-
id: deployed.
|
|
135
|
-
name: deployed.
|
|
189
|
+
id: deployed.appId,
|
|
190
|
+
name: deployed.appName,
|
|
136
191
|
region: deployed.region ?? null,
|
|
137
|
-
liveDeploymentId: deployed.
|
|
138
|
-
liveUrl: toAbsoluteUrl(deployed.
|
|
192
|
+
liveDeploymentId: deployed.promoted ? deployed.deploymentId : deployed.previousDeploymentId,
|
|
193
|
+
liveUrl: toAbsoluteUrl(deployed.appEndpointDomain ?? null)
|
|
139
194
|
},
|
|
140
195
|
deployment: {
|
|
141
|
-
id: deployed.
|
|
196
|
+
id: deployed.deploymentId,
|
|
142
197
|
status: "running",
|
|
143
|
-
url: toAbsoluteUrl(deployed.
|
|
144
|
-
|
|
198
|
+
url: toAbsoluteUrl(deployed.appEndpointDomain ?? deployed.deploymentEndpointDomain ?? null),
|
|
199
|
+
live: deployed.promoted
|
|
200
|
+
},
|
|
201
|
+
promoted: deployed.promoted
|
|
145
202
|
};
|
|
146
203
|
},
|
|
147
204
|
async updateAppEnv(options) {
|
|
148
205
|
const updateResult = await sdk.updateEnv({
|
|
149
|
-
|
|
206
|
+
appId: options.appId,
|
|
150
207
|
envVars: options.envVars,
|
|
151
208
|
timeoutSeconds: 120,
|
|
152
209
|
pollIntervalMs: 2e3,
|
|
210
|
+
signal: options.signal,
|
|
153
211
|
progress: options.progress
|
|
154
212
|
});
|
|
155
213
|
if (updateResult.isErr()) throw new Error(updateResult.error.message);
|
|
156
214
|
const promoteResult = await sdk.promote({
|
|
157
|
-
|
|
158
|
-
|
|
215
|
+
appId: options.appId,
|
|
216
|
+
deploymentId: updateResult.value.deploymentId,
|
|
159
217
|
timeoutSeconds: 120,
|
|
160
218
|
pollIntervalMs: 2e3,
|
|
219
|
+
signal: options.signal,
|
|
161
220
|
progress: options.promoteProgress
|
|
162
221
|
});
|
|
163
222
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
164
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
223
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
224
|
+
appId: options.appId,
|
|
225
|
+
signal: options.signal
|
|
226
|
+
}), sdk.showDeployment({
|
|
227
|
+
deploymentId: updateResult.value.deploymentId,
|
|
228
|
+
signal: options.signal
|
|
229
|
+
})]);
|
|
165
230
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
166
231
|
if (versionResult.isErr()) throw new Error(versionResult.error.message);
|
|
167
232
|
return {
|
|
@@ -170,21 +235,27 @@ function createPreviewAppProvider(client, options) {
|
|
|
170
235
|
id: serviceResult.value.id,
|
|
171
236
|
name: serviceResult.value.name,
|
|
172
237
|
region: serviceResult.value.region ?? null,
|
|
173
|
-
liveDeploymentId: serviceResult.value.
|
|
174
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
238
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
239
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
175
240
|
},
|
|
176
241
|
deployment: {
|
|
177
242
|
id: versionResult.value.id,
|
|
178
243
|
status: versionResult.value.status,
|
|
179
244
|
createdAt: versionResult.value.createdAt,
|
|
180
|
-
url: toAbsoluteUrl(serviceResult.value.
|
|
245
|
+
url: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? versionResult.value.previewDomain ?? null),
|
|
181
246
|
live: true
|
|
182
247
|
},
|
|
183
248
|
variables: envVarNames(versionResult.value.envVars)
|
|
184
249
|
};
|
|
185
250
|
},
|
|
186
251
|
async listAppEnvNames(options) {
|
|
187
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.
|
|
252
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showApp({
|
|
253
|
+
appId: options.appId,
|
|
254
|
+
signal: options.signal
|
|
255
|
+
}), sdk.showDeployment({
|
|
256
|
+
deploymentId: options.deploymentId,
|
|
257
|
+
signal: options.signal
|
|
258
|
+
})]);
|
|
188
259
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
189
260
|
if (versionResult.isErr()) throw new Error(versionResult.error.message);
|
|
190
261
|
return {
|
|
@@ -193,21 +264,27 @@ function createPreviewAppProvider(client, options) {
|
|
|
193
264
|
id: serviceResult.value.id,
|
|
194
265
|
name: serviceResult.value.name,
|
|
195
266
|
region: serviceResult.value.region ?? null,
|
|
196
|
-
liveDeploymentId: serviceResult.value.
|
|
197
|
-
liveUrl: toAbsoluteUrl(serviceResult.value.
|
|
267
|
+
liveDeploymentId: serviceResult.value.latestDeploymentId ?? null,
|
|
268
|
+
liveUrl: toAbsoluteUrl(serviceResult.value.appEndpointDomain ?? null)
|
|
198
269
|
},
|
|
199
270
|
deployment: {
|
|
200
271
|
id: versionResult.value.id,
|
|
201
272
|
status: versionResult.value.status,
|
|
202
273
|
createdAt: versionResult.value.createdAt,
|
|
203
274
|
url: toAbsoluteUrl(versionResult.value.previewDomain ?? null),
|
|
204
|
-
live: serviceResult.value.
|
|
275
|
+
live: serviceResult.value.latestDeploymentId === versionResult.value.id
|
|
205
276
|
},
|
|
206
277
|
variables: envVarNames(versionResult.value.envVars)
|
|
207
278
|
};
|
|
208
279
|
},
|
|
209
|
-
async listDeployments(appId) {
|
|
210
|
-
const [appResult, versionsResult] = await Promise.all([sdk.
|
|
280
|
+
async listDeployments(appId, options) {
|
|
281
|
+
const [appResult, versionsResult] = await Promise.all([sdk.showApp({
|
|
282
|
+
appId,
|
|
283
|
+
signal: options?.signal
|
|
284
|
+
}), sdk.listDeployments({
|
|
285
|
+
appId,
|
|
286
|
+
signal: options?.signal
|
|
287
|
+
})]);
|
|
211
288
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
212
289
|
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
213
290
|
return {
|
|
@@ -215,8 +292,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
215
292
|
id: appResult.value.id,
|
|
216
293
|
name: appResult.value.name,
|
|
217
294
|
region: appResult.value.region ?? null,
|
|
218
|
-
liveDeploymentId: appResult.value.
|
|
219
|
-
liveUrl: toAbsoluteUrl(appResult.value.
|
|
295
|
+
liveDeploymentId: appResult.value.latestDeploymentId ?? null,
|
|
296
|
+
liveUrl: toAbsoluteUrl(appResult.value.appEndpointDomain ?? null)
|
|
220
297
|
},
|
|
221
298
|
deployments: versionsResult.value.slice().sort((left, right) => {
|
|
222
299
|
const byDate = right.createdAt.localeCompare(left.createdAt);
|
|
@@ -230,14 +307,17 @@ function createPreviewAppProvider(client, options) {
|
|
|
230
307
|
}))
|
|
231
308
|
};
|
|
232
309
|
},
|
|
233
|
-
async showDeployment(deploymentId) {
|
|
234
|
-
const deploymentResult = await sdk.
|
|
310
|
+
async showDeployment(deploymentId, options) {
|
|
311
|
+
const deploymentResult = await sdk.showDeployment({
|
|
312
|
+
deploymentId,
|
|
313
|
+
signal: options?.signal
|
|
314
|
+
});
|
|
235
315
|
if (deploymentResult.isErr()) {
|
|
236
316
|
if (ApiError.is(deploymentResult.error) && deploymentResult.error.statusCode === 404) return null;
|
|
237
317
|
throw new Error(deploymentResult.error.message);
|
|
238
318
|
}
|
|
239
319
|
return {
|
|
240
|
-
app: await findAppForDeployment(sdk, deploymentId),
|
|
320
|
+
app: await findAppForDeployment(sdk, deploymentId, options?.signal),
|
|
241
321
|
deployment: {
|
|
242
322
|
id: deploymentResult.value.id,
|
|
243
323
|
status: deploymentResult.value.status,
|
|
@@ -252,7 +332,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
252
332
|
const result = await streamLogs({
|
|
253
333
|
baseUrl: options.baseUrl,
|
|
254
334
|
token: await options.getToken(),
|
|
255
|
-
|
|
335
|
+
deploymentId: streamOptions.deploymentId,
|
|
256
336
|
signal: streamOptions.signal
|
|
257
337
|
}, streamOptions.onRecord);
|
|
258
338
|
if (result.isErr()) {
|
|
@@ -263,22 +343,28 @@ function createPreviewAppProvider(client, options) {
|
|
|
263
343
|
};
|
|
264
344
|
}
|
|
265
345
|
async function listBranches(client, options) {
|
|
266
|
-
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
346
|
+
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
347
|
+
params: {
|
|
348
|
+
path: { projectId: options.projectId },
|
|
349
|
+
query: { gitName: options.gitName }
|
|
350
|
+
},
|
|
351
|
+
signal: options.signal
|
|
352
|
+
});
|
|
270
353
|
if (result.error || !result.data) throw apiCallError("Failed to list branches", result.response, result.error);
|
|
271
|
-
return result.data.data
|
|
354
|
+
return result.data.data.map((branch) => ({
|
|
355
|
+
id: branch.id,
|
|
356
|
+
gitName: branch.gitName,
|
|
357
|
+
isDefault: branch.isDefault,
|
|
358
|
+
role: branch.role
|
|
359
|
+
}));
|
|
272
360
|
}
|
|
273
361
|
async function resolveOrCreateBranch(client, options) {
|
|
274
362
|
const existing = (await listBranches(client, options))[0];
|
|
275
363
|
if (existing) return existing;
|
|
276
364
|
const result = await client.POST("/v1/projects/{projectId}/branches", {
|
|
277
365
|
params: { path: { projectId: options.projectId } },
|
|
278
|
-
body: {
|
|
279
|
-
|
|
280
|
-
isDefault: options.gitName === "main"
|
|
281
|
-
}
|
|
366
|
+
body: { gitName: options.gitName },
|
|
367
|
+
signal: options.signal
|
|
282
368
|
});
|
|
283
369
|
if (result.error || !result.data) {
|
|
284
370
|
if (result.response.status === 409) {
|
|
@@ -287,17 +373,26 @@ async function resolveOrCreateBranch(client, options) {
|
|
|
287
373
|
}
|
|
288
374
|
throw apiCallError(`Failed to create branch "${options.gitName}"`, result.response, result.error);
|
|
289
375
|
}
|
|
290
|
-
|
|
376
|
+
const branch = result.data.data;
|
|
377
|
+
return {
|
|
378
|
+
id: branch.id,
|
|
379
|
+
gitName: branch.gitName,
|
|
380
|
+
isDefault: branch.isDefault,
|
|
381
|
+
role: branch.role
|
|
382
|
+
};
|
|
291
383
|
}
|
|
292
384
|
async function listComputeServices(client, options) {
|
|
293
385
|
const services = [];
|
|
294
386
|
let cursor;
|
|
295
387
|
while (true) {
|
|
296
|
-
const result = await client.GET("/v1/
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
388
|
+
const result = await client.GET("/v1/apps", {
|
|
389
|
+
params: { query: {
|
|
390
|
+
projectId: options.projectId,
|
|
391
|
+
branchGitName: options.branchGitName,
|
|
392
|
+
cursor
|
|
393
|
+
} },
|
|
394
|
+
signal: options.signal
|
|
395
|
+
});
|
|
301
396
|
if (result.error || !result.data) throw apiCallError("Failed to list apps", result.response, result.error);
|
|
302
397
|
services.push(...result.data.data);
|
|
303
398
|
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
@@ -308,12 +403,15 @@ async function listComputeServices(client, options) {
|
|
|
308
403
|
name: service.name,
|
|
309
404
|
region: service.region.id ?? null,
|
|
310
405
|
branchId: service.branchId,
|
|
311
|
-
liveDeploymentId: service.
|
|
312
|
-
liveUrl: toAbsoluteUrl(service.
|
|
406
|
+
liveDeploymentId: service.latestDeploymentId ?? null,
|
|
407
|
+
liveUrl: toAbsoluteUrl(service.appEndpointDomain ?? null)
|
|
313
408
|
}));
|
|
314
409
|
}
|
|
315
|
-
async function listComputeServiceDomains(client,
|
|
316
|
-
const result = await client.GET("/v1/
|
|
410
|
+
async function listComputeServiceDomains(client, appId, signal) {
|
|
411
|
+
const result = await client.GET("/v1/apps/{appId}/domains", {
|
|
412
|
+
params: { path: { appId } },
|
|
413
|
+
signal
|
|
414
|
+
});
|
|
317
415
|
if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
|
|
318
416
|
return result.data.data.map((domain) => normalizeDomainRecord(domain));
|
|
319
417
|
}
|
|
@@ -323,7 +421,7 @@ function normalizeDomainRecord(domain) {
|
|
|
323
421
|
type: domain.type,
|
|
324
422
|
url: domain.url,
|
|
325
423
|
hostname: domain.hostname,
|
|
326
|
-
|
|
424
|
+
appId: domain.appId,
|
|
327
425
|
status: domain.status,
|
|
328
426
|
foundryStatus: domain.foundryStatus,
|
|
329
427
|
failureReason: domain.failureReason,
|
|
@@ -355,19 +453,24 @@ function normalizeHostnameForComparison(hostname) {
|
|
|
355
453
|
async function createBranchApp(client, options) {
|
|
356
454
|
const branch = await resolveOrCreateBranch(client, {
|
|
357
455
|
projectId: options.projectId,
|
|
358
|
-
gitName: options.branchName
|
|
456
|
+
gitName: options.branchName,
|
|
457
|
+
signal: options.signal
|
|
458
|
+
});
|
|
459
|
+
const result = await client.POST("/v1/apps", {
|
|
460
|
+
body: {
|
|
461
|
+
projectId: options.projectId,
|
|
462
|
+
branchId: branch.id,
|
|
463
|
+
displayName: options.appName,
|
|
464
|
+
...options.region ? { regionId: options.region } : {}
|
|
465
|
+
},
|
|
466
|
+
signal: options.signal
|
|
359
467
|
});
|
|
360
|
-
const result = await client.POST("/v1/compute-services", { body: {
|
|
361
|
-
projectId: options.projectId,
|
|
362
|
-
branchId: branch.id,
|
|
363
|
-
displayName: options.appName,
|
|
364
|
-
...options.region ? { regionId: options.region } : {}
|
|
365
|
-
} });
|
|
366
468
|
if (result.error || !result.data) {
|
|
367
469
|
if (result.response.status === 409) {
|
|
368
470
|
const matched = (await listComputeServices(client, {
|
|
369
471
|
projectId: options.projectId,
|
|
370
|
-
branchGitName: options.branchName
|
|
472
|
+
branchGitName: options.branchName,
|
|
473
|
+
signal: options.signal
|
|
371
474
|
})).find((app) => app.name === options.appName);
|
|
372
475
|
if (matched) return {
|
|
373
476
|
appId: matched.id,
|
|
@@ -391,7 +494,7 @@ function apiCallError(summary, response, error) {
|
|
|
391
494
|
return /* @__PURE__ */ new Error(`${summary}: ${message}${hint}`);
|
|
392
495
|
}
|
|
393
496
|
function domainApiCallError(summary, response, error) {
|
|
394
|
-
return new
|
|
497
|
+
return new DomainApiError({
|
|
395
498
|
summary,
|
|
396
499
|
status: response.status,
|
|
397
500
|
code: error.error?.code ?? null,
|
|
@@ -399,33 +502,46 @@ function domainApiCallError(summary, response, error) {
|
|
|
399
502
|
hint: error.error?.hint ?? null
|
|
400
503
|
});
|
|
401
504
|
}
|
|
402
|
-
async function findAppForDeployment(sdk, deploymentId) {
|
|
403
|
-
const projectsResult = await sdk.listProjects();
|
|
505
|
+
async function findAppForDeployment(sdk, deploymentId, signal) {
|
|
506
|
+
const projectsResult = await sdk.listProjects({ signal });
|
|
404
507
|
if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
|
|
405
508
|
for (const project of projectsResult.value) {
|
|
406
|
-
const servicesResult = await sdk.
|
|
509
|
+
const servicesResult = await sdk.listApps({
|
|
510
|
+
projectId: project.id,
|
|
511
|
+
signal
|
|
512
|
+
});
|
|
407
513
|
if (servicesResult.isErr()) throw new Error(servicesResult.error.message);
|
|
408
514
|
for (const service of servicesResult.value) {
|
|
409
|
-
const
|
|
410
|
-
if (
|
|
411
|
-
const app = {
|
|
412
|
-
id: detailResult.value.id,
|
|
413
|
-
name: detailResult.value.name,
|
|
414
|
-
region: detailResult.value.region ?? null,
|
|
415
|
-
liveDeploymentId: detailResult.value.latestVersionId ?? null,
|
|
416
|
-
liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
|
|
417
|
-
};
|
|
418
|
-
if (app.liveDeploymentId === deploymentId) return app;
|
|
419
|
-
const versionsResult = await sdk.listVersions({ serviceId: service.id });
|
|
420
|
-
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
421
|
-
if (versionsResult.value.some((version) => version.id === deploymentId)) return app;
|
|
515
|
+
const app = await findServiceAppForDeployment(sdk, service.id, deploymentId, signal);
|
|
516
|
+
if (app) return app;
|
|
422
517
|
}
|
|
423
518
|
}
|
|
424
519
|
return null;
|
|
425
520
|
}
|
|
521
|
+
async function findServiceAppForDeployment(sdk, serviceId, deploymentId, signal) {
|
|
522
|
+
const detailResult = await sdk.showApp({
|
|
523
|
+
appId: serviceId,
|
|
524
|
+
signal
|
|
525
|
+
});
|
|
526
|
+
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
527
|
+
const app = {
|
|
528
|
+
id: detailResult.value.id,
|
|
529
|
+
name: detailResult.value.name,
|
|
530
|
+
region: detailResult.value.region ?? null,
|
|
531
|
+
liveDeploymentId: detailResult.value.latestDeploymentId ?? null,
|
|
532
|
+
liveUrl: toAbsoluteUrl(detailResult.value.appEndpointDomain ?? null)
|
|
533
|
+
};
|
|
534
|
+
if (app.liveDeploymentId === deploymentId) return app;
|
|
535
|
+
const versionsResult = await sdk.listDeployments({
|
|
536
|
+
appId: serviceId,
|
|
537
|
+
signal
|
|
538
|
+
});
|
|
539
|
+
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
540
|
+
return versionsResult.value.some((version) => version.id === deploymentId) ? app : null;
|
|
541
|
+
}
|
|
426
542
|
function toAbsoluteUrl(url) {
|
|
427
543
|
if (!url) return null;
|
|
428
544
|
return url.startsWith("https://") || url.startsWith("http://") ? url : `https://${url}`;
|
|
429
545
|
}
|
|
430
546
|
//#endregion
|
|
431
|
-
export {
|
|
547
|
+
export { DomainApiError, createAppProvider };
|