@rendobar/sdk 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +46 -7
- package/dist/index.d.cts +29 -4
- package/dist/index.d.mts +29 -4
- package/dist/index.mjs +46 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -307,22 +307,53 @@ function toBlob(file) {
|
|
|
307
307
|
return file instanceof Blob ? file : new Blob([file]);
|
|
308
308
|
}
|
|
309
309
|
/**
|
|
310
|
+
* Per-attempt upload time budget. fetch() exposes no upload progress, so a
|
|
311
|
+
* stalled socket and a slow link are indistinguishable from the outside; a
|
|
312
|
+
* hard per-attempt budget is the only portable stall cap. The ladder escalates
|
|
313
|
+
* (healthy 500 KiB/s assumption first, then 100, then 50) so a genuinely slow
|
|
314
|
+
* connection that times out on an early attempt still completes on a later,
|
|
315
|
+
* more patient one — while a hung socket gets cut and retried on a fresh
|
|
316
|
+
* connection instead of waiting on the OS TCP timeout.
|
|
317
|
+
*
|
|
318
|
+
* @internal exported for tests
|
|
319
|
+
*/
|
|
320
|
+
function attemptTimeoutMs(sizeBytes, attempt) {
|
|
321
|
+
const GRACE_MS = [
|
|
322
|
+
1e4,
|
|
323
|
+
3e4,
|
|
324
|
+
6e4
|
|
325
|
+
];
|
|
326
|
+
const RATE_BPS = [
|
|
327
|
+
500 * 1024,
|
|
328
|
+
100 * 1024,
|
|
329
|
+
50 * 1024
|
|
330
|
+
];
|
|
331
|
+
const i = Math.min(attempt, GRACE_MS.length - 1);
|
|
332
|
+
return GRACE_MS[i] + Math.ceil(sizeBytes / RATE_BPS[i] * 1e3);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
310
335
|
* PUT a body to a presigned R2 url with bounded retry.
|
|
311
336
|
*
|
|
312
337
|
* Returns the ETag string when the bucket exposes it, or `null` when the
|
|
313
|
-
* response header is absent (e.g. bucket CORS not exposing ETag).
|
|
314
|
-
*
|
|
315
|
-
*
|
|
338
|
+
* response header is absent (e.g. bucket CORS not exposing ETag). Network/HTTP
|
|
339
|
+
* failures and per-attempt timeouts trigger retries; a caller abort and a
|
|
340
|
+
* missing ETag do not (the latter is a deterministic misconfiguration, not a
|
|
341
|
+
* transient error).
|
|
342
|
+
*
|
|
343
|
+
* @internal exported for tests
|
|
316
344
|
*/
|
|
317
|
-
async function putWithRetry(url, body, signal, attempts = 3) {
|
|
345
|
+
async function putWithRetry(url, body, signal, sizeBytes, attempts = 3, attemptTimeouts) {
|
|
318
346
|
let lastErr;
|
|
319
347
|
for (let i = 0; i < attempts; i++) {
|
|
320
348
|
if (signal?.aborted) throw new Error("Upload aborted");
|
|
349
|
+
const timeoutMs = attemptTimeouts?.[i] ?? attemptTimeoutMs(sizeBytes, i);
|
|
350
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
351
|
+
const attemptSignal = signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
321
352
|
try {
|
|
322
353
|
const res = await fetch(url, {
|
|
323
354
|
method: "PUT",
|
|
324
355
|
body,
|
|
325
|
-
signal
|
|
356
|
+
signal: attemptSignal
|
|
326
357
|
});
|
|
327
358
|
if (!res.ok) throw new Error(`Upload PUT failed: ${res.status}`);
|
|
328
359
|
return res.headers.get("etag");
|
|
@@ -378,7 +409,7 @@ function createUploadsResource(request) {
|
|
|
378
409
|
return init.data;
|
|
379
410
|
}
|
|
380
411
|
if (init.status === "presigned") {
|
|
381
|
-
await putWithRetry(init.upload.url, blob, options.signal);
|
|
412
|
+
await putWithRetry(init.upload.url, blob, options.signal, size);
|
|
382
413
|
options.onProgress?.({
|
|
383
414
|
loaded: size,
|
|
384
415
|
total: size
|
|
@@ -399,7 +430,7 @@ function createUploadsResource(request) {
|
|
|
399
430
|
const chunk = blob.slice(start, Math.min(start + partSize, size));
|
|
400
431
|
let etag;
|
|
401
432
|
try {
|
|
402
|
-
etag = await putWithRetry(p.url, chunk, combinedSignal);
|
|
433
|
+
etag = await putWithRetry(p.url, chunk, combinedSignal, chunk.size);
|
|
403
434
|
} catch (e) {
|
|
404
435
|
internal.abort();
|
|
405
436
|
partError = e instanceof Error ? e : new Error(String(e));
|
|
@@ -668,6 +699,8 @@ const KNOWN_EVENT_TYPES = new Set([
|
|
|
668
699
|
"job.progress",
|
|
669
700
|
"job.step",
|
|
670
701
|
"job.log",
|
|
702
|
+
"job.metrics",
|
|
703
|
+
"job.context",
|
|
671
704
|
"balance.updated",
|
|
672
705
|
"subscription.updated",
|
|
673
706
|
"notification",
|
|
@@ -756,6 +789,12 @@ function dispatchJobEvent(event, options) {
|
|
|
756
789
|
case "job.result":
|
|
757
790
|
options.onResult?.(event);
|
|
758
791
|
break;
|
|
792
|
+
case "job.metrics":
|
|
793
|
+
options.onMetrics?.(event);
|
|
794
|
+
break;
|
|
795
|
+
case "job.context":
|
|
796
|
+
options.onContext?.(event);
|
|
797
|
+
break;
|
|
759
798
|
}
|
|
760
799
|
}
|
|
761
800
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -2269,6 +2269,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2269
2269
|
error: ZodOptional<ZodString>;
|
|
2270
2270
|
}, $strip>>;
|
|
2271
2271
|
logsAvailable: ZodBoolean;
|
|
2272
|
+
metricsAvailable: ZodBoolean;
|
|
2272
2273
|
createdAt: ZodNumber;
|
|
2273
2274
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2274
2275
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2305,6 +2306,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2305
2306
|
error: ZodOptional<ZodString>;
|
|
2306
2307
|
}, $strip>>;
|
|
2307
2308
|
logsAvailable: ZodBoolean;
|
|
2309
|
+
metricsAvailable: ZodBoolean;
|
|
2308
2310
|
createdAt: ZodNumber;
|
|
2309
2311
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2310
2312
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2343,6 +2345,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2343
2345
|
error: ZodOptional<ZodString>;
|
|
2344
2346
|
}, $strip>>;
|
|
2345
2347
|
logsAvailable: ZodBoolean;
|
|
2348
|
+
metricsAvailable: ZodBoolean;
|
|
2346
2349
|
createdAt: ZodNumber;
|
|
2347
2350
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2348
2351
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2381,6 +2384,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2381
2384
|
error: ZodOptional<ZodString>;
|
|
2382
2385
|
}, $strip>>;
|
|
2383
2386
|
logsAvailable: ZodBoolean;
|
|
2387
|
+
metricsAvailable: ZodBoolean;
|
|
2384
2388
|
createdAt: ZodNumber;
|
|
2385
2389
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2386
2390
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2461,6 +2465,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2461
2465
|
error: ZodOptional<ZodString>;
|
|
2462
2466
|
}, $strip>>;
|
|
2463
2467
|
logsAvailable: ZodBoolean;
|
|
2468
|
+
metricsAvailable: ZodBoolean;
|
|
2464
2469
|
createdAt: ZodNumber;
|
|
2465
2470
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2466
2471
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2503,6 +2508,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2503
2508
|
error: ZodOptional<ZodString>;
|
|
2504
2509
|
}, $strip>>;
|
|
2505
2510
|
logsAvailable: ZodBoolean;
|
|
2511
|
+
metricsAvailable: ZodBoolean;
|
|
2506
2512
|
createdAt: ZodNumber;
|
|
2507
2513
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2508
2514
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2520,7 +2526,7 @@ declare const jobTypeSchema: ZodObject<{
|
|
|
2520
2526
|
summary: ZodString;
|
|
2521
2527
|
needs: ZodArray<ZodString>;
|
|
2522
2528
|
pattern: ZodNullable<ZodString>;
|
|
2523
|
-
|
|
2529
|
+
runner: ZodOptional<ZodObject<{
|
|
2524
2530
|
id: ZodString;
|
|
2525
2531
|
resource: ZodString;
|
|
2526
2532
|
}, $strip>>;
|
|
@@ -2866,6 +2872,19 @@ declare const orgEventSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2866
2872
|
stepProgress: ZodOptional<ZodNumber>;
|
|
2867
2873
|
eta: ZodOptional<ZodNumber>;
|
|
2868
2874
|
metrics: ZodOptional<ZodRecord<ZodString, ZodUnion<readonly [ZodNumber, ZodString]>>>;
|
|
2875
|
+
}, $strip>, ZodObject<{
|
|
2876
|
+
type: ZodLiteral<"job.metrics">;
|
|
2877
|
+
jobId: ZodString;
|
|
2878
|
+
timestamp: ZodNumber;
|
|
2879
|
+
cpuPct: ZodNumber;
|
|
2880
|
+
cpuCores: ZodNumber;
|
|
2881
|
+
allocatedCores: ZodOptional<ZodNumber>;
|
|
2882
|
+
memUsedMB: ZodNumber;
|
|
2883
|
+
memLimitMB: ZodNumber;
|
|
2884
|
+
diskRMBps: ZodOptional<ZodNumber>;
|
|
2885
|
+
diskWMBps: ZodOptional<ZodNumber>;
|
|
2886
|
+
netRxMBps: ZodOptional<ZodNumber>;
|
|
2887
|
+
netTxMBps: ZodOptional<ZodNumber>;
|
|
2869
2888
|
}, $strip>, ZodObject<{
|
|
2870
2889
|
type: ZodLiteral<"job.step">;
|
|
2871
2890
|
jobId: ZodString;
|
|
@@ -2902,10 +2921,10 @@ declare const orgEventSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2902
2921
|
}, $strip>], "type">;
|
|
2903
2922
|
type OrgEvent = output<typeof orgEventSchema>;
|
|
2904
2923
|
/**
|
|
2905
|
-
* Log entry data structure used by dashboard hooks and
|
|
2924
|
+
* Log entry data structure used by dashboard hooks and runner.
|
|
2906
2925
|
* Import from `@rendobar/shared/events/org-events`.
|
|
2907
2926
|
*
|
|
2908
|
-
* Matches
|
|
2927
|
+
* Matches runner's log event format.
|
|
2909
2928
|
*/
|
|
2910
2929
|
interface LogEntryData {
|
|
2911
2930
|
timestamp: number;
|
|
@@ -2949,7 +2968,7 @@ declare function jobData<T>(job: JobResponse): T | null;
|
|
|
2949
2968
|
* Per-job execution timing breakdown. Returned by `client.jobs.getTimings(id)`.
|
|
2950
2969
|
*
|
|
2951
2970
|
* All values are milliseconds, or `null` if the corresponding stage did not
|
|
2952
|
-
* execute (e.g. a sync-completed job has no
|
|
2971
|
+
* execute (e.g. a sync-completed job has no runner or queue timings).
|
|
2953
2972
|
*/
|
|
2954
2973
|
interface JobTimings {
|
|
2955
2974
|
jobId: string;
|
|
@@ -3278,6 +3297,12 @@ interface JobSubscribeOptions {
|
|
|
3278
3297
|
onComplete?: (event: Extract<OrgEvent, {
|
|
3279
3298
|
type: "job.status";
|
|
3280
3299
|
}>) => void;
|
|
3300
|
+
onMetrics?: (event: Extract<OrgEvent, {
|
|
3301
|
+
type: "job.metrics";
|
|
3302
|
+
}>) => void;
|
|
3303
|
+
onContext?: (event: Extract<OrgEvent, {
|
|
3304
|
+
type: "job.context";
|
|
3305
|
+
}>) => void;
|
|
3281
3306
|
onError?: (error: Error) => void;
|
|
3282
3307
|
}
|
|
3283
3308
|
interface JobSubscription {
|
package/dist/index.d.mts
CHANGED
|
@@ -2269,6 +2269,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2269
2269
|
error: ZodOptional<ZodString>;
|
|
2270
2270
|
}, $strip>>;
|
|
2271
2271
|
logsAvailable: ZodBoolean;
|
|
2272
|
+
metricsAvailable: ZodBoolean;
|
|
2272
2273
|
createdAt: ZodNumber;
|
|
2273
2274
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2274
2275
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2305,6 +2306,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2305
2306
|
error: ZodOptional<ZodString>;
|
|
2306
2307
|
}, $strip>>;
|
|
2307
2308
|
logsAvailable: ZodBoolean;
|
|
2309
|
+
metricsAvailable: ZodBoolean;
|
|
2308
2310
|
createdAt: ZodNumber;
|
|
2309
2311
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2310
2312
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2343,6 +2345,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2343
2345
|
error: ZodOptional<ZodString>;
|
|
2344
2346
|
}, $strip>>;
|
|
2345
2347
|
logsAvailable: ZodBoolean;
|
|
2348
|
+
metricsAvailable: ZodBoolean;
|
|
2346
2349
|
createdAt: ZodNumber;
|
|
2347
2350
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2348
2351
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2381,6 +2384,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2381
2384
|
error: ZodOptional<ZodString>;
|
|
2382
2385
|
}, $strip>>;
|
|
2383
2386
|
logsAvailable: ZodBoolean;
|
|
2387
|
+
metricsAvailable: ZodBoolean;
|
|
2384
2388
|
createdAt: ZodNumber;
|
|
2385
2389
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2386
2390
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2461,6 +2465,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2461
2465
|
error: ZodOptional<ZodString>;
|
|
2462
2466
|
}, $strip>>;
|
|
2463
2467
|
logsAvailable: ZodBoolean;
|
|
2468
|
+
metricsAvailable: ZodBoolean;
|
|
2464
2469
|
createdAt: ZodNumber;
|
|
2465
2470
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2466
2471
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2503,6 +2508,7 @@ declare const jobResponseSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2503
2508
|
error: ZodOptional<ZodString>;
|
|
2504
2509
|
}, $strip>>;
|
|
2505
2510
|
logsAvailable: ZodBoolean;
|
|
2511
|
+
metricsAvailable: ZodBoolean;
|
|
2506
2512
|
createdAt: ZodNumber;
|
|
2507
2513
|
dispatchedAt: ZodNullable<ZodNumber>;
|
|
2508
2514
|
startedAt: ZodNullable<ZodNumber>;
|
|
@@ -2520,7 +2526,7 @@ declare const jobTypeSchema: ZodObject<{
|
|
|
2520
2526
|
summary: ZodString;
|
|
2521
2527
|
needs: ZodArray<ZodString>;
|
|
2522
2528
|
pattern: ZodNullable<ZodString>;
|
|
2523
|
-
|
|
2529
|
+
runner: ZodOptional<ZodObject<{
|
|
2524
2530
|
id: ZodString;
|
|
2525
2531
|
resource: ZodString;
|
|
2526
2532
|
}, $strip>>;
|
|
@@ -2866,6 +2872,19 @@ declare const orgEventSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2866
2872
|
stepProgress: ZodOptional<ZodNumber>;
|
|
2867
2873
|
eta: ZodOptional<ZodNumber>;
|
|
2868
2874
|
metrics: ZodOptional<ZodRecord<ZodString, ZodUnion<readonly [ZodNumber, ZodString]>>>;
|
|
2875
|
+
}, $strip>, ZodObject<{
|
|
2876
|
+
type: ZodLiteral<"job.metrics">;
|
|
2877
|
+
jobId: ZodString;
|
|
2878
|
+
timestamp: ZodNumber;
|
|
2879
|
+
cpuPct: ZodNumber;
|
|
2880
|
+
cpuCores: ZodNumber;
|
|
2881
|
+
allocatedCores: ZodOptional<ZodNumber>;
|
|
2882
|
+
memUsedMB: ZodNumber;
|
|
2883
|
+
memLimitMB: ZodNumber;
|
|
2884
|
+
diskRMBps: ZodOptional<ZodNumber>;
|
|
2885
|
+
diskWMBps: ZodOptional<ZodNumber>;
|
|
2886
|
+
netRxMBps: ZodOptional<ZodNumber>;
|
|
2887
|
+
netTxMBps: ZodOptional<ZodNumber>;
|
|
2869
2888
|
}, $strip>, ZodObject<{
|
|
2870
2889
|
type: ZodLiteral<"job.step">;
|
|
2871
2890
|
jobId: ZodString;
|
|
@@ -2902,10 +2921,10 @@ declare const orgEventSchema: ZodDiscriminatedUnion<[ZodObject<{
|
|
|
2902
2921
|
}, $strip>], "type">;
|
|
2903
2922
|
type OrgEvent = output<typeof orgEventSchema>;
|
|
2904
2923
|
/**
|
|
2905
|
-
* Log entry data structure used by dashboard hooks and
|
|
2924
|
+
* Log entry data structure used by dashboard hooks and runner.
|
|
2906
2925
|
* Import from `@rendobar/shared/events/org-events`.
|
|
2907
2926
|
*
|
|
2908
|
-
* Matches
|
|
2927
|
+
* Matches runner's log event format.
|
|
2909
2928
|
*/
|
|
2910
2929
|
interface LogEntryData {
|
|
2911
2930
|
timestamp: number;
|
|
@@ -2949,7 +2968,7 @@ declare function jobData<T>(job: JobResponse): T | null;
|
|
|
2949
2968
|
* Per-job execution timing breakdown. Returned by `client.jobs.getTimings(id)`.
|
|
2950
2969
|
*
|
|
2951
2970
|
* All values are milliseconds, or `null` if the corresponding stage did not
|
|
2952
|
-
* execute (e.g. a sync-completed job has no
|
|
2971
|
+
* execute (e.g. a sync-completed job has no runner or queue timings).
|
|
2953
2972
|
*/
|
|
2954
2973
|
interface JobTimings {
|
|
2955
2974
|
jobId: string;
|
|
@@ -3278,6 +3297,12 @@ interface JobSubscribeOptions {
|
|
|
3278
3297
|
onComplete?: (event: Extract<OrgEvent, {
|
|
3279
3298
|
type: "job.status";
|
|
3280
3299
|
}>) => void;
|
|
3300
|
+
onMetrics?: (event: Extract<OrgEvent, {
|
|
3301
|
+
type: "job.metrics";
|
|
3302
|
+
}>) => void;
|
|
3303
|
+
onContext?: (event: Extract<OrgEvent, {
|
|
3304
|
+
type: "job.context";
|
|
3305
|
+
}>) => void;
|
|
3281
3306
|
onError?: (error: Error) => void;
|
|
3282
3307
|
}
|
|
3283
3308
|
interface JobSubscription {
|
package/dist/index.mjs
CHANGED
|
@@ -306,22 +306,53 @@ function toBlob(file) {
|
|
|
306
306
|
return file instanceof Blob ? file : new Blob([file]);
|
|
307
307
|
}
|
|
308
308
|
/**
|
|
309
|
+
* Per-attempt upload time budget. fetch() exposes no upload progress, so a
|
|
310
|
+
* stalled socket and a slow link are indistinguishable from the outside; a
|
|
311
|
+
* hard per-attempt budget is the only portable stall cap. The ladder escalates
|
|
312
|
+
* (healthy 500 KiB/s assumption first, then 100, then 50) so a genuinely slow
|
|
313
|
+
* connection that times out on an early attempt still completes on a later,
|
|
314
|
+
* more patient one — while a hung socket gets cut and retried on a fresh
|
|
315
|
+
* connection instead of waiting on the OS TCP timeout.
|
|
316
|
+
*
|
|
317
|
+
* @internal exported for tests
|
|
318
|
+
*/
|
|
319
|
+
function attemptTimeoutMs(sizeBytes, attempt) {
|
|
320
|
+
const GRACE_MS = [
|
|
321
|
+
1e4,
|
|
322
|
+
3e4,
|
|
323
|
+
6e4
|
|
324
|
+
];
|
|
325
|
+
const RATE_BPS = [
|
|
326
|
+
500 * 1024,
|
|
327
|
+
100 * 1024,
|
|
328
|
+
50 * 1024
|
|
329
|
+
];
|
|
330
|
+
const i = Math.min(attempt, GRACE_MS.length - 1);
|
|
331
|
+
return GRACE_MS[i] + Math.ceil(sizeBytes / RATE_BPS[i] * 1e3);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
309
334
|
* PUT a body to a presigned R2 url with bounded retry.
|
|
310
335
|
*
|
|
311
336
|
* Returns the ETag string when the bucket exposes it, or `null` when the
|
|
312
|
-
* response header is absent (e.g. bucket CORS not exposing ETag).
|
|
313
|
-
*
|
|
314
|
-
*
|
|
337
|
+
* response header is absent (e.g. bucket CORS not exposing ETag). Network/HTTP
|
|
338
|
+
* failures and per-attempt timeouts trigger retries; a caller abort and a
|
|
339
|
+
* missing ETag do not (the latter is a deterministic misconfiguration, not a
|
|
340
|
+
* transient error).
|
|
341
|
+
*
|
|
342
|
+
* @internal exported for tests
|
|
315
343
|
*/
|
|
316
|
-
async function putWithRetry(url, body, signal, attempts = 3) {
|
|
344
|
+
async function putWithRetry(url, body, signal, sizeBytes, attempts = 3, attemptTimeouts) {
|
|
317
345
|
let lastErr;
|
|
318
346
|
for (let i = 0; i < attempts; i++) {
|
|
319
347
|
if (signal?.aborted) throw new Error("Upload aborted");
|
|
348
|
+
const timeoutMs = attemptTimeouts?.[i] ?? attemptTimeoutMs(sizeBytes, i);
|
|
349
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
350
|
+
const attemptSignal = signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
320
351
|
try {
|
|
321
352
|
const res = await fetch(url, {
|
|
322
353
|
method: "PUT",
|
|
323
354
|
body,
|
|
324
|
-
signal
|
|
355
|
+
signal: attemptSignal
|
|
325
356
|
});
|
|
326
357
|
if (!res.ok) throw new Error(`Upload PUT failed: ${res.status}`);
|
|
327
358
|
return res.headers.get("etag");
|
|
@@ -377,7 +408,7 @@ function createUploadsResource(request) {
|
|
|
377
408
|
return init.data;
|
|
378
409
|
}
|
|
379
410
|
if (init.status === "presigned") {
|
|
380
|
-
await putWithRetry(init.upload.url, blob, options.signal);
|
|
411
|
+
await putWithRetry(init.upload.url, blob, options.signal, size);
|
|
381
412
|
options.onProgress?.({
|
|
382
413
|
loaded: size,
|
|
383
414
|
total: size
|
|
@@ -398,7 +429,7 @@ function createUploadsResource(request) {
|
|
|
398
429
|
const chunk = blob.slice(start, Math.min(start + partSize, size));
|
|
399
430
|
let etag;
|
|
400
431
|
try {
|
|
401
|
-
etag = await putWithRetry(p.url, chunk, combinedSignal);
|
|
432
|
+
etag = await putWithRetry(p.url, chunk, combinedSignal, chunk.size);
|
|
402
433
|
} catch (e) {
|
|
403
434
|
internal.abort();
|
|
404
435
|
partError = e instanceof Error ? e : new Error(String(e));
|
|
@@ -667,6 +698,8 @@ const KNOWN_EVENT_TYPES = new Set([
|
|
|
667
698
|
"job.progress",
|
|
668
699
|
"job.step",
|
|
669
700
|
"job.log",
|
|
701
|
+
"job.metrics",
|
|
702
|
+
"job.context",
|
|
670
703
|
"balance.updated",
|
|
671
704
|
"subscription.updated",
|
|
672
705
|
"notification",
|
|
@@ -755,6 +788,12 @@ function dispatchJobEvent(event, options) {
|
|
|
755
788
|
case "job.result":
|
|
756
789
|
options.onResult?.(event);
|
|
757
790
|
break;
|
|
791
|
+
case "job.metrics":
|
|
792
|
+
options.onMetrics?.(event);
|
|
793
|
+
break;
|
|
794
|
+
case "job.context":
|
|
795
|
+
options.onContext?.(event);
|
|
796
|
+
break;
|
|
758
797
|
}
|
|
759
798
|
}
|
|
760
799
|
//#endregion
|