@slicervm/sdk 0.1.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.
@@ -0,0 +1,424 @@
1
+ import { IncomingMessage } from 'node:http';
2
+ import { Readable } from 'node:stream';
3
+ import { URL } from 'node:url';
4
+
5
+ /**
6
+ * Slicer API types. Wire shapes mirror the Go SDK at github.com/slicervm/sdk
7
+ * (which calls these "Node" / "SlicerNode"); the TS SDK renames to "VM" for
8
+ * clarity, since Slicer's primary primitive is a VM.
9
+ */
10
+ interface HostGroup {
11
+ name: string;
12
+ count: number;
13
+ ramBytes: number;
14
+ cpus: number;
15
+ arch: string;
16
+ gpuCount?: number;
17
+ }
18
+ interface VMInfo {
19
+ hostname: string;
20
+ hostGroup?: string;
21
+ ip: string;
22
+ ramBytes?: number;
23
+ cpus?: number;
24
+ createdAt: string;
25
+ arch?: string;
26
+ tags?: string[];
27
+ status?: string;
28
+ persistent?: boolean;
29
+ }
30
+ interface CreateVMRequest {
31
+ ramBytes?: number;
32
+ cpus?: number;
33
+ gpuCount?: number;
34
+ persistent?: boolean;
35
+ diskImage?: string;
36
+ importUser?: string;
37
+ sshKeys?: string[];
38
+ userdata?: string;
39
+ ip?: string;
40
+ tags?: string[];
41
+ secrets?: string[];
42
+ }
43
+ interface CreateVMResponse {
44
+ hostname: string;
45
+ hostGroup?: string;
46
+ ip: string;
47
+ createdAt: string;
48
+ arch?: string;
49
+ }
50
+ interface AgentHealth {
51
+ hostname?: string;
52
+ agentUptime?: number;
53
+ agentVersion?: string;
54
+ systemUptime?: number;
55
+ userdataRan?: boolean;
56
+ }
57
+ interface VMLogs {
58
+ hostname: string;
59
+ lines: number;
60
+ content: string;
61
+ }
62
+ interface DeleteResponse {
63
+ message?: string;
64
+ diskRemoved?: string;
65
+ error?: string;
66
+ }
67
+ /** Wire encoding of exec stdout/stderr. Defaults to `"text"`. */
68
+ type ExecStdio = 'text' | 'base64';
69
+ declare const ExecStdioText: ExecStdio;
70
+ declare const ExecStdioBase64: ExecStdio;
71
+ interface ExecRequest {
72
+ command?: string;
73
+ args?: string[];
74
+ env?: string[];
75
+ uid?: number;
76
+ gid?: number;
77
+ stdin?: Buffer | string;
78
+ shell?: string;
79
+ cwd?: string;
80
+ permissions?: string;
81
+ /**
82
+ * Wire encoding for stdout/stderr.
83
+ * - `"text"` (default): frames carry UTF-8 strings. Safe for text output only —
84
+ * arbitrary binary will be mangled by JSON string escaping.
85
+ * - `"base64"`: frames carry base64-encoded bytes. Required for binary output
86
+ * (video, compressed archives, raw protocol streams). The SDK decodes
87
+ * automatically — callers get `Buffer` on `execBuffered({ stdio: 'base64' })`
88
+ * and `{stdoutBytes, stderrBytes, dataBytes}` on streamed frames.
89
+ */
90
+ stdio?: ExecStdio;
91
+ }
92
+ interface ExecFrame {
93
+ timestamp?: string;
94
+ type?: string;
95
+ pid?: number;
96
+ encoding?: ExecStdio;
97
+ /** Raw wire value — string under text mode, base64 string under base64 mode. */
98
+ data?: string;
99
+ startedAt?: string;
100
+ endedAt?: string;
101
+ signal?: string;
102
+ stdout?: string;
103
+ stderr?: string;
104
+ /** Decoded bytes when `encoding === 'base64'`. SDK-populated convenience field. */
105
+ dataBytes?: Buffer;
106
+ stdoutBytes?: Buffer;
107
+ stderrBytes?: Buffer;
108
+ exitCode?: number;
109
+ error?: string;
110
+ }
111
+ interface ExecResult {
112
+ stdout: string;
113
+ stderr: string;
114
+ encoding?: ExecStdio;
115
+ pid?: number;
116
+ startedAt?: string;
117
+ endedAt?: string;
118
+ signal?: string;
119
+ exitCode: number;
120
+ error?: string;
121
+ }
122
+ /** Returned by `execBuffered` when `stdio === 'base64'`. stdout/stderr are decoded Buffers. */
123
+ interface ExecResultBinary {
124
+ stdout: Buffer;
125
+ stderr: Buffer;
126
+ encoding: 'base64';
127
+ pid?: number;
128
+ startedAt?: string;
129
+ endedAt?: string;
130
+ signal?: string;
131
+ exitCode: number;
132
+ error?: string;
133
+ }
134
+ interface FSEntry {
135
+ name: string;
136
+ type: 'file' | 'directory' | 'symlink' | string;
137
+ size: number;
138
+ mtime: string;
139
+ mode: string;
140
+ }
141
+ interface FSMkdirRequest {
142
+ path: string;
143
+ recursive?: boolean;
144
+ mode?: string;
145
+ }
146
+ interface ShutdownRequest {
147
+ action?: 'shutdown' | 'reboot';
148
+ }
149
+ interface VMStat {
150
+ hostname: string;
151
+ ip: string;
152
+ createdAt: string;
153
+ snapshot?: VMSnapshot | null;
154
+ error?: string;
155
+ }
156
+ interface VMSnapshot {
157
+ hostname: string;
158
+ arch: string;
159
+ timestamp: string;
160
+ uptime: string;
161
+ totalCpus: number;
162
+ totalMemory: number;
163
+ memoryUsed: number;
164
+ memoryAvailable: number;
165
+ memoryUsedPercent: number;
166
+ loadAvg1: number;
167
+ loadAvg5: number;
168
+ loadAvg15: number;
169
+ diskReadTotal: number;
170
+ diskWriteTotal: number;
171
+ networkReadTotal: number;
172
+ networkWriteTotal: number;
173
+ diskIOInflight: number;
174
+ openConnections: number;
175
+ openFiles: number;
176
+ entropy: number;
177
+ diskSpaceTotal: number;
178
+ diskSpaceUsed: number;
179
+ diskSpaceFree: number;
180
+ diskSpaceUsedPercent: number;
181
+ }
182
+ interface SlicerInfo {
183
+ version?: string;
184
+ gitCommit?: string;
185
+ platform?: string;
186
+ arch?: string;
187
+ }
188
+ interface ListOptions {
189
+ tag?: string;
190
+ tagPrefix?: string;
191
+ }
192
+ interface WaitOptions {
193
+ timeoutMs?: number;
194
+ intervalMs?: number;
195
+ }
196
+ interface CreateVMOptions {
197
+ /**
198
+ * Server-side wait: `"agent"` waits for the in-guest agent to be ready,
199
+ * `"userdata"` additionally waits for userdata to run. If unset the daemon
200
+ * returns immediately once the VM is scheduled.
201
+ */
202
+ wait?: 'agent' | 'userdata';
203
+ /** Server-side wait timeout, in seconds. Forwarded as a Go duration. */
204
+ waitTimeoutSec?: number;
205
+ }
206
+ interface Secret {
207
+ name: string;
208
+ size: number;
209
+ permissions: string;
210
+ uid?: number;
211
+ gid?: number;
212
+ modifiedAt?: string;
213
+ }
214
+ interface CreateSecretRequest {
215
+ name: string;
216
+ data: string;
217
+ permissions?: string;
218
+ uid?: number;
219
+ gid?: number;
220
+ }
221
+ interface UpdateSecretRequest {
222
+ data: string;
223
+ permissions?: string;
224
+ uid?: number;
225
+ gid?: number;
226
+ }
227
+ declare class SecretExistsError extends Error {
228
+ constructor(name: string);
229
+ }
230
+ declare class SlicerAPIError extends Error {
231
+ readonly status: number;
232
+ readonly method: string;
233
+ readonly path: string;
234
+ readonly body: string;
235
+ constructor(method: string, path: string, status: number, body: string);
236
+ }
237
+ declare const MiB: (n: number) => number;
238
+ declare const GiB: (n: number) => number;
239
+ declare const NonRootUser = 4294967295;
240
+
241
+ /**
242
+ * HTTP transport for the Slicer API. Supports two modes:
243
+ * - Unix socket: absolute path (`/...`), `unix://...`, `./...`, `../...`, `~/...`, or any `*.sock`.
244
+ * - Network URL: `http://host[:port]` or `https://host`.
245
+ *
246
+ * Mirrors the detection rules in the Go SDK's `normalizeUnixSocketPath`.
247
+ */
248
+
249
+ type Transport = {
250
+ kind: 'socket';
251
+ socketPath: string;
252
+ } | {
253
+ kind: 'net';
254
+ url: URL;
255
+ };
256
+ declare function resolveTransport(baseURL: string): Transport;
257
+ interface TransportClientOptions {
258
+ baseURL: string;
259
+ token?: string;
260
+ userAgent?: string;
261
+ }
262
+ declare class TransportClient {
263
+ readonly transport: Transport;
264
+ private readonly token?;
265
+ private readonly userAgent;
266
+ constructor(opts: TransportClientOptions);
267
+ private agent;
268
+ private buildRequestOptions;
269
+ /** Buffered JSON request. Rejects on non-2xx via SlicerAPIError. */
270
+ request<T = unknown>(method: string, reqPath: string, body?: unknown): Promise<T>;
271
+ /** Raw-bytes request (for binary cp endpoints). */
272
+ requestRaw(method: string, reqPath: string, body?: Buffer, contentType?: string): Promise<Buffer>;
273
+ /** Streaming request producing a Node Readable of the response body. */
274
+ requestStreamRaw(method: string, reqPath: string, body?: Buffer | Readable, contentType?: string): Promise<IncomingMessage>;
275
+ /** Yields decoded JSON frames from an NDJSON response (one JSON object per line). */
276
+ requestNDJSON<Frame = unknown>(method: string, reqPath: string, body?: Buffer | Readable): AsyncGenerator<Frame, void, void>;
277
+ }
278
+
279
+ /**
280
+ * VM handle — returned from `client.vms.create()` / `client.vms.get()`.
281
+ * Exposes per-VM operations (exec, fs, power, lifecycle).
282
+ */
283
+
284
+ /** Per-VM filesystem operations. */
285
+ declare class VMFileSystem {
286
+ private readonly transport;
287
+ private readonly hostname;
288
+ constructor(transport: TransportClient, hostname: string);
289
+ readDir(path: string): Promise<FSEntry[]>;
290
+ stat(path: string): Promise<FSEntry | null>;
291
+ exists(path: string): Promise<boolean>;
292
+ mkdir(req: FSMkdirRequest): Promise<void>;
293
+ remove(path: string, recursive?: boolean): Promise<void>;
294
+ readFile(path: string): Promise<Buffer>;
295
+ writeFile(path: string, content: Buffer | string, opts?: {
296
+ uid?: number;
297
+ gid?: number;
298
+ permissions?: string;
299
+ }): Promise<void>;
300
+ /** Upload a tar archive, expanded into the VM at `path`. */
301
+ tarTo(path: string, tar: Buffer | Readable): Promise<void>;
302
+ /** Download `path` from the VM as a tar archive. */
303
+ tarFrom(path: string): Promise<Buffer>;
304
+ }
305
+ interface VMInit {
306
+ hostname: string;
307
+ hostGroup: string;
308
+ ip?: string;
309
+ createdAt?: string;
310
+ arch?: string;
311
+ }
312
+ declare class VM {
313
+ readonly hostname: string;
314
+ readonly hostGroup: string;
315
+ readonly ip?: string;
316
+ readonly createdAt?: string;
317
+ readonly arch?: string;
318
+ readonly fs: VMFileSystem;
319
+ private readonly transport;
320
+ constructor(transport: TransportClient, init: VMInit);
321
+ delete(): Promise<void>;
322
+ health(): Promise<AgentHealth>;
323
+ logs(): Promise<VMLogs>;
324
+ waitForAgent(opts?: WaitOptions): Promise<AgentHealth>;
325
+ waitForUserdata(opts?: WaitOptions): Promise<AgentHealth>;
326
+ shutdown(req?: ShutdownRequest): Promise<void>;
327
+ pause(): Promise<void>;
328
+ resume(): Promise<void>;
329
+ relaunch(): Promise<void>;
330
+ /** Mac-only on current daemons. Throws `SlicerAPIError 404` on Linux. */
331
+ suspend(): Promise<void>;
332
+ /** Mac-only on current daemons. Throws `SlicerAPIError 404` on Linux. */
333
+ restore(): Promise<void>;
334
+ /**
335
+ * Streaming exec — yields NDJSON frames (`started`, `stdout`, `stderr`, `exit`).
336
+ * When `req.stdio === 'base64'`, each frame's `data`/`stdout`/`stderr` string
337
+ * fields are preserved as-is (base64-encoded) and the SDK populates decoded
338
+ * `dataBytes`/`stdoutBytes`/`stderrBytes` Buffers alongside for convenience.
339
+ */
340
+ exec(req: ExecRequest): AsyncGenerator<ExecFrame, void, void>;
341
+ /**
342
+ * Buffered exec via `?buffered=true`. stdin is intentionally unsupported
343
+ * (matches Go SDK `ExecBuffered`); use `exec()` for stdin cases.
344
+ *
345
+ * When `req.stdio === 'base64'`, stdout/stderr are decoded from base64 and
346
+ * returned as `Buffer` — use this for binary output. Otherwise the result
347
+ * carries UTF-8 strings.
348
+ */
349
+ execBuffered(req: ExecRequest & {
350
+ stdio: 'base64';
351
+ }): Promise<ExecResultBinary>;
352
+ execBuffered(req: ExecRequest): Promise<ExecResult>;
353
+ }
354
+
355
+ /**
356
+ * Top-level namespaces on SlicerClient: hostGroups, vms, secrets.
357
+ * Keep control-plane operations here; per-VM operations live on the VM handle.
358
+ */
359
+
360
+ declare class HostGroupsAPI {
361
+ private readonly transport;
362
+ constructor(transport: TransportClient);
363
+ list(): Promise<HostGroup[]>;
364
+ /** Convenience lookup (no single-group endpoint exists on the daemon). */
365
+ find(name: string): Promise<HostGroup | undefined>;
366
+ listVMs(name: string, opts?: ListOptions): Promise<VMInfo[]>;
367
+ }
368
+ declare class VMsAPI {
369
+ private readonly transport;
370
+ constructor(transport: TransportClient);
371
+ create(hostGroup: string, req?: CreateVMRequest, opts?: CreateVMOptions): Promise<VM>;
372
+ /**
373
+ * Build a VM handle for an existing VM given its hostgroup + hostname. No
374
+ * request is issued — use `health()` or `getInfo()` to verify reachability.
375
+ */
376
+ attach(hostGroup: string, hostname: string): VM;
377
+ /** Look up a VM by hostname across all host groups. Returns `undefined` if not found. */
378
+ get(hostname: string): Promise<VM | undefined>;
379
+ /** Return raw VM metadata across all host groups. */
380
+ list(opts?: ListOptions): Promise<VMInfo[]>;
381
+ stats(): Promise<VMStat[]>;
382
+ /**
383
+ * Raw response accessor — bypasses the VM handle. Useful when you only
384
+ * want the create metadata without a handle.
385
+ */
386
+ createRaw(hostGroup: string, req?: CreateVMRequest, opts?: CreateVMOptions): Promise<CreateVMResponse>;
387
+ }
388
+ declare class SecretsAPI {
389
+ private readonly transport;
390
+ constructor(transport: TransportClient);
391
+ list(): Promise<Secret[]>;
392
+ create(req: CreateSecretRequest): Promise<void>;
393
+ patch(name: string, req: UpdateSecretRequest): Promise<void>;
394
+ delete(name: string): Promise<void>;
395
+ }
396
+
397
+ /**
398
+ * SlicerClient — grouped TypeScript client for the Slicer VM API.
399
+ *
400
+ * Shape:
401
+ * client.hostGroups.list() / find(name) / listVMs(name)
402
+ * client.vms.create(group, req, opts) → VM / get(name) / list() / stats() / attach(group, name)
403
+ * client.secrets.list / create / patch / delete
404
+ * client.getInfo()
405
+ *
406
+ * Per-VM operations live on the `VM` handle returned from `client.vms.create`
407
+ * or `client.vms.attach`: `vm.exec`, `vm.execBuffered`, `vm.fs.*`,
408
+ * `vm.pause/resume/suspend/restore/shutdown/relaunch`, `vm.health/logs`,
409
+ * `vm.waitForAgent/waitForUserdata`, `vm.delete`.
410
+ */
411
+
412
+ interface SlicerClientOptions extends TransportClientOptions {
413
+ }
414
+ declare class SlicerClient {
415
+ readonly transport: TransportClient;
416
+ readonly hostGroups: HostGroupsAPI;
417
+ readonly vms: VMsAPI;
418
+ readonly secrets: SecretsAPI;
419
+ constructor(opts: SlicerClientOptions);
420
+ static fromEnv(overrides?: Partial<SlicerClientOptions>): SlicerClient;
421
+ getInfo(): Promise<SlicerInfo>;
422
+ }
423
+
424
+ export { type AgentHealth, type CreateSecretRequest, type CreateVMOptions, type CreateVMRequest, type CreateVMResponse, type DeleteResponse, type ExecFrame, type ExecRequest, type ExecResult, type ExecResultBinary, type ExecStdio, ExecStdioBase64, ExecStdioText, type FSEntry, type FSMkdirRequest, GiB, type HostGroup, HostGroupsAPI, type ListOptions, MiB, NonRootUser, type Secret, SecretExistsError, SecretsAPI, type ShutdownRequest, SlicerAPIError, SlicerClient, type SlicerClientOptions, type SlicerInfo, type UpdateSecretRequest, VM, VMFileSystem, type VMInfo, type VMInit, type VMLogs, type VMSnapshot, type VMStat, VMsAPI, type WaitOptions, resolveTransport };