@prisma/compute-sdk 0.20.0 → 0.22.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/README.md +3 -1
- package/dist/api-client.d.ts +105 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +39 -0
- package/dist/api-client.js.map +1 -1
- package/dist/artifact-postprocess.d.ts +7 -0
- package/dist/artifact-postprocess.d.ts.map +1 -0
- package/dist/artifact-postprocess.js +54 -0
- package/dist/artifact-postprocess.js.map +1 -0
- package/dist/compute-client.d.ts.map +1 -1
- package/dist/compute-client.js +73 -35
- package/dist/compute-client.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/nextjs-build.d.ts.map +1 -1
- package/dist/nextjs-build.js +2 -0
- package/dist/nextjs-build.js.map +1 -1
- package/dist/upload-artifact.d.ts +5 -0
- package/dist/upload-artifact.d.ts.map +1 -0
- package/dist/upload-artifact.js +27 -0
- package/dist/upload-artifact.js.map +1 -0
- package/package.json +2 -2
- package/src/api-client.ts +89 -0
- package/src/artifact-postprocess.ts +74 -0
- package/src/compute-client.ts +142 -36
- package/src/errors.ts +1 -0
- package/src/index.ts +3 -0
- package/src/nextjs-build.ts +3 -0
- package/src/upload-artifact.ts +30 -0
package/src/compute-client.ts
CHANGED
|
@@ -48,6 +48,7 @@ import type {
|
|
|
48
48
|
VersionInfo,
|
|
49
49
|
} from "./types.ts";
|
|
50
50
|
import { REGIONS } from "./types.ts";
|
|
51
|
+
import { uploadArtifact } from "./upload-artifact.ts";
|
|
51
52
|
|
|
52
53
|
type VersionDetailData = InferOk<
|
|
53
54
|
Awaited<ReturnType<InternalApiClient["getVersion"]>>
|
|
@@ -284,13 +285,19 @@ export class ComputeClient {
|
|
|
284
285
|
? artifact.defaultPortMapping
|
|
285
286
|
: undefined);
|
|
286
287
|
|
|
288
|
+
yield* Result.await(
|
|
289
|
+
self.#applyEnvVars(
|
|
290
|
+
target.projectId,
|
|
291
|
+
target.branchId,
|
|
292
|
+
options.envVars,
|
|
293
|
+
options.signal,
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
|
|
287
297
|
const createResponse = yield* Result.await(
|
|
288
298
|
self.#api.createServiceVersion(
|
|
289
299
|
target.serviceId,
|
|
290
|
-
{
|
|
291
|
-
envVars: options.envVars,
|
|
292
|
-
portMapping,
|
|
293
|
-
},
|
|
300
|
+
portMapping ? { portMapping } : {},
|
|
294
301
|
options.signal,
|
|
295
302
|
),
|
|
296
303
|
);
|
|
@@ -309,7 +316,7 @@ export class ComputeClient {
|
|
|
309
316
|
|
|
310
317
|
options.progress?.onUploadStart?.();
|
|
311
318
|
yield* Result.await(
|
|
312
|
-
self.#
|
|
319
|
+
self.#uploadArtifactResult(uploadUrl, archiveBytes, options.signal),
|
|
313
320
|
);
|
|
314
321
|
options.progress?.onUploadComplete?.();
|
|
315
322
|
|
|
@@ -412,14 +419,25 @@ export class ComputeClient {
|
|
|
412
419
|
);
|
|
413
420
|
}
|
|
414
421
|
|
|
422
|
+
yield* self.#checkAborted(options.signal);
|
|
423
|
+
yield* Result.await(
|
|
424
|
+
self.#applyEnvVars(
|
|
425
|
+
target.projectId,
|
|
426
|
+
target.branchId,
|
|
427
|
+
options.envVars,
|
|
428
|
+
options.signal,
|
|
429
|
+
),
|
|
430
|
+
);
|
|
431
|
+
|
|
415
432
|
yield* self.#checkAborted(options.signal);
|
|
416
433
|
|
|
417
434
|
const createResponse = yield* Result.await(
|
|
418
435
|
self.#api.createServiceVersion(
|
|
419
436
|
target.serviceId,
|
|
420
437
|
{
|
|
421
|
-
|
|
422
|
-
|
|
438
|
+
...(options.portMapping !== undefined
|
|
439
|
+
? { portMapping: options.portMapping }
|
|
440
|
+
: {}),
|
|
423
441
|
skipCodeUpload: true,
|
|
424
442
|
},
|
|
425
443
|
options.signal,
|
|
@@ -1179,9 +1197,14 @@ export class ComputeClient {
|
|
|
1179
1197
|
serviceId: string;
|
|
1180
1198
|
serviceName: string;
|
|
1181
1199
|
region: string;
|
|
1200
|
+
branchId: string | null;
|
|
1182
1201
|
isNewService: boolean;
|
|
1183
1202
|
},
|
|
1184
|
-
|
|
1203
|
+
| MissingArgumentError
|
|
1204
|
+
| CancelledError
|
|
1205
|
+
| AuthenticationError
|
|
1206
|
+
| ApiError
|
|
1207
|
+
| InvalidOptionsError
|
|
1185
1208
|
>
|
|
1186
1209
|
> {
|
|
1187
1210
|
const self = this;
|
|
@@ -1190,15 +1213,27 @@ export class ComputeClient {
|
|
|
1190
1213
|
const service = yield* Result.await(
|
|
1191
1214
|
self.#api.getService(options.serviceId, options.signal),
|
|
1192
1215
|
);
|
|
1193
|
-
|
|
1194
|
-
if (!projectId) {
|
|
1216
|
+
if (!service.projectId) {
|
|
1195
1217
|
return Result.err(new MissingArgumentError({ field: "projectId" }));
|
|
1196
1218
|
}
|
|
1219
|
+
const requestedProjectId = options.projectId?.replace(/^proj_/, "");
|
|
1220
|
+
const serviceProjectId = service.projectId.replace(/^proj_/, "");
|
|
1221
|
+
if (
|
|
1222
|
+
requestedProjectId !== undefined &&
|
|
1223
|
+
requestedProjectId !== serviceProjectId
|
|
1224
|
+
) {
|
|
1225
|
+
return Result.err(
|
|
1226
|
+
new InvalidOptionsError({
|
|
1227
|
+
message: `Service ${service.id} belongs to project ${service.projectId}, but project ${options.projectId} was provided`,
|
|
1228
|
+
}),
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1197
1231
|
return Result.ok({
|
|
1198
|
-
projectId,
|
|
1232
|
+
projectId: service.projectId,
|
|
1199
1233
|
serviceId: service.id,
|
|
1200
1234
|
serviceName: service.name ?? service.id,
|
|
1201
1235
|
region: service.region.id,
|
|
1236
|
+
branchId: service.branchId ?? null,
|
|
1202
1237
|
isNewService: false,
|
|
1203
1238
|
});
|
|
1204
1239
|
}
|
|
@@ -1239,6 +1274,7 @@ export class ComputeClient {
|
|
|
1239
1274
|
serviceId: response.id,
|
|
1240
1275
|
serviceName: response.name,
|
|
1241
1276
|
region: response.region.id,
|
|
1277
|
+
branchId: response.branchId ?? null,
|
|
1242
1278
|
isNewService: true,
|
|
1243
1279
|
});
|
|
1244
1280
|
}
|
|
@@ -1263,13 +1299,20 @@ export class ComputeClient {
|
|
|
1263
1299
|
await options.interaction.selectService(serviceInfos);
|
|
1264
1300
|
|
|
1265
1301
|
if (selectedServiceId !== null) {
|
|
1266
|
-
const
|
|
1267
|
-
invariant(
|
|
1302
|
+
const selected = services.find((s) => s.id === selectedServiceId);
|
|
1303
|
+
invariant(
|
|
1304
|
+
selected,
|
|
1305
|
+
"selectService returned service ID not in the list",
|
|
1306
|
+
);
|
|
1307
|
+
const service = yield* Result.await(
|
|
1308
|
+
self.#api.getService(selectedServiceId, options.signal),
|
|
1309
|
+
);
|
|
1268
1310
|
return Result.ok({
|
|
1269
1311
|
projectId,
|
|
1270
1312
|
serviceId: selectedServiceId,
|
|
1271
|
-
serviceName: service.name,
|
|
1313
|
+
serviceName: service.name ?? selected.name,
|
|
1272
1314
|
region: service.region.id,
|
|
1315
|
+
branchId: service.branchId ?? null,
|
|
1273
1316
|
isNewService: false,
|
|
1274
1317
|
});
|
|
1275
1318
|
}
|
|
@@ -1306,39 +1349,102 @@ export class ComputeClient {
|
|
|
1306
1349
|
serviceId: response.id,
|
|
1307
1350
|
serviceName: response.name,
|
|
1308
1351
|
region: response.region.id,
|
|
1352
|
+
branchId: response.branchId ?? null,
|
|
1309
1353
|
isNewService: true,
|
|
1310
1354
|
});
|
|
1311
1355
|
});
|
|
1312
1356
|
}
|
|
1313
1357
|
|
|
1314
|
-
async #
|
|
1358
|
+
async #applyEnvVars(
|
|
1359
|
+
projectId: string,
|
|
1360
|
+
branchId: string | null,
|
|
1361
|
+
envVars: Record<string, string | null> | undefined,
|
|
1362
|
+
signal?: AbortSignal,
|
|
1363
|
+
): Promise<Result<void, ApiRequestError>> {
|
|
1364
|
+
if (!envVars || Object.keys(envVars).length === 0) {
|
|
1365
|
+
return Result.ok(undefined);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
const self = this;
|
|
1369
|
+
return Result.gen(async function* () {
|
|
1370
|
+
const scope = yield* Result.await(
|
|
1371
|
+
self.#resolveEnvironmentVariableScope(projectId, branchId, signal),
|
|
1372
|
+
);
|
|
1373
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
1374
|
+
yield* self.#checkAborted(signal);
|
|
1375
|
+
const existing = yield* Result.await(
|
|
1376
|
+
self.#api.listEnvironmentVariables({ ...scope, key }, signal),
|
|
1377
|
+
);
|
|
1378
|
+
const current = existing[0];
|
|
1379
|
+
|
|
1380
|
+
if (value === null) {
|
|
1381
|
+
if (current) {
|
|
1382
|
+
yield* self.#checkAborted(signal);
|
|
1383
|
+
// Do not pass signal to mutating transport; aborting it can make remote completion ambiguous.
|
|
1384
|
+
yield* Result.await(
|
|
1385
|
+
self.#api.deleteEnvironmentVariable(current.id),
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
if (current) {
|
|
1392
|
+
yield* self.#checkAborted(signal);
|
|
1393
|
+
// Do not pass signal to mutating transport; aborting it can make remote completion ambiguous.
|
|
1394
|
+
yield* Result.await(
|
|
1395
|
+
self.#api.updateEnvironmentVariable(current.id, { value }),
|
|
1396
|
+
);
|
|
1397
|
+
continue;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
yield* self.#checkAborted(signal);
|
|
1401
|
+
// Do not pass signal to mutating transport; aborting it can make remote completion ambiguous.
|
|
1402
|
+
yield* Result.await(
|
|
1403
|
+
self.#api.createEnvironmentVariable({ ...scope, key, value }),
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
return Result.ok(undefined);
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
async #resolveEnvironmentVariableScope(
|
|
1412
|
+
projectId: string,
|
|
1413
|
+
branchId: string | null,
|
|
1414
|
+
signal?: AbortSignal,
|
|
1415
|
+
): Promise<
|
|
1416
|
+
Result<
|
|
1417
|
+
| { projectId: string; class: "production" }
|
|
1418
|
+
| {
|
|
1419
|
+
projectId: string;
|
|
1420
|
+
class: "preview";
|
|
1421
|
+
branchId: string;
|
|
1422
|
+
},
|
|
1423
|
+
ApiRequestError
|
|
1424
|
+
>
|
|
1425
|
+
> {
|
|
1426
|
+
if (!branchId) {
|
|
1427
|
+
return Result.ok({ projectId, class: "production" });
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
const branch = await this.#api.getBranch(branchId, signal);
|
|
1431
|
+
if (branch.isErr()) return branch;
|
|
1432
|
+
|
|
1433
|
+
if (branch.value.role === "preview") {
|
|
1434
|
+
return Result.ok({ projectId, class: "preview", branchId });
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
return Result.ok({ projectId, class: "production" });
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
async #uploadArtifactResult(
|
|
1315
1441
|
url: string,
|
|
1316
1442
|
body: Uint8Array,
|
|
1317
1443
|
signal?: AbortSignal,
|
|
1318
1444
|
): Promise<Result<void, ArtifactError | CancelledError>> {
|
|
1319
1445
|
return Result.tryPromise({
|
|
1320
1446
|
try: async () => {
|
|
1321
|
-
signal
|
|
1322
|
-
// Intentionally do not pass AbortSignal to this mutating upload request.
|
|
1323
|
-
// Aborting transport can leave completion ambiguous server-side.
|
|
1324
|
-
const res = await fetch(url, {
|
|
1325
|
-
method: "PUT",
|
|
1326
|
-
headers: { "content-type": "application/gzip" },
|
|
1327
|
-
body,
|
|
1328
|
-
});
|
|
1329
|
-
|
|
1330
|
-
if (!res.ok) {
|
|
1331
|
-
let message = `Artifact upload failed with HTTP ${res.status}`;
|
|
1332
|
-
try {
|
|
1333
|
-
const json = (await res.json()) as { error?: unknown };
|
|
1334
|
-
if (typeof json.error === "string" && json.error.length > 0) {
|
|
1335
|
-
message = `Artifact upload failed: ${json.error}`;
|
|
1336
|
-
}
|
|
1337
|
-
} catch {
|
|
1338
|
-
// ignore body parse failures
|
|
1339
|
-
}
|
|
1340
|
-
throw new Error(message);
|
|
1341
|
-
}
|
|
1447
|
+
await uploadArtifact(url, body, signal);
|
|
1342
1448
|
},
|
|
1343
1449
|
catch: (e) => {
|
|
1344
1450
|
if (signal?.aborted) return new CancelledError();
|
package/src/errors.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -7,6 +7,8 @@ export {
|
|
|
7
7
|
type Result,
|
|
8
8
|
TaggedError,
|
|
9
9
|
} from "better-result";
|
|
10
|
+
export { createArchive } from "./archive.ts";
|
|
11
|
+
export { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
|
|
10
12
|
export { AstroBuild } from "./astro-build.ts";
|
|
11
13
|
export { AutoBuild } from "./auto-build.ts";
|
|
12
14
|
export type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
|
|
@@ -94,3 +96,4 @@ export type {
|
|
|
94
96
|
VersionInfo,
|
|
95
97
|
} from "./types.ts";
|
|
96
98
|
export { KNOWN_REGION_IDS, REGIONS } from "./types.ts";
|
|
99
|
+
export { uploadArtifact } from "./upload-artifact.ts";
|
package/src/nextjs-build.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cp, mkdtemp, readdir, rm, stat } from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { normalizeArtifactSymlinks } from "./artifact-postprocess.ts";
|
|
4
5
|
import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
|
|
5
6
|
import {
|
|
6
7
|
hasPackageDependency,
|
|
@@ -95,6 +96,8 @@ export class NextjsBuild implements BuildStrategy {
|
|
|
95
96
|
? "server.js"
|
|
96
97
|
: path.posix.join(serverSubpath, "server.js");
|
|
97
98
|
|
|
99
|
+
await normalizeArtifactSymlinks(artifactDir, this.#appPath, signal);
|
|
100
|
+
|
|
98
101
|
return {
|
|
99
102
|
directory: artifactDir,
|
|
100
103
|
entrypoint,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PUT a gzipped compute artifact to a Foundry-minted presigned upload URL.
|
|
3
|
+
*/
|
|
4
|
+
export async function uploadArtifact(
|
|
5
|
+
uploadUrl: string,
|
|
6
|
+
body: Uint8Array,
|
|
7
|
+
signal?: AbortSignal,
|
|
8
|
+
): Promise<void> {
|
|
9
|
+
signal?.throwIfAborted();
|
|
10
|
+
// Intentionally do not pass AbortSignal to this mutating upload request.
|
|
11
|
+
// Aborting transport can leave completion ambiguous server-side.
|
|
12
|
+
const response = await fetch(uploadUrl, {
|
|
13
|
+
method: "PUT",
|
|
14
|
+
headers: { "content-type": "application/gzip" },
|
|
15
|
+
body,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
let message = `Artifact upload failed with HTTP ${response.status}`;
|
|
20
|
+
try {
|
|
21
|
+
const json = (await response.json()) as { error?: unknown };
|
|
22
|
+
if (typeof json.error === "string" && json.error.length > 0) {
|
|
23
|
+
message = `Artifact upload failed: ${json.error}`;
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// ignore body parse failures
|
|
27
|
+
}
|
|
28
|
+
throw new Error(message);
|
|
29
|
+
}
|
|
30
|
+
}
|