@tangle-network/sandbox 0.10.4 → 0.10.5-develop.20260715115519.fee3d86
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/README.md +109 -0
- package/dist/agent/index.d.ts +3 -3
- package/dist/{client-B8i6qrQr.d.ts → client-CSaBJ8wD.d.ts} +7 -3
- package/dist/{client-DTpHjPjc.js → client-_OBj4sNO.js} +479 -61
- package/dist/collaboration/index.js +1 -1
- package/dist/{collaboration-QZXrXdIb.js → collaboration-CcZE2xMl.js} +1 -1
- package/dist/core.d.ts +4 -4
- package/dist/core.js +3 -3
- package/dist/{errors--P_nbLzM.d.ts → errors-CNCz3Ms9.d.ts} +1 -1
- package/dist/{errors-DSz87Rkk.js → errors-wd266B9Q.js} +3 -3
- package/dist/{index-BFnMEze6.d.ts → index-CEZaPvfX.d.ts} +2 -2
- package/dist/index.d.ts +28 -7
- package/dist/index.js +7 -282
- package/dist/intelligence/index.js +1 -1
- package/dist/{runtime-api-CYA2DUQw.js → runtime-api-BWq4XSrb.js} +269 -3
- package/dist/runtime.d.ts +50 -6
- package/dist/runtime.js +6 -4
- package/dist/{sandbox-BtNWbfd3.d.ts → sandbox-B9P4tyt4.d.ts} +11 -10
- package/dist/{sandbox-Be9WAqSg.js → sandbox-KiKLRbR_.js} +97 -45
- package/dist/tangle/index.d.ts +1 -1
- package/dist/tangle/index.js +1 -1
- package/dist/{tangle-D6UfK_B0.js → tangle-Os9sH-ms.js} +2 -2
- package/dist/{types-BvSoEHz8.d.ts → types-LNLeU9Ub.d.ts} +142 -25
- package/package.json +3 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { f as ValidationError, l as ServerError, p as parseErrorResponse } from "./errors-
|
|
1
|
+
import { c as SandboxError, d as TimeoutError, f as ValidationError, i as NetworkError, l as ServerError, p as parseErrorResponse, s as QuotaError } from "./errors-wd266B9Q.js";
|
|
2
|
+
import { FILE_UPLOAD_SESSION_MAX_BYTES, isFileTooLargeErrorBody, isPayloadTooLargeErrorBody } from "@tangle-network/runtime-contracts";
|
|
2
3
|
//#region src/backend-config.ts
|
|
3
4
|
const LEGACY_QUESTION_ALIAS_KEY = ["question", "Channel"].join("");
|
|
4
5
|
function parseModelString(model) {
|
|
@@ -153,6 +154,238 @@ function serializeForSidecar(profile) {
|
|
|
153
154
|
return toBackendProfile(profile);
|
|
154
155
|
}
|
|
155
156
|
//#endregion
|
|
157
|
+
//#region src/lib/chunked-upload.ts
|
|
158
|
+
/**
|
|
159
|
+
* Chunked upload — the sanctioned SDK path for delivering payloads larger
|
|
160
|
+
* than the sandbox API's single-request body caps. Splits the payload into
|
|
161
|
+
* server-sized parts against a `/fs/upload-session` session, PUTs each part
|
|
162
|
+
* with transient retry, then commits with a whole-payload SHA-256 so the
|
|
163
|
+
* runtime can verify nothing was dropped or reordered in transit.
|
|
164
|
+
*
|
|
165
|
+
* Browser/Worker-safe: no `node:` imports, no `Buffer`. Input normalizes to
|
|
166
|
+
* a `Uint8Array` and hashes via Web Crypto (`crypto.subtle`), available in
|
|
167
|
+
* browsers, Workers, and Node 18+ — the same environments this module must
|
|
168
|
+
* run in unmodified.
|
|
169
|
+
*/
|
|
170
|
+
const DEFAULT_MAX_RETRIES = 4;
|
|
171
|
+
const RETRY_BASE_MS = 250;
|
|
172
|
+
const RETRY_MAX_MS = 2e3;
|
|
173
|
+
const delay = (ms, signal) => new Promise((resolve, reject) => {
|
|
174
|
+
if (signal?.aborted) {
|
|
175
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const timer = setTimeout(() => {
|
|
179
|
+
signal?.removeEventListener("abort", onAbort);
|
|
180
|
+
resolve();
|
|
181
|
+
}, ms);
|
|
182
|
+
function onAbort() {
|
|
183
|
+
clearTimeout(timer);
|
|
184
|
+
reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
185
|
+
}
|
|
186
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
187
|
+
});
|
|
188
|
+
/** Transient part-upload failures worth retrying: rate-limit/budget (429),
|
|
189
|
+
* 5xx, transport (network), and request timeouts — mirrors
|
|
190
|
+
* `isTransientWriteError` in `sandbox.ts`. A non-transient error (bad path,
|
|
191
|
+
* auth, checksum, containment) fails loud immediately. */
|
|
192
|
+
function isTransientUploadError(err) {
|
|
193
|
+
return err instanceof QuotaError || err instanceof ServerError || err instanceof NetworkError || err instanceof TimeoutError;
|
|
194
|
+
}
|
|
195
|
+
function isChecksumMismatch(err) {
|
|
196
|
+
return err instanceof SandboxError && err.code === "CHECKSUM_MISMATCH";
|
|
197
|
+
}
|
|
198
|
+
/** Cheap size probe used for the pre-flight cap check, read directly off
|
|
199
|
+
* the input shape (`Blob.size` / `ArrayBuffer.byteLength` / view
|
|
200
|
+
* `byteLength`) so an oversized `Blob` never has its bytes materialized
|
|
201
|
+
* just to be rejected. Strings have no cheap length in UTF-8, so they're
|
|
202
|
+
* encoded once here (and once more in {@link normalizeToBytes} — an
|
|
203
|
+
* acceptable cost given strings are never the multi-MB case this path
|
|
204
|
+
* exists for). */
|
|
205
|
+
function sizeOfInput(data) {
|
|
206
|
+
if (typeof data === "string") return new TextEncoder().encode(data).byteLength;
|
|
207
|
+
if (data instanceof ArrayBuffer) return data.byteLength;
|
|
208
|
+
if (ArrayBuffer.isView(data)) return data.byteLength;
|
|
209
|
+
return data.size;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Normalizes to a `Uint8Array` backed by a plain (never shared)
|
|
213
|
+
* `ArrayBuffer`. A caller-supplied view may be backed by a
|
|
214
|
+
* `SharedArrayBuffer`, which `crypto.subtle.digest` and `fetch`'s
|
|
215
|
+
* `BodyInit` both reject at the type level (and some engines reject at
|
|
216
|
+
* runtime) — copying here keeps every downstream call on one concrete,
|
|
217
|
+
* always-accepted buffer type.
|
|
218
|
+
*/
|
|
219
|
+
async function normalizeToBytes(data) {
|
|
220
|
+
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
221
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data.slice(0));
|
|
222
|
+
if (ArrayBuffer.isView(data)) {
|
|
223
|
+
const copy = new Uint8Array(data.byteLength);
|
|
224
|
+
copy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
225
|
+
return copy;
|
|
226
|
+
}
|
|
227
|
+
return new Uint8Array(await data.arrayBuffer());
|
|
228
|
+
}
|
|
229
|
+
function webCryptoSubtle() {
|
|
230
|
+
const subtle = globalThis.crypto?.subtle;
|
|
231
|
+
if (!subtle) throw new Error("chunked upload requires Web Crypto (crypto.subtle) for SHA-256 hashing — available in browsers, Workers, and Node 18+");
|
|
232
|
+
return subtle;
|
|
233
|
+
}
|
|
234
|
+
async function sha256Hex(bytes) {
|
|
235
|
+
const digest = await webCryptoSubtle().digest("SHA-256", bytes);
|
|
236
|
+
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Canonical size-cap bodies (413 `PAYLOAD_TOO_LARGE` / `FILE_TOO_LARGE`)
|
|
240
|
+
* carry `surface`/`limitBytes`/`actualBytes` that the generic error parser
|
|
241
|
+
* drops; fold them into the message before delegating to
|
|
242
|
+
* `parseErrorResponse` for the rest (status→class mapping, retryAfterMs,
|
|
243
|
+
* origin).
|
|
244
|
+
*/
|
|
245
|
+
async function parseUploadError(response) {
|
|
246
|
+
const bodyText = await response.text();
|
|
247
|
+
let parsedBody;
|
|
248
|
+
try {
|
|
249
|
+
parsedBody = JSON.parse(bodyText);
|
|
250
|
+
} catch {
|
|
251
|
+
parsedBody = void 0;
|
|
252
|
+
}
|
|
253
|
+
if (isPayloadTooLargeErrorBody(parsedBody) || isFileTooLargeErrorBody(parsedBody)) {
|
|
254
|
+
const { code, message, surface, limitBytes, actualBytes } = parsedBody.error;
|
|
255
|
+
const detail = typeof actualBytes === "number" ? `${message} (${surface}: ${actualBytes} of ${limitBytes} bytes)` : `${message} (${surface}: limit ${limitBytes} bytes)`;
|
|
256
|
+
return parseErrorResponse(response.status, JSON.stringify({
|
|
257
|
+
code,
|
|
258
|
+
message: detail
|
|
259
|
+
}), void 0, response.headers);
|
|
260
|
+
}
|
|
261
|
+
return parseErrorResponse(response.status, bodyText, void 0, response.headers);
|
|
262
|
+
}
|
|
263
|
+
async function initUploadSession(transport, remotePath, totalBytes, sha256, mode, signal) {
|
|
264
|
+
signal?.throwIfAborted();
|
|
265
|
+
const response = await transport.fetch("/fs/upload-session", {
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers: { "Content-Type": "application/json" },
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
path: remotePath,
|
|
270
|
+
mode,
|
|
271
|
+
totalBytes,
|
|
272
|
+
sha256
|
|
273
|
+
}),
|
|
274
|
+
signal
|
|
275
|
+
});
|
|
276
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
277
|
+
return (await response.json()).data;
|
|
278
|
+
}
|
|
279
|
+
async function putPart(transport, uploadId, index, chunk, options) {
|
|
280
|
+
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
281
|
+
for (let attempt = 0;; attempt++) {
|
|
282
|
+
options.signal?.throwIfAborted();
|
|
283
|
+
try {
|
|
284
|
+
const response = await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}/parts/${index}`, {
|
|
285
|
+
method: "PUT",
|
|
286
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
287
|
+
body: chunk,
|
|
288
|
+
signal: options.signal
|
|
289
|
+
});
|
|
290
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
291
|
+
return;
|
|
292
|
+
} catch (err) {
|
|
293
|
+
if (isTransientUploadError(err) && attempt < maxRetries) {
|
|
294
|
+
const retryAfterMs = err instanceof SandboxError ? err.retryAfterMs : void 0;
|
|
295
|
+
const backoff = Math.min(RETRY_BASE_MS * 2 ** attempt, RETRY_MAX_MS);
|
|
296
|
+
await delay(retryAfterMs ?? backoff, options.signal);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function partCount(totalBytes, partSize) {
|
|
304
|
+
return Math.ceil(totalBytes / partSize);
|
|
305
|
+
}
|
|
306
|
+
async function uploadAllParts(transport, uploadId, bytes, partSize, totalParts, options) {
|
|
307
|
+
const totalBytes = bytes.byteLength;
|
|
308
|
+
const paceMs = options.paceMs ?? 0;
|
|
309
|
+
let uploadedBytes = 0;
|
|
310
|
+
let started = false;
|
|
311
|
+
for (let index = 0; index < totalParts; index++) {
|
|
312
|
+
if (started && paceMs > 0) await delay(paceMs, options.signal);
|
|
313
|
+
started = true;
|
|
314
|
+
const start = index * partSize;
|
|
315
|
+
const end = Math.min(start + partSize, totalBytes);
|
|
316
|
+
await putPart(transport, uploadId, index, bytes.subarray(start, end), options);
|
|
317
|
+
uploadedBytes += end - start;
|
|
318
|
+
options.onProgress?.({
|
|
319
|
+
bytesUploaded: uploadedBytes,
|
|
320
|
+
totalBytes,
|
|
321
|
+
percentage: totalBytes === 0 ? 100 : Math.round(uploadedBytes / totalBytes * 100)
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async function commitSession(transport, uploadId, totalParts, sha256, signal) {
|
|
326
|
+
signal?.throwIfAborted();
|
|
327
|
+
const response = await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}/commit`, {
|
|
328
|
+
method: "POST",
|
|
329
|
+
headers: { "Content-Type": "application/json" },
|
|
330
|
+
body: JSON.stringify({
|
|
331
|
+
totalParts,
|
|
332
|
+
sha256
|
|
333
|
+
}),
|
|
334
|
+
signal
|
|
335
|
+
});
|
|
336
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
337
|
+
return (await response.json()).data;
|
|
338
|
+
}
|
|
339
|
+
/** Best-effort abort of an in-progress session — never masks the real
|
|
340
|
+
* failure that triggered it, and never itself throws. An orphaned session
|
|
341
|
+
* also self-expires server-side (`expiresAt`), so a failed DELETE here is
|
|
342
|
+
* not a leak, just deferred cleanup. */
|
|
343
|
+
async function abortSession(transport, uploadId) {
|
|
344
|
+
try {
|
|
345
|
+
await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}`, { method: "DELETE" });
|
|
346
|
+
} catch {}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Upload arbitrary binary or text data to the sandbox via the chunked
|
|
350
|
+
* upload-session protocol, verifying integrity with a whole-payload
|
|
351
|
+
* SHA-256 at commit. Browser/Worker-safe and works identically over the
|
|
352
|
+
* gateway proxy or a direct sidecar connection — see
|
|
353
|
+
* {@link FileSystem.uploadData}.
|
|
354
|
+
*
|
|
355
|
+
* @param transport - Fetch-shaped adapter scoped to the sandbox runtime
|
|
356
|
+
* (paths are relative to it, e.g. `/fs/upload-session`).
|
|
357
|
+
* @param remotePath - Destination path in the sandbox.
|
|
358
|
+
* @param data - Payload to upload. Strings encode as UTF-8.
|
|
359
|
+
* @param options - See {@link ChunkedUploadOptions}.
|
|
360
|
+
* @throws {SandboxError} `PAYLOAD_TOO_LARGE` immediately (zero requests) if
|
|
361
|
+
* the payload exceeds {@link FILE_UPLOAD_SESSION_MAX_BYTES}; otherwise the
|
|
362
|
+
* typed error from whichever step (init/part/commit) failed after retries
|
|
363
|
+
* are exhausted.
|
|
364
|
+
*/
|
|
365
|
+
async function uploadChunked(transport, remotePath, data, options = {}) {
|
|
366
|
+
const estimatedSize = sizeOfInput(data);
|
|
367
|
+
if (estimatedSize > FILE_UPLOAD_SESSION_MAX_BYTES) throw new SandboxError(`Payload for ${remotePath} is ${estimatedSize} bytes, over the ${FILE_UPLOAD_SESSION_MAX_BYTES} byte chunked-upload session cap`, "PAYLOAD_TOO_LARGE", 413);
|
|
368
|
+
options.signal?.throwIfAborted();
|
|
369
|
+
const bytes = await normalizeToBytes(data);
|
|
370
|
+
options.signal?.throwIfAborted();
|
|
371
|
+
const sha256 = await sha256Hex(bytes);
|
|
372
|
+
const init = await initUploadSession(transport, remotePath, bytes.byteLength, sha256, options.mode, options.signal);
|
|
373
|
+
const totalParts = partCount(bytes.byteLength, init.partSize);
|
|
374
|
+
try {
|
|
375
|
+
await uploadAllParts(transport, init.uploadId, bytes, init.partSize, totalParts, options);
|
|
376
|
+
try {
|
|
377
|
+
return await commitSession(transport, init.uploadId, totalParts, sha256, options.signal);
|
|
378
|
+
} catch (err) {
|
|
379
|
+
if (!isChecksumMismatch(err)) throw err;
|
|
380
|
+
await uploadAllParts(transport, init.uploadId, bytes, init.partSize, totalParts, options);
|
|
381
|
+
return await commitSession(transport, init.uploadId, totalParts, sha256, options.signal);
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
await abortSession(transport, init.uploadId);
|
|
385
|
+
throw err;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
//#endregion
|
|
156
389
|
//#region src/runtime-api.ts
|
|
157
390
|
/** Internal typed client for routes served by a sandbox runtime. */
|
|
158
391
|
var SandboxRuntimeApi = class {
|
|
@@ -203,7 +436,7 @@ var SandboxRuntimeApi = class {
|
|
|
203
436
|
method: "POST",
|
|
204
437
|
body: JSON.stringify({
|
|
205
438
|
paths: chunk,
|
|
206
|
-
|
|
439
|
+
encoding: options.encoding ?? "utf8"
|
|
207
440
|
})
|
|
208
441
|
});
|
|
209
442
|
for (const [path, result] of Object.entries(payload.data.files)) if (result.success) files.push({
|
|
@@ -249,6 +482,25 @@ var SandboxRuntimeApi = class {
|
|
|
249
482
|
})
|
|
250
483
|
})).data;
|
|
251
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Upload in-memory binary or text data to the sandbox over the chunked
|
|
487
|
+
* upload-session protocol — the browser/Worker-safe sanctioned path for
|
|
488
|
+
* payloads over ~1 MiB, sized to clear the gateway proxy's per-request cap
|
|
489
|
+
* (parts stay under {@link FILE_UPLOAD_PART_MAX_BYTES}). Binary-safe:
|
|
490
|
+
* accepts a `Blob`, `ArrayBuffer`, `ArrayBufferView`, or UTF-8 `string`.
|
|
491
|
+
* Delegates to the shared `uploadChunked` engine in `lib/chunked-upload.js`,
|
|
492
|
+
* wired to this client's `transport.fetch` so requests carry the same
|
|
493
|
+
* scoped-token `Authorization` header and base URL as every other method
|
|
494
|
+
* on this class (e.g. {@link SandboxRuntimeApi.writeFile}) — works
|
|
495
|
+
* identically over the gateway proxy or a direct sidecar connection.
|
|
496
|
+
*
|
|
497
|
+
* @throws {SandboxError} `PAYLOAD_TOO_LARGE` immediately, before any
|
|
498
|
+
* request, if the payload exceeds the chunked-upload session cap.
|
|
499
|
+
*/
|
|
500
|
+
async uploadData(remotePath, data, options) {
|
|
501
|
+
await this.transport.ensureRunning();
|
|
502
|
+
return uploadChunked({ fetch: (path, init) => this.transport.fetch(path, init) }, remotePath, data, options);
|
|
503
|
+
}
|
|
252
504
|
async deleteFile(path, options = {}) {
|
|
253
505
|
await this.transport.ensureRunning();
|
|
254
506
|
const params = new URLSearchParams();
|
|
@@ -259,6 +511,19 @@ var SandboxRuntimeApi = class {
|
|
|
259
511
|
body: JSON.stringify({ path })
|
|
260
512
|
});
|
|
261
513
|
}
|
|
514
|
+
async renameFile(sourcePath, destinationPath, options = {}) {
|
|
515
|
+
await this.transport.ensureRunning();
|
|
516
|
+
const params = new URLSearchParams();
|
|
517
|
+
if (options.sessionId) params.set("sessionId", options.sessionId);
|
|
518
|
+
const query = params.toString();
|
|
519
|
+
return (await this.json(`/files/rename${query ? `?${query}` : ""}`, {
|
|
520
|
+
method: "POST",
|
|
521
|
+
body: JSON.stringify({
|
|
522
|
+
sourcePath,
|
|
523
|
+
destinationPath
|
|
524
|
+
})
|
|
525
|
+
})).data;
|
|
526
|
+
}
|
|
262
527
|
async fileTree(path, options = {}) {
|
|
263
528
|
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
529
|
await this.transport.ensureRunning();
|
|
@@ -272,6 +537,7 @@ var SandboxRuntimeApi = class {
|
|
|
272
537
|
const info = normalizeSessionInfo(await this.json("/agents/sessions", {
|
|
273
538
|
method: "POST",
|
|
274
539
|
body: JSON.stringify({
|
|
540
|
+
...options.sessionId !== void 0 ? { sessionId: options.sessionId } : {},
|
|
275
541
|
...options.title !== void 0 ? { title: options.title } : {},
|
|
276
542
|
...options.parentId !== void 0 ? { parentID: options.parentId } : {},
|
|
277
543
|
backend: normalizeRuntimeBackendConfig(options.backend)
|
|
@@ -431,4 +697,4 @@ function normalizeSessionInfo(raw) {
|
|
|
431
697
|
};
|
|
432
698
|
}
|
|
433
699
|
//#endregion
|
|
434
|
-
export { serializeForSidecar as i, normalizeSessionInfo as n,
|
|
700
|
+
export { serializeForSidecar as a, normalizeRuntimeBackendConfig as i, normalizeSessionInfo as n, uploadChunked as r, SandboxRuntimeApi as t };
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
import {
|
|
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
|
|
1
|
+
import { Ai as UploadProgress, E as ChunkedUploadResult, Fr as SandboxTerminalManager, H as CreateTaskSessionOptions, Ir as SandboxTerminalRequestOptions, Jr as SendSessionMessageOptions, M as CommitTaskSessionOptions, Nr as SandboxTerminalCreateOptions, Pi as WriteFileOptions, Pr as SandboxTerminalInfo, T as ChunkedUploadOptions, V as CreateSessionOptions, Xr as SentSessionMessage, Yr as SendSessionMessageRequest, Yt as ListMessagesOptions, at as FileReadBatchOptions, ei as SessionInfo, ft as FileTreeOptions, gi as TaskSessionCommitResult, hi as TaskSessionChanges, jn as RenameOptions, jr as SandboxRuntimeProfileList, kr as SandboxRuntimeHealth, lt as FileRenameResult, mt as FileWriteResult, ni as SessionMessage, ot as FileReadBatchResult, pt as FileTreeResult, vi as TaskSessionInfo, wr as SandboxPortBinding } from "./types-LNLeU9Ub.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-CNCz3Ms9.js";
|
|
3
3
|
|
|
4
|
+
//#region src/lib/chunked-upload.d.ts
|
|
5
|
+
/** The transport a caller wires this module to — {@link SandboxInstance.runtimeFetch}
|
|
6
|
+
* in the SDK, or any fetch-shaped adapter in a standalone consumer. */
|
|
7
|
+
interface ChunkedUploadTransport {
|
|
8
|
+
fetch(path: string, init?: RequestInit): Promise<Response>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Upload arbitrary binary or text data to the sandbox via the chunked
|
|
12
|
+
* upload-session protocol, verifying integrity with a whole-payload
|
|
13
|
+
* SHA-256 at commit. Browser/Worker-safe and works identically over the
|
|
14
|
+
* gateway proxy or a direct sidecar connection — see
|
|
15
|
+
* {@link FileSystem.uploadData}.
|
|
16
|
+
*
|
|
17
|
+
* @param transport - Fetch-shaped adapter scoped to the sandbox runtime
|
|
18
|
+
* (paths are relative to it, e.g. `/fs/upload-session`).
|
|
19
|
+
* @param remotePath - Destination path in the sandbox.
|
|
20
|
+
* @param data - Payload to upload. Strings encode as UTF-8.
|
|
21
|
+
* @param options - See {@link ChunkedUploadOptions}.
|
|
22
|
+
* @throws {SandboxError} `PAYLOAD_TOO_LARGE` immediately (zero requests) if
|
|
23
|
+
* the payload exceeds {@link FILE_UPLOAD_SESSION_MAX_BYTES}; otherwise the
|
|
24
|
+
* typed error from whichever step (init/part/commit) failed after retries
|
|
25
|
+
* are exhausted.
|
|
26
|
+
*/
|
|
27
|
+
declare function uploadChunked(transport: ChunkedUploadTransport, remotePath: string, data: Blob | ArrayBuffer | ArrayBufferView | string, options?: ChunkedUploadOptions): Promise<ChunkedUploadResult>;
|
|
28
|
+
//#endregion
|
|
4
29
|
//#region src/runtime-api.d.ts
|
|
5
30
|
interface RuntimeTransport {
|
|
6
31
|
ensureRunning(): Promise<void>;
|
|
@@ -16,7 +41,24 @@ declare class SandboxRuntimeApi {
|
|
|
16
41
|
profiles(): Promise<SandboxRuntimeProfileList>;
|
|
17
42
|
readFiles(paths: string[], options?: FileReadBatchOptions): Promise<FileReadBatchResult>;
|
|
18
43
|
writeFile(path: string, content: string, options?: WriteFileOptions): Promise<FileWriteResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Upload in-memory binary or text data to the sandbox over the chunked
|
|
46
|
+
* upload-session protocol — the browser/Worker-safe sanctioned path for
|
|
47
|
+
* payloads over ~1 MiB, sized to clear the gateway proxy's per-request cap
|
|
48
|
+
* (parts stay under {@link FILE_UPLOAD_PART_MAX_BYTES}). Binary-safe:
|
|
49
|
+
* accepts a `Blob`, `ArrayBuffer`, `ArrayBufferView`, or UTF-8 `string`.
|
|
50
|
+
* Delegates to the shared `uploadChunked` engine in `lib/chunked-upload.js`,
|
|
51
|
+
* wired to this client's `transport.fetch` so requests carry the same
|
|
52
|
+
* scoped-token `Authorization` header and base URL as every other method
|
|
53
|
+
* on this class (e.g. {@link SandboxRuntimeApi.writeFile}) — works
|
|
54
|
+
* identically over the gateway proxy or a direct sidecar connection.
|
|
55
|
+
*
|
|
56
|
+
* @throws {SandboxError} `PAYLOAD_TOO_LARGE` immediately, before any
|
|
57
|
+
* request, if the payload exceeds the chunked-upload session cap.
|
|
58
|
+
*/
|
|
59
|
+
uploadData(remotePath: string, data: Blob | ArrayBuffer | ArrayBufferView | string, options?: ChunkedUploadOptions): Promise<ChunkedUploadResult>;
|
|
19
60
|
deleteFile(path: string, options?: Pick<WriteFileOptions, "sessionId">): Promise<void>;
|
|
61
|
+
renameFile(sourcePath: string, destinationPath: string, options?: RenameOptions): Promise<FileRenameResult>;
|
|
20
62
|
fileTree(path: string, options?: FileTreeOptions): Promise<FileTreeResult>;
|
|
21
63
|
createSession(options: CreateSessionOptions): Promise<SessionInfo>;
|
|
22
64
|
messages(id: string, options?: Omit<ListMessagesOptions, "sessionId">): Promise<SessionMessage[]>;
|
|
@@ -36,9 +78,9 @@ declare class SandboxRuntimeApi {
|
|
|
36
78
|
//#endregion
|
|
37
79
|
//#region src/runtime-client.d.ts
|
|
38
80
|
interface SandboxRuntimeClientConfig {
|
|
39
|
-
/** Browser-safe proxy base returned by
|
|
81
|
+
/** Browser-safe proxy base returned by a runtime-scoped token mint. */
|
|
40
82
|
baseUrl: string;
|
|
41
|
-
/** Short-lived
|
|
83
|
+
/** Short-lived `session-runtime` or `read-only` token. */
|
|
42
84
|
token: string;
|
|
43
85
|
/** Request timeout in milliseconds. Defaults to 30 seconds. */
|
|
44
86
|
timeoutMs?: number;
|
|
@@ -49,7 +91,9 @@ interface SandboxRuntimeClientConfig {
|
|
|
49
91
|
* Browser- and Worker-safe client for one sandbox runtime.
|
|
50
92
|
*
|
|
51
93
|
* Construct it from the scoped token response returned by
|
|
52
|
-
* `box.mintScopedToken(
|
|
94
|
+
* `box.mintScopedToken({ scope: "session-runtime", sessionId })` or
|
|
95
|
+
* `box.mintScopedToken({ scope: "read-only" })`. The full Sandbox API key
|
|
96
|
+
* remains server-side.
|
|
53
97
|
*/
|
|
54
98
|
declare class SandboxRuntimeClient extends SandboxRuntimeApi {
|
|
55
99
|
private readonly auth;
|
|
@@ -59,4 +103,4 @@ declare class SandboxRuntimeClient extends SandboxRuntimeApi {
|
|
|
59
103
|
}
|
|
60
104
|
declare function createSandboxRuntimeClient(config: SandboxRuntimeClientConfig): SandboxRuntimeClient;
|
|
61
105
|
//#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 };
|
|
106
|
+
export { AuthError, CapabilityError, type ChunkedUploadOptions, type ChunkedUploadResult, type ChunkedUploadTransport, type FileReadBatchOptions, type FileReadBatchResult, type FileRenameResult, type FileTreeOptions, type FileTreeResult, type FileWriteResult, type ListMessagesOptions, NetworkError, NotFoundError, PartialFailureError, QuotaError, type RenameOptions, SandboxError, type SandboxErrorJson, type SandboxFailureDetail, SandboxRuntimeClient, type SandboxRuntimeClientConfig, type SandboxRuntimeHealth, type SandboxTerminalCreateOptions, type SandboxTerminalInfo, type SandboxTerminalManager, type SandboxTerminalRequestOptions, ServerError, type SessionMessage, StateError, TimeoutError, type UploadProgress, ValidationError, type WriteFileOptions, createSandboxRuntimeClient, uploadChunked };
|
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as SandboxRuntimeApi } from "./runtime-api-
|
|
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-
|
|
1
|
+
import { r as uploadChunked, t as SandboxRuntimeApi } from "./runtime-api-BWq4XSrb.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-wd266B9Q.js";
|
|
3
3
|
//#region src/runtime-client.ts
|
|
4
4
|
const DEFAULT_RUNTIME_TIMEOUT_MS = 3e4;
|
|
5
5
|
function requireToken(token) {
|
|
@@ -28,7 +28,9 @@ function requireTimeout(timeoutMs) {
|
|
|
28
28
|
* Browser- and Worker-safe client for one sandbox runtime.
|
|
29
29
|
*
|
|
30
30
|
* Construct it from the scoped token response returned by
|
|
31
|
-
* `box.mintScopedToken(
|
|
31
|
+
* `box.mintScopedToken({ scope: "session-runtime", sessionId })` or
|
|
32
|
+
* `box.mintScopedToken({ scope: "read-only" })`. The full Sandbox API key
|
|
33
|
+
* remains server-side.
|
|
32
34
|
*/
|
|
33
35
|
var SandboxRuntimeClient = class extends SandboxRuntimeApi {
|
|
34
36
|
auth;
|
|
@@ -78,4 +80,4 @@ function createSandboxRuntimeClient(config) {
|
|
|
78
80
|
return new SandboxRuntimeClient(config);
|
|
79
81
|
}
|
|
80
82
|
//#endregion
|
|
81
|
-
export { AuthError, CapabilityError, NetworkError, NotFoundError, PartialFailureError, QuotaError, SandboxError, SandboxRuntimeClient, ServerError, StateError, TimeoutError, ValidationError, createSandboxRuntimeClient };
|
|
83
|
+
export { AuthError, CapabilityError, NetworkError, NotFoundError, PartialFailureError, QuotaError, SandboxError, SandboxRuntimeClient, ServerError, StateError, TimeoutError, ValidationError, createSandboxRuntimeClient, uploadChunked };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as EgressManager, $r as SessionForkOptions, At as GitStatus, Br as SandboxTraceOptions, D as CodeExecutionOptions, Di as TurnDriveResult, Dr as SandboxResourceUsage, Dt as GitCommit, Et as GitBranch, Fi as WriteManyFile, Fr as SandboxTerminalManager, G as DispatchPromptOptions, Gn as SandboxConnection, Gr as SearchOptions, Gt as IntelligenceReportCompareTo, H as CreateTaskSessionOptions, Hn as SSHCommandDescriptor, Hr as ScopedToken, Ht as InstalledTool, Ii as WriteManyOptions, In as RolloutOptions, It as GpuLeaseManager, Jr as SendSessionMessageOptions, Jt as JsonValue, K as DispatchedSession, Lr as SandboxTraceBundle, M as CommitTaskSessionOptions, Mi as WaitForOptions, Mn as RestoreSnapshotOptions, Mr as SandboxStatus, N as CompletedTurnResult, Ni as WaitForRolloutOptions, Nn as ResumeOptions, O as CodeExecutionResult, Pi as WriteFileOptions, Pn as Rollout, Qr as SessionEventStreamOptions, Rn as RolloutStartResult, Si as TeeAttestationResponse, Un as SSHCredentials, Ut as IntelligenceReport, V as CreateSessionOptions, Wr as SearchMatch, Wt as IntelligenceReportBudget, Xr as SentSessionMessage, Y as DriveTurnOptions, Yr as SendSessionMessageRequest, Yt as ListMessagesOptions, Z as DriverInfo, _n as PromptOptions, ai as SnapshotInfo, bi as TeeAttestationOptions, bn as ProvisionResult, cn as PreviewLinkManager, ei as SessionInfo, en as MintScopedTokenOptions, fn as ProcessManager, fr as SandboxFleetTraceBundle, gi as TaskSessionCommitResult, gn as PromptInputPart, hi as TaskSessionChanges, jr as SandboxRuntimeProfileList, jt as GpuLease, k as CodeLanguage, kr as SandboxRuntimeHealth, kt as GitDiff, l as BackendManager, li as StartupDiagnostics, mi as TaskResult, mt as FileWriteResult, ni as SessionMessage, nt as ExecOptions, oi as SnapshotOptions, on as PermissionsManager, pi as TaskOptions, qn as SandboxEvent, qt as IntelligenceReportWindow, rn as NetworkManager, rt as ExecResult, s as BackendConfig, si as SnapshotResult, ti as SessionListOptions, tt as EventStreamOptions, ut as FileSystem, vi as TaskSessionInfo, vn as PromptResult, w as BranchOptions, wi as TeePublicKeyResponse, wr as SandboxPortBinding, xr as SandboxInfo, yn as ProvisionEvent } from "./types-LNLeU9Ub.js";
|
|
2
2
|
|
|
3
3
|
//#region src/mcp.d.ts
|
|
4
4
|
/**
|
|
@@ -894,12 +894,18 @@ declare class SandboxInstance {
|
|
|
894
894
|
private fsReadBatch;
|
|
895
895
|
private fsTree;
|
|
896
896
|
private fsUpload;
|
|
897
|
+
/** See {@link FileSystem.uploadData}. Delegates to the shared, browser-safe
|
|
898
|
+
* chunked-upload flow in `lib/chunked-upload.ts`, wired to this sandbox's
|
|
899
|
+
* runtime endpoint (works over the gateway proxy or a direct connection —
|
|
900
|
+
* both are transparent through `runtimeFetch`). */
|
|
901
|
+
private fsUploadData;
|
|
897
902
|
private fsDownload;
|
|
898
903
|
private fsUploadDir;
|
|
899
904
|
private fsDownloadDir;
|
|
900
905
|
private fsList;
|
|
901
906
|
private fsStat;
|
|
902
907
|
private fsDelete;
|
|
908
|
+
private fsRename;
|
|
903
909
|
private fsMkdir;
|
|
904
910
|
private fsExists;
|
|
905
911
|
/**
|
|
@@ -1498,15 +1504,10 @@ declare class SandboxInstance {
|
|
|
1498
1504
|
*/
|
|
1499
1505
|
driveTurn(message: string | PromptInputPart[], opts: DriveTurnOptions): Promise<TurnDriveResult>;
|
|
1500
1506
|
/**
|
|
1501
|
-
* Mint a scoped, time-bounded JWT for
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
* Use this to give a browser direct read access to the sandbox without
|
|
1507
|
-
* leaking the full bearer (`box.connection.authToken`). The returned
|
|
1508
|
-
* token verifies against the same sidecar middleware that already
|
|
1509
|
-
* gates ProductTokenIssuer-issued JWTs — no new sidecar surface.
|
|
1507
|
+
* Mint a scoped, time-bounded JWT for browser access (Issue #913 Gap 1).
|
|
1508
|
+
* Authority is the caller's `TANGLE_API_KEY` (sk-tan-*); signing secrets
|
|
1509
|
+
* stay server-side. Session/project scopes work with SessionGatewayClient,
|
|
1510
|
+
* while session-runtime/read-only scopes work with SandboxRuntimeClient.
|
|
1510
1511
|
*/
|
|
1511
1512
|
mintScopedToken(opts: MintScopedTokenOptions): Promise<ScopedToken>;
|
|
1512
1513
|
/** @internal — invoked by SandboxSession.status(). */
|