@lizard-build/sdk 0.1.35 → 0.1.37
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 +93 -27
- package/dist/index.d.mts +424 -103
- package/dist/index.d.ts +424 -103
- package/dist/index.js +279 -113
- package/dist/index.mjs +268 -113
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,16 +20,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AddonsAPI: () => AddonsAPI,
|
|
24
|
+
ApiKeysAPI: () => ApiKeysAPI,
|
|
23
25
|
AuthenticationError: () => AuthenticationError,
|
|
26
|
+
BillingAPI: () => BillingAPI,
|
|
24
27
|
CodeSandbox: () => CodeSandbox,
|
|
25
28
|
ConflictError: () => ConflictError,
|
|
26
29
|
DeployHandle: () => DeployHandle,
|
|
30
|
+
DomainsAPI: () => DomainsAPI,
|
|
27
31
|
Lizard: () => Lizard,
|
|
28
32
|
LizardError: () => LizardError,
|
|
33
|
+
MetricsAPI: () => MetricsAPI,
|
|
29
34
|
NotFoundError: () => NotFoundError,
|
|
35
|
+
PlatformClient: () => PlatformClient,
|
|
36
|
+
ProjectsAPI: () => ProjectsAPI,
|
|
37
|
+
RegionsAPI: () => RegionsAPI,
|
|
30
38
|
Sandbox: () => Sandbox,
|
|
39
|
+
SecretsAPI: () => SecretsAPI,
|
|
40
|
+
ServicesAPI: () => ServicesAPI,
|
|
31
41
|
TimeoutError: () => TimeoutError,
|
|
32
42
|
Volume: () => Volume,
|
|
43
|
+
WorkspacesAPI: () => WorkspacesAPI,
|
|
33
44
|
resolveProjectId: () => resolveProjectId
|
|
34
45
|
});
|
|
35
46
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -475,8 +486,10 @@ var SandboxClient = class {
|
|
|
475
486
|
projectId,
|
|
476
487
|
metadata: opts?.metadata,
|
|
477
488
|
envs: opts?.envs,
|
|
489
|
+
region: opts?.region,
|
|
478
490
|
volumeId: opts?.volumeId,
|
|
479
|
-
volumeName: opts?.volumeName
|
|
491
|
+
volumeName: opts?.volumeName,
|
|
492
|
+
lizardToken: opts?.lizardToken
|
|
480
493
|
})
|
|
481
494
|
});
|
|
482
495
|
if (!res.ok) await handleApiError(res);
|
|
@@ -567,8 +580,14 @@ var Sandbox = class extends SandboxClient {
|
|
|
567
580
|
/**
|
|
568
581
|
* Connect to an existing sandbox by its ID.
|
|
569
582
|
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
583
|
+
* Verifies the sandbox exists and is reachable, then returns a handle to it.
|
|
584
|
+
* Throws `NotFoundError` if it has been killed or has expired.
|
|
585
|
+
*
|
|
586
|
+
* This used to call `resume` first, on the assumption that a sandbox you are
|
|
587
|
+
* reconnecting to might be paused. Sandboxes are pods now and pause/resume is a
|
|
588
|
+
* `501` on every one of them, so that call turned every `connect()` into an
|
|
589
|
+
* error against a perfectly healthy sandbox. Connecting does not need to change
|
|
590
|
+
* a sandbox's state, so it no longer tries to.
|
|
572
591
|
*
|
|
573
592
|
* @example
|
|
574
593
|
* ```ts
|
|
@@ -576,7 +595,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
576
595
|
* ```
|
|
577
596
|
*/
|
|
578
597
|
static async connect(sandboxId, opts) {
|
|
579
|
-
await SandboxClient.
|
|
598
|
+
await SandboxClient.getSandboxInfo(sandboxId, opts);
|
|
580
599
|
return new this({ sandboxId, ...opts });
|
|
581
600
|
}
|
|
582
601
|
/**
|
|
@@ -599,37 +618,23 @@ var Sandbox = class extends SandboxClient {
|
|
|
599
618
|
return SandboxClient.killSandbox(this.sandboxId, this.resolveOpts(opts));
|
|
600
619
|
}
|
|
601
620
|
/**
|
|
602
|
-
* Pause the sandbox
|
|
603
|
-
*
|
|
604
|
-
* Memory, filesystem, and running processes are held in the host's RAM —
|
|
605
|
-
* nothing is written to disk, so a paused sandbox does not survive a host
|
|
606
|
-
* failure. Resume with `sandbox.resume()` or `Sandbox.connect(id)`.
|
|
607
|
-
*
|
|
608
|
-
* Pausing does not buy you time past the original deadline. Resuming pushes the
|
|
609
|
-
* expiry forward by however long the sandbox was paused — so a pause/resume cycle
|
|
610
|
-
* costs no runtime — but that adjustment only happens on `resume()`. A sandbox left
|
|
611
|
-
* paused past its original `expiresAt` is deleted there, within a minute, and
|
|
612
|
-
* `resume()` then returns `false`.
|
|
613
|
-
*
|
|
614
|
-
* In other words: pause and come back *before* the original deadline and you lose
|
|
615
|
-
* nothing; leave it paused across the deadline and it is gone. Pass `timeoutMs: 0`
|
|
616
|
-
* at create time to opt out of expiry entirely, which is the only way to park a
|
|
617
|
-
* sandbox indefinitely.
|
|
621
|
+
* Pause the sandbox by freezing it in place.
|
|
618
622
|
*
|
|
619
|
-
* @
|
|
623
|
+
* @deprecated Not implemented for the current runtime — always throws
|
|
624
|
+
* `LizardError` with HTTP 501. Sandboxes run as pods, and the equivalent is a CRIU
|
|
625
|
+
* checkpoint of the pod, which is not built. To park work across a gap, put it on a
|
|
626
|
+
* {@link Volume} and create a fresh sandbox on that volume later; the volume is the
|
|
627
|
+
* part that is meant to outlive a sandbox.
|
|
620
628
|
*/
|
|
621
629
|
async pause(opts) {
|
|
622
630
|
return SandboxClient.pauseSandbox(this.sandboxId, this.resolveOpts(opts));
|
|
623
631
|
}
|
|
624
632
|
/**
|
|
625
|
-
* Resume a paused sandbox
|
|
633
|
+
* Resume a paused sandbox.
|
|
626
634
|
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
* @returns `true` if resumed successfully, `false` if the sandbox no longer exists
|
|
632
|
-
* (including because it expired while paused).
|
|
635
|
+
* @deprecated Not implemented for the current runtime — always throws
|
|
636
|
+
* `LizardError` with HTTP 501. See {@link pause}. `Sandbox.connect()` no longer
|
|
637
|
+
* calls this, so reconnecting to a running sandbox works without it.
|
|
633
638
|
*/
|
|
634
639
|
async resume(opts) {
|
|
635
640
|
return SandboxClient.resumeSandbox(this.sandboxId, this.resolveOpts(opts));
|
|
@@ -1085,13 +1090,233 @@ var MetricsAPI = class {
|
|
|
1085
1090
|
}
|
|
1086
1091
|
};
|
|
1087
1092
|
|
|
1093
|
+
// src/platform/workspaces.ts
|
|
1094
|
+
var WorkspacesAPI = class {
|
|
1095
|
+
constructor(client) {
|
|
1096
|
+
this.client = client;
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* List workspaces the calling credential can see.
|
|
1100
|
+
*
|
|
1101
|
+
* A scoped API key sees only what it is scoped to: a workspace-scoped key returns
|
|
1102
|
+
* that one workspace, and a project-scoped key returns the workspace containing its
|
|
1103
|
+
* project. A full key returns every workspace the account belongs to.
|
|
1104
|
+
*/
|
|
1105
|
+
list() {
|
|
1106
|
+
return this.client.get("/api/workspaces");
|
|
1107
|
+
}
|
|
1108
|
+
/** Create a workspace. The caller becomes its owner. */
|
|
1109
|
+
create(opts) {
|
|
1110
|
+
return this.client.post("/api/workspaces", opts);
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Delete a workspace.
|
|
1114
|
+
*
|
|
1115
|
+
* Empty-only by default — the server refuses while any project or sandbox remains,
|
|
1116
|
+
* so this cannot quietly destroy a user's work. Pass `{ force: true }` to delete a
|
|
1117
|
+
* workspace and everything in it; that is irreversible.
|
|
1118
|
+
*/
|
|
1119
|
+
delete(id, opts) {
|
|
1120
|
+
const qs = opts?.force ? "" : "?requireEmpty=true";
|
|
1121
|
+
return this.client.delete(`/api/workspaces/${id}${qs}`);
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Find a workspace by name, slug, or id, or `null` if there is no such workspace.
|
|
1125
|
+
* Matching is exact; id wins, then slug, then name.
|
|
1126
|
+
*/
|
|
1127
|
+
async find(nameOrSlugOrId) {
|
|
1128
|
+
const all = await this.list();
|
|
1129
|
+
return all.find((w) => w.id === nameOrSlugOrId) ?? all.find((w) => w.slug === nameOrSlugOrId) ?? all.find((w) => w.name === nameOrSlugOrId) ?? null;
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// src/platform/api-keys.ts
|
|
1134
|
+
var ApiKeysAPI = class {
|
|
1135
|
+
constructor(client) {
|
|
1136
|
+
this.client = client;
|
|
1137
|
+
}
|
|
1138
|
+
/** List the account's API keys. Previews only — full keys are never returned here. */
|
|
1139
|
+
list() {
|
|
1140
|
+
return this.client.get("/api/account/api-keys");
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Create an API key.
|
|
1144
|
+
*
|
|
1145
|
+
* The response is the only place the full key appears. Omitting every scope creates
|
|
1146
|
+
* a full-access key; the server rejects an attempt to create one from a key that is
|
|
1147
|
+
* itself scoped.
|
|
1148
|
+
*/
|
|
1149
|
+
create(opts) {
|
|
1150
|
+
const scopes = [
|
|
1151
|
+
...opts.scopes ?? [],
|
|
1152
|
+
...(opts.workspaces ?? []).map((id) => ({ type: "workspace", id })),
|
|
1153
|
+
...(opts.projects ?? []).map((id) => ({ type: "project", id }))
|
|
1154
|
+
];
|
|
1155
|
+
return this.client.post("/api/account/api-keys", { name: opts.name, scopes });
|
|
1156
|
+
}
|
|
1157
|
+
/** Revoke a key by id. It stops working immediately, everywhere. */
|
|
1158
|
+
delete(id) {
|
|
1159
|
+
return this.client.delete(`/api/account/api-keys/${id}`);
|
|
1160
|
+
}
|
|
1161
|
+
};
|
|
1162
|
+
|
|
1163
|
+
// src/platform/regions.ts
|
|
1164
|
+
var RegionsAPI = class {
|
|
1165
|
+
constructor(client) {
|
|
1166
|
+
this.client = client;
|
|
1167
|
+
}
|
|
1168
|
+
/** List every region, including ones not currently accepting workloads. */
|
|
1169
|
+
list() {
|
|
1170
|
+
return this.client.get("/api/regions");
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
|
|
1174
|
+
// src/platform/billing.ts
|
|
1175
|
+
var BillingAPI = class {
|
|
1176
|
+
constructor(client) {
|
|
1177
|
+
this.client = client;
|
|
1178
|
+
}
|
|
1179
|
+
/** Current balance, status, burn rate, and runway. */
|
|
1180
|
+
balance() {
|
|
1181
|
+
return this.client.get("/api/billing/balance");
|
|
1182
|
+
}
|
|
1183
|
+
/** A page of balance transactions, newest first. */
|
|
1184
|
+
transactions(opts) {
|
|
1185
|
+
const qs = new URLSearchParams();
|
|
1186
|
+
if (opts?.limit !== void 0) qs.set("limit", String(opts.limit));
|
|
1187
|
+
if (opts?.cursor) qs.set("cursor", opts.cursor);
|
|
1188
|
+
if (opts?.includeUsage) qs.set("includeUsage", "1");
|
|
1189
|
+
const q = qs.toString();
|
|
1190
|
+
return this.client.get(`/api/billing/transactions${q ? `?${q}` : ""}`);
|
|
1191
|
+
}
|
|
1192
|
+
/** Cost summary for the current billing period, broken down by resource. */
|
|
1193
|
+
summary() {
|
|
1194
|
+
return this.client.get("/api/billing/summary");
|
|
1195
|
+
}
|
|
1196
|
+
/** Live (not-yet-invoiced) usage accumulating right now. */
|
|
1197
|
+
live() {
|
|
1198
|
+
return this.client.get("/api/billing/live");
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
// src/volume/index.ts
|
|
1203
|
+
var Volume = class _Volume {
|
|
1204
|
+
constructor(opts) {
|
|
1205
|
+
this.volumeId = opts.volumeId;
|
|
1206
|
+
this.name = opts.name;
|
|
1207
|
+
this.config = new ConnectionConfig(opts);
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* Create a volume. Throws `ConflictError` (409) if the project already has one with
|
|
1211
|
+
* this name — use {@link getOrCreate} when you want "make sure this exists" instead.
|
|
1212
|
+
*/
|
|
1213
|
+
static async create(projectId, name, opts) {
|
|
1214
|
+
const config = new ConnectionConfig(opts);
|
|
1215
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1216
|
+
method: "POST",
|
|
1217
|
+
headers: config.headers,
|
|
1218
|
+
body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5, region: opts?.region })
|
|
1219
|
+
});
|
|
1220
|
+
if (!res.ok) await handleApiError(res);
|
|
1221
|
+
const vol = await res.json();
|
|
1222
|
+
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Return the project's volume with this name, creating it first if it does not
|
|
1226
|
+
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1227
|
+
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1228
|
+
*
|
|
1229
|
+
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1230
|
+
* and never resizes one that is already there.
|
|
1231
|
+
*/
|
|
1232
|
+
static async getOrCreate(projectId, name, opts) {
|
|
1233
|
+
const config = new ConnectionConfig(opts);
|
|
1234
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1235
|
+
method: "POST",
|
|
1236
|
+
headers: config.headers,
|
|
1237
|
+
body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5, region: opts?.region, getOrCreate: true })
|
|
1238
|
+
});
|
|
1239
|
+
if (!res.ok) await handleApiError(res);
|
|
1240
|
+
const vol = await res.json();
|
|
1241
|
+
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1242
|
+
}
|
|
1243
|
+
/** Look a volume up by name or by id. */
|
|
1244
|
+
static async get(projectId, nameOrId, opts) {
|
|
1245
|
+
const config = new ConnectionConfig(opts);
|
|
1246
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1247
|
+
headers: config.headers
|
|
1248
|
+
});
|
|
1249
|
+
if (!res.ok) await handleApiError(res);
|
|
1250
|
+
const vol = await res.json();
|
|
1251
|
+
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1252
|
+
}
|
|
1253
|
+
static async list(projectId, opts) {
|
|
1254
|
+
const config = new ConnectionConfig(opts);
|
|
1255
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1256
|
+
headers: config.headers
|
|
1257
|
+
});
|
|
1258
|
+
if (!res.ok) await handleApiError(res);
|
|
1259
|
+
return res.json();
|
|
1260
|
+
}
|
|
1261
|
+
/** Delete a volume by name or by id, without constructing one first. */
|
|
1262
|
+
static async delete(projectId, nameOrId, opts) {
|
|
1263
|
+
const config = new ConnectionConfig(opts);
|
|
1264
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1265
|
+
method: "DELETE",
|
|
1266
|
+
headers: config.headers
|
|
1267
|
+
});
|
|
1268
|
+
if (!res.ok) await handleApiError(res);
|
|
1269
|
+
}
|
|
1270
|
+
async getInfo(projectId) {
|
|
1271
|
+
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1272
|
+
headers: this.config.headers
|
|
1273
|
+
});
|
|
1274
|
+
if (!res.ok) await handleApiError(res);
|
|
1275
|
+
return res.json();
|
|
1276
|
+
}
|
|
1277
|
+
async delete(projectId) {
|
|
1278
|
+
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1279
|
+
method: "DELETE",
|
|
1280
|
+
headers: this.config.headers
|
|
1281
|
+
});
|
|
1282
|
+
if (!res.ok) await handleApiError(res);
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1088
1286
|
// src/lizard.ts
|
|
1089
1287
|
var Lizard = class {
|
|
1090
1288
|
constructor(opts) {
|
|
1289
|
+
// ── Volumes, bound to this client's project ───────────────────────────────
|
|
1290
|
+
/**
|
|
1291
|
+
* Persistent volumes in this client's project.
|
|
1292
|
+
*
|
|
1293
|
+
* The same calls as the static {@link Volume} methods, minus the `projectId`
|
|
1294
|
+
* argument — the client already knows it.
|
|
1295
|
+
*
|
|
1296
|
+
* @requires `project` to be set in the constructor.
|
|
1297
|
+
*
|
|
1298
|
+
* @example
|
|
1299
|
+
* ```ts
|
|
1300
|
+
* const lizard = new Lizard({ project: 'my-project' })
|
|
1301
|
+
* const vol = await lizard.volumes.getOrCreate('scratch', { sizeGb: 10 })
|
|
1302
|
+
* const sb = await lizard.create('codex', { volumeName: 'scratch' })
|
|
1303
|
+
* ```
|
|
1304
|
+
*/
|
|
1305
|
+
this.volumes = {
|
|
1306
|
+
create: async (name, opts) => Volume.create(await this.projectId(), name, { ...await this.connectionOpts(), ...opts }),
|
|
1307
|
+
getOrCreate: async (name, opts) => Volume.getOrCreate(await this.projectId(), name, { ...await this.connectionOpts(), ...opts }),
|
|
1308
|
+
get: async (nameOrId, opts) => Volume.get(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts }),
|
|
1309
|
+
list: async (opts) => Volume.list(await this.projectId(), { ...await this.connectionOpts(), ...opts }),
|
|
1310
|
+
delete: async (nameOrId, opts) => Volume.delete(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts })
|
|
1311
|
+
};
|
|
1091
1312
|
this.config = new ConnectionConfig(opts);
|
|
1092
1313
|
this.projectRef = opts.project;
|
|
1093
1314
|
const platform = new PlatformClient(opts);
|
|
1094
1315
|
this._platform = platform;
|
|
1316
|
+
this.workspaces = new WorkspacesAPI(platform);
|
|
1317
|
+
this.apiKeys = new ApiKeysAPI(platform);
|
|
1318
|
+
this.regions = new RegionsAPI(platform);
|
|
1319
|
+
this.billing = new BillingAPI(platform);
|
|
1095
1320
|
this.projects = new ProjectsAPI(platform);
|
|
1096
1321
|
this.services = new ServicesAPI(platform);
|
|
1097
1322
|
this.addons = new AddonsAPI(platform);
|
|
@@ -1117,7 +1342,7 @@ var Lizard = class {
|
|
|
1117
1342
|
const sandboxOpts = { ...opts, ...await this.connectionOpts(), projectId };
|
|
1118
1343
|
return template ? Sandbox.create(template, sandboxOpts) : Sandbox.create(sandboxOpts);
|
|
1119
1344
|
}
|
|
1120
|
-
/** Connect to an existing sandbox by ID
|
|
1345
|
+
/** Connect to an existing sandbox by ID. Throws `NotFoundError` if it is gone. */
|
|
1121
1346
|
async connect(sandboxId, opts) {
|
|
1122
1347
|
return Sandbox.connect(sandboxId, await this.connectionOpts(opts));
|
|
1123
1348
|
}
|
|
@@ -1125,6 +1350,20 @@ var Lizard = class {
|
|
|
1125
1350
|
async list(opts) {
|
|
1126
1351
|
return Sandbox.list(await this.connectionOpts(opts));
|
|
1127
1352
|
}
|
|
1353
|
+
// ── Account ───────────────────────────────────────────────────────────────
|
|
1354
|
+
/**
|
|
1355
|
+
* The account this credential belongs to — the SDK's `lizard whoami`.
|
|
1356
|
+
*
|
|
1357
|
+
* Works for a scoped key as well as a full one: the identity is the account that
|
|
1358
|
+
* created the key, which is what the key's usage bills to.
|
|
1359
|
+
*/
|
|
1360
|
+
async whoami() {
|
|
1361
|
+
return this.platform.get("/api/auth/me");
|
|
1362
|
+
}
|
|
1363
|
+
/** The underlying HTTP client, for endpoints this SDK does not wrap yet. */
|
|
1364
|
+
get platform() {
|
|
1365
|
+
return this._platform;
|
|
1366
|
+
}
|
|
1128
1367
|
};
|
|
1129
1368
|
|
|
1130
1369
|
// src/code-interpreter/types.ts
|
|
@@ -1316,101 +1555,28 @@ async function* readLines(body) {
|
|
|
1316
1555
|
reader.releaseLock();
|
|
1317
1556
|
}
|
|
1318
1557
|
}
|
|
1319
|
-
|
|
1320
|
-
// src/volume/index.ts
|
|
1321
|
-
var Volume = class _Volume {
|
|
1322
|
-
constructor(opts) {
|
|
1323
|
-
this.volumeId = opts.volumeId;
|
|
1324
|
-
this.name = opts.name;
|
|
1325
|
-
this.config = new ConnectionConfig(opts);
|
|
1326
|
-
}
|
|
1327
|
-
/**
|
|
1328
|
-
* Create a volume. Throws `ConflictError` (409) if the project already has one with
|
|
1329
|
-
* this name — use {@link getOrCreate} when you want "make sure this exists" instead.
|
|
1330
|
-
*/
|
|
1331
|
-
static async create(projectId, name, opts) {
|
|
1332
|
-
const config = new ConnectionConfig(opts);
|
|
1333
|
-
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1334
|
-
method: "POST",
|
|
1335
|
-
headers: config.headers,
|
|
1336
|
-
body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5 })
|
|
1337
|
-
});
|
|
1338
|
-
if (!res.ok) await handleApiError(res);
|
|
1339
|
-
const vol = await res.json();
|
|
1340
|
-
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1341
|
-
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Return the project's volume with this name, creating it first if it does not
|
|
1344
|
-
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1345
|
-
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1346
|
-
*
|
|
1347
|
-
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1348
|
-
* and never resizes one that is already there.
|
|
1349
|
-
*/
|
|
1350
|
-
static async getOrCreate(projectId, name, opts) {
|
|
1351
|
-
const config = new ConnectionConfig(opts);
|
|
1352
|
-
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1353
|
-
method: "POST",
|
|
1354
|
-
headers: config.headers,
|
|
1355
|
-
body: JSON.stringify({ name, sizeGb: opts?.sizeGb ?? 5, getOrCreate: true })
|
|
1356
|
-
});
|
|
1357
|
-
if (!res.ok) await handleApiError(res);
|
|
1358
|
-
const vol = await res.json();
|
|
1359
|
-
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1360
|
-
}
|
|
1361
|
-
/** Look a volume up by name or by id. */
|
|
1362
|
-
static async get(projectId, nameOrId, opts) {
|
|
1363
|
-
const config = new ConnectionConfig(opts);
|
|
1364
|
-
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1365
|
-
headers: config.headers
|
|
1366
|
-
});
|
|
1367
|
-
if (!res.ok) await handleApiError(res);
|
|
1368
|
-
const vol = await res.json();
|
|
1369
|
-
return new _Volume({ volumeId: vol.id, name: vol.name, ...opts });
|
|
1370
|
-
}
|
|
1371
|
-
static async list(projectId, opts) {
|
|
1372
|
-
const config = new ConnectionConfig(opts);
|
|
1373
|
-
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes`, {
|
|
1374
|
-
headers: config.headers
|
|
1375
|
-
});
|
|
1376
|
-
if (!res.ok) await handleApiError(res);
|
|
1377
|
-
return res.json();
|
|
1378
|
-
}
|
|
1379
|
-
/** Delete a volume by name or by id, without constructing one first. */
|
|
1380
|
-
static async delete(projectId, nameOrId, opts) {
|
|
1381
|
-
const config = new ConnectionConfig(opts);
|
|
1382
|
-
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1383
|
-
method: "DELETE",
|
|
1384
|
-
headers: config.headers
|
|
1385
|
-
});
|
|
1386
|
-
if (!res.ok) await handleApiError(res);
|
|
1387
|
-
}
|
|
1388
|
-
async getInfo(projectId) {
|
|
1389
|
-
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1390
|
-
headers: this.config.headers
|
|
1391
|
-
});
|
|
1392
|
-
if (!res.ok) await handleApiError(res);
|
|
1393
|
-
return res.json();
|
|
1394
|
-
}
|
|
1395
|
-
async delete(projectId) {
|
|
1396
|
-
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1397
|
-
method: "DELETE",
|
|
1398
|
-
headers: this.config.headers
|
|
1399
|
-
});
|
|
1400
|
-
if (!res.ok) await handleApiError(res);
|
|
1401
|
-
}
|
|
1402
|
-
};
|
|
1403
1558
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1404
1559
|
0 && (module.exports = {
|
|
1560
|
+
AddonsAPI,
|
|
1561
|
+
ApiKeysAPI,
|
|
1405
1562
|
AuthenticationError,
|
|
1563
|
+
BillingAPI,
|
|
1406
1564
|
CodeSandbox,
|
|
1407
1565
|
ConflictError,
|
|
1408
1566
|
DeployHandle,
|
|
1567
|
+
DomainsAPI,
|
|
1409
1568
|
Lizard,
|
|
1410
1569
|
LizardError,
|
|
1570
|
+
MetricsAPI,
|
|
1411
1571
|
NotFoundError,
|
|
1572
|
+
PlatformClient,
|
|
1573
|
+
ProjectsAPI,
|
|
1574
|
+
RegionsAPI,
|
|
1412
1575
|
Sandbox,
|
|
1576
|
+
SecretsAPI,
|
|
1577
|
+
ServicesAPI,
|
|
1413
1578
|
TimeoutError,
|
|
1414
1579
|
Volume,
|
|
1580
|
+
WorkspacesAPI,
|
|
1415
1581
|
resolveProjectId
|
|
1416
1582
|
});
|