@prisma/compute-sdk 0.2.0 → 0.3.0
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/api-client.d.ts +229 -4
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +46 -26
- package/dist/api-client.js.map +1 -1
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +25 -11
- package/dist/archive.js.map +1 -1
- package/dist/compute-client.d.ts +8 -1
- package/dist/compute-client.d.ts.map +1 -1
- package/dist/compute-client.js +40 -11
- package/dist/compute-client.js.map +1 -1
- package/dist/errors.d.ts +10 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +8 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/polling.d.ts.map +1 -1
- package/dist/polling.js +1 -1
- package/dist/polling.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -6
- package/src/api-client.ts +69 -15
- package/src/archive.ts +33 -9
- package/src/compute-client.ts +64 -11
- package/src/errors.ts +13 -0
- package/src/index.ts +4 -0
- package/src/polling.ts +3 -1
- package/src/types.ts +11 -0
package/src/api-client.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ManagementApiClient, paths } from "@prisma/management-api-sdk";
|
|
2
2
|
import { Result } from "better-result";
|
|
3
|
-
import { ApiError, AuthenticationError } from "./errors.ts";
|
|
3
|
+
import { ApiError, AuthenticationError, CancelledError } from "./errors.ts";
|
|
4
4
|
|
|
5
|
-
export type ApiClientError = AuthenticationError | ApiError;
|
|
5
|
+
export type ApiClientError = CancelledError | AuthenticationError | ApiError;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Lean internal wrapper around ManagementApiClient.
|
|
@@ -26,9 +26,21 @@ export class InternalApiClient {
|
|
|
26
26
|
signal,
|
|
27
27
|
}),
|
|
28
28
|
"/v1/projects",
|
|
29
|
+
signal,
|
|
29
30
|
);
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
async createProject(body: CreateProjectBody, signal?: AbortSignal) {
|
|
34
|
+
return this.#request(
|
|
35
|
+
this.#client.POST("/v1/projects", {
|
|
36
|
+
body: body as SdkCreateProjectBody,
|
|
37
|
+
signal,
|
|
38
|
+
}),
|
|
39
|
+
"/v1/projects",
|
|
40
|
+
signal,
|
|
41
|
+
).then((r) => r.map((body) => body.data));
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
async getProject(id: string, signal?: AbortSignal) {
|
|
33
45
|
return this.#request(
|
|
34
46
|
this.#client.GET("/v1/projects/{id}", {
|
|
@@ -36,6 +48,7 @@ export class InternalApiClient {
|
|
|
36
48
|
signal,
|
|
37
49
|
}),
|
|
38
50
|
"/v1/projects/{id}",
|
|
51
|
+
signal,
|
|
39
52
|
).then((r) => r.map((body) => body.data));
|
|
40
53
|
}
|
|
41
54
|
|
|
@@ -47,6 +60,7 @@ export class InternalApiClient {
|
|
|
47
60
|
signal,
|
|
48
61
|
}),
|
|
49
62
|
"/v1/projects/{projectId}/compute-services",
|
|
63
|
+
signal,
|
|
50
64
|
);
|
|
51
65
|
}
|
|
52
66
|
|
|
@@ -62,6 +76,7 @@ export class InternalApiClient {
|
|
|
62
76
|
signal,
|
|
63
77
|
}),
|
|
64
78
|
"/v1/projects/{projectId}/compute-services",
|
|
79
|
+
signal,
|
|
65
80
|
).then((r) => r.map((body) => body.data));
|
|
66
81
|
}
|
|
67
82
|
|
|
@@ -72,6 +87,7 @@ export class InternalApiClient {
|
|
|
72
87
|
signal,
|
|
73
88
|
}),
|
|
74
89
|
"/v1/compute-services/{computeServiceId}",
|
|
90
|
+
signal,
|
|
75
91
|
).then((r) => r.map((body) => body.data));
|
|
76
92
|
}
|
|
77
93
|
|
|
@@ -84,6 +100,7 @@ export class InternalApiClient {
|
|
|
84
100
|
params: { path: { computeServiceId } },
|
|
85
101
|
signal,
|
|
86
102
|
}),
|
|
103
|
+
signal,
|
|
87
104
|
);
|
|
88
105
|
}
|
|
89
106
|
|
|
@@ -98,6 +115,7 @@ export class InternalApiClient {
|
|
|
98
115
|
signal,
|
|
99
116
|
}),
|
|
100
117
|
"/v1/compute-services/{computeServiceId}/versions",
|
|
118
|
+
signal,
|
|
101
119
|
);
|
|
102
120
|
}
|
|
103
121
|
|
|
@@ -113,6 +131,7 @@ export class InternalApiClient {
|
|
|
113
131
|
signal,
|
|
114
132
|
}),
|
|
115
133
|
"/v1/compute-services/{computeServiceId}/versions",
|
|
134
|
+
signal,
|
|
116
135
|
).then((r) => r.map((body) => body.data));
|
|
117
136
|
}
|
|
118
137
|
|
|
@@ -123,6 +142,7 @@ export class InternalApiClient {
|
|
|
123
142
|
signal,
|
|
124
143
|
}),
|
|
125
144
|
"/v1/compute-services/versions/{versionId}",
|
|
145
|
+
signal,
|
|
126
146
|
).then((r) => r.map((body) => body.data));
|
|
127
147
|
}
|
|
128
148
|
|
|
@@ -133,6 +153,7 @@ export class InternalApiClient {
|
|
|
133
153
|
signal,
|
|
134
154
|
}),
|
|
135
155
|
"/v1/compute-services/versions/{versionId}/start",
|
|
156
|
+
signal,
|
|
136
157
|
).then((r) => r.map((body) => body.data));
|
|
137
158
|
}
|
|
138
159
|
|
|
@@ -145,6 +166,7 @@ export class InternalApiClient {
|
|
|
145
166
|
params: { path: { versionId } },
|
|
146
167
|
signal,
|
|
147
168
|
}),
|
|
169
|
+
signal,
|
|
148
170
|
);
|
|
149
171
|
}
|
|
150
172
|
|
|
@@ -157,23 +179,33 @@ export class InternalApiClient {
|
|
|
157
179
|
params: { path: { versionId } },
|
|
158
180
|
signal,
|
|
159
181
|
}),
|
|
182
|
+
signal,
|
|
160
183
|
);
|
|
161
184
|
}
|
|
162
185
|
|
|
163
186
|
async #request<TData>(
|
|
164
187
|
request: Promise<RequestResult<TData>>,
|
|
165
188
|
endpoint: string,
|
|
189
|
+
signal?: AbortSignal,
|
|
166
190
|
): Promise<Result<NonNullable<TData>, ApiClientError>> {
|
|
167
|
-
|
|
191
|
+
let result: RequestResult<TData>;
|
|
192
|
+
try {
|
|
193
|
+
result = await request;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
return Result.err(parseRequestError(error, undefined, signal));
|
|
196
|
+
}
|
|
168
197
|
if (result.error) {
|
|
169
|
-
return Result.err(
|
|
198
|
+
return Result.err(
|
|
199
|
+
parseRequestError(result.error, result.response, signal),
|
|
200
|
+
);
|
|
170
201
|
}
|
|
171
202
|
const body = result.data;
|
|
172
203
|
if (body == null) {
|
|
173
204
|
return Result.err(
|
|
174
|
-
|
|
205
|
+
parseRequestError(
|
|
175
206
|
undefined,
|
|
176
207
|
undefined,
|
|
208
|
+
signal,
|
|
177
209
|
`Management API returned an empty response body for ${endpoint}`,
|
|
178
210
|
),
|
|
179
211
|
);
|
|
@@ -189,12 +221,13 @@ export class InternalApiClient {
|
|
|
189
221
|
}>
|
|
190
222
|
>,
|
|
191
223
|
endpoint: string,
|
|
224
|
+
signal?: AbortSignal,
|
|
192
225
|
): Promise<Result<TItem[], ApiClientError>> {
|
|
193
226
|
const allItems: TItem[] = [];
|
|
194
227
|
let cursor: string | undefined;
|
|
195
228
|
|
|
196
229
|
for (;;) {
|
|
197
|
-
const result = await this.#request(makeRequest(cursor), endpoint);
|
|
230
|
+
const result = await this.#request(makeRequest(cursor), endpoint, signal);
|
|
198
231
|
if (result.isErr()) return result;
|
|
199
232
|
|
|
200
233
|
allItems.push(...result.value.data);
|
|
@@ -209,10 +242,18 @@ export class InternalApiClient {
|
|
|
209
242
|
|
|
210
243
|
async #unwrapVoid(
|
|
211
244
|
request: Promise<RequestResult<unknown>>,
|
|
245
|
+
signal?: AbortSignal,
|
|
212
246
|
): Promise<Result<void, ApiClientError>> {
|
|
213
|
-
|
|
247
|
+
let result: RequestResult<unknown>;
|
|
248
|
+
try {
|
|
249
|
+
result = await request;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
return Result.err(parseRequestError(error, undefined, signal));
|
|
252
|
+
}
|
|
214
253
|
if (result.error) {
|
|
215
|
-
return Result.err(
|
|
254
|
+
return Result.err(
|
|
255
|
+
parseRequestError(result.error, result.response, signal),
|
|
256
|
+
);
|
|
216
257
|
}
|
|
217
258
|
return Result.ok(undefined);
|
|
218
259
|
}
|
|
@@ -222,6 +263,14 @@ type RequestResult<TData> =
|
|
|
222
263
|
| { data: TData; error?: never; response: Response }
|
|
223
264
|
| { data?: never; error: unknown; response: Response };
|
|
224
265
|
|
|
266
|
+
type SdkCreateProjectBody = NonNullable<
|
|
267
|
+
paths["/v1/projects"]["post"]["requestBody"]
|
|
268
|
+
>["content"]["application/json"];
|
|
269
|
+
|
|
270
|
+
type CreateProjectBody = Omit<SdkCreateProjectBody, "region"> & {
|
|
271
|
+
region?: string;
|
|
272
|
+
};
|
|
273
|
+
|
|
225
274
|
type SdkCreateProjectServiceBody = NonNullable<
|
|
226
275
|
paths["/v1/projects/{projectId}/compute-services"]["post"]["requestBody"]
|
|
227
276
|
>["content"]["application/json"];
|
|
@@ -303,20 +352,25 @@ function parseApiError(
|
|
|
303
352
|
});
|
|
304
353
|
}
|
|
305
354
|
|
|
355
|
+
function parseRequestError(
|
|
356
|
+
error: unknown,
|
|
357
|
+
response?: Response,
|
|
358
|
+
signal?: AbortSignal,
|
|
359
|
+
fallbackMessage?: string,
|
|
360
|
+
): ApiClientError {
|
|
361
|
+
if (signal?.aborted) {
|
|
362
|
+
return new CancelledError();
|
|
363
|
+
}
|
|
364
|
+
return parseApiError(error, response, fallbackMessage);
|
|
365
|
+
}
|
|
366
|
+
|
|
306
367
|
/** Extract the upload URL from a version creation response. */
|
|
307
368
|
export function readUploadUrl(data: {
|
|
308
369
|
uploadUrl?: string | null;
|
|
309
|
-
artifactUploadUrl?: string | null;
|
|
310
370
|
}): string | null {
|
|
311
371
|
if (typeof data.uploadUrl === "string" && data.uploadUrl.length > 0) {
|
|
312
372
|
return data.uploadUrl;
|
|
313
373
|
}
|
|
314
|
-
if (
|
|
315
|
-
typeof data.artifactUploadUrl === "string" &&
|
|
316
|
-
data.artifactUploadUrl.length > 0
|
|
317
|
-
) {
|
|
318
|
-
return data.artifactUploadUrl;
|
|
319
|
-
}
|
|
320
374
|
return null;
|
|
321
375
|
}
|
|
322
376
|
|
package/src/archive.ts
CHANGED
|
@@ -19,9 +19,10 @@ export async function createArchive(
|
|
|
19
19
|
entrypoint: string,
|
|
20
20
|
): Promise<Uint8Array> {
|
|
21
21
|
const packer = pack();
|
|
22
|
+
const rootPath = path.resolve(directory);
|
|
22
23
|
|
|
23
24
|
// Walk the directory and add all files
|
|
24
|
-
await addDirectory(packer,
|
|
25
|
+
await addDirectory(packer, rootPath, rootPath, "bundle");
|
|
25
26
|
|
|
26
27
|
// Inject the manifest as a synthetic entry
|
|
27
28
|
const manifest = JSON.stringify(
|
|
@@ -43,42 +44,49 @@ export async function createArchive(
|
|
|
43
44
|
|
|
44
45
|
async function addDirectory(
|
|
45
46
|
packer: Pack,
|
|
47
|
+
rootPath: string,
|
|
46
48
|
fsPath: string,
|
|
47
49
|
tarPrefix: string,
|
|
48
50
|
): Promise<void> {
|
|
49
|
-
const
|
|
51
|
+
const directoryPath = resolvePathWithinRoot(rootPath, fsPath);
|
|
52
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
50
53
|
|
|
51
54
|
for (const entry of entries) {
|
|
52
|
-
const fullPath = path.join(
|
|
55
|
+
const fullPath = path.join(directoryPath, entry.name);
|
|
53
56
|
const tarPath = `${tarPrefix}/${entry.name}`;
|
|
54
57
|
|
|
55
58
|
if (entry.isSymbolicLink()) {
|
|
56
59
|
// Dereference symlinks: stat the target and add accordingly
|
|
57
60
|
const target = await readlink(fullPath);
|
|
58
|
-
const resolvedPath =
|
|
61
|
+
const resolvedPath = resolvePathWithinRoot(
|
|
62
|
+
rootPath,
|
|
63
|
+
path.resolve(directoryPath, target),
|
|
64
|
+
);
|
|
59
65
|
const resolvedStat = await stat(resolvedPath);
|
|
60
66
|
|
|
61
67
|
if (resolvedStat.isDirectory()) {
|
|
62
|
-
await addDirectory(packer, resolvedPath, tarPath);
|
|
68
|
+
await addDirectory(packer, rootPath, resolvedPath, tarPath);
|
|
63
69
|
} else if (resolvedStat.isFile()) {
|
|
64
|
-
await addFile(packer, resolvedPath, tarPath, resolvedStat);
|
|
70
|
+
await addFile(packer, rootPath, resolvedPath, tarPath, resolvedStat);
|
|
65
71
|
}
|
|
66
72
|
} else if (entry.isDirectory()) {
|
|
67
|
-
await addDirectory(packer, fullPath, tarPath);
|
|
73
|
+
await addDirectory(packer, rootPath, fullPath, tarPath);
|
|
68
74
|
} else if (entry.isFile()) {
|
|
69
75
|
const fileStat = await lstat(fullPath);
|
|
70
|
-
await addFile(packer, fullPath, tarPath, fileStat);
|
|
76
|
+
await addFile(packer, rootPath, fullPath, tarPath, fileStat);
|
|
71
77
|
}
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
async function addFile(
|
|
76
82
|
packer: Pack,
|
|
83
|
+
rootPath: string,
|
|
77
84
|
fsPath: string,
|
|
78
85
|
tarPath: string,
|
|
79
86
|
fileStat: { size: number; mode: number; mtime: Date },
|
|
80
87
|
): Promise<void> {
|
|
81
|
-
const
|
|
88
|
+
const filePath = resolvePathWithinRoot(rootPath, fsPath);
|
|
89
|
+
const content = await readFile(filePath);
|
|
82
90
|
packer.entry(
|
|
83
91
|
{
|
|
84
92
|
name: tarPath,
|
|
@@ -90,6 +98,22 @@ async function addFile(
|
|
|
90
98
|
);
|
|
91
99
|
}
|
|
92
100
|
|
|
101
|
+
function resolvePathWithinRoot(rootPath: string, fsPath: string): string {
|
|
102
|
+
const normalizedRootPath = path.resolve(rootPath);
|
|
103
|
+
const resolvedPath = path.resolve(fsPath);
|
|
104
|
+
const relativePath = path.relative(normalizedRootPath, resolvedPath);
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
relativePath === ".." ||
|
|
108
|
+
relativePath.startsWith(`..${path.sep}`) ||
|
|
109
|
+
path.isAbsolute(relativePath)
|
|
110
|
+
) {
|
|
111
|
+
throw new Error(`Symlink target escapes archive root: ${resolvedPath}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return resolvedPath;
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
function collectGzipped(packer: Pack): Promise<Uint8Array> {
|
|
94
118
|
return new Promise<Uint8Array>((resolve, reject) => {
|
|
95
119
|
const chunks: Buffer[] = [];
|
package/src/compute-client.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ManagementApiClient } from "@prisma/management-api-sdk";
|
|
2
2
|
import { type InferOk, Result } from "better-result";
|
|
3
|
+
import invariant from "tiny-invariant";
|
|
3
4
|
import {
|
|
4
5
|
InternalApiClient,
|
|
5
6
|
readUploadUrl,
|
|
@@ -28,11 +29,13 @@ import {
|
|
|
28
29
|
type DestroyVersionError,
|
|
29
30
|
MissingArgumentError,
|
|
30
31
|
NoExistingVersionError,
|
|
32
|
+
NoVersionsFoundError,
|
|
31
33
|
type UpdateEnvError,
|
|
32
34
|
type VersionOperationError,
|
|
33
35
|
} from "./errors.ts";
|
|
34
36
|
import { pollVersionStatus } from "./polling.ts";
|
|
35
37
|
import type {
|
|
38
|
+
CreateProjectResult,
|
|
36
39
|
PortMapping,
|
|
37
40
|
ProjectInfo,
|
|
38
41
|
ResolvedConfig,
|
|
@@ -116,6 +119,13 @@ export interface DeleteServiceOptions {
|
|
|
116
119
|
signal?: AbortSignal;
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
export interface CreateProjectOptions {
|
|
123
|
+
name: string;
|
|
124
|
+
createDatabase?: boolean;
|
|
125
|
+
region?: string;
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
}
|
|
128
|
+
|
|
119
129
|
export interface ListProjectsOptions {
|
|
120
130
|
signal?: AbortSignal;
|
|
121
131
|
}
|
|
@@ -252,7 +262,9 @@ export class ComputeClient {
|
|
|
252
262
|
yield* self.#checkAborted(options.signal);
|
|
253
263
|
|
|
254
264
|
options.progress?.onUploadStart?.();
|
|
255
|
-
yield* Result.await(
|
|
265
|
+
yield* Result.await(
|
|
266
|
+
self.#uploadArtifact(uploadUrl, archiveBytes, options.signal),
|
|
267
|
+
);
|
|
256
268
|
options.progress?.onUploadComplete?.();
|
|
257
269
|
|
|
258
270
|
yield* self.#checkAborted(options.signal);
|
|
@@ -408,7 +420,7 @@ export class ComputeClient {
|
|
|
408
420
|
.sort(versionSortComparator);
|
|
409
421
|
|
|
410
422
|
if (versionInfos.length === 0) {
|
|
411
|
-
return Result.err(new
|
|
423
|
+
return Result.err(new NoVersionsFoundError({ serviceId }));
|
|
412
424
|
}
|
|
413
425
|
|
|
414
426
|
if (!options.interaction?.selectVersion) {
|
|
@@ -603,6 +615,45 @@ export class ComputeClient {
|
|
|
603
615
|
});
|
|
604
616
|
}
|
|
605
617
|
|
|
618
|
+
async createProject(
|
|
619
|
+
options: CreateProjectOptions,
|
|
620
|
+
): Promise<Result<CreateProjectResult, ApiRequestError>> {
|
|
621
|
+
const self = this;
|
|
622
|
+
return Result.gen(async function* () {
|
|
623
|
+
yield* self.#checkAborted(options.signal);
|
|
624
|
+
const createDatabase = options.createDatabase ?? false;
|
|
625
|
+
const response = yield* Result.await(
|
|
626
|
+
self.#api.createProject(
|
|
627
|
+
{
|
|
628
|
+
name: options.name,
|
|
629
|
+
createDatabase,
|
|
630
|
+
region: options.region,
|
|
631
|
+
},
|
|
632
|
+
options.signal,
|
|
633
|
+
),
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
const result: CreateProjectResult = {
|
|
637
|
+
id: response.id,
|
|
638
|
+
name: response.name,
|
|
639
|
+
defaultRegion: response.defaultRegion ?? undefined,
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
if (response.database) {
|
|
643
|
+
const connection = response.database.connections?.[0];
|
|
644
|
+
result.database = {
|
|
645
|
+
id: response.database.id,
|
|
646
|
+
name: response.database.name,
|
|
647
|
+
region: response.database.region.id,
|
|
648
|
+
connectionString:
|
|
649
|
+
connection?.endpoints?.direct?.connectionString ?? undefined,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return Result.ok(result);
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
606
657
|
async listProjects(
|
|
607
658
|
options: ListProjectsOptions = {},
|
|
608
659
|
): Promise<Result<ProjectInfo[], ApiRequestError>> {
|
|
@@ -819,7 +870,7 @@ export class ComputeClient {
|
|
|
819
870
|
serviceName: string;
|
|
820
871
|
region: string;
|
|
821
872
|
},
|
|
822
|
-
MissingArgumentError | AuthenticationError | ApiError
|
|
873
|
+
MissingArgumentError | CancelledError | AuthenticationError | ApiError
|
|
823
874
|
>
|
|
824
875
|
> {
|
|
825
876
|
const self = this;
|
|
@@ -900,9 +951,7 @@ export class ComputeClient {
|
|
|
900
951
|
|
|
901
952
|
if (selectedServiceId !== null) {
|
|
902
953
|
const service = services.find((s) => s.id === selectedServiceId);
|
|
903
|
-
|
|
904
|
-
throw new Error("selectService returned service ID not in the list");
|
|
905
|
-
}
|
|
954
|
+
invariant(service, "selectService returned service ID not in the list");
|
|
906
955
|
return Result.ok({
|
|
907
956
|
projectId,
|
|
908
957
|
serviceId: selectedServiceId,
|
|
@@ -950,13 +999,15 @@ export class ComputeClient {
|
|
|
950
999
|
async #uploadArtifact(
|
|
951
1000
|
url: string,
|
|
952
1001
|
body: Uint8Array,
|
|
953
|
-
|
|
1002
|
+
signal?: AbortSignal,
|
|
1003
|
+
): Promise<Result<void, ArtifactError | CancelledError>> {
|
|
954
1004
|
return Result.tryPromise({
|
|
955
1005
|
try: async () => {
|
|
956
1006
|
const res = await fetch(url, {
|
|
957
1007
|
method: "PUT",
|
|
958
1008
|
headers: { "content-type": "application/gzip" },
|
|
959
1009
|
body,
|
|
1010
|
+
signal,
|
|
960
1011
|
});
|
|
961
1012
|
|
|
962
1013
|
if (!res.ok) {
|
|
@@ -973,10 +1024,12 @@ export class ComputeClient {
|
|
|
973
1024
|
}
|
|
974
1025
|
},
|
|
975
1026
|
catch: (e) =>
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1027
|
+
signal?.aborted
|
|
1028
|
+
? new CancelledError()
|
|
1029
|
+
: new ArtifactError({
|
|
1030
|
+
message: e instanceof Error ? e.message : String(e),
|
|
1031
|
+
cause: e,
|
|
1032
|
+
}),
|
|
980
1033
|
});
|
|
981
1034
|
}
|
|
982
1035
|
}
|
package/src/errors.ts
CHANGED
|
@@ -80,6 +80,18 @@ export class NoExistingVersionError extends TaggedError(
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
export class NoVersionsFoundError extends TaggedError("NoVersionsFoundError")<{
|
|
84
|
+
serviceId: string;
|
|
85
|
+
message: string;
|
|
86
|
+
}>() {
|
|
87
|
+
constructor(args: { serviceId: string }) {
|
|
88
|
+
super({
|
|
89
|
+
serviceId: args.serviceId,
|
|
90
|
+
message: `Service ${args.serviceId} has no versions to destroy`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
83
95
|
export class CancelledError extends TaggedError("CancelledError")<{
|
|
84
96
|
message: string;
|
|
85
97
|
}>() {
|
|
@@ -131,6 +143,7 @@ export type UpdateEnvError =
|
|
|
131
143
|
export type DestroyVersionError =
|
|
132
144
|
| CancelledError
|
|
133
145
|
| MissingArgumentError
|
|
146
|
+
| NoVersionsFoundError
|
|
134
147
|
| AuthenticationError
|
|
135
148
|
| ApiError
|
|
136
149
|
| TimeoutError
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export type {
|
|
|
21
21
|
UpdateEnvProgress,
|
|
22
22
|
} from "./callbacks.ts";
|
|
23
23
|
export type {
|
|
24
|
+
CreateProjectOptions,
|
|
24
25
|
CreateServiceOptions,
|
|
25
26
|
DeleteServiceOptions,
|
|
26
27
|
DeleteVersionOptions,
|
|
@@ -60,11 +61,14 @@ export {
|
|
|
60
61
|
DestroyAggregateError,
|
|
61
62
|
MissingArgumentError,
|
|
62
63
|
NoExistingVersionError,
|
|
64
|
+
NoVersionsFoundError,
|
|
63
65
|
TimeoutError,
|
|
64
66
|
VersionFailedError,
|
|
65
67
|
} from "./errors.ts";
|
|
66
68
|
// Domain types
|
|
67
69
|
export type {
|
|
70
|
+
CreateProjectResult,
|
|
71
|
+
DatabaseInfo,
|
|
68
72
|
PortMapping,
|
|
69
73
|
ProjectInfo,
|
|
70
74
|
RegionInfo,
|
package/src/polling.ts
CHANGED
|
@@ -45,7 +45,9 @@ export async function pollVersionStatus(
|
|
|
45
45
|
return Result.err(new CancelledError());
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const version = yield* Result.await(
|
|
48
|
+
const version = yield* Result.await(
|
|
49
|
+
api.getVersion(versionId, options.signal),
|
|
50
|
+
);
|
|
49
51
|
|
|
50
52
|
if (version.status !== lastStatus) {
|
|
51
53
|
lastStatus = version.status;
|
package/src/types.ts
CHANGED
|
@@ -12,6 +12,17 @@ export interface ProjectInfo {
|
|
|
12
12
|
defaultRegion?: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export interface DatabaseInfo {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
region: string;
|
|
19
|
+
connectionString?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CreateProjectResult extends ProjectInfo {
|
|
23
|
+
database?: DatabaseInfo;
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
export interface ServiceInfo {
|
|
16
27
|
id: string;
|
|
17
28
|
name: string;
|