@slicervm/sdk 0.1.7 → 0.1.8
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 +29 -1
- package/dist/index.cjs +227 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +125 -5
- package/dist/index.d.ts +125 -5
- package/dist/index.js +225 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for the [Slicer](https://slicervm.com) VM control-plane API.
|
|
4
4
|
|
|
5
|
-
Mirrors the [Go SDK](https://github.com/slicervm/sdk) semantically. The top-level `SlicerClient` exposes `hostGroups`, `vms`, and `secrets` namespaces for control-plane operations; per-VM operations live on a `VM` handle returned from `client.vms.create()` / `client.vms.attach()`.
|
|
5
|
+
Mirrors the [Go SDK](https://github.com/slicervm/sdk) semantically. The top-level `SlicerClient` exposes `hostGroups`, `vms`, `commits`, and `secrets` namespaces for control-plane operations; per-VM operations live on a `VM` handle returned from `client.vms.create()` / `client.vms.attach()`.
|
|
6
6
|
|
|
7
7
|
Supports Unix socket and HTTP(S) transports.
|
|
8
8
|
|
|
@@ -33,6 +33,34 @@ for await (const f of vm.bg.logs(bg.execId, { follow: true })) {
|
|
|
33
33
|
await vm.delete();
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
## Cold forks
|
|
37
|
+
|
|
38
|
+
A stopped persistent VM can be committed as an immutable disk parent, then
|
|
39
|
+
forked into cold-booted children. Fork calls always wait until the child agent
|
|
40
|
+
has finalised its guest identity.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
await vm.shutdown();
|
|
44
|
+
const parent = await vm.commit({
|
|
45
|
+
tags: ['node-build'],
|
|
46
|
+
cacheKey: 'node-build-v1',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const child = await parent.fork({
|
|
50
|
+
waitTimeoutSec: 120,
|
|
51
|
+
network: { allow: [], drop: ['0.0.0.0/0'] },
|
|
52
|
+
tags: ['job=node-build'],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const description = await child.describe();
|
|
56
|
+
console.log(description.parentCommitId, description.network.effective);
|
|
57
|
+
|
|
58
|
+
const cached = await client.commits.list({ cacheKey: 'node-build-v1' });
|
|
59
|
+
await child.delete();
|
|
60
|
+
await vm.delete();
|
|
61
|
+
await client.commits.delete(parent.commitId);
|
|
62
|
+
```
|
|
63
|
+
|
|
36
64
|
## Status
|
|
37
65
|
|
|
38
66
|
Pre-release. See `ts-plan.md`.
|
package/dist/index.cjs
CHANGED
|
@@ -284,7 +284,71 @@ function agentHealthFromWire(w) {
|
|
|
284
284
|
...w.agent_uptime !== void 0 && { agentUptime: w.agent_uptime },
|
|
285
285
|
...w.agent_version !== void 0 && { agentVersion: w.agent_version },
|
|
286
286
|
...w.system_uptime !== void 0 && { systemUptime: w.system_uptime },
|
|
287
|
-
...w.userdata_ran !== void 0 && { userdataRan: w.userdata_ran }
|
|
287
|
+
...w.userdata_ran !== void 0 && { userdataRan: w.userdata_ran },
|
|
288
|
+
...w.userdata_exit_code !== void 0 && { userdataExitCode: w.userdata_exit_code }
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
function vmCommitFromWire(w) {
|
|
292
|
+
return {
|
|
293
|
+
hostname: w.hostname,
|
|
294
|
+
commitId: w.commit_id,
|
|
295
|
+
status: w.status,
|
|
296
|
+
...w.parent_status !== void 0 && { parentStatus: w.parent_status },
|
|
297
|
+
mode: w.mode ?? "",
|
|
298
|
+
...w.tags !== void 0 && { tags: w.tags },
|
|
299
|
+
...w.labels !== void 0 && { labels: w.labels },
|
|
300
|
+
...w.cache_key !== void 0 && { cacheKey: w.cache_key }
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function vmCommitInfoFromWire(w) {
|
|
304
|
+
return {
|
|
305
|
+
commitId: w.commit_id,
|
|
306
|
+
sourceHostname: w.source_hostname,
|
|
307
|
+
sourceHostGroup: w.source_host_group,
|
|
308
|
+
createdAt: w.created_at,
|
|
309
|
+
mode: w.mode,
|
|
310
|
+
...w.tags !== void 0 && { tags: w.tags },
|
|
311
|
+
...w.labels !== void 0 && { labels: w.labels },
|
|
312
|
+
...w.cache_key !== void 0 && { cacheKey: w.cache_key }
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function vmCommitDeleteFromWire(w) {
|
|
316
|
+
return { commitId: w.commit_id, status: w.status };
|
|
317
|
+
}
|
|
318
|
+
function vmForkFromWire(w) {
|
|
319
|
+
return {
|
|
320
|
+
hostname: w.hostname,
|
|
321
|
+
sourceHostname: w.source_hostname,
|
|
322
|
+
...w.commit_id !== void 0 && { commitId: w.commit_id },
|
|
323
|
+
status: w.status,
|
|
324
|
+
...w.parent_status !== void 0 && { parentStatus: w.parent_status },
|
|
325
|
+
...w.child_status !== void 0 && { childStatus: w.child_status },
|
|
326
|
+
mode: w.mode ?? ""
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function vmDescriptionFromWire(w) {
|
|
330
|
+
return {
|
|
331
|
+
hostname: w.hostname,
|
|
332
|
+
...w.hostgroup !== void 0 && { hostGroup: w.hostgroup },
|
|
333
|
+
...w.ip !== void 0 && { ip: w.ip },
|
|
334
|
+
...w.ram_bytes !== void 0 && { ramBytes: w.ram_bytes },
|
|
335
|
+
...w.cpus !== void 0 && { cpus: w.cpus },
|
|
336
|
+
...w.created_at !== void 0 && { createdAt: w.created_at },
|
|
337
|
+
...w.arch !== void 0 && { arch: w.arch },
|
|
338
|
+
...w.tags !== void 0 && { tags: w.tags },
|
|
339
|
+
...w.status !== void 0 && { status: w.status },
|
|
340
|
+
...w.persistent !== void 0 && { persistent: w.persistent },
|
|
341
|
+
...w.storage !== void 0 && { storage: w.storage },
|
|
342
|
+
...w.image !== void 0 && { image: w.image },
|
|
343
|
+
...w.commit_id !== void 0 && { commitId: w.commit_id },
|
|
344
|
+
...w.parent_commit_id !== void 0 && { parentCommitId: w.parent_commit_id },
|
|
345
|
+
network: {
|
|
346
|
+
...w.network.mode !== void 0 && { mode: w.network.mode },
|
|
347
|
+
...w.network.policy_source !== void 0 && { policySource: w.network.policy_source },
|
|
348
|
+
hostGroup: w.network.host_group,
|
|
349
|
+
...w.network.override !== void 0 && { override: w.network.override },
|
|
350
|
+
effective: w.network.effective
|
|
351
|
+
}
|
|
288
352
|
};
|
|
289
353
|
}
|
|
290
354
|
function fsEntryFromWire(w) {
|
|
@@ -739,6 +803,48 @@ var VMFileSystem = class {
|
|
|
739
803
|
);
|
|
740
804
|
}
|
|
741
805
|
};
|
|
806
|
+
var CommittedVM = class {
|
|
807
|
+
constructor(transport, hostGroup, response) {
|
|
808
|
+
this.transport = transport;
|
|
809
|
+
this.hostname = response.hostname;
|
|
810
|
+
this.hostGroup = hostGroup;
|
|
811
|
+
this.commitId = response.commitId;
|
|
812
|
+
this.status = response.status;
|
|
813
|
+
if (response.parentStatus !== void 0) this.parentStatus = response.parentStatus;
|
|
814
|
+
this.mode = response.mode;
|
|
815
|
+
if (response.tags !== void 0) this.tags = response.tags;
|
|
816
|
+
if (response.labels !== void 0) this.labels = response.labels;
|
|
817
|
+
if (response.cacheKey !== void 0) this.cacheKey = response.cacheKey;
|
|
818
|
+
}
|
|
819
|
+
transport;
|
|
820
|
+
hostname;
|
|
821
|
+
hostGroup;
|
|
822
|
+
commitId;
|
|
823
|
+
status;
|
|
824
|
+
parentStatus;
|
|
825
|
+
mode;
|
|
826
|
+
tags;
|
|
827
|
+
labels;
|
|
828
|
+
cacheKey;
|
|
829
|
+
async fork(opts = {}) {
|
|
830
|
+
const res = await forkPath(
|
|
831
|
+
this.transport,
|
|
832
|
+
this.commitId,
|
|
833
|
+
opts
|
|
834
|
+
);
|
|
835
|
+
return new VM(this.transport, {
|
|
836
|
+
hostname: res.hostname,
|
|
837
|
+
hostGroup: this.hostGroup
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
async forkRaw(opts = {}) {
|
|
841
|
+
return forkPath(
|
|
842
|
+
this.transport,
|
|
843
|
+
this.commitId,
|
|
844
|
+
opts
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
};
|
|
742
848
|
var VM = class {
|
|
743
849
|
hostname;
|
|
744
850
|
hostGroup;
|
|
@@ -778,6 +884,14 @@ var VM = class {
|
|
|
778
884
|
async logs() {
|
|
779
885
|
return this.transport.request("GET", `/vm/${encodeURIComponent(this.hostname)}/logs`);
|
|
780
886
|
}
|
|
887
|
+
/** Return configuration, fork lineage, and effective network policy. */
|
|
888
|
+
async describe() {
|
|
889
|
+
const wire = await this.transport.request(
|
|
890
|
+
"GET",
|
|
891
|
+
`/vm/${encodeURIComponent(this.hostname)}`
|
|
892
|
+
);
|
|
893
|
+
return vmDescriptionFromWire(wire);
|
|
894
|
+
}
|
|
781
895
|
async waitForAgent(opts = {}) {
|
|
782
896
|
const timeoutMs = opts.timeoutMs ?? 12e4;
|
|
783
897
|
const intervalMs = opts.intervalMs ?? 500;
|
|
@@ -804,10 +918,15 @@ var VM = class {
|
|
|
804
918
|
while (Date.now() < deadline) {
|
|
805
919
|
try {
|
|
806
920
|
last = await this.health();
|
|
807
|
-
if (last.userdataRan) return last;
|
|
808
921
|
} catch (err) {
|
|
809
922
|
lastErr = err;
|
|
810
923
|
}
|
|
924
|
+
if (last?.userdataRan) {
|
|
925
|
+
if (last.userdataExitCode !== void 0 && last.userdataExitCode !== 0) {
|
|
926
|
+
throw new Error(`userdata failed with exit code ${last.userdataExitCode}`);
|
|
927
|
+
}
|
|
928
|
+
return last;
|
|
929
|
+
}
|
|
811
930
|
await sleep(intervalMs);
|
|
812
931
|
}
|
|
813
932
|
throw new Error(
|
|
@@ -839,6 +958,25 @@ var VM = class {
|
|
|
839
958
|
async restore() {
|
|
840
959
|
await this.transport.request("POST", `/vm/${encodeURIComponent(this.hostname)}/restore`);
|
|
841
960
|
}
|
|
961
|
+
/**
|
|
962
|
+
* Commit a stopped persistent VM disk into an immutable parent.
|
|
963
|
+
*/
|
|
964
|
+
async commit(opts = {}) {
|
|
965
|
+
const cacheKey = opts.cacheKey?.trim();
|
|
966
|
+
const tags = opts.tags && opts.tags.length > 0 ? opts.tags : void 0;
|
|
967
|
+
const labels = opts.labels && Object.keys(opts.labels).length > 0 ? opts.labels : void 0;
|
|
968
|
+
const body = tags !== void 0 || labels !== void 0 || cacheKey ? {
|
|
969
|
+
...tags !== void 0 && { tags },
|
|
970
|
+
...labels !== void 0 && { labels },
|
|
971
|
+
...cacheKey && { cache_key: cacheKey }
|
|
972
|
+
} : void 0;
|
|
973
|
+
const wire = await this.transport.request(
|
|
974
|
+
"POST",
|
|
975
|
+
`/vm/${encodeURIComponent(this.hostname)}/commit`,
|
|
976
|
+
body
|
|
977
|
+
);
|
|
978
|
+
return new CommittedVM(this.transport, this.hostGroup, vmCommitFromWire(wire));
|
|
979
|
+
}
|
|
842
980
|
// --- port forwarding ---------------------------------------------------
|
|
843
981
|
/**
|
|
844
982
|
* Open one or more port forwards from the host to this VM. Each spec follows
|
|
@@ -958,6 +1096,32 @@ function sleep(ms) {
|
|
|
958
1096
|
function errMsg(e) {
|
|
959
1097
|
return e instanceof Error ? e.message : String(e);
|
|
960
1098
|
}
|
|
1099
|
+
async function forkPath(transport, commitId, opts) {
|
|
1100
|
+
const id = validateCommitId(commitId);
|
|
1101
|
+
const q = new URLSearchParams();
|
|
1102
|
+
q.set("wait", "agent");
|
|
1103
|
+
if (opts.waitTimeoutSec !== void 0 && opts.waitTimeoutSec > 0) {
|
|
1104
|
+
q.set("timeout", `${opts.waitTimeoutSec}s`);
|
|
1105
|
+
}
|
|
1106
|
+
const query = q.toString() ? `?${q.toString()}` : "";
|
|
1107
|
+
const body = opts.network !== void 0 || (opts.tags?.length ?? 0) > 0 ? {
|
|
1108
|
+
...opts.network !== void 0 && { network: opts.network },
|
|
1109
|
+
...(opts.tags?.length ?? 0) > 0 && { tags: opts.tags }
|
|
1110
|
+
} : void 0;
|
|
1111
|
+
const wire = await transport.request(
|
|
1112
|
+
"POST",
|
|
1113
|
+
`/vm/commits/${encodeURIComponent(id)}/fork${query}`,
|
|
1114
|
+
body
|
|
1115
|
+
);
|
|
1116
|
+
return vmForkFromWire(wire);
|
|
1117
|
+
}
|
|
1118
|
+
function validateCommitId(commitId) {
|
|
1119
|
+
const value = commitId.trim();
|
|
1120
|
+
if (!value || value === "." || value === ".." || value.includes("..") || value.includes("/") || value.includes("\\") || value.includes("\0")) {
|
|
1121
|
+
throw new Error(`invalid commit ID ${JSON.stringify(value)}`);
|
|
1122
|
+
}
|
|
1123
|
+
return value;
|
|
1124
|
+
}
|
|
961
1125
|
var VMBg = class {
|
|
962
1126
|
constructor(transport, hostname) {
|
|
963
1127
|
this.transport = transport;
|
|
@@ -1216,6 +1380,54 @@ var VMsAPI = class {
|
|
|
1216
1380
|
return createVMResFromWire(wire);
|
|
1217
1381
|
}
|
|
1218
1382
|
};
|
|
1383
|
+
var CommitsAPI = class {
|
|
1384
|
+
constructor(transport) {
|
|
1385
|
+
this.transport = transport;
|
|
1386
|
+
}
|
|
1387
|
+
transport;
|
|
1388
|
+
async list(opts = {}) {
|
|
1389
|
+
const qs = new URLSearchParams();
|
|
1390
|
+
for (const tag of opts.tags ?? []) {
|
|
1391
|
+
const value = tag.trim();
|
|
1392
|
+
if (value) qs.append("tag", value);
|
|
1393
|
+
}
|
|
1394
|
+
const cacheKey = opts.cacheKey?.trim();
|
|
1395
|
+
const source = opts.source?.trim();
|
|
1396
|
+
const mode = opts.mode?.trim();
|
|
1397
|
+
if (cacheKey) qs.set("cache_key", cacheKey);
|
|
1398
|
+
if (source) qs.set("source", source);
|
|
1399
|
+
if (mode) qs.set("mode", mode);
|
|
1400
|
+
const encoded = qs.toString();
|
|
1401
|
+
const query = encoded ? `?${encoded}` : "";
|
|
1402
|
+
const wire = await this.transport.request("GET", `/vm/commits${query}`);
|
|
1403
|
+
return (wire ?? []).map(vmCommitInfoFromWire);
|
|
1404
|
+
}
|
|
1405
|
+
async delete(commitId) {
|
|
1406
|
+
const id = validateCommitId2(commitId);
|
|
1407
|
+
const wire = await this.transport.request(
|
|
1408
|
+
"DELETE",
|
|
1409
|
+
`/vm/commits/${encodeURIComponent(id)}`
|
|
1410
|
+
);
|
|
1411
|
+
return vmCommitDeleteFromWire(wire);
|
|
1412
|
+
}
|
|
1413
|
+
async fork(commitId, opts = {}) {
|
|
1414
|
+
const id = validateCommitId2(commitId);
|
|
1415
|
+
const qs = new URLSearchParams({ wait: "agent" });
|
|
1416
|
+
if (opts.waitTimeoutSec !== void 0 && opts.waitTimeoutSec > 0) {
|
|
1417
|
+
qs.set("timeout", `${opts.waitTimeoutSec}s`);
|
|
1418
|
+
}
|
|
1419
|
+
const body = opts.network !== void 0 || (opts.tags?.length ?? 0) > 0 ? {
|
|
1420
|
+
...opts.network !== void 0 && { network: opts.network },
|
|
1421
|
+
...(opts.tags?.length ?? 0) > 0 && { tags: opts.tags }
|
|
1422
|
+
} : void 0;
|
|
1423
|
+
const wire = await this.transport.request(
|
|
1424
|
+
"POST",
|
|
1425
|
+
`/vm/commits/${encodeURIComponent(id)}/fork?${qs.toString()}`,
|
|
1426
|
+
body
|
|
1427
|
+
);
|
|
1428
|
+
return vmForkFromWire(wire);
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1219
1431
|
var SecretsAPI = class {
|
|
1220
1432
|
constructor(transport) {
|
|
1221
1433
|
this.transport = transport;
|
|
@@ -1262,10 +1474,18 @@ function buildListQuery(opts) {
|
|
|
1262
1474
|
const s = qs.toString();
|
|
1263
1475
|
return s ? `?${s}` : "";
|
|
1264
1476
|
}
|
|
1477
|
+
function validateCommitId2(commitId) {
|
|
1478
|
+
const value = commitId.trim();
|
|
1479
|
+
if (!value || value === "." || value === ".." || value.includes("..") || value.includes("/") || value.includes("\\") || value.includes("\0")) {
|
|
1480
|
+
throw new Error(`invalid commit ID ${JSON.stringify(value)}`);
|
|
1481
|
+
}
|
|
1482
|
+
return value;
|
|
1483
|
+
}
|
|
1265
1484
|
|
|
1266
1485
|
// src/proxy.ts
|
|
1267
1486
|
var ProxySecretBearer = "bearer";
|
|
1268
1487
|
var ProxySecretBasic = "basic";
|
|
1488
|
+
var ProxySecretOAuthClientCredentials = "oauth-client-creds";
|
|
1269
1489
|
function clientFromWire(w) {
|
|
1270
1490
|
return { name: w.name, createdAt: w.created_at };
|
|
1271
1491
|
}
|
|
@@ -1422,12 +1642,14 @@ var SlicerClient = class _SlicerClient {
|
|
|
1422
1642
|
transport;
|
|
1423
1643
|
hostGroups;
|
|
1424
1644
|
vms;
|
|
1645
|
+
commits;
|
|
1425
1646
|
secrets;
|
|
1426
1647
|
proxy;
|
|
1427
1648
|
constructor(opts) {
|
|
1428
1649
|
this.transport = new TransportClient(opts);
|
|
1429
1650
|
this.hostGroups = new HostGroupsAPI(this.transport);
|
|
1430
1651
|
this.vms = new VMsAPI(this.transport);
|
|
1652
|
+
this.commits = new CommitsAPI(this.transport);
|
|
1431
1653
|
this.secrets = new SecretsAPI(this.transport);
|
|
1432
1654
|
this.proxy = new ProxyAPI(this.transport);
|
|
1433
1655
|
}
|
|
@@ -1586,6 +1808,8 @@ var SlicerShellSession = class {
|
|
|
1586
1808
|
}
|
|
1587
1809
|
};
|
|
1588
1810
|
|
|
1811
|
+
exports.CommitsAPI = CommitsAPI;
|
|
1812
|
+
exports.CommittedVM = CommittedVM;
|
|
1589
1813
|
exports.ExecStdioBase64 = ExecStdioBase64;
|
|
1590
1814
|
exports.ExecStdioText = ExecStdioText;
|
|
1591
1815
|
exports.FRAME_TYPE_DATA = FRAME_TYPE_DATA;
|
|
@@ -1603,6 +1827,7 @@ exports.ProxyAllowsAPI = ProxyAllowsAPI;
|
|
|
1603
1827
|
exports.ProxyClientsAPI = ProxyClientsAPI;
|
|
1604
1828
|
exports.ProxySecretBasic = ProxySecretBasic;
|
|
1605
1829
|
exports.ProxySecretBearer = ProxySecretBearer;
|
|
1830
|
+
exports.ProxySecretOAuthClientCredentials = ProxySecretOAuthClientCredentials;
|
|
1606
1831
|
exports.ProxySecretsAPI = ProxySecretsAPI;
|
|
1607
1832
|
exports.SecretExistsError = SecretExistsError;
|
|
1608
1833
|
exports.SecretsAPI = SecretsAPI;
|