@tangle-network/sandbox 0.60.31-develop.20261010074258.7991cf8 → 0.60.31-develop.20261010075509.de7486e
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/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +4 -4
- package/dist/agent/preview.d.ts +1 -1
- package/dist/agent/preview.js +2 -2
- package/dist/{agent-run-outcome-C8Si8478.d.ts → agent-run-outcome-CGf6PAs8.d.ts} +1 -1
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +1 -1
- package/dist/{browser-interactive-control-controller-DRCfxOQz.d.ts → browser-interactive-control-controller-JUW3gOGH.d.ts} +1 -1
- package/dist/chunked-upload-CfefWUE5.js +435 -0
- package/dist/chunked-upload-file-Bo2ROB52.js +109 -0
- package/dist/{client-HewG9j9A.d.ts → client-B6JfkRhc.d.ts} +5 -5
- package/dist/{client-BzXVeXvo.js → client-p2d-6oAH.js} +4 -4
- package/dist/collaboration/index.d.ts +1 -1
- package/dist/collaboration/index.js +1 -1
- package/dist/core.d.ts +5 -5
- package/dist/core.js +3 -3
- package/dist/{index-D_o4zbXJ.d.ts → index-DHgljRHu.d.ts} +2 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +6 -6
- package/dist/interactive-control.d.ts +1 -1
- package/dist/{interactive-controller-ykaThYp6.d.ts → interactive-controller-DNbLzamS.d.ts} +2 -2
- package/dist/{interactive-controller-CvW2-UfM.js → interactive-controller-Dxt5sW2N.js} +3 -291
- package/dist/{lines-DCxU0xIV.d.ts → lines-BOWMNDp5.d.ts} +1 -1
- package/dist/lines.d.ts +1 -1
- package/dist/{local-cli-auth-Cr1fyoKv.js → local-cli-auth-BWELjBLz.js} +1 -1
- package/dist/{mcp-local-DY1CnWBn.js → mcp-local-DjryqUiY.js} +1 -1
- package/dist/{preview-DcT5Fb1W.d.ts → preview-B4yfnMgD.d.ts} +3 -3
- package/dist/runtime.d.ts +6 -31
- package/dist/runtime.js +2 -1
- package/dist/{sandbox-CbuA-iZi.js → sandbox-B6LlVm4f.js} +109 -8
- package/dist/{sandbox-CrET4m65.d.ts → sandbox-WpE5rzUa.d.ts} +6 -6
- package/dist/{secp256k1-CyKOxB5J.js → secp256k1-Dx2XABHz.js} +1 -1
- package/dist/tangle/index.d.ts +1 -1
- package/dist/tangle/index.js +1 -1
- package/dist/{tangle-C1dd-4xk.js → tangle-Ux41HNTu.js} +3 -3
- package/dist/{types-BeWUGJ5S.d.ts → types-i3Vs02b8.d.ts} +74 -3
- package/package.json +5 -5
- /package/dist/{cli-auth-bundle-BwIJkzAQ.js → cli-auth-bundle-Dm8w5faq.js} +0 -0
- /package/dist/{cli-auth-bundle-BMcIiB-I.d.ts → cli-auth-bundle-ODe06Ts7.d.ts} +0 -0
- /package/dist/{collaboration-CrO2Lhyi.js → collaboration-DaWEv29D.js} +0 -0
- /package/dist/{errors-D7RVedpR.d.ts → errors-CRssX9qs.d.ts} +0 -0
- /package/dist/{index-BoQeoNOD.d.ts → index-BgmgfYZZ.d.ts} +0 -0
- /package/dist/{index-BXcL8P-U.d.ts → index-DHuHjNie.d.ts} +0 -0
- /package/dist/{line-application-C2SuT1zK.js → line-application-Cq6dJLBD.js} +0 -0
- /package/dist/{preview-operations-CbTiBE-a.js → preview-operations-DqSo-IBm.js} +0 -0
- /package/dist/{raw-evidence-archive-Bi-Lt83d.js → raw-evidence-archive-Br5a3xZ_.js} +0 -0
- /package/dist/{terminal-stream-B6bUr0hj.d.ts → terminal-stream-CV1pMSKC.d.ts} +0 -0
- /package/dist/{utils-ChcSLv53.js → utils-B7_9Hl_z.js} +0 -0
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as SandboxSession, h as SandboxTaskSession, r as SandboxInstance } from "../sandbox-
|
|
2
|
-
import { D as CodeExecutionResult, E as CodeExecutionOptions, Ji as SessionInfo, Jr as SandboxFleetParent, O as CodeLanguage, Xi as SessionListOptions,
|
|
3
|
-
import { i as Sandbox } from "../client-
|
|
4
|
-
import { u as PreviewAuthorizer } from "../preview-
|
|
1
|
+
import { _ as SandboxSession, h as SandboxTaskSession, r as SandboxInstance } from "../sandbox-WpE5rzUa.js";
|
|
2
|
+
import { D as CodeExecutionResult, E as CodeExecutionOptions, Ji as SessionInfo, Jr as SandboxFleetParent, O as CodeLanguage, Xi as SessionListOptions, co as BackendType, d as BackendConfig, k as CodeResultPart } from "../types-i3Vs02b8.js";
|
|
3
|
+
import { i as Sandbox } from "../client-B6JfkRhc.js";
|
|
4
|
+
import { u as PreviewAuthorizer } from "../preview-B4yfnMgD.js";
|
|
5
5
|
import * as _$_modelcontextprotocol_sdk_server_index_js0 from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { JSONSchema } from "zod/v4/core";
|
|
7
7
|
import { ToolSet } from "ai";
|
package/dist/agent/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as TOOL_SPECS, i as ALL_TOOL_SPECS, o as serializeToolResult, r as bindToolSpecs, t as createMcpServer } from "../mcp-local-
|
|
2
|
-
import {
|
|
1
|
+
import { a as TOOL_SPECS, i as ALL_TOOL_SPECS, o as serializeToolResult, r as bindToolSpecs, t as createMcpServer } from "../mcp-local-DjryqUiY.js";
|
|
2
|
+
import { E as assertCurrentBackendType } from "../interactive-controller-Dxt5sW2N.js";
|
|
3
3
|
import { h as StateError, l as NotFoundError, v as ValidationError } from "../errors-Cq4hMysQ.js";
|
|
4
|
-
import { n as Sandbox } from "../client-
|
|
5
|
-
import { t as SandboxInstance } from "../sandbox-
|
|
4
|
+
import { n as Sandbox } from "../client-p2d-6oAH.js";
|
|
5
|
+
import { t as SandboxInstance } from "../sandbox-B6LlVm4f.js";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
//#region src/agent/instances.ts
|
|
8
8
|
const managers = /* @__PURE__ */ new WeakMap();
|
package/dist/agent/preview.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as publishAgentPreview, a as previewOperationTool, c as AgentPreviewOptions, d as PreviewExecutionContext, f as PublishAgentPreviewOptions, g as listAgentPreviews, h as getAgentPreview, i as PreviewTool, l as PreviewAuthorizationRequest, m as ensureAgentPreview, n as PREVIEW_MCP_ALIAS, o as previewToolsForProfile, p as assertPreviewId, r as PREVIEW_TOOLS, s as AgentPreviewError, t as servePreviewMcp, u as PreviewAuthorizer, v as removeAgentPreview, y as resolveSelfSandbox } from "../preview-
|
|
1
|
+
import { _ as publishAgentPreview, a as previewOperationTool, c as AgentPreviewOptions, d as PreviewExecutionContext, f as PublishAgentPreviewOptions, g as listAgentPreviews, h as getAgentPreview, i as PreviewTool, l as PreviewAuthorizationRequest, m as ensureAgentPreview, n as PREVIEW_MCP_ALIAS, o as previewToolsForProfile, p as assertPreviewId, r as PREVIEW_TOOLS, s as AgentPreviewError, t as servePreviewMcp, u as PreviewAuthorizer, v as removeAgentPreview, y as resolveSelfSandbox } from "../preview-B4yfnMgD.js";
|
|
2
2
|
export { AgentPreviewError, AgentPreviewOptions, PREVIEW_MCP_ALIAS, PREVIEW_TOOLS, PreviewAuthorizationRequest, PreviewAuthorizer, PreviewExecutionContext, PreviewTool, PublishAgentPreviewOptions, assertPreviewId, ensureAgentPreview, getAgentPreview, listAgentPreviews, previewOperationTool, previewToolsForProfile, publishAgentPreview, removeAgentPreview, resolveSelfSandbox, servePreviewMcp };
|
package/dist/agent/preview.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as listAgentPreviews, c as resolveSelfSandbox, i as getAgentPreview, n as assertPreviewId, o as publishAgentPreview, r as ensureAgentPreview, s as removeAgentPreview, t as AgentPreviewError } from "../preview-operations-
|
|
1
|
+
import { a as listAgentPreviews, c as resolveSelfSandbox, i as getAgentPreview, n as assertPreviewId, o as publishAgentPreview, r as ensureAgentPreview, s as removeAgentPreview, t as AgentPreviewError } from "../preview-operations-DqSo-IBm.js";
|
|
2
2
|
import { agentProfileSchema } from "@tangle-network/agent-interface";
|
|
3
3
|
//#region src/agent/preview-policy.ts
|
|
4
4
|
/** Channel-neutral preview tool selection from a host-authored profile. */
|
|
@@ -66,7 +66,7 @@ async function servePreviewMcp(request, config) {
|
|
|
66
66
|
if (typeof config.authorize !== "function") throw new Error("Preview MCP requires a host authorization callback");
|
|
67
67
|
const tools = config.tools ?? PREVIEW_TOOLS;
|
|
68
68
|
if (!tools.length || tools.some((tool) => !PREVIEW_TOOLS.includes(tool))) throw new Error("Preview MCP requires an explicit nonempty preview-only tool grant");
|
|
69
|
-
const [{ createMcpServer }, { WebStandardStreamableHTTPServerTransport }] = await Promise.all([import("../mcp-local-
|
|
69
|
+
const [{ createMcpServer }, { WebStandardStreamableHTTPServerTransport }] = await Promise.all([import("../mcp-local-DjryqUiY.js").then((n) => n.n), import("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js")]);
|
|
70
70
|
const handle = await createMcpServer(config.box, {
|
|
71
71
|
name: "tangle-previews",
|
|
72
72
|
sessionId: config.sessionId,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as AgentQuestionRequest, ct as DurablePlanSnapshot, i as AgentApprovalRequirement, kr as SandboxEvent, o as AgentRunStatus, s as AgentToolInvocation } from "./types-
|
|
1
|
+
import { a as AgentQuestionRequest, ct as DurablePlanSnapshot, i as AgentApprovalRequirement, kr as SandboxEvent, o as AgentRunStatus, s as AgentToolInvocation } from "./types-i3Vs02b8.js";
|
|
2
2
|
import { InteractionRequest } from "@tangle-network/agent-interface";
|
|
3
3
|
|
|
4
4
|
//#region src/agent-run-outcome.d.ts
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as materializeCliAuthBundle, n as assertCliAuthReferenceSupported, r as cliAuthReferenceSchema, t as CliAuthReference } from "../cli-auth-bundle-
|
|
2
|
-
import { _ as ReadTokenPayload, a as issueCollaborationToken, c as issueSessionScopedToken, d as AnyTokenPayload, f as BatchScopedTokenPayload, g as ProjectScopedTokenPayload, h as IssueCollaborationTokenOptions, i as issueBatchScopedToken, l as unsafeDecodeToken, m as CollaborationTokenPayload, n as getTokenTTL, o as issueProjectScopedToken, p as CollaborationAccess, r as isTokenExpiringSoon, s as issueReadToken, t as ProductTokenIssuer, u as verifyToken, v as SessionScopedTokenPayload, y as TokenScope } from "../index-
|
|
1
|
+
import { i as materializeCliAuthBundle, n as assertCliAuthReferenceSupported, r as cliAuthReferenceSchema, t as CliAuthReference } from "../cli-auth-bundle-ODe06Ts7.js";
|
|
2
|
+
import { _ as ReadTokenPayload, a as issueCollaborationToken, c as issueSessionScopedToken, d as AnyTokenPayload, f as BatchScopedTokenPayload, g as ProjectScopedTokenPayload, h as IssueCollaborationTokenOptions, i as issueBatchScopedToken, l as unsafeDecodeToken, m as CollaborationTokenPayload, n as getTokenTTL, o as issueProjectScopedToken, p as CollaborationAccess, r as isTokenExpiringSoon, s as issueReadToken, t as ProductTokenIssuer, u as verifyToken, v as SessionScopedTokenPayload, y as TokenScope } from "../index-BgmgfYZZ.js";
|
|
3
3
|
export { AnyTokenPayload, BatchScopedTokenPayload, CliAuthReference, CollaborationAccess, CollaborationTokenPayload, IssueCollaborationTokenOptions, ProductTokenIssuer, ProjectScopedTokenPayload, ReadTokenPayload, SessionScopedTokenPayload, TokenScope, assertCliAuthReferenceSupported, cliAuthReferenceSchema, getTokenTTL, isTokenExpiringSoon, issueBatchScopedToken, issueCollaborationToken, issueProjectScopedToken, issueReadToken, issueSessionScopedToken, materializeCliAuthBundle, unsafeDecodeToken, verifyToken };
|
package/dist/auth/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as materializeCliAuthBundle, n as assertCliAuthReferenceSupported, r as cliAuthReferenceSchema } from "../cli-auth-bundle-
|
|
1
|
+
import { i as materializeCliAuthBundle, n as assertCliAuthReferenceSupported, r as cliAuthReferenceSchema } from "../cli-auth-bundle-Dm8w5faq.js";
|
|
2
2
|
//#region src/auth/tokens.ts
|
|
3
3
|
const textEncoder = new TextEncoder();
|
|
4
4
|
const textDecoder = new TextDecoder();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as TerminalStreamHandlers } from "./terminal-stream-
|
|
1
|
+
import { r as TerminalStreamHandlers } from "./terminal-stream-CV1pMSKC.js";
|
|
2
2
|
import { AgentInteractiveSessionAttach, AgentInteractiveSessionControlClaimAcknowledgement, AgentInteractiveSessionStatus } from "@tangle-network/agent-interface";
|
|
3
3
|
import { AgentInteractiveSessionControlClaim as AgentInteractiveSessionControlClaim$1, AgentInteractiveSessionControlClaimRequest as AgentInteractiveSessionControlClaimRequest$1, AgentInteractiveSessionRef as AgentInteractiveSessionRef$1 } from "@tangle-network/agent-interface/environment-interactive-control";
|
|
4
4
|
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { _ as TimeoutError, c as NetworkError, d as QuotaError, m as ServerError, p as SandboxError, y as parseErrorResponse } from "./errors-Cq4hMysQ.js";
|
|
2
|
+
//#region ../../../packages/runtime-contracts/dist/file-limits.js
|
|
3
|
+
const MEBIBYTE$1 = 1024 * 1024;
|
|
4
|
+
10 * MEBIBYTE$1;
|
|
5
|
+
const FILE_DECODED_WRITE_MAX_BYTES = 5 * MEBIBYTE$1;
|
|
6
|
+
5 * MEBIBYTE$1;
|
|
7
|
+
10 * MEBIBYTE$1;
|
|
8
|
+
5 * MEBIBYTE$1;
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region ../../../packages/runtime-contracts/dist/request-limits.js
|
|
11
|
+
/**
|
|
12
|
+
* Raw WIRE/TRANSPORT caps: request-byte limits checked while the body
|
|
13
|
+
* streams in (bodyLimit middleware, Content-Length, encoded proxy bodies),
|
|
14
|
+
* before anything is parsed or decoded. Rejections against these carry
|
|
15
|
+
* code `PAYLOAD_TOO_LARGE` (`payload-too-large.ts`) — the remedy is to
|
|
16
|
+
* split the delivery. Decoded/parsed-content caps (code `FILE_TOO_LARGE`)
|
|
17
|
+
* live in `file-io.ts`.
|
|
18
|
+
*/
|
|
19
|
+
const MEBIBYTE = 1024 * 1024;
|
|
20
|
+
/**
|
|
21
|
+
* Gateway (CF Worker) proxy cap on any request body it forwards — both
|
|
22
|
+
* pass-through requests and route-constructed (`options.body`) proxy
|
|
23
|
+
* payloads. Workers buffer forwarded bodies (streaming upstream stalls),
|
|
24
|
+
* so this bounds Worker memory per request.
|
|
25
|
+
*/
|
|
26
|
+
const SANDBOX_PROXY_REQUEST_MAX_BYTES = MEBIBYTE;
|
|
27
|
+
32 * MEBIBYTE;
|
|
28
|
+
/**
|
|
29
|
+
* Max assembled size of one chunked-upload session — the ceiling of the
|
|
30
|
+
* sanctioned >1 MiB delivery path. Parts stage in sidecar memory until
|
|
31
|
+
* commit, so this bounds per-session memory, not the destination
|
|
32
|
+
* filesystem.
|
|
33
|
+
*/
|
|
34
|
+
const FILE_UPLOAD_SESSION_MAX_BYTES = 64 * MEBIBYTE;
|
|
35
|
+
128 * MEBIBYTE;
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region ../../../packages/runtime-contracts/dist/size-limit-errors.js
|
|
38
|
+
/** Canonical error codes for wire-size and decoded-content rejections. */
|
|
39
|
+
const PAYLOAD_TOO_LARGE_CODE = "PAYLOAD_TOO_LARGE";
|
|
40
|
+
const FILE_TOO_LARGE_CODE = "FILE_TOO_LARGE";
|
|
41
|
+
function isRecord(value) {
|
|
42
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
43
|
+
}
|
|
44
|
+
function isPositiveInteger(value) {
|
|
45
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
46
|
+
}
|
|
47
|
+
function isSizeLimitErrorBodyFor(value, code) {
|
|
48
|
+
if (!isRecord(value) || value.success !== false || !isRecord(value.error)) return false;
|
|
49
|
+
const error = value.error;
|
|
50
|
+
return error.code === code && typeof error.message === "string" && typeof error.surface === "string" && isPositiveInteger(error.limitBytes) && (error.actualBytes === void 0 || isPositiveInteger(error.actualBytes));
|
|
51
|
+
}
|
|
52
|
+
function isPayloadTooLargeErrorBody(value) {
|
|
53
|
+
return isSizeLimitErrorBodyFor(value, PAYLOAD_TOO_LARGE_CODE);
|
|
54
|
+
}
|
|
55
|
+
function isFileTooLargeErrorBody(value) {
|
|
56
|
+
return isSizeLimitErrorBodyFor(value, FILE_TOO_LARGE_CODE);
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/lib/chunked-upload.ts
|
|
60
|
+
/**
|
|
61
|
+
* Chunked upload — the sanctioned SDK path for delivering payloads larger
|
|
62
|
+
* than the sandbox API's single-request body caps. Splits the payload into
|
|
63
|
+
* server-sized parts against a `/fs/upload-session` session, PUTs each part
|
|
64
|
+
* with transient retry, then commits with a whole-payload SHA-256 so the
|
|
65
|
+
* runtime can verify nothing was dropped or reordered in transit.
|
|
66
|
+
*
|
|
67
|
+
* Browser/Worker-safe: no `node:` imports, no `Buffer`. Input normalizes to
|
|
68
|
+
* a `Uint8Array` and hashes via Web Crypto (`crypto.subtle`), available in
|
|
69
|
+
* browsers, Workers, and Node 18+ — the same environments this module must
|
|
70
|
+
* run in unmodified.
|
|
71
|
+
*/
|
|
72
|
+
const DEFAULT_MAX_RETRIES = 4;
|
|
73
|
+
const RETRY_BASE_MS = 250;
|
|
74
|
+
const RETRY_MAX_MS = 2e3;
|
|
75
|
+
/** Concurrent part PUTs — indexed parts + commit-time assembly make out-of-
|
|
76
|
+
* order completion safe; the cap keeps one session polite to the sidecar's
|
|
77
|
+
* staging budget. */
|
|
78
|
+
const DEFAULT_UPLOAD_CONCURRENCY = 4;
|
|
79
|
+
const MAX_UPLOAD_CONCURRENCY = 8;
|
|
80
|
+
const delay = (ms, signal) => new Promise((resolve, reject) => {
|
|
81
|
+
if (signal?.aborted) {
|
|
82
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const timer = setTimeout(() => {
|
|
86
|
+
signal?.removeEventListener("abort", onAbort);
|
|
87
|
+
resolve();
|
|
88
|
+
}, ms);
|
|
89
|
+
function onAbort() {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
92
|
+
}
|
|
93
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
94
|
+
});
|
|
95
|
+
/** Transient part-upload failures worth retrying: rate-limit/budget (429),
|
|
96
|
+
* 5xx, transport (network), and request timeouts — mirrors
|
|
97
|
+
* `isTransientWriteError` in `sandbox.ts`. A non-transient error (bad path,
|
|
98
|
+
* auth, checksum, containment) fails loud immediately. */
|
|
99
|
+
function isTransientUploadError(rejection) {
|
|
100
|
+
return rejection instanceof QuotaError || rejection instanceof ServerError || rejection instanceof NetworkError || rejection instanceof TimeoutError;
|
|
101
|
+
}
|
|
102
|
+
function isChecksumMismatch(rejection) {
|
|
103
|
+
return rejection instanceof SandboxError && rejection.code === "CHECKSUM_MISMATCH";
|
|
104
|
+
}
|
|
105
|
+
/** Cheap size probe used for the pre-flight cap check, read directly off
|
|
106
|
+
* the input shape (`Blob.size` / `ArrayBuffer.byteLength` / view
|
|
107
|
+
* `byteLength`) so an oversized `Blob` never has its bytes materialized
|
|
108
|
+
* just to be rejected. Strings have no cheap length in UTF-8, so they're
|
|
109
|
+
* encoded once here (and once more in {@link normalizeToBytes} — an
|
|
110
|
+
* acceptable cost given strings are never the multi-MB case this path
|
|
111
|
+
* exists for). */
|
|
112
|
+
function sizeOfInput(data) {
|
|
113
|
+
if (typeof data === "string") return new TextEncoder().encode(data).byteLength;
|
|
114
|
+
if (data instanceof ArrayBuffer) return data.byteLength;
|
|
115
|
+
if (ArrayBuffer.isView(data)) return data.byteLength;
|
|
116
|
+
return data.size;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Normalizes to a `Uint8Array` backed by a plain (never shared)
|
|
120
|
+
* `ArrayBuffer`. A caller-supplied view may be backed by a
|
|
121
|
+
* `SharedArrayBuffer`, which `crypto.subtle.digest` and `fetch`'s
|
|
122
|
+
* `BodyInit` both reject at the type level (and some engines reject at
|
|
123
|
+
* runtime) — copying here keeps every downstream call on one concrete,
|
|
124
|
+
* always-accepted buffer type.
|
|
125
|
+
*/
|
|
126
|
+
async function normalizeToBytes(data) {
|
|
127
|
+
if (typeof data === "string") return new Uint8Array(new TextEncoder().encode(data));
|
|
128
|
+
if (data instanceof ArrayBuffer) return new Uint8Array(data.slice(0));
|
|
129
|
+
if (ArrayBuffer.isView(data)) {
|
|
130
|
+
const copy = new Uint8Array(data.byteLength);
|
|
131
|
+
copy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
132
|
+
return copy;
|
|
133
|
+
}
|
|
134
|
+
return new Uint8Array(await data.arrayBuffer());
|
|
135
|
+
}
|
|
136
|
+
function webCryptoSubtle() {
|
|
137
|
+
const subtle = globalThis.crypto?.subtle;
|
|
138
|
+
if (!subtle) throw new Error("chunked upload requires Web Crypto (crypto.subtle) for SHA-256 hashing — available in browsers, Workers, and Node 18+");
|
|
139
|
+
return subtle;
|
|
140
|
+
}
|
|
141
|
+
/** Compress one part with the platform's native gzip — Web standard
|
|
142
|
+
* `CompressionStream` (browsers, Workers, Node 18+). Returns null when the
|
|
143
|
+
* runtime lacks the API: the caller degrades to an uncompressed part,
|
|
144
|
+
* which every server accepts (the encoding is optional by contract). */
|
|
145
|
+
async function gzipPart(bytes) {
|
|
146
|
+
const CompressionStreamCtor = globalThis.CompressionStream;
|
|
147
|
+
if (!CompressionStreamCtor) return null;
|
|
148
|
+
try {
|
|
149
|
+
const compressed = new Blob([bytes]).stream().pipeThrough(new CompressionStreamCtor("gzip"));
|
|
150
|
+
const buffer = await new Response(compressed).arrayBuffer();
|
|
151
|
+
return new Uint8Array(buffer);
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Codec preference among the encodings the runtime advertised: zstd (better
|
|
157
|
+
* ratio AND speed) when the caller supplied a codec for it, then gzip. A
|
|
158
|
+
* runtime that advertises nothing predates wire compression and stores a
|
|
159
|
+
* part's bytes as sent, so it gets raw parts. Probing happens with the
|
|
160
|
+
* chosen codec — the same codec compresses every part. */
|
|
161
|
+
function codecChain(accepted, codecs) {
|
|
162
|
+
const chain = [];
|
|
163
|
+
const negotiated = new Set(accepted ?? []);
|
|
164
|
+
if (codecs?.zstd && negotiated.has("zstd")) chain.push({
|
|
165
|
+
encoding: "zstd",
|
|
166
|
+
codec: codecs.zstd
|
|
167
|
+
});
|
|
168
|
+
if (negotiated.has("gzip")) chain.push({
|
|
169
|
+
encoding: "gzip",
|
|
170
|
+
codec: gzipPart
|
|
171
|
+
});
|
|
172
|
+
return chain;
|
|
173
|
+
}
|
|
174
|
+
/** Auto mode probes part 0 with the best available codec; if the ratio says
|
|
175
|
+
* incompressible (>= 95% of raw — model weights, JPEGs, packed archives),
|
|
176
|
+
* parts go raw and the CPU is not burned again. */
|
|
177
|
+
async function planCompression(mode, firstRaw, accepted, codecs) {
|
|
178
|
+
if (mode === false) return {
|
|
179
|
+
encoding: null,
|
|
180
|
+
codec: null
|
|
181
|
+
};
|
|
182
|
+
if (firstRaw.byteLength === 0) return {
|
|
183
|
+
encoding: null,
|
|
184
|
+
codec: null
|
|
185
|
+
};
|
|
186
|
+
for (const candidate of codecChain(accepted, codecs)) {
|
|
187
|
+
const firstWire = await candidate.codec(firstRaw);
|
|
188
|
+
if (firstWire === null) continue;
|
|
189
|
+
if (mode === true || firstWire.byteLength < firstRaw.byteLength * .95) return {
|
|
190
|
+
encoding: candidate.encoding,
|
|
191
|
+
codec: candidate.codec,
|
|
192
|
+
firstPartWire: firstWire
|
|
193
|
+
};
|
|
194
|
+
return {
|
|
195
|
+
encoding: null,
|
|
196
|
+
codec: null
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
encoding: null,
|
|
201
|
+
codec: null
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function firstPart(bytes, partSize) {
|
|
205
|
+
return bytes.subarray(0, Math.min(partSize, bytes.byteLength));
|
|
206
|
+
}
|
|
207
|
+
async function sha256Hex(bytes) {
|
|
208
|
+
const digest = await webCryptoSubtle().digest("SHA-256", bytes);
|
|
209
|
+
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Canonical size-cap bodies (413 `PAYLOAD_TOO_LARGE` / `FILE_TOO_LARGE`)
|
|
213
|
+
* carry `surface`/`limitBytes`/`actualBytes` that the generic error parser
|
|
214
|
+
* drops; fold them into the message before delegating to
|
|
215
|
+
* `parseErrorResponse` for the rest (status→class mapping, retryAfterMs,
|
|
216
|
+
* origin).
|
|
217
|
+
*/
|
|
218
|
+
async function parseUploadError(response) {
|
|
219
|
+
const bodyText = await response.text();
|
|
220
|
+
let parsedBody;
|
|
221
|
+
try {
|
|
222
|
+
parsedBody = JSON.parse(bodyText);
|
|
223
|
+
} catch {
|
|
224
|
+
parsedBody = void 0;
|
|
225
|
+
}
|
|
226
|
+
if (isPayloadTooLargeErrorBody(parsedBody) || isFileTooLargeErrorBody(parsedBody)) {
|
|
227
|
+
const { code, message, surface, limitBytes, actualBytes } = parsedBody.error;
|
|
228
|
+
const detail = typeof actualBytes === "number" ? `${message} (${surface}: ${actualBytes} of ${limitBytes} bytes)` : `${message} (${surface}: limit ${limitBytes} bytes)`;
|
|
229
|
+
return parseErrorResponse(response.status, JSON.stringify({
|
|
230
|
+
code,
|
|
231
|
+
message: detail
|
|
232
|
+
}), void 0, response.headers);
|
|
233
|
+
}
|
|
234
|
+
return parseErrorResponse(response.status, bodyText, void 0, response.headers);
|
|
235
|
+
}
|
|
236
|
+
async function initUploadSession(transport, remotePath, totalBytes, sha256, mode, signal) {
|
|
237
|
+
signal?.throwIfAborted();
|
|
238
|
+
const response = await transport.fetch("/fs/upload-session", {
|
|
239
|
+
method: "POST",
|
|
240
|
+
headers: { "Content-Type": "application/json" },
|
|
241
|
+
body: JSON.stringify({
|
|
242
|
+
path: remotePath,
|
|
243
|
+
mode,
|
|
244
|
+
totalBytes,
|
|
245
|
+
sha256
|
|
246
|
+
}),
|
|
247
|
+
signal
|
|
248
|
+
});
|
|
249
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
250
|
+
return (await response.json()).data;
|
|
251
|
+
}
|
|
252
|
+
async function putPart(transport, uploadId, index, options, wire) {
|
|
253
|
+
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
254
|
+
for (let attempt = 0;; attempt++) {
|
|
255
|
+
options.signal?.throwIfAborted();
|
|
256
|
+
try {
|
|
257
|
+
const response = await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}/parts/${index}`, {
|
|
258
|
+
method: "PUT",
|
|
259
|
+
headers: {
|
|
260
|
+
"Content-Type": "application/octet-stream",
|
|
261
|
+
...wire.encoding ? { "Content-Encoding": wire.encoding } : {}
|
|
262
|
+
},
|
|
263
|
+
body: wire.body,
|
|
264
|
+
signal: options.signal
|
|
265
|
+
});
|
|
266
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
267
|
+
return;
|
|
268
|
+
} catch (err) {
|
|
269
|
+
if (isTransientUploadError(err) && attempt < maxRetries) {
|
|
270
|
+
const retryAfterMs = err instanceof SandboxError ? err.retryAfterMs : void 0;
|
|
271
|
+
const backoff = Math.min(RETRY_BASE_MS * 2 ** attempt, RETRY_MAX_MS);
|
|
272
|
+
await delay(retryAfterMs ?? backoff, options.signal);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
throw err;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function partCount(totalBytes, partSize) {
|
|
280
|
+
return Math.ceil(totalBytes / partSize);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Upload every part with bounded concurrency. Parts are INDEXED and staged
|
|
284
|
+
* independently server-side; assembly and the whole-payload SHA-256 happen
|
|
285
|
+
* at commit — so out-of-order completion is safe by contract (the S3-
|
|
286
|
+
* multipart property). Concurrency is capped (default 4, max 8) to stay a
|
|
287
|
+
* polite citizen of the sidecar's per-session staging budget; `paceMs`
|
|
288
|
+
* still spaces DISPATCHES for callers that need to throttle.
|
|
289
|
+
*/
|
|
290
|
+
async function uploadAllParts(transport, uploadId, bytes, partSize, totalParts, options, plan, skip) {
|
|
291
|
+
const totalBytes = bytes.byteLength;
|
|
292
|
+
const paceMs = options.paceMs ?? 0;
|
|
293
|
+
const concurrency = Math.min(Math.max(1, options.concurrency ?? DEFAULT_UPLOAD_CONCURRENCY), MAX_UPLOAD_CONCURRENCY);
|
|
294
|
+
let uploadedBytes = 0;
|
|
295
|
+
let wireBytes = 0;
|
|
296
|
+
let nextIndex = 0;
|
|
297
|
+
const results = /* @__PURE__ */ new Map();
|
|
298
|
+
const dispatch = async (index) => {
|
|
299
|
+
const start = index * partSize;
|
|
300
|
+
const end = Math.min(start + partSize, totalBytes);
|
|
301
|
+
const raw = bytes.subarray(start, end);
|
|
302
|
+
let wireBody = raw;
|
|
303
|
+
let encoding = null;
|
|
304
|
+
if (plan.codec && plan.encoding) if (index === 0 && plan.firstPartWire) {
|
|
305
|
+
wireBody = plan.firstPartWire;
|
|
306
|
+
encoding = plan.encoding;
|
|
307
|
+
} else {
|
|
308
|
+
const compressed = await plan.codec(raw);
|
|
309
|
+
if (compressed) {
|
|
310
|
+
wireBody = compressed;
|
|
311
|
+
encoding = plan.encoding;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
wireBytes += wireBody.byteLength;
|
|
315
|
+
await putPart(transport, uploadId, index, options, {
|
|
316
|
+
body: wireBody,
|
|
317
|
+
encoding
|
|
318
|
+
});
|
|
319
|
+
uploadedBytes += end - start;
|
|
320
|
+
options.onProgress?.({
|
|
321
|
+
bytesUploaded: uploadedBytes,
|
|
322
|
+
totalBytes,
|
|
323
|
+
percentage: totalBytes === 0 ? 100 : Math.round(uploadedBytes / totalBytes * 100)
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
try {
|
|
327
|
+
while (nextIndex < totalParts || results.size > 0) {
|
|
328
|
+
options.signal?.throwIfAborted();
|
|
329
|
+
while (results.size < concurrency && nextIndex < totalParts) {
|
|
330
|
+
const index = nextIndex++;
|
|
331
|
+
if (skip?.has(index)) continue;
|
|
332
|
+
results.set(index, dispatch(index));
|
|
333
|
+
if (paceMs > 0) await delay(paceMs, options.signal);
|
|
334
|
+
}
|
|
335
|
+
const [headIndex, head] = results.entries().next().value;
|
|
336
|
+
results.delete(headIndex);
|
|
337
|
+
await head;
|
|
338
|
+
}
|
|
339
|
+
} catch (err) {
|
|
340
|
+
await Promise.allSettled(results.values());
|
|
341
|
+
throw err;
|
|
342
|
+
}
|
|
343
|
+
return wireBytes;
|
|
344
|
+
}
|
|
345
|
+
async function commitSession(transport, uploadId, totalParts, sha256, signal) {
|
|
346
|
+
signal?.throwIfAborted();
|
|
347
|
+
const response = await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}/commit`, {
|
|
348
|
+
method: "POST",
|
|
349
|
+
headers: { "Content-Type": "application/json" },
|
|
350
|
+
body: JSON.stringify({
|
|
351
|
+
totalParts,
|
|
352
|
+
sha256
|
|
353
|
+
}),
|
|
354
|
+
signal
|
|
355
|
+
});
|
|
356
|
+
if (!response.ok) throw await parseUploadError(response);
|
|
357
|
+
return (await response.json()).data;
|
|
358
|
+
}
|
|
359
|
+
/** Best-effort abort of an in-progress session — never masks the real
|
|
360
|
+
* failure that triggered it, and never itself throws. An orphaned session
|
|
361
|
+
* also self-expires server-side (`expiresAt`), so a failed DELETE here is
|
|
362
|
+
* not a leak, just deferred cleanup. */
|
|
363
|
+
async function abortSession(transport, uploadId) {
|
|
364
|
+
try {
|
|
365
|
+
await transport.fetch(`/fs/upload-session/${encodeURIComponent(uploadId)}`, { method: "DELETE" });
|
|
366
|
+
} catch {}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Upload arbitrary binary or text data to the sandbox via the chunked
|
|
370
|
+
* upload-session protocol, verifying integrity with a whole-payload
|
|
371
|
+
* SHA-256 at commit. Browser/Worker-safe and works identically over the
|
|
372
|
+
* gateway proxy or a direct sidecar connection — see
|
|
373
|
+
* {@link FileSystem.uploadData}.
|
|
374
|
+
*
|
|
375
|
+
* @param transport - Fetch-shaped adapter scoped to the sandbox runtime
|
|
376
|
+
* (paths are relative to it, e.g. `/fs/upload-session`).
|
|
377
|
+
* @param remotePath - Destination path in the sandbox.
|
|
378
|
+
* @param data - Payload to upload. Strings encode as UTF-8.
|
|
379
|
+
* @param options - See {@link ChunkedUploadOptions}.
|
|
380
|
+
* @throws {SandboxError} `PAYLOAD_TOO_LARGE` immediately (zero requests) if
|
|
381
|
+
* the payload exceeds {@link FILE_UPLOAD_SESSION_MAX_BYTES}; otherwise the
|
|
382
|
+
* typed error from whichever step (init/part/commit) failed after retries
|
|
383
|
+
* are exhausted.
|
|
384
|
+
*/
|
|
385
|
+
async function uploadChunked(transport, remotePath, data, options = {}) {
|
|
386
|
+
const estimatedSize = sizeOfInput(data);
|
|
387
|
+
if (estimatedSize > 67108864) 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);
|
|
388
|
+
options.signal?.throwIfAborted();
|
|
389
|
+
const bytes = await normalizeToBytes(data);
|
|
390
|
+
options.signal?.throwIfAborted();
|
|
391
|
+
const sha256 = await sha256Hex(bytes);
|
|
392
|
+
const init = await initUploadSession(transport, remotePath, bytes.byteLength, sha256, options.mode, options.signal);
|
|
393
|
+
const totalParts = partCount(bytes.byteLength, init.partSize);
|
|
394
|
+
const plan = await planCompression(options.compression, firstPart(bytes, init.partSize), init.acceptedEncodings, options.codecs);
|
|
395
|
+
let wireBytes = 0;
|
|
396
|
+
options.onSession?.({
|
|
397
|
+
uploadId: init.uploadId,
|
|
398
|
+
partSize: init.partSize,
|
|
399
|
+
totalParts,
|
|
400
|
+
expiresAt: init.expiresAt
|
|
401
|
+
});
|
|
402
|
+
try {
|
|
403
|
+
wireBytes += await uploadAllParts(transport, init.uploadId, bytes, init.partSize, totalParts, options, plan);
|
|
404
|
+
try {
|
|
405
|
+
return {
|
|
406
|
+
...await commitSession(transport, init.uploadId, totalParts, sha256, options.signal),
|
|
407
|
+
wireBytes
|
|
408
|
+
};
|
|
409
|
+
} catch (err) {
|
|
410
|
+
if (!isChecksumMismatch(err)) throw err;
|
|
411
|
+
wireBytes += await uploadAllParts(transport, init.uploadId, bytes, init.partSize, totalParts, options, plan);
|
|
412
|
+
return {
|
|
413
|
+
...await commitSession(transport, init.uploadId, totalParts, sha256, options.signal),
|
|
414
|
+
wireBytes
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
} catch (err) {
|
|
418
|
+
if (options.keepSessionOnFailure) throw new ChunkedUploadInterruptedError(init.uploadId, err);
|
|
419
|
+
await abortSession(transport, init.uploadId);
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/** An upload that failed mid-flight while `keepSessionOnFailure` left the
|
|
424
|
+
* session (and its staged parts) alive. Carry `uploadId` straight into
|
|
425
|
+
* `resumeChunkedUpload` with the SAME payload to finish it. */
|
|
426
|
+
var ChunkedUploadInterruptedError = class extends Error {
|
|
427
|
+
constructor(uploadId, cause) {
|
|
428
|
+
super(`Chunked upload interrupted; session ${uploadId} kept its staged parts — resume with resumeChunkedUpload and the same payload`);
|
|
429
|
+
this.uploadId = uploadId;
|
|
430
|
+
this.cause = cause;
|
|
431
|
+
this.name = "ChunkedUploadInterruptedError";
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
//#endregion
|
|
435
|
+
export { planCompression as a, FILE_UPLOAD_SESSION_MAX_BYTES as c, partCount as i, SANDBOX_PROXY_REQUEST_MAX_BYTES as l, commitSession as n, putPart as o, initUploadSession as r, uploadChunked as s, abortSession as t, FILE_DECODED_WRITE_MAX_BYTES as u };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { a as planCompression, c as FILE_UPLOAD_SESSION_MAX_BYTES, i as partCount, n as commitSession, o as putPart, r as initUploadSession, t as abortSession } from "./chunked-upload-CfefWUE5.js";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { open } from "node:fs/promises";
|
|
4
|
+
//#region src/lib/chunked-upload-file.ts
|
|
5
|
+
/**
|
|
6
|
+
* Chunked upload from a LOCAL FILE (Node runtimes) — streams the payload off
|
|
7
|
+
* disk: per-part reads at offsets into one reusable buffer, an incremental
|
|
8
|
+
* node:crypto SHA-256, and the exact same wire protocol as
|
|
9
|
+
* `lib/chunked-upload.ts` (whose session primitives this composes). The
|
|
10
|
+
* whole payload never sits in RAM — the client memory ceiling is one part,
|
|
11
|
+
* not the file.
|
|
12
|
+
*
|
|
13
|
+
* Browser/Worker callers use `uploadChunked` (Blob/ArrayBuffer inputs);
|
|
14
|
+
* this module is the Node-side twin for the `fs.upload(localPath, …)` path.
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_FILE_CONCURRENCY = 4;
|
|
17
|
+
const MAX_FILE_CONCURRENCY = 8;
|
|
18
|
+
async function uploadChunkedFromFile(transport, remotePath, localPath, options = {}) {
|
|
19
|
+
const handle = await open(localPath, "r");
|
|
20
|
+
try {
|
|
21
|
+
const { size } = await handle.stat();
|
|
22
|
+
if (size > 67108864) throw new Error(`File ${localPath} is ${size} bytes, over the ${FILE_UPLOAD_SESSION_MAX_BYTES} byte chunked-upload session cap`);
|
|
23
|
+
const hash = createHash("sha256");
|
|
24
|
+
const hashReader = handle.createReadStream({ autoClose: false });
|
|
25
|
+
for await (const chunk of hashReader) hash.update(chunk);
|
|
26
|
+
const sha256 = hash.digest("hex");
|
|
27
|
+
const init = await initUploadSession(transport, remotePath, size, sha256, options.mode, options.signal);
|
|
28
|
+
const totalParts = partCount(size, init.partSize);
|
|
29
|
+
options.onSession?.({
|
|
30
|
+
uploadId: init.uploadId,
|
|
31
|
+
partSize: init.partSize,
|
|
32
|
+
totalParts,
|
|
33
|
+
expiresAt: init.expiresAt
|
|
34
|
+
});
|
|
35
|
+
let wireBytes = 0;
|
|
36
|
+
const readPart = async (index) => {
|
|
37
|
+
const start = index * init.partSize;
|
|
38
|
+
const length = Math.min(init.partSize, size - start);
|
|
39
|
+
const buffer = Buffer.alloc(length);
|
|
40
|
+
const { bytesRead } = await handle.read(buffer, 0, length, start);
|
|
41
|
+
if (bytesRead !== length) throw new Error(`Short read for part ${index}: ${bytesRead} of ${length} bytes (file changed mid-upload?)`);
|
|
42
|
+
return buffer;
|
|
43
|
+
};
|
|
44
|
+
const part0 = await readPart(0);
|
|
45
|
+
const plan = await planCompression(options.compression, new Uint8Array(part0), init.acceptedEncodings, options.codecs);
|
|
46
|
+
const part0Wire = plan.firstPartWire ?? part0;
|
|
47
|
+
const encoding = plan.firstPartWire ? plan.encoding : null;
|
|
48
|
+
let uploadedBytes = 0;
|
|
49
|
+
const concurrency = Math.min(Math.max(1, options.concurrency ?? DEFAULT_FILE_CONCURRENCY), MAX_FILE_CONCURRENCY);
|
|
50
|
+
const report = (bytes) => {
|
|
51
|
+
uploadedBytes += bytes;
|
|
52
|
+
options.onProgress?.({
|
|
53
|
+
bytesUploaded: uploadedBytes,
|
|
54
|
+
totalBytes: size,
|
|
55
|
+
percentage: size === 0 ? 100 : Math.round(uploadedBytes / size * 100)
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
if (totalParts > 0) {
|
|
60
|
+
wireBytes += part0Wire.length;
|
|
61
|
+
await putPart(transport, init.uploadId, 0, options, {
|
|
62
|
+
body: new Uint8Array(part0Wire),
|
|
63
|
+
encoding
|
|
64
|
+
});
|
|
65
|
+
report(part0.length);
|
|
66
|
+
}
|
|
67
|
+
let nextIndex = 1;
|
|
68
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
69
|
+
while (nextIndex < totalParts || inFlight.size > 0) {
|
|
70
|
+
options.signal?.throwIfAborted();
|
|
71
|
+
while (inFlight.size < concurrency && nextIndex < totalParts) {
|
|
72
|
+
const index = nextIndex++;
|
|
73
|
+
const task = (async () => {
|
|
74
|
+
const raw = await readPart(index);
|
|
75
|
+
let body = new Uint8Array(raw);
|
|
76
|
+
let partEncoding = null;
|
|
77
|
+
if (plan.codec && plan.encoding) {
|
|
78
|
+
const compressed = await plan.codec(body);
|
|
79
|
+
if (compressed) {
|
|
80
|
+
body = compressed;
|
|
81
|
+
partEncoding = plan.encoding;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
wireBytes += body.byteLength;
|
|
85
|
+
await putPart(transport, init.uploadId, index, options, {
|
|
86
|
+
body,
|
|
87
|
+
encoding: partEncoding
|
|
88
|
+
});
|
|
89
|
+
report(raw.length);
|
|
90
|
+
})();
|
|
91
|
+
inFlight.add(task);
|
|
92
|
+
task.finally(() => inFlight.delete(task)).catch(() => void 0);
|
|
93
|
+
}
|
|
94
|
+
await inFlight.values().next().value;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
...await commitSession(transport, init.uploadId, totalParts, sha256, options.signal),
|
|
98
|
+
wireBytes
|
|
99
|
+
};
|
|
100
|
+
} catch (err) {
|
|
101
|
+
await abortSession(transport, init.uploadId);
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
} finally {
|
|
105
|
+
await handle.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { uploadChunkedFromFile };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { l as TraceExportResult, n as HttpClient, r as SandboxInstance, u as TraceExportSink } from "./sandbox-
|
|
2
|
-
import { $r as SandboxFleetToken, Ar as SandboxFleetAgent, B as CreateSandboxOptions, Bt as FleetDispatchStreamOptions, Ca as TokenRefreshHandler, En as ListSandboxOptions, F as CreateIntelligenceReportOptions, Ft as FleetAgentResult, G as DeleteMatchingSandboxesFilter, Gr as SandboxFleetManifest, Gt as FleetMachineId, Ht as FleetDriveTurnRequest, I as CreateRequestOptions, Ir as SandboxFleetDispatchResponse, Jn as PromptResult, Jr as SandboxFleetParent, Jt as FleetRunEvent, K as DeleteMatchingSandboxesOptions, Kn as PromptInputPart, Kt as FleetPromptDispatchOptions, L as CreateSandboxFleetOptions, Lr as SandboxFleetDriverCapability, Lt as FleetDispatchCancelResult, M as ConversationTurnOptions, Mr as SandboxFleetArtifact, N as ConversationTurnResult, Nr as SandboxFleetArtifactSpec, Nt as FleetAgentId, Or as SandboxEnvironment, Pr as SandboxFleetCostEstimate, Qr as SandboxFleetSpend, R as CreateSandboxFleetTokenOptions, Ri as SecretsManager, Rt as FleetDispatchResultBuffer, Si as SandboxShapesInfo, Tn as ListSandboxFleetOptions, Ur as SandboxFleetMachineRecord, Ut as FleetExecDispatchOptions, Vt as FleetDriveTurnOutcome, Wr as SandboxFleetMachineSpec, Wt as FleetExecDispatchResult, Xr as SandboxFleetPolicy, Yt as FleetRunOptions, _i as SandboxRunGeneration, _n as IntelligenceReport, ar as ReapExpiredSandboxFleetsResult, b as BatchRunRequest, br as SandboxConfig, ca as SshKeysManager, ci as SandboxFleetWorkspaceSnapshotResult, d as BackendConfig, ei as SandboxFleetTraceBundle, er as PublicTemplateInfo, fa as SubscriptionInfo, ii as SandboxFleetUsage, ir as ReapExpiredSandboxFleetsOptions, ka as UsageInfo, l as AttachSandboxFleetMachineOptions, li as SandboxIdentity, nr as PublishPublicTemplateOptions, oi as SandboxFleetWorkspaceReconcileResult, or as ReconcileSandboxFleetsOptions, q as DeleteMatchingSandboxesResult, qn as PromptOptions, qr as SandboxFleetOperationsSummary, qt as FleetPromptDispatchResult, ri as SandboxFleetTraceOptions, rr as PublishPublicTemplateVersionOptions, si as SandboxFleetWorkspaceRestoreResult, sr as ReconcileSandboxFleetsResult,
|
|
3
|
-
import { l as ScopedToken, s as MintInteractiveSessionTokenOptions } from "./terminal-stream-
|
|
4
|
-
import { I as LinesClient } from "./lines-
|
|
5
|
-
import { f as SandboxError } from "./errors-
|
|
1
|
+
import { l as TraceExportResult, n as HttpClient, r as SandboxInstance, u as TraceExportSink } from "./sandbox-WpE5rzUa.js";
|
|
2
|
+
import { $r as SandboxFleetToken, Ar as SandboxFleetAgent, B as CreateSandboxOptions, Bt as FleetDispatchStreamOptions, Ca as TokenRefreshHandler, En as ListSandboxOptions, F as CreateIntelligenceReportOptions, Ft as FleetAgentResult, G as DeleteMatchingSandboxesFilter, Gr as SandboxFleetManifest, Gt as FleetMachineId, Ht as FleetDriveTurnRequest, I as CreateRequestOptions, Ir as SandboxFleetDispatchResponse, Jn as PromptResult, Jr as SandboxFleetParent, Jt as FleetRunEvent, K as DeleteMatchingSandboxesOptions, Kn as PromptInputPart, Kt as FleetPromptDispatchOptions, L as CreateSandboxFleetOptions, Lr as SandboxFleetDriverCapability, Lt as FleetDispatchCancelResult, M as ConversationTurnOptions, Mr as SandboxFleetArtifact, N as ConversationTurnResult, Nr as SandboxFleetArtifactSpec, Nt as FleetAgentId, Or as SandboxEnvironment, Pr as SandboxFleetCostEstimate, Qr as SandboxFleetSpend, R as CreateSandboxFleetTokenOptions, Ri as SecretsManager, Rt as FleetDispatchResultBuffer, Si as SandboxShapesInfo, Tn as ListSandboxFleetOptions, Ur as SandboxFleetMachineRecord, Ut as FleetExecDispatchOptions, Vt as FleetDriveTurnOutcome, Wr as SandboxFleetMachineSpec, Wt as FleetExecDispatchResult, Xr as SandboxFleetPolicy, Yt as FleetRunOptions, _i as SandboxRunGeneration, _n as IntelligenceReport, ar as ReapExpiredSandboxFleetsResult, b as BatchRunRequest, br as SandboxConfig, ca as SshKeysManager, ci as SandboxFleetWorkspaceSnapshotResult, d as BackendConfig, ei as SandboxFleetTraceBundle, er as PublicTemplateInfo, fa as SubscriptionInfo, ii as SandboxFleetUsage, ir as ReapExpiredSandboxFleetsOptions, ka as UsageInfo, l as AttachSandboxFleetMachineOptions, li as SandboxIdentity, nr as PublishPublicTemplateOptions, oi as SandboxFleetWorkspaceReconcileResult, or as ReconcileSandboxFleetsOptions, q as DeleteMatchingSandboxesResult, qn as PromptOptions, qr as SandboxFleetOperationsSummary, qt as FleetPromptDispatchResult, ri as SandboxFleetTraceOptions, ro as BatchEvent, rr as PublishPublicTemplateVersionOptions, si as SandboxFleetWorkspaceRestoreResult, sr as ReconcileSandboxFleetsResult, tr as PublicTemplateVersionInfo, ui as SandboxInfo, v as BatchResult, vn as IntelligenceReportBudget, vt as ExecOptions, xn as IntelligenceReportWindow, y as BatchRunOptions, yn as IntelligenceReportCompareTo, yt as ExecResult, z as CreateSandboxFleetWithCoordinatorOptions, zr as SandboxFleetInfo, zt as FleetDispatchResultBufferOptions } from "./types-i3Vs02b8.js";
|
|
3
|
+
import { l as ScopedToken, s as MintInteractiveSessionTokenOptions } from "./terminal-stream-CV1pMSKC.js";
|
|
4
|
+
import { I as LinesClient } from "./lines-BOWMNDp5.js";
|
|
5
|
+
import { f as SandboxError } from "./errors-CRssX9qs.js";
|
|
6
6
|
import { AgentInteractiveSessionRef, AgentProfile } from "@tangle-network/agent-interface";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|