@opengeni/sdk 4.4.1 → 4.5.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/README.md +27 -0
- package/dist/adapters/next.js +2 -2
- package/dist/artifacts.js +4 -4
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +5 -3
- package/dist/chat/index.js +5 -5
- package/dist/{chunk-3BWTS2MJ.js → chunk-ARDVIZIJ.js} +2 -2
- package/dist/{chunk-PVWOBYAZ.js → chunk-BXMNDWAN.js} +256 -78
- package/dist/chunk-BXMNDWAN.js.map +1 -0
- package/dist/{chunk-IVHLADZ7.js → chunk-GRUMGFK6.js} +2 -2
- package/dist/{chunk-2RVPHF37.js → chunk-JBAGMSN2.js} +66 -10
- package/dist/chunk-JBAGMSN2.js.map +1 -0
- package/dist/{chunk-35S72HAE.js → chunk-U4JUWOZV.js} +5 -5
- package/dist/{chunk-BLID3DCD.js → chunk-V4AIZAFF.js} +1 -1
- package/dist/chunk-V4AIZAFF.js.map +1 -0
- package/dist/{chunk-ALXDFL6C.js → chunk-VSOXNL3T.js} +2 -2
- package/dist/{chunk-CT6P2W2C.js → chunk-WI3WUT5H.js} +2 -2
- package/dist/client.d.ts +24 -1
- package/dist/codex-realtime-controller.js +1 -1
- package/dist/core.d.ts +2 -0
- package/dist/core.js +5 -3
- package/dist/document-authority.js +3 -3
- package/dist/editable-artifacts.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +35 -33
- package/dist/index.js.map +1 -1
- package/dist/read-retry.d.ts +61 -0
- package/dist/realtime.js +5 -5
- package/dist/session-proxy.d.ts +6 -1
- package/dist/session-proxy.js +2 -2
- package/dist/site-bridge-host.js +3 -3
- package/dist/site-browser-runtime.gen.d.ts +1 -1
- package/dist/site-document.js +1 -1
- package/dist/site-document.js.map +1 -1
- package/dist/site.js +3 -3
- package/dist/types.d.ts +40 -0
- package/dist/workspace-artifacts.d.ts +5 -0
- package/dist/workspace-live-stream.d.ts +7 -0
- package/package.json +3 -3
- package/src/browser.ts +2 -0
- package/src/client.ts +191 -73
- package/src/core.ts +2 -0
- package/src/index.ts +4 -0
- package/src/read-retry.ts +207 -0
- package/src/session-proxy.ts +95 -4
- package/src/site-browser-runtime.gen.ts +1 -1
- package/src/types.ts +38 -0
- package/src/workspace-artifacts.ts +6 -0
- package/src/workspace-live-stream.ts +12 -1
- package/dist/chunk-2RVPHF37.js.map +0 -1
- package/dist/chunk-BLID3DCD.js.map +0 -1
- package/dist/chunk-PVWOBYAZ.js.map +0 -1
- /package/dist/{chunk-3BWTS2MJ.js.map → chunk-ARDVIZIJ.js.map} +0 -0
- /package/dist/{chunk-IVHLADZ7.js.map → chunk-GRUMGFK6.js.map} +0 -0
- /package/dist/{chunk-35S72HAE.js.map → chunk-U4JUWOZV.js.map} +0 -0
- /package/dist/{chunk-ALXDFL6C.js.map → chunk-VSOXNL3T.js.map} +0 -0
- /package/dist/{chunk-CT6P2W2C.js.map → chunk-WI3WUT5H.js.map} +0 -0
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
OPENGENI_API_CONTRACT_REVISION,
|
|
19
19
|
OPENGENI_CORRELATION_HEADER,
|
|
20
20
|
RETAINED_OUTPUT_MAX_PAGE_BYTES
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-V4AIZAFF.js";
|
|
22
22
|
import {
|
|
23
23
|
OpenGeniInteractionClient,
|
|
24
24
|
decodeComputerFrameMetadataHeader,
|
|
@@ -390,6 +390,118 @@ function withDeprecationNotices(fetchImpl, handler) {
|
|
|
390
390
|
};
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
+
// src/read-retry.ts
|
|
394
|
+
var DEFAULT_READ_RETRY_POLICY = Object.freeze({
|
|
395
|
+
maxAttempts: 4,
|
|
396
|
+
initialDelayMs: 250,
|
|
397
|
+
maxDelayMs: 2e3,
|
|
398
|
+
maxElapsedMs: 5e3
|
|
399
|
+
});
|
|
400
|
+
var MAX_READ_RETRY_ATTEMPTS = 10;
|
|
401
|
+
var MAX_READ_RETRY_ELAPSED_MS = 6e4;
|
|
402
|
+
function boundedNumber(value, fallback, min, max) {
|
|
403
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
404
|
+
return Math.min(Math.max(value, min), max);
|
|
405
|
+
}
|
|
406
|
+
function resolveReadRetryPolicy(options) {
|
|
407
|
+
if (options === false) return null;
|
|
408
|
+
const input = options && typeof options === "object" ? options : {};
|
|
409
|
+
const maxAttempts = Math.floor(
|
|
410
|
+
boundedNumber(
|
|
411
|
+
input.maxAttempts,
|
|
412
|
+
DEFAULT_READ_RETRY_POLICY.maxAttempts,
|
|
413
|
+
1,
|
|
414
|
+
MAX_READ_RETRY_ATTEMPTS
|
|
415
|
+
)
|
|
416
|
+
);
|
|
417
|
+
if (maxAttempts <= 1) return null;
|
|
418
|
+
const maxElapsedMs = boundedNumber(
|
|
419
|
+
input.maxElapsedMs,
|
|
420
|
+
DEFAULT_READ_RETRY_POLICY.maxElapsedMs,
|
|
421
|
+
0,
|
|
422
|
+
MAX_READ_RETRY_ELAPSED_MS
|
|
423
|
+
);
|
|
424
|
+
const maxDelayMs = boundedNumber(
|
|
425
|
+
input.maxDelayMs,
|
|
426
|
+
DEFAULT_READ_RETRY_POLICY.maxDelayMs,
|
|
427
|
+
0,
|
|
428
|
+
MAX_READ_RETRY_ELAPSED_MS
|
|
429
|
+
);
|
|
430
|
+
const initialDelayMs = boundedNumber(
|
|
431
|
+
input.initialDelayMs,
|
|
432
|
+
DEFAULT_READ_RETRY_POLICY.initialDelayMs,
|
|
433
|
+
0,
|
|
434
|
+
maxDelayMs
|
|
435
|
+
);
|
|
436
|
+
return { maxAttempts, initialDelayMs, maxDelayMs, maxElapsedMs };
|
|
437
|
+
}
|
|
438
|
+
function isSafeReadMethod(method) {
|
|
439
|
+
const normalized = method.toUpperCase();
|
|
440
|
+
return normalized === "GET" || normalized === "HEAD";
|
|
441
|
+
}
|
|
442
|
+
function isTransientGatewayStatus(status) {
|
|
443
|
+
return status === 502 || status === 503 || status === 504;
|
|
444
|
+
}
|
|
445
|
+
var transportFailures = /* @__PURE__ */ new WeakSet();
|
|
446
|
+
function markTransportFailure(error) {
|
|
447
|
+
if (error instanceof TypeError) transportFailures.add(error);
|
|
448
|
+
}
|
|
449
|
+
var invalidResponses = /* @__PURE__ */ new WeakSet();
|
|
450
|
+
function invalidApiResponseError(body, options) {
|
|
451
|
+
const error = new OpenGeniApiError(502, body, options);
|
|
452
|
+
invalidResponses.add(error);
|
|
453
|
+
return error;
|
|
454
|
+
}
|
|
455
|
+
var NETWORK_FAILURE_MESSAGE = /failed to fetch|fetch failed|networkerror|network error|load failed|network request failed|network connection was lost|terminated|err_http2|econnreset|socket hang up/iu;
|
|
456
|
+
function isTransientRequestError(error) {
|
|
457
|
+
if (error instanceof OpenGeniApiError) {
|
|
458
|
+
return !invalidResponses.has(error) && isTransientGatewayStatus(error.status) && error.retryable;
|
|
459
|
+
}
|
|
460
|
+
if (!(error instanceof TypeError)) return false;
|
|
461
|
+
return transportFailures.has(error) || NETWORK_FAILURE_MESSAGE.test(error.message);
|
|
462
|
+
}
|
|
463
|
+
function parseRetryAfterMs(value, now = Date.now()) {
|
|
464
|
+
if (value === null || value === void 0) return null;
|
|
465
|
+
const trimmed = value.trim();
|
|
466
|
+
if (!trimmed) return null;
|
|
467
|
+
if (/^\d+$/.test(trimmed)) {
|
|
468
|
+
const seconds = Number(trimmed);
|
|
469
|
+
return Number.isSafeInteger(seconds) ? seconds * 1e3 : null;
|
|
470
|
+
}
|
|
471
|
+
if (!/[A-Za-z]/.test(trimmed)) return null;
|
|
472
|
+
const at = Date.parse(trimmed);
|
|
473
|
+
if (!Number.isFinite(at)) return null;
|
|
474
|
+
return Math.max(0, at - now);
|
|
475
|
+
}
|
|
476
|
+
function readRetryDelayMs(policy, retry, elapsedMs, retryAfterMs, random = Math.random) {
|
|
477
|
+
if (retry >= policy.maxAttempts) return null;
|
|
478
|
+
let delay;
|
|
479
|
+
if (retryAfterMs !== null) {
|
|
480
|
+
delay = retryAfterMs * (1 + 0.2 * Math.min(Math.max(random(), 0), 1));
|
|
481
|
+
} else {
|
|
482
|
+
const base = Math.min(policy.maxDelayMs, policy.initialDelayMs * 2 ** (retry - 1));
|
|
483
|
+
delay = base / 2 + base / 2 * Math.min(Math.max(random(), 0), 1);
|
|
484
|
+
}
|
|
485
|
+
if (elapsedMs + delay > policy.maxElapsedMs) return null;
|
|
486
|
+
return Math.round(delay);
|
|
487
|
+
}
|
|
488
|
+
function abortableReadRetryDelay(ms, signal) {
|
|
489
|
+
if (signal?.aborted) {
|
|
490
|
+
return Promise.reject(signal.reason ?? new DOMException("Request aborted", "AbortError"));
|
|
491
|
+
}
|
|
492
|
+
return new Promise((resolve, reject) => {
|
|
493
|
+
const onAbort = () => {
|
|
494
|
+
clearTimeout(timer);
|
|
495
|
+
reject(signal?.reason ?? new DOMException("Request aborted", "AbortError"));
|
|
496
|
+
};
|
|
497
|
+
const timer = setTimeout(() => {
|
|
498
|
+
signal?.removeEventListener("abort", onAbort);
|
|
499
|
+
resolve();
|
|
500
|
+
}, ms);
|
|
501
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
393
505
|
// src/workspace-control-stream.ts
|
|
394
506
|
async function* streamWorkspaceControlEvents(transport, options = {}) {
|
|
395
507
|
const signal = options.signal;
|
|
@@ -614,7 +726,8 @@ function parseWorkspaceLiveEvent(data) {
|
|
|
614
726
|
}
|
|
615
727
|
if (!isRecord2(value)) return null;
|
|
616
728
|
if (value.type === "workspace.sessions.changed" && typeof value.workspaceId === "string" && typeof value.available === "boolean" && (value.sessionIds === null || Array.isArray(value.sessionIds) && value.sessionIds.every((id) => typeof id === "string"))) {
|
|
617
|
-
|
|
729
|
+
const { siteSessionIds, ...hint } = value;
|
|
730
|
+
return Array.isArray(siteSessionIds) && siteSessionIds.every((id) => typeof id === "string") ? { ...hint, siteSessionIds } : hint;
|
|
618
731
|
}
|
|
619
732
|
if (typeof value.sequence !== "number") return null;
|
|
620
733
|
if (value.type === "workspace.control.changed" && typeof value.id === "string" && Number.isSafeInteger(value.sequence)) {
|
|
@@ -1019,6 +1132,7 @@ var OpenGeniClient = class {
|
|
|
1019
1132
|
fetchImpl;
|
|
1020
1133
|
sessionCommandTimeoutMs;
|
|
1021
1134
|
apiContractStrict;
|
|
1135
|
+
readRetryPolicy;
|
|
1022
1136
|
active = /* @__PURE__ */ new Map();
|
|
1023
1137
|
generations = /* @__PURE__ */ new Map();
|
|
1024
1138
|
queued = /* @__PURE__ */ new Map();
|
|
@@ -1039,6 +1153,7 @@ var OpenGeniClient = class {
|
|
|
1039
1153
|
}
|
|
1040
1154
|
this.sessionCommandTimeoutMs = sessionCommandTimeoutMs;
|
|
1041
1155
|
this.apiContractStrict = defaultApiContractMode(options) === "strict";
|
|
1156
|
+
this.readRetryPolicy = resolveReadRetryPolicy(options.readRetry);
|
|
1042
1157
|
this.interaction = new OpenGeniInteractionClient(this);
|
|
1043
1158
|
this.tools = createLazyToolsFacade(this);
|
|
1044
1159
|
}
|
|
@@ -1130,7 +1245,7 @@ var OpenGeniClient = class {
|
|
|
1130
1245
|
options.signal ? { signal: options.signal } : {}
|
|
1131
1246
|
);
|
|
1132
1247
|
if (!isTranscriptionRecordingListResponse(body)) {
|
|
1133
|
-
throw
|
|
1248
|
+
throw invalidApiResponseError("Invalid transcription recording list response.", {
|
|
1134
1249
|
code: "invalid_response"
|
|
1135
1250
|
});
|
|
1136
1251
|
}
|
|
@@ -1586,6 +1701,7 @@ var OpenGeniClient = class {
|
|
|
1586
1701
|
if (options.mineOnly) query.mineOnly = "true";
|
|
1587
1702
|
if (options.includePinned === false) query.includePinned = "false";
|
|
1588
1703
|
if (options.archivedOnly) query.archivedOnly = "true";
|
|
1704
|
+
if (options.siteConversations) query.siteConversations = options.siteConversations;
|
|
1589
1705
|
result = await this.requestJson(
|
|
1590
1706
|
"GET",
|
|
1591
1707
|
path,
|
|
@@ -1634,6 +1750,16 @@ var OpenGeniClient = class {
|
|
|
1634
1750
|
throw unsupportedSessionPage("Site access-filtered session lists");
|
|
1635
1751
|
return response;
|
|
1636
1752
|
}
|
|
1753
|
+
/**
|
|
1754
|
+
* Record that this person opened a Site, which orders its sidebar row like
|
|
1755
|
+
* session activity. Personal; needs `artifacts:read`.
|
|
1756
|
+
*/
|
|
1757
|
+
async recordSiteOpened(workspaceId, siteId) {
|
|
1758
|
+
return this.requestJson(
|
|
1759
|
+
"POST",
|
|
1760
|
+
`/v1/workspaces/${encodeURIComponent(workspaceId)}/published-artifacts/${encodeURIComponent(siteId)}/opened`
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1637
1763
|
/** Console/owner-authorized agent only. Never available through the Site frame bridge. */
|
|
1638
1764
|
async listSiteSessionAccess(workspaceId, siteId) {
|
|
1639
1765
|
return this.requestJson(
|
|
@@ -3409,7 +3535,7 @@ var OpenGeniClient = class {
|
|
|
3409
3535
|
const header = response.headers.get("x-opengeni-browser-frame");
|
|
3410
3536
|
if (mediaType !== "image/jpeg" && mediaType !== "image/png" || !header || header.length > 64 * 1024) {
|
|
3411
3537
|
await cancelResponseBody(response, "browser frame metadata is invalid");
|
|
3412
|
-
throw
|
|
3538
|
+
throw invalidApiResponseError("browser frame metadata is invalid");
|
|
3413
3539
|
}
|
|
3414
3540
|
let metadata;
|
|
3415
3541
|
try {
|
|
@@ -3418,11 +3544,11 @@ var OpenGeniClient = class {
|
|
|
3418
3544
|
);
|
|
3419
3545
|
} catch {
|
|
3420
3546
|
await cancelResponseBody(response, "browser frame metadata is invalid");
|
|
3421
|
-
throw
|
|
3547
|
+
throw invalidApiResponseError("browser frame metadata is invalid");
|
|
3422
3548
|
}
|
|
3423
3549
|
const data = await readBoundedResponseBytes(response, 24 * 1024 * 1024, null);
|
|
3424
3550
|
if (metadata.browserSessionId !== browserSessionId || metadata.targetId !== targetId || metadata.mediaType !== mediaType) {
|
|
3425
|
-
throw
|
|
3551
|
+
throw invalidApiResponseError("browser frame evidence does not match its request");
|
|
3426
3552
|
}
|
|
3427
3553
|
return { ...metadata, data };
|
|
3428
3554
|
}
|
|
@@ -3453,7 +3579,7 @@ var OpenGeniClient = class {
|
|
|
3453
3579
|
options
|
|
3454
3580
|
);
|
|
3455
3581
|
if (state.browserSessionId !== browserSessionId || state.targetId !== targetId) {
|
|
3456
|
-
throw
|
|
3582
|
+
throw invalidApiResponseError("browser target state belongs to another binding");
|
|
3457
3583
|
}
|
|
3458
3584
|
return state;
|
|
3459
3585
|
}
|
|
@@ -3466,7 +3592,7 @@ var OpenGeniClient = class {
|
|
|
3466
3592
|
options
|
|
3467
3593
|
);
|
|
3468
3594
|
if (result.browserSessionId !== browserSessionId || result.targetId !== targetId || result.kind !== request.kind || result.targetGeneration !== request.expectedTargetGeneration || result.documentGeneration !== request.expectedDocumentGeneration || result.frameId !== request.expectedFrameId) {
|
|
3469
|
-
throw
|
|
3595
|
+
throw invalidApiResponseError("browser DOM read belongs to another binding");
|
|
3470
3596
|
}
|
|
3471
3597
|
return result;
|
|
3472
3598
|
}
|
|
@@ -3677,19 +3803,19 @@ var OpenGeniClient = class {
|
|
|
3677
3803
|
const mediaType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
3678
3804
|
if (mediaType !== "image/jpeg" && mediaType !== "image/png") {
|
|
3679
3805
|
await cancelResponseBody(response, "computer frame media type is invalid");
|
|
3680
|
-
throw
|
|
3806
|
+
throw invalidApiResponseError("computer frame media type is invalid");
|
|
3681
3807
|
}
|
|
3682
3808
|
const metadataHeader = response.headers.get("x-opengeni-computer-frame");
|
|
3683
3809
|
if (!metadataHeader || metadataHeader.length > 32 * 1024) {
|
|
3684
3810
|
await cancelResponseBody(response, "computer frame metadata is invalid");
|
|
3685
|
-
throw
|
|
3811
|
+
throw invalidApiResponseError("computer frame metadata is invalid");
|
|
3686
3812
|
}
|
|
3687
3813
|
let metadata;
|
|
3688
3814
|
try {
|
|
3689
3815
|
metadata = decodeComputerFrameMetadataHeader(metadataHeader);
|
|
3690
3816
|
} catch {
|
|
3691
3817
|
await cancelResponseBody(response, "computer frame metadata is invalid");
|
|
3692
|
-
throw
|
|
3818
|
+
throw invalidApiResponseError("computer frame metadata is invalid");
|
|
3693
3819
|
}
|
|
3694
3820
|
const bytes = await readBoundedResponseBytes(response, 256 * 1024, null);
|
|
3695
3821
|
const mismatchReason = computerFrameEvidenceMismatchReason(metadata, {
|
|
@@ -3699,7 +3825,7 @@ var OpenGeniClient = class {
|
|
|
3699
3825
|
sha256: await sha256Hex(bytes)
|
|
3700
3826
|
});
|
|
3701
3827
|
if (mismatchReason) {
|
|
3702
|
-
throw
|
|
3828
|
+
throw invalidApiResponseError("computer frame evidence does not match its request");
|
|
3703
3829
|
}
|
|
3704
3830
|
return { ...metadata, data: bytes };
|
|
3705
3831
|
}
|
|
@@ -5440,7 +5566,7 @@ var OpenGeniClient = class {
|
|
|
5440
5566
|
if (!metadata.available) return { metadata, bytes: null };
|
|
5441
5567
|
const supportedScreenshot = (metadata.kind === "computer_screenshot" || metadata.kind === "browser_screenshot") && ["image/png", "image/jpeg", "image/webp"].includes(metadata.contentType);
|
|
5442
5568
|
if (!supportedScreenshot || !metadata.dimensions || metadata.originalBytes <= 0 || metadata.originalBytes > COMPUTER_SCREENSHOT_MAX_BYTES) {
|
|
5443
|
-
throw
|
|
5569
|
+
throw invalidApiResponseError("retained screenshot metadata is invalid");
|
|
5444
5570
|
}
|
|
5445
5571
|
const bytes = await this.downloadRetainedArtifactBytes(metadata, options);
|
|
5446
5572
|
return { metadata, bytes };
|
|
@@ -5453,7 +5579,7 @@ var OpenGeniClient = class {
|
|
|
5453
5579
|
const bytes = new Uint8Array(artifact.originalBytes);
|
|
5454
5580
|
const pageBytes = Math.min(artifact.retrieval.maxRangeBytes, RETAINED_OUTPUT_MAX_PAGE_BYTES);
|
|
5455
5581
|
if (!Number.isSafeInteger(pageBytes) || pageBytes <= 0) {
|
|
5456
|
-
throw
|
|
5582
|
+
throw invalidApiResponseError("retained artifact range metadata is invalid");
|
|
5457
5583
|
}
|
|
5458
5584
|
for (let start = 0; start < bytes.byteLength; start += pageBytes) {
|
|
5459
5585
|
options.signal?.throwIfAborted();
|
|
@@ -5473,15 +5599,15 @@ var OpenGeniClient = class {
|
|
|
5473
5599
|
}
|
|
5474
5600
|
}
|
|
5475
5601
|
}
|
|
5476
|
-
if (!page) throw
|
|
5602
|
+
if (!page) throw invalidApiResponseError("retained artifact range retry exhausted");
|
|
5477
5603
|
const expectedLength = end - start + 1;
|
|
5478
5604
|
if (page.status !== 206 || page.contentType !== artifact.contentType || page.contentLength !== expectedLength || page.contentRange !== `bytes ${start}-${end}/${artifact.originalBytes}`) {
|
|
5479
|
-
throw
|
|
5605
|
+
throw invalidApiResponseError("retained artifact range response is invalid");
|
|
5480
5606
|
}
|
|
5481
5607
|
bytes.set(page.bytes, start);
|
|
5482
5608
|
}
|
|
5483
5609
|
if (await sha256Hex(bytes) !== artifact.sha256) {
|
|
5484
|
-
throw
|
|
5610
|
+
throw invalidApiResponseError("retained artifact checksum mismatch");
|
|
5485
5611
|
}
|
|
5486
5612
|
return bytes;
|
|
5487
5613
|
}
|
|
@@ -5517,7 +5643,7 @@ var OpenGeniClient = class {
|
|
|
5517
5643
|
}
|
|
5518
5644
|
if (response.headers.get("accept-ranges") !== "bytes") {
|
|
5519
5645
|
await cancelResponseBody(response, "retained artifact response omitted byte-range support");
|
|
5520
|
-
throw
|
|
5646
|
+
throw invalidApiResponseError("retained artifact response omitted byte-range support");
|
|
5521
5647
|
}
|
|
5522
5648
|
let declaredLength;
|
|
5523
5649
|
try {
|
|
@@ -7819,63 +7945,114 @@ var OpenGeniClient = class {
|
|
|
7819
7945
|
const correlationId = crypto.randomUUID();
|
|
7820
7946
|
const abort = requestAbortSignal(options);
|
|
7821
7947
|
try {
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
Accept: "application/json",
|
|
7834
|
-
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
7835
|
-
},
|
|
7836
|
-
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
7837
|
-
...abort.signal ? { signal: abort.signal } : {}
|
|
7838
|
-
}),
|
|
7839
|
-
abort.signal
|
|
7948
|
+
const retryPolicy = isSafeReadMethod(method) ? this.readRetryPolicy : null;
|
|
7949
|
+
if (!retryPolicy) {
|
|
7950
|
+
return await this.requestJsonAttempt(
|
|
7951
|
+
method,
|
|
7952
|
+
path,
|
|
7953
|
+
body,
|
|
7954
|
+
query,
|
|
7955
|
+
options,
|
|
7956
|
+
abort.signal,
|
|
7957
|
+
correlationId,
|
|
7958
|
+
null
|
|
7840
7959
|
);
|
|
7841
|
-
} catch (error) {
|
|
7842
|
-
if (options.signal?.aborted) throw error;
|
|
7843
|
-
if (isMutationMethod(method)) {
|
|
7844
|
-
throw mutationTransportError(correlationId);
|
|
7845
|
-
}
|
|
7846
|
-
throw error;
|
|
7847
7960
|
}
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7961
|
+
const startedAt = Date.now();
|
|
7962
|
+
for (let retry = 1; ; retry += 1) {
|
|
7963
|
+
const attempt = {
|
|
7964
|
+
transportFailure: false,
|
|
7965
|
+
gatewayFailure: false,
|
|
7966
|
+
retryAfterMs: null
|
|
7967
|
+
};
|
|
7968
|
+
try {
|
|
7969
|
+
return await this.requestJsonAttempt(
|
|
7970
|
+
method,
|
|
7971
|
+
path,
|
|
7972
|
+
body,
|
|
7973
|
+
query,
|
|
7974
|
+
options,
|
|
7975
|
+
abort.signal,
|
|
7976
|
+
correlationId,
|
|
7977
|
+
attempt
|
|
7854
7978
|
);
|
|
7855
|
-
}
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7979
|
+
} catch (error) {
|
|
7980
|
+
const transient = attempt.transportFailure || attempt.gatewayFailure && isTransientRequestError(error);
|
|
7981
|
+
if (abort.signal?.aborted || !transient) throw error;
|
|
7982
|
+
const delay = readRetryDelayMs(
|
|
7983
|
+
retryPolicy,
|
|
7984
|
+
retry,
|
|
7985
|
+
Date.now() - startedAt,
|
|
7986
|
+
attempt.retryAfterMs
|
|
7860
7987
|
);
|
|
7861
|
-
|
|
7988
|
+
if (delay === null) throw error;
|
|
7989
|
+
await abortableReadRetryDelay(delay, abort.signal);
|
|
7862
7990
|
}
|
|
7863
|
-
await awaitWithAbort(assertJsonResponse(response, { method, correlationId }), abort.signal);
|
|
7864
|
-
const value = await awaitWithAbort(response.json(), abort.signal);
|
|
7865
|
-
recordObservedSessionSequence(value, response.headers.get(SESSION_SEQUENCE_HEADER));
|
|
7866
|
-
return value;
|
|
7867
|
-
} catch (error) {
|
|
7868
|
-
if (options.signal?.aborted) throw error;
|
|
7869
|
-
if (error instanceof OpenGeniApiError) throw error;
|
|
7870
|
-
if (isMutationMethod(method)) {
|
|
7871
|
-
throw mutationTransportError(correlationId);
|
|
7872
|
-
}
|
|
7873
|
-
throw error;
|
|
7874
7991
|
}
|
|
7875
7992
|
} finally {
|
|
7876
7993
|
abort.dispose();
|
|
7877
7994
|
}
|
|
7878
7995
|
}
|
|
7996
|
+
async requestJsonAttempt(method, path, body, query, options, signal, correlationId, attempt) {
|
|
7997
|
+
if (signal?.aborted) {
|
|
7998
|
+
throw signal.reason ?? new DOMException("Request aborted", "AbortError");
|
|
7999
|
+
}
|
|
8000
|
+
const headers = this.headers(correlationId);
|
|
8001
|
+
let response;
|
|
8002
|
+
try {
|
|
8003
|
+
response = await awaitWithAbort(
|
|
8004
|
+
this.fetchImpl(this.url(path, query), {
|
|
8005
|
+
method,
|
|
8006
|
+
headers: {
|
|
8007
|
+
...headers,
|
|
8008
|
+
Accept: "application/json",
|
|
8009
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
8010
|
+
},
|
|
8011
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
8012
|
+
...signal ? { signal } : {}
|
|
8013
|
+
}),
|
|
8014
|
+
signal
|
|
8015
|
+
);
|
|
8016
|
+
} catch (error) {
|
|
8017
|
+
if (options.signal?.aborted) throw error;
|
|
8018
|
+
if (isMutationMethod(method)) {
|
|
8019
|
+
throw mutationTransportError(correlationId);
|
|
8020
|
+
}
|
|
8021
|
+
if (error instanceof TypeError && attempt) attempt.transportFailure = true;
|
|
8022
|
+
markTransportFailure(error);
|
|
8023
|
+
throw error;
|
|
8024
|
+
}
|
|
8025
|
+
assertApiContractResponse(response, this.apiContractStrict);
|
|
8026
|
+
try {
|
|
8027
|
+
if (!response.ok) {
|
|
8028
|
+
if (attempt && isTransientGatewayStatus(response.status)) {
|
|
8029
|
+
attempt.gatewayFailure = true;
|
|
8030
|
+
attempt.retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
8031
|
+
}
|
|
8032
|
+
throw await awaitWithAbort(
|
|
8033
|
+
apiErrorFromResponse(response, { method, correlationId }),
|
|
8034
|
+
signal
|
|
8035
|
+
);
|
|
8036
|
+
}
|
|
8037
|
+
if (options.responseType === "void") {
|
|
8038
|
+
await awaitWithAbort(cancelResponseBody(response, "discarding void API response"), signal);
|
|
8039
|
+
return void 0;
|
|
8040
|
+
}
|
|
8041
|
+
await awaitWithAbort(assertJsonResponse(response, { method, correlationId }), signal);
|
|
8042
|
+
const value = await awaitWithAbort(response.json(), signal);
|
|
8043
|
+
recordObservedSessionSequence(value, response.headers.get(SESSION_SEQUENCE_HEADER));
|
|
8044
|
+
return value;
|
|
8045
|
+
} catch (error) {
|
|
8046
|
+
if (options.signal?.aborted) throw error;
|
|
8047
|
+
if (error instanceof OpenGeniApiError) throw error;
|
|
8048
|
+
if (isMutationMethod(method)) {
|
|
8049
|
+
throw mutationTransportError(correlationId);
|
|
8050
|
+
}
|
|
8051
|
+
if (error instanceof TypeError && attempt) attempt.transportFailure = true;
|
|
8052
|
+
markTransportFailure(error);
|
|
8053
|
+
throw error;
|
|
8054
|
+
}
|
|
8055
|
+
}
|
|
7879
8056
|
/** Authenticated, contract-checked response for bounded streaming downloads. */
|
|
7880
8057
|
async requestResponse(method, path, query = {}, options = {}) {
|
|
7881
8058
|
const correlationId = crypto.randomUUID();
|
|
@@ -7965,7 +8142,7 @@ function isTranscriptionRecordingResponse(value) {
|
|
|
7965
8142
|
}
|
|
7966
8143
|
function transcriptionRecordingResponse(value) {
|
|
7967
8144
|
if (isTranscriptionRecordingResponse(value)) return value;
|
|
7968
|
-
throw
|
|
8145
|
+
throw invalidApiResponseError("Invalid transcription recording response.", {
|
|
7969
8146
|
code: "invalid_response"
|
|
7970
8147
|
});
|
|
7971
8148
|
}
|
|
@@ -8062,7 +8239,7 @@ async function apiErrorFromResponse(response, context) {
|
|
|
8062
8239
|
async function assertJsonResponse(response, context) {
|
|
8063
8240
|
if (isJsonContentType(response.headers.get("content-type"))) return;
|
|
8064
8241
|
await cancelResponseBody(response, "unexpected non-JSON API response");
|
|
8065
|
-
throw
|
|
8242
|
+
throw invalidApiResponseError("", {
|
|
8066
8243
|
code: "upstream_unavailable",
|
|
8067
8244
|
retryable: true,
|
|
8068
8245
|
correlationId: response.headers.get(OPENGENI_CORRELATION_HEADER) ?? context.correlationId,
|
|
@@ -8137,44 +8314,44 @@ async function cancelResponseBody(response, reason) {
|
|
|
8137
8314
|
}
|
|
8138
8315
|
function assertRetainedWorkspaceArtifactReceipt(workspaceId, artifact) {
|
|
8139
8316
|
if (!parseRetainedGeneratedImageReference(artifact, workspaceId) && !parseRetainedWorkspaceFileReference(artifact, workspaceId)) {
|
|
8140
|
-
throw
|
|
8317
|
+
throw invalidApiResponseError("retained workspace artifact receipt is invalid");
|
|
8141
8318
|
}
|
|
8142
8319
|
}
|
|
8143
8320
|
function assertSafeArtifactDownloadUrl(value) {
|
|
8144
8321
|
if (!value || typeof value.url !== "string" || typeof value.expiresAt !== "string" || !Number.isFinite(Date.parse(value.expiresAt))) {
|
|
8145
|
-
throw
|
|
8322
|
+
throw invalidApiResponseError("retained artifact download URL is invalid");
|
|
8146
8323
|
}
|
|
8147
8324
|
let parsed;
|
|
8148
8325
|
try {
|
|
8149
8326
|
parsed = new URL(value.url);
|
|
8150
8327
|
} catch {
|
|
8151
|
-
throw
|
|
8328
|
+
throw invalidApiResponseError("retained artifact download URL is invalid");
|
|
8152
8329
|
}
|
|
8153
8330
|
if (!["http:", "https:"].includes(parsed.protocol) || parsed.username || parsed.password) {
|
|
8154
|
-
throw
|
|
8331
|
+
throw invalidApiResponseError("retained artifact download URL is unsafe");
|
|
8155
8332
|
}
|
|
8156
8333
|
}
|
|
8157
8334
|
function assertSafeVideoArtifactPlaybackSource(value, expectedArtifactId) {
|
|
8158
8335
|
if (!value || value.schemaVersion !== 1 || value.artifactId !== expectedArtifactId || value.contentType !== "video/mp4" || value.acceptRanges !== "bytes" || !Number.isSafeInteger(value.sizeBytes) || value.sizeBytes <= 0 || value.sizeBytes > GENERATED_VIDEO_MAX_BYTES || !/^[0-9a-f]{64}$/.test(value.sha256)) {
|
|
8159
|
-
throw
|
|
8336
|
+
throw invalidApiResponseError("generated-video playback source is invalid");
|
|
8160
8337
|
}
|
|
8161
8338
|
assertSafeArtifactDownloadUrl({ url: value.url, expiresAt: value.expiresAt });
|
|
8162
8339
|
}
|
|
8163
8340
|
function parseBoundedContentLength(value) {
|
|
8164
8341
|
if (value === null) return null;
|
|
8165
8342
|
if (!/^\d+$/.test(value)) {
|
|
8166
|
-
throw
|
|
8343
|
+
throw invalidApiResponseError("invalid retained artifact content-length");
|
|
8167
8344
|
}
|
|
8168
8345
|
const length = Number(value);
|
|
8169
8346
|
if (!Number.isSafeInteger(length) || length > RETAINED_OUTPUT_MAX_PAGE_BYTES) {
|
|
8170
|
-
throw
|
|
8347
|
+
throw invalidApiResponseError("retained artifact response exceeds the SDK byte limit");
|
|
8171
8348
|
}
|
|
8172
8349
|
return length;
|
|
8173
8350
|
}
|
|
8174
8351
|
async function readBoundedResponseBytes(response, maxBytes, expectedBytes) {
|
|
8175
8352
|
if (!response.body) {
|
|
8176
8353
|
if (expectedBytes !== null && expectedBytes !== 0) {
|
|
8177
|
-
throw
|
|
8354
|
+
throw invalidApiResponseError("retained artifact response length mismatch");
|
|
8178
8355
|
}
|
|
8179
8356
|
return new Uint8Array();
|
|
8180
8357
|
}
|
|
@@ -8188,7 +8365,7 @@ async function readBoundedResponseBytes(response, maxBytes, expectedBytes) {
|
|
|
8188
8365
|
totalBytes += value.byteLength;
|
|
8189
8366
|
if (totalBytes > maxBytes) {
|
|
8190
8367
|
await reader.cancel("retained artifact response exceeded the SDK byte limit").catch(() => void 0);
|
|
8191
|
-
throw
|
|
8368
|
+
throw invalidApiResponseError("retained artifact response exceeds the SDK byte limit");
|
|
8192
8369
|
}
|
|
8193
8370
|
chunks.push(value);
|
|
8194
8371
|
}
|
|
@@ -8196,7 +8373,7 @@ async function readBoundedResponseBytes(response, maxBytes, expectedBytes) {
|
|
|
8196
8373
|
reader.releaseLock();
|
|
8197
8374
|
}
|
|
8198
8375
|
if (expectedBytes !== null && totalBytes !== expectedBytes) {
|
|
8199
|
-
throw
|
|
8376
|
+
throw invalidApiResponseError("retained artifact response length mismatch");
|
|
8200
8377
|
}
|
|
8201
8378
|
const bytes = new Uint8Array(totalBytes);
|
|
8202
8379
|
let offset = 0;
|
|
@@ -8228,6 +8405,7 @@ export {
|
|
|
8228
8405
|
vaultErrorCode,
|
|
8229
8406
|
vaultErrorDetail,
|
|
8230
8407
|
parseDeprecationNotice,
|
|
8408
|
+
isTransientRequestError,
|
|
8231
8409
|
streamWorkspaceControlEvents,
|
|
8232
8410
|
streamWorkspaceInteractionRevisions,
|
|
8233
8411
|
streamWorkspaceLiveEvents,
|
|
@@ -8242,4 +8420,4 @@ export {
|
|
|
8242
8420
|
parseMediaGenerationResult,
|
|
8243
8421
|
OpenGeniClient
|
|
8244
8422
|
};
|
|
8245
|
-
//# sourceMappingURL=chunk-
|
|
8423
|
+
//# sourceMappingURL=chunk-BXMNDWAN.js.map
|