@prisma/cli 3.0.0-dev.53.1 → 3.0.0-dev.54.1
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 +8 -3
- package/dist/adapters/local-state.js +11 -3
- package/dist/adapters/mock-api.js +6 -2
- package/dist/adapters/token-storage.js +63 -22
- package/dist/cli.js +14 -3
- package/dist/cli2.js +1 -0
- package/dist/controllers/app-env.js +78 -46
- package/dist/controllers/app.js +111 -62
- package/dist/controllers/auth.js +8 -8
- package/dist/controllers/project.js +107 -67
- package/dist/lib/app/bun-project.js +12 -5
- package/dist/lib/app/local-dev.js +34 -18
- package/dist/lib/app/preview-build.js +90 -62
- package/dist/lib/app/preview-provider.js +118 -49
- package/dist/lib/auth/auth-ops.js +30 -21
- package/dist/lib/auth/guard.js +3 -2
- package/dist/lib/auth/login.js +31 -17
- package/dist/lib/project/interactive-setup.js +1 -1
- package/dist/lib/project/local-pin.js +27 -8
- package/dist/lib/project/resolution.js +14 -8
- package/dist/lib/project/setup.js +2 -2
- package/dist/shell/command-runner.js +9 -4
- package/dist/shell/errors.js +12 -1
- package/dist/shell/runtime.js +2 -2
- package/package.json +1 -1
|
@@ -16,24 +16,28 @@ var PreviewBuildStrategy = class {
|
|
|
16
16
|
#appPath;
|
|
17
17
|
#entrypoint;
|
|
18
18
|
#buildType;
|
|
19
|
+
#signal;
|
|
19
20
|
constructor(options) {
|
|
20
21
|
this.#appPath = options.appPath;
|
|
21
22
|
this.#entrypoint = options.entrypoint;
|
|
22
23
|
this.#buildType = options.buildType ?? "auto";
|
|
24
|
+
this.#signal = options.signal;
|
|
23
25
|
}
|
|
24
|
-
async canBuild() {
|
|
26
|
+
async canBuild(signal = this.#signal) {
|
|
25
27
|
const { strategy } = await resolvePreviewBuildStrategy({
|
|
26
28
|
appPath: this.#appPath,
|
|
27
29
|
entrypoint: this.#entrypoint,
|
|
28
|
-
buildType: this.#buildType
|
|
30
|
+
buildType: this.#buildType,
|
|
31
|
+
signal
|
|
29
32
|
});
|
|
30
|
-
return strategy.canBuild();
|
|
33
|
+
return strategy.canBuild(signal);
|
|
31
34
|
}
|
|
32
|
-
async execute() {
|
|
35
|
+
async execute(signal = this.#signal) {
|
|
33
36
|
const { artifact } = await executePreviewBuild({
|
|
34
37
|
appPath: this.#appPath,
|
|
35
38
|
entrypoint: this.#entrypoint,
|
|
36
|
-
buildType: this.#buildType
|
|
39
|
+
buildType: this.#buildType,
|
|
40
|
+
signal
|
|
37
41
|
});
|
|
38
42
|
return artifact;
|
|
39
43
|
}
|
|
@@ -42,12 +46,13 @@ async function executePreviewBuild(options) {
|
|
|
42
46
|
const { strategy, buildType } = await resolvePreviewBuildStrategy({
|
|
43
47
|
appPath: options.appPath,
|
|
44
48
|
entrypoint: options.entrypoint,
|
|
45
|
-
buildType: options.buildType ?? "auto"
|
|
49
|
+
buildType: options.buildType ?? "auto",
|
|
50
|
+
signal: options.signal
|
|
46
51
|
});
|
|
47
|
-
const artifact = await strategy.execute();
|
|
52
|
+
const artifact = await strategy.execute(options.signal);
|
|
48
53
|
try {
|
|
49
|
-
if (buildType === "nextjs") await restageNextjsArtifact(artifact, options.appPath);
|
|
50
|
-
await normalizeArtifactSymlinks(artifact.directory, options.appPath);
|
|
54
|
+
if (buildType === "nextjs") await restageNextjsArtifact(artifact, options.appPath, options.signal);
|
|
55
|
+
await normalizeArtifactSymlinks(artifact.directory, options.appPath, options.signal);
|
|
51
56
|
return {
|
|
52
57
|
artifact,
|
|
53
58
|
buildType
|
|
@@ -62,7 +67,8 @@ async function resolvePreviewBuildStrategy(options) {
|
|
|
62
67
|
const strategy = await createPreviewBuildStrategy({
|
|
63
68
|
appPath: options.appPath,
|
|
64
69
|
entrypoint: options.entrypoint,
|
|
65
|
-
buildType: options.buildType
|
|
70
|
+
buildType: options.buildType,
|
|
71
|
+
signal: options.signal
|
|
66
72
|
});
|
|
67
73
|
return {
|
|
68
74
|
buildType: options.buildType,
|
|
@@ -74,9 +80,10 @@ async function resolvePreviewBuildStrategy(options) {
|
|
|
74
80
|
const strategy = await createPreviewBuildStrategy({
|
|
75
81
|
appPath: options.appPath,
|
|
76
82
|
entrypoint: options.entrypoint,
|
|
77
|
-
buildType
|
|
83
|
+
buildType,
|
|
84
|
+
signal: options.signal
|
|
78
85
|
});
|
|
79
|
-
if (await strategy.canBuild()) return {
|
|
86
|
+
if (await strategy.canBuild(options.signal)) return {
|
|
80
87
|
buildType,
|
|
81
88
|
strategy
|
|
82
89
|
};
|
|
@@ -86,7 +93,8 @@ async function resolvePreviewBuildStrategy(options) {
|
|
|
86
93
|
strategy: await createPreviewBuildStrategy({
|
|
87
94
|
appPath: options.appPath,
|
|
88
95
|
entrypoint: options.entrypoint,
|
|
89
|
-
buildType: "bun"
|
|
96
|
+
buildType: "bun",
|
|
97
|
+
signal: options.signal
|
|
90
98
|
})
|
|
91
99
|
};
|
|
92
100
|
}
|
|
@@ -97,7 +105,7 @@ async function createPreviewBuildStrategy(options) {
|
|
|
97
105
|
case "astro": return new AstroBuild({ appPath: options.appPath });
|
|
98
106
|
case "tanstack-start": return new TanstackStartBuild({ appPath: options.appPath });
|
|
99
107
|
case "bun": {
|
|
100
|
-
const entrypoint = await resolveBunEntrypoint(options.appPath, options.entrypoint);
|
|
108
|
+
const entrypoint = await resolveBunEntrypoint(options.appPath, options.entrypoint, options.signal);
|
|
101
109
|
return new BunBuild({
|
|
102
110
|
appPath: options.appPath,
|
|
103
111
|
entrypoint
|
|
@@ -112,74 +120,78 @@ async function stageNextjsStandaloneArtifact(options) {
|
|
|
112
120
|
await copyPathMaterializingSymlinks(standaloneRoot, artifactRoot, {
|
|
113
121
|
standaloneRoot,
|
|
114
122
|
appRoot,
|
|
115
|
-
sourceRoot: await resolveSourceRoot(appRoot)
|
|
123
|
+
sourceRoot: await resolveSourceRoot(appRoot, options.signal),
|
|
124
|
+
signal: options.signal
|
|
116
125
|
});
|
|
117
|
-
await hoistPnpmDependencies(path.join(artifactRoot, "node_modules"));
|
|
126
|
+
await hoistPnpmDependencies(path.join(artifactRoot, "node_modules"), options.signal);
|
|
118
127
|
}
|
|
119
|
-
async function restageNextjsArtifact(artifact, appPath) {
|
|
128
|
+
async function restageNextjsArtifact(artifact, appPath, signal) {
|
|
120
129
|
const artifactDir = artifact.directory;
|
|
121
130
|
const standaloneDir = path.join(appPath, ".next", "standalone");
|
|
122
|
-
await rm(artifactDir, {
|
|
131
|
+
await unsupportedFilesystemBoundary(signal, () => rm(artifactDir, {
|
|
123
132
|
recursive: true,
|
|
124
133
|
force: true
|
|
125
|
-
});
|
|
134
|
+
}));
|
|
126
135
|
await stageNextjsStandaloneArtifact({
|
|
127
136
|
standaloneDir,
|
|
128
137
|
artifactDir,
|
|
129
|
-
appPath
|
|
138
|
+
appPath,
|
|
139
|
+
signal
|
|
130
140
|
});
|
|
131
141
|
const serverSubpath = nextjsServerSubpath(artifact.entrypoint);
|
|
132
142
|
const serverDir = serverSubpath ? path.join(artifactDir, serverSubpath) : artifactDir;
|
|
133
143
|
const publicDir = path.join(appPath, "public");
|
|
134
|
-
if (await directoryExists(publicDir)) await cp(publicDir, path.join(serverDir, "public"), {
|
|
144
|
+
if (await directoryExists(publicDir, signal)) await unsupportedFilesystemBoundary(signal, () => cp(publicDir, path.join(serverDir, "public"), {
|
|
135
145
|
recursive: true,
|
|
136
146
|
verbatimSymlinks: true
|
|
137
|
-
});
|
|
147
|
+
}));
|
|
138
148
|
const staticDir = path.join(appPath, ".next", "static");
|
|
139
|
-
if (await directoryExists(staticDir)) await cp(staticDir, path.join(serverDir, ".next", "static"), {
|
|
149
|
+
if (await directoryExists(staticDir, signal)) await unsupportedFilesystemBoundary(signal, () => cp(staticDir, path.join(serverDir, ".next", "static"), {
|
|
140
150
|
recursive: true,
|
|
141
151
|
verbatimSymlinks: true
|
|
142
|
-
});
|
|
152
|
+
}));
|
|
143
153
|
}
|
|
144
154
|
function nextjsServerSubpath(entrypoint) {
|
|
145
155
|
const dir = path.posix.dirname(entrypoint);
|
|
146
156
|
return dir === "." ? "" : dir;
|
|
147
157
|
}
|
|
148
|
-
async function hoistPnpmDependencies(nodeModulesDir) {
|
|
158
|
+
async function hoistPnpmDependencies(nodeModulesDir, signal) {
|
|
149
159
|
const pnpmNodeModulesDir = path.join(nodeModulesDir, ".pnpm", "node_modules");
|
|
150
|
-
if (!await directoryExists(pnpmNodeModulesDir)) return;
|
|
151
|
-
const entries = await readdir(pnpmNodeModulesDir, { withFileTypes: true });
|
|
160
|
+
if (!await directoryExists(pnpmNodeModulesDir, signal)) return;
|
|
161
|
+
const entries = await unsupportedFilesystemBoundary(signal, () => readdir(pnpmNodeModulesDir, { withFileTypes: true }));
|
|
152
162
|
for (const entry of entries) {
|
|
153
163
|
const sourcePath = path.join(pnpmNodeModulesDir, entry.name);
|
|
154
164
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
155
|
-
const scopedEntries = await readdir(sourcePath, { withFileTypes: true });
|
|
165
|
+
const scopedEntries = await unsupportedFilesystemBoundary(signal, () => readdir(sourcePath, { withFileTypes: true }));
|
|
156
166
|
for (const scopedEntry of scopedEntries) {
|
|
157
167
|
const scopedDestination = path.join(nodeModulesDir, entry.name, scopedEntry.name);
|
|
158
|
-
if (await pathExists(scopedDestination)) continue;
|
|
159
|
-
await mkdir(path.dirname(scopedDestination), { recursive: true });
|
|
168
|
+
if (await pathExists(scopedDestination, signal)) continue;
|
|
169
|
+
await unsupportedFilesystemBoundary(signal, () => mkdir(path.dirname(scopedDestination), { recursive: true }));
|
|
160
170
|
await copyPathMaterializingSymlinks(path.join(sourcePath, scopedEntry.name), scopedDestination, {
|
|
161
171
|
standaloneRoot: pnpmNodeModulesDir,
|
|
162
172
|
appRoot: nodeModulesDir,
|
|
163
|
-
sourceRoot: nodeModulesDir
|
|
173
|
+
sourceRoot: nodeModulesDir,
|
|
174
|
+
signal
|
|
164
175
|
});
|
|
165
176
|
}
|
|
166
177
|
continue;
|
|
167
178
|
}
|
|
168
179
|
const destinationPath = path.join(nodeModulesDir, entry.name);
|
|
169
|
-
if (await pathExists(destinationPath)) continue;
|
|
180
|
+
if (await pathExists(destinationPath, signal)) continue;
|
|
170
181
|
await copyPathMaterializingSymlinks(sourcePath, destinationPath, {
|
|
171
182
|
standaloneRoot: pnpmNodeModulesDir,
|
|
172
183
|
appRoot: nodeModulesDir,
|
|
173
|
-
sourceRoot: nodeModulesDir
|
|
184
|
+
sourceRoot: nodeModulesDir,
|
|
185
|
+
signal
|
|
174
186
|
});
|
|
175
187
|
}
|
|
176
188
|
}
|
|
177
|
-
async function normalizeArtifactSymlinks(artifactDir, appPath) {
|
|
189
|
+
async function normalizeArtifactSymlinks(artifactDir, appPath, signal) {
|
|
178
190
|
const normalizedArtifactDir = path.resolve(artifactDir);
|
|
179
191
|
const normalizedAppPath = path.resolve(appPath);
|
|
180
192
|
await walkDirectory(normalizedArtifactDir);
|
|
181
193
|
async function walkDirectory(directory) {
|
|
182
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
194
|
+
const entries = await unsupportedFilesystemBoundary(signal, () => readdir(directory, { withFileTypes: true }));
|
|
183
195
|
for (const entry of entries) {
|
|
184
196
|
const fullPath = path.join(directory, entry.name);
|
|
185
197
|
if (entry.isDirectory()) {
|
|
@@ -187,19 +199,19 @@ async function normalizeArtifactSymlinks(artifactDir, appPath) {
|
|
|
187
199
|
continue;
|
|
188
200
|
}
|
|
189
201
|
if (!entry.isSymbolicLink()) continue;
|
|
190
|
-
const target = await readlink(fullPath);
|
|
202
|
+
const target = await unsupportedFilesystemBoundary(signal, () => readlink(fullPath));
|
|
191
203
|
const resolvedTarget = path.resolve(path.dirname(fullPath), target);
|
|
192
204
|
if (isPathWithin(normalizedArtifactDir, resolvedTarget)) continue;
|
|
193
205
|
if (!isPathWithin(normalizedAppPath, resolvedTarget)) throw new Error(`Build artifact symlink escapes the app directory: ${resolvedTarget}`);
|
|
194
|
-
const targetStat = await stat(resolvedTarget);
|
|
195
|
-
await rm(fullPath, {
|
|
206
|
+
const targetStat = await unsupportedFilesystemBoundary(signal, () => stat(resolvedTarget));
|
|
207
|
+
await unsupportedFilesystemBoundary(signal, () => rm(fullPath, {
|
|
196
208
|
force: true,
|
|
197
209
|
recursive: true
|
|
198
|
-
});
|
|
199
|
-
await cp(resolvedTarget, fullPath, {
|
|
210
|
+
}));
|
|
211
|
+
await unsupportedFilesystemBoundary(signal, () => cp(resolvedTarget, fullPath, {
|
|
200
212
|
recursive: targetStat.isDirectory(),
|
|
201
213
|
dereference: true
|
|
202
|
-
});
|
|
214
|
+
}));
|
|
203
215
|
if (targetStat.isDirectory()) await walkDirectory(fullPath);
|
|
204
216
|
}
|
|
205
217
|
}
|
|
@@ -208,8 +220,11 @@ function isPathWithin(rootPath, candidatePath) {
|
|
|
208
220
|
const relativePath = path.relative(rootPath, candidatePath);
|
|
209
221
|
return relativePath === "" || !relativePath.startsWith(`..${path.sep}`) && relativePath !== ".." && !path.isAbsolute(relativePath);
|
|
210
222
|
}
|
|
223
|
+
function isPathWithinWorkspaceDependency(sourceRoot, candidatePath) {
|
|
224
|
+
return isPathWithin(path.join(sourceRoot, "node_modules"), candidatePath);
|
|
225
|
+
}
|
|
211
226
|
async function copyPathMaterializingSymlinks(sourcePath, destinationPath, options) {
|
|
212
|
-
const sourceStat = await lstat(sourcePath);
|
|
227
|
+
const sourceStat = await unsupportedFilesystemBoundary(options.signal, () => lstat(sourcePath));
|
|
213
228
|
if (sourceStat.isSymbolicLink()) {
|
|
214
229
|
const resolvedTarget = await resolveSymlinkTarget(sourcePath, options);
|
|
215
230
|
if (resolvedTarget === null) return;
|
|
@@ -217,27 +232,27 @@ async function copyPathMaterializingSymlinks(sourcePath, destinationPath, option
|
|
|
217
232
|
return;
|
|
218
233
|
}
|
|
219
234
|
if (sourceStat.isDirectory()) {
|
|
220
|
-
await mkdir(destinationPath, { recursive: true });
|
|
221
|
-
const entries = await readdir(sourcePath, { withFileTypes: true });
|
|
235
|
+
await unsupportedFilesystemBoundary(options.signal, () => mkdir(destinationPath, { recursive: true }));
|
|
236
|
+
const entries = await unsupportedFilesystemBoundary(options.signal, () => readdir(sourcePath, { withFileTypes: true }));
|
|
222
237
|
for (const entry of entries) await copyPathMaterializingSymlinks(path.join(sourcePath, entry.name), path.join(destinationPath, entry.name), options);
|
|
223
238
|
return;
|
|
224
239
|
}
|
|
225
240
|
if (sourceStat.isFile()) {
|
|
226
|
-
await mkdir(path.dirname(destinationPath), { recursive: true });
|
|
227
|
-
await copyFile(sourcePath, destinationPath);
|
|
228
|
-
await chmod(destinationPath, sourceStat.mode);
|
|
241
|
+
await unsupportedFilesystemBoundary(options.signal, () => mkdir(path.dirname(destinationPath), { recursive: true }));
|
|
242
|
+
await unsupportedFilesystemBoundary(options.signal, () => copyFile(sourcePath, destinationPath));
|
|
243
|
+
await unsupportedFilesystemBoundary(options.signal, () => chmod(destinationPath, sourceStat.mode));
|
|
229
244
|
}
|
|
230
245
|
}
|
|
231
246
|
async function resolveSymlinkTarget(symlinkPath, options) {
|
|
232
|
-
const linkTarget = await readlink(symlinkPath);
|
|
247
|
+
const linkTarget = await unsupportedFilesystemBoundary(options.signal, () => readlink(symlinkPath));
|
|
233
248
|
const resolvedTarget = path.resolve(path.dirname(symlinkPath), linkTarget);
|
|
234
|
-
if (await pathExists(resolvedTarget)) {
|
|
235
|
-
if (!isPathWithin(options.appRoot, resolvedTarget) && !
|
|
249
|
+
if (await pathExists(resolvedTarget, options.signal)) {
|
|
250
|
+
if (!isPathWithin(options.appRoot, resolvedTarget) && !isPathWithinWorkspaceDependency(options.sourceRoot, resolvedTarget)) throw new Error(`Build artifact symlink escapes the app directory: ${resolvedTarget}`);
|
|
236
251
|
return resolvedTarget;
|
|
237
252
|
}
|
|
238
253
|
if (isPathWithin(options.standaloneRoot, resolvedTarget)) {
|
|
239
254
|
const fallbackTarget = path.join(options.appRoot, path.relative(options.standaloneRoot, resolvedTarget));
|
|
240
|
-
if (await pathExists(fallbackTarget)) return fallbackTarget;
|
|
255
|
+
if (await pathExists(fallbackTarget, options.signal)) return fallbackTarget;
|
|
241
256
|
}
|
|
242
257
|
if (isPnpmHoistLink(symlinkPath)) return null;
|
|
243
258
|
throw new Error(`Next.js standalone symlink target is missing: ${symlinkPath} -> ${linkTarget} (resolved to ${resolvedTarget})`);
|
|
@@ -247,38 +262,51 @@ function isPnpmHoistLink(symlinkPath) {
|
|
|
247
262
|
for (let i = 0; i < parts.length - 1; i++) if (parts[i] === ".pnpm" && parts[i + 1] === "node_modules") return true;
|
|
248
263
|
return false;
|
|
249
264
|
}
|
|
250
|
-
async function pathExists(targetPath) {
|
|
265
|
+
async function pathExists(targetPath, signal) {
|
|
251
266
|
try {
|
|
252
|
-
await stat(targetPath);
|
|
267
|
+
await unsupportedFilesystemBoundary(signal, () => stat(targetPath));
|
|
253
268
|
return true;
|
|
254
|
-
} catch {
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (signal?.aborted) throw error;
|
|
255
271
|
return false;
|
|
256
272
|
}
|
|
257
273
|
}
|
|
258
|
-
async function directoryExists(targetPath) {
|
|
274
|
+
async function directoryExists(targetPath, signal) {
|
|
259
275
|
try {
|
|
260
|
-
return (await stat(targetPath)).isDirectory();
|
|
261
|
-
} catch {
|
|
276
|
+
return (await unsupportedFilesystemBoundary(signal, () => stat(targetPath))).isDirectory();
|
|
277
|
+
} catch (error) {
|
|
278
|
+
if (signal?.aborted) throw error;
|
|
262
279
|
return false;
|
|
263
280
|
}
|
|
264
281
|
}
|
|
265
|
-
async function resolveSourceRoot(appRoot) {
|
|
282
|
+
async function resolveSourceRoot(appRoot, signal) {
|
|
266
283
|
let current = path.resolve(appRoot);
|
|
267
284
|
while (true) {
|
|
268
|
-
if (await pathExists(path.join(current, ".git")) || await pathExists(path.join(current, "pnpm-workspace.yaml")) || await pathExists(path.join(current, "bun.lock")) || await pathExists(path.join(current, "bun.lockb")) || await packageJsonDeclaresWorkspaces(current)) return current;
|
|
285
|
+
if (await pathExists(path.join(current, ".git"), signal) || await pathExists(path.join(current, "pnpm-workspace.yaml"), signal) || await pathExists(path.join(current, "bun.lock"), signal) || await pathExists(path.join(current, "bun.lockb"), signal) || await packageJsonDeclaresWorkspaces(current, signal)) return current;
|
|
269
286
|
const parent = path.dirname(current);
|
|
270
287
|
if (parent === current) return path.resolve(appRoot);
|
|
271
288
|
current = parent;
|
|
272
289
|
}
|
|
273
290
|
}
|
|
274
|
-
async function packageJsonDeclaresWorkspaces(directory) {
|
|
291
|
+
async function packageJsonDeclaresWorkspaces(directory, signal) {
|
|
292
|
+
signal?.throwIfAborted();
|
|
275
293
|
try {
|
|
276
|
-
const content = await readFile(path.join(directory, "package.json"),
|
|
294
|
+
const content = await readFile(path.join(directory, "package.json"), {
|
|
295
|
+
encoding: "utf8",
|
|
296
|
+
signal
|
|
297
|
+
});
|
|
277
298
|
const parsed = JSON.parse(content);
|
|
278
299
|
return Boolean(parsed.workspaces);
|
|
279
|
-
} catch {
|
|
300
|
+
} catch (error) {
|
|
301
|
+
if (signal?.aborted) throw error;
|
|
280
302
|
return false;
|
|
281
303
|
}
|
|
282
304
|
}
|
|
305
|
+
async function unsupportedFilesystemBoundary(signal, operation) {
|
|
306
|
+
signal?.throwIfAborted();
|
|
307
|
+
const result = await operation();
|
|
308
|
+
signal?.throwIfAborted();
|
|
309
|
+
return result;
|
|
310
|
+
}
|
|
283
311
|
//#endregion
|
|
284
312
|
export { PREVIEW_BUILD_TYPES, PreviewBuildStrategy, RESOLVED_PREVIEW_BUILD_TYPES, executePreviewBuild };
|
|
@@ -19,7 +19,10 @@ function createPreviewAppProvider(client, options) {
|
|
|
19
19
|
const sdk = new ComputeClient(client);
|
|
20
20
|
return {
|
|
21
21
|
async createProject(options) {
|
|
22
|
-
const projectResult = await sdk.createProject({
|
|
22
|
+
const projectResult = await sdk.createProject({
|
|
23
|
+
name: options.name,
|
|
24
|
+
signal: options.signal
|
|
25
|
+
});
|
|
23
26
|
if (projectResult.isErr()) throw new Error(projectResult.error.message);
|
|
24
27
|
return {
|
|
25
28
|
id: projectResult.value.id,
|
|
@@ -29,17 +32,22 @@ function createPreviewAppProvider(client, options) {
|
|
|
29
32
|
async listApps(projectId, options) {
|
|
30
33
|
return listComputeServices(client, {
|
|
31
34
|
projectId,
|
|
32
|
-
branchGitName: options?.branchName
|
|
35
|
+
branchGitName: options?.branchName,
|
|
36
|
+
signal: options?.signal
|
|
33
37
|
});
|
|
34
38
|
},
|
|
35
|
-
async removeApp(appId) {
|
|
36
|
-
const appResult = await sdk.showService({
|
|
39
|
+
async removeApp(appId, options) {
|
|
40
|
+
const appResult = await sdk.showService({
|
|
41
|
+
serviceId: appId,
|
|
42
|
+
signal: options?.signal
|
|
43
|
+
});
|
|
37
44
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
38
45
|
const destroyResult = await sdk.destroyService({
|
|
39
46
|
serviceId: appId,
|
|
40
47
|
keepService: false,
|
|
41
48
|
timeoutSeconds: 120,
|
|
42
|
-
pollIntervalMs: 2e3
|
|
49
|
+
pollIntervalMs: 2e3,
|
|
50
|
+
signal: options?.signal
|
|
43
51
|
});
|
|
44
52
|
if (destroyResult.isErr()) throw new Error(destroyResult.error.message);
|
|
45
53
|
return {
|
|
@@ -47,17 +55,18 @@ function createPreviewAppProvider(client, options) {
|
|
|
47
55
|
name: appResult.value.name
|
|
48
56
|
};
|
|
49
57
|
},
|
|
50
|
-
async listDomains(appId) {
|
|
51
|
-
return listComputeServiceDomains(client, appId);
|
|
58
|
+
async listDomains(appId, options) {
|
|
59
|
+
return listComputeServiceDomains(client, appId, options?.signal);
|
|
52
60
|
},
|
|
53
61
|
async addDomain(options) {
|
|
54
62
|
const result = await client.POST("/v1/compute-services/{computeServiceId}/domains", {
|
|
55
63
|
params: { path: { computeServiceId: options.appId } },
|
|
56
|
-
body: { hostname: options.hostname }
|
|
64
|
+
body: { hostname: options.hostname },
|
|
65
|
+
signal: options.signal
|
|
57
66
|
});
|
|
58
67
|
if (result.error || !result.data) {
|
|
59
68
|
if (result.response.status === 409) {
|
|
60
|
-
const existing = (await listComputeServiceDomains(client, options.appId)).find((domain) => sameHostname(domain.hostname, options.hostname));
|
|
69
|
+
const existing = (await listComputeServiceDomains(client, options.appId, options.signal)).find((domain) => sameHostname(domain.hostname, options.hostname));
|
|
61
70
|
if (existing) return {
|
|
62
71
|
domain: existing,
|
|
63
72
|
existing: true
|
|
@@ -70,17 +79,26 @@ function createPreviewAppProvider(client, options) {
|
|
|
70
79
|
existing: false
|
|
71
80
|
};
|
|
72
81
|
},
|
|
73
|
-
async showDomain(domainId) {
|
|
74
|
-
const result = await client.GET("/v1/domains/{domainId}", {
|
|
82
|
+
async showDomain(domainId, options) {
|
|
83
|
+
const result = await client.GET("/v1/domains/{domainId}", {
|
|
84
|
+
params: { path: { domainId } },
|
|
85
|
+
signal: options?.signal
|
|
86
|
+
});
|
|
75
87
|
if (result.error || !result.data) throw domainApiCallError("Failed to show custom domain", result.response, result.error);
|
|
76
88
|
return normalizeDomainRecord(result.data.data);
|
|
77
89
|
},
|
|
78
|
-
async removeDomain(domainId) {
|
|
79
|
-
const result = await client.DELETE("/v1/domains/{domainId}", {
|
|
90
|
+
async removeDomain(domainId, options) {
|
|
91
|
+
const result = await client.DELETE("/v1/domains/{domainId}", {
|
|
92
|
+
params: { path: { domainId } },
|
|
93
|
+
signal: options?.signal
|
|
94
|
+
});
|
|
80
95
|
if (result.error) throw domainApiCallError("Failed to remove custom domain", result.response, result.error);
|
|
81
96
|
},
|
|
82
|
-
async retryDomain(domainId) {
|
|
83
|
-
const result = await client.POST("/v1/domains/{domainId}/retry", {
|
|
97
|
+
async retryDomain(domainId, options) {
|
|
98
|
+
const result = await client.POST("/v1/domains/{domainId}/retry", {
|
|
99
|
+
params: { path: { domainId } },
|
|
100
|
+
signal: options?.signal
|
|
101
|
+
});
|
|
84
102
|
if (result.error || !result.data) throw domainApiCallError("Failed to retry custom domain", result.response, result.error);
|
|
85
103
|
return normalizeDomainRecord(result.data.data);
|
|
86
104
|
},
|
|
@@ -90,6 +108,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
90
108
|
versionId: options.deploymentId,
|
|
91
109
|
timeoutSeconds: 120,
|
|
92
110
|
pollIntervalMs: 2e3,
|
|
111
|
+
signal: options.signal,
|
|
93
112
|
progress: options.progress
|
|
94
113
|
});
|
|
95
114
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
@@ -103,7 +122,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
103
122
|
projectId: options.projectId,
|
|
104
123
|
branchName: options.branchName,
|
|
105
124
|
appName: options.appName,
|
|
106
|
-
region: options.region
|
|
125
|
+
region: options.region,
|
|
126
|
+
signal: options.signal
|
|
107
127
|
}) : {
|
|
108
128
|
appId: void 0,
|
|
109
129
|
appName: options.appName,
|
|
@@ -113,7 +133,8 @@ function createPreviewAppProvider(client, options) {
|
|
|
113
133
|
strategy: new PreviewBuildStrategy({
|
|
114
134
|
appPath: path.resolve(options.cwd),
|
|
115
135
|
entrypoint: options.entrypoint,
|
|
116
|
-
buildType: options.buildType
|
|
136
|
+
buildType: options.buildType,
|
|
137
|
+
signal: options.signal
|
|
117
138
|
}),
|
|
118
139
|
projectId: options.projectId,
|
|
119
140
|
serviceId: resolvedApp.appId,
|
|
@@ -124,6 +145,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
124
145
|
timeoutSeconds: 120,
|
|
125
146
|
pollIntervalMs: 2e3,
|
|
126
147
|
interaction: options.interaction,
|
|
148
|
+
signal: options.signal,
|
|
127
149
|
progress: options.progress
|
|
128
150
|
});
|
|
129
151
|
if (deployResult.isErr()) throw new Error(deployResult.error.message);
|
|
@@ -150,6 +172,7 @@ function createPreviewAppProvider(client, options) {
|
|
|
150
172
|
envVars: options.envVars,
|
|
151
173
|
timeoutSeconds: 120,
|
|
152
174
|
pollIntervalMs: 2e3,
|
|
175
|
+
signal: options.signal,
|
|
153
176
|
progress: options.progress
|
|
154
177
|
});
|
|
155
178
|
if (updateResult.isErr()) throw new Error(updateResult.error.message);
|
|
@@ -158,10 +181,17 @@ function createPreviewAppProvider(client, options) {
|
|
|
158
181
|
versionId: updateResult.value.versionId,
|
|
159
182
|
timeoutSeconds: 120,
|
|
160
183
|
pollIntervalMs: 2e3,
|
|
184
|
+
signal: options.signal,
|
|
161
185
|
progress: options.promoteProgress
|
|
162
186
|
});
|
|
163
187
|
if (promoteResult.isErr()) throw new Error(promoteResult.error.message);
|
|
164
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.showService({
|
|
188
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showService({
|
|
189
|
+
serviceId: options.appId,
|
|
190
|
+
signal: options.signal
|
|
191
|
+
}), sdk.showVersion({
|
|
192
|
+
versionId: updateResult.value.versionId,
|
|
193
|
+
signal: options.signal
|
|
194
|
+
})]);
|
|
165
195
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
166
196
|
if (versionResult.isErr()) throw new Error(versionResult.error.message);
|
|
167
197
|
return {
|
|
@@ -184,7 +214,13 @@ function createPreviewAppProvider(client, options) {
|
|
|
184
214
|
};
|
|
185
215
|
},
|
|
186
216
|
async listAppEnvNames(options) {
|
|
187
|
-
const [serviceResult, versionResult] = await Promise.all([sdk.showService({
|
|
217
|
+
const [serviceResult, versionResult] = await Promise.all([sdk.showService({
|
|
218
|
+
serviceId: options.appId,
|
|
219
|
+
signal: options.signal
|
|
220
|
+
}), sdk.showVersion({
|
|
221
|
+
versionId: options.deploymentId,
|
|
222
|
+
signal: options.signal
|
|
223
|
+
})]);
|
|
188
224
|
if (serviceResult.isErr()) throw new Error(serviceResult.error.message);
|
|
189
225
|
if (versionResult.isErr()) throw new Error(versionResult.error.message);
|
|
190
226
|
return {
|
|
@@ -206,8 +242,14 @@ function createPreviewAppProvider(client, options) {
|
|
|
206
242
|
variables: envVarNames(versionResult.value.envVars)
|
|
207
243
|
};
|
|
208
244
|
},
|
|
209
|
-
async listDeployments(appId) {
|
|
210
|
-
const [appResult, versionsResult] = await Promise.all([sdk.showService({
|
|
245
|
+
async listDeployments(appId, options) {
|
|
246
|
+
const [appResult, versionsResult] = await Promise.all([sdk.showService({
|
|
247
|
+
serviceId: appId,
|
|
248
|
+
signal: options?.signal
|
|
249
|
+
}), sdk.listVersions({
|
|
250
|
+
serviceId: appId,
|
|
251
|
+
signal: options?.signal
|
|
252
|
+
})]);
|
|
211
253
|
if (appResult.isErr()) throw new Error(appResult.error.message);
|
|
212
254
|
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
213
255
|
return {
|
|
@@ -230,14 +272,17 @@ function createPreviewAppProvider(client, options) {
|
|
|
230
272
|
}))
|
|
231
273
|
};
|
|
232
274
|
},
|
|
233
|
-
async showDeployment(deploymentId) {
|
|
234
|
-
const deploymentResult = await sdk.showVersion({
|
|
275
|
+
async showDeployment(deploymentId, options) {
|
|
276
|
+
const deploymentResult = await sdk.showVersion({
|
|
277
|
+
versionId: deploymentId,
|
|
278
|
+
signal: options?.signal
|
|
279
|
+
});
|
|
235
280
|
if (deploymentResult.isErr()) {
|
|
236
281
|
if (ApiError.is(deploymentResult.error) && deploymentResult.error.statusCode === 404) return null;
|
|
237
282
|
throw new Error(deploymentResult.error.message);
|
|
238
283
|
}
|
|
239
284
|
return {
|
|
240
|
-
app: await findAppForDeployment(sdk, deploymentId),
|
|
285
|
+
app: await findAppForDeployment(sdk, deploymentId, options?.signal),
|
|
241
286
|
deployment: {
|
|
242
287
|
id: deploymentResult.value.id,
|
|
243
288
|
status: deploymentResult.value.status,
|
|
@@ -263,10 +308,13 @@ function createPreviewAppProvider(client, options) {
|
|
|
263
308
|
};
|
|
264
309
|
}
|
|
265
310
|
async function listBranches(client, options) {
|
|
266
|
-
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
311
|
+
const result = await client.GET("/v1/projects/{projectId}/branches", {
|
|
312
|
+
params: {
|
|
313
|
+
path: { projectId: options.projectId },
|
|
314
|
+
query: { gitName: options.gitName }
|
|
315
|
+
},
|
|
316
|
+
signal: options.signal
|
|
317
|
+
});
|
|
270
318
|
if (result.error || !result.data) throw apiCallError("Failed to list branches", result.response, result.error);
|
|
271
319
|
return result.data.data;
|
|
272
320
|
}
|
|
@@ -278,7 +326,8 @@ async function resolveOrCreateBranch(client, options) {
|
|
|
278
326
|
body: {
|
|
279
327
|
gitName: options.gitName,
|
|
280
328
|
isDefault: options.gitName === "main"
|
|
281
|
-
}
|
|
329
|
+
},
|
|
330
|
+
signal: options.signal
|
|
282
331
|
});
|
|
283
332
|
if (result.error || !result.data) {
|
|
284
333
|
if (result.response.status === 409) {
|
|
@@ -293,11 +342,14 @@ async function listComputeServices(client, options) {
|
|
|
293
342
|
const services = [];
|
|
294
343
|
let cursor;
|
|
295
344
|
while (true) {
|
|
296
|
-
const result = await client.GET("/v1/compute-services", {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
345
|
+
const result = await client.GET("/v1/compute-services", {
|
|
346
|
+
params: { query: {
|
|
347
|
+
projectId: options.projectId,
|
|
348
|
+
branchGitName: options.branchGitName,
|
|
349
|
+
cursor
|
|
350
|
+
} },
|
|
351
|
+
signal: options.signal
|
|
352
|
+
});
|
|
301
353
|
if (result.error || !result.data) throw apiCallError("Failed to list apps", result.response, result.error);
|
|
302
354
|
services.push(...result.data.data);
|
|
303
355
|
if (!result.data.pagination.hasMore || !result.data.pagination.nextCursor) break;
|
|
@@ -312,8 +364,11 @@ async function listComputeServices(client, options) {
|
|
|
312
364
|
liveUrl: toAbsoluteUrl(service.serviceEndpointDomain ?? null)
|
|
313
365
|
}));
|
|
314
366
|
}
|
|
315
|
-
async function listComputeServiceDomains(client, computeServiceId) {
|
|
316
|
-
const result = await client.GET("/v1/compute-services/{computeServiceId}/domains", {
|
|
367
|
+
async function listComputeServiceDomains(client, computeServiceId, signal) {
|
|
368
|
+
const result = await client.GET("/v1/compute-services/{computeServiceId}/domains", {
|
|
369
|
+
params: { path: { computeServiceId } },
|
|
370
|
+
signal
|
|
371
|
+
});
|
|
317
372
|
if (result.error || !result.data) throw domainApiCallError("Failed to list custom domains", result.response, result.error);
|
|
318
373
|
return result.data.data.map((domain) => normalizeDomainRecord(domain));
|
|
319
374
|
}
|
|
@@ -355,19 +410,24 @@ function normalizeHostnameForComparison(hostname) {
|
|
|
355
410
|
async function createBranchApp(client, options) {
|
|
356
411
|
const branch = await resolveOrCreateBranch(client, {
|
|
357
412
|
projectId: options.projectId,
|
|
358
|
-
gitName: options.branchName
|
|
413
|
+
gitName: options.branchName,
|
|
414
|
+
signal: options.signal
|
|
415
|
+
});
|
|
416
|
+
const result = await client.POST("/v1/compute-services", {
|
|
417
|
+
body: {
|
|
418
|
+
projectId: options.projectId,
|
|
419
|
+
branchId: branch.id,
|
|
420
|
+
displayName: options.appName,
|
|
421
|
+
...options.region ? { regionId: options.region } : {}
|
|
422
|
+
},
|
|
423
|
+
signal: options.signal
|
|
359
424
|
});
|
|
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
425
|
if (result.error || !result.data) {
|
|
367
426
|
if (result.response.status === 409) {
|
|
368
427
|
const matched = (await listComputeServices(client, {
|
|
369
428
|
projectId: options.projectId,
|
|
370
|
-
branchGitName: options.branchName
|
|
429
|
+
branchGitName: options.branchName,
|
|
430
|
+
signal: options.signal
|
|
371
431
|
})).find((app) => app.name === options.appName);
|
|
372
432
|
if (matched) return {
|
|
373
433
|
appId: matched.id,
|
|
@@ -399,14 +459,20 @@ function domainApiCallError(summary, response, error) {
|
|
|
399
459
|
hint: error.error?.hint ?? null
|
|
400
460
|
});
|
|
401
461
|
}
|
|
402
|
-
async function findAppForDeployment(sdk, deploymentId) {
|
|
403
|
-
const projectsResult = await sdk.listProjects();
|
|
462
|
+
async function findAppForDeployment(sdk, deploymentId, signal) {
|
|
463
|
+
const projectsResult = await sdk.listProjects({ signal });
|
|
404
464
|
if (projectsResult.isErr()) throw new Error(projectsResult.error.message);
|
|
405
465
|
for (const project of projectsResult.value) {
|
|
406
|
-
const servicesResult = await sdk.listServices({
|
|
466
|
+
const servicesResult = await sdk.listServices({
|
|
467
|
+
projectId: project.id,
|
|
468
|
+
signal
|
|
469
|
+
});
|
|
407
470
|
if (servicesResult.isErr()) throw new Error(servicesResult.error.message);
|
|
408
471
|
for (const service of servicesResult.value) {
|
|
409
|
-
const detailResult = await sdk.showService({
|
|
472
|
+
const detailResult = await sdk.showService({
|
|
473
|
+
serviceId: service.id,
|
|
474
|
+
signal
|
|
475
|
+
});
|
|
410
476
|
if (detailResult.isErr()) throw new Error(detailResult.error.message);
|
|
411
477
|
const app = {
|
|
412
478
|
id: detailResult.value.id,
|
|
@@ -416,7 +482,10 @@ async function findAppForDeployment(sdk, deploymentId) {
|
|
|
416
482
|
liveUrl: toAbsoluteUrl(detailResult.value.serviceEndpointDomain ?? null)
|
|
417
483
|
};
|
|
418
484
|
if (app.liveDeploymentId === deploymentId) return app;
|
|
419
|
-
const versionsResult = await sdk.listVersions({
|
|
485
|
+
const versionsResult = await sdk.listVersions({
|
|
486
|
+
serviceId: service.id,
|
|
487
|
+
signal
|
|
488
|
+
});
|
|
420
489
|
if (versionsResult.isErr()) throw new Error(versionsResult.error.message);
|
|
421
490
|
if (versionsResult.value.some((version) => version.id === deploymentId)) return app;
|
|
422
491
|
}
|