@sapiom/sandbox 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @sapiom/sandbox
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2781e03: Add multipart file upload support. New `uploadFile(path, content, opts?)` handles the full initiate → parallel part uploads → complete lifecycle with per-part retries (408/425/429/5xx + network errors, honors `Retry-After`) and auto-abort on failure. Accepts `Blob | Uint8Array | string`. Low-level `initiateMultipartUpload` / `uploadPart` / `completeMultipartUpload` / `abortMultipartUpload` / `listMultipartParts` primitives are exposed for resumable or custom-retry use cases, and a typed `SandboxHttpError` carries `status` + `retryAfterMs` for programmatic handling.
8
+
9
+ ## 0.7.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 0f8d6cd: support keepAlive and processTimeout opts
14
+
3
15
  ## 0.6.0
4
16
 
5
17
  ### Minor Changes
package/README.md CHANGED
@@ -75,6 +75,80 @@ Writes a file relative to the sandbox's workspace root.
75
75
  await sandbox.writeFile("src/index.ts", 'console.log("hi")');
76
76
  ```
77
77
 
78
+ ### `sandbox.uploadFile(path, content, opts?)`
79
+
80
+ Uploads a file using multipart upload. Handles the full `initiate → upload parts → complete` lifecycle, with parallel part uploads and automatic abort on any failure. Prefer this over `writeFile` for binary content or files over a few MB.
81
+
82
+ ```typescript
83
+ import { openAsBlob } from "node:fs";
84
+
85
+ // From a buffer / Uint8Array
86
+ await sandbox.uploadFile("data/snapshot.bin", new Uint8Array(bytes));
87
+
88
+ // From a file on disk without slurping it into memory (Node 20+)
89
+ const blob = await openAsBlob("./huge.parquet");
90
+ await sandbox.uploadFile("datasets/huge.parquet", blob, {
91
+ partSize: 5 * 1024 * 1024,
92
+ concurrency: 4,
93
+ onPartUploaded: (part, progress) => {
94
+ const pct = ((progress.bytesUploaded / progress.totalBytes) * 100).toFixed(1);
95
+ console.log(`part ${part.partNumber} ok — ${pct}%`);
96
+ },
97
+ });
98
+
99
+ // Cancel a running upload — the server-side multipart session is auto-aborted
100
+ const ctrl = new AbortController();
101
+ setTimeout(() => ctrl.abort(), 10_000);
102
+ await sandbox.uploadFile("big.bin", blob, { signal: ctrl.signal });
103
+ ```
104
+
105
+ **Options:**
106
+
107
+ | Option | Type | Default | Description |
108
+ |-------------------|-------------------------|-----------------|-----------------------------------------------------------------------------|
109
+ | `partSize` | `number` | `5 * 1024 * 1024` | Part size in bytes. The Sapiom ingress rejects uploads over ~8 MiB, so keep this ≤ 7 MiB. |
110
+ | `concurrency` | `number` | `4` | Number of parallel part uploads. Blaxel recommends 3–5. |
111
+ | `permissions` | `string` | `"0644"` | Unix file permissions. |
112
+ | `maxRetries` | `number` | `3` | Retries per failed part on 408/425/429/5xx and network errors. `0` disables. |
113
+ | `retryBaseDelayMs` | `number` | `50` | Initial backoff in ms. Doubles per attempt with jitter; honors `Retry-After`. |
114
+ | `signal` | `AbortSignal` | — | Cancel the upload. Triggers an auto-abort of the server-side session. |
115
+ | `onPartUploaded` | `(part, progress) => void` | — | Fired after each part finishes (completion order — not `partNumber` order). |
116
+
117
+ The server accepts at most **10,000 parts per upload**. If `content.size / partSize > 10_000`, `uploadFile` throws before making any request and suggests a larger `partSize`.
118
+
119
+ ### Low-level multipart API
120
+
121
+ For resumable uploads or custom retry logic, drive the multipart lifecycle directly:
122
+
123
+ ```typescript
124
+ const { uploadId } = await sandbox.initiateMultipartUpload("large.bin");
125
+
126
+ try {
127
+ // ...upload parts as bytes become available
128
+ const part1 = await sandbox.uploadPart(uploadId, 1, chunk1);
129
+ const part2 = await sandbox.uploadPart(uploadId, 2, chunk2);
130
+
131
+ // Inspect server-side state (useful after a crash/reconnect)
132
+ const uploaded = await sandbox.listMultipartParts(uploadId);
133
+
134
+ await sandbox.completeMultipartUpload(uploadId, [
135
+ { partNumber: part1.partNumber, etag: part1.etag },
136
+ { partNumber: part2.partNumber, etag: part2.etag },
137
+ ]);
138
+ } catch (err) {
139
+ await sandbox.abortMultipartUpload(uploadId);
140
+ throw err;
141
+ }
142
+ ```
143
+
144
+ | Method | Description |
145
+ |------------------------------------------------------|---------------------------------------------|
146
+ | `initiateMultipartUpload(path, opts?)` | Start a session. Returns `{ uploadId, path }`. |
147
+ | `uploadPart(uploadId, partNumber, bytes, opts?)` | Upload one part (1-indexed, 1–10000). |
148
+ | `listMultipartParts(uploadId, opts?)` | List parts already uploaded. |
149
+ | `completeMultipartUpload(uploadId, parts, opts?)` | Commit the upload. |
150
+ | `abortMultipartUpload(uploadId, opts?)` | Discard the session and clean up parts. |
151
+
78
152
  ### `sandbox.readFile(path)`
79
153
 
80
154
  Reads a file relative to the sandbox's workspace root and returns its content as a string.
@@ -1,3 +1,4 @@
1
1
  export { SapiomSandbox } from "./sandbox.js";
2
- export type { SandboxCreateOptions, SandboxCreateResponse, SandboxTier, PortSpec, ExecOptions, ExecStreamOptions, ExecResult, StreamingExecResult, OutputLine, ProcessCreateResponse, ProcessStatusResponse, } from "./types.js";
2
+ export { SandboxHttpError } from "./multipart.js";
3
+ export type { SandboxCreateOptions, SandboxCreateResponse, SandboxTier, PortSpec, ExecOptions, ExecStreamOptions, ExecResult, StreamingExecResult, OutputLine, ProcessCreateResponse, ProcessStatusResponse, MultipartInitiateResponse, MultipartUploadedPart, MultipartPartInfo, UploadFileOptions, UploadProgress, } from "./types.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SapiomSandbox = void 0;
3
+ exports.SandboxHttpError = exports.SapiomSandbox = void 0;
4
4
  var sandbox_js_1 = require("./sandbox.js");
5
5
  Object.defineProperty(exports, "SapiomSandbox", { enumerable: true, get: function () { return sandbox_js_1.SapiomSandbox; } });
6
+ var multipart_js_1 = require("./multipart.js");
7
+ Object.defineProperty(exports, "SandboxHttpError", { enumerable: true, get: function () { return multipart_js_1.SandboxHttpError; } });
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAApC,2GAAA,aAAa,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,2CAA6C;AAApC,2GAAA,aAAa,OAAA;AACtB,+CAAkD;AAAzC,gHAAA,gBAAgB,OAAA"}
@@ -0,0 +1,75 @@
1
+ /** Max parts allowed per multipart upload (Blaxel constraint). */
2
+ export declare const MAX_PARTS = 10000;
3
+ /** Default number of retries for a single failed part upload. */
4
+ export declare const DEFAULT_MAX_RETRIES = 3;
5
+ /** Default initial retry backoff in milliseconds. */
6
+ export declare const DEFAULT_RETRY_BASE_DELAY_MS = 50;
7
+ /**
8
+ * Error thrown by multipart HTTP methods when the server returns a non-2xx.
9
+ * Exposes `status` + `retryAfterMs` (parsed from `Retry-After`) so callers
10
+ * and the retry loop can make informed decisions.
11
+ */
12
+ export declare class SandboxHttpError extends Error {
13
+ readonly status: number;
14
+ readonly retryAfterMs?: number;
15
+ constructor(message: string, status: number, retryAfterMs?: number);
16
+ }
17
+ /**
18
+ * Parse a `Retry-After` header value. Supports both forms:
19
+ * - delta-seconds integer (e.g. `"30"`)
20
+ * - HTTP-date (e.g. `"Wed, 21 Oct 2015 07:28:00 GMT"`)
21
+ */
22
+ export declare function parseRetryAfter(header: string | null): number | undefined;
23
+ /**
24
+ * Wrap a `fetch` response: if non-2xx, throw a `SandboxHttpError` carrying
25
+ * the status + Retry-After, otherwise return the response for the caller to
26
+ * parse.
27
+ */
28
+ export declare function ensureOk(response: Response, errorPrefix: string): Promise<Response>;
29
+ export interface RetryOptions {
30
+ /** Max number of retry attempts after the initial try. @default 3 */
31
+ maxRetries?: number;
32
+ /** Initial backoff in ms. Doubles each retry with up to `base` ms jitter. @default 50 */
33
+ retryBaseDelayMs?: number;
34
+ /** AbortSignal to cancel the retry loop. */
35
+ signal?: AbortSignal;
36
+ }
37
+ /**
38
+ * Retry `fn` up to `maxRetries` times on retryable errors with jittered
39
+ * exponential backoff. Honors `Retry-After` when the server provides one.
40
+ * Respects `signal` for prompt cancellation during the backoff wait.
41
+ */
42
+ export declare function withRetry<T>(fn: (attempt: number) => Promise<T>, opts?: RetryOptions): Promise<T>;
43
+ /**
44
+ * Default part size: 5 MiB. Bottom of Blaxel's recommended 5–10 MB range
45
+ * and well clear of the Sapiom ingress 8 MiB body-size ceiling (with
46
+ * room left for multipart form-data overhead).
47
+ */
48
+ export declare const DEFAULT_PART_SIZE: number;
49
+ /** Default number of parallel part uploads. */
50
+ export declare const DEFAULT_CONCURRENCY = 4;
51
+ /** Default file permissions (Blaxel default). */
52
+ export declare const DEFAULT_PERMISSIONS = "0644";
53
+ /**
54
+ * Normalize any supported content type into a `Blob`.
55
+ * `Blob.slice()` gives us random-access + lazy reads, so large inputs don't
56
+ * have to sit materialized in memory.
57
+ */
58
+ export declare function toBlob(content: Blob | Uint8Array | string): Blob;
59
+ export interface PartPlan {
60
+ partNumber: number;
61
+ start: number;
62
+ end: number;
63
+ }
64
+ /**
65
+ * Split a byte range into part plans.
66
+ * Always emits at least one part (even for zero-byte inputs) so the caller
67
+ * still goes through the initiate/upload/complete handshake.
68
+ */
69
+ export declare function planParts(totalBytes: number, partSize: number): PartPlan[];
70
+ /**
71
+ * Run `worker` over `items` with at most `concurrency` promises in flight.
72
+ * Rejects on the first worker failure (and stops scheduling further items).
73
+ */
74
+ export declare function runWithConcurrency<T, R>(items: readonly T[], concurrency: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
75
+ //# sourceMappingURL=multipart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/multipart.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,eAAO,MAAM,SAAS,QAAS,CAAC;AAEhC,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,qDAAqD;AACrD,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAK9C;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;CAMnE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAOzE;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,QAAQ,CAAC,CASnB;AAED,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAcD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAoBD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AAEjD,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,iDAAiD;AACjD,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,IAAI,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CAMhE;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAsB1E;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,EAAE,CAAC,CAqCd"}
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_PERMISSIONS = exports.DEFAULT_CONCURRENCY = exports.DEFAULT_PART_SIZE = exports.SandboxHttpError = exports.DEFAULT_RETRY_BASE_DELAY_MS = exports.DEFAULT_MAX_RETRIES = exports.MAX_PARTS = void 0;
4
+ exports.parseRetryAfter = parseRetryAfter;
5
+ exports.ensureOk = ensureOk;
6
+ exports.withRetry = withRetry;
7
+ exports.toBlob = toBlob;
8
+ exports.planParts = planParts;
9
+ exports.runWithConcurrency = runWithConcurrency;
10
+ /** Max parts allowed per multipart upload (Blaxel constraint). */
11
+ exports.MAX_PARTS = 10000;
12
+ /** Default number of retries for a single failed part upload. */
13
+ exports.DEFAULT_MAX_RETRIES = 3;
14
+ /** Default initial retry backoff in milliseconds. */
15
+ exports.DEFAULT_RETRY_BASE_DELAY_MS = 50;
16
+ /** HTTP status codes worth retrying. 4xx are user errors unless explicitly transient. */
17
+ const RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]);
18
+ /**
19
+ * Error thrown by multipart HTTP methods when the server returns a non-2xx.
20
+ * Exposes `status` + `retryAfterMs` (parsed from `Retry-After`) so callers
21
+ * and the retry loop can make informed decisions.
22
+ */
23
+ class SandboxHttpError extends Error {
24
+ constructor(message, status, retryAfterMs) {
25
+ super(message);
26
+ this.name = "SandboxHttpError";
27
+ this.status = status;
28
+ if (retryAfterMs !== undefined)
29
+ this.retryAfterMs = retryAfterMs;
30
+ }
31
+ }
32
+ exports.SandboxHttpError = SandboxHttpError;
33
+ /**
34
+ * Parse a `Retry-After` header value. Supports both forms:
35
+ * - delta-seconds integer (e.g. `"30"`)
36
+ * - HTTP-date (e.g. `"Wed, 21 Oct 2015 07:28:00 GMT"`)
37
+ */
38
+ function parseRetryAfter(header) {
39
+ if (!header)
40
+ return undefined;
41
+ const seconds = Number(header);
42
+ if (Number.isFinite(seconds) && seconds >= 0)
43
+ return seconds * 1000;
44
+ const date = Date.parse(header);
45
+ if (!Number.isNaN(date))
46
+ return Math.max(0, date - Date.now());
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Wrap a `fetch` response: if non-2xx, throw a `SandboxHttpError` carrying
51
+ * the status + Retry-After, otherwise return the response for the caller to
52
+ * parse.
53
+ */
54
+ async function ensureOk(response, errorPrefix) {
55
+ if (response.ok)
56
+ return response;
57
+ const text = await response.text().catch(() => "");
58
+ const retryAfterMs = parseRetryAfter(response.headers.get("Retry-After"));
59
+ throw new SandboxHttpError(`${errorPrefix}: ${response.status} ${text}`, response.status, retryAfterMs);
60
+ }
61
+ /** Whether this error is worth retrying. */
62
+ function isRetryable(err) {
63
+ if (err instanceof SandboxHttpError)
64
+ return RETRYABLE_STATUS.has(err.status);
65
+ // Network-level failures (fetch rejected): typically TypeError "fetch failed"
66
+ // or AbortError. Retry non-abort errors.
67
+ if (err instanceof Error) {
68
+ if (err.name === "AbortError")
69
+ return false;
70
+ return true;
71
+ }
72
+ return false;
73
+ }
74
+ /**
75
+ * Retry `fn` up to `maxRetries` times on retryable errors with jittered
76
+ * exponential backoff. Honors `Retry-After` when the server provides one.
77
+ * Respects `signal` for prompt cancellation during the backoff wait.
78
+ */
79
+ async function withRetry(fn, opts) {
80
+ const maxRetries = opts?.maxRetries ?? exports.DEFAULT_MAX_RETRIES;
81
+ const base = opts?.retryBaseDelayMs ?? exports.DEFAULT_RETRY_BASE_DELAY_MS;
82
+ const signal = opts?.signal;
83
+ for (let attempt = 0;; attempt++) {
84
+ try {
85
+ return await fn(attempt);
86
+ }
87
+ catch (err) {
88
+ if (attempt >= maxRetries || !isRetryable(err) || signal?.aborted) {
89
+ throw err;
90
+ }
91
+ const backoff = err instanceof SandboxHttpError && err.retryAfterMs !== undefined
92
+ ? err.retryAfterMs
93
+ : base * 2 ** attempt + Math.random() * base;
94
+ await sleepWithSignal(backoff, signal);
95
+ }
96
+ }
97
+ }
98
+ function sleepWithSignal(ms, signal) {
99
+ return new Promise((resolve, reject) => {
100
+ if (signal?.aborted) {
101
+ reject(new DOMException("Aborted", "AbortError"));
102
+ return;
103
+ }
104
+ const timer = setTimeout(() => {
105
+ signal?.removeEventListener("abort", onAbort);
106
+ resolve();
107
+ }, ms);
108
+ const onAbort = () => {
109
+ clearTimeout(timer);
110
+ reject(new DOMException("Aborted", "AbortError"));
111
+ };
112
+ signal?.addEventListener("abort", onAbort, { once: true });
113
+ });
114
+ }
115
+ /**
116
+ * Default part size: 5 MiB. Bottom of Blaxel's recommended 5–10 MB range
117
+ * and well clear of the Sapiom ingress 8 MiB body-size ceiling (with
118
+ * room left for multipart form-data overhead).
119
+ */
120
+ exports.DEFAULT_PART_SIZE = 5 * 1024 * 1024;
121
+ /** Default number of parallel part uploads. */
122
+ exports.DEFAULT_CONCURRENCY = 4;
123
+ /** Default file permissions (Blaxel default). */
124
+ exports.DEFAULT_PERMISSIONS = "0644";
125
+ /**
126
+ * Normalize any supported content type into a `Blob`.
127
+ * `Blob.slice()` gives us random-access + lazy reads, so large inputs don't
128
+ * have to sit materialized in memory.
129
+ */
130
+ function toBlob(content) {
131
+ if (content instanceof Blob)
132
+ return content;
133
+ if (typeof content === "string") {
134
+ return new Blob([new TextEncoder().encode(content)]);
135
+ }
136
+ return new Blob([content]);
137
+ }
138
+ /**
139
+ * Split a byte range into part plans.
140
+ * Always emits at least one part (even for zero-byte inputs) so the caller
141
+ * still goes through the initiate/upload/complete handshake.
142
+ */
143
+ function planParts(totalBytes, partSize) {
144
+ if (!Number.isFinite(partSize) || partSize <= 0) {
145
+ throw new Error(`partSize must be a positive integer (got ${partSize})`);
146
+ }
147
+ const count = totalBytes === 0 ? 1 : Math.ceil(totalBytes / partSize);
148
+ if (count > exports.MAX_PARTS) {
149
+ const minPartSize = Math.ceil(totalBytes / exports.MAX_PARTS);
150
+ throw new Error(`File of ${totalBytes} bytes would require ${count} parts at partSize=${partSize}, ` +
151
+ `but the server accepts at most ${exports.MAX_PARTS}. Increase partSize to at least ${minPartSize}.`);
152
+ }
153
+ const plans = [];
154
+ for (let i = 0; i < count; i++) {
155
+ const start = i * partSize;
156
+ const end = Math.min(start + partSize, totalBytes);
157
+ plans.push({ partNumber: i + 1, start, end });
158
+ }
159
+ return plans;
160
+ }
161
+ /**
162
+ * Run `worker` over `items` with at most `concurrency` promises in flight.
163
+ * Rejects on the first worker failure (and stops scheduling further items).
164
+ */
165
+ async function runWithConcurrency(items, concurrency, worker) {
166
+ if (!Number.isFinite(concurrency) || concurrency < 1) {
167
+ throw new Error(`concurrency must be >= 1 (got ${concurrency})`);
168
+ }
169
+ const results = new Array(items.length);
170
+ let next = 0;
171
+ let failed = false;
172
+ let firstError;
173
+ const limit = Math.min(concurrency, items.length);
174
+ const runners = [];
175
+ for (let slot = 0; slot < limit; slot++) {
176
+ runners.push((async () => {
177
+ while (!failed) {
178
+ const i = next++;
179
+ if (i >= items.length)
180
+ return;
181
+ try {
182
+ results[i] = await worker(items[i], i);
183
+ }
184
+ catch (err) {
185
+ if (!failed) {
186
+ failed = true;
187
+ firstError = err;
188
+ }
189
+ return;
190
+ }
191
+ }
192
+ })());
193
+ }
194
+ await Promise.all(runners);
195
+ if (failed)
196
+ throw firstError;
197
+ return results;
198
+ }
199
+ //# sourceMappingURL=multipart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipart.js","sourceRoot":"","sources":["../../src/multipart.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { SandboxCreateOptions, ExecOptions, ExecResult, ExecStreamOptions, StreamingExecResult, ProcessStatusResponse } from "./types.js";
1
+ import type { SandboxCreateOptions, ExecOptions, ExecResult, ExecStreamOptions, StreamingExecResult, ProcessStatusResponse, MultipartInitiateResponse, MultipartPartInfo, MultipartUploadedPart, UploadFileOptions } from "./types.js";
2
2
  export declare class SapiomSandbox {
3
3
  /** Name / identifier of the sandbox. */
4
4
  readonly name: string;
@@ -31,6 +31,72 @@ export declare class SapiomSandbox {
31
31
  * @returns The file content as a string.
32
32
  */
33
33
  readFile(path: string): Promise<string>;
34
+ /**
35
+ * Upload a file to the sandbox using multipart upload.
36
+ *
37
+ * Handles the full initiate → part upload → complete lifecycle, with
38
+ * parallel part uploads and automatic abort on any failure (including
39
+ * `signal` aborts).
40
+ *
41
+ * Prefer this over {@link writeFile} for binary content or any file over
42
+ * a few MB. `writeFile` stays available for small text files.
43
+ *
44
+ * @param path - File path relative to workspaceRoot.
45
+ * @param content - Blob, Uint8Array, or string. Strings are UTF-8 encoded.
46
+ * @param opts - Upload options.
47
+ */
48
+ uploadFile(path: string, content: Blob | Uint8Array | string, opts?: UploadFileOptions): Promise<void>;
49
+ /**
50
+ * Initiate a multipart upload for a file path.
51
+ *
52
+ * Low-level: prefer {@link uploadFile} for the full lifecycle. Use this
53
+ * when you need custom retry/progress/resumable behavior.
54
+ */
55
+ initiateMultipartUpload(path: string, opts?: {
56
+ permissions?: string;
57
+ signal?: AbortSignal;
58
+ }): Promise<MultipartInitiateResponse>;
59
+ /**
60
+ * Upload a single part of a multipart upload.
61
+ *
62
+ * Low-level: prefer {@link uploadFile} for the full lifecycle.
63
+ *
64
+ * @param uploadId - Upload session ID from {@link initiateMultipartUpload}.
65
+ * @param partNumber - 1-indexed part number (1 to 10000).
66
+ * @param part - The part bytes.
67
+ */
68
+ uploadPart(uploadId: string, partNumber: number, part: Blob | Uint8Array, opts?: {
69
+ signal?: AbortSignal;
70
+ }): Promise<MultipartUploadedPart>;
71
+ /**
72
+ * Complete a multipart upload by committing the uploaded parts.
73
+ *
74
+ * Low-level: prefer {@link uploadFile} for the full lifecycle.
75
+ */
76
+ completeMultipartUpload(uploadId: string, parts: Array<{
77
+ partNumber: number;
78
+ etag: string;
79
+ }>, opts?: {
80
+ signal?: AbortSignal;
81
+ }): Promise<{
82
+ message: string;
83
+ path: string;
84
+ }>;
85
+ /**
86
+ * Abort a multipart upload and clean up any uploaded parts on the server.
87
+ */
88
+ abortMultipartUpload(uploadId: string, opts?: {
89
+ signal?: AbortSignal;
90
+ }): Promise<void>;
91
+ /**
92
+ * List the parts already uploaded for a multipart upload.
93
+ *
94
+ * Useful for resumable uploads: after reconnecting, call this to see
95
+ * which part numbers you still need to upload.
96
+ */
97
+ listMultipartParts(uploadId: string, opts?: {
98
+ signal?: AbortSignal;
99
+ }): Promise<MultipartPartInfo[]>;
34
100
  /**
35
101
  * Execute a command in the sandbox.
36
102
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EAEpB,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EAGnB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AA0DpB,qBAAa,aAAa;IACxB,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,OAAO;IAcP;;OAEG;WACU,MAAM,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwCvE;;;;;OAKG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB7D;;;;;OAKG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB7C;;;;;;;;;OASG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BpE;;;;;;;;;OASG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,mBAAmB,CAAC;IA4H/B;;;;;;;OAOG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAe7D;;;;;;;;OAQG;IACG,cAAc,CAClB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACvE,OAAO,CAAC,UAAU,CAAC;IAItB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBhB,cAAc;YA8Bd,YAAY;CAqC3B"}
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox.ts"],"names":[],"mappings":"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"}