@indexable/sdk 0.0.1 → 0.0.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.
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indexable/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"typecheck": "bunx tsc --noEmit"
|
|
14
14
|
},
|
|
15
15
|
"optionalDependencies": {
|
|
16
|
-
"@indexable/sdk-linux-x64-gnu": "0.0.
|
|
16
|
+
"@indexable/sdk-linux-x64-gnu": "0.0.4"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"bun-types": "latest"
|
package/src/index.test.ts
CHANGED
|
@@ -38,11 +38,15 @@ describe("Ix", () => {
|
|
|
38
38
|
|
|
39
39
|
describe("Vm lifecycle", () => {
|
|
40
40
|
test(
|
|
41
|
-
"spawn → getters → stop",
|
|
41
|
+
"spawn → ready → getters → stop",
|
|
42
42
|
async () => {
|
|
43
43
|
const ix = new Ix();
|
|
44
|
-
const vm = track(
|
|
44
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-lifecycle" }));
|
|
45
45
|
|
|
46
|
+
// ID is available immediately (client-generated).
|
|
47
|
+
expect(vm.id).toMatch(/^vm_/);
|
|
48
|
+
|
|
49
|
+
await vm.ready();
|
|
46
50
|
expect(vm.id).toBeTruthy();
|
|
47
51
|
expect(vm.image).toBe(IMAGE);
|
|
48
52
|
expect(vm.ipv6).toBeTruthy();
|
|
@@ -60,7 +64,7 @@ describe("Vm filesystem", () => {
|
|
|
60
64
|
"writeFile → readFile → listDir",
|
|
61
65
|
async () => {
|
|
62
66
|
const ix = new Ix();
|
|
63
|
-
const vm = track(
|
|
67
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-fs" }));
|
|
64
68
|
|
|
65
69
|
const content = `hello from sdk test ${Date.now()}`;
|
|
66
70
|
await vm.writeFile("/tmp/sdk-test.txt", content);
|
|
@@ -76,12 +80,71 @@ describe("Vm filesystem", () => {
|
|
|
76
80
|
);
|
|
77
81
|
});
|
|
78
82
|
|
|
83
|
+
describe("Vm exec", () => {
|
|
84
|
+
test(
|
|
85
|
+
"exec → capture stdout and exit code",
|
|
86
|
+
async () => {
|
|
87
|
+
const ix = new Ix();
|
|
88
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-exec" }));
|
|
89
|
+
|
|
90
|
+
const result = await vm.exec(["echo", "hello from exec"]);
|
|
91
|
+
expect(result.exitCode).toBe(0);
|
|
92
|
+
expect(result.stdout).toContain("hello from exec");
|
|
93
|
+
expect(result.stderr).toBe("");
|
|
94
|
+
},
|
|
95
|
+
TIMEOUT_MS,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
test(
|
|
99
|
+
"exec → nonzero exit code",
|
|
100
|
+
async () => {
|
|
101
|
+
const ix = new Ix();
|
|
102
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-exec-fail" }));
|
|
103
|
+
|
|
104
|
+
const result = await vm.exec(["sh", "-c", "exit 42"]);
|
|
105
|
+
expect(result.exitCode).toBe(42);
|
|
106
|
+
},
|
|
107
|
+
TIMEOUT_MS,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
test(
|
|
111
|
+
"exec → capture stderr",
|
|
112
|
+
async () => {
|
|
113
|
+
const ix = new Ix();
|
|
114
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-exec-stderr" }));
|
|
115
|
+
|
|
116
|
+
const result = await vm.exec([
|
|
117
|
+
"sh",
|
|
118
|
+
"-c",
|
|
119
|
+
"echo err >&2; echo out",
|
|
120
|
+
]);
|
|
121
|
+
expect(result.exitCode).toBe(0);
|
|
122
|
+
expect(result.stdout).toContain("out");
|
|
123
|
+
expect(result.stderr).toContain("err");
|
|
124
|
+
},
|
|
125
|
+
TIMEOUT_MS,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
test(
|
|
129
|
+
"exec → working directory",
|
|
130
|
+
async () => {
|
|
131
|
+
const ix = new Ix();
|
|
132
|
+
const vm = track(ix.spawn(IMAGE, { name: "sdk-exec-cwd" }));
|
|
133
|
+
|
|
134
|
+
const result = await vm.exec(["pwd"], "/tmp");
|
|
135
|
+
expect(result.exitCode).toBe(0);
|
|
136
|
+
expect(result.stdout.trim()).toBe("/tmp");
|
|
137
|
+
},
|
|
138
|
+
TIMEOUT_MS,
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
79
142
|
describe("Vm version control", () => {
|
|
80
143
|
test(
|
|
81
144
|
"fork → write on fork → merge back",
|
|
82
145
|
async () => {
|
|
83
146
|
const ix = new Ix();
|
|
84
|
-
const main = track(
|
|
147
|
+
const main = track(ix.spawn(IMAGE, { name: "sdk-vcs-main" }));
|
|
85
148
|
|
|
86
149
|
await main.writeFile("/tmp/file-a.txt", "from main");
|
|
87
150
|
|
package/src/index.ts
CHANGED
|
@@ -7,17 +7,9 @@
|
|
|
7
7
|
* import Ix from "@indexable/sdk"
|
|
8
8
|
*
|
|
9
9
|
* const ix = new Ix()
|
|
10
|
-
* const vm =
|
|
11
|
-
* console.log(vm.
|
|
12
|
-
*
|
|
13
|
-
* await vm.writeFile("/tmp/hi", "hello")
|
|
14
|
-
* const content = await vm.readFile("/tmp/hi")
|
|
15
|
-
*
|
|
16
|
-
* const fork = await vm.fork("experiment")
|
|
17
|
-
* await fork.writeFile("/tmp/new", "from fork")
|
|
18
|
-
* await vm.merge(fork)
|
|
19
|
-
*
|
|
20
|
-
* await vm.stop()
|
|
10
|
+
* const vm = ix.spawn("ubuntu:24.04") // sync — no await
|
|
11
|
+
* console.log(vm.id) // "vm_06e9..." (available immediately)
|
|
12
|
+
* await vm.writeFile("/tmp/hi", "hello") // first await creates the VM on server
|
|
21
13
|
* ```
|
|
22
14
|
*/
|
|
23
15
|
|
|
@@ -71,27 +63,46 @@ export interface SecretEntry {
|
|
|
71
63
|
createdAt: string;
|
|
72
64
|
}
|
|
73
65
|
|
|
66
|
+
/** Output from executing a command inside a VM. */
|
|
67
|
+
export interface ExecResult {
|
|
68
|
+
/** Process exit code (0 = success). */
|
|
69
|
+
exitCode: number;
|
|
70
|
+
/** Captured stdout. */
|
|
71
|
+
stdout: string;
|
|
72
|
+
/** Captured stderr. */
|
|
73
|
+
stderr: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
74
76
|
export interface ConnectOptions {
|
|
75
77
|
server?: string;
|
|
76
78
|
token?: string;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
/** A virtual machine. */
|
|
81
|
+
/** A virtual machine handle. Getters return `null` until the first awaited operation. */
|
|
80
82
|
export interface Vm {
|
|
81
|
-
/** VM identifier
|
|
83
|
+
/** VM identifier — always available, even before the VM is created on the server. */
|
|
82
84
|
readonly id: string;
|
|
83
|
-
readonly name: string;
|
|
84
|
-
readonly image: string;
|
|
85
|
-
readonly status: string;
|
|
86
|
-
readonly ipv6: string;
|
|
85
|
+
readonly name: string | null;
|
|
86
|
+
readonly image: string | null;
|
|
87
|
+
readonly status: string | null;
|
|
88
|
+
readonly ipv6: string | null;
|
|
87
89
|
readonly ipv4: string | null;
|
|
88
90
|
readonly subdomain: string | null;
|
|
91
|
+
readonly startedAt: string | null;
|
|
92
|
+
readonly stoppedAt: string | null;
|
|
93
|
+
readonly failureReason: string | null;
|
|
94
|
+
|
|
95
|
+
/** Explicitly trigger VM creation when you need metadata before any operation. */
|
|
96
|
+
ready(): Promise<void>;
|
|
89
97
|
|
|
90
98
|
stop(): Promise<void>;
|
|
91
99
|
start(): Promise<void>;
|
|
92
100
|
restart(): Promise<void>;
|
|
93
101
|
delete(): Promise<void>;
|
|
94
102
|
|
|
103
|
+
/** Execute a command inside the VM and return its output. */
|
|
104
|
+
exec(command: string[], workingDir?: string): Promise<ExecResult>;
|
|
105
|
+
|
|
95
106
|
writeFile(path: string, content: string): Promise<void>;
|
|
96
107
|
readFile(path: string): Promise<string>;
|
|
97
108
|
listDir(path: string): Promise<DirEntry[]>;
|
|
@@ -116,8 +127,8 @@ export class Ix {
|
|
|
116
127
|
this.inner = new native.Ix(options ?? undefined);
|
|
117
128
|
}
|
|
118
129
|
|
|
119
|
-
/** Create a VM from an OCI image. */
|
|
120
|
-
|
|
130
|
+
/** Create a VM handle from an OCI image. Returns immediately (sync). */
|
|
131
|
+
spawn(image: string, options?: SpawnOptions): Vm {
|
|
121
132
|
return this.inner.spawn(image, options ?? undefined);
|
|
122
133
|
}
|
|
123
134
|
|