@tangle-network/sandbox 0.10.1 → 0.10.3

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,434 @@
1
+ import { f as ValidationError, l as ServerError, p as parseErrorResponse } from "./errors-DSz87Rkk.js";
2
+ //#region src/backend-config.ts
3
+ const LEGACY_QUESTION_ALIAS_KEY = ["question", "Channel"].join("");
4
+ function parseModelString(model) {
5
+ const parts = model.split("/");
6
+ if (parts.length >= 2) return {
7
+ provider: parts[0],
8
+ model: parts.slice(1).join("/")
9
+ };
10
+ return { model };
11
+ }
12
+ /**
13
+ * Normalize runtime backend config for the wire format.
14
+ *
15
+ * Callers set `backend.profile` (named string or portable AgentProfile).
16
+ * This function generates the native `inlineProfile` shim automatically.
17
+ */
18
+ function normalizeRuntimeBackendConfig(backend, options = {}) {
19
+ if (!backend && !options.model) return void 0;
20
+ if (backend && LEGACY_QUESTION_ALIAS_KEY in backend) throw new Error(`[sandbox-sdk] backend.${LEGACY_QUESTION_ALIAS_KEY} was removed. Use backend.interactions.question instead.`);
21
+ const portableProfile = backend?.profile && typeof backend.profile !== "string" ? backend.profile : void 0;
22
+ const inlineProfile = portableProfile ? toBackendProfile(portableProfile) : void 0;
23
+ const callerInlineProfile = backend?.inlineProfile;
24
+ if (callerInlineProfile && !inlineProfile) console.warn("[sandbox-sdk] backend.inlineProfile is deprecated. Use backend.profile (AgentPortableProfile) instead.");
25
+ if (inlineProfile && portableProfile) {
26
+ const reasoningEffort = portableProfile.model?.reasoningEffort ?? portableProfile.extensions?.[backend?.type ?? ""]?.reasoningEffort;
27
+ if (typeof reasoningEffort === "string" && reasoningEffort !== "auto" && reasoningEffort !== "none") inlineProfile.reasoningEffort = reasoningEffort;
28
+ }
29
+ return {
30
+ ...backend?.type ? { type: backend.type } : {},
31
+ ...typeof backend?.profile === "string" ? { profile: backend.profile } : {},
32
+ ...inlineProfile ? { inlineProfile } : callerInlineProfile ? { inlineProfile: callerInlineProfile } : {},
33
+ ...backend?.model ? { model: backend.model } : options.model ? { model: parseModelString(options.model) } : {},
34
+ ...backend?.server ? { server: backend.server } : {},
35
+ ...backend?.interactions !== void 0 ? { interactions: backend.interactions } : {},
36
+ ...backend?.metadata !== void 0 ? { metadata: backend.metadata } : {}
37
+ };
38
+ }
39
+ /**
40
+ * Permission keys the sidecar's strict `permission` schema accepts
41
+ * (apps/sidecar/src/schemas/agent-profile-schema.ts → permissionConfigSchema).
42
+ * Any other portable-permission key is a per-tool gate, not a permission, and
43
+ * is routed into `tools` instead of passed through — the sidecar's `.strict()`
44
+ * schema rejects unknown permission keys with `unrecognized_keys`.
45
+ *
46
+ * Name must not carry an UPPERCASE `SIDECAR_`/`ORCHESTRATOR_`-style prefix:
47
+ * obfuscate.sh runs `--rename-globals false`, so a module-global identifier
48
+ * ships verbatim in dist/, and verify-dist.sh bans those prefixes as
49
+ * closed-source leaks.
50
+ */
51
+ const CANONICAL_PERMISSION_KEYS = new Set([
52
+ "edit",
53
+ "bash",
54
+ "webfetch",
55
+ "mcp",
56
+ "doom_loop",
57
+ "external_directory"
58
+ ]);
59
+ function hasAnyProfileResource(resources) {
60
+ return !!(resources.files?.length || resources.tools?.length || resources.skills?.length || resources.agents?.length || resources.commands?.length || resources.instructions);
61
+ }
62
+ function validateProfileResources(profile) {
63
+ if (profile.resources !== void 0 && (profile.resources === null || typeof profile.resources !== "object" || Array.isArray(profile.resources))) throw new Error("backend.profile.resources must be an object when provided");
64
+ if (profile.resources?.plugins?.length) throw new Error("backend.profile.resources.plugins is not supported by the sandbox SDK profile contract; use backend-specific provider profiles for OpenCode plugin resources");
65
+ }
66
+ function toBackendProfile(profile) {
67
+ validateProfileResources(profile);
68
+ const permission = {};
69
+ const derivedTools = {};
70
+ for (const [rawKey, value] of Object.entries(profile.permissions ?? {})) {
71
+ const key = rawKey === "network" ? "webfetch" : rawKey;
72
+ if (CANONICAL_PERMISSION_KEYS.has(key)) permission[key] = value;
73
+ else if (typeof value === "string") derivedTools[key] = value !== "deny";
74
+ else console.warn(`[sandbox-sdk] dropping unsupported permission key "${rawKey}": not a canonical sidecar permission and not a string tool gate`);
75
+ }
76
+ const tools = {
77
+ ...derivedTools,
78
+ ...profile.tools ?? {}
79
+ };
80
+ const mcp = profile.mcp ? Object.fromEntries(Object.entries(profile.mcp).map(([name, config]) => {
81
+ const c = config;
82
+ const transport = c.transport;
83
+ const command = c.command;
84
+ const hasCommand = Array.isArray(command) ? command.length > 0 : typeof command === "string" && command.trim().length > 0;
85
+ const isRemote = transport === "http" || transport === "sse" || typeof c.url === "string" && !hasCommand;
86
+ const enabled = c.enabled;
87
+ const timeout = c.timeout;
88
+ if (isRemote) return [name, {
89
+ type: "remote",
90
+ url: c.url,
91
+ ...c.headers ? { headers: c.headers } : {},
92
+ ...enabled !== void 0 ? { enabled } : {},
93
+ ...timeout !== void 0 ? { timeout } : {}
94
+ }];
95
+ return [name, {
96
+ type: "local",
97
+ command: [...Array.isArray(command) ? command : typeof command === "string" ? command.trim().split(/\s+/).filter(Boolean) : [], ...c.args ?? []],
98
+ ...c.env ? { environment: c.env } : {},
99
+ ...enabled !== void 0 ? { enabled } : {},
100
+ ...timeout !== void 0 ? { timeout } : {}
101
+ }];
102
+ })) : void 0;
103
+ const openCodeExtension = profile.extensions?.opencode;
104
+ const plugins = openCodeExtension?.plugins;
105
+ if (plugins !== void 0 && (!Array.isArray(plugins) || plugins.some((plugin) => typeof plugin !== "string" || !plugin.trim()))) throw new Error("backend.profile.extensions.opencode.plugins must be an array of non-empty package names");
106
+ const commands = openCodeExtension?.commands;
107
+ if (commands !== void 0 && (commands === null || typeof commands !== "object" || Array.isArray(commands))) throw new Error("backend.profile.extensions.opencode.commands must be an object");
108
+ const profileExtends = openCodeExtension?.extends;
109
+ if (profileExtends !== void 0 && typeof profileExtends !== "string" && (!Array.isArray(profileExtends) || profileExtends.some((entry) => typeof entry !== "string" || !entry.trim()))) throw new Error("backend.profile.extensions.opencode.extends must be a profile name or array of profile names");
110
+ const agents = profile.subagents ? Object.fromEntries(Object.entries(profile.subagents).map(([name, subagent]) => [name, {
111
+ description: subagent.description,
112
+ prompt: subagent.prompt,
113
+ model: subagent.model,
114
+ tools: subagent.tools,
115
+ permission: subagent.permissions,
116
+ maxSteps: subagent.maxSteps,
117
+ ...subagent.metadata ?? {}
118
+ }])) : void 0;
119
+ return {
120
+ name: profile.name,
121
+ description: profile.description,
122
+ version: profile.version,
123
+ tags: profile.tags,
124
+ ...profileExtends ? { extends: profileExtends } : {},
125
+ model: profile.model?.default,
126
+ small_model: profile.model?.small,
127
+ ...profile.prompt?.systemPrompt ? { systemPrompt: profile.prompt.systemPrompt } : {},
128
+ ...Object.keys(tools).length > 0 ? { tools } : {},
129
+ ...profile.prompt?.instructions?.length ? { instructions: profile.prompt.instructions } : {},
130
+ ...Object.keys(permission).length > 0 ? { permission } : {},
131
+ ...mcp ? { mcp } : {},
132
+ ...profile.connections?.length ? { connections: profile.connections } : {},
133
+ ...agents ? { agent: agents } : {},
134
+ ...profile.resources && hasAnyProfileResource(profile.resources) ? { resources: profile.resources } : {},
135
+ ...profile.hooks ? { hooks: profile.hooks } : {},
136
+ ...profile.modes ? { modes: profile.modes } : {},
137
+ ...commands ? { command: commands } : {},
138
+ ...plugins?.length ? { plugin: plugins } : {},
139
+ ...profile.extensions ? { extensions: profile.extensions } : {}
140
+ };
141
+ }
142
+ /**
143
+ * Serialize a portable AgentProfile into the sidecar's canonical inline-profile
144
+ * wire shape (validated by inlineProfileSchema in
145
+ * apps/sidecar/src/schemas/agent-profile-schema.ts).
146
+ *
147
+ * Single choke point every product shares: streamPrompt →
148
+ * normalizeRuntimeBackendConfig → toBackendProfile. Exported so callers and the
149
+ * drift-guard test target one contract — the test parses this output with the
150
+ * sidecar's own schema, so any future schema tightening fails here first.
151
+ */
152
+ function serializeForSidecar(profile) {
153
+ return toBackendProfile(profile);
154
+ }
155
+ //#endregion
156
+ //#region src/runtime-api.ts
157
+ /** Internal typed client for routes served by a sandbox runtime. */
158
+ var SandboxRuntimeApi = class {
159
+ terminals;
160
+ constructor(transport) {
161
+ this.transport = transport;
162
+ this.terminals = {
163
+ create: (options, request) => this.createTerminal(options, request),
164
+ input: (terminalId, data, request) => this.writeTerminal(terminalId, data, request),
165
+ list: () => this.listTerminals(),
166
+ get: (terminalId) => this.getTerminal(terminalId)
167
+ };
168
+ }
169
+ async health() {
170
+ await this.transport.ensureRunning();
171
+ return this.json("/health", { method: "GET" });
172
+ }
173
+ async ports() {
174
+ await this.transport.ensureRunning();
175
+ return (await this.json("/ports", { method: "GET" })).data?.ports ?? [];
176
+ }
177
+ async profiles() {
178
+ await this.transport.ensureRunning();
179
+ return this.json("/profiles", { method: "GET" });
180
+ }
181
+ async readFiles(paths, options = {}) {
182
+ if (paths.length === 0) return {
183
+ files: [],
184
+ errors: [],
185
+ stats: {
186
+ requested: 0,
187
+ succeeded: 0,
188
+ failed: 0
189
+ }
190
+ };
191
+ await this.transport.ensureRunning();
192
+ const files = [];
193
+ const errors = [];
194
+ let requested = 0;
195
+ let succeeded = 0;
196
+ let failed = 0;
197
+ for (let offset = 0; offset < paths.length; offset += 100) {
198
+ const chunk = paths.slice(offset, offset + 100);
199
+ const params = new URLSearchParams();
200
+ if (options.sessionId) params.set("sessionId", options.sessionId);
201
+ const query = params.toString();
202
+ const payload = await this.json(`/files/read-batch${query ? `?${query}` : ""}`, {
203
+ method: "POST",
204
+ body: JSON.stringify({
205
+ paths: chunk,
206
+ ...options.encoding ? { encoding: options.encoding } : {}
207
+ })
208
+ });
209
+ for (const [path, result] of Object.entries(payload.data.files)) if (result.success) files.push({
210
+ path,
211
+ content: result.content,
212
+ encoding: result.encoding,
213
+ hash: result.hash,
214
+ size: result.size,
215
+ mtime: result.mtime
216
+ });
217
+ else errors.push({
218
+ path,
219
+ error: result.error,
220
+ code: result.code
221
+ });
222
+ const results = Object.values(payload.data.files);
223
+ requested += payload.data.stats?.requested ?? chunk.length;
224
+ succeeded += payload.data.stats?.succeeded ?? results.filter((entry) => entry.success).length;
225
+ failed += payload.data.stats?.failed ?? results.filter((entry) => !entry.success).length;
226
+ }
227
+ return {
228
+ files,
229
+ errors,
230
+ stats: {
231
+ requested,
232
+ succeeded,
233
+ failed
234
+ }
235
+ };
236
+ }
237
+ async writeFile(path, content, options = {}) {
238
+ await this.transport.ensureRunning();
239
+ const params = new URLSearchParams();
240
+ if (options.sessionId) params.set("sessionId", options.sessionId);
241
+ const query = params.toString();
242
+ return (await this.json(`/files/write${query ? `?${query}` : ""}`, {
243
+ method: "POST",
244
+ body: JSON.stringify({
245
+ path,
246
+ content,
247
+ ...options.encoding !== void 0 ? { encoding: options.encoding } : {},
248
+ ...options.mode !== void 0 ? { mode: options.mode } : {}
249
+ })
250
+ })).data;
251
+ }
252
+ async deleteFile(path, options = {}) {
253
+ await this.transport.ensureRunning();
254
+ const params = new URLSearchParams();
255
+ if (options.sessionId) params.set("sessionId", options.sessionId);
256
+ const query = params.toString();
257
+ await this.request(`/files/delete${query ? `?${query}` : ""}`, {
258
+ method: "POST",
259
+ body: JSON.stringify({ path })
260
+ });
261
+ }
262
+ async fileTree(path, options = {}) {
263
+ if (options.maxDepth !== void 0 && (!Number.isInteger(options.maxDepth) || options.maxDepth < 1 || options.maxDepth > 20)) throw new ValidationError("maxDepth must be an integer between 1 and 20");
264
+ await this.transport.ensureRunning();
265
+ const params = new URLSearchParams({ path });
266
+ if (options.maxDepth !== void 0) params.set("maxDepth", String(options.maxDepth));
267
+ if (options.sessionId) params.set("sessionId", options.sessionId);
268
+ return (await this.json(`/files/tree?${params}`, { method: "GET" })).data;
269
+ }
270
+ async createSession(options) {
271
+ await this.transport.ensureRunning();
272
+ const info = normalizeSessionInfo(await this.json("/agents/sessions", {
273
+ method: "POST",
274
+ body: JSON.stringify({
275
+ ...options.title !== void 0 ? { title: options.title } : {},
276
+ ...options.parentId !== void 0 ? { parentID: options.parentId } : {},
277
+ backend: normalizeRuntimeBackendConfig(options.backend)
278
+ })
279
+ }));
280
+ if (!info) throw new ServerError("Session creation response missing session id", 502, {
281
+ endpoint: "/agents/sessions",
282
+ origin: "runtime"
283
+ });
284
+ return info;
285
+ }
286
+ async messages(id, options = {}) {
287
+ await this.transport.ensureRunning();
288
+ const params = new URLSearchParams({ sessionId: id });
289
+ if (options.limit !== void 0) params.set("limit", String(options.limit));
290
+ if (options.offset !== void 0) params.set("offset", String(options.offset));
291
+ if (options.since !== void 0) params.set("since", String(options.since));
292
+ const query = params.toString();
293
+ return (await this.json(`/messages${query ? `?${query}` : ""}`, { method: "GET" })).map((message) => ({
294
+ id: message.info.id,
295
+ role: message.info.role,
296
+ timestamp: message.info.timestamp,
297
+ parts: message.parts,
298
+ metadata: message.info.metadata
299
+ }));
300
+ }
301
+ async createTaskSession(options) {
302
+ await this.transport.ensureRunning();
303
+ const info = await this.json("/tasks", {
304
+ method: "POST",
305
+ body: JSON.stringify({
306
+ sessionId: options.sessionId,
307
+ backend: normalizeRuntimeBackendConfig(options.backend),
308
+ title: options.title,
309
+ ...options.parentSessionId !== void 0 ? { parentSessionId: options.parentSessionId } : {},
310
+ ...options.profile !== void 0 ? { profile: options.profile } : {},
311
+ ...options.isolateFileWrites !== void 0 ? { isolateFileWrites: options.isolateFileWrites } : {}
312
+ })
313
+ });
314
+ if (!info.id) throw new ServerError("Task session creation response missing session id", 502, {
315
+ endpoint: "/tasks",
316
+ origin: "runtime"
317
+ });
318
+ return info;
319
+ }
320
+ async sendSessionMessage(id, request, options = {}) {
321
+ if (options.timeoutMs !== void 0 && options.timeoutMs <= 0) throw new ValidationError("timeoutMs must be greater than zero");
322
+ await this.transport.ensureRunning();
323
+ const headers = new Headers({ "x-no-retry": "true" });
324
+ if (options.credentials?.apiKey) headers.set("X-Backend-Api-Key", options.credentials.apiKey);
325
+ if (options.credentials?.baseUrl) headers.set("X-Backend-Base-Url", options.credentials.baseUrl);
326
+ const timeoutSignal = options.timeoutMs !== void 0 ? AbortSignal.timeout(options.timeoutMs) : void 0;
327
+ const signal = options.signal && timeoutSignal ? AbortSignal.any([options.signal, timeoutSignal]) : options.signal ?? timeoutSignal;
328
+ return this.json(`/agents/sessions/${encodeURIComponent(id)}/messages`, {
329
+ method: "POST",
330
+ headers,
331
+ signal,
332
+ body: JSON.stringify({
333
+ ...request.messageId !== void 0 ? { messageID: request.messageId } : {},
334
+ parts: request.parts,
335
+ ...request.system !== void 0 ? { system: request.system } : {},
336
+ ...request.agent !== void 0 ? { agent: request.agent } : {},
337
+ ...request.model !== void 0 ? { model: {
338
+ providerID: request.model.providerId,
339
+ modelID: request.model.modelId
340
+ } } : {},
341
+ ...request.reasoningEffort !== void 0 ? { reasoningEffort: request.reasoningEffort } : {},
342
+ ...request.turnId !== void 0 ? { turnId: request.turnId } : {},
343
+ ...request.interactions !== void 0 ? { interactions: request.interactions } : {}
344
+ })
345
+ });
346
+ }
347
+ async deleteSession(id) {
348
+ await this.transport.ensureRunning();
349
+ await this.request(`/agents/sessions/${encodeURIComponent(id)}`, { method: "DELETE" });
350
+ }
351
+ async taskSessionChanges(id) {
352
+ await this.transport.ensureRunning();
353
+ return this.json(`/tasks/${encodeURIComponent(id)}/changes`, { method: "GET" });
354
+ }
355
+ async commitTaskSession(id, options = {}) {
356
+ await this.transport.ensureRunning();
357
+ return this.json(`/tasks/${encodeURIComponent(id)}/changes`, {
358
+ method: "POST",
359
+ body: JSON.stringify({
360
+ ...options.message !== void 0 ? { message: options.message } : {},
361
+ ...options.files !== void 0 ? { files: options.files } : {}
362
+ })
363
+ });
364
+ }
365
+ async createTerminal(options = {}, request = {}) {
366
+ await this.transport.ensureRunning();
367
+ const params = new URLSearchParams();
368
+ if (request.sessionId) params.set("sessionId", request.sessionId);
369
+ const query = params.toString();
370
+ return (await this.json(`/terminals${query ? `?${query}` : ""}`, {
371
+ method: "POST",
372
+ body: JSON.stringify(options)
373
+ })).data;
374
+ }
375
+ async writeTerminal(terminalId, data, request = {}) {
376
+ await this.transport.ensureRunning();
377
+ const params = new URLSearchParams();
378
+ if (request.sessionId) params.set("sessionId", request.sessionId);
379
+ const query = params.toString();
380
+ await this.request(`/terminals/${encodeURIComponent(terminalId)}/input${query ? `?${query}` : ""}`, {
381
+ method: "POST",
382
+ body: JSON.stringify({ data })
383
+ });
384
+ }
385
+ async listTerminals() {
386
+ await this.transport.ensureRunning();
387
+ return (await this.json("/terminals", { method: "GET" })).data ?? [];
388
+ }
389
+ async getTerminal(terminalId) {
390
+ await this.transport.ensureRunning();
391
+ const response = await this.transport.fetch(`/terminals/${encodeURIComponent(terminalId)}`, { method: "GET" });
392
+ if (response.status === 404) return null;
393
+ await this.assertOk(response);
394
+ return (await response.json()).data;
395
+ }
396
+ async json(path, init) {
397
+ return await (await this.request(path, init)).json();
398
+ }
399
+ async request(path, init) {
400
+ const response = await this.transport.fetch(path, init);
401
+ await this.assertOk(response);
402
+ return response;
403
+ }
404
+ async assertOk(response) {
405
+ if (response.ok) return;
406
+ const body = await response.text();
407
+ throw parseErrorResponse(response.status, body, void 0, response.headers);
408
+ }
409
+ };
410
+ function normalizeSessionInfo(raw) {
411
+ const id = raw.id;
412
+ if (typeof id !== "string") return null;
413
+ const status = raw.status || "running";
414
+ return {
415
+ id,
416
+ parentId: typeof raw.parentID === "string" ? raw.parentID : typeof raw.parentId === "string" ? raw.parentId : void 0,
417
+ status: [
418
+ "queued",
419
+ "running",
420
+ "completed",
421
+ "failed",
422
+ "cancelled"
423
+ ].includes(status) ? status : "running",
424
+ backend: typeof raw.backendType === "string" ? raw.backendType : typeof raw.backend === "string" ? raw.backend : void 0,
425
+ model: typeof raw.model === "string" ? raw.model : void 0,
426
+ promptCount: typeof raw.promptCount === "number" ? raw.promptCount : void 0,
427
+ createdAt: raw.createdAt ? new Date(raw.createdAt) : void 0,
428
+ startedAt: raw.startedAt ? new Date(raw.startedAt) : void 0,
429
+ endedAt: raw.endedAt ? new Date(raw.endedAt) : void 0,
430
+ raw
431
+ };
432
+ }
433
+ //#endregion
434
+ export { serializeForSidecar as i, normalizeSessionInfo as n, normalizeRuntimeBackendConfig as r, SandboxRuntimeApi as t };
@@ -0,0 +1,62 @@
1
+ import { A as CommitTaskSessionOptions, B as CreateTaskSessionOptions, Cr as SandboxTerminalInfo, Gr as SessionMessage, Kt as ListMessagesOptions, Lr as SendSessionMessageOptions, Rr as SendSessionMessageRequest, Si as WriteFileOptions, Sr as SandboxTerminalCreateOptions, Tr as SandboxTerminalRequestOptions, Ur as SessionInfo, ai as TaskSessionCommitResult, br as SandboxRuntimeProfileList, dt as FileWriteResult, ii as TaskSessionChanges, it as FileReadBatchResult, lt as FileTreeOptions, pr as SandboxPortBinding, rt as FileReadBatchOptions, si as TaskSessionInfo, ut as FileTreeResult, vr as SandboxRuntimeHealth, wr as SandboxTerminalManager, z as CreateSessionOptions, zr as SentSessionMessage } from "./types-Cmpv-ox_.js";
2
+ import { a as NotFoundError, c as SandboxError, d as ServerError, f as StateError, i as NetworkError, l as SandboxErrorJson, m as ValidationError, n as CapabilityError, o as PartialFailureError, p as TimeoutError, s as QuotaError, t as AuthError, u as SandboxFailureDetail } from "./errors--P_nbLzM.js";
3
+
4
+ //#region src/runtime-api.d.ts
5
+ interface RuntimeTransport {
6
+ ensureRunning(): Promise<void>;
7
+ fetch(path: string, init?: RequestInit): Promise<Response>;
8
+ }
9
+ /** Internal typed client for routes served by a sandbox runtime. */
10
+ declare class SandboxRuntimeApi {
11
+ private readonly transport;
12
+ readonly terminals: SandboxTerminalManager;
13
+ constructor(transport: RuntimeTransport);
14
+ health(): Promise<SandboxRuntimeHealth>;
15
+ ports(): Promise<SandboxPortBinding[]>;
16
+ profiles(): Promise<SandboxRuntimeProfileList>;
17
+ readFiles(paths: string[], options?: FileReadBatchOptions): Promise<FileReadBatchResult>;
18
+ writeFile(path: string, content: string, options?: WriteFileOptions): Promise<FileWriteResult>;
19
+ deleteFile(path: string, options?: Pick<WriteFileOptions, "sessionId">): Promise<void>;
20
+ fileTree(path: string, options?: FileTreeOptions): Promise<FileTreeResult>;
21
+ createSession(options: CreateSessionOptions): Promise<SessionInfo>;
22
+ messages(id: string, options?: Omit<ListMessagesOptions, "sessionId">): Promise<SessionMessage[]>;
23
+ createTaskSession(options: CreateTaskSessionOptions): Promise<TaskSessionInfo>;
24
+ sendSessionMessage(id: string, request: SendSessionMessageRequest, options?: SendSessionMessageOptions): Promise<SentSessionMessage>;
25
+ deleteSession(id: string): Promise<void>;
26
+ taskSessionChanges(id: string): Promise<TaskSessionChanges>;
27
+ commitTaskSession(id: string, options?: CommitTaskSessionOptions): Promise<TaskSessionCommitResult>;
28
+ private createTerminal;
29
+ private writeTerminal;
30
+ private listTerminals;
31
+ private getTerminal;
32
+ private json;
33
+ private request;
34
+ private assertOk;
35
+ }
36
+ //#endregion
37
+ //#region src/runtime-client.d.ts
38
+ interface SandboxRuntimeClientConfig {
39
+ /** Browser-safe proxy base returned by `box.mintScopedToken()`. */
40
+ baseUrl: string;
41
+ /** Short-lived scoped token returned by `box.mintScopedToken()`. */
42
+ token: string;
43
+ /** Request timeout in milliseconds. Defaults to 30 seconds. */
44
+ timeoutMs?: number;
45
+ /** Fetch implementation override for Workers, tests, or custom runtimes. */
46
+ fetch?: typeof globalThis.fetch;
47
+ }
48
+ /**
49
+ * Browser- and Worker-safe client for one sandbox runtime.
50
+ *
51
+ * Construct it from the scoped token response returned by
52
+ * `box.mintScopedToken()`. The full Sandbox API key remains server-side.
53
+ */
54
+ declare class SandboxRuntimeClient extends SandboxRuntimeApi {
55
+ private readonly auth;
56
+ constructor(config: SandboxRuntimeClientConfig);
57
+ /** Replace an expiring scoped token without rebuilding consumers. */
58
+ updateToken(token: string): void;
59
+ }
60
+ declare function createSandboxRuntimeClient(config: SandboxRuntimeClientConfig): SandboxRuntimeClient;
61
+ //#endregion
62
+ export { AuthError, CapabilityError, type FileReadBatchOptions, type FileReadBatchResult, type FileTreeOptions, type FileTreeResult, type FileWriteResult, type ListMessagesOptions, NetworkError, NotFoundError, PartialFailureError, QuotaError, SandboxError, type SandboxErrorJson, type SandboxFailureDetail, SandboxRuntimeClient, type SandboxRuntimeClientConfig, type SandboxRuntimeHealth, type SandboxTerminalCreateOptions, type SandboxTerminalInfo, type SandboxTerminalManager, type SandboxTerminalRequestOptions, ServerError, type SessionMessage, StateError, TimeoutError, ValidationError, type WriteFileOptions, createSandboxRuntimeClient };
@@ -0,0 +1,81 @@
1
+ import { t as SandboxRuntimeApi } from "./runtime-api-CYA2DUQw.js";
2
+ import { a as NotFoundError, c as SandboxError, d as TimeoutError, f as ValidationError, i as NetworkError, l as ServerError, n as CapabilityError, o as PartialFailureError, s as QuotaError, t as AuthError, u as StateError } from "./errors-DSz87Rkk.js";
3
+ //#region src/runtime-client.ts
4
+ const DEFAULT_RUNTIME_TIMEOUT_MS = 3e4;
5
+ function requireToken(token) {
6
+ const value = token.trim();
7
+ if (!value) throw new ValidationError("Scoped runtime token is required");
8
+ return value;
9
+ }
10
+ function requireBaseUrl(baseUrl) {
11
+ let url;
12
+ try {
13
+ url = new URL(baseUrl);
14
+ } catch {
15
+ throw new ValidationError("Scoped runtime base URL must be absolute");
16
+ }
17
+ if (url.protocol !== "https:" && url.protocol !== "http:") throw new ValidationError("Scoped runtime base URL must use HTTP or HTTPS");
18
+ if (url.username || url.password) throw new ValidationError("Scoped runtime base URL must not include credentials");
19
+ if (url.search || url.hash) throw new ValidationError("Scoped runtime base URL must not include a query or fragment");
20
+ return url.toString().replace(/\/+$/, "");
21
+ }
22
+ function requireTimeout(timeoutMs) {
23
+ const value = timeoutMs ?? DEFAULT_RUNTIME_TIMEOUT_MS;
24
+ if (!Number.isFinite(value) || value <= 0) throw new ValidationError("Scoped runtime timeout must be positive");
25
+ return value;
26
+ }
27
+ /**
28
+ * Browser- and Worker-safe client for one sandbox runtime.
29
+ *
30
+ * Construct it from the scoped token response returned by
31
+ * `box.mintScopedToken()`. The full Sandbox API key remains server-side.
32
+ */
33
+ var SandboxRuntimeClient = class extends SandboxRuntimeApi {
34
+ auth;
35
+ constructor(config) {
36
+ const baseUrl = requireBaseUrl(config.baseUrl);
37
+ const auth = { token: requireToken(config.token) };
38
+ const timeoutMs = requireTimeout(config.timeoutMs);
39
+ const fetchImpl = config.fetch ?? globalThis.fetch;
40
+ if (typeof fetchImpl !== "function") throw new ValidationError("Scoped runtime client requires a fetch implementation");
41
+ super({
42
+ ensureRunning: async () => void 0,
43
+ fetch: async (path, init = {}) => {
44
+ if (!path.startsWith("/") || path.startsWith("//")) throw new ValidationError("Scoped runtime request paths must start with one slash");
45
+ const headers = new Headers(init.headers);
46
+ headers.set("Authorization", `Bearer ${auth.token}`);
47
+ const isFormData = typeof FormData !== "undefined" && init.body instanceof FormData;
48
+ if (init.body !== void 0 && !isFormData && !headers.has("Content-Type")) headers.set("Content-Type", "application/json");
49
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
50
+ const signal = init.signal ? AbortSignal.any([init.signal, timeoutSignal]) : timeoutSignal;
51
+ try {
52
+ return await fetchImpl(`${baseUrl}${path}`, {
53
+ ...init,
54
+ headers,
55
+ signal
56
+ });
57
+ } catch (error) {
58
+ if (timeoutSignal.aborted && !init.signal?.aborted) throw new TimeoutError(timeoutMs, void 0, {
59
+ origin: "runtime",
60
+ endpoint: path
61
+ });
62
+ if (init.signal?.aborted) throw error;
63
+ throw new NetworkError(`Scoped runtime request failed: ${path}`, error instanceof Error ? error : new Error(String(error)), {
64
+ origin: "runtime",
65
+ endpoint: path
66
+ });
67
+ }
68
+ }
69
+ });
70
+ this.auth = auth;
71
+ }
72
+ /** Replace an expiring scoped token without rebuilding consumers. */
73
+ updateToken(token) {
74
+ this.auth.token = requireToken(token);
75
+ }
76
+ };
77
+ function createSandboxRuntimeClient(config) {
78
+ return new SandboxRuntimeClient(config);
79
+ }
80
+ //#endregion
81
+ export { AuthError, CapabilityError, NetworkError, NotFoundError, PartialFailureError, QuotaError, SandboxError, SandboxRuntimeClient, ServerError, StateError, TimeoutError, ValidationError, createSandboxRuntimeClient };