@drej/flue 1.0.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,30 @@
1
+ import { SandboxFactory } from "@flue/runtime";
2
+ import { Sandbox } from "drej";
3
+
4
+ //#region src/index.d.ts
5
+ /**
6
+ * Flue `SandboxFactory` backed by a drej `Sandbox`.
7
+ *
8
+ * Pass an already-created `Sandbox` (lifecycle is the caller's responsibility —
9
+ * the adapter never calls `sb.close()`). Returns a factory suitable for
10
+ * Flue's `sandbox` agent option.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // src/sandboxes/drej.ts (Flue adapter file)
15
+ * import { drej } from "@drej/flue";
16
+ * import { Drej } from "drej";
17
+ * import { SQLiteAdapter } from "@drej/sqlite";
18
+ *
19
+ * const client = new Drej({ baseUrl: "http://localhost:8080", adapter: new SQLiteAdapter("./drej.db") });
20
+ *
21
+ * export default drej(
22
+ * await client.sandbox({ image: "node:22", resources: { cpu: "500m", memory: "256Mi" } }),
23
+ * );
24
+ * ```
25
+ */
26
+ declare function drej(sandbox: Sandbox, opts?: {
27
+ cwd?: string;
28
+ }): SandboxFactory;
29
+ //#endregion
30
+ export { drej };
package/dist/index.mjs ADDED
@@ -0,0 +1,113 @@
1
+ import { createSandboxSessionEnv } from "@flue/runtime";
2
+ //#region src/index.ts
3
+ function esc(p) {
4
+ return `'${p.replace(/'/g, "'\\''")}'`;
5
+ }
6
+ function rejectAfter(ms) {
7
+ return new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`exec timed out after ${ms}ms`)), ms));
8
+ }
9
+ function uint8ToBase64(buf) {
10
+ let binary = "";
11
+ for (let i = 0; i < buf.length; i++) binary += String.fromCharCode(buf[i]);
12
+ return btoa(binary);
13
+ }
14
+ function base64ToUint8(b64) {
15
+ const binary = atob(b64);
16
+ const buf = new Uint8Array(binary.length);
17
+ for (let i = 0; i < binary.length; i++) buf[i] = binary.charCodeAt(i);
18
+ return buf;
19
+ }
20
+ var DrejSandboxApi = class {
21
+ sb;
22
+ constructor(sb) {
23
+ this.sb = sb;
24
+ }
25
+ async exec(command, opts) {
26
+ const run = Promise.resolve(this.sb.exec(command, {
27
+ cwd: opts?.cwd,
28
+ env: opts?.env,
29
+ strict: false
30
+ }));
31
+ if (opts?.timeoutMs == null) return run;
32
+ return Promise.race([run, rejectAfter(Math.ceil(opts.timeoutMs))]);
33
+ }
34
+ readFile(path) {
35
+ return this.sb.readFile(path);
36
+ }
37
+ async readFileBuffer(path) {
38
+ const { stdout } = await this.sb.exec(`base64 -w0 ${esc(path)}`);
39
+ return base64ToUint8(stdout.trim());
40
+ }
41
+ /**
42
+ * Write a file into the sandbox.
43
+ *
44
+ * When `content` is a `Uint8Array`, the bytes are base64-encoded and piped
45
+ * through `base64 -d` in the container. This relies on the shell `ARG_MAX`
46
+ * limit (~2 MB on Linux), so binary writes are capped at roughly **1.5 MB**.
47
+ * For larger binary files, write via string (pre-encoded) or split writes.
48
+ */
49
+ async writeFile(path, content) {
50
+ if (typeof content === "string") {
51
+ await this.sb.writeFile(path, content);
52
+ return;
53
+ }
54
+ const b64 = uint8ToBase64(content);
55
+ await this.sb.exec(`echo '${b64}' | base64 -d > ${esc(path)}`);
56
+ }
57
+ async stat(path) {
58
+ const { stdout, exitCode } = await this.sb.exec(`stat -c '%F|%s|%Y' ${esc(path)}`, { strict: false });
59
+ if (exitCode !== 0) throw new Error(`stat: cannot stat '${path}': No such file or directory`);
60
+ const [typeStr, sizeStr, mtimeStr] = stdout.trim().split("|");
61
+ return {
62
+ isFile: typeStr === "regular file",
63
+ isDirectory: typeStr === "directory",
64
+ isSymbolicLink: typeStr === "symbolic link",
65
+ size: parseInt(sizeStr, 10),
66
+ mtime: /* @__PURE__ */ new Date(parseInt(mtimeStr, 10) * 1e3)
67
+ };
68
+ }
69
+ async readdir(path) {
70
+ const entries = await this.sb.listDirectory(path, { depth: 1 });
71
+ const prefix = (path.endsWith("/") ? path.slice(0, -1) : path) + "/";
72
+ return entries.filter((e) => e.path.startsWith(prefix) && !e.path.slice(prefix.length).includes("/")).map((e) => e.path.slice(prefix.length)).filter(Boolean);
73
+ }
74
+ async exists(path) {
75
+ const { exitCode } = await this.sb.exec(`test -e ${esc(path)}`, { strict: false });
76
+ return exitCode === 0;
77
+ }
78
+ async mkdir(path, opts) {
79
+ await this.sb.exec(`mkdir ${opts?.recursive ? "-p " : ""}${esc(path)}`);
80
+ }
81
+ async rm(path, opts) {
82
+ const flags = [opts?.recursive && "-r", opts?.force && "-f"].filter(Boolean).join(" ");
83
+ await this.sb.exec(`rm ${flags ? flags + " " : ""}${esc(path)}`);
84
+ }
85
+ };
86
+ /**
87
+ * Flue `SandboxFactory` backed by a drej `Sandbox`.
88
+ *
89
+ * Pass an already-created `Sandbox` (lifecycle is the caller's responsibility —
90
+ * the adapter never calls `sb.close()`). Returns a factory suitable for
91
+ * Flue's `sandbox` agent option.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * // src/sandboxes/drej.ts (Flue adapter file)
96
+ * import { drej } from "@drej/flue";
97
+ * import { Drej } from "drej";
98
+ * import { SQLiteAdapter } from "@drej/sqlite";
99
+ *
100
+ * const client = new Drej({ baseUrl: "http://localhost:8080", adapter: new SQLiteAdapter("./drej.db") });
101
+ *
102
+ * export default drej(
103
+ * await client.sandbox({ image: "node:22", resources: { cpu: "500m", memory: "256Mi" } }),
104
+ * );
105
+ * ```
106
+ */
107
+ function drej(sandbox, opts) {
108
+ return { async createSessionEnv(_) {
109
+ return createSandboxSessionEnv(new DrejSandboxApi(sandbox), opts?.cwd ?? "/");
110
+ } };
111
+ }
112
+ //#endregion
113
+ export { drej };
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@drej/flue",
3
+ "version": "1.0.0",
4
+ "files": [
5
+ "dist"
6
+ ],
7
+ "type": "module",
8
+ "main": "./dist/index.mjs",
9
+ "types": "./dist/index.d.mts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.mjs",
13
+ "types": "./dist/index.d.mts"
14
+ }
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "build": "tsdown",
21
+ "test": "bun test"
22
+ },
23
+ "devDependencies": {
24
+ "@flue/runtime": "1.0.0-beta.3",
25
+ "bun-types": "1.3.14",
26
+ "drej": "workspace:*",
27
+ "tsdown": "0.22.3",
28
+ "typescript": "6.0.3"
29
+ },
30
+ "peerDependencies": {
31
+ "@flue/runtime": ">=1.0.0-beta",
32
+ "drej": ">=0.8.0"
33
+ }
34
+ }