@slicervm/sdk 0.1.2 → 0.1.4
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.cjs +99 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.js +99 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -143,6 +143,42 @@ interface FSMkdirRequest {
|
|
|
143
143
|
recursive?: boolean;
|
|
144
144
|
mode?: string;
|
|
145
145
|
}
|
|
146
|
+
type FSWatchEventType = 'create' | 'write' | 'remove' | 'rename' | 'chmod';
|
|
147
|
+
interface FSWatchRequest {
|
|
148
|
+
/** Absolute paths inside the VM to watch. At least one is required. */
|
|
149
|
+
paths: string[];
|
|
150
|
+
/** Optional glob patterns to filter event paths (e.g. `["*.go", "bin/*"]`). */
|
|
151
|
+
patterns?: string[];
|
|
152
|
+
/**
|
|
153
|
+
* Restrict to a subset of event types. When omitted, all types are delivered.
|
|
154
|
+
*/
|
|
155
|
+
events?: FSWatchEventType[];
|
|
156
|
+
/** UID used by the agent to resolve `~` in paths. Default: 0 (root). */
|
|
157
|
+
uid?: number;
|
|
158
|
+
/** Watch directories recursively. */
|
|
159
|
+
recursive?: boolean;
|
|
160
|
+
/** Stop the stream after the first matching event. */
|
|
161
|
+
oneShot?: boolean;
|
|
162
|
+
/** Coalesce events arriving within this window. Go-duration string e.g. `"100ms"`. */
|
|
163
|
+
debounce?: string;
|
|
164
|
+
/** Server-side wall-clock cap on the stream. Go-duration string e.g. `"5m"`. */
|
|
165
|
+
timeout?: string;
|
|
166
|
+
/** Stop after delivering this many events. */
|
|
167
|
+
maxEvents?: number;
|
|
168
|
+
/** Forwarded as the SSE `Last-Event-ID` header for cross-connection resume. */
|
|
169
|
+
lastEventId?: string;
|
|
170
|
+
}
|
|
171
|
+
interface FSWatchEvent {
|
|
172
|
+
/** Monotonic per-stream ID (from the SSE `id:` line). */
|
|
173
|
+
id: number;
|
|
174
|
+
type: FSWatchEventType | string;
|
|
175
|
+
path: string;
|
|
176
|
+
/** RFC3339Nano string (when present). */
|
|
177
|
+
timestamp: string;
|
|
178
|
+
size: number;
|
|
179
|
+
isDir: boolean;
|
|
180
|
+
message?: string;
|
|
181
|
+
}
|
|
146
182
|
interface ShutdownRequest {
|
|
147
183
|
action?: 'shutdown' | 'reboot';
|
|
148
184
|
}
|
|
@@ -271,7 +307,7 @@ declare class TransportClient {
|
|
|
271
307
|
/** Raw-bytes request (for binary cp endpoints). */
|
|
272
308
|
requestRaw(method: string, reqPath: string, body?: Buffer, contentType?: string): Promise<Buffer>;
|
|
273
309
|
/** Streaming request producing a Node Readable of the response body. */
|
|
274
|
-
requestStreamRaw(method: string, reqPath: string, body?: Buffer | Readable, contentType?: string): Promise<IncomingMessage>;
|
|
310
|
+
requestStreamRaw(method: string, reqPath: string, body?: Buffer | Readable, contentType?: string, extraHeaders?: Record<string, string>): Promise<IncomingMessage>;
|
|
275
311
|
/** Yields decoded JSON frames from an NDJSON response (one JSON object per line). */
|
|
276
312
|
requestNDJSON<Frame = unknown>(method: string, reqPath: string, body?: Buffer | Readable): AsyncGenerator<Frame, void, void>;
|
|
277
313
|
}
|
|
@@ -387,6 +423,22 @@ declare class VMFileSystem {
|
|
|
387
423
|
}): Promise<void>;
|
|
388
424
|
/** Upload a tar archive, expanded into the VM at `path`. */
|
|
389
425
|
tarTo(path: string, tar: Buffer | Readable): Promise<void>;
|
|
426
|
+
/**
|
|
427
|
+
* Open a Server-Sent Events stream of filesystem events from the VM.
|
|
428
|
+
* Yields one `FSWatchEvent` per agent-side event. The stream stays open
|
|
429
|
+
* until the supplied request's `timeout` / `maxEvents` is hit, the daemon
|
|
430
|
+
* tears it down, or the caller breaks out of the loop.
|
|
431
|
+
*
|
|
432
|
+
* Heartbeat SSE comments and named `event:` lines are silently dropped.
|
|
433
|
+
*
|
|
434
|
+
* Example:
|
|
435
|
+
* ```ts
|
|
436
|
+
* for await (const e of vm.fs.watch({ paths: ['/tmp'], recursive: true })) {
|
|
437
|
+
* console.log(e.type, e.path);
|
|
438
|
+
* }
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
watch(req: FSWatchRequest): AsyncGenerator<FSWatchEvent, void, void>;
|
|
390
442
|
/** Download `path` from the VM as a tar archive. */
|
|
391
443
|
tarFrom(path: string): Promise<Buffer>;
|
|
392
444
|
}
|
|
@@ -523,4 +575,4 @@ declare class SlicerClient {
|
|
|
523
575
|
getInfo(): Promise<SlicerInfo>;
|
|
524
576
|
}
|
|
525
577
|
|
|
526
|
-
export { type AddressMapping, 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, Forwarder, type ForwarderListener, type ForwarderOptions, 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, parseAddressMapping, resolveTransport };
|
|
578
|
+
export { type AddressMapping, 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, type FSWatchEvent, type FSWatchEventType, type FSWatchRequest, Forwarder, type ForwarderListener, type ForwarderOptions, 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, parseAddressMapping, resolveTransport };
|
package/dist/index.d.ts
CHANGED
|
@@ -143,6 +143,42 @@ interface FSMkdirRequest {
|
|
|
143
143
|
recursive?: boolean;
|
|
144
144
|
mode?: string;
|
|
145
145
|
}
|
|
146
|
+
type FSWatchEventType = 'create' | 'write' | 'remove' | 'rename' | 'chmod';
|
|
147
|
+
interface FSWatchRequest {
|
|
148
|
+
/** Absolute paths inside the VM to watch. At least one is required. */
|
|
149
|
+
paths: string[];
|
|
150
|
+
/** Optional glob patterns to filter event paths (e.g. `["*.go", "bin/*"]`). */
|
|
151
|
+
patterns?: string[];
|
|
152
|
+
/**
|
|
153
|
+
* Restrict to a subset of event types. When omitted, all types are delivered.
|
|
154
|
+
*/
|
|
155
|
+
events?: FSWatchEventType[];
|
|
156
|
+
/** UID used by the agent to resolve `~` in paths. Default: 0 (root). */
|
|
157
|
+
uid?: number;
|
|
158
|
+
/** Watch directories recursively. */
|
|
159
|
+
recursive?: boolean;
|
|
160
|
+
/** Stop the stream after the first matching event. */
|
|
161
|
+
oneShot?: boolean;
|
|
162
|
+
/** Coalesce events arriving within this window. Go-duration string e.g. `"100ms"`. */
|
|
163
|
+
debounce?: string;
|
|
164
|
+
/** Server-side wall-clock cap on the stream. Go-duration string e.g. `"5m"`. */
|
|
165
|
+
timeout?: string;
|
|
166
|
+
/** Stop after delivering this many events. */
|
|
167
|
+
maxEvents?: number;
|
|
168
|
+
/** Forwarded as the SSE `Last-Event-ID` header for cross-connection resume. */
|
|
169
|
+
lastEventId?: string;
|
|
170
|
+
}
|
|
171
|
+
interface FSWatchEvent {
|
|
172
|
+
/** Monotonic per-stream ID (from the SSE `id:` line). */
|
|
173
|
+
id: number;
|
|
174
|
+
type: FSWatchEventType | string;
|
|
175
|
+
path: string;
|
|
176
|
+
/** RFC3339Nano string (when present). */
|
|
177
|
+
timestamp: string;
|
|
178
|
+
size: number;
|
|
179
|
+
isDir: boolean;
|
|
180
|
+
message?: string;
|
|
181
|
+
}
|
|
146
182
|
interface ShutdownRequest {
|
|
147
183
|
action?: 'shutdown' | 'reboot';
|
|
148
184
|
}
|
|
@@ -271,7 +307,7 @@ declare class TransportClient {
|
|
|
271
307
|
/** Raw-bytes request (for binary cp endpoints). */
|
|
272
308
|
requestRaw(method: string, reqPath: string, body?: Buffer, contentType?: string): Promise<Buffer>;
|
|
273
309
|
/** Streaming request producing a Node Readable of the response body. */
|
|
274
|
-
requestStreamRaw(method: string, reqPath: string, body?: Buffer | Readable, contentType?: string): Promise<IncomingMessage>;
|
|
310
|
+
requestStreamRaw(method: string, reqPath: string, body?: Buffer | Readable, contentType?: string, extraHeaders?: Record<string, string>): Promise<IncomingMessage>;
|
|
275
311
|
/** Yields decoded JSON frames from an NDJSON response (one JSON object per line). */
|
|
276
312
|
requestNDJSON<Frame = unknown>(method: string, reqPath: string, body?: Buffer | Readable): AsyncGenerator<Frame, void, void>;
|
|
277
313
|
}
|
|
@@ -387,6 +423,22 @@ declare class VMFileSystem {
|
|
|
387
423
|
}): Promise<void>;
|
|
388
424
|
/** Upload a tar archive, expanded into the VM at `path`. */
|
|
389
425
|
tarTo(path: string, tar: Buffer | Readable): Promise<void>;
|
|
426
|
+
/**
|
|
427
|
+
* Open a Server-Sent Events stream of filesystem events from the VM.
|
|
428
|
+
* Yields one `FSWatchEvent` per agent-side event. The stream stays open
|
|
429
|
+
* until the supplied request's `timeout` / `maxEvents` is hit, the daemon
|
|
430
|
+
* tears it down, or the caller breaks out of the loop.
|
|
431
|
+
*
|
|
432
|
+
* Heartbeat SSE comments and named `event:` lines are silently dropped.
|
|
433
|
+
*
|
|
434
|
+
* Example:
|
|
435
|
+
* ```ts
|
|
436
|
+
* for await (const e of vm.fs.watch({ paths: ['/tmp'], recursive: true })) {
|
|
437
|
+
* console.log(e.type, e.path);
|
|
438
|
+
* }
|
|
439
|
+
* ```
|
|
440
|
+
*/
|
|
441
|
+
watch(req: FSWatchRequest): AsyncGenerator<FSWatchEvent, void, void>;
|
|
390
442
|
/** Download `path` from the VM as a tar archive. */
|
|
391
443
|
tarFrom(path: string): Promise<Buffer>;
|
|
392
444
|
}
|
|
@@ -523,4 +575,4 @@ declare class SlicerClient {
|
|
|
523
575
|
getInfo(): Promise<SlicerInfo>;
|
|
524
576
|
}
|
|
525
577
|
|
|
526
|
-
export { type AddressMapping, 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, Forwarder, type ForwarderListener, type ForwarderOptions, 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, parseAddressMapping, resolveTransport };
|
|
578
|
+
export { type AddressMapping, 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, type FSWatchEvent, type FSWatchEventType, type FSWatchRequest, Forwarder, type ForwarderListener, type ForwarderOptions, 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, parseAddressMapping, resolveTransport };
|
package/dist/index.js
CHANGED
|
@@ -150,9 +150,9 @@ var TransportClient = class {
|
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
/** Streaming request producing a Node Readable of the response body. */
|
|
153
|
-
requestStreamRaw(method, reqPath, body, contentType = "application/octet-stream") {
|
|
153
|
+
requestStreamRaw(method, reqPath, body, contentType = "application/octet-stream", extraHeaders = {}) {
|
|
154
154
|
return new Promise((resolve, reject) => {
|
|
155
|
-
const headers = {};
|
|
155
|
+
const headers = { ...extraHeaders };
|
|
156
156
|
if (body instanceof Buffer) {
|
|
157
157
|
headers["Content-Type"] = contentType;
|
|
158
158
|
headers["Content-Length"] = String(body.length);
|
|
@@ -639,6 +639,85 @@ var VMFileSystem = class {
|
|
|
639
639
|
);
|
|
640
640
|
for await (const _ of res) void _;
|
|
641
641
|
}
|
|
642
|
+
/**
|
|
643
|
+
* Open a Server-Sent Events stream of filesystem events from the VM.
|
|
644
|
+
* Yields one `FSWatchEvent` per agent-side event. The stream stays open
|
|
645
|
+
* until the supplied request's `timeout` / `maxEvents` is hit, the daemon
|
|
646
|
+
* tears it down, or the caller breaks out of the loop.
|
|
647
|
+
*
|
|
648
|
+
* Heartbeat SSE comments and named `event:` lines are silently dropped.
|
|
649
|
+
*
|
|
650
|
+
* Example:
|
|
651
|
+
* ```ts
|
|
652
|
+
* for await (const e of vm.fs.watch({ paths: ['/tmp'], recursive: true })) {
|
|
653
|
+
* console.log(e.type, e.path);
|
|
654
|
+
* }
|
|
655
|
+
* ```
|
|
656
|
+
*/
|
|
657
|
+
async *watch(req) {
|
|
658
|
+
if (!req.paths || req.paths.length === 0) {
|
|
659
|
+
throw new Error("vm.fs.watch: paths is required");
|
|
660
|
+
}
|
|
661
|
+
const q = new URLSearchParams();
|
|
662
|
+
for (const p of req.paths) if (p) q.append("paths", p);
|
|
663
|
+
for (const p of req.patterns ?? []) if (p) q.append("patterns", p);
|
|
664
|
+
for (const e of req.events ?? []) if (e) q.append("events", e);
|
|
665
|
+
if (req.uid !== void 0 && req.uid !== 0) q.set("uid", String(req.uid));
|
|
666
|
+
if (req.recursive) q.set("recursive", "true");
|
|
667
|
+
if (req.oneShot) q.set("one_shot", "true");
|
|
668
|
+
if (req.debounce) q.set("debounce", req.debounce);
|
|
669
|
+
if (req.timeout) q.set("timeout", req.timeout);
|
|
670
|
+
if (req.maxEvents !== void 0 && req.maxEvents > 0) {
|
|
671
|
+
q.set("max_events", String(req.maxEvents));
|
|
672
|
+
}
|
|
673
|
+
const extraHeaders = { Accept: "text/event-stream" };
|
|
674
|
+
if (req.lastEventId) extraHeaders["Last-Event-ID"] = req.lastEventId;
|
|
675
|
+
const res = await this.transport.requestStreamRaw(
|
|
676
|
+
"GET",
|
|
677
|
+
`/vm/${encodeURIComponent(this.hostname)}/fs/watch?${q.toString()}`,
|
|
678
|
+
void 0,
|
|
679
|
+
void 0,
|
|
680
|
+
extraHeaders
|
|
681
|
+
);
|
|
682
|
+
res.setEncoding("utf8");
|
|
683
|
+
let buffer = "";
|
|
684
|
+
let dataLines = [];
|
|
685
|
+
let pendingId = 0;
|
|
686
|
+
for await (const chunk of res) {
|
|
687
|
+
buffer += chunk;
|
|
688
|
+
let nl;
|
|
689
|
+
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
690
|
+
const raw = buffer.slice(0, nl);
|
|
691
|
+
buffer = buffer.slice(nl + 1);
|
|
692
|
+
const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
|
|
693
|
+
if (line === "") {
|
|
694
|
+
if (dataLines.length > 0) {
|
|
695
|
+
const payload = dataLines.join("\n");
|
|
696
|
+
dataLines = [];
|
|
697
|
+
try {
|
|
698
|
+
const parsed = JSON.parse(payload);
|
|
699
|
+
const evt = {
|
|
700
|
+
id: typeof parsed.id === "number" && parsed.id !== 0 ? parsed.id : pendingId,
|
|
701
|
+
type: parsed.type ?? "",
|
|
702
|
+
path: parsed.path ?? "",
|
|
703
|
+
timestamp: parsed.timestamp ?? "",
|
|
704
|
+
size: parsed.size ?? 0,
|
|
705
|
+
isDir: parsed.isDir ?? false,
|
|
706
|
+
...parsed.message !== void 0 && { message: parsed.message }
|
|
707
|
+
};
|
|
708
|
+
yield evt;
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
} else if (line.startsWith(":")) ; else if (line.startsWith("data:")) {
|
|
713
|
+
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
714
|
+
} else if (line.startsWith("id:")) {
|
|
715
|
+
const v = parseInt(line.slice(3).trim(), 10);
|
|
716
|
+
if (!Number.isNaN(v)) pendingId = v;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
642
721
|
/** Download `path` from the VM as a tar archive. */
|
|
643
722
|
async tarFrom(path3) {
|
|
644
723
|
const q = new URLSearchParams({ path: path3, mode: "tar" });
|
|
@@ -779,7 +858,8 @@ var VM = class {
|
|
|
779
858
|
*/
|
|
780
859
|
async *exec(req) {
|
|
781
860
|
const { path: path3, body } = buildExecPath(this.hostname, req, false);
|
|
782
|
-
for await (const
|
|
861
|
+
for await (const raw of this.transport.requestNDJSON("POST", path3, body)) {
|
|
862
|
+
const frame = normalizeExecFrame(raw);
|
|
783
863
|
if (frame.encoding === "base64") {
|
|
784
864
|
if (frame.data) frame.dataBytes = Buffer.from(frame.data, "base64");
|
|
785
865
|
if (frame.stdout) frame.stdoutBytes = Buffer.from(frame.stdout, "base64");
|
|
@@ -820,6 +900,22 @@ var VM = class {
|
|
|
820
900
|
};
|
|
821
901
|
}
|
|
822
902
|
};
|
|
903
|
+
function normalizeExecFrame(raw) {
|
|
904
|
+
const frame = {};
|
|
905
|
+
if (raw.timestamp !== void 0) frame.timestamp = raw.timestamp;
|
|
906
|
+
if (raw.type !== void 0) frame.type = raw.type;
|
|
907
|
+
if (raw.pid !== void 0) frame.pid = raw.pid;
|
|
908
|
+
if (raw.encoding !== void 0) frame.encoding = raw.encoding;
|
|
909
|
+
if (raw.data !== void 0) frame.data = raw.data;
|
|
910
|
+
if (raw.started_at !== void 0) frame.startedAt = raw.started_at;
|
|
911
|
+
if (raw.ended_at !== void 0) frame.endedAt = raw.ended_at;
|
|
912
|
+
if (raw.signal !== void 0) frame.signal = raw.signal;
|
|
913
|
+
if (raw.stdout !== void 0) frame.stdout = raw.stdout;
|
|
914
|
+
if (raw.stderr !== void 0) frame.stderr = raw.stderr;
|
|
915
|
+
if (raw.exit_code !== void 0) frame.exitCode = raw.exit_code;
|
|
916
|
+
if (raw.error !== void 0) frame.error = raw.error;
|
|
917
|
+
return frame;
|
|
918
|
+
}
|
|
823
919
|
function buildExecPath(hostname, req, buffered) {
|
|
824
920
|
const q = new URLSearchParams();
|
|
825
921
|
if (req.command) q.set("cmd", req.command);
|