@lizard-build/sdk 0.1.41 → 0.1.42
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/index.d.mts +35 -2
- package/dist/index.d.ts +35 -2
- package/dist/index.js +47 -7
- package/dist/index.mjs +47 -7
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1352,6 +1352,12 @@ interface VolumeInfo {
|
|
|
1352
1352
|
status: string;
|
|
1353
1353
|
attachedTo?: string | null;
|
|
1354
1354
|
createdAt: number;
|
|
1355
|
+
/**
|
|
1356
|
+
* Whether `sizeGb` is actually enforced as a hard limit on the volume's node.
|
|
1357
|
+
* Returned by {@link Volume.resize}; `false` means the size was recorded but the
|
|
1358
|
+
* node cannot enforce it, so writes past it are not refused.
|
|
1359
|
+
*/
|
|
1360
|
+
sizeEnforced?: boolean;
|
|
1355
1361
|
}
|
|
1356
1362
|
interface CreateVolumeOpts extends ConnectionOpts {
|
|
1357
1363
|
/** Whole GB, default 5. New volumes allow 1–50 GB unless the server config sets another maximum. Existing volumes are never resized. */
|
|
@@ -1399,8 +1405,8 @@ declare class Volume {
|
|
|
1399
1405
|
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1400
1406
|
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1401
1407
|
*
|
|
1402
|
-
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1403
|
-
*
|
|
1408
|
+
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create,
|
|
1409
|
+
* so an existing volume keeps its size. Call {@link Volume.resize} to change it.
|
|
1404
1410
|
*/
|
|
1405
1411
|
static getOrCreate(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
|
|
1406
1412
|
/** Look a volume up by name or by id. */
|
|
@@ -1408,7 +1414,26 @@ declare class Volume {
|
|
|
1408
1414
|
static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
|
|
1409
1415
|
/** Delete a volume by name or by id, without constructing one first. */
|
|
1410
1416
|
static delete(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<void>;
|
|
1417
|
+
/**
|
|
1418
|
+
* Resize a volume, by name or by id, to `sizeGb`.
|
|
1419
|
+
*
|
|
1420
|
+
* The change is in place and online: the size is a quota, so no data is copied,
|
|
1421
|
+
* it completes in well under a second, and a sandbox that has the volume mounted
|
|
1422
|
+
* keeps running and sees the new size immediately. Both growing and shrinking are
|
|
1423
|
+
* allowed, but a shrink must leave at least 10% of the new size free — otherwise
|
|
1424
|
+
* it throws `ConflictError` with `code: 'volume_too_full_to_shrink'`.
|
|
1425
|
+
*
|
|
1426
|
+
* Other failures carry a `code` too: `invalid_volume_size`, `volume_not_resizable`,
|
|
1427
|
+
* `volume_resize_in_progress`, `volume_not_provisioned`,
|
|
1428
|
+
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
1429
|
+
* the size is left unchanged).
|
|
1430
|
+
*
|
|
1431
|
+
* @returns The volume's updated info, including `sizeEnforced`.
|
|
1432
|
+
*/
|
|
1433
|
+
static resize(projectId: string, nameOrId: string, sizeGb: number, opts?: ConnectionOpts): Promise<VolumeInfo>;
|
|
1411
1434
|
getInfo(projectId: string): Promise<VolumeInfo>;
|
|
1435
|
+
/** Resize this volume in place — see the static {@link Volume.resize}. */
|
|
1436
|
+
resize(projectId: string, sizeGb: number): Promise<VolumeInfo>;
|
|
1412
1437
|
delete(projectId: string): Promise<void>;
|
|
1413
1438
|
}
|
|
1414
1439
|
|
|
@@ -1508,6 +1533,7 @@ declare class Lizard {
|
|
|
1508
1533
|
getOrCreate: (name: string, opts?: CreateVolumeOpts) => Promise<Volume>;
|
|
1509
1534
|
get: (nameOrId: string, opts?: ConnectionOpts) => Promise<Volume>;
|
|
1510
1535
|
list: (opts?: ConnectionOpts) => Promise<VolumeInfo[]>;
|
|
1536
|
+
resize: (nameOrId: string, sizeGb: number, opts?: ConnectionOpts) => Promise<VolumeInfo>;
|
|
1511
1537
|
delete: (nameOrId: string, opts?: ConnectionOpts) => Promise<void>;
|
|
1512
1538
|
};
|
|
1513
1539
|
/**
|
|
@@ -1557,6 +1583,13 @@ interface Account {
|
|
|
1557
1583
|
declare function resolveProjectId(ref: string, config: ConnectionConfig): Promise<string>;
|
|
1558
1584
|
|
|
1559
1585
|
declare class LizardError extends Error {
|
|
1586
|
+
/** HTTP status of the failed API call, when the error came from one. */
|
|
1587
|
+
status?: number;
|
|
1588
|
+
/**
|
|
1589
|
+
* The server's machine-readable error code, when it sent one — e.g.
|
|
1590
|
+
* `'volume_too_full_to_shrink'`. Branch on this rather than on `message`.
|
|
1591
|
+
*/
|
|
1592
|
+
code?: string;
|
|
1560
1593
|
constructor(message: string);
|
|
1561
1594
|
}
|
|
1562
1595
|
/** Config was saved, but one or more deploy/restart actions failed. Never retry blindly. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1352,6 +1352,12 @@ interface VolumeInfo {
|
|
|
1352
1352
|
status: string;
|
|
1353
1353
|
attachedTo?: string | null;
|
|
1354
1354
|
createdAt: number;
|
|
1355
|
+
/**
|
|
1356
|
+
* Whether `sizeGb` is actually enforced as a hard limit on the volume's node.
|
|
1357
|
+
* Returned by {@link Volume.resize}; `false` means the size was recorded but the
|
|
1358
|
+
* node cannot enforce it, so writes past it are not refused.
|
|
1359
|
+
*/
|
|
1360
|
+
sizeEnforced?: boolean;
|
|
1355
1361
|
}
|
|
1356
1362
|
interface CreateVolumeOpts extends ConnectionOpts {
|
|
1357
1363
|
/** Whole GB, default 5. New volumes allow 1–50 GB unless the server config sets another maximum. Existing volumes are never resized. */
|
|
@@ -1399,8 +1405,8 @@ declare class Volume {
|
|
|
1399
1405
|
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1400
1406
|
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1401
1407
|
*
|
|
1402
|
-
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1403
|
-
*
|
|
1408
|
+
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create,
|
|
1409
|
+
* so an existing volume keeps its size. Call {@link Volume.resize} to change it.
|
|
1404
1410
|
*/
|
|
1405
1411
|
static getOrCreate(projectId: string, name: string, opts?: CreateVolumeOpts): Promise<Volume>;
|
|
1406
1412
|
/** Look a volume up by name or by id. */
|
|
@@ -1408,7 +1414,26 @@ declare class Volume {
|
|
|
1408
1414
|
static list(projectId: string, opts?: ConnectionOpts): Promise<VolumeInfo[]>;
|
|
1409
1415
|
/** Delete a volume by name or by id, without constructing one first. */
|
|
1410
1416
|
static delete(projectId: string, nameOrId: string, opts?: ConnectionOpts): Promise<void>;
|
|
1417
|
+
/**
|
|
1418
|
+
* Resize a volume, by name or by id, to `sizeGb`.
|
|
1419
|
+
*
|
|
1420
|
+
* The change is in place and online: the size is a quota, so no data is copied,
|
|
1421
|
+
* it completes in well under a second, and a sandbox that has the volume mounted
|
|
1422
|
+
* keeps running and sees the new size immediately. Both growing and shrinking are
|
|
1423
|
+
* allowed, but a shrink must leave at least 10% of the new size free — otherwise
|
|
1424
|
+
* it throws `ConflictError` with `code: 'volume_too_full_to_shrink'`.
|
|
1425
|
+
*
|
|
1426
|
+
* Other failures carry a `code` too: `invalid_volume_size`, `volume_not_resizable`,
|
|
1427
|
+
* `volume_resize_in_progress`, `volume_not_provisioned`,
|
|
1428
|
+
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
1429
|
+
* the size is left unchanged).
|
|
1430
|
+
*
|
|
1431
|
+
* @returns The volume's updated info, including `sizeEnforced`.
|
|
1432
|
+
*/
|
|
1433
|
+
static resize(projectId: string, nameOrId: string, sizeGb: number, opts?: ConnectionOpts): Promise<VolumeInfo>;
|
|
1411
1434
|
getInfo(projectId: string): Promise<VolumeInfo>;
|
|
1435
|
+
/** Resize this volume in place — see the static {@link Volume.resize}. */
|
|
1436
|
+
resize(projectId: string, sizeGb: number): Promise<VolumeInfo>;
|
|
1412
1437
|
delete(projectId: string): Promise<void>;
|
|
1413
1438
|
}
|
|
1414
1439
|
|
|
@@ -1508,6 +1533,7 @@ declare class Lizard {
|
|
|
1508
1533
|
getOrCreate: (name: string, opts?: CreateVolumeOpts) => Promise<Volume>;
|
|
1509
1534
|
get: (nameOrId: string, opts?: ConnectionOpts) => Promise<Volume>;
|
|
1510
1535
|
list: (opts?: ConnectionOpts) => Promise<VolumeInfo[]>;
|
|
1536
|
+
resize: (nameOrId: string, sizeGb: number, opts?: ConnectionOpts) => Promise<VolumeInfo>;
|
|
1511
1537
|
delete: (nameOrId: string, opts?: ConnectionOpts) => Promise<void>;
|
|
1512
1538
|
};
|
|
1513
1539
|
/**
|
|
@@ -1557,6 +1583,13 @@ interface Account {
|
|
|
1557
1583
|
declare function resolveProjectId(ref: string, config: ConnectionConfig): Promise<string>;
|
|
1558
1584
|
|
|
1559
1585
|
declare class LizardError extends Error {
|
|
1586
|
+
/** HTTP status of the failed API call, when the error came from one. */
|
|
1587
|
+
status?: number;
|
|
1588
|
+
/**
|
|
1589
|
+
* The server's machine-readable error code, when it sent one — e.g.
|
|
1590
|
+
* `'volume_too_full_to_shrink'`. Branch on this rather than on `message`.
|
|
1591
|
+
*/
|
|
1592
|
+
code?: string;
|
|
1560
1593
|
constructor(message: string);
|
|
1561
1594
|
}
|
|
1562
1595
|
/** Config was saved, but one or more deploy/restart actions failed. Never retry blindly. */
|
package/dist/index.js
CHANGED
|
@@ -112,17 +112,23 @@ var TimeoutError = class extends LizardError {
|
|
|
112
112
|
};
|
|
113
113
|
async function handleApiError(res) {
|
|
114
114
|
let message;
|
|
115
|
+
let code;
|
|
115
116
|
try {
|
|
116
117
|
const body = await res.json();
|
|
117
118
|
message = body.error ?? res.statusText;
|
|
119
|
+
if (typeof body.code === "string") code = body.code;
|
|
118
120
|
} catch {
|
|
119
121
|
message = res.statusText;
|
|
120
122
|
}
|
|
121
|
-
|
|
122
|
-
if (res.status ===
|
|
123
|
-
if (res.status ===
|
|
124
|
-
if (res.status ===
|
|
125
|
-
|
|
123
|
+
let err;
|
|
124
|
+
if (res.status === 401 || res.status === 403) err = new AuthenticationError(message);
|
|
125
|
+
else if (res.status === 404) err = new NotFoundError(message);
|
|
126
|
+
else if (res.status === 409) err = new ConflictError(message);
|
|
127
|
+
else if (res.status === 408 || res.status === 504) err = new TimeoutError(message);
|
|
128
|
+
else err = new LizardError(`API error ${res.status}: ${message}`);
|
|
129
|
+
err.status = res.status;
|
|
130
|
+
err.code = code;
|
|
131
|
+
throw err;
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
// src/platform/client.ts
|
|
@@ -1565,8 +1571,8 @@ var Volume = class _Volume {
|
|
|
1565
1571
|
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1566
1572
|
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1567
1573
|
*
|
|
1568
|
-
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1569
|
-
*
|
|
1574
|
+
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create,
|
|
1575
|
+
* so an existing volume keeps its size. Call {@link Volume.resize} to change it.
|
|
1570
1576
|
*/
|
|
1571
1577
|
static async getOrCreate(projectId, name, opts) {
|
|
1572
1578
|
const config = new ConnectionConfig(opts);
|
|
@@ -1606,6 +1612,32 @@ var Volume = class _Volume {
|
|
|
1606
1612
|
});
|
|
1607
1613
|
if (!res.ok) await handleApiError(res);
|
|
1608
1614
|
}
|
|
1615
|
+
/**
|
|
1616
|
+
* Resize a volume, by name or by id, to `sizeGb`.
|
|
1617
|
+
*
|
|
1618
|
+
* The change is in place and online: the size is a quota, so no data is copied,
|
|
1619
|
+
* it completes in well under a second, and a sandbox that has the volume mounted
|
|
1620
|
+
* keeps running and sees the new size immediately. Both growing and shrinking are
|
|
1621
|
+
* allowed, but a shrink must leave at least 10% of the new size free — otherwise
|
|
1622
|
+
* it throws `ConflictError` with `code: 'volume_too_full_to_shrink'`.
|
|
1623
|
+
*
|
|
1624
|
+
* Other failures carry a `code` too: `invalid_volume_size`, `volume_not_resizable`,
|
|
1625
|
+
* `volume_resize_in_progress`, `volume_not_provisioned`,
|
|
1626
|
+
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
1627
|
+
* the size is left unchanged).
|
|
1628
|
+
*
|
|
1629
|
+
* @returns The volume's updated info, including `sizeEnforced`.
|
|
1630
|
+
*/
|
|
1631
|
+
static async resize(projectId, nameOrId, sizeGb, opts) {
|
|
1632
|
+
const config = new ConnectionConfig(opts);
|
|
1633
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1634
|
+
method: "PATCH",
|
|
1635
|
+
headers: config.headers,
|
|
1636
|
+
body: JSON.stringify({ sizeGb })
|
|
1637
|
+
});
|
|
1638
|
+
if (!res.ok) await handleApiError(res);
|
|
1639
|
+
return res.json();
|
|
1640
|
+
}
|
|
1609
1641
|
async getInfo(projectId) {
|
|
1610
1642
|
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1611
1643
|
headers: this.config.headers
|
|
@@ -1613,6 +1645,13 @@ var Volume = class _Volume {
|
|
|
1613
1645
|
if (!res.ok) await handleApiError(res);
|
|
1614
1646
|
return res.json();
|
|
1615
1647
|
}
|
|
1648
|
+
/** Resize this volume in place — see the static {@link Volume.resize}. */
|
|
1649
|
+
async resize(projectId, sizeGb) {
|
|
1650
|
+
return _Volume.resize(projectId, this.volumeId, sizeGb, {
|
|
1651
|
+
apiKey: this.config.apiKey,
|
|
1652
|
+
apiUrl: this.config.apiUrl
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1616
1655
|
async delete(projectId) {
|
|
1617
1656
|
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1618
1657
|
method: "DELETE",
|
|
@@ -1646,6 +1685,7 @@ var Lizard = class {
|
|
|
1646
1685
|
getOrCreate: async (name, opts) => Volume.getOrCreate(await this.projectId(), name, { ...await this.connectionOpts(), ...opts }),
|
|
1647
1686
|
get: async (nameOrId, opts) => Volume.get(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts }),
|
|
1648
1687
|
list: async (opts) => Volume.list(await this.projectId(), { ...await this.connectionOpts(), ...opts }),
|
|
1688
|
+
resize: async (nameOrId, sizeGb, opts) => Volume.resize(await this.projectId(), nameOrId, sizeGb, { ...await this.connectionOpts(), ...opts }),
|
|
1649
1689
|
delete: async (nameOrId, opts) => Volume.delete(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts })
|
|
1650
1690
|
};
|
|
1651
1691
|
this.config = new ConnectionConfig(opts);
|
package/dist/index.mjs
CHANGED
|
@@ -61,17 +61,23 @@ var TimeoutError = class extends LizardError {
|
|
|
61
61
|
};
|
|
62
62
|
async function handleApiError(res) {
|
|
63
63
|
let message;
|
|
64
|
+
let code;
|
|
64
65
|
try {
|
|
65
66
|
const body = await res.json();
|
|
66
67
|
message = body.error ?? res.statusText;
|
|
68
|
+
if (typeof body.code === "string") code = body.code;
|
|
67
69
|
} catch {
|
|
68
70
|
message = res.statusText;
|
|
69
71
|
}
|
|
70
|
-
|
|
71
|
-
if (res.status ===
|
|
72
|
-
if (res.status ===
|
|
73
|
-
if (res.status ===
|
|
74
|
-
|
|
72
|
+
let err;
|
|
73
|
+
if (res.status === 401 || res.status === 403) err = new AuthenticationError(message);
|
|
74
|
+
else if (res.status === 404) err = new NotFoundError(message);
|
|
75
|
+
else if (res.status === 409) err = new ConflictError(message);
|
|
76
|
+
else if (res.status === 408 || res.status === 504) err = new TimeoutError(message);
|
|
77
|
+
else err = new LizardError(`API error ${res.status}: ${message}`);
|
|
78
|
+
err.status = res.status;
|
|
79
|
+
err.code = code;
|
|
80
|
+
throw err;
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
// src/platform/client.ts
|
|
@@ -1514,8 +1520,8 @@ var Volume = class _Volume {
|
|
|
1514
1520
|
* exist yet. This is the reason a volume's name is its key: an agent that wants
|
|
1515
1521
|
* "the scratch disk for this task" no longer has to store an id between runs.
|
|
1516
1522
|
*
|
|
1517
|
-
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create
|
|
1518
|
-
*
|
|
1523
|
+
* An existing volume is returned as-is — `sizeGb` applies only to a fresh create,
|
|
1524
|
+
* so an existing volume keeps its size. Call {@link Volume.resize} to change it.
|
|
1519
1525
|
*/
|
|
1520
1526
|
static async getOrCreate(projectId, name, opts) {
|
|
1521
1527
|
const config = new ConnectionConfig(opts);
|
|
@@ -1555,6 +1561,32 @@ var Volume = class _Volume {
|
|
|
1555
1561
|
});
|
|
1556
1562
|
if (!res.ok) await handleApiError(res);
|
|
1557
1563
|
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Resize a volume, by name or by id, to `sizeGb`.
|
|
1566
|
+
*
|
|
1567
|
+
* The change is in place and online: the size is a quota, so no data is copied,
|
|
1568
|
+
* it completes in well under a second, and a sandbox that has the volume mounted
|
|
1569
|
+
* keeps running and sees the new size immediately. Both growing and shrinking are
|
|
1570
|
+
* allowed, but a shrink must leave at least 10% of the new size free — otherwise
|
|
1571
|
+
* it throws `ConflictError` with `code: 'volume_too_full_to_shrink'`.
|
|
1572
|
+
*
|
|
1573
|
+
* Other failures carry a `code` too: `invalid_volume_size`, `volume_not_resizable`,
|
|
1574
|
+
* `volume_resize_in_progress`, `volume_not_provisioned`,
|
|
1575
|
+
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
1576
|
+
* the size is left unchanged).
|
|
1577
|
+
*
|
|
1578
|
+
* @returns The volume's updated info, including `sizeEnforced`.
|
|
1579
|
+
*/
|
|
1580
|
+
static async resize(projectId, nameOrId, sizeGb, opts) {
|
|
1581
|
+
const config = new ConnectionConfig(opts);
|
|
1582
|
+
const res = await fetch(`${config.apiUrl}/api/projects/${projectId}/volumes/${encodeURIComponent(nameOrId)}`, {
|
|
1583
|
+
method: "PATCH",
|
|
1584
|
+
headers: config.headers,
|
|
1585
|
+
body: JSON.stringify({ sizeGb })
|
|
1586
|
+
});
|
|
1587
|
+
if (!res.ok) await handleApiError(res);
|
|
1588
|
+
return res.json();
|
|
1589
|
+
}
|
|
1558
1590
|
async getInfo(projectId) {
|
|
1559
1591
|
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1560
1592
|
headers: this.config.headers
|
|
@@ -1562,6 +1594,13 @@ var Volume = class _Volume {
|
|
|
1562
1594
|
if (!res.ok) await handleApiError(res);
|
|
1563
1595
|
return res.json();
|
|
1564
1596
|
}
|
|
1597
|
+
/** Resize this volume in place — see the static {@link Volume.resize}. */
|
|
1598
|
+
async resize(projectId, sizeGb) {
|
|
1599
|
+
return _Volume.resize(projectId, this.volumeId, sizeGb, {
|
|
1600
|
+
apiKey: this.config.apiKey,
|
|
1601
|
+
apiUrl: this.config.apiUrl
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1565
1604
|
async delete(projectId) {
|
|
1566
1605
|
const res = await fetch(`${this.config.apiUrl}/api/projects/${projectId}/volumes/${this.volumeId}`, {
|
|
1567
1606
|
method: "DELETE",
|
|
@@ -1595,6 +1634,7 @@ var Lizard = class {
|
|
|
1595
1634
|
getOrCreate: async (name, opts) => Volume.getOrCreate(await this.projectId(), name, { ...await this.connectionOpts(), ...opts }),
|
|
1596
1635
|
get: async (nameOrId, opts) => Volume.get(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts }),
|
|
1597
1636
|
list: async (opts) => Volume.list(await this.projectId(), { ...await this.connectionOpts(), ...opts }),
|
|
1637
|
+
resize: async (nameOrId, sizeGb, opts) => Volume.resize(await this.projectId(), nameOrId, sizeGb, { ...await this.connectionOpts(), ...opts }),
|
|
1598
1638
|
delete: async (nameOrId, opts) => Volume.delete(await this.projectId(), nameOrId, { ...await this.connectionOpts(), ...opts })
|
|
1599
1639
|
};
|
|
1600
1640
|
this.config = new ConnectionConfig(opts);
|
package/package.json
CHANGED