@bounded-sh/client 0.0.100-performance.1 → 0.0.101
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 +83 -0
- package/dist/auth/turnkey-auth.d.ts +4 -1
- package/dist/builds/client.d.ts +50 -5
- package/dist/builds/index.d.ts +6 -1
- package/dist/builds/media-tools.d.ts +37 -0
- package/dist/builds/types.d.ts +316 -16
- package/dist/{email-auth-provider-BGTfU1_i.mjs → email-auth-provider-BJXeBUwp.mjs} +2 -2
- package/dist/{email-auth-provider-CIRbOSM3.mjs.map → email-auth-provider-BJXeBUwp.mjs.map} +1 -1
- package/dist/{email-auth-provider-C6SFJd9L.js → email-auth-provider-Cr3I4Po5.js} +2 -2
- package/dist/{email-auth-provider-C6SFJd9L.js.map → email-auth-provider-Cr3I4Po5.js.map} +1 -1
- package/dist/{email-auth-provider-CIRbOSM3.mjs → email-auth-provider-Ct3YA68i.mjs} +2 -2
- package/dist/{email-auth-provider-BGTfU1_i.mjs.map → email-auth-provider-Ct3YA68i.mjs.map} +1 -1
- package/dist/{email-auth-provider-Cpj8hIFu.js → email-auth-provider-DCZ93FYg.js} +2 -2
- package/dist/{email-auth-provider-Cpj8hIFu.js.map → email-auth-provider-DCZ93FYg.js.map} +1 -1
- package/dist/{guest-auth-provider-0PjGFGDm.js → guest-auth-provider--Sqlucfr.js} +2 -2
- package/dist/{guest-auth-provider-0PjGFGDm.js.map → guest-auth-provider--Sqlucfr.js.map} +1 -1
- package/dist/{guest-auth-provider-pC-AheTZ.js → guest-auth-provider-CPj-w7_R.js} +2 -2
- package/dist/{guest-auth-provider-pC-AheTZ.js.map → guest-auth-provider-CPj-w7_R.js.map} +1 -1
- package/dist/{guest-auth-provider-DVxlea-z.mjs → guest-auth-provider-CUo6sgop.mjs} +2 -2
- package/dist/{guest-auth-provider-DVxlea-z.mjs.map → guest-auth-provider-CUo6sgop.mjs.map} +1 -1
- package/dist/{guest-auth-provider-C23vWrOT.mjs → guest-auth-provider-DMtDTZeA.mjs} +2 -2
- package/dist/{guest-auth-provider-C23vWrOT.mjs.map → guest-auth-provider-DMtDTZeA.mjs.map} +1 -1
- package/dist/{index-DmAXYXDi.mjs → index-CaZx7sd8.mjs} +687 -142
- package/dist/index-CaZx7sd8.mjs.map +1 -0
- package/dist/{index-DUVRmF9-.js → index-Pyb2SLgv.js} +689 -141
- package/dist/index-Pyb2SLgv.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{index.native-r1I-9E8e.mjs → index.native-3T0IcOed.mjs} +370 -9
- package/dist/index.native-3T0IcOed.mjs.map +1 -0
- package/dist/{index.native-CllNqdoy.js → index.native-PGrxu7RO.js} +370 -8
- package/dist/index.native-PGrxu7RO.js.map +1 -0
- package/dist/index.native.d.ts +3 -1
- package/dist/index.native.js +18 -1
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +2 -2
- package/dist/{injected-evm-wallet-provider-BPZMEE8I.mjs → injected-evm-wallet-provider-B3Mtkdnu.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-BPZMEE8I.mjs.map → injected-evm-wallet-provider-B3Mtkdnu.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-BXM8TfS3.js → injected-evm-wallet-provider-BNu6Z-iN.js} +2 -2
- package/dist/{injected-evm-wallet-provider-BXM8TfS3.js.map → injected-evm-wallet-provider-BNu6Z-iN.js.map} +1 -1
- package/dist/{injected-evm-wallet-provider-CkhN5u3d.mjs → injected-evm-wallet-provider-C8rBnyO1.mjs} +2 -2
- package/dist/{injected-evm-wallet-provider-CkhN5u3d.mjs.map → injected-evm-wallet-provider-C8rBnyO1.mjs.map} +1 -1
- package/dist/{injected-evm-wallet-provider-Dq3FDV1M.js → injected-evm-wallet-provider-U0XJu5HM.js} +2 -2
- package/dist/{injected-evm-wallet-provider-Dq3FDV1M.js.map → injected-evm-wallet-provider-U0XJu5HM.js.map} +1 -1
- package/dist/{injected-wallet-provider-Bi_mB_q3.js → injected-wallet-provider-29eTkM-A.js} +2 -2
- package/dist/injected-wallet-provider-29eTkM-A.js.map +1 -0
- package/dist/{injected-wallet-provider-BlSdRbgq.mjs → injected-wallet-provider-BnmYbm79.mjs} +2 -2
- package/dist/injected-wallet-provider-BnmYbm79.mjs.map +1 -0
- package/dist/{injected-wallet-provider-B3LLEpfp.js → injected-wallet-provider-Cv9RELO6.js} +2 -2
- package/dist/injected-wallet-provider-Cv9RELO6.js.map +1 -0
- package/dist/{injected-wallet-provider-CLLhLBAJ.mjs → injected-wallet-provider-DR8xVudg.mjs} +2 -2
- package/dist/injected-wallet-provider-DR8xVudg.mjs.map +1 -0
- package/dist/services/broadcast.d.ts +28 -0
- package/dist/services/session.d.ts +28 -0
- package/package.json +2 -2
- package/dist/index-DUVRmF9-.js.map +0 -1
- package/dist/index-DmAXYXDi.mjs.map +0 -1
- package/dist/index.native-CllNqdoy.js.map +0 -1
- package/dist/index.native-r1I-9E8e.mjs.map +0 -1
- package/dist/injected-wallet-provider-B3LLEpfp.js.map +0 -1
- package/dist/injected-wallet-provider-Bi_mB_q3.js.map +0 -1
- package/dist/injected-wallet-provider-BlSdRbgq.mjs.map +0 -1
- package/dist/injected-wallet-provider-CLLhLBAJ.mjs.map +0 -1
|
@@ -35,13 +35,6 @@ function walletOperationGuard() {
|
|
|
35
35
|
throw new Error('wallet_session_changed');
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
function walletLoginGuard(signal) {
|
|
39
|
-
const generation = ++loginGeneration;
|
|
40
|
-
return () => {
|
|
41
|
-
if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || generation !== loginGeneration)
|
|
42
|
-
throw new Error('wallet_login_cancelled');
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
38
|
// This realm owns one active SDK session and one retained signer frame.
|
|
46
39
|
let activeWalletState;
|
|
47
40
|
function setWalletSessionState(key, state) { activeWalletState = { key, state }; }
|
|
@@ -4522,11 +4515,6 @@ function ensureFonts() {
|
|
|
4522
4515
|
link.setAttribute("data-bounded-fonts", "1");
|
|
4523
4516
|
document.head.append(pre1, pre2, link);
|
|
4524
4517
|
}
|
|
4525
|
-
/** Tag the already mounted login document without moving or navigating it. */
|
|
4526
|
-
function bindWarmSignerFrame(frame, context) {
|
|
4527
|
-
if ((modal === null || modal === void 0 ? void 0 : modal.iframe) === frame)
|
|
4528
|
-
modal.iframeContext = context;
|
|
4529
|
-
}
|
|
4530
4518
|
|
|
4531
4519
|
// turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
|
|
4532
4520
|
// in-app WIDGET (bounded-widget-modal.ts). The Bounded-owned signer page is loaded
|
|
@@ -5885,14 +5873,13 @@ function completeLoginInPopup(openerOrigin) {
|
|
|
5885
5873
|
// identical to exchangeCode's tail so the realtime worker cannot tell them apart.
|
|
5886
5874
|
async function establishInlineSession(data, beforeCommit, beforeStore) {
|
|
5887
5875
|
const base = await issuerBase();
|
|
5888
|
-
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
5889
5876
|
const idToken = tokenField(data, 'id_token', 'idToken');
|
|
5890
5877
|
if (!idToken)
|
|
5891
5878
|
throw new Error('No id_token in the inline session response');
|
|
5892
5879
|
const accessToken = tokenField(data, 'access_token', 'accessToken') || idToken;
|
|
5893
5880
|
const refreshToken = boundedRefreshTokenField(data);
|
|
5894
5881
|
const user = userFromIdToken(idToken);
|
|
5895
|
-
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => {
|
|
5882
|
+
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { });
|
|
5896
5883
|
// Adopt the OIDC provider on EVERY session surface - including core's signing
|
|
5897
5884
|
// pointer (getConfig().authProvider), which this path used to skip, leaving
|
|
5898
5885
|
// onchain writes routed through a previous (e.g. logged-out wallet) provider.
|
|
@@ -6321,7 +6308,7 @@ async function getAuthProvider(config) {
|
|
|
6321
6308
|
// manager as legacy email sessions. Human login should be started
|
|
6322
6309
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6323
6310
|
// logout surface for those sessions.
|
|
6324
|
-
currentAuthProvider = new (await import('./email-auth-provider-
|
|
6311
|
+
currentAuthProvider = new (await import('./email-auth-provider-BJXeBUwp.mjs')).EmailAuthProvider();
|
|
6325
6312
|
break;
|
|
6326
6313
|
case "phantom": {
|
|
6327
6314
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6363,7 +6350,7 @@ async function getAuthProvider(config) {
|
|
|
6363
6350
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6364
6351
|
// evidence the user has a wallet.
|
|
6365
6352
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6366
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
6353
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-DR8xVudg.mjs');
|
|
6367
6354
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6368
6355
|
break;
|
|
6369
6356
|
}
|
|
@@ -6376,7 +6363,7 @@ async function getAuthProvider(config) {
|
|
|
6376
6363
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6377
6364
|
// to point at a specific wallet or set chainId/domain.
|
|
6378
6365
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6379
|
-
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-
|
|
6366
|
+
const { InjectedEvmWalletProvider } = await import('./injected-evm-wallet-provider-B3Mtkdnu.mjs');
|
|
6380
6367
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6381
6368
|
break;
|
|
6382
6369
|
}
|
|
@@ -6401,7 +6388,7 @@ async function getAuthProvider(config) {
|
|
|
6401
6388
|
break;
|
|
6402
6389
|
case "guest":
|
|
6403
6390
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6404
|
-
currentAuthProvider = new (await import('./guest-auth-provider-
|
|
6391
|
+
currentAuthProvider = new (await import('./guest-auth-provider-CUo6sgop.mjs')).GuestAuthProvider();
|
|
6405
6392
|
break;
|
|
6406
6393
|
}
|
|
6407
6394
|
if (!currentAuthProvider) {
|
|
@@ -6463,7 +6450,7 @@ async function signInAnonymously() {
|
|
|
6463
6450
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6464
6451
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6465
6452
|
// so bundle-splitting can see it.
|
|
6466
|
-
const provider = new (await import('./guest-auth-provider-
|
|
6453
|
+
const provider = new (await import('./guest-auth-provider-CUo6sgop.mjs')).GuestAuthProvider();
|
|
6467
6454
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6468
6455
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6469
6456
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6634,7 +6621,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6634
6621
|
if (!sharedWalletReady) {
|
|
6635
6622
|
sharedWalletReady = (async () => {
|
|
6636
6623
|
await getConfig();
|
|
6637
|
-
await import('./injected-wallet-provider-
|
|
6624
|
+
await import('./injected-wallet-provider-DR8xVudg.mjs');
|
|
6638
6625
|
})().catch((error) => {
|
|
6639
6626
|
sharedWalletReady = null;
|
|
6640
6627
|
throw error;
|
|
@@ -6737,7 +6724,7 @@ async function loginWithWallet(options) {
|
|
|
6737
6724
|
await ensureSharedWalletLoginReady();
|
|
6738
6725
|
else
|
|
6739
6726
|
await ensureWalletLoginReady();
|
|
6740
|
-
const { InjectedWalletProvider } = await import('./injected-wallet-provider-
|
|
6727
|
+
const { InjectedWalletProvider } = await import('./injected-wallet-provider-DR8xVudg.mjs');
|
|
6741
6728
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6742
6729
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6743
6730
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -7743,12 +7730,14 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7743
7730
|
: undefined;
|
|
7744
7731
|
return {
|
|
7745
7732
|
email: trimmed, frameUrl, signerOrigin,
|
|
7746
|
-
run(iframe,
|
|
7733
|
+
run(iframe, _signal) {
|
|
7747
7734
|
if (!ceremonyId) {
|
|
7748
7735
|
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7749
7736
|
}
|
|
7750
7737
|
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId };
|
|
7751
|
-
|
|
7738
|
+
// BSA-2026-004: the login code is typed only in /wallet/turnkey/otp-frame.
|
|
7739
|
+
// The scoped signer URL is for post-login signing, not OTP entry.
|
|
7740
|
+
return runOtpFrame(run);
|
|
7752
7741
|
},
|
|
7753
7742
|
};
|
|
7754
7743
|
}
|
|
@@ -7853,104 +7842,6 @@ function runOtpFrame(run) {
|
|
|
7853
7842
|
run.iframe.src = url;
|
|
7854
7843
|
});
|
|
7855
7844
|
}
|
|
7856
|
-
// The scoped document owns both OTP and signing. Adopt only its sanitized app
|
|
7857
|
-
// session, acknowledge with a narrow grant, then wait for wallet readiness.
|
|
7858
|
-
function runScopedOtpFrame(run, frameUrl, signal) {
|
|
7859
|
-
const assertCurrent = walletLoginGuard(signal);
|
|
7860
|
-
const beforeStore = getActiveSessionManager().captureSessionEstablishment();
|
|
7861
|
-
return new Promise((resolve, reject) => {
|
|
7862
|
-
let settled = false, adopting = false, started = false;
|
|
7863
|
-
let user = null;
|
|
7864
|
-
let adoptedToken = '';
|
|
7865
|
-
let context = null;
|
|
7866
|
-
const post = (data) => { var _a; return (_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(data, run.signerOrigin); };
|
|
7867
|
-
const cleanup = () => {
|
|
7868
|
-
settled = true;
|
|
7869
|
-
clearTimeout(timer);
|
|
7870
|
-
window.removeEventListener('message', onMessage);
|
|
7871
|
-
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', abort);
|
|
7872
|
-
};
|
|
7873
|
-
const fail = (error) => { cleanup(); reject(error instanceof Error ? error : new Error(String(error))); };
|
|
7874
|
-
const abort = () => { post({ type: 'bounded:otp:cancel' }); fail(new Error('wallet_login_cancelled')); };
|
|
7875
|
-
const finish = (ready, reason, expiresAt) => {
|
|
7876
|
-
if (!user || !context || getActiveSessionManager().getIdToken() !== adoptedToken) {
|
|
7877
|
-
fail(new Error('wallet_session_changed'));
|
|
7878
|
-
return;
|
|
7879
|
-
}
|
|
7880
|
-
setWalletSessionState(context.key, ready && Number.isFinite(expiresAt) && expiresAt > Date.now()
|
|
7881
|
-
? { status: 'ready', expiresAt: expiresAt } : { status: 'verification-required', reason });
|
|
7882
|
-
cleanup();
|
|
7883
|
-
resolve(user);
|
|
7884
|
-
};
|
|
7885
|
-
const onMessage = async (event) => {
|
|
7886
|
-
if (settled || event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7887
|
-
return;
|
|
7888
|
-
const d = event.data;
|
|
7889
|
-
if (!d || typeof d !== 'object')
|
|
7890
|
-
return;
|
|
7891
|
-
if (d.type === 'bounded:otp:ready' && !started) {
|
|
7892
|
-
started = true;
|
|
7893
|
-
post({ type: 'bounded:otp:start', email: run.email, ceremonyId: run.ceremonyId,
|
|
7894
|
-
otpId: run.otpId, otpEncryptionTargetBundle: run.otpEncryptionTargetBundle });
|
|
7895
|
-
}
|
|
7896
|
-
if (d.type === 'bounded:otp:wallet-ready' && user) {
|
|
7897
|
-
finish(d.ok === true, typeof d.error === 'string' ? d.error : 'wallet_session_unavailable', d.expiresAt);
|
|
7898
|
-
}
|
|
7899
|
-
if (d.type !== 'bounded:otp:result' || adopting)
|
|
7900
|
-
return;
|
|
7901
|
-
if (d.ok !== true || !d.session || typeof d.session.idToken !== 'string') {
|
|
7902
|
-
fail(new Error(String(d.error || 'wallet_login_failed')));
|
|
7903
|
-
return;
|
|
7904
|
-
}
|
|
7905
|
-
adopting = true;
|
|
7906
|
-
try {
|
|
7907
|
-
assertCurrent();
|
|
7908
|
-
const token = d.session.idToken;
|
|
7909
|
-
const claims = JSON.parse(getPlatform().atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
|
|
7910
|
-
context = walletContextFromClaims(claims, run.base, run.appId, window.location.origin);
|
|
7911
|
-
if (context.scope !== 'app')
|
|
7912
|
-
throw new Error('wallet_scope_mismatch');
|
|
7913
|
-
user = await establishInlineSession(d.session, () => { assertCurrent(); if (settled)
|
|
7914
|
-
throw new Error('wallet_login_cancelled'); }, beforeStore);
|
|
7915
|
-
adoptedToken = token;
|
|
7916
|
-
bindWarmSignerFrame(run.iframe, context.key);
|
|
7917
|
-
if (settled || (signal === null || signal === void 0 ? void 0 : signal.aborted) || getActiveSessionManager().getIdToken() !== token)
|
|
7918
|
-
throw new Error('wallet_session_changed');
|
|
7919
|
-
setWalletSessionState(context.key, { status: 'verification-required', reason: 'wallet_session_pending' });
|
|
7920
|
-
const authorization = await requestTurnkeyActionAuthorization({
|
|
7921
|
-
baseUrl: run.base, idToken: token, action: 'createWallet', fetchImpl: (u, i) => fetch(u, i),
|
|
7922
|
-
});
|
|
7923
|
-
if (settled || getActiveSessionManager().getIdToken() !== token)
|
|
7924
|
-
throw new Error('wallet_session_changed');
|
|
7925
|
-
post({ type: 'bounded:otp:authorization', authorization });
|
|
7926
|
-
}
|
|
7927
|
-
catch (error) {
|
|
7928
|
-
if (user && adoptedToken) {
|
|
7929
|
-
post({ type: 'bounded:otp:authorization', authorization: '' });
|
|
7930
|
-
finish(false, 'wallet_session_unavailable');
|
|
7931
|
-
}
|
|
7932
|
-
else
|
|
7933
|
-
fail(error);
|
|
7934
|
-
}
|
|
7935
|
-
};
|
|
7936
|
-
const timer = setTimeout(() => {
|
|
7937
|
-
if (user)
|
|
7938
|
-
finish(false, 'wallet_session_timeout');
|
|
7939
|
-
else
|
|
7940
|
-
fail(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7941
|
-
}, 180000);
|
|
7942
|
-
window.addEventListener('message', onMessage);
|
|
7943
|
-
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', abort, { once: true });
|
|
7944
|
-
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
7945
|
-
abort();
|
|
7946
|
-
return;
|
|
7947
|
-
}
|
|
7948
|
-
if (run.iframe.src !== frameUrl)
|
|
7949
|
-
run.iframe.src = frameUrl;
|
|
7950
|
-
// Readiness can predate listener installation when reusing a mounted frame.
|
|
7951
|
-
post({ type: 'bounded:otp:hello' });
|
|
7952
|
-
});
|
|
7953
|
-
}
|
|
7954
7845
|
|
|
7955
7846
|
// bounded-login-widget.ts - the UNIFIED Bounded login surface: one in-app card
|
|
7956
7847
|
// (Shadow-DOM modal from bounded-widget-modal.ts, Bounded look + motion) that folds
|
|
@@ -8490,24 +8381,10 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8490
8381
|
settleAttempt(attempt);
|
|
8491
8382
|
return;
|
|
8492
8383
|
}
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
}
|
|
8498
|
-
const controller = new AbortController();
|
|
8499
|
-
abortScopedLogin = () => controller.abort();
|
|
8500
|
-
// Mount once in the shared modal. Moving a live iframe would discard
|
|
8501
|
-
// the trusted document holding the private in-memory session key.
|
|
8502
|
-
detachIframe(m);
|
|
8503
|
-
const frame = ensureIframe(m, handle.frameUrl, handle.signerOrigin, `login:${attempt}`);
|
|
8504
|
-
setPanelHeight(m, 380);
|
|
8505
|
-
const completion = handle.run(frame, controller.signal);
|
|
8506
|
-
m.chain = completion.then(() => undefined, () => undefined);
|
|
8507
|
-
const user = await completion;
|
|
8508
|
-
abortScopedLogin = null;
|
|
8509
|
-
settleAttempt(attempt);
|
|
8510
|
-
succeed(user);
|
|
8384
|
+
// BSA-2026-004: collect the code in the Bounded OTP frame, never in
|
|
8385
|
+
// this tenant DOM and never in the unframeable signer document.
|
|
8386
|
+
if (settleAttempt(attempt))
|
|
8387
|
+
swap(renderOtpFrame(handle));
|
|
8511
8388
|
})
|
|
8512
8389
|
.catch((err) => {
|
|
8513
8390
|
if (!settleAttempt(attempt))
|
|
@@ -9363,9 +9240,26 @@ async function getReviewCapability(appId, runId, gateId, options) {
|
|
|
9363
9240
|
body: { expectedPreviewUrl: options.expectedPreviewUrl },
|
|
9364
9241
|
});
|
|
9365
9242
|
}
|
|
9243
|
+
/**
|
|
9244
|
+
* Add funds to a run parked for funding. Accounts billed through payer shards refuse it with
|
|
9245
|
+
* `topup_unavailable_payer_shard` (in `details.upstreamCode`): a parked run there holds no money, so the payer adds
|
|
9246
|
+
* credits and submits the build again.
|
|
9247
|
+
*/
|
|
9366
9248
|
async function topup(appId, runId, options) {
|
|
9367
9249
|
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/topup`, { method: 'POST', body: options });
|
|
9368
9250
|
}
|
|
9251
|
+
/** An image build's verified images and its asset's current release. */
|
|
9252
|
+
async function media(appId, runId) {
|
|
9253
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media`);
|
|
9254
|
+
}
|
|
9255
|
+
/** A short-lived signed URL for one image of an image build (usable directly as an image source). */
|
|
9256
|
+
async function mediaDownloadUrl(appId, runId, artifactId) {
|
|
9257
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media-download-url`, { method: 'POST', body: { artifactId } });
|
|
9258
|
+
}
|
|
9259
|
+
/** Roll back the release an image build published: its asset returns to the release it replaced. */
|
|
9260
|
+
async function rollbackMedia(appId, runId, options = {}) {
|
|
9261
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media-rollback`, { method: 'POST', body: options.note ? { note: options.note } : {} });
|
|
9262
|
+
}
|
|
9369
9263
|
async function list$1(appId, limit = 20) {
|
|
9370
9264
|
const requestedLimit = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 20;
|
|
9371
9265
|
return requestDevApi(`${appPath(appId)}?limit=${requestedLimit}`);
|
|
@@ -9397,13 +9291,15 @@ const RUN_STATES = [
|
|
|
9397
9291
|
...NON_TERMINAL_STATES,
|
|
9398
9292
|
...TERMINAL_STATES,
|
|
9399
9293
|
];
|
|
9400
|
-
const PARK_REASONS = ['gate', 'funding'];
|
|
9294
|
+
const PARK_REASONS = ['gate', 'funding', 'preview', 'design'];
|
|
9401
9295
|
const FAILURE_REASONS = [
|
|
9402
9296
|
'admission_rejected',
|
|
9403
9297
|
'dispatch_timeout',
|
|
9404
9298
|
'auth_revoked',
|
|
9405
9299
|
'owner_changed',
|
|
9406
9300
|
'policy_changed',
|
|
9301
|
+
'target_retired',
|
|
9302
|
+
'promotion_rejected',
|
|
9407
9303
|
'quarantine_forced',
|
|
9408
9304
|
'bind_failed',
|
|
9409
9305
|
'internal_error',
|
|
@@ -9661,6 +9557,345 @@ function useBuildRun(appId, runId, options) {
|
|
|
9661
9557
|
return { run, events, loading, error };
|
|
9662
9558
|
}
|
|
9663
9559
|
|
|
9560
|
+
const TERMINAL = new Set(['promoted', 'failed', 'canceled', 'rejected', 'expired', 'rebase_required', 'reported']);
|
|
9561
|
+
const KEY = { type: 'string', minLength: 1, maxLength: 256, description: 'A key unique to this intent; retrying with the same key never repeats the action.' };
|
|
9562
|
+
const RUN_ID = { type: 'string', minLength: 1, maxLength: 128, description: 'The build run id media_create or media_edit returned.' };
|
|
9563
|
+
const REGION = {
|
|
9564
|
+
type: 'object',
|
|
9565
|
+
additionalProperties: false,
|
|
9566
|
+
required: ['x', 'y', 'width', 'height'],
|
|
9567
|
+
properties: {
|
|
9568
|
+
x: { type: 'integer', minimum: 0 },
|
|
9569
|
+
y: { type: 'integer', minimum: 0 },
|
|
9570
|
+
width: { type: 'integer', minimum: 1 },
|
|
9571
|
+
height: { type: 'integer', minimum: 1 },
|
|
9572
|
+
},
|
|
9573
|
+
description: 'A rectangle in whole pixels of the image; nothing outside it changes.',
|
|
9574
|
+
};
|
|
9575
|
+
const SPEC = { type: 'object', description: 'The deliverable spec (image: size, quality, format, background, candidates, model, references, region; video: durationSeconds, resolution, aspectRatio, audio, images, scenes, replaceScenes, captions). See the builds docs.' };
|
|
9576
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9577
|
+
const text = (value, max) => typeof value === 'string' && value.trim().length > 0 && value.length <= max ? value : undefined;
|
|
9578
|
+
const refuse = (code, message, next = ['media_inspect'], retryable = false) => ({ ok: false, code, message, retryable, next });
|
|
9579
|
+
function region(value) {
|
|
9580
|
+
if (!isRecord(value))
|
|
9581
|
+
return undefined;
|
|
9582
|
+
const { x, y, width, height } = value;
|
|
9583
|
+
return [x, y, width, height].every(Number.isSafeInteger) && x >= 0 && y >= 0
|
|
9584
|
+
&& width >= 1 && height >= 1
|
|
9585
|
+
? { x: x, y: y, width: width, height: height }
|
|
9586
|
+
: undefined;
|
|
9587
|
+
}
|
|
9588
|
+
/** A thrown API error, as the tool result the model reads. The developer API answers with a coarse public code and
|
|
9589
|
+
* relays Build's own reason (base_moved, candidate_unknown, media_storage_quota, ...) as details.upstreamCode. */
|
|
9590
|
+
function failure(error) {
|
|
9591
|
+
var _a;
|
|
9592
|
+
const apiError = error;
|
|
9593
|
+
const upstream = (_a = apiError === null || apiError === void 0 ? void 0 : apiError.details) === null || _a === void 0 ? void 0 : _a.upstreamCode;
|
|
9594
|
+
return refuse(typeof upstream === 'string' && /^[a-z][a-z0-9_]{0,79}$/.test(upstream) && upstream !== 'unknown_upstream_error'
|
|
9595
|
+
? upstream
|
|
9596
|
+
: typeof (apiError === null || apiError === void 0 ? void 0 : apiError.code) === 'string' ? apiError.code : 'request_failed', typeof (apiError === null || apiError === void 0 ? void 0 : apiError.message) === 'string' ? apiError.message : 'The request failed.', ['media_inspect'], (apiError === null || apiError === void 0 ? void 0 : apiError.retryable) === true);
|
|
9597
|
+
}
|
|
9598
|
+
/** What a run lets an agent do next. */
|
|
9599
|
+
function nextFor(run) {
|
|
9600
|
+
var _a;
|
|
9601
|
+
if ((_a = run.design) === null || _a === void 0 ? void 0 : _a.gate)
|
|
9602
|
+
return ['media_select', 'media_revise', 'media_export'];
|
|
9603
|
+
if (run.state === 'promoted')
|
|
9604
|
+
return ['media_export', 'media_edit', 'media_create'];
|
|
9605
|
+
if (run.state === 'parked' && run.parkReason === 'gate')
|
|
9606
|
+
return ['media_propose', 'media_export'];
|
|
9607
|
+
if (TERMINAL.has(run.state))
|
|
9608
|
+
return ['media_create'];
|
|
9609
|
+
return ['media_inspect'];
|
|
9610
|
+
}
|
|
9611
|
+
function candidateView(candidate) {
|
|
9612
|
+
return Object.assign(Object.assign(Object.assign(Object.assign({ id: candidate.id }, (candidate.url ? { url: candidate.url } : {})), { mimeType: candidate.mimeType, width: candidate.width, height: candidate.height }), (candidate.durationMs !== undefined ? { durationMs: candidate.durationMs } : {})), (candidate.scenes ? { scenes: candidate.scenes } : {}));
|
|
9613
|
+
}
|
|
9614
|
+
function mediaAgentTools(appId, client = {
|
|
9615
|
+
submit: submit,
|
|
9616
|
+
get: get,
|
|
9617
|
+
decideGate: decideGate,
|
|
9618
|
+
media: media,
|
|
9619
|
+
mediaDownloadUrl: mediaDownloadUrl,
|
|
9620
|
+
}) {
|
|
9621
|
+
const run = async (runId) => (await client.get(appId, runId)).run;
|
|
9622
|
+
const submit = async (options) => {
|
|
9623
|
+
try {
|
|
9624
|
+
const submitted = await client.submit(appId, options);
|
|
9625
|
+
return { ok: true, data: { runId: submitted.runId, status: submitted.status }, next: ['media_inspect'] };
|
|
9626
|
+
}
|
|
9627
|
+
catch (error) {
|
|
9628
|
+
return failure(error);
|
|
9629
|
+
}
|
|
9630
|
+
};
|
|
9631
|
+
/** The open design review of a run, or the refusal that explains why there is none. */
|
|
9632
|
+
const openReview = async (input) => {
|
|
9633
|
+
var _a;
|
|
9634
|
+
const runId = text(input.runId, 128);
|
|
9635
|
+
if (!runId)
|
|
9636
|
+
return refuse('input_invalid', 'runId is required.');
|
|
9637
|
+
let current;
|
|
9638
|
+
try {
|
|
9639
|
+
current = await run(runId);
|
|
9640
|
+
}
|
|
9641
|
+
catch (error) {
|
|
9642
|
+
return failure(error);
|
|
9643
|
+
}
|
|
9644
|
+
const gate = (_a = current.design) === null || _a === void 0 ? void 0 : _a.gate;
|
|
9645
|
+
if (!gate) {
|
|
9646
|
+
return refuse('no_open_review', `Run ${runId} is ${current.state}${current.parkReason ? ` (${current.parkReason})` : ''}; no design round is waiting for a decision.`, nextFor(current));
|
|
9647
|
+
}
|
|
9648
|
+
return { run: current, gateId: gate.gateId };
|
|
9649
|
+
};
|
|
9650
|
+
const candidateOf = (current, id) => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = current.design) === null || _a === void 0 ? void 0 : _a.rounds) === null || _b === void 0 ? void 0 : _b.find((round) => { var _a; return round.round === ((_a = current.design) === null || _a === void 0 ? void 0 : _a.round); })) === null || _c === void 0 ? void 0 : _c.candidates) === null || _d === void 0 ? void 0 : _d.find((candidate) => candidate.id === id); };
|
|
9651
|
+
return [
|
|
9652
|
+
{
|
|
9653
|
+
name: 'media_create',
|
|
9654
|
+
description: 'Start an image or video build for this app. Pass forkOf to start a new asset from a retained release. Returns the run id; the first round of candidates follows (read it with media_inspect).',
|
|
9655
|
+
inputSchema: {
|
|
9656
|
+
type: 'object',
|
|
9657
|
+
additionalProperties: false,
|
|
9658
|
+
required: ['kind', 'prompt', 'idempotencyKey'],
|
|
9659
|
+
properties: {
|
|
9660
|
+
kind: { type: 'string', enum: ['image', 'video'] },
|
|
9661
|
+
prompt: { type: 'string', minLength: 1, maxLength: 4000, description: 'What to make.' },
|
|
9662
|
+
spec: SPEC,
|
|
9663
|
+
forkOf: {
|
|
9664
|
+
type: 'object',
|
|
9665
|
+
additionalProperties: false,
|
|
9666
|
+
required: ['assetId', 'releaseId'],
|
|
9667
|
+
properties: { assetId: { type: 'string' }, releaseId: { type: 'string' } },
|
|
9668
|
+
description: 'A retained release of this app to start from.',
|
|
9669
|
+
},
|
|
9670
|
+
idempotencyKey: KEY,
|
|
9671
|
+
},
|
|
9672
|
+
},
|
|
9673
|
+
async execute(raw) {
|
|
9674
|
+
const input = isRecord(raw) ? raw : {};
|
|
9675
|
+
const prompt = text(input.prompt, 4000);
|
|
9676
|
+
const key = text(input.idempotencyKey, 256);
|
|
9677
|
+
if ((input.kind !== 'image' && input.kind !== 'video') || !prompt || !key) {
|
|
9678
|
+
return refuse('input_invalid', 'kind (image or video), prompt and idempotencyKey are required.', []);
|
|
9679
|
+
}
|
|
9680
|
+
return submit({
|
|
9681
|
+
operation: 'create',
|
|
9682
|
+
prompt,
|
|
9683
|
+
deliverable: Object.assign(Object.assign({ kind: input.kind }, (isRecord(input.spec) ? { spec: input.spec } : {})), (isRecord(input.forkOf) ? { forkOf: input.forkOf } : {})),
|
|
9684
|
+
idempotencyKey: key,
|
|
9685
|
+
});
|
|
9686
|
+
},
|
|
9687
|
+
},
|
|
9688
|
+
{
|
|
9689
|
+
name: 'media_edit',
|
|
9690
|
+
description: 'Edit a released image or video. Name the asset and the release you edit (a newer release refuses the edit as base_moved). An image spec may carry region to change only a rectangle; a video spec may carry replaceScenes or captions, and a captions-only edit makes no generation call.',
|
|
9691
|
+
inputSchema: {
|
|
9692
|
+
type: 'object',
|
|
9693
|
+
additionalProperties: false,
|
|
9694
|
+
required: ['kind', 'assetId', 'expectedReleaseId', 'prompt', 'idempotencyKey'],
|
|
9695
|
+
properties: {
|
|
9696
|
+
kind: { type: 'string', enum: ['image', 'video'] },
|
|
9697
|
+
assetId: { type: 'string' },
|
|
9698
|
+
expectedReleaseId: { type: 'string' },
|
|
9699
|
+
prompt: { type: 'string', minLength: 1, maxLength: 4000, description: 'The change to make.' },
|
|
9700
|
+
spec: SPEC,
|
|
9701
|
+
idempotencyKey: KEY,
|
|
9702
|
+
},
|
|
9703
|
+
},
|
|
9704
|
+
async execute(raw) {
|
|
9705
|
+
const input = isRecord(raw) ? raw : {};
|
|
9706
|
+
const prompt = text(input.prompt, 4000);
|
|
9707
|
+
const key = text(input.idempotencyKey, 256);
|
|
9708
|
+
const assetId = text(input.assetId, 128);
|
|
9709
|
+
const expectedReleaseId = text(input.expectedReleaseId, 128);
|
|
9710
|
+
if ((input.kind !== 'image' && input.kind !== 'video') || !prompt || !key || !assetId || !expectedReleaseId) {
|
|
9711
|
+
return refuse('input_invalid', 'kind, assetId, expectedReleaseId, prompt and idempotencyKey are required.', []);
|
|
9712
|
+
}
|
|
9713
|
+
return submit({
|
|
9714
|
+
operation: 'edit',
|
|
9715
|
+
prompt,
|
|
9716
|
+
deliverable: Object.assign({ kind: input.kind, assetId,
|
|
9717
|
+
expectedReleaseId }, (isRecord(input.spec) ? { spec: input.spec } : {})),
|
|
9718
|
+
idempotencyKey: key,
|
|
9719
|
+
});
|
|
9720
|
+
},
|
|
9721
|
+
},
|
|
9722
|
+
{
|
|
9723
|
+
name: 'media_inspect',
|
|
9724
|
+
description: 'Read a media build: its state, the candidates of the round under review (with their scenes), the decision it waits on, and its release once published.',
|
|
9725
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['runId'], properties: { runId: RUN_ID } },
|
|
9726
|
+
async execute(raw) {
|
|
9727
|
+
var _a, _b, _c, _d, _e;
|
|
9728
|
+
const runId = text(isRecord(raw) ? raw.runId : undefined, 128);
|
|
9729
|
+
if (!runId)
|
|
9730
|
+
return refuse('input_invalid', 'runId is required.', []);
|
|
9731
|
+
try {
|
|
9732
|
+
const current = await run(runId);
|
|
9733
|
+
const round = (_b = (_a = current.design) === null || _a === void 0 ? void 0 : _a.rounds) === null || _b === void 0 ? void 0 : _b.find((entry) => { var _a; return entry.round === ((_a = current.design) === null || _a === void 0 ? void 0 : _a.round); });
|
|
9734
|
+
const media = current.state === 'promoted' || current.media ? await client.media(appId, runId) : undefined;
|
|
9735
|
+
return {
|
|
9736
|
+
ok: true,
|
|
9737
|
+
data: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ runId, state: current.state }, (current.parkReason ? { parkReason: current.parkReason } : {})), (current.failureReason ? { failureReason: current.failureReason } : {})), (current.failureDetail ? { failureDetail: current.failureDetail } : {})), (round
|
|
9738
|
+
? Object.assign({ round: round.round, maxRounds: (_c = current.design) === null || _c === void 0 ? void 0 : _c.maxRounds, candidates: ((_d = round.candidates) !== null && _d !== void 0 ? _d : []).map(candidateView) }, (round.revisionFailed ? { revisionFailed: true } : {})) : {})), (((_e = current.design) === null || _e === void 0 ? void 0 : _e.gate) ? { review: { gateId: current.design.gate.gateId, allowedDecisions: current.design.gate.allowedDecisions } } : {})), (current.state === 'parked' && current.parkReason === 'funding'
|
|
9739
|
+
? { waitingFor: 'funding: the payer adds funds and, where top-up is unavailable (topup_unavailable_payer_shard), submits the build again; an agent cannot' }
|
|
9740
|
+
: {})), (media ? { media: media.media, asset: media.asset } : {})),
|
|
9741
|
+
next: nextFor(current),
|
|
9742
|
+
};
|
|
9743
|
+
}
|
|
9744
|
+
catch (error) {
|
|
9745
|
+
return failure(error);
|
|
9746
|
+
}
|
|
9747
|
+
},
|
|
9748
|
+
},
|
|
9749
|
+
{
|
|
9750
|
+
name: 'media_revise',
|
|
9751
|
+
description: 'Ask for another round of the design under review. Name the candidate to revise; for an image, region limits the change to a rectangle of that candidate (PNG only); for a multi-scene video, sceneIds regenerates only those scenes and keeps every other scene byte for byte.',
|
|
9752
|
+
inputSchema: {
|
|
9753
|
+
type: 'object',
|
|
9754
|
+
additionalProperties: false,
|
|
9755
|
+
required: ['runId', 'feedback', 'idempotencyKey'],
|
|
9756
|
+
properties: {
|
|
9757
|
+
runId: RUN_ID,
|
|
9758
|
+
feedback: { type: 'string', minLength: 1, maxLength: 4000, description: 'What to change.' },
|
|
9759
|
+
candidateId: { type: 'string', description: 'The candidate to revise; without it the whole round is redone from the feedback.' },
|
|
9760
|
+
sceneIds: { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 6 },
|
|
9761
|
+
region: REGION,
|
|
9762
|
+
idempotencyKey: KEY,
|
|
9763
|
+
},
|
|
9764
|
+
},
|
|
9765
|
+
async execute(raw) {
|
|
9766
|
+
var _a, _b;
|
|
9767
|
+
const input = isRecord(raw) ? raw : {};
|
|
9768
|
+
const feedback = text(input.feedback, 4000);
|
|
9769
|
+
const key = text(input.idempotencyKey, 256);
|
|
9770
|
+
if (!feedback || !key)
|
|
9771
|
+
return refuse('input_invalid', 'runId, feedback and idempotencyKey are required.', []);
|
|
9772
|
+
const review = await openReview(input);
|
|
9773
|
+
if ('ok' in review)
|
|
9774
|
+
return review;
|
|
9775
|
+
if (!((_b = (_a = review.run.design) === null || _a === void 0 ? void 0 : _a.gate) === null || _b === void 0 ? void 0 : _b.allowedDecisions.includes('request_changes'))) {
|
|
9776
|
+
return refuse('decision_not_allowed', 'This round takes no revision (it may be the last one): select a candidate instead.', ['media_select']);
|
|
9777
|
+
}
|
|
9778
|
+
const candidate = input.candidateId === undefined ? undefined : candidateOf(review.run, input.candidateId);
|
|
9779
|
+
if (input.candidateId !== undefined && !candidate) {
|
|
9780
|
+
return refuse('candidate_unknown', `No candidate ${String(input.candidateId)} in the round under review.`, ['media_inspect']);
|
|
9781
|
+
}
|
|
9782
|
+
const sceneIds = Array.isArray(input.sceneIds) ? input.sceneIds.filter((id) => typeof id === 'string') : undefined;
|
|
9783
|
+
if (sceneIds && (!(candidate === null || candidate === void 0 ? void 0 : candidate.scenes) || !sceneIds.every((id) => candidate.scenes.some((scene) => scene.id === id)))) {
|
|
9784
|
+
return refuse('scenes_unknown', 'sceneIds must name scenes of the multi-scene candidate being revised (candidateId).', ['media_inspect']);
|
|
9785
|
+
}
|
|
9786
|
+
const area = input.region === undefined ? undefined : region(input.region);
|
|
9787
|
+
if (input.region !== undefined
|
|
9788
|
+
&& (!area || (candidate === null || candidate === void 0 ? void 0 : candidate.mimeType) !== 'image/png' || area.x + area.width > candidate.width || area.y + area.height > candidate.height)) {
|
|
9789
|
+
return refuse('region_invalid', 'region must lie inside the PNG candidate being revised (candidateId).', ['media_inspect']);
|
|
9790
|
+
}
|
|
9791
|
+
try {
|
|
9792
|
+
const decided = await client.decideGate(appId, review.run.runId, review.gateId, Object.assign(Object.assign(Object.assign(Object.assign({ decision: 'request_changes', feedback: { text: feedback } }, (candidate ? { selectedArtifactId: candidate.id } : {})), (sceneIds ? { sceneIds } : {})), (area ? { region: area } : {})), { idempotencyKey: key }));
|
|
9793
|
+
return { ok: true, data: { runId: review.run.runId, state: decided.state }, next: ['media_inspect'] };
|
|
9794
|
+
}
|
|
9795
|
+
catch (error) {
|
|
9796
|
+
return failure(error);
|
|
9797
|
+
}
|
|
9798
|
+
},
|
|
9799
|
+
},
|
|
9800
|
+
{
|
|
9801
|
+
name: 'media_select',
|
|
9802
|
+
description: 'Choose a candidate of the round under review. The chosen candidate is what the build releases, through the app\'s landing policy.',
|
|
9803
|
+
inputSchema: {
|
|
9804
|
+
type: 'object',
|
|
9805
|
+
additionalProperties: false,
|
|
9806
|
+
required: ['runId', 'candidateId', 'idempotencyKey'],
|
|
9807
|
+
properties: { runId: RUN_ID, candidateId: { type: 'string' }, idempotencyKey: KEY },
|
|
9808
|
+
},
|
|
9809
|
+
async execute(raw) {
|
|
9810
|
+
const input = isRecord(raw) ? raw : {};
|
|
9811
|
+
const key = text(input.idempotencyKey, 256);
|
|
9812
|
+
if (!key)
|
|
9813
|
+
return refuse('input_invalid', 'runId, candidateId and idempotencyKey are required.', []);
|
|
9814
|
+
const review = await openReview(input);
|
|
9815
|
+
if ('ok' in review)
|
|
9816
|
+
return review;
|
|
9817
|
+
const candidate = candidateOf(review.run, input.candidateId);
|
|
9818
|
+
if (!candidate)
|
|
9819
|
+
return refuse('candidate_unknown', `No candidate ${String(input.candidateId)} in the round under review.`, ['media_inspect']);
|
|
9820
|
+
try {
|
|
9821
|
+
const decided = await client.decideGate(appId, review.run.runId, review.gateId, {
|
|
9822
|
+
decision: 'approve',
|
|
9823
|
+
selectedArtifactId: candidate.id,
|
|
9824
|
+
idempotencyKey: key,
|
|
9825
|
+
});
|
|
9826
|
+
return { ok: true, data: { runId: review.run.runId, state: decided.state, selectedArtifactId: candidate.id }, next: ['media_propose', 'media_inspect'] };
|
|
9827
|
+
}
|
|
9828
|
+
catch (error) {
|
|
9829
|
+
return failure(error);
|
|
9830
|
+
}
|
|
9831
|
+
},
|
|
9832
|
+
},
|
|
9833
|
+
{
|
|
9834
|
+
name: 'media_export',
|
|
9835
|
+
description: 'A short-lived signed URL for one verified image or video of a build (a published release, or a candidate the build deposited), with its digest.',
|
|
9836
|
+
inputSchema: {
|
|
9837
|
+
type: 'object',
|
|
9838
|
+
additionalProperties: false,
|
|
9839
|
+
required: ['runId', 'artifactId'],
|
|
9840
|
+
properties: { runId: RUN_ID, artifactId: { type: 'string' } },
|
|
9841
|
+
},
|
|
9842
|
+
async execute(raw) {
|
|
9843
|
+
var _a, _b;
|
|
9844
|
+
const input = isRecord(raw) ? raw : {};
|
|
9845
|
+
const runId = text(input.runId, 128);
|
|
9846
|
+
const artifactId = text(input.artifactId, 64);
|
|
9847
|
+
if (!runId || !artifactId)
|
|
9848
|
+
return refuse('input_invalid', 'runId and artifactId are required.', []);
|
|
9849
|
+
try {
|
|
9850
|
+
const view = await client.media(appId, runId);
|
|
9851
|
+
const artifact = (_b = (_a = view.media) === null || _a === void 0 ? void 0 : _a.artifacts) === null || _b === void 0 ? void 0 : _b.find((entry) => entry.id === artifactId);
|
|
9852
|
+
if (!artifact) {
|
|
9853
|
+
return refuse('artifact_unavailable', `Run ${runId} has no verified artifact ${artifactId} yet; a candidate under review is exported from its round's url (media_inspect).`, ['media_inspect']);
|
|
9854
|
+
}
|
|
9855
|
+
const signed = await client.mediaDownloadUrl(appId, runId, artifactId);
|
|
9856
|
+
return {
|
|
9857
|
+
ok: true,
|
|
9858
|
+
data: { runId, artifactId, url: signed.url, expiresAtMs: signed.expiresAtMs, sha256: artifact.sha256, mimeType: artifact.mimeType, bytes: artifact.bytes },
|
|
9859
|
+
next: ['media_inspect'],
|
|
9860
|
+
};
|
|
9861
|
+
}
|
|
9862
|
+
catch (error) {
|
|
9863
|
+
return failure(error);
|
|
9864
|
+
}
|
|
9865
|
+
},
|
|
9866
|
+
},
|
|
9867
|
+
{
|
|
9868
|
+
name: 'media_propose',
|
|
9869
|
+
description: 'Put a build\'s chosen candidate forward for publication and report where it stands. Publishing is decided by the app\'s landing policy (the owner approves the release, or the policy lands it); this tool never approves it.',
|
|
9870
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['runId'], properties: { runId: RUN_ID } },
|
|
9871
|
+
async execute(raw) {
|
|
9872
|
+
var _a;
|
|
9873
|
+
const runId = text(isRecord(raw) ? raw.runId : undefined, 128);
|
|
9874
|
+
if (!runId)
|
|
9875
|
+
return refuse('input_invalid', 'runId is required.', []);
|
|
9876
|
+
try {
|
|
9877
|
+
const current = await run(runId);
|
|
9878
|
+
if (current.state === 'promoted') {
|
|
9879
|
+
const view = await client.media(appId, runId);
|
|
9880
|
+
return { ok: true, data: { runId, state: 'published', release: view.asset.currentRelease }, next: nextFor(current) };
|
|
9881
|
+
}
|
|
9882
|
+
if (current.state === 'parked' && current.parkReason === 'gate') {
|
|
9883
|
+
const gate = current.gates.find((entry) => !entry.decided);
|
|
9884
|
+
return { ok: true, data: Object.assign(Object.assign({ runId, state: 'awaiting_publication' }, (gate ? { gateId: gate.gateId } : {})), { decidedBy: 'the app owner, under the landing policy' }), next: ['media_inspect'] };
|
|
9885
|
+
}
|
|
9886
|
+
if ((_a = current.design) === null || _a === void 0 ? void 0 : _a.gate) {
|
|
9887
|
+
return refuse('not_selected', 'Choose a candidate first (media_select); only a chosen candidate can be published.', ['media_select', 'media_revise']);
|
|
9888
|
+
}
|
|
9889
|
+
return refuse('not_proposable', `Run ${runId} is ${current.state}${current.parkReason ? ` (${current.parkReason})` : ''}; it has no candidate waiting for publication.`, nextFor(current));
|
|
9890
|
+
}
|
|
9891
|
+
catch (error) {
|
|
9892
|
+
return failure(error);
|
|
9893
|
+
}
|
|
9894
|
+
},
|
|
9895
|
+
},
|
|
9896
|
+
];
|
|
9897
|
+
}
|
|
9898
|
+
|
|
9664
9899
|
/**
|
|
9665
9900
|
* Registered first-party product surfaces only, with
|
|
9666
9901
|
* one exact Drafted exception for delegated review/decision routes. Other
|
|
@@ -9678,6 +9913,9 @@ const builds = {
|
|
|
9678
9913
|
uploadInput,
|
|
9679
9914
|
list: list$1,
|
|
9680
9915
|
watch,
|
|
9916
|
+
media,
|
|
9917
|
+
mediaDownloadUrl,
|
|
9918
|
+
rollbackMedia,
|
|
9681
9919
|
};
|
|
9682
9920
|
|
|
9683
9921
|
async function create(options = {}) {
|
|
@@ -10482,5 +10720,312 @@ function defaultInjectedEvmProvider() {
|
|
|
10482
10720
|
return null;
|
|
10483
10721
|
}
|
|
10484
10722
|
|
|
10485
|
-
|
|
10486
|
-
|
|
10723
|
+
/** Admission comes from an app-authenticated function invoking the Cloudflare
|
|
10724
|
+
* broadcast connector. No application membership is managed by this helper. */
|
|
10725
|
+
async function connectBroadcast(ticket, options) {
|
|
10726
|
+
var _a, _b, _c, _d;
|
|
10727
|
+
const url = new URL(ticket.url);
|
|
10728
|
+
if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))))
|
|
10729
|
+
throw new Error("Invalid broadcast URL");
|
|
10730
|
+
if (!/^[a-f0-9]{64}$/.test(ticket.token) || ticket.transport !== "webrtc-broadcast" || !Number.isFinite(ticket.expiresAt) || ticket.expiresAt <= Date.now()
|
|
10731
|
+
|| !Number.isInteger(ticket.maxSeconds) || ticket.maxSeconds < 15 || ticket.maxSeconds > 300
|
|
10732
|
+
|| !["publisher", "listener"].includes(ticket.role) || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
|
|
10733
|
+
throw new Error("Invalid or expired broadcast ticket");
|
|
10734
|
+
const publisher = ticket.role === "publisher";
|
|
10735
|
+
const tracks = publisher ? [(_b = options.microphone) === null || _b === void 0 ? void 0 : _b.getAudioTracks()[0], (_c = options.assistant) === null || _c === void 0 ? void 0 : _c.getAudioTracks()[0]] : [];
|
|
10736
|
+
if (publisher && tracks.some(track => !track || track.readyState !== "live"))
|
|
10737
|
+
throw new Error("Microphone and assistant audio tracks are required");
|
|
10738
|
+
if (!publisher && !options.audio)
|
|
10739
|
+
throw new Error("Two playback elements are required");
|
|
10740
|
+
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.cloudflare.com:3478" }] });
|
|
10741
|
+
let stopped = false, stopPromise;
|
|
10742
|
+
let resolveClosed;
|
|
10743
|
+
const closed = new Promise(resolve => { resolveClosed = resolve; });
|
|
10744
|
+
let disconnectTimer;
|
|
10745
|
+
const request = async (method, body) => {
|
|
10746
|
+
const response = await fetch(ticket.url, Object.assign(Object.assign({ method, headers: { Authorization: `Bearer ${ticket.token}`, "Content-Type": "application/json" } }, (body === undefined ? {} : { body: JSON.stringify(body) })), { signal: AbortSignal.timeout(15000), redirect: "error", cache: "no-store" }));
|
|
10747
|
+
if (!response.ok)
|
|
10748
|
+
throw new Error(`Broadcast request failed (${response.status})`);
|
|
10749
|
+
return response.json();
|
|
10750
|
+
};
|
|
10751
|
+
const connection = {
|
|
10752
|
+
closed,
|
|
10753
|
+
status: () => request("GET"),
|
|
10754
|
+
close() {
|
|
10755
|
+
var _a, _b;
|
|
10756
|
+
if (stopPromise)
|
|
10757
|
+
return stopPromise;
|
|
10758
|
+
stopped = true;
|
|
10759
|
+
clearTimeout(deadline);
|
|
10760
|
+
clearTimeout(disconnectTimer);
|
|
10761
|
+
peer.close();
|
|
10762
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", abort);
|
|
10763
|
+
tracks.forEach(t => t === null || t === void 0 ? void 0 : t.removeEventListener("ended", abort));
|
|
10764
|
+
(_b = options.audio) === null || _b === void 0 ? void 0 : _b.forEach(audio => { audio.pause(); audio.srcObject = null; });
|
|
10765
|
+
resolveClosed();
|
|
10766
|
+
// These tracks also belong to the primary voice connection. Closing the
|
|
10767
|
+
// broadcast must not stop the microphone or assistant's direct playback.
|
|
10768
|
+
stopPromise = (async () => {
|
|
10769
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
10770
|
+
try {
|
|
10771
|
+
await request("DELETE");
|
|
10772
|
+
return;
|
|
10773
|
+
}
|
|
10774
|
+
catch (error) {
|
|
10775
|
+
if (attempt === 2)
|
|
10776
|
+
throw error;
|
|
10777
|
+
await new Promise(resolve => setTimeout(resolve, 250 * (attempt + 1)));
|
|
10778
|
+
}
|
|
10779
|
+
}
|
|
10780
|
+
})();
|
|
10781
|
+
return stopPromise;
|
|
10782
|
+
},
|
|
10783
|
+
};
|
|
10784
|
+
const abort = () => { void connection.close().catch(() => { }); };
|
|
10785
|
+
const deadline = setTimeout(abort, ticket.maxSeconds * 1000);
|
|
10786
|
+
(_d = options.signal) === null || _d === void 0 ? void 0 : _d.addEventListener("abort", abort, { once: true });
|
|
10787
|
+
tracks.forEach(track => track === null || track === void 0 ? void 0 : track.addEventListener("ended", abort, { once: true }));
|
|
10788
|
+
let audioMids = [];
|
|
10789
|
+
peer.addEventListener("track", event => {
|
|
10790
|
+
var _a;
|
|
10791
|
+
const audio = (_a = options.audio) === null || _a === void 0 ? void 0 : _a[audioMids.indexOf(event.transceiver.mid || "")];
|
|
10792
|
+
if (!audio) {
|
|
10793
|
+
abort();
|
|
10794
|
+
return;
|
|
10795
|
+
}
|
|
10796
|
+
audio.srcObject = new MediaStream([event.track]);
|
|
10797
|
+
void audio.play().catch(abort);
|
|
10798
|
+
});
|
|
10799
|
+
peer.addEventListener("connectionstatechange", () => {
|
|
10800
|
+
clearTimeout(disconnectTimer);
|
|
10801
|
+
if (peer.connectionState === "failed")
|
|
10802
|
+
abort();
|
|
10803
|
+
else if (peer.connectionState === "disconnected")
|
|
10804
|
+
disconnectTimer = setTimeout(abort, 5000);
|
|
10805
|
+
});
|
|
10806
|
+
try {
|
|
10807
|
+
let result;
|
|
10808
|
+
if (publisher) {
|
|
10809
|
+
for (const track of tracks)
|
|
10810
|
+
peer.addTransceiver(track, { direction: "sendonly", sendEncodings: [{ maxBitrate: 32000 }] });
|
|
10811
|
+
await peer.setLocalDescription(await peer.createOffer());
|
|
10812
|
+
result = await request("POST", { sdp: peer.localDescription.sdp });
|
|
10813
|
+
if (stopped)
|
|
10814
|
+
throw new Error("Broadcast cancelled");
|
|
10815
|
+
await peer.setRemoteDescription(result.sessionDescription);
|
|
10816
|
+
}
|
|
10817
|
+
else {
|
|
10818
|
+
result = await request("POST", {});
|
|
10819
|
+
if (stopped)
|
|
10820
|
+
throw new Error("Broadcast cancelled");
|
|
10821
|
+
audioMids = ["microphone", "assistant"].map(name => { var _a, _b; return ((_b = (_a = result.tracks) === null || _a === void 0 ? void 0 : _a.find(track => track.trackName === name)) === null || _b === void 0 ? void 0 : _b.mid) || ""; });
|
|
10822
|
+
if (audioMids.some(mid => !mid) || new Set(audioMids).size !== 2)
|
|
10823
|
+
throw new Error("Invalid broadcast audio tracks");
|
|
10824
|
+
await peer.setRemoteDescription(result.sessionDescription);
|
|
10825
|
+
await peer.setLocalDescription(await peer.createAnswer());
|
|
10826
|
+
await request("PUT", { sdp: peer.localDescription.sdp });
|
|
10827
|
+
}
|
|
10828
|
+
await new Promise((resolve, reject) => {
|
|
10829
|
+
var _a;
|
|
10830
|
+
const timer = setTimeout(() => done(new Error("Broadcast connection timed out")), 15000);
|
|
10831
|
+
const check = () => {
|
|
10832
|
+
if (stopped || ["failed", "closed"].includes(peer.connectionState))
|
|
10833
|
+
done(new Error("Broadcast connection ended"));
|
|
10834
|
+
else if (peer.connectionState === "connected")
|
|
10835
|
+
done();
|
|
10836
|
+
};
|
|
10837
|
+
const done = (error) => { var _a; clearTimeout(timer); peer.removeEventListener("connectionstatechange", check); (_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", check); error ? reject(error) : resolve(); };
|
|
10838
|
+
peer.addEventListener("connectionstatechange", check);
|
|
10839
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.addEventListener("abort", check, { once: true });
|
|
10840
|
+
check();
|
|
10841
|
+
});
|
|
10842
|
+
if (stopped)
|
|
10843
|
+
throw new Error("Broadcast cancelled");
|
|
10844
|
+
return connection;
|
|
10845
|
+
}
|
|
10846
|
+
catch (error) {
|
|
10847
|
+
await connection.close().catch(() => { });
|
|
10848
|
+
throw error;
|
|
10849
|
+
}
|
|
10850
|
+
}
|
|
10851
|
+
|
|
10852
|
+
/** Attach browser media directly to the connector's provider. Bounded observes
|
|
10853
|
+
* usage independently; data-channel messages never count as billing receipts. */
|
|
10854
|
+
async function connectServiceSession(ticket, options) {
|
|
10855
|
+
var _a, _b, _c;
|
|
10856
|
+
const url = new URL(ticket.url);
|
|
10857
|
+
if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))))
|
|
10858
|
+
throw new Error("Invalid service session URL");
|
|
10859
|
+
if (!/^[a-f0-9]{64}$/.test(ticket.token) || ticket.transport !== "webrtc-session" || !Number.isFinite(ticket.expiresAt) || ticket.expiresAt <= Date.now())
|
|
10860
|
+
throw new Error("Invalid or expired service session ticket");
|
|
10861
|
+
if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted)
|
|
10862
|
+
throw new Error("Service session aborted");
|
|
10863
|
+
const peer = new RTCPeerConnection();
|
|
10864
|
+
const audioStream = new MediaStream();
|
|
10865
|
+
const channel = peer.createDataChannel("oai-events");
|
|
10866
|
+
let ready = false, finished = false, closing = false;
|
|
10867
|
+
let resolveClosed, rejectClosed;
|
|
10868
|
+
let resolveReady, rejectReady;
|
|
10869
|
+
let pollTimer;
|
|
10870
|
+
const closed = new Promise((resolve, reject) => { resolveClosed = resolve; rejectClosed = reject; });
|
|
10871
|
+
void closed.catch(() => { });
|
|
10872
|
+
const connected = new Promise((resolve, reject) => { resolveReady = resolve; rejectReady = reject; });
|
|
10873
|
+
void connected.catch(() => { });
|
|
10874
|
+
const request = async (method, body) => {
|
|
10875
|
+
const response = await fetch(ticket.url, Object.assign(Object.assign({ method, headers: Object.assign({ Authorization: `Bearer ${ticket.token}` }, (body === undefined ? {} : { "Content-Type": "application/json" })) }, (body === undefined ? {} : { body: JSON.stringify(body) })), { signal: AbortSignal.timeout(15000), cache: "no-store", redirect: "error" }));
|
|
10876
|
+
if (!response.ok)
|
|
10877
|
+
throw new Error(`Service session request failed (${response.status})`);
|
|
10878
|
+
return response.json();
|
|
10879
|
+
};
|
|
10880
|
+
const cleanup = () => {
|
|
10881
|
+
var _a;
|
|
10882
|
+
clearTimeout(startTimer);
|
|
10883
|
+
clearTimeout(pollTimer);
|
|
10884
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", abort);
|
|
10885
|
+
options.stream.getTracks().forEach(track => track.stop());
|
|
10886
|
+
options.audio.pause();
|
|
10887
|
+
options.audio.srcObject = null;
|
|
10888
|
+
channel.close();
|
|
10889
|
+
peer.close();
|
|
10890
|
+
};
|
|
10891
|
+
const fail = (error) => {
|
|
10892
|
+
if (finished)
|
|
10893
|
+
return;
|
|
10894
|
+
finished = true;
|
|
10895
|
+
rejectReady(error);
|
|
10896
|
+
rejectClosed(error);
|
|
10897
|
+
cleanup();
|
|
10898
|
+
};
|
|
10899
|
+
const poll = async (until) => {
|
|
10900
|
+
if (finished)
|
|
10901
|
+
return;
|
|
10902
|
+
try {
|
|
10903
|
+
const state = await request("GET");
|
|
10904
|
+
if (state.state === "closed" && state.finalUsage === true && Number.isFinite(state.seconds) && state.seconds >= 0 && Number.isSafeInteger(state.chargedMicroUsd) && state.chargedMicroUsd >= 0) {
|
|
10905
|
+
finished = true;
|
|
10906
|
+
resolveClosed({ seconds: state.seconds, chargedMicroUsd: state.chargedMicroUsd, finalUsage: true });
|
|
10907
|
+
if (!ready)
|
|
10908
|
+
rejectReady(new Error("Service session ended before startup"));
|
|
10909
|
+
cleanup();
|
|
10910
|
+
return;
|
|
10911
|
+
}
|
|
10912
|
+
if (["waiting", "creating", "active"].includes(state.state))
|
|
10913
|
+
await request("DELETE");
|
|
10914
|
+
if (state.state === "attention") {
|
|
10915
|
+
fail(new Error("Service session requires reconciliation"));
|
|
10916
|
+
return;
|
|
10917
|
+
}
|
|
10918
|
+
}
|
|
10919
|
+
catch ( /* bounded retries; never invent a receipt after a network failure */_a) { /* bounded retries; never invent a receipt after a network failure */ }
|
|
10920
|
+
if (Date.now() >= until) {
|
|
10921
|
+
fail(new Error("Service session finalization unconfirmed; check session status"));
|
|
10922
|
+
return;
|
|
10923
|
+
}
|
|
10924
|
+
pollTimer = setTimeout(() => { void poll(until); }, 500);
|
|
10925
|
+
};
|
|
10926
|
+
const session = {
|
|
10927
|
+
audioStream,
|
|
10928
|
+
closed,
|
|
10929
|
+
send(event) {
|
|
10930
|
+
if (!ready || closing || finished || channel.readyState !== "open")
|
|
10931
|
+
throw new Error("Service session is not accepting messages");
|
|
10932
|
+
const json = JSON.stringify(event);
|
|
10933
|
+
if (new TextEncoder().encode(json).byteLength > 65536 || channel.bufferedAmount > 256000)
|
|
10934
|
+
throw new Error("Service session backpressure limit");
|
|
10935
|
+
channel.send(json);
|
|
10936
|
+
},
|
|
10937
|
+
close() {
|
|
10938
|
+
if (!closing && !finished) {
|
|
10939
|
+
closing = true;
|
|
10940
|
+
options.stream.getTracks().forEach(track => track.stop());
|
|
10941
|
+
options.audio.pause();
|
|
10942
|
+
options.audio.srcObject = null;
|
|
10943
|
+
// Keep WebRTC alive while the server collects final usage. HTTP close
|
|
10944
|
+
// also works when the provider data channel is already gone.
|
|
10945
|
+
void request("DELETE").catch(() => { }).then(() => poll(Date.now() + 45000));
|
|
10946
|
+
}
|
|
10947
|
+
return closed;
|
|
10948
|
+
},
|
|
10949
|
+
};
|
|
10950
|
+
const abort = () => { void session.close(); };
|
|
10951
|
+
const startTimer = setTimeout(() => { void request("DELETE").catch(() => { }); fail(new Error("Service session startup timed out")); }, 30000);
|
|
10952
|
+
(_b = options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener("abort", abort, { once: true });
|
|
10953
|
+
peer.addEventListener("track", ({ track }) => { if (closing || finished)
|
|
10954
|
+
return; audioStream.addTrack(track); options.audio.srcObject = audioStream; void options.audio.play().catch(() => { void session.close(); fail(new Error("Audio playback was blocked")); }); });
|
|
10955
|
+
channel.addEventListener("message", ({ data }) => {
|
|
10956
|
+
var _a;
|
|
10957
|
+
if (finished || closing)
|
|
10958
|
+
return;
|
|
10959
|
+
let event;
|
|
10960
|
+
try {
|
|
10961
|
+
event = JSON.parse(String(data));
|
|
10962
|
+
}
|
|
10963
|
+
catch (_b) {
|
|
10964
|
+
return;
|
|
10965
|
+
}
|
|
10966
|
+
if ((event === null || event === void 0 ? void 0 : event.type) === "session.started" && !ready) {
|
|
10967
|
+
ready = true;
|
|
10968
|
+
clearTimeout(startTimer);
|
|
10969
|
+
resolveReady();
|
|
10970
|
+
}
|
|
10971
|
+
if ((event === null || event === void 0 ? void 0 : event.type) === "session.closed")
|
|
10972
|
+
void session.close();
|
|
10973
|
+
try {
|
|
10974
|
+
(_a = options.onEvent) === null || _a === void 0 ? void 0 : _a.call(options, event);
|
|
10975
|
+
}
|
|
10976
|
+
catch ( /* UI callback failure cannot own cleanup */_c) { /* UI callback failure cannot own cleanup */ }
|
|
10977
|
+
});
|
|
10978
|
+
peer.addEventListener("connectionstatechange", () => { if (["failed", "closed"].includes(peer.connectionState) && !finished)
|
|
10979
|
+
void session.close(); });
|
|
10980
|
+
channel.addEventListener("close", () => { if (!finished)
|
|
10981
|
+
void session.close(); });
|
|
10982
|
+
try {
|
|
10983
|
+
for (const track of options.stream.getAudioTracks())
|
|
10984
|
+
peer.addTrack(track, options.stream);
|
|
10985
|
+
if (!options.stream.getAudioTracks().length)
|
|
10986
|
+
throw new Error("An audio track is required");
|
|
10987
|
+
await peer.setLocalDescription(await peer.createOffer());
|
|
10988
|
+
if (peer.iceGatheringState !== "complete")
|
|
10989
|
+
await new Promise((resolve, reject) => {
|
|
10990
|
+
var _a;
|
|
10991
|
+
const timer = setTimeout(() => done(new Error("Service session ICE gathering timed out")), 10000);
|
|
10992
|
+
const done = (error) => {
|
|
10993
|
+
var _a;
|
|
10994
|
+
clearTimeout(timer);
|
|
10995
|
+
peer.removeEventListener("icegatheringstatechange", check);
|
|
10996
|
+
peer.removeEventListener("connectionstatechange", check);
|
|
10997
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", check);
|
|
10998
|
+
error ? reject(error) : resolve();
|
|
10999
|
+
};
|
|
11000
|
+
const check = () => {
|
|
11001
|
+
var _a;
|
|
11002
|
+
if (closing || finished || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) || peer.connectionState === "closed")
|
|
11003
|
+
done(new Error("Service session aborted during ICE gathering"));
|
|
11004
|
+
else if (peer.iceGatheringState === "complete")
|
|
11005
|
+
done();
|
|
11006
|
+
};
|
|
11007
|
+
peer.addEventListener("icegatheringstatechange", check);
|
|
11008
|
+
peer.addEventListener("connectionstatechange", check);
|
|
11009
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.addEventListener("abort", check, { once: true });
|
|
11010
|
+
check();
|
|
11011
|
+
});
|
|
11012
|
+
if (closing || finished)
|
|
11013
|
+
throw new Error("Service session aborted before admission");
|
|
11014
|
+
if (!((_c = peer.localDescription) === null || _c === void 0 ? void 0 : _c.sdp.includes("\r\na=candidate:")))
|
|
11015
|
+
throw new Error("Service session has no usable ICE candidates");
|
|
11016
|
+
const answer = await request("POST", { sdp: peer.localDescription.sdp });
|
|
11017
|
+
if (closing || finished)
|
|
11018
|
+
throw new Error("Service session aborted during admission");
|
|
11019
|
+
await peer.setRemoteDescription({ type: "answer", sdp: answer.sdp });
|
|
11020
|
+
await connected;
|
|
11021
|
+
return session;
|
|
11022
|
+
}
|
|
11023
|
+
catch (error) {
|
|
11024
|
+
void request("DELETE").catch(() => { });
|
|
11025
|
+
fail(error instanceof Error ? error : new Error("Service session startup failed"));
|
|
11026
|
+
throw error;
|
|
11027
|
+
}
|
|
11028
|
+
}
|
|
11029
|
+
|
|
11030
|
+
export { onrampStatus as $, getAuthProvider as A, signInAnonymously as B, loginWithPrivy as C, loginWithWallet as D, ensureWalletLoginReady as E, ensureSharedWalletLoginReady as F, preloadWalletLogin as G, loginWithRedirect as H, completeLoginFromRedirect as I, loginWithPopup as J, completeLoginInPopup as K, openBoundedWidget as L, ensureSignedIn as M, useAuth as N, useQuery as O, useBuildRun as P, apps as Q, signSolanaMessageViaTurnkey as R, getOrCreateTurnkeyWallet as S, openTurnkeyKeyExport as T, getTurnkeyWalletSessionState as U, getTurnkeyWalletRecoveryUrl as V, WalletConfigError as W, startTurnkeyEmailLogin as X, getIdToken as Y, onramp as Z, onrampQuote as _, signMessageWithTurnkey as a, setPlatform as a0, OffchainAuthProvider as a1, PrivyExpoProvider as a2, requestEip6963Providers as a3, connectBroadcast as a4, connectServiceSession as a5, builds as a6, BuildsApiError as a7, mediaAgentTools as a8, NON_TERMINAL_STATES as a9, TERMINAL_STATES as aa, RUN_STATES as ab, PARK_REASONS as ac, FAILURE_REASONS as ad, BUILD_REVIEW_CAPABILITY_SCHEMA as ae, BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA as af, BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA as ag, signTransactionWithTurnkey as b, signTransactionV1WithTurnkey as c, signAndSubmitTransactionWithTurnkey as d, bs58 as e, defaultInjectedProvider as f, getPlatform as g, hasTurnkeyWallet as h, firstStandardWalletProvider as i, setAuthLoading as j, bufferExports as k, setStoredAuthMethod as l, confirmAndCheckTransaction as m, normalizeSolanaRpcUrl as n, defaultInjectedEvmProvider as o, init as p, getCurrentUser as q, resolveSolanaRpcUrl as r, setCurrentUser as s, transactionHasSignature as t, onAuthStateChanged as u, onAuthLoadingChanged as v, getAuthLoading as w, waitForAuthReady as x, login as y, logout as z };
|
|
11031
|
+
//# sourceMappingURL=index-CaZx7sd8.mjs.map
|