@sapiom/tools 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.
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/dist/cjs/_client/index.d.ts +68 -0
- package/dist/cjs/_client/index.d.ts.map +1 -0
- package/dist/cjs/_client/index.js +115 -0
- package/dist/cjs/_client/index.js.map +1 -0
- package/dist/cjs/agent/index.d.ts +90 -0
- package/dist/cjs/agent/index.d.ts.map +1 -0
- package/dist/cjs/agent/index.js +108 -0
- package/dist/cjs/agent/index.js.map +1 -0
- package/dist/cjs/client.d.ts +51 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +50 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/index.d.ts +22 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +59 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/repositories/index.d.ts +59 -0
- package/dist/cjs/repositories/index.d.ts.map +1 -0
- package/dist/cjs/repositories/index.js +107 -0
- package/dist/cjs/repositories/index.js.map +1 -0
- package/dist/cjs/sandboxes/index.d.ts +67 -0
- package/dist/cjs/sandboxes/index.d.ts.map +1 -0
- package/dist/cjs/sandboxes/index.js +255 -0
- package/dist/cjs/sandboxes/index.js.map +1 -0
- package/dist/cjs/sandboxes/types.d.ts +111 -0
- package/dist/cjs/sandboxes/types.d.ts.map +1 -0
- package/dist/cjs/sandboxes/types.js +3 -0
- package/dist/cjs/sandboxes/types.js.map +1 -0
- package/dist/esm/_client/index.d.ts +68 -0
- package/dist/esm/_client/index.d.ts.map +1 -0
- package/dist/esm/_client/index.js +110 -0
- package/dist/esm/_client/index.js.map +1 -0
- package/dist/esm/agent/index.d.ts +90 -0
- package/dist/esm/agent/index.d.ts.map +1 -0
- package/dist/esm/agent/index.js +103 -0
- package/dist/esm/agent/index.js.map +1 -0
- package/dist/esm/client.d.ts +51 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +47 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/index.d.ts +22 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/repositories/index.d.ts +59 -0
- package/dist/esm/repositories/index.d.ts.map +1 -0
- package/dist/esm/repositories/index.js +99 -0
- package/dist/esm/repositories/index.js.map +1 -0
- package/dist/esm/sandboxes/index.d.ts +67 -0
- package/dist/esm/sandboxes/index.d.ts.map +1 -0
- package/dist/esm/sandboxes/index.js +249 -0
- package/dist/esm/sandboxes/index.js.map +1 -0
- package/dist/esm/sandboxes/types.d.ts +111 -0
- package/dist/esm/sandboxes/types.d.ts.map +1 -0
- package/dist/esm/sandboxes/types.js +2 -0
- package/dist/esm/sandboxes/types.js.map +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +69 -0
- package/src/agent/README.md +36 -0
- package/src/repositories/README.md +29 -0
- package/src/sandboxes/README.md +30 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@sapiom/tools` — the typed Sapiom capability client.
|
|
3
|
+
*
|
|
4
|
+
* The same catalog your agents call over MCP, callable from code. Capabilities are
|
|
5
|
+
* namespaces (`sandboxes`, `repositories`, `agent`, … ), importable from the barrel
|
|
6
|
+
* or a subpath:
|
|
7
|
+
*
|
|
8
|
+
* import { sandboxes } from "@sapiom/tools";
|
|
9
|
+
* import { sandboxes } from "@sapiom/tools/sandboxes";
|
|
10
|
+
*
|
|
11
|
+
* Auth is implicit: ambient (engine-injected) inside a workflow step, or explicit
|
|
12
|
+
* via `createClient({ apiKey })` standalone.
|
|
13
|
+
*/
|
|
14
|
+
export { createClient } from "./client.js";
|
|
15
|
+
export type { Sapiom } from "./client.js";
|
|
16
|
+
export type { TransportConfig, Attribution } from "./_client/index.js";
|
|
17
|
+
export * as sandboxes from "./sandboxes/index.js";
|
|
18
|
+
export { Sandbox } from "./sandboxes/index.js";
|
|
19
|
+
export * as repositories from "./repositories/index.js";
|
|
20
|
+
export { Repository } from "./repositories/index.js";
|
|
21
|
+
export * as agent from "./agent/index.js";
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEvE,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,KAAK,YAAY,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@sapiom/tools` — the typed Sapiom capability client.
|
|
3
|
+
*
|
|
4
|
+
* The same catalog your agents call over MCP, callable from code. Capabilities are
|
|
5
|
+
* namespaces (`sandboxes`, `repositories`, `agent`, … ), importable from the barrel
|
|
6
|
+
* or a subpath:
|
|
7
|
+
*
|
|
8
|
+
* import { sandboxes } from "@sapiom/tools";
|
|
9
|
+
* import { sandboxes } from "@sapiom/tools/sandboxes";
|
|
10
|
+
*
|
|
11
|
+
* Auth is implicit: ambient (engine-injected) inside a workflow step, or explicit
|
|
12
|
+
* via `createClient({ apiKey })` standalone.
|
|
13
|
+
*/
|
|
14
|
+
export { createClient } from "./client.js";
|
|
15
|
+
export * as sandboxes from "./sandboxes/index.js";
|
|
16
|
+
export { Sandbox } from "./sandboxes/index.js";
|
|
17
|
+
export * as repositories from "./repositories/index.js";
|
|
18
|
+
export { Repository } from "./repositories/index.js";
|
|
19
|
+
export * as agent from "./agent/index.js";
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,OAAO,KAAK,YAAY,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "module"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `repositories` capability — in-network git repos: create, get, list, delete, and
|
|
3
|
+
* the first cross-capability mesh method, `repo.pushFromSandbox(sandbox)`.
|
|
4
|
+
*
|
|
5
|
+
* import { repositories } from "@sapiom/tools";
|
|
6
|
+
* const repo = await repositories.create("my-app");
|
|
7
|
+
* // … an agent or your code writes files in a sandbox checkout of the repo …
|
|
8
|
+
* await repo.pushFromSandbox(box, { message: "build: page" });
|
|
9
|
+
*
|
|
10
|
+
* `pushFromSandbox` is the deterministic counterpart to a fuzzy agent step: it
|
|
11
|
+
* composes the `sandboxes` capability (calls `sandbox.exec`) to commit + push the
|
|
12
|
+
* repo's working tree. It references the `Sandbox` TYPE only — no module cycle.
|
|
13
|
+
*
|
|
14
|
+
* Note: `cloneUrl` is the unauthenticated origin. The gateway authenticates clones
|
|
15
|
+
* via basic-auth (the `auth` block returned by create); inside an agent run the
|
|
16
|
+
* `gitRepository` auto-clone wires that credential into the in-sandbox origin, so
|
|
17
|
+
* `pushFromSandbox` doesn't need it.
|
|
18
|
+
*/
|
|
19
|
+
import { Transport } from "../_client/index.js";
|
|
20
|
+
import type { Sandbox } from "../sandboxes/index.js";
|
|
21
|
+
export interface PushResult {
|
|
22
|
+
/** False when there was nothing to commit. */
|
|
23
|
+
pushed: boolean;
|
|
24
|
+
sha: string | null;
|
|
25
|
+
}
|
|
26
|
+
/** A connected in-network repository. */
|
|
27
|
+
export declare class Repository {
|
|
28
|
+
readonly slug: string;
|
|
29
|
+
/** Unauthenticated clone origin (see module note on auth). */
|
|
30
|
+
readonly cloneUrl: string;
|
|
31
|
+
readonly status: string;
|
|
32
|
+
private readonly transport;
|
|
33
|
+
private readonly baseUrl;
|
|
34
|
+
private constructor();
|
|
35
|
+
static create(slug: string, transport?: Transport, baseUrl?: string): Promise<Repository>;
|
|
36
|
+
static get(slug: string, transport?: Transport, baseUrl?: string): Promise<Repository>;
|
|
37
|
+
static list(transport?: Transport, baseUrl?: string): Promise<Repository[]>;
|
|
38
|
+
static delete(slug: string, transport?: Transport, baseUrl?: string): Promise<void>;
|
|
39
|
+
/** Adopt a known repo without a round-trip (e.g. one returned from another step). */
|
|
40
|
+
static attach(slug: string, cloneUrl: string, transport?: Transport, baseUrl?: string): Repository;
|
|
41
|
+
/** Delete this repository. */
|
|
42
|
+
delete(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Deterministically stage + commit + push this repo's working tree FROM a
|
|
45
|
+
* sandbox checkout (no LLM). Assumes the repo is checked out at the canonical
|
|
46
|
+
* `/workspace/<slug>` with an authenticated `origin` (which the agent's
|
|
47
|
+
* `gitRepository` auto-clone sets up). No-op when there's nothing to commit.
|
|
48
|
+
*/
|
|
49
|
+
pushFromSandbox(sandbox: Sandbox, opts?: {
|
|
50
|
+
message?: string;
|
|
51
|
+
}): Promise<PushResult>;
|
|
52
|
+
}
|
|
53
|
+
export declare function create(slug: string): Promise<Repository>;
|
|
54
|
+
export declare function get(slug: string): Promise<Repository>;
|
|
55
|
+
export declare function list(): Promise<Repository[]>;
|
|
56
|
+
export declare function attach(slug: string, cloneUrl: string): Repository;
|
|
57
|
+
declare function deleteRepository(slug: string): Promise<void>;
|
|
58
|
+
export { deleteRepository as delete };
|
|
59
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/repositories/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,SAAS,EAAoB,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAuBrD,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,yCAAyC;AACzC,qBAAa,UAAU;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO;WAYM,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,SAA8B,EAAE,OAAO,SAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;WAShH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,SAA8B,EAAE,OAAO,SAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;WAK7G,IAAI,CAAC,SAAS,GAAE,SAA8B,EAAE,OAAO,SAAmB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;WAKlG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,SAA8B,EAAE,OAAO,SAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvH,qFAAqF;IACrF,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,GAAE,SAA8B,EAAE,OAAO,SAAmB,GAAG,UAAU;IAIhI,8BAA8B;IAC9B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;;;OAKG;IACG,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;CAgB9F;AAGD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAExD;AACD,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAErD;AACD,wBAAgB,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAE5C;AACD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAEjE;AACD,iBAAS,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AACD,OAAO,EAAE,gBAAgB,IAAI,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `repositories` capability — in-network git repos: create, get, list, delete, and
|
|
3
|
+
* the first cross-capability mesh method, `repo.pushFromSandbox(sandbox)`.
|
|
4
|
+
*
|
|
5
|
+
* import { repositories } from "@sapiom/tools";
|
|
6
|
+
* const repo = await repositories.create("my-app");
|
|
7
|
+
* // … an agent or your code writes files in a sandbox checkout of the repo …
|
|
8
|
+
* await repo.pushFromSandbox(box, { message: "build: page" });
|
|
9
|
+
*
|
|
10
|
+
* `pushFromSandbox` is the deterministic counterpart to a fuzzy agent step: it
|
|
11
|
+
* composes the `sandboxes` capability (calls `sandbox.exec`) to commit + push the
|
|
12
|
+
* repo's working tree. It references the `Sandbox` TYPE only — no module cycle.
|
|
13
|
+
*
|
|
14
|
+
* Note: `cloneUrl` is the unauthenticated origin. The gateway authenticates clones
|
|
15
|
+
* via basic-auth (the `auth` block returned by create); inside an agent run the
|
|
16
|
+
* `gitRepository` auto-clone wires that credential into the in-sandbox origin, so
|
|
17
|
+
* `pushFromSandbox` doesn't need it.
|
|
18
|
+
*/
|
|
19
|
+
import { defaultTransport } from "../_client/index.js";
|
|
20
|
+
const DEFAULT_BASE_URL = process.env.SAPIOM_GIT_URL || "https://git.services.sapiom.ai";
|
|
21
|
+
/** Canonical in-sandbox checkout path (matches the agent's `gitRepository` auto-clone). */
|
|
22
|
+
const checkoutDir = (slug) => `/workspace/${slug}`;
|
|
23
|
+
/** A connected in-network repository. */
|
|
24
|
+
export class Repository {
|
|
25
|
+
constructor(fields, transport, baseUrl) {
|
|
26
|
+
this.slug = fields.slug;
|
|
27
|
+
this.cloneUrl = fields.cloneUrl;
|
|
28
|
+
this.status = fields.status;
|
|
29
|
+
this.transport = transport;
|
|
30
|
+
this.baseUrl = baseUrl;
|
|
31
|
+
}
|
|
32
|
+
static async create(slug, transport = defaultTransport(), baseUrl = DEFAULT_BASE_URL) {
|
|
33
|
+
const r = await transport.request(`${baseUrl}/v1/git/repositories`, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
body: JSON.stringify({ slug }),
|
|
36
|
+
});
|
|
37
|
+
// create doesn't return a status; a just-created repo is active.
|
|
38
|
+
return new Repository({ slug: r.slug, cloneUrl: r.cloneUrl, status: "active" }, transport, baseUrl);
|
|
39
|
+
}
|
|
40
|
+
static async get(slug, transport = defaultTransport(), baseUrl = DEFAULT_BASE_URL) {
|
|
41
|
+
const r = await transport.request(`${baseUrl}/v1/git/repositories/${encodeURIComponent(slug)}`);
|
|
42
|
+
return new Repository(r, transport, baseUrl);
|
|
43
|
+
}
|
|
44
|
+
static async list(transport = defaultTransport(), baseUrl = DEFAULT_BASE_URL) {
|
|
45
|
+
const r = await transport.request(`${baseUrl}/v1/git/repositories`);
|
|
46
|
+
return r.repositories.map((s) => new Repository(s, transport, baseUrl));
|
|
47
|
+
}
|
|
48
|
+
static async delete(slug, transport = defaultTransport(), baseUrl = DEFAULT_BASE_URL) {
|
|
49
|
+
await transport.request(`${baseUrl}/v1/git/repositories/${encodeURIComponent(slug)}`, { method: "DELETE" }).catch(() => undefined);
|
|
50
|
+
}
|
|
51
|
+
/** Adopt a known repo without a round-trip (e.g. one returned from another step). */
|
|
52
|
+
static attach(slug, cloneUrl, transport = defaultTransport(), baseUrl = DEFAULT_BASE_URL) {
|
|
53
|
+
return new Repository({ slug, cloneUrl, status: "active" }, transport, baseUrl);
|
|
54
|
+
}
|
|
55
|
+
/** Delete this repository. */
|
|
56
|
+
delete() {
|
|
57
|
+
return Repository.delete(this.slug, this.transport, this.baseUrl);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deterministically stage + commit + push this repo's working tree FROM a
|
|
61
|
+
* sandbox checkout (no LLM). Assumes the repo is checked out at the canonical
|
|
62
|
+
* `/workspace/<slug>` with an authenticated `origin` (which the agent's
|
|
63
|
+
* `gitRepository` auto-clone sets up). No-op when there's nothing to commit.
|
|
64
|
+
*/
|
|
65
|
+
async pushFromSandbox(sandbox, opts = {}) {
|
|
66
|
+
const message = (opts.message ?? `update ${this.slug}`).replace(/'/g, ""); // single-quote-safe for sh -c
|
|
67
|
+
const script = `cd ${checkoutDir(this.slug)} && git add -A && ` +
|
|
68
|
+
`if git diff --cached --quiet; then echo NO_CHANGES; else ` +
|
|
69
|
+
`git -c user.email=workflow@sapiom.ai -c user.name=sapiom-workflow commit -m "${message}" >/dev/null && ` +
|
|
70
|
+
`git push origin HEAD && printf "SHA:%s\\n" "$(git rev-parse HEAD)"; fi`;
|
|
71
|
+
const { stdout, stderr, exitCode } = await sandbox.exec(`sh -c '${script}'`);
|
|
72
|
+
const out = `${stdout}\n${stderr}`;
|
|
73
|
+
if (out.includes("NO_CHANGES"))
|
|
74
|
+
return { pushed: false, sha: null };
|
|
75
|
+
const sha = out.match(/SHA:([0-9a-f]{7,40})/)?.[1] ?? null;
|
|
76
|
+
if (exitCode !== 0 || !sha) {
|
|
77
|
+
throw new Error(`pushFromSandbox(${this.slug}) failed (exit ${exitCode}): ${out.slice(-300)}`);
|
|
78
|
+
}
|
|
79
|
+
return { pushed: true, sha };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Ambient-bound namespace functions.
|
|
83
|
+
export function create(slug) {
|
|
84
|
+
return Repository.create(slug);
|
|
85
|
+
}
|
|
86
|
+
export function get(slug) {
|
|
87
|
+
return Repository.get(slug);
|
|
88
|
+
}
|
|
89
|
+
export function list() {
|
|
90
|
+
return Repository.list();
|
|
91
|
+
}
|
|
92
|
+
export function attach(slug, cloneUrl) {
|
|
93
|
+
return Repository.attach(slug, cloneUrl);
|
|
94
|
+
}
|
|
95
|
+
function deleteRepository(slug) {
|
|
96
|
+
return Repository.delete(slug);
|
|
97
|
+
}
|
|
98
|
+
export { deleteRepository as delete };
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/repositories/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sandbox` capability — an isolated, ephemeral compute instance for running code
|
|
3
|
+
* or agents securely: create, exec (sync / fire-and-forget / streaming), read &
|
|
4
|
+
* write files, then destroy. Ported from the legacy `@sapiom/sandbox` onto the
|
|
5
|
+
* `_client` transport, with the Blaxel specifics removed:
|
|
6
|
+
* - auth comes from the transport (ambient or explicit), not per-call apiKey
|
|
7
|
+
* - the host is a platform routing detail (overridable), not a "blaxel" concept
|
|
8
|
+
* - custom image build (the Blaxel-runtime Dockerfile) is deferred, not exposed
|
|
9
|
+
*
|
|
10
|
+
* import { sandbox } from "@sapiom/tools"; // ambient auth
|
|
11
|
+
* const box = await sandbox.create({ name: "demo" });
|
|
12
|
+
* const { stdout } = await box.exec("echo hi");
|
|
13
|
+
* await box.destroy();
|
|
14
|
+
*/
|
|
15
|
+
import { Transport } from "../_client/index.js";
|
|
16
|
+
import type { ExecOptions, ExecResult, ExecStreamOptions, ProcessStatus, SandboxCreateOptions, StreamingExecResult } from "./types.js";
|
|
17
|
+
export type { ExecOptions, ExecResult, ExecStreamOptions, OutputLine, PortSpec, ProcessStatus, SandboxCreateOptions, SandboxTier, StreamingExecResult, } from "./types.js";
|
|
18
|
+
/** A live sandbox handle. Create via {@link create}; pass between steps to share state. */
|
|
19
|
+
export declare class Sandbox {
|
|
20
|
+
/** Name / identifier of the sandbox. */
|
|
21
|
+
readonly name: string;
|
|
22
|
+
/** Absolute workspace root path inside the sandbox. */
|
|
23
|
+
readonly workspaceRoot: string;
|
|
24
|
+
private readonly transport;
|
|
25
|
+
private readonly baseUrl;
|
|
26
|
+
private constructor();
|
|
27
|
+
/** Create a sandbox and return a handle. Uses the ambient transport unless one is supplied. */
|
|
28
|
+
static create(opts: SandboxCreateOptions, transport?: Transport): Promise<Sandbox>;
|
|
29
|
+
/** Adopt an existing sandbox by name (e.g. one a prior step kept). */
|
|
30
|
+
static attach(name: string, opts?: {
|
|
31
|
+
workspaceRoot?: string;
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
}, transport?: Transport): Sandbox;
|
|
34
|
+
private fileUrl;
|
|
35
|
+
private procUrl;
|
|
36
|
+
/** Write a file (path relative to the workspace root). */
|
|
37
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
38
|
+
/** Read a file (path relative to the workspace root). */
|
|
39
|
+
readFile(path: string): Promise<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Execute a command. Waits for completion by default; set `waitForCompletion:
|
|
42
|
+
* false` for fire-and-forget, or use {@link execStream} for real-time output.
|
|
43
|
+
*/
|
|
44
|
+
exec(command: string, opts?: ExecOptions): Promise<ExecResult>;
|
|
45
|
+
/** Execute a command and stream output lines in real time. `exitCode` populates after `output` drains. */
|
|
46
|
+
execStream(command: string, opts?: ExecStreamOptions): Promise<StreamingExecResult>;
|
|
47
|
+
/** Current status of a process by PID (useful for fire-and-forget execs). */
|
|
48
|
+
getProcess(pid: string): Promise<ProcessStatus>;
|
|
49
|
+
/** Wait for a process to finish by polling its status. */
|
|
50
|
+
waitForProcess(pid: string, opts?: {
|
|
51
|
+
pollInterval?: number;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
signal?: AbortSignal;
|
|
54
|
+
}): Promise<ExecResult>;
|
|
55
|
+
/** Destroy the sandbox and release its resources. */
|
|
56
|
+
destroy(): Promise<void>;
|
|
57
|
+
private createProcess;
|
|
58
|
+
private pollProcess;
|
|
59
|
+
}
|
|
60
|
+
/** Create a sandbox (ambient transport). The namespace's primary entry point. */
|
|
61
|
+
export declare function create(opts: SandboxCreateOptions): Promise<Sandbox>;
|
|
62
|
+
/** Adopt an existing sandbox by name (ambient transport). */
|
|
63
|
+
export declare function attach(name: string, opts?: {
|
|
64
|
+
workspaceRoot?: string;
|
|
65
|
+
baseUrl?: string;
|
|
66
|
+
}): Sandbox;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sandboxes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,SAAS,EAAoB,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAEV,WAAW,EACX,UAAU,EACV,iBAAiB,EAGjB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,mBAAmB,GACpB,MAAM,YAAY,CAAC;AA0BpB,2FAA2F;AAC3F,qBAAa,OAAO;IAClB,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO;IAOP,+FAA+F;WAClF,MAAM,CAAC,IAAI,EAAE,oBAAoB,EAAE,SAAS,GAAE,SAA8B,GAAG,OAAO,CAAC,OAAO,CAAC;IAyB5G,sEAAsE;IACtE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,EAAE,SAAS,GAAE,SAA8B,GAAG,OAAO;IAIxI,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,OAAO;IAIf,0DAA0D;IACpD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7D,yDAAyD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO7C;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAWpE,0GAA0G;IACpG,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA4DzF,6EAA6E;IACvE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMrD,0DAA0D;IACpD,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;IAIhI,qDAAqD;IAC/C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOhB,aAAa;YAqBb,WAAW;CAc1B;AAED,iFAAiF;AACjF,wBAAgB,MAAM,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnE;AAED,6DAA6D;AAC7D,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAEjG"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sandbox` capability — an isolated, ephemeral compute instance for running code
|
|
3
|
+
* or agents securely: create, exec (sync / fire-and-forget / streaming), read &
|
|
4
|
+
* write files, then destroy. Ported from the legacy `@sapiom/sandbox` onto the
|
|
5
|
+
* `_client` transport, with the Blaxel specifics removed:
|
|
6
|
+
* - auth comes from the transport (ambient or explicit), not per-call apiKey
|
|
7
|
+
* - the host is a platform routing detail (overridable), not a "blaxel" concept
|
|
8
|
+
* - custom image build (the Blaxel-runtime Dockerfile) is deferred, not exposed
|
|
9
|
+
*
|
|
10
|
+
* import { sandbox } from "@sapiom/tools"; // ambient auth
|
|
11
|
+
* const box = await sandbox.create({ name: "demo" });
|
|
12
|
+
* const { stdout } = await box.exec("echo hi");
|
|
13
|
+
* await box.destroy();
|
|
14
|
+
*/
|
|
15
|
+
import { defaultTransport } from "../_client/index.js";
|
|
16
|
+
/** Platform sandbox service. Host routing is an internal detail — override via `baseUrl` or SAPIOM_SANDBOX_URL. */
|
|
17
|
+
const DEFAULT_BASE_URL = process.env.SAPIOM_SANDBOX_URL || "https://blaxel.services.sapiom.ai";
|
|
18
|
+
const DEFAULT_POLL_INTERVAL = 1000;
|
|
19
|
+
const DEFAULT_EXEC_TIMEOUT = 60000;
|
|
20
|
+
function assertRelativePath(path) {
|
|
21
|
+
if (path.split("/").some((seg) => seg === "..")) {
|
|
22
|
+
throw new Error(`Path must not contain '..' segments: ${path}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function encodePathSegments(path) {
|
|
26
|
+
return path
|
|
27
|
+
.split("/")
|
|
28
|
+
.map((seg) => encodeURIComponent(seg))
|
|
29
|
+
.join("/");
|
|
30
|
+
}
|
|
31
|
+
function parseOutputLine(line) {
|
|
32
|
+
if (line.startsWith("stdout:"))
|
|
33
|
+
return { stream: "stdout", data: line.slice(7) };
|
|
34
|
+
if (line.startsWith("stderr:"))
|
|
35
|
+
return { stream: "stderr", data: line.slice(7) };
|
|
36
|
+
return { stream: "stdout", data: line }; // unrecognized framing — keep, don't drop
|
|
37
|
+
}
|
|
38
|
+
/** A live sandbox handle. Create via {@link create}; pass between steps to share state. */
|
|
39
|
+
export class Sandbox {
|
|
40
|
+
constructor(name, workspaceRoot, transport, baseUrl) {
|
|
41
|
+
this.name = name;
|
|
42
|
+
this.workspaceRoot = workspaceRoot;
|
|
43
|
+
this.transport = transport;
|
|
44
|
+
this.baseUrl = baseUrl;
|
|
45
|
+
}
|
|
46
|
+
/** Create a sandbox and return a handle. Uses the ambient transport unless one is supplied. */
|
|
47
|
+
static async create(opts, transport = defaultTransport()) {
|
|
48
|
+
if (opts.port !== undefined && opts.ports !== undefined) {
|
|
49
|
+
throw new Error("Cannot specify both 'port' and 'ports'");
|
|
50
|
+
}
|
|
51
|
+
const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
52
|
+
const body = { name: opts.name };
|
|
53
|
+
if (opts.tier !== undefined)
|
|
54
|
+
body.tier = opts.tier;
|
|
55
|
+
if (opts.ttl !== undefined)
|
|
56
|
+
body.ttl = opts.ttl;
|
|
57
|
+
if (opts.envs !== undefined)
|
|
58
|
+
body.envs = opts.envs;
|
|
59
|
+
if (opts.port !== undefined)
|
|
60
|
+
body.port = opts.port;
|
|
61
|
+
if (opts.ports !== undefined)
|
|
62
|
+
body.ports = opts.ports;
|
|
63
|
+
if (opts.image !== undefined)
|
|
64
|
+
body.image = opts.image;
|
|
65
|
+
const res = await transport.fetch(`${baseUrl}/v1/sandboxes`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "content-type": "application/json" },
|
|
68
|
+
body: JSON.stringify(body),
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok)
|
|
71
|
+
throw new Error(`Failed to create sandbox: ${res.status} ${await res.text()}`);
|
|
72
|
+
const data = (await res.json());
|
|
73
|
+
return new Sandbox(data.name, data.workspaceRoot, transport, baseUrl);
|
|
74
|
+
}
|
|
75
|
+
/** Adopt an existing sandbox by name (e.g. one a prior step kept). */
|
|
76
|
+
static attach(name, opts = {}, transport = defaultTransport()) {
|
|
77
|
+
return new Sandbox(name, opts.workspaceRoot ?? "/", transport, opts.baseUrl ?? DEFAULT_BASE_URL);
|
|
78
|
+
}
|
|
79
|
+
fileUrl(path) {
|
|
80
|
+
assertRelativePath(path);
|
|
81
|
+
const base = this.workspaceRoot.endsWith("/") ? this.workspaceRoot.slice(0, -1) : this.workspaceRoot;
|
|
82
|
+
const rel = path.startsWith("/") ? path.slice(1) : path;
|
|
83
|
+
const abs = `${base}/${rel}`.replace(/^\//, "");
|
|
84
|
+
return `${this.baseUrl}/v1/sandboxes/${encodeURIComponent(this.name)}/filesystem/${encodePathSegments(abs)}`;
|
|
85
|
+
}
|
|
86
|
+
procUrl(suffix = "") {
|
|
87
|
+
return `${this.baseUrl}/v1/sandboxes/${encodeURIComponent(this.name)}/process${suffix}`;
|
|
88
|
+
}
|
|
89
|
+
/** Write a file (path relative to the workspace root). */
|
|
90
|
+
async writeFile(path, content) {
|
|
91
|
+
const res = await this.transport.fetch(this.fileUrl(path), {
|
|
92
|
+
method: "PUT",
|
|
93
|
+
headers: { "content-type": "application/json" },
|
|
94
|
+
body: JSON.stringify({ content }),
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok)
|
|
97
|
+
throw new Error(`Failed to write file '${path}': ${res.status} ${await res.text()}`);
|
|
98
|
+
}
|
|
99
|
+
/** Read a file (path relative to the workspace root). */
|
|
100
|
+
async readFile(path) {
|
|
101
|
+
const res = await this.transport.fetch(this.fileUrl(path));
|
|
102
|
+
if (!res.ok)
|
|
103
|
+
throw new Error(`Failed to read file '${path}': ${res.status} ${await res.text()}`);
|
|
104
|
+
const data = (await res.json());
|
|
105
|
+
return data.content;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Execute a command. Waits for completion by default; set `waitForCompletion:
|
|
109
|
+
* false` for fire-and-forget, or use {@link execStream} for real-time output.
|
|
110
|
+
*/
|
|
111
|
+
async exec(command, opts) {
|
|
112
|
+
const proc = await this.createProcess(command, opts);
|
|
113
|
+
if (proc.status === "completed") {
|
|
114
|
+
return { pid: proc.pid, exitCode: proc.exitCode ?? 0, stdout: proc.stdout ?? "", stderr: proc.stderr ?? "" };
|
|
115
|
+
}
|
|
116
|
+
if (opts?.waitForCompletion === false) {
|
|
117
|
+
return { pid: proc.pid, exitCode: -1, stdout: proc.stdout ?? "", stderr: proc.stderr ?? "" };
|
|
118
|
+
}
|
|
119
|
+
return this.pollProcess(proc.pid, opts);
|
|
120
|
+
}
|
|
121
|
+
/** Execute a command and stream output lines in real time. `exitCode` populates after `output` drains. */
|
|
122
|
+
async execStream(command, opts) {
|
|
123
|
+
const proc = await this.createProcess(command, opts);
|
|
124
|
+
if (proc.status === "completed") {
|
|
125
|
+
const code = proc.exitCode ?? 0;
|
|
126
|
+
const stdout = proc.stdout ?? "";
|
|
127
|
+
const stderr = proc.stderr ?? "";
|
|
128
|
+
const output = (async function* () {
|
|
129
|
+
if (stdout)
|
|
130
|
+
yield { stream: "stdout", data: stdout };
|
|
131
|
+
if (stderr)
|
|
132
|
+
yield { stream: "stderr", data: stderr };
|
|
133
|
+
})();
|
|
134
|
+
return { pid: proc.pid, get exitCode() { return code; }, output };
|
|
135
|
+
}
|
|
136
|
+
let finalExitCode = -1;
|
|
137
|
+
const transport = this.transport;
|
|
138
|
+
const signal = opts?.signal;
|
|
139
|
+
const logsUrl = this.procUrl(`/${proc.pid}/logs/stream`);
|
|
140
|
+
const statusUrl = this.procUrl(`/${proc.pid}`);
|
|
141
|
+
async function* streamOutput() {
|
|
142
|
+
const res = await transport.fetch(logsUrl, { signal });
|
|
143
|
+
if (!res.ok)
|
|
144
|
+
throw new Error(`Failed to stream process ${proc.pid}: ${res.status} ${await res.text()}`);
|
|
145
|
+
if (!res.body)
|
|
146
|
+
throw new Error(`No response body for process ${proc.pid} log stream`);
|
|
147
|
+
const reader = res.body.getReader();
|
|
148
|
+
const decoder = new TextDecoder();
|
|
149
|
+
let buffer = "";
|
|
150
|
+
try {
|
|
151
|
+
for (;;) {
|
|
152
|
+
const { done, value } = await reader.read();
|
|
153
|
+
if (done)
|
|
154
|
+
break;
|
|
155
|
+
buffer += decoder.decode(value, { stream: true });
|
|
156
|
+
const lines = buffer.split("\n");
|
|
157
|
+
buffer = lines.pop();
|
|
158
|
+
for (const line of lines)
|
|
159
|
+
if (line)
|
|
160
|
+
yield parseOutputLine(line);
|
|
161
|
+
}
|
|
162
|
+
buffer += decoder.decode();
|
|
163
|
+
if (buffer)
|
|
164
|
+
yield parseOutputLine(buffer);
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
reader.releaseLock();
|
|
168
|
+
}
|
|
169
|
+
let status = await readStatus();
|
|
170
|
+
while (status.status !== "completed") {
|
|
171
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
172
|
+
status = await readStatus();
|
|
173
|
+
}
|
|
174
|
+
finalExitCode = status.exitCode ?? 0;
|
|
175
|
+
async function readStatus() {
|
|
176
|
+
const s = await transport.fetch(statusUrl, { signal });
|
|
177
|
+
if (!s.ok)
|
|
178
|
+
throw new Error(`Failed to get final status for process ${proc.pid}: ${s.status} ${await s.text()}`);
|
|
179
|
+
return (await s.json());
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return { pid: proc.pid, get exitCode() { return finalExitCode; }, output: streamOutput() };
|
|
183
|
+
}
|
|
184
|
+
/** Current status of a process by PID (useful for fire-and-forget execs). */
|
|
185
|
+
async getProcess(pid) {
|
|
186
|
+
const res = await this.transport.fetch(this.procUrl(`/${pid}`));
|
|
187
|
+
if (!res.ok)
|
|
188
|
+
throw new Error(`Failed to get process ${pid}: ${res.status} ${await res.text()}`);
|
|
189
|
+
return (await res.json());
|
|
190
|
+
}
|
|
191
|
+
/** Wait for a process to finish by polling its status. */
|
|
192
|
+
async waitForProcess(pid, opts) {
|
|
193
|
+
return this.pollProcess(pid, opts);
|
|
194
|
+
}
|
|
195
|
+
/** Destroy the sandbox and release its resources. */
|
|
196
|
+
async destroy() {
|
|
197
|
+
const res = await this.transport.fetch(`${this.baseUrl}/v1/sandboxes/${encodeURIComponent(this.name)}`, { method: "DELETE" });
|
|
198
|
+
if (!res.ok)
|
|
199
|
+
throw new Error(`Failed to destroy sandbox: ${res.status} ${await res.text()}`);
|
|
200
|
+
}
|
|
201
|
+
// --- internal ---
|
|
202
|
+
async createProcess(command, opts) {
|
|
203
|
+
const body = { command };
|
|
204
|
+
if (opts?.cwd !== undefined) {
|
|
205
|
+
assertRelativePath(opts.cwd);
|
|
206
|
+
const base = this.workspaceRoot.endsWith("/") ? this.workspaceRoot.slice(0, -1) : this.workspaceRoot;
|
|
207
|
+
body.cwd = `${base}/${opts.cwd.startsWith("/") ? opts.cwd.slice(1) : opts.cwd}`;
|
|
208
|
+
}
|
|
209
|
+
if (opts?.env !== undefined)
|
|
210
|
+
body.env = opts.env;
|
|
211
|
+
if (opts?.keepAlive !== undefined)
|
|
212
|
+
body.keepAlive = opts.keepAlive;
|
|
213
|
+
if (opts?.processTimeout !== undefined)
|
|
214
|
+
body.timeout = opts.processTimeout;
|
|
215
|
+
const res = await this.transport.fetch(this.procUrl(), {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: { "content-type": "application/json" },
|
|
218
|
+
body: JSON.stringify(body),
|
|
219
|
+
signal: opts?.signal,
|
|
220
|
+
});
|
|
221
|
+
if (!res.ok)
|
|
222
|
+
throw new Error(`Failed to execute command: ${res.status} ${await res.text()}`);
|
|
223
|
+
return (await res.json());
|
|
224
|
+
}
|
|
225
|
+
async pollProcess(pid, opts) {
|
|
226
|
+
const pollInterval = opts?.pollInterval ?? DEFAULT_POLL_INTERVAL;
|
|
227
|
+
const deadline = Date.now() + (opts?.timeout ?? DEFAULT_EXEC_TIMEOUT);
|
|
228
|
+
while (Date.now() < deadline) {
|
|
229
|
+
const res = await this.transport.fetch(this.procUrl(`/${pid}`), { signal: opts?.signal });
|
|
230
|
+
if (!res.ok)
|
|
231
|
+
throw new Error(`Failed to poll process ${pid}: ${res.status} ${await res.text()}`);
|
|
232
|
+
const status = (await res.json());
|
|
233
|
+
if (status.status === "completed") {
|
|
234
|
+
return { pid, exitCode: status.exitCode ?? 0, stdout: status.stdout ?? "", stderr: status.stderr ?? "" };
|
|
235
|
+
}
|
|
236
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
237
|
+
}
|
|
238
|
+
throw new Error(`Process ${pid} timed out after ${opts?.timeout ?? DEFAULT_EXEC_TIMEOUT}ms`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** Create a sandbox (ambient transport). The namespace's primary entry point. */
|
|
242
|
+
export function create(opts) {
|
|
243
|
+
return Sandbox.create(opts);
|
|
244
|
+
}
|
|
245
|
+
/** Adopt an existing sandbox by name (ambient transport). */
|
|
246
|
+
export function attach(name, opts) {
|
|
247
|
+
return Sandbox.attach(name, opts);
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sandboxes/index.ts"],"names":[],"mappings":"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"}
|