@axiom-lattice/microsandbox-service 0.0.6 → 0.0.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/CHANGELOG.md +13 -0
- package/__mocks__/microsandbox.ts +34 -0
- package/dist/{chunk-U7OY36QN.mjs → chunk-AYZRAXEI.mjs} +2 -2
- package/dist/{chunk-DXY4IZGV.mjs → chunk-BVTB6UPA.mjs} +219 -47
- package/dist/chunk-BVTB6UPA.mjs.map +1 -0
- package/dist/cli.js +228 -56
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/index.d.mts +17 -5
- package/dist/index.d.ts +17 -5
- package/dist/index.js +228 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.js +228 -56
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +2 -2
- package/jest.config.js +3 -0
- package/package.json +2 -2
- package/src/__tests__/MicrosandboxRuntimeService.test.ts +183 -46
- package/src/__tests__/SandboxRegistry.test.ts +36 -17
- package/src/app.ts +2 -0
- package/src/controllers/sandbox.ts +2 -1
- package/src/controllers/volume-fs.ts +123 -0
- package/src/routes/volume-fs.ts +12 -0
- package/src/schemas/sandbox.ts +1 -1
- package/src/schemas/volume-fs.ts +23 -0
- package/src/services/MicrosandboxRuntimeService.ts +103 -61
- package/src/services/SandboxRegistry.ts +27 -7
- package/src/types/runtime-service.ts +13 -0
- package/dist/chunk-DXY4IZGV.mjs.map +0 -1
- /package/dist/{chunk-U7OY36QN.mjs.map → chunk-AYZRAXEI.mjs.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const mockBuilder = {
|
|
2
|
+
image: jest.fn().mockReturnThis(),
|
|
3
|
+
cpus: jest.fn().mockReturnThis(),
|
|
4
|
+
memory: jest.fn().mockReturnThis(),
|
|
5
|
+
idleTimeout: jest.fn().mockReturnThis(),
|
|
6
|
+
envs: jest.fn().mockReturnThis(),
|
|
7
|
+
volume: jest.fn().mockReturnThis(),
|
|
8
|
+
createDetached: jest.fn(),
|
|
9
|
+
create: jest.fn(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Sandbox = {
|
|
13
|
+
get: jest.fn(),
|
|
14
|
+
start: jest.fn(),
|
|
15
|
+
startDetached: jest.fn(),
|
|
16
|
+
remove: jest.fn(),
|
|
17
|
+
list: jest.fn(),
|
|
18
|
+
builder: jest.fn().mockReturnValue(mockBuilder),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Volume = {
|
|
22
|
+
get: jest.fn(),
|
|
23
|
+
builder: jest.fn().mockReturnValue({
|
|
24
|
+
quota: jest.fn().mockReturnThis(),
|
|
25
|
+
create: jest.fn(),
|
|
26
|
+
}),
|
|
27
|
+
list: jest.fn(),
|
|
28
|
+
remove: jest.fn(),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const MountBuilder = class {};
|
|
32
|
+
export const VolumeBuilder = class {};
|
|
33
|
+
export const SandboxBuilder = class {};
|
|
34
|
+
export { Sandbox as SandboxHandle };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildApp
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BVTB6UPA.mjs";
|
|
4
4
|
|
|
5
5
|
// src/lib/server-cli.ts
|
|
6
6
|
function parsePort(raw, source) {
|
|
@@ -97,4 +97,4 @@ async function startServer({
|
|
|
97
97
|
export {
|
|
98
98
|
startServer
|
|
99
99
|
};
|
|
100
|
-
//# sourceMappingURL=chunk-
|
|
100
|
+
//# sourceMappingURL=chunk-AYZRAXEI.mjs.map
|
|
@@ -17,11 +17,10 @@ var SandboxRegistry = class {
|
|
|
17
17
|
}
|
|
18
18
|
const creation = (async () => {
|
|
19
19
|
let native;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
20
|
+
const image = createOptions?.image ?? DEFAULT_IMAGE;
|
|
21
|
+
const cpus = createOptions?.cpus ?? 1;
|
|
22
|
+
const memoryMib = createOptions?.memoryMib ?? 512;
|
|
23
|
+
const env = createOptions?.env ?? void 0;
|
|
25
24
|
try {
|
|
26
25
|
const handle = await Sandbox.get(name);
|
|
27
26
|
if (handle.status === "running") {
|
|
@@ -35,7 +34,23 @@ var SandboxRegistry = class {
|
|
|
35
34
|
native = void 0;
|
|
36
35
|
}
|
|
37
36
|
if (!native) {
|
|
38
|
-
|
|
37
|
+
const builder = Sandbox.builder(name).image(image).cpus(cpus).memory(memoryMib).idleTimeout(300);
|
|
38
|
+
if (env) {
|
|
39
|
+
builder.envs(env);
|
|
40
|
+
}
|
|
41
|
+
const volumes = createOptions?.volumes;
|
|
42
|
+
if (volumes) {
|
|
43
|
+
for (const [guestPath, def] of Object.entries(volumes)) {
|
|
44
|
+
if (def.type === "bind" && def.source) {
|
|
45
|
+
builder.volume(guestPath, (b) => b.bind(def.source));
|
|
46
|
+
} else if (def.type === "named" && def.name) {
|
|
47
|
+
builder.volume(guestPath, (b) => b.named(def.name));
|
|
48
|
+
} else if (def.type === "tmpfs") {
|
|
49
|
+
builder.volume(guestPath, (b) => def.sizeMib ? b.tmpfs().size(def.sizeMib) : b.tmpfs());
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
native = await builder.createDetached();
|
|
39
54
|
}
|
|
40
55
|
this.handles.set(name, native);
|
|
41
56
|
return native;
|
|
@@ -57,16 +72,36 @@ var SandboxRegistry = class {
|
|
|
57
72
|
};
|
|
58
73
|
|
|
59
74
|
// src/services/MicrosandboxRuntimeService.ts
|
|
60
|
-
import {
|
|
75
|
+
import { Sandbox as Sandbox2, Volume } from "microsandbox";
|
|
76
|
+
function parseEnvArray(env) {
|
|
77
|
+
if (!Array.isArray(env)) return env;
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const entry of env) {
|
|
80
|
+
if (typeof entry !== "string") continue;
|
|
81
|
+
const eq = entry.indexOf("=");
|
|
82
|
+
if (eq < 0) continue;
|
|
83
|
+
result[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
61
87
|
function parseConfigJson(configJson) {
|
|
62
88
|
try {
|
|
63
|
-
|
|
89
|
+
const raw = JSON.parse(configJson);
|
|
90
|
+
return {
|
|
91
|
+
name: raw.name ?? "",
|
|
92
|
+
image: raw.image ?? "",
|
|
93
|
+
memoryMib: raw.memoryMib ?? raw.memory_mib,
|
|
94
|
+
cpus: raw.cpus,
|
|
95
|
+
env: raw.env != null ? parseEnvArray(raw.env) : void 0,
|
|
96
|
+
volumes: raw.volumes
|
|
97
|
+
};
|
|
64
98
|
} catch {
|
|
65
99
|
return { name: "", image: "" };
|
|
66
100
|
}
|
|
67
101
|
}
|
|
68
102
|
function msToIsoString(ms) {
|
|
69
103
|
if (ms == null) return "";
|
|
104
|
+
if (ms instanceof Date) return ms.toISOString();
|
|
70
105
|
return new Date(ms).toISOString();
|
|
71
106
|
}
|
|
72
107
|
var MicrosandboxRuntimeService = class {
|
|
@@ -99,35 +134,32 @@ var MicrosandboxRuntimeService = class {
|
|
|
99
134
|
updatedAt: msToIsoString(info.updatedAt)
|
|
100
135
|
};
|
|
101
136
|
}
|
|
102
|
-
|
|
103
|
-
if (!volumes)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return Mount.bind(definition.source, { readonly: definition.readonly ?? false });
|
|
113
|
-
}
|
|
114
|
-
if (definition.type === "named") {
|
|
115
|
-
return Mount.named(definition.name, { readonly: definition.readonly ?? false });
|
|
137
|
+
applyVolumes(builder, volumes) {
|
|
138
|
+
if (!volumes) return;
|
|
139
|
+
for (const [mountPath, definition] of Object.entries(volumes)) {
|
|
140
|
+
if (definition.type === "bind") {
|
|
141
|
+
builder.volume(mountPath, (b) => b.bind(definition.source));
|
|
142
|
+
} else if (definition.type === "named") {
|
|
143
|
+
builder.volume(mountPath, (b) => b.named(definition.name));
|
|
144
|
+
} else {
|
|
145
|
+
builder.volume(mountPath, (b) => b.tmpfs().size(definition.sizeMib ?? 0));
|
|
146
|
+
}
|
|
116
147
|
}
|
|
117
|
-
return Mount.tmpfs({ sizeMib: definition.sizeMib });
|
|
118
148
|
}
|
|
119
149
|
async ensureNamedVolumes(volumes) {
|
|
120
150
|
if (!volumes) {
|
|
121
151
|
return;
|
|
122
152
|
}
|
|
123
153
|
const defaultQuotaMib = Number(process.env.MICROSANDBOX_VOLUME_QUOTA_MIB ?? "1024");
|
|
124
|
-
const namedVolumes = Object.values(volumes).filter(
|
|
154
|
+
const namedVolumes = Object.values(volumes).filter(
|
|
155
|
+
(v) => v.type === "named"
|
|
156
|
+
);
|
|
125
157
|
await Promise.all(
|
|
126
158
|
namedVolumes.map(async (definition) => {
|
|
127
159
|
try {
|
|
128
160
|
await Volume.get(definition.name);
|
|
129
161
|
} catch {
|
|
130
|
-
await Volume.
|
|
162
|
+
await Volume.builder(definition.name).quota(defaultQuotaMib).create();
|
|
131
163
|
}
|
|
132
164
|
})
|
|
133
165
|
);
|
|
@@ -152,7 +184,7 @@ var MicrosandboxRuntimeService = class {
|
|
|
152
184
|
cpus,
|
|
153
185
|
memoryMib,
|
|
154
186
|
env: input.env,
|
|
155
|
-
volumes:
|
|
187
|
+
volumes: input.volumes
|
|
156
188
|
});
|
|
157
189
|
return {
|
|
158
190
|
name,
|
|
@@ -188,7 +220,15 @@ var MicrosandboxRuntimeService = class {
|
|
|
188
220
|
}
|
|
189
221
|
async listSandboxes(_query) {
|
|
190
222
|
const all = await Sandbox2.list();
|
|
191
|
-
const items = all.map(
|
|
223
|
+
const items = all.map(
|
|
224
|
+
(info) => this.toListItem({
|
|
225
|
+
name: info.name,
|
|
226
|
+
status: info.status,
|
|
227
|
+
configJson: info.configJson,
|
|
228
|
+
createdAt: info.createdAt,
|
|
229
|
+
updatedAt: info.updatedAt
|
|
230
|
+
})
|
|
231
|
+
).filter((item) => {
|
|
192
232
|
if (_query.status && item.status !== _query.status) {
|
|
193
233
|
return false;
|
|
194
234
|
}
|
|
@@ -209,6 +249,23 @@ var MicrosandboxRuntimeService = class {
|
|
|
209
249
|
try {
|
|
210
250
|
const handle = await Sandbox2.get(name);
|
|
211
251
|
const config = parseConfigJson(handle.configJson);
|
|
252
|
+
let metrics;
|
|
253
|
+
try {
|
|
254
|
+
const m = await handle.metrics();
|
|
255
|
+
metrics = {
|
|
256
|
+
cpuPercent: m.cpuPercent,
|
|
257
|
+
memoryBytes: m.memoryBytes,
|
|
258
|
+
memoryLimitBytes: m.memoryLimitBytes,
|
|
259
|
+
diskReadBytes: m.diskReadBytes,
|
|
260
|
+
diskWriteBytes: m.diskWriteBytes,
|
|
261
|
+
netRxBytes: m.netRxBytes,
|
|
262
|
+
netTxBytes: m.netTxBytes,
|
|
263
|
+
uptimeMs: m.uptimeMs,
|
|
264
|
+
timestampMs: m.timestamp.getTime()
|
|
265
|
+
};
|
|
266
|
+
} catch {
|
|
267
|
+
metrics = void 0;
|
|
268
|
+
}
|
|
212
269
|
return {
|
|
213
270
|
name: handle.name,
|
|
214
271
|
status: handle.status,
|
|
@@ -217,6 +274,7 @@ var MicrosandboxRuntimeService = class {
|
|
|
217
274
|
memoryMib: config.memoryMib,
|
|
218
275
|
env: config.env ?? {},
|
|
219
276
|
volumes: config.volumes ?? {},
|
|
277
|
+
metrics,
|
|
220
278
|
createdAt: msToIsoString(handle.createdAt),
|
|
221
279
|
updatedAt: msToIsoString(handle.updatedAt)
|
|
222
280
|
};
|
|
@@ -234,7 +292,7 @@ var MicrosandboxRuntimeService = class {
|
|
|
234
292
|
}
|
|
235
293
|
async readFile(sandboxName, path) {
|
|
236
294
|
const resolvedPath = this.resolvePath(path);
|
|
237
|
-
const content = await this.getNative(sandboxName).fs().
|
|
295
|
+
const content = await this.getNative(sandboxName).fs().readToString(resolvedPath);
|
|
238
296
|
return { path: resolvedPath, content };
|
|
239
297
|
}
|
|
240
298
|
async writeFile(sandboxName, path, content) {
|
|
@@ -244,7 +302,7 @@ var MicrosandboxRuntimeService = class {
|
|
|
244
302
|
}
|
|
245
303
|
async listPath(sandboxName, path, recursive) {
|
|
246
304
|
const resolvedPath = this.resolvePath(path);
|
|
247
|
-
const entries = await this.getNative(sandboxName).fs().list(resolvedPath
|
|
305
|
+
const entries = await this.getNative(sandboxName).fs().list(resolvedPath);
|
|
248
306
|
return {
|
|
249
307
|
entries: entries.map((entry) => ({
|
|
250
308
|
path: entry.path,
|
|
@@ -254,20 +312,20 @@ var MicrosandboxRuntimeService = class {
|
|
|
254
312
|
}
|
|
255
313
|
async findFiles(sandboxName, path, pattern) {
|
|
256
314
|
const resolvedPath = this.resolvePath(path);
|
|
257
|
-
const output = await this.getNative(sandboxName).
|
|
258
|
-
|
|
259
|
-
args
|
|
260
|
-
|
|
315
|
+
const output = await this.getNative(sandboxName).execWith(
|
|
316
|
+
"find",
|
|
317
|
+
(b) => b.args([resolvedPath, "-name", pattern, "-type", "f"])
|
|
318
|
+
);
|
|
261
319
|
return { files: output.stdout().split("\n").filter(Boolean) };
|
|
262
320
|
}
|
|
263
321
|
async searchInFile(sandboxName, path, query) {
|
|
264
322
|
const resolvedPath = this.resolvePath(path);
|
|
265
323
|
let stdout;
|
|
266
324
|
try {
|
|
267
|
-
const output = await this.getNative(sandboxName).
|
|
268
|
-
|
|
269
|
-
args
|
|
270
|
-
|
|
325
|
+
const output = await this.getNative(sandboxName).execWith(
|
|
326
|
+
"grep",
|
|
327
|
+
(b) => b.args(["-n", "-E", query, resolvedPath])
|
|
328
|
+
);
|
|
271
329
|
stdout = output.stdout();
|
|
272
330
|
} catch (error) {
|
|
273
331
|
if (typeof error === "object" && error !== null && "code" in error && error.code === 1) {
|
|
@@ -288,7 +346,7 @@ var MicrosandboxRuntimeService = class {
|
|
|
288
346
|
async replaceInFile(sandboxName, input) {
|
|
289
347
|
const resolvedPath = this.resolvePath(input.path);
|
|
290
348
|
const fs = this.getNative(sandboxName).fs();
|
|
291
|
-
const original = await fs.
|
|
349
|
+
const original = await fs.readToString(resolvedPath);
|
|
292
350
|
if (!input.search) {
|
|
293
351
|
return { replaced: 0 };
|
|
294
352
|
}
|
|
@@ -312,15 +370,15 @@ var MicrosandboxRuntimeService = class {
|
|
|
312
370
|
return { path: resolvedPath, contentBase64: buffer.toString("base64") };
|
|
313
371
|
}
|
|
314
372
|
async execCommand(input) {
|
|
315
|
-
const output = await this.getNative(input.sandboxName).
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
373
|
+
const output = await this.getNative(input.sandboxName).execWith("sh", (b) => {
|
|
374
|
+
b.args(["-c", input.command]);
|
|
375
|
+
if (input.exec_dir) b.cwd(input.exec_dir);
|
|
376
|
+
if (input.timeout) b.timeout(input.timeout * 1e3);
|
|
377
|
+
return b;
|
|
320
378
|
});
|
|
321
379
|
return {
|
|
322
380
|
stdout: output.stdout(),
|
|
323
|
-
stderr: output.stderr
|
|
381
|
+
stderr: output.stderr(),
|
|
324
382
|
exitCode: output.code ?? 0
|
|
325
383
|
};
|
|
326
384
|
}
|
|
@@ -462,7 +520,7 @@ var sandboxNameParamsSchema = z2.object({
|
|
|
462
520
|
name: z2.string().min(1)
|
|
463
521
|
});
|
|
464
522
|
var listSandboxesQuerySchema = z2.object({
|
|
465
|
-
status: z2.enum(["running", "stopped", "unknown"]).optional(),
|
|
523
|
+
status: z2.enum(["running", "stopped", "crashed", "unknown"]).optional(),
|
|
466
524
|
image: z2.string().min(1).optional(),
|
|
467
525
|
search: z2.string().min(1).optional()
|
|
468
526
|
});
|
|
@@ -570,7 +628,8 @@ function createSandboxController(runtimeService) {
|
|
|
570
628
|
},
|
|
571
629
|
uploadFile: async (request, reply) => {
|
|
572
630
|
const body = uploadFileSchema.parse(request.body ?? {});
|
|
573
|
-
|
|
631
|
+
const contentBase64 = "contentBase64" in body ? body.contentBase64 : Buffer.from(body.content).toString("base64");
|
|
632
|
+
return reply.send(ok(await runtimeService.uploadFile(body.sandboxName, body.path, contentBase64)));
|
|
574
633
|
},
|
|
575
634
|
downloadFile: async (request, reply) => {
|
|
576
635
|
const query = downloadFileSchema.parse(request.query ?? {});
|
|
@@ -605,6 +664,118 @@ function registerSandboxRoutes(app, runtimeService) {
|
|
|
605
664
|
app.post("/api/shell/exec", controller.execCommand);
|
|
606
665
|
}
|
|
607
666
|
|
|
667
|
+
// src/controllers/volume-fs.ts
|
|
668
|
+
import { Volume as Volume2 } from "microsandbox";
|
|
669
|
+
import z4 from "zod";
|
|
670
|
+
|
|
671
|
+
// src/schemas/volume-fs.ts
|
|
672
|
+
import z3 from "zod";
|
|
673
|
+
var volumeFsReadSchema = z3.object({
|
|
674
|
+
path: z3.string().min(1)
|
|
675
|
+
});
|
|
676
|
+
var volumeFsWriteSchema = z3.object({
|
|
677
|
+
path: z3.string().min(1),
|
|
678
|
+
content: z3.string()
|
|
679
|
+
});
|
|
680
|
+
var volumeFsListSchema = z3.object({
|
|
681
|
+
path: z3.string().min(1)
|
|
682
|
+
});
|
|
683
|
+
var volumeFsUploadSchema = z3.object({
|
|
684
|
+
path: z3.string().min(1),
|
|
685
|
+
contentBase64: z3.string().min(1)
|
|
686
|
+
});
|
|
687
|
+
var volumeFsDownloadSchema = z3.object({
|
|
688
|
+
path: z3.string().min(1)
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// src/controllers/volume-fs.ts
|
|
692
|
+
function createVolumeFsController() {
|
|
693
|
+
return {
|
|
694
|
+
readFile: async (request, reply) => {
|
|
695
|
+
const { name } = request.params;
|
|
696
|
+
try {
|
|
697
|
+
const { path } = volumeFsReadSchema.parse(request.body ?? {});
|
|
698
|
+
const vfs = (await Volume2.get(name)).fs();
|
|
699
|
+
const content = await vfs.readToString(path);
|
|
700
|
+
return reply.send(ok({ path, content }));
|
|
701
|
+
} catch (err) {
|
|
702
|
+
if (err instanceof z4.ZodError) {
|
|
703
|
+
throw new HttpError(400, "VALIDATION_ERROR", err.message);
|
|
704
|
+
}
|
|
705
|
+
throw new HttpError(404, "VOLUME_READ_ERROR", `Failed to read from volume '${name}': ${String(err)}`);
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
writeFile: async (request, reply) => {
|
|
709
|
+
const { name } = request.params;
|
|
710
|
+
try {
|
|
711
|
+
const { path, content } = volumeFsWriteSchema.parse(request.body ?? {});
|
|
712
|
+
const vfs = (await Volume2.get(name)).fs();
|
|
713
|
+
await vfs.write(path, content);
|
|
714
|
+
return reply.send(ok({ path }));
|
|
715
|
+
} catch (err) {
|
|
716
|
+
if (err instanceof z4.ZodError) {
|
|
717
|
+
throw new HttpError(400, "VALIDATION_ERROR", err.message);
|
|
718
|
+
}
|
|
719
|
+
throw new HttpError(500, "VOLUME_WRITE_ERROR", `Failed to write to volume '${name}': ${String(err)}`);
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
listPath: async (request, reply) => {
|
|
723
|
+
const { name } = request.params;
|
|
724
|
+
try {
|
|
725
|
+
const { path } = volumeFsListSchema.parse(request.body ?? {});
|
|
726
|
+
const vfs = (await Volume2.get(name)).fs();
|
|
727
|
+
const entries = await vfs.list(path);
|
|
728
|
+
return reply.send(ok({ entries }));
|
|
729
|
+
} catch (err) {
|
|
730
|
+
if (err instanceof z4.ZodError) {
|
|
731
|
+
throw new HttpError(400, "VALIDATION_ERROR", err.message);
|
|
732
|
+
}
|
|
733
|
+
throw new HttpError(404, "VOLUME_LIST_ERROR", `Failed to list volume '${name}': ${String(err)}`);
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
downloadFile: async (request, reply) => {
|
|
737
|
+
const { name } = request.params;
|
|
738
|
+
try {
|
|
739
|
+
const { path } = volumeFsDownloadSchema.parse(request.query ?? {});
|
|
740
|
+
const vfs = (await Volume2.get(name)).fs();
|
|
741
|
+
const buf = await vfs.read(path);
|
|
742
|
+
const contentBase64 = Buffer.from(buf).toString("base64");
|
|
743
|
+
return reply.send(ok({ path, contentBase64 }));
|
|
744
|
+
} catch (err) {
|
|
745
|
+
if (err instanceof z4.ZodError) {
|
|
746
|
+
throw new HttpError(400, "VALIDATION_ERROR", err.message);
|
|
747
|
+
}
|
|
748
|
+
throw new HttpError(404, "VOLUME_DOWNLOAD_ERROR", `Failed to download from volume '${name}': ${String(err)}`);
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
uploadFile: async (request, reply) => {
|
|
752
|
+
const { name } = request.params;
|
|
753
|
+
try {
|
|
754
|
+
const { path, contentBase64 } = volumeFsUploadSchema.parse(request.body ?? {});
|
|
755
|
+
const vfs = (await Volume2.get(name)).fs();
|
|
756
|
+
const data = Buffer.from(contentBase64, "base64");
|
|
757
|
+
await vfs.write(path, data);
|
|
758
|
+
return reply.send(ok({ path }));
|
|
759
|
+
} catch (err) {
|
|
760
|
+
if (err instanceof z4.ZodError) {
|
|
761
|
+
throw new HttpError(400, "VALIDATION_ERROR", err.message);
|
|
762
|
+
}
|
|
763
|
+
throw new HttpError(500, "VOLUME_UPLOAD_ERROR", `Failed to upload to volume '${name}': ${String(err)}`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// src/routes/volume-fs.ts
|
|
770
|
+
function registerVolumeFsRoutes(app) {
|
|
771
|
+
const controller = createVolumeFsController();
|
|
772
|
+
app.post("/api/volumes/:name/fs/read", controller.readFile);
|
|
773
|
+
app.post("/api/volumes/:name/fs/write", controller.writeFile);
|
|
774
|
+
app.post("/api/volumes/:name/fs/list", controller.listPath);
|
|
775
|
+
app.get("/api/volumes/:name/fs/download", controller.downloadFile);
|
|
776
|
+
app.post("/api/volumes/:name/fs/upload", controller.uploadFile);
|
|
777
|
+
}
|
|
778
|
+
|
|
608
779
|
// src/services/ImageService.ts
|
|
609
780
|
import { exec } from "child_process";
|
|
610
781
|
import { promisify } from "util";
|
|
@@ -706,6 +877,7 @@ function buildApp({
|
|
|
706
877
|
registerHealthRoutes(app);
|
|
707
878
|
registerSandboxRoutes(app, runtimeService);
|
|
708
879
|
registerImageRoutes(app, imageService);
|
|
880
|
+
registerVolumeFsRoutes(app);
|
|
709
881
|
app.setErrorHandler((error, _request, reply) => {
|
|
710
882
|
const { statusCode, body } = toErrorResponse(error);
|
|
711
883
|
reply.status(statusCode).send(body);
|
|
@@ -718,4 +890,4 @@ export {
|
|
|
718
890
|
MicrosandboxRuntimeService,
|
|
719
891
|
buildApp
|
|
720
892
|
};
|
|
721
|
-
//# sourceMappingURL=chunk-
|
|
893
|
+
//# sourceMappingURL=chunk-BVTB6UPA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/SandboxRegistry.ts","../src/services/MicrosandboxRuntimeService.ts","../src/app.ts","../src/lib/errors.ts","../src/lib/http.ts","../src/routes/health.ts","../src/controllers/images.ts","../src/schemas/images.ts","../src/routes/images.ts","../src/schemas/sandbox.ts","../src/controllers/sandbox.ts","../src/routes/sandbox.ts","../src/controllers/volume-fs.ts","../src/schemas/volume-fs.ts","../src/routes/volume-fs.ts","../src/services/ImageService.ts"],"sourcesContent":["import { Sandbox } from \"microsandbox\";\nimport type { SandboxHandle } from \"microsandbox\";\n\nconst DEFAULT_IMAGE = process.env.MICROSANDBOX_IMAGE ?? \"daytonaio/sandbox:0.6.0\";\n\nexport class SandboxRegistry {\n private handles = new Map<string, unknown>();\n private creating = new Map<string, Promise<unknown>>();\n\n async ensure(name: string, createOptions?: Record<string, unknown>): Promise<unknown> {\n const cached = this.handles.get(name);\n if (cached) {\n return cached;\n }\n\n const inflight = this.creating.get(name);\n if (inflight) {\n return inflight;\n }\n\n const creation = (async () => {\n let native: unknown;\n const image = (createOptions?.image as string) ?? DEFAULT_IMAGE;\n const cpus = (createOptions?.cpus as number) ?? 1;\n const memoryMib = (createOptions?.memoryMib as number) ?? 512;\n const env = (createOptions?.env as Record<string, string>) ?? undefined;\n\n try {\n const handle: SandboxHandle = await Sandbox.get(name);\n\n if (handle.status === \"running\") {\n native = await handle.connect();\n } else if (handle.status === \"stopped\") {\n native = await Sandbox.start(name);\n } else if (handle.status === \"crashed\" || handle.status === \"draining\") {\n await Sandbox.remove(name);\n }\n } catch {\n native = undefined;\n }\n\n if (!native) {\n const builder = Sandbox.builder(name)\n .image(image)\n .cpus(cpus)\n .memory(memoryMib)\n .idleTimeout(300);\n if (env) {\n builder.envs(env);\n }\n const volumes = createOptions?.volumes as Record<string, { type: string; source?: string; name?: string; sizeMib?: number }> | undefined;\n if (volumes) {\n for (const [guestPath, def] of Object.entries(volumes)) {\n if (def.type === \"bind\" && def.source) {\n builder.volume(guestPath, (b) => b.bind(def.source!));\n } else if (def.type === \"named\" && def.name) {\n builder.volume(guestPath, (b) => b.named(def.name!));\n } else if (def.type === \"tmpfs\") {\n builder.volume(guestPath, (b) => def.sizeMib ? b.tmpfs().size(def.sizeMib) : b.tmpfs());\n }\n }\n }\n native = await builder.createDetached();\n }\n\n this.handles.set(name, native);\n return native;\n })();\n\n this.creating.set(name, creation);\n void creation.finally(() => this.creating.delete(name));\n\n return creation;\n }\n\n get(name: string): unknown {\n const handle = this.handles.get(name);\n\n if (!handle) {\n throw new Error(`Sandbox ${name} not found`);\n }\n\n return handle;\n }\n\n delete(name: string): void {\n this.handles.delete(name);\n }\n}\n","import { Sandbox, Volume, MountBuilder } from \"microsandbox\";\nimport type { SandboxHandle } from \"microsandbox\";\nimport type { EnsureSandboxInput, ListSandboxesQuery, ShellExecInput } from \"../schemas/sandbox\";\nimport type { SandboxRuntimeMetrics } from \"../types/runtime-service\";\nimport { SandboxRegistry } from \"./SandboxRegistry\";\n\ntype VolumeConfig = NonNullable<EnsureSandboxInput[\"volumes\"]>[string];\n\ntype RuntimeNative = {\n fs(): {\n readToString(path: string): Promise<string>;\n write(path: string, data: Buffer): Promise<void>;\n list(path: string): Promise<Array<{ path: string; kind: string; size?: number; modified?: unknown }>>;\n read(path: string): Promise<Buffer | Uint8Array | string>;\n };\n execWith(cmd: string, configure: (b: { args(args: string[]): unknown; cwd(cwd: string): unknown; timeout(ms: number): unknown }) => unknown): Promise<{\n stdout(): string;\n stderr(): string;\n code?: number;\n }>;\n stop(): Promise<void>;\n kill(): Promise<void>;\n};\n\ntype SandboxConfig = {\n name: string;\n image: string;\n memoryMib?: number;\n cpus?: number;\n env?: Record<string, string>;\n volumes?: Record<string, unknown>;\n};\n\nfunction parseEnvArray(env: unknown): Record<string, string> {\n if (!Array.isArray(env)) return env as Record<string, string>;\n const result: Record<string, string> = {};\n for (const entry of env) {\n if (typeof entry !== \"string\") continue;\n const eq = entry.indexOf(\"=\");\n if (eq < 0) continue;\n result[entry.slice(0, eq)] = entry.slice(eq + 1);\n }\n return result;\n}\n\nfunction parseConfigJson(configJson: string): SandboxConfig {\n try {\n const raw = JSON.parse(configJson);\n return {\n name: raw.name ?? \"\",\n image: raw.image ?? \"\",\n memoryMib: raw.memoryMib ?? raw.memory_mib,\n cpus: raw.cpus,\n env: raw.env != null ? parseEnvArray(raw.env) : undefined,\n volumes: raw.volumes,\n };\n } catch {\n return { name: \"\", image: \"\" };\n }\n}\n\nfunction msToIsoString(ms: number | Date | null | undefined): string {\n if (ms == null) return \"\";\n if (ms instanceof Date) return ms.toISOString();\n return new Date(ms).toISOString();\n}\n\nexport class MicrosandboxRuntimeService {\n constructor(private deps: { registry?: SandboxRegistry } = {}) {}\n\n private get registry(): SandboxRegistry {\n return this.deps.registry ?? (this.deps.registry = new SandboxRegistry());\n }\n\n private resolvePath(path: string): string {\n const homeDir = process.env.MICROSANDBOX_HOME_DIR ?? \"/home/daytona\";\n if (path === \"~\" || path.startsWith(\"~/\")) {\n return `${homeDir}${path === \"~\" ? \"\" : \"/\" + path.slice(2)}`;\n }\n return path;\n }\n\n private toListItem(info: {\n name: string;\n status: string;\n configJson: string;\n createdAt?: number | Date | null;\n updatedAt?: number | Date | null;\n }): {\n name: string;\n status: string;\n image?: string;\n cpus?: number;\n memoryMib?: number;\n envCount: number;\n volumeCount: number;\n createdAt: string;\n updatedAt: string;\n } {\n const config = parseConfigJson(info.configJson);\n const env = config.env ?? {};\n const volumes = config.volumes ?? {};\n\n return {\n name: info.name,\n status: info.status,\n image: config.image,\n cpus: config.cpus,\n memoryMib: config.memoryMib,\n envCount: Object.keys(env).length,\n volumeCount: Object.keys(volumes).length,\n createdAt: msToIsoString(info.createdAt),\n updatedAt: msToIsoString(info.updatedAt),\n };\n }\n\n private applyVolumes(\n builder: ReturnType<typeof Sandbox.builder>,\n volumes?: EnsureSandboxInput[\"volumes\"]\n ): void {\n if (!volumes) return;\n\n for (const [mountPath, definition] of Object.entries(volumes)) {\n if (definition.type === \"bind\") {\n builder.volume(mountPath, (b) => b.bind(definition.source));\n } else if (definition.type === \"named\") {\n builder.volume(mountPath, (b) => b.named(definition.name));\n } else {\n builder.volume(mountPath, (b) => b.tmpfs().size(definition.sizeMib ?? 0));\n }\n }\n }\n\n private async ensureNamedVolumes(volumes?: EnsureSandboxInput[\"volumes\"]): Promise<void> {\n if (!volumes) {\n return;\n }\n\n const defaultQuotaMib = Number(process.env.MICROSANDBOX_VOLUME_QUOTA_MIB ?? \"1024\");\n\n const namedVolumes = Object.values(volumes).filter(\n (v): v is Extract<VolumeConfig, { type: \"named\" }> => v.type === \"named\"\n );\n\n await Promise.all(\n namedVolumes.map(async (definition) => {\n try {\n await Volume.get(definition.name);\n } catch {\n await Volume.builder(definition.name).quota(defaultQuotaMib).create();\n }\n })\n );\n }\n\n private getNative(name: string): RuntimeNative {\n return this.registry.get(name) as RuntimeNative;\n }\n\n private async getOrEnsureNative(name: string): Promise<RuntimeNative> {\n try {\n return this.getNative(name);\n } catch {\n return (await this.registry.ensure(name)) as RuntimeNative;\n }\n }\n\n async ensureSandbox(\n name: string,\n input: EnsureSandboxInput\n ): Promise<{\n name: string;\n status: string;\n }> {\n const image = input.image ?? process.env.MICROSANDBOX_IMAGE ?? \"python:3.11-slim\";\n const cpus = input.cpus ?? Number(process.env.MICROSANDBOX_CPUS ?? \"1\");\n const memoryMib = input.memoryMib ?? Number(process.env.MICROSANDBOX_MEMORY ?? \"512\");\n\n await this.ensureNamedVolumes(input.volumes);\n\n await this.registry.ensure(name, {\n image,\n cpus,\n memoryMib,\n env: input.env,\n volumes: input.volumes,\n });\n\n return {\n name,\n status: \"running\",\n };\n }\n\n async startSandbox(name: string): Promise<{ name: string; status: string }> {\n await Sandbox.start(name);\n this.registry.delete(name);\n await this.registry.ensure(name);\n return { name, status: \"running\" };\n }\n\n async stopSandbox(name: string): Promise<{ name: string; status: string }> {\n const native = await this.getOrEnsureNative(name);\n await native.stop();\n this.registry.delete(name);\n return { name, status: \"stopped\" };\n }\n\n async killSandbox(name: string): Promise<{ name: string; status: string }> {\n const native = await this.getOrEnsureNative(name);\n await native.kill();\n this.registry.delete(name);\n return { name, status: \"unknown\" };\n }\n\n async deleteSandbox(name: string): Promise<{ name: string; status: string }> {\n try {\n await this.getNative(name).kill();\n } catch {\n // Ignore missing cached native handle before remove.\n }\n\n await Sandbox.remove(name);\n this.registry.delete(name);\n\n return { name, status: \"unknown\" };\n }\n\n async listSandboxes(_query: ListSandboxesQuery): Promise<{\n items: Array<{\n name: string;\n status: string;\n image?: string;\n cpus?: number;\n memoryMib?: number;\n envCount: number;\n volumeCount: number;\n createdAt: string;\n updatedAt: string;\n }>;\n total: number;\n }> {\n const all: SandboxHandle[] = await Sandbox.list();\n\n const items = all\n .map((info) =>\n this.toListItem({\n name: info.name,\n status: info.status,\n configJson: info.configJson,\n createdAt: info.createdAt,\n updatedAt: info.updatedAt,\n })\n )\n .filter((item) => {\n if (_query.status && item.status !== _query.status) {\n return false;\n }\n\n if (_query.image && item.image !== _query.image) {\n return false;\n }\n\n if (_query.search) {\n const haystack = [item.name, item.image]\n .filter((value): value is string => Boolean(value))\n .join(\" \")\n .toLowerCase();\n\n if (!haystack.includes(_query.search.toLowerCase())) {\n return false;\n }\n }\n\n return true;\n });\n\n return { items, total: items.length };\n }\n\n async getSandbox(\n name: string\n ): Promise<{\n name: string;\n status: string;\n image?: string;\n cpus?: number;\n memoryMib?: number;\n env: Record<string, string>;\n volumes: Record<string, unknown>;\n metrics?: SandboxRuntimeMetrics;\n createdAt: string;\n updatedAt: string;\n } | undefined> {\n try {\n const handle: SandboxHandle = await Sandbox.get(name);\n const config = parseConfigJson(handle.configJson);\n let metrics: SandboxRuntimeMetrics | undefined;\n\n try {\n const m = await handle.metrics();\n metrics = {\n cpuPercent: m.cpuPercent,\n memoryBytes: m.memoryBytes,\n memoryLimitBytes: m.memoryLimitBytes,\n diskReadBytes: m.diskReadBytes,\n diskWriteBytes: m.diskWriteBytes,\n netRxBytes: m.netRxBytes,\n netTxBytes: m.netTxBytes,\n uptimeMs: m.uptimeMs,\n timestampMs: m.timestamp.getTime(),\n };\n } catch {\n metrics = undefined;\n }\n\n return {\n name: handle.name,\n status: handle.status,\n image: config.image,\n cpus: config.cpus,\n memoryMib: config.memoryMib,\n env: config.env ?? {},\n volumes: config.volumes ?? {},\n metrics,\n createdAt: msToIsoString(handle.createdAt),\n updatedAt: msToIsoString(handle.updatedAt),\n };\n } catch {\n return undefined;\n }\n }\n\n async getStatus(name: string): Promise<{ name: string; status: string }> {\n try {\n const handle: SandboxHandle = await Sandbox.get(name);\n return { name, status: handle.status };\n } catch {\n return { name, status: \"unknown\" };\n }\n }\n\n async readFile(sandboxName: string, path: string): Promise<{ path: string; content: string }> {\n const resolvedPath = this.resolvePath(path);\n const content = await this.getNative(sandboxName).fs().readToString(resolvedPath);\n return { path: resolvedPath, content };\n }\n\n async writeFile(sandboxName: string, path: string, content: string): Promise<{ path: string }> {\n const resolvedPath = this.resolvePath(path);\n await this.getNative(sandboxName).fs().write(resolvedPath, Buffer.from(content));\n return { path: resolvedPath };\n }\n\n async listPath(\n sandboxName: string,\n path: string,\n recursive?: boolean\n ): Promise<{ entries: Array<{ path: string; type: string }> }> {\n const resolvedPath = this.resolvePath(path);\n const entries = await this.getNative(sandboxName).fs().list(resolvedPath);\n return {\n entries: entries.map((entry) => ({\n path: entry.path,\n type: entry.kind,\n })),\n };\n }\n\n async findFiles(sandboxName: string, path: string, pattern: string): Promise<{ files: string[] }> {\n const resolvedPath = this.resolvePath(path);\n const output = await this.getNative(sandboxName).execWith(\"find\", (b) =>\n b.args([resolvedPath, \"-name\", pattern, \"-type\", \"f\"])\n );\n return { files: output.stdout().split(\"\\n\").filter(Boolean) };\n }\n\n async searchInFile(\n sandboxName: string,\n path: string,\n query: string\n ): Promise<{ matches: Array<{ line: number; content: string }> }> {\n const resolvedPath = this.resolvePath(path);\n let stdout: string;\n\n try {\n const output = await this.getNative(sandboxName).execWith(\"grep\", (b) =>\n b.args([\"-n\", \"-E\", query, resolvedPath])\n );\n stdout = output.stdout();\n } catch (error) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && error.code === 1) {\n return { matches: [] };\n }\n\n throw error;\n }\n\n return {\n matches: stdout\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => {\n const separator = line.indexOf(\":\");\n return {\n line: Number(line.slice(0, separator)),\n content: line.slice(separator + 1),\n };\n }),\n };\n }\n\n async replaceInFile(\n sandboxName: string,\n input: { path: string; search: string; replace: string }\n ): Promise<{ replaced: number }> {\n const resolvedPath = this.resolvePath(input.path);\n const fs = this.getNative(sandboxName).fs();\n const original = await fs.readToString(resolvedPath);\n\n if (!input.search) {\n return { replaced: 0 };\n }\n\n const occurrences = original.split(input.search).length - 1;\n if (occurrences === 0) {\n return { replaced: 0 };\n }\n\n const updated = original.split(input.search).join(input.replace);\n await fs.write(resolvedPath, Buffer.from(updated));\n\n return { replaced: occurrences };\n }\n\n async uploadFile(sandboxName: string, path: string, contentBase64: string): Promise<{ path: string }> {\n const resolvedPath = this.resolvePath(path);\n await this.getNative(sandboxName).fs().write(resolvedPath, Buffer.from(contentBase64, \"base64\"));\n return { path: resolvedPath };\n }\n\n async downloadFile(sandboxName: string, path: string): Promise<{ path: string; contentBase64: string }> {\n const resolvedPath = this.resolvePath(path);\n const data = await this.getNative(sandboxName).fs().read(resolvedPath);\n const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);\n return { path: resolvedPath, contentBase64: buffer.toString(\"base64\") };\n }\n\n async execCommand(input: ShellExecInput): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n const output = await this.getNative(input.sandboxName).execWith(\"sh\", (b) => {\n b.args([\"-c\", input.command]);\n if (input.exec_dir) b.cwd(input.exec_dir);\n if (input.timeout) b.timeout(input.timeout * 1000);\n return b;\n });\n\n return {\n stdout: output.stdout(),\n stderr: output.stderr(),\n exitCode: output.code ?? 0,\n };\n }\n}\n","import cors from \"@fastify/cors\";\nimport multipart from \"@fastify/multipart\";\nimport sensible from \"@fastify/sensible\";\nimport fastify, { type FastifyInstance } from \"fastify\";\nimport { toErrorResponse } from \"./lib/errors\";\nimport { registerHealthRoutes } from \"./routes/health\";\nimport { registerImageRoutes } from \"./routes/images\";\nimport { registerSandboxRoutes } from \"./routes/sandbox\";\nimport { registerVolumeFsRoutes } from \"./routes/volume-fs\";\nimport { ImageService } from \"./services/ImageService\";\nimport { MicrosandboxRuntimeService } from \"./services/MicrosandboxRuntimeService\";\nimport type { RuntimeService } from \"./types/runtime-service\";\n\nexport function buildApp({\n runtimeService = new MicrosandboxRuntimeService(),\n imageService = new ImageService(),\n apiKey,\n}: {\n runtimeService?: RuntimeService;\n imageService?: ImageService;\n apiKey?: string;\n} = {}): FastifyInstance {\n const app = fastify({ logger: false });\n\n app.register(cors, {\n delegator: (request, callback) => {\n callback(null, {\n origin: true,\n methods: request.headers[\"access-control-request-method\"] ?? \"*\",\n allowedHeaders: request.headers[\"access-control-request-headers\"],\n });\n },\n });\n app.register(sensible);\n app.register(multipart);\n\n if (apiKey) {\n app.addHook(\"onRequest\", async (request, reply) => {\n if (request.method === \"OPTIONS\" || !request.url.startsWith(\"/api/\")) {\n return;\n }\n\n if (request.headers.authorization !== `Bearer ${apiKey}`) {\n await reply.code(401).send({\n success: false,\n error: {\n code: \"UNAUTHORIZED\",\n message: \"Unauthorized\",\n },\n });\n }\n });\n }\n\n registerHealthRoutes(app);\n registerSandboxRoutes(app, runtimeService);\n registerImageRoutes(app, imageService);\n registerVolumeFsRoutes(app);\n\n app.setErrorHandler((error, _request, reply) => {\n const { statusCode, body } = toErrorResponse(error);\n reply.status(statusCode).send(body);\n });\n\n return app;\n}\n","export class HttpError extends Error {\n constructor(\n public statusCode: number,\n public code: string,\n message: string\n ) {\n super(message);\n }\n}\n\nexport function toErrorResponse(error: unknown): {\n statusCode: number;\n body: {\n success: false;\n error: {\n code: string;\n message: string;\n };\n };\n} {\n if (error instanceof HttpError) {\n return {\n statusCode: error.statusCode,\n body: {\n success: false,\n error: {\n code: error.code,\n message: error.message,\n },\n },\n };\n }\n\n return {\n statusCode: 500,\n body: {\n success: false,\n error: {\n code: \"INTERNAL_ERROR\",\n message: error instanceof Error ? error.message : String(error),\n },\n },\n };\n}\n","export type SuccessResponse<T> = {\n success: true;\n data: T;\n};\n\nexport function ok<T>(data: T): SuccessResponse<T> {\n return {\n success: true,\n data,\n };\n}\n","import type { FastifyInstance } from \"fastify\";\nimport { ok } from \"../lib/http\";\n\nexport function registerHealthRoutes(app: FastifyInstance): void {\n app.get(\"/health\", async () => ok({ status: \"ok\" }));\n}\n","import type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { ZodError } from \"zod\";\nimport { HttpError } from \"../lib/errors\";\nimport { ok } from \"../lib/http\";\nimport { ImageService } from \"../services/ImageService\";\nimport { imageRefQuerySchema, pullImageSchema } from \"../schemas/images\";\n\nfunction parseOrThrow<T>(parse: () => T): T {\n try {\n return parse();\n } catch (error) {\n if (error instanceof ZodError) {\n throw new HttpError(400, \"INVALID_REQUEST\", error.issues[0]?.message ?? \"Invalid request\");\n }\n\n throw error;\n }\n}\n\nexport function createImageController(imageService: ImageService) {\n return {\n listImages: async (_request: FastifyRequest, reply: FastifyReply) => {\n return reply.send(ok(await imageService.listImages()));\n },\n pullImage: async (request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply) => {\n const body = parseOrThrow(() => pullImageSchema.parse(request.body ?? {}));\n return reply.send(ok(await imageService.pullImage(body)));\n },\n getImage: async (request: FastifyRequest<{ Querystring: unknown }>, reply: FastifyReply) => {\n const query = parseOrThrow(() => imageRefQuerySchema.parse(request.query ?? {}));\n return reply.send(ok(await imageService.getImage(query.ref)));\n },\n deleteImage: async (request: FastifyRequest<{ Querystring: unknown }>, reply: FastifyReply) => {\n const query = parseOrThrow(() => imageRefQuerySchema.parse(request.query ?? {}));\n return reply.send(ok(await imageService.deleteImage(query.ref)));\n },\n };\n}\n","import z from \"zod\";\n\nexport const imageRefQuerySchema = z.object({\n ref: z.string().min(1),\n});\n\nexport const pullImageSchema = z.object({\n ref: z.string().min(1),\n});\n\nexport type ImageRefQuery = z.infer<typeof imageRefQuerySchema>;\nexport type PullImageInput = z.infer<typeof pullImageSchema>;\n","import type { FastifyInstance } from \"fastify\";\nimport { createImageController } from \"../controllers/images\";\nimport { ImageService } from \"../services/ImageService\";\n\nexport function registerImageRoutes(app: FastifyInstance, imageService: ImageService): void {\n const controller = createImageController(imageService);\n\n app.get(\"/api/images\", controller.listImages);\n app.post(\"/api/images/pull\", controller.pullImage);\n app.get(\"/api/images/detail\", controller.getImage);\n app.delete(\"/api/images/detail\", controller.deleteImage);\n}\n","import z from \"zod\";\n\nconst bindMountSchema = z.object({\n type: z.literal(\"bind\"),\n source: z.string().min(1),\n readonly: z.boolean().optional(),\n});\n\nconst namedMountSchema = z.object({\n type: z.literal(\"named\"),\n name: z.string().min(1),\n readonly: z.boolean().optional(),\n});\n\nconst tmpfsMountSchema = z.object({\n type: z.literal(\"tmpfs\"),\n sizeMib: z.number().int().positive().optional(),\n});\n\nexport const volumeSchema = z.union([\n bindMountSchema,\n namedMountSchema,\n tmpfsMountSchema,\n]);\n\nexport const ensureSandboxSchema = z.object({\n image: z.string().optional(),\n cpus: z.number().int().positive().optional(),\n memoryMib: z.number().int().positive().optional(),\n env: z.record(z.string()).optional(),\n volumes: z.record(volumeSchema).optional(),\n});\n\nexport const sandboxNameParamsSchema = z.object({\n name: z.string().min(1),\n});\n\nexport const listSandboxesQuerySchema = z.object({\n status: z.enum([\"running\", \"stopped\", \"crashed\", \"unknown\"]).optional(),\n image: z.string().min(1).optional(),\n search: z.string().min(1).optional(),\n});\n\nconst sandboxAndPathSchema = z.object({\n sandboxName: z.string().min(1),\n path: z.string().min(1),\n});\n\nexport const readFileSchema = sandboxAndPathSchema;\n\nexport const writeFileSchema = sandboxAndPathSchema.extend({\n content: z.string(),\n});\n\nexport const listPathSchema = sandboxAndPathSchema.extend({\n recursive: z.boolean().optional(),\n});\n\nexport const findFilesSchema = sandboxAndPathSchema.extend({\n pattern: z.string().min(1),\n});\n\nexport const searchInFileSchema = sandboxAndPathSchema.extend({\n query: z.string().min(1),\n});\n\nexport const replaceInFileSchema = sandboxAndPathSchema.extend({\n search: z.string(),\n replace: z.string(),\n});\n\nexport const uploadFileSchema = sandboxAndPathSchema.and(\n z.union([\n z.object({ contentBase64: z.string() }),\n z.object({ content: z.string().transform((content) => Buffer.from(content).toString(\"base64\")) }),\n ])\n);\n\nexport const downloadFileSchema = sandboxAndPathSchema;\n\nexport const shellExecSchema = z.object({\n sandboxName: z.string().min(1),\n command: z.string().min(1),\n exec_dir: z.string().optional(),\n timeout: z.number().int().positive().optional(),\n});\n\nexport type EnsureSandboxInput = z.infer<typeof ensureSandboxSchema>;\nexport type ListSandboxesQuery = z.infer<typeof listSandboxesQuerySchema>;\nexport type ShellExecInput = z.infer<typeof shellExecSchema>;\n","import type { FastifyReply, FastifyRequest } from \"fastify\";\nimport {\n downloadFileSchema,\n ensureSandboxSchema,\n findFilesSchema,\n listSandboxesQuerySchema,\n listPathSchema,\n readFileSchema,\n replaceInFileSchema,\n sandboxNameParamsSchema,\n searchInFileSchema,\n shellExecSchema,\n uploadFileSchema,\n writeFileSchema,\n} from \"../schemas/sandbox\";\nimport { HttpError } from \"../lib/errors\";\nimport { ok } from \"../lib/http\";\nimport type { RuntimeService } from \"../types/runtime-service\";\n\nexport function createSandboxController(runtimeService: RuntimeService): {\n ensureSandbox(\n request: FastifyRequest<{ Params: { name: string }; Body: unknown }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n startSandbox(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n stopSandbox(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n killSandbox(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n deleteSandbox(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n listSandboxes(\n request: FastifyRequest<{ Querystring: unknown }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n getSandbox(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n getStatus(\n request: FastifyRequest<{ Params: { name: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n readFile(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n writeFile(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n listPath(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n findFiles(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n searchInFile(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n replaceInFile(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n uploadFile(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n downloadFile(\n request: FastifyRequest<{ Querystring: unknown }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n execCommand(request: FastifyRequest<{ Body: unknown }>, reply: FastifyReply): Promise<FastifyReply>;\n} {\n return {\n ensureSandbox: async (\n request: FastifyRequest<{ Params: { name: string }; Body: unknown }>,\n reply: FastifyReply\n ) => {\n const body = ensureSandboxSchema.parse(request.body ?? {});\n const result = await runtimeService.ensureSandbox(request.params.name, body);\n return reply.send(ok(result));\n },\n\n startSandbox: async (request, reply) => {\n return reply.send(ok(await runtimeService.startSandbox(request.params.name)));\n },\n\n stopSandbox: async (request, reply) => {\n return reply.send(ok(await runtimeService.stopSandbox(request.params.name)));\n },\n\n killSandbox: async (request, reply) => {\n return reply.send(ok(await runtimeService.killSandbox(request.params.name)));\n },\n\n deleteSandbox: async (request, reply) => {\n return reply.send(ok(await runtimeService.deleteSandbox(request.params.name)));\n },\n\n listSandboxes: async (request, reply) => {\n const query = listSandboxesQuerySchema.parse(request.query ?? {});\n return reply.send(ok(await runtimeService.listSandboxes(query)));\n },\n\n getSandbox: async (request, reply) => {\n const params = sandboxNameParamsSchema.parse(request.params ?? {});\n const sandbox = await runtimeService.getSandbox(params.name);\n\n if (!sandbox) {\n throw new HttpError(404, \"SANDBOX_NOT_FOUND\", `Sandbox '${params.name}' not found`);\n }\n\n return reply.send(ok(sandbox));\n },\n\n getStatus: async (request, reply) => {\n return reply.send(ok(await runtimeService.getStatus(request.params.name)));\n },\n\n readFile: async (request, reply) => {\n const body = readFileSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.readFile(body.sandboxName, body.path)));\n },\n\n writeFile: async (request, reply) => {\n const body = writeFileSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.writeFile(body.sandboxName, body.path, body.content)));\n },\n\n listPath: async (request, reply) => {\n const body = listPathSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.listPath(body.sandboxName, body.path, body.recursive)));\n },\n\n findFiles: async (request, reply) => {\n const body = findFilesSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.findFiles(body.sandboxName, body.path, body.pattern)));\n },\n\n searchInFile: async (request, reply) => {\n const body = searchInFileSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.searchInFile(body.sandboxName, body.path, body.query)));\n },\n\n replaceInFile: async (request, reply) => {\n const body = replaceInFileSchema.parse(request.body ?? {});\n return reply.send(\n ok(\n await runtimeService.replaceInFile(body.sandboxName, {\n path: body.path,\n search: body.search,\n replace: body.replace,\n })\n )\n );\n },\n\n uploadFile: async (request, reply) => {\n const body = uploadFileSchema.parse(request.body ?? {});\n const contentBase64 = \"contentBase64\" in body ? body.contentBase64 : Buffer.from(body.content).toString(\"base64\");\n return reply.send(ok(await runtimeService.uploadFile(body.sandboxName, body.path, contentBase64)));\n },\n\n downloadFile: async (request, reply) => {\n const query = downloadFileSchema.parse(request.query ?? {});\n return reply.send(ok(await runtimeService.downloadFile(query.sandboxName, query.path)));\n },\n\n execCommand: async (request, reply) => {\n const body = shellExecSchema.parse(request.body ?? {});\n return reply.send(ok(await runtimeService.execCommand(body)));\n },\n };\n}\n","import type { FastifyInstance } from \"fastify\";\nimport { createSandboxController } from \"../controllers/sandbox\";\nimport type { RuntimeService } from \"../types/runtime-service\";\n\nexport function registerSandboxRoutes(\n app: FastifyInstance,\n runtimeService: RuntimeService\n): void {\n const controller = createSandboxController(runtimeService);\n\n app.get(\"/api/sandboxes\", controller.listSandboxes);\n app.get(\"/api/sandboxes/:name\", controller.getSandbox);\n app.put(\"/api/sandboxes/:name\", controller.ensureSandbox);\n app.post(\"/api/sandboxes/:name/start\", controller.startSandbox);\n app.post(\"/api/sandboxes/:name/stop\", controller.stopSandbox);\n app.post(\"/api/sandboxes/:name/kill\", controller.killSandbox);\n app.delete(\"/api/sandboxes/:name\", controller.deleteSandbox);\n app.get(\"/api/sandboxes/:name/status\", controller.getStatus);\n\n app.post(\"/api/files/read\", controller.readFile);\n app.post(\"/api/files/write\", controller.writeFile);\n app.post(\"/api/files/list\", controller.listPath);\n app.post(\"/api/files/find\", controller.findFiles);\n app.post(\"/api/files/search\", controller.searchInFile);\n app.post(\"/api/files/replace\", controller.replaceInFile);\n app.post(\"/api/files/upload\", controller.uploadFile);\n app.get(\"/api/files/download\", controller.downloadFile);\n\n app.post(\"/api/shell/exec\", controller.execCommand);\n}\n","import type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { Volume } from \"microsandbox\";\nimport z from \"zod\";\nimport { HttpError } from \"../lib/errors\";\nimport { ok } from \"../lib/http\";\nimport {\n volumeFsReadSchema,\n volumeFsWriteSchema,\n volumeFsListSchema,\n volumeFsUploadSchema,\n volumeFsDownloadSchema,\n} from \"../schemas/volume-fs\";\n\ninterface VolumeFsParams {\n name: string;\n}\n\nexport function createVolumeFsController(): {\n readFile(\n request: FastifyRequest<{ Params: VolumeFsParams; Body: { path: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n writeFile(\n request: FastifyRequest<{ Params: VolumeFsParams; Body: { path: string; content: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n listPath(\n request: FastifyRequest<{ Params: VolumeFsParams; Body: { path: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n downloadFile(\n request: FastifyRequest<{ Params: VolumeFsParams; Querystring: { path: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n uploadFile(\n request: FastifyRequest<{ Params: VolumeFsParams; Body: { path: string; contentBase64: string } }>,\n reply: FastifyReply\n ): Promise<FastifyReply>;\n} {\n return {\n readFile: async (request, reply) => {\n const { name } = request.params;\n\n try {\n const { path } = volumeFsReadSchema.parse(request.body ?? {});\n const vfs = (await Volume.get(name)).fs();\n const content = await vfs.readToString(path);\n return reply.send(ok({ path, content }));\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new HttpError(400, \"VALIDATION_ERROR\", err.message);\n }\n throw new HttpError(404, \"VOLUME_READ_ERROR\", `Failed to read from volume '${name}': ${String(err)}`);\n }\n },\n\n writeFile: async (request, reply) => {\n const { name } = request.params;\n\n try {\n const { path, content } = volumeFsWriteSchema.parse(request.body ?? {});\n const vfs = (await Volume.get(name)).fs();\n await vfs.write(path, content);\n return reply.send(ok({ path }));\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new HttpError(400, \"VALIDATION_ERROR\", err.message);\n }\n throw new HttpError(500, \"VOLUME_WRITE_ERROR\", `Failed to write to volume '${name}': ${String(err)}`);\n }\n },\n\n listPath: async (request, reply) => {\n const { name } = request.params;\n\n try {\n const { path } = volumeFsListSchema.parse(request.body ?? {});\n const vfs = (await Volume.get(name)).fs();\n const entries = await vfs.list(path);\n return reply.send(ok({ entries }));\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new HttpError(400, \"VALIDATION_ERROR\", err.message);\n }\n throw new HttpError(404, \"VOLUME_LIST_ERROR\", `Failed to list volume '${name}': ${String(err)}`);\n }\n },\n\n downloadFile: async (request, reply) => {\n const { name } = request.params;\n\n try {\n const { path } = volumeFsDownloadSchema.parse(request.query ?? {});\n const vfs = (await Volume.get(name)).fs();\n const buf = await vfs.read(path);\n const contentBase64 = Buffer.from(buf).toString(\"base64\");\n return reply.send(ok({ path, contentBase64 }));\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new HttpError(400, \"VALIDATION_ERROR\", err.message);\n }\n throw new HttpError(404, \"VOLUME_DOWNLOAD_ERROR\", `Failed to download from volume '${name}': ${String(err)}`);\n }\n },\n\n uploadFile: async (request, reply) => {\n const { name } = request.params;\n\n try {\n const { path, contentBase64 } = volumeFsUploadSchema.parse(request.body ?? {});\n const vfs = (await Volume.get(name)).fs();\n const data = Buffer.from(contentBase64, \"base64\");\n await vfs.write(path, data);\n return reply.send(ok({ path }));\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n throw new HttpError(400, \"VALIDATION_ERROR\", err.message);\n }\n throw new HttpError(500, \"VOLUME_UPLOAD_ERROR\", `Failed to upload to volume '${name}': ${String(err)}`);\n }\n },\n };\n}\n","import z from \"zod\";\n\nexport const volumeFsReadSchema = z.object({\n path: z.string().min(1),\n});\n\nexport const volumeFsWriteSchema = z.object({\n path: z.string().min(1),\n content: z.string(),\n});\n\nexport const volumeFsListSchema = z.object({\n path: z.string().min(1),\n});\n\nexport const volumeFsUploadSchema = z.object({\n path: z.string().min(1),\n contentBase64: z.string().min(1),\n});\n\nexport const volumeFsDownloadSchema = z.object({\n path: z.string().min(1),\n});\n","import type { FastifyInstance } from \"fastify\";\nimport { createVolumeFsController } from \"../controllers/volume-fs\";\n\nexport function registerVolumeFsRoutes(app: FastifyInstance): void {\n const controller = createVolumeFsController();\n\n app.post(\"/api/volumes/:name/fs/read\", controller.readFile);\n app.post(\"/api/volumes/:name/fs/write\", controller.writeFile);\n app.post(\"/api/volumes/:name/fs/list\", controller.listPath);\n app.get(\"/api/volumes/:name/fs/download\", controller.downloadFile);\n app.post(\"/api/volumes/:name/fs/upload\", controller.uploadFile);\n}\n","import { exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { PullImageInput } from \"../schemas/images\";\n\nconst execAsync = promisify(exec);\n\nexport type ImageRecord = {\n ref: string;\n sourceType: string;\n cached: boolean;\n size?: number;\n createdAt?: string;\n lastUsedAt?: string;\n};\n\ntype ImageBindings = {\n list(): Promise<ImageRecord[]>;\n pull(ref: string): Promise<ImageRecord>;\n inspect(ref: string): Promise<ImageRecord>;\n remove(ref: string): Promise<void>;\n};\n\ntype CliImageInfo = {\n architecture: string;\n created_at: string;\n digest: string;\n layer_count: number;\n os: string;\n reference: string;\n size_bytes: number;\n};\n\nfunction getMsbPath(): string {\n return process.env.MICROSANDBOX_CLI_PATH || `${process.env.HOME}/.microsandbox/bin/msb`;\n}\n\nclass MicrosandboxImageBindings implements ImageBindings {\n private get msb(): string {\n return getMsbPath();\n }\n\n async list(): Promise<ImageRecord[]> {\n const { stdout } = await execAsync(`${this.msb} image ls --format json`);\n const images: CliImageInfo[] = JSON.parse(stdout);\n return images.map((img) => ({\n ref: img.reference,\n sourceType: \"oci\",\n cached: true,\n size: img.size_bytes,\n createdAt: img.created_at,\n }));\n }\n\n async pull(ref: string): Promise<ImageRecord> {\n await execAsync(`${this.msb} image pull ${ref}`);\n return this.inspect(ref);\n }\n\n async inspect(ref: string): Promise<ImageRecord> {\n const { stdout } = await execAsync(`${this.msb} image inspect ${ref} --format json`);\n const img: CliImageInfo = JSON.parse(stdout);\n return {\n ref: img.reference,\n sourceType: \"oci\",\n cached: true,\n size: img.size_bytes,\n createdAt: img.created_at,\n };\n }\n\n async remove(ref: string): Promise<void> {\n await execAsync(`${this.msb} image rm ${ref}`);\n }\n}\n\nexport class ImageService {\n constructor(\n private readonly deps: {\n bindings?: ImageBindings;\n } = {}\n ) {}\n\n private get bindings(): ImageBindings {\n return this.deps.bindings ?? new MicrosandboxImageBindings();\n }\n\n async listImages(): Promise<{ items: ImageRecord[]; total: number }> {\n const items = await this.bindings.list();\n return { items, total: items.length };\n }\n\n async pullImage(input: PullImageInput): Promise<ImageRecord> {\n return await this.bindings.pull(input.ref);\n }\n\n async getImage(ref: string): Promise<ImageRecord> {\n return await this.bindings.inspect(ref);\n }\n\n async deleteImage(ref: string): Promise<{ ref: string }> {\n await this.bindings.remove(ref);\n return { ref };\n }\n}\n"],"mappings":"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","names":["Sandbox","Sandbox","z","Volume","z","z","Volume","z"]}
|