@bounded-sh/client 0.0.100-performance.1 → 0.0.100
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 +4 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- 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.js +2 -1
- package/dist/index.native.js.map +1 -1
- package/dist/index.native.mjs +1 -1
- 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
|
@@ -56,13 +56,6 @@ function walletOperationGuard() {
|
|
|
56
56
|
throw new Error('wallet_session_changed');
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
function walletLoginGuard(signal) {
|
|
60
|
-
const generation = ++loginGeneration;
|
|
61
|
-
return () => {
|
|
62
|
-
if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || generation !== loginGeneration)
|
|
63
|
-
throw new Error('wallet_login_cancelled');
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
59
|
// This realm owns one active SDK session and one retained signer frame.
|
|
67
60
|
let activeWalletState;
|
|
68
61
|
function setWalletSessionState(key, state) { activeWalletState = { key, state }; }
|
|
@@ -4543,11 +4536,6 @@ function ensureFonts() {
|
|
|
4543
4536
|
link.setAttribute("data-bounded-fonts", "1");
|
|
4544
4537
|
document.head.append(pre1, pre2, link);
|
|
4545
4538
|
}
|
|
4546
|
-
/** Tag the already mounted login document without moving or navigating it. */
|
|
4547
|
-
function bindWarmSignerFrame(frame, context) {
|
|
4548
|
-
if ((modal === null || modal === void 0 ? void 0 : modal.iframe) === frame)
|
|
4549
|
-
modal.iframeContext = context;
|
|
4550
|
-
}
|
|
4551
4539
|
|
|
4552
4540
|
// turnkey-wallet-widget.ts - runs one Turnkey signer exchange inside the shared
|
|
4553
4541
|
// in-app WIDGET (bounded-widget-modal.ts). The Bounded-owned signer page is loaded
|
|
@@ -5906,14 +5894,13 @@ function completeLoginInPopup(openerOrigin) {
|
|
|
5906
5894
|
// identical to exchangeCode's tail so the realtime worker cannot tell them apart.
|
|
5907
5895
|
async function establishInlineSession(data, beforeCommit, beforeStore) {
|
|
5908
5896
|
const base = await issuerBase();
|
|
5909
|
-
beforeCommit === null || beforeCommit === void 0 ? void 0 : beforeCommit();
|
|
5910
5897
|
const idToken = tokenField(data, 'id_token', 'idToken');
|
|
5911
5898
|
if (!idToken)
|
|
5912
5899
|
throw new Error('No id_token in the inline session response');
|
|
5913
5900
|
const accessToken = tokenField(data, 'access_token', 'accessToken') || idToken;
|
|
5914
5901
|
const refreshToken = boundedRefreshTokenField(data);
|
|
5915
5902
|
const user = userFromIdToken(idToken);
|
|
5916
|
-
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => {
|
|
5903
|
+
const rollback = await sessionManager().storeSession(String(user.address || ''), accessToken, idToken, refreshToken, base, () => { });
|
|
5917
5904
|
// Adopt the OIDC provider on EVERY session surface - including core's signing
|
|
5918
5905
|
// pointer (getConfig().authProvider), which this path used to skip, leaving
|
|
5919
5906
|
// onchain writes routed through a previous (e.g. logged-out wallet) provider.
|
|
@@ -6342,7 +6329,7 @@ async function getAuthProvider(config) {
|
|
|
6342
6329
|
// manager as legacy email sessions. Human login should be started
|
|
6343
6330
|
// with loginWithRedirect(); this provider is kept as the restore and
|
|
6344
6331
|
// logout surface for those sessions.
|
|
6345
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-
|
|
6332
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./email-auth-provider-Cr3I4Po5.js'); })).EmailAuthProvider();
|
|
6346
6333
|
break;
|
|
6347
6334
|
case "phantom": {
|
|
6348
6335
|
// First-class Solana WALLET LOGIN (the poof/TaroBase-style "connect
|
|
@@ -6384,7 +6371,7 @@ async function getAuthProvider(config) {
|
|
|
6384
6371
|
// (bounded-login-widget.ts), so registration never counts as
|
|
6385
6372
|
// evidence the user has a wallet.
|
|
6386
6373
|
await ensureSolanaMobileWalletRegistered(config, configuredNetwork);
|
|
6387
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6374
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-Cv9RELO6.js'); });
|
|
6388
6375
|
currentAuthProvider = new InjectedWalletProvider(resolveInjectedWalletConfig(config), rpcUrl, configuredNetwork);
|
|
6389
6376
|
break;
|
|
6390
6377
|
}
|
|
@@ -6397,7 +6384,7 @@ async function getAuthProvider(config) {
|
|
|
6397
6384
|
// Selecting authMethod:'evm-wallet' IS the opt-in — pass evmWalletConfig
|
|
6398
6385
|
// to point at a specific wallet or set chainId/domain.
|
|
6399
6386
|
const evmWalletConfig = ((_a = config.evmWalletConfig) !== null && _a !== void 0 ? _a : {});
|
|
6400
|
-
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-
|
|
6387
|
+
const { InjectedEvmWalletProvider } = await Promise.resolve().then(function () { return require('./injected-evm-wallet-provider-U0XJu5HM.js'); });
|
|
6401
6388
|
currentAuthProvider = new InjectedEvmWalletProvider(evmWalletConfig);
|
|
6402
6389
|
break;
|
|
6403
6390
|
}
|
|
@@ -6422,7 +6409,7 @@ async function getAuthProvider(config) {
|
|
|
6422
6409
|
break;
|
|
6423
6410
|
case "guest":
|
|
6424
6411
|
// Anonymous auth: a device-local ed25519 keypair signs the challenge.
|
|
6425
|
-
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6412
|
+
currentAuthProvider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-CPj-w7_R.js'); })).GuestAuthProvider();
|
|
6426
6413
|
break;
|
|
6427
6414
|
}
|
|
6428
6415
|
if (!currentAuthProvider) {
|
|
@@ -6484,7 +6471,7 @@ async function signInAnonymously() {
|
|
|
6484
6471
|
// Lazy-load the guest provider so its ed25519/web3 dependencies stay out of
|
|
6485
6472
|
// the main bundle for data-only apps. Specifier is a static string literal
|
|
6486
6473
|
// so bundle-splitting can see it.
|
|
6487
|
-
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-
|
|
6474
|
+
const provider = new (await Promise.resolve().then(function () { return require('./guest-auth-provider-CPj-w7_R.js'); })).GuestAuthProvider();
|
|
6488
6475
|
setAuthLoading(true); // reflect "signing in…" while the guest keypair session is minted
|
|
6489
6476
|
// adoptSessionProvider awaits only getConfig() (already resolved here) and then
|
|
6490
6477
|
// runs every write - provider/method/config/marker/user - in one synchronous
|
|
@@ -6655,7 +6642,7 @@ function ensureSharedWalletLoginReady() {
|
|
|
6655
6642
|
if (!sharedWalletReady) {
|
|
6656
6643
|
sharedWalletReady = (async () => {
|
|
6657
6644
|
await core.getConfig();
|
|
6658
|
-
await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6645
|
+
await Promise.resolve().then(function () { return require('./injected-wallet-provider-Cv9RELO6.js'); });
|
|
6659
6646
|
})().catch((error) => {
|
|
6660
6647
|
sharedWalletReady = null;
|
|
6661
6648
|
throw error;
|
|
@@ -6758,7 +6745,7 @@ async function loginWithWallet(options) {
|
|
|
6758
6745
|
await ensureSharedWalletLoginReady();
|
|
6759
6746
|
else
|
|
6760
6747
|
await ensureWalletLoginReady();
|
|
6761
|
-
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-
|
|
6748
|
+
const { InjectedWalletProvider } = await Promise.resolve().then(function () { return require('./injected-wallet-provider-Cv9RELO6.js'); });
|
|
6762
6749
|
// Keep the RAW wallet provider: the offchain wrapper forwards only a fixed
|
|
6763
6750
|
// set of methods, so cleanup below must speak to the provider that actually
|
|
6764
6751
|
// holds the config rather than to whatever is wrapping it.
|
|
@@ -7764,12 +7751,14 @@ async function startTurnkeyEmailLogin(email) {
|
|
|
7764
7751
|
: undefined;
|
|
7765
7752
|
return {
|
|
7766
7753
|
email: trimmed, frameUrl, signerOrigin,
|
|
7767
|
-
run(iframe,
|
|
7754
|
+
run(iframe, _signal) {
|
|
7768
7755
|
if (!ceremonyId) {
|
|
7769
7756
|
return Promise.reject(new Error('This app is not configured for in-frame wallet login. Please try again.'));
|
|
7770
7757
|
}
|
|
7771
7758
|
const run = { iframe, base, signerOrigin, appId, email: trimmed, otpId, otpEncryptionTargetBundle, ceremonyId };
|
|
7772
|
-
|
|
7759
|
+
// BSA-2026-004: the login code is typed only in /wallet/turnkey/otp-frame.
|
|
7760
|
+
// The scoped signer URL is for post-login signing, not OTP entry.
|
|
7761
|
+
return runOtpFrame(run);
|
|
7773
7762
|
},
|
|
7774
7763
|
};
|
|
7775
7764
|
}
|
|
@@ -7874,104 +7863,6 @@ function runOtpFrame(run) {
|
|
|
7874
7863
|
run.iframe.src = url;
|
|
7875
7864
|
});
|
|
7876
7865
|
}
|
|
7877
|
-
// The scoped document owns both OTP and signing. Adopt only its sanitized app
|
|
7878
|
-
// session, acknowledge with a narrow grant, then wait for wallet readiness.
|
|
7879
|
-
function runScopedOtpFrame(run, frameUrl, signal) {
|
|
7880
|
-
const assertCurrent = walletLoginGuard(signal);
|
|
7881
|
-
const beforeStore = core.getActiveSessionManager().captureSessionEstablishment();
|
|
7882
|
-
return new Promise((resolve, reject) => {
|
|
7883
|
-
let settled = false, adopting = false, started = false;
|
|
7884
|
-
let user = null;
|
|
7885
|
-
let adoptedToken = '';
|
|
7886
|
-
let context = null;
|
|
7887
|
-
const post = (data) => { var _a; return (_a = run.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(data, run.signerOrigin); };
|
|
7888
|
-
const cleanup = () => {
|
|
7889
|
-
settled = true;
|
|
7890
|
-
clearTimeout(timer);
|
|
7891
|
-
window.removeEventListener('message', onMessage);
|
|
7892
|
-
signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', abort);
|
|
7893
|
-
};
|
|
7894
|
-
const fail = (error) => { cleanup(); reject(error instanceof Error ? error : new Error(String(error))); };
|
|
7895
|
-
const abort = () => { post({ type: 'bounded:otp:cancel' }); fail(new Error('wallet_login_cancelled')); };
|
|
7896
|
-
const finish = (ready, reason, expiresAt) => {
|
|
7897
|
-
if (!user || !context || core.getActiveSessionManager().getIdToken() !== adoptedToken) {
|
|
7898
|
-
fail(new Error('wallet_session_changed'));
|
|
7899
|
-
return;
|
|
7900
|
-
}
|
|
7901
|
-
setWalletSessionState(context.key, ready && Number.isFinite(expiresAt) && expiresAt > Date.now()
|
|
7902
|
-
? { status: 'ready', expiresAt: expiresAt } : { status: 'verification-required', reason });
|
|
7903
|
-
cleanup();
|
|
7904
|
-
resolve(user);
|
|
7905
|
-
};
|
|
7906
|
-
const onMessage = async (event) => {
|
|
7907
|
-
if (settled || event.origin !== run.signerOrigin || event.source !== run.iframe.contentWindow)
|
|
7908
|
-
return;
|
|
7909
|
-
const d = event.data;
|
|
7910
|
-
if (!d || typeof d !== 'object')
|
|
7911
|
-
return;
|
|
7912
|
-
if (d.type === 'bounded:otp:ready' && !started) {
|
|
7913
|
-
started = true;
|
|
7914
|
-
post({ type: 'bounded:otp:start', email: run.email, ceremonyId: run.ceremonyId,
|
|
7915
|
-
otpId: run.otpId, otpEncryptionTargetBundle: run.otpEncryptionTargetBundle });
|
|
7916
|
-
}
|
|
7917
|
-
if (d.type === 'bounded:otp:wallet-ready' && user) {
|
|
7918
|
-
finish(d.ok === true, typeof d.error === 'string' ? d.error : 'wallet_session_unavailable', d.expiresAt);
|
|
7919
|
-
}
|
|
7920
|
-
if (d.type !== 'bounded:otp:result' || adopting)
|
|
7921
|
-
return;
|
|
7922
|
-
if (d.ok !== true || !d.session || typeof d.session.idToken !== 'string') {
|
|
7923
|
-
fail(new Error(String(d.error || 'wallet_login_failed')));
|
|
7924
|
-
return;
|
|
7925
|
-
}
|
|
7926
|
-
adopting = true;
|
|
7927
|
-
try {
|
|
7928
|
-
assertCurrent();
|
|
7929
|
-
const token = d.session.idToken;
|
|
7930
|
-
const claims = JSON.parse(getPlatform().atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
|
|
7931
|
-
context = walletContextFromClaims(claims, run.base, run.appId, window.location.origin);
|
|
7932
|
-
if (context.scope !== 'app')
|
|
7933
|
-
throw new Error('wallet_scope_mismatch');
|
|
7934
|
-
user = await establishInlineSession(d.session, () => { assertCurrent(); if (settled)
|
|
7935
|
-
throw new Error('wallet_login_cancelled'); }, beforeStore);
|
|
7936
|
-
adoptedToken = token;
|
|
7937
|
-
bindWarmSignerFrame(run.iframe, context.key);
|
|
7938
|
-
if (settled || (signal === null || signal === void 0 ? void 0 : signal.aborted) || core.getActiveSessionManager().getIdToken() !== token)
|
|
7939
|
-
throw new Error('wallet_session_changed');
|
|
7940
|
-
setWalletSessionState(context.key, { status: 'verification-required', reason: 'wallet_session_pending' });
|
|
7941
|
-
const authorization = await requestTurnkeyActionAuthorization({
|
|
7942
|
-
baseUrl: run.base, idToken: token, action: 'createWallet', fetchImpl: (u, i) => fetch(u, i),
|
|
7943
|
-
});
|
|
7944
|
-
if (settled || core.getActiveSessionManager().getIdToken() !== token)
|
|
7945
|
-
throw new Error('wallet_session_changed');
|
|
7946
|
-
post({ type: 'bounded:otp:authorization', authorization });
|
|
7947
|
-
}
|
|
7948
|
-
catch (error) {
|
|
7949
|
-
if (user && adoptedToken) {
|
|
7950
|
-
post({ type: 'bounded:otp:authorization', authorization: '' });
|
|
7951
|
-
finish(false, 'wallet_session_unavailable');
|
|
7952
|
-
}
|
|
7953
|
-
else
|
|
7954
|
-
fail(error);
|
|
7955
|
-
}
|
|
7956
|
-
};
|
|
7957
|
-
const timer = setTimeout(() => {
|
|
7958
|
-
if (user)
|
|
7959
|
-
finish(false, 'wallet_session_timeout');
|
|
7960
|
-
else
|
|
7961
|
-
fail(new Error('The sign-in code entry timed out. Please try again.'));
|
|
7962
|
-
}, 180000);
|
|
7963
|
-
window.addEventListener('message', onMessage);
|
|
7964
|
-
signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', abort, { once: true });
|
|
7965
|
-
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
7966
|
-
abort();
|
|
7967
|
-
return;
|
|
7968
|
-
}
|
|
7969
|
-
if (run.iframe.src !== frameUrl)
|
|
7970
|
-
run.iframe.src = frameUrl;
|
|
7971
|
-
// Readiness can predate listener installation when reusing a mounted frame.
|
|
7972
|
-
post({ type: 'bounded:otp:hello' });
|
|
7973
|
-
});
|
|
7974
|
-
}
|
|
7975
7866
|
|
|
7976
7867
|
// bounded-login-widget.ts - the UNIFIED Bounded login surface: one in-app card
|
|
7977
7868
|
// (Shadow-DOM modal from bounded-widget-modal.ts, Bounded look + motion) that folds
|
|
@@ -8511,24 +8402,10 @@ async function prepareAndOpen(opts, pending) {
|
|
|
8511
8402
|
settleAttempt(attempt);
|
|
8512
8403
|
return;
|
|
8513
8404
|
}
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
}
|
|
8519
|
-
const controller = new AbortController();
|
|
8520
|
-
abortScopedLogin = () => controller.abort();
|
|
8521
|
-
// Mount once in the shared modal. Moving a live iframe would discard
|
|
8522
|
-
// the trusted document holding the private in-memory session key.
|
|
8523
|
-
detachIframe(m);
|
|
8524
|
-
const frame = ensureIframe(m, handle.frameUrl, handle.signerOrigin, `login:${attempt}`);
|
|
8525
|
-
setPanelHeight(m, 380);
|
|
8526
|
-
const completion = handle.run(frame, controller.signal);
|
|
8527
|
-
m.chain = completion.then(() => undefined, () => undefined);
|
|
8528
|
-
const user = await completion;
|
|
8529
|
-
abortScopedLogin = null;
|
|
8530
|
-
settleAttempt(attempt);
|
|
8531
|
-
succeed(user);
|
|
8405
|
+
// BSA-2026-004: collect the code in the Bounded OTP frame, never in
|
|
8406
|
+
// this tenant DOM and never in the unframeable signer document.
|
|
8407
|
+
if (settleAttempt(attempt))
|
|
8408
|
+
swap(renderOtpFrame(handle));
|
|
8532
8409
|
})
|
|
8533
8410
|
.catch((err) => {
|
|
8534
8411
|
if (!settleAttempt(attempt))
|
|
@@ -9384,9 +9261,26 @@ async function getReviewCapability(appId, runId, gateId, options) {
|
|
|
9384
9261
|
body: { expectedPreviewUrl: options.expectedPreviewUrl },
|
|
9385
9262
|
});
|
|
9386
9263
|
}
|
|
9264
|
+
/**
|
|
9265
|
+
* Add funds to a run parked for funding. Accounts billed through payer shards refuse it with
|
|
9266
|
+
* `topup_unavailable_payer_shard` (in `details.upstreamCode`): a parked run there holds no money, so the payer adds
|
|
9267
|
+
* credits and submits the build again.
|
|
9268
|
+
*/
|
|
9387
9269
|
async function topup(appId, runId, options) {
|
|
9388
9270
|
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/topup`, { method: 'POST', body: options });
|
|
9389
9271
|
}
|
|
9272
|
+
/** An image build's verified images and its asset's current release. */
|
|
9273
|
+
async function media(appId, runId) {
|
|
9274
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media`);
|
|
9275
|
+
}
|
|
9276
|
+
/** A short-lived signed URL for one image of an image build (usable directly as an image source). */
|
|
9277
|
+
async function mediaDownloadUrl(appId, runId, artifactId) {
|
|
9278
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media-download-url`, { method: 'POST', body: { artifactId } });
|
|
9279
|
+
}
|
|
9280
|
+
/** Roll back the release an image build published: its asset returns to the release it replaced. */
|
|
9281
|
+
async function rollbackMedia(appId, runId, options = {}) {
|
|
9282
|
+
return requestDevApi(`${appPath(appId)}/${encodeURIComponent(runId)}/media-rollback`, { method: 'POST', body: options.note ? { note: options.note } : {} });
|
|
9283
|
+
}
|
|
9390
9284
|
async function list$1(appId, limit = 20) {
|
|
9391
9285
|
const requestedLimit = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 20;
|
|
9392
9286
|
return requestDevApi(`${appPath(appId)}?limit=${requestedLimit}`);
|
|
@@ -9418,13 +9312,15 @@ const RUN_STATES = [
|
|
|
9418
9312
|
...NON_TERMINAL_STATES,
|
|
9419
9313
|
...TERMINAL_STATES,
|
|
9420
9314
|
];
|
|
9421
|
-
const PARK_REASONS = ['gate', 'funding'];
|
|
9315
|
+
const PARK_REASONS = ['gate', 'funding', 'preview', 'design'];
|
|
9422
9316
|
const FAILURE_REASONS = [
|
|
9423
9317
|
'admission_rejected',
|
|
9424
9318
|
'dispatch_timeout',
|
|
9425
9319
|
'auth_revoked',
|
|
9426
9320
|
'owner_changed',
|
|
9427
9321
|
'policy_changed',
|
|
9322
|
+
'target_retired',
|
|
9323
|
+
'promotion_rejected',
|
|
9428
9324
|
'quarantine_forced',
|
|
9429
9325
|
'bind_failed',
|
|
9430
9326
|
'internal_error',
|
|
@@ -9682,6 +9578,345 @@ function useBuildRun(appId, runId, options) {
|
|
|
9682
9578
|
return { run, events, loading, error };
|
|
9683
9579
|
}
|
|
9684
9580
|
|
|
9581
|
+
const TERMINAL = new Set(['promoted', 'failed', 'canceled', 'rejected', 'expired', 'rebase_required', 'reported']);
|
|
9582
|
+
const KEY = { type: 'string', minLength: 1, maxLength: 256, description: 'A key unique to this intent; retrying with the same key never repeats the action.' };
|
|
9583
|
+
const RUN_ID = { type: 'string', minLength: 1, maxLength: 128, description: 'The build run id media_create or media_edit returned.' };
|
|
9584
|
+
const REGION = {
|
|
9585
|
+
type: 'object',
|
|
9586
|
+
additionalProperties: false,
|
|
9587
|
+
required: ['x', 'y', 'width', 'height'],
|
|
9588
|
+
properties: {
|
|
9589
|
+
x: { type: 'integer', minimum: 0 },
|
|
9590
|
+
y: { type: 'integer', minimum: 0 },
|
|
9591
|
+
width: { type: 'integer', minimum: 1 },
|
|
9592
|
+
height: { type: 'integer', minimum: 1 },
|
|
9593
|
+
},
|
|
9594
|
+
description: 'A rectangle in whole pixels of the image; nothing outside it changes.',
|
|
9595
|
+
};
|
|
9596
|
+
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.' };
|
|
9597
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9598
|
+
const text = (value, max) => typeof value === 'string' && value.trim().length > 0 && value.length <= max ? value : undefined;
|
|
9599
|
+
const refuse = (code, message, next = ['media_inspect'], retryable = false) => ({ ok: false, code, message, retryable, next });
|
|
9600
|
+
function region(value) {
|
|
9601
|
+
if (!isRecord(value))
|
|
9602
|
+
return undefined;
|
|
9603
|
+
const { x, y, width, height } = value;
|
|
9604
|
+
return [x, y, width, height].every(Number.isSafeInteger) && x >= 0 && y >= 0
|
|
9605
|
+
&& width >= 1 && height >= 1
|
|
9606
|
+
? { x: x, y: y, width: width, height: height }
|
|
9607
|
+
: undefined;
|
|
9608
|
+
}
|
|
9609
|
+
/** A thrown API error, as the tool result the model reads. The developer API answers with a coarse public code and
|
|
9610
|
+
* relays Build's own reason (base_moved, candidate_unknown, media_storage_quota, ...) as details.upstreamCode. */
|
|
9611
|
+
function failure(error) {
|
|
9612
|
+
var _a;
|
|
9613
|
+
const apiError = error;
|
|
9614
|
+
const upstream = (_a = apiError === null || apiError === void 0 ? void 0 : apiError.details) === null || _a === void 0 ? void 0 : _a.upstreamCode;
|
|
9615
|
+
return refuse(typeof upstream === 'string' && /^[a-z][a-z0-9_]{0,79}$/.test(upstream) && upstream !== 'unknown_upstream_error'
|
|
9616
|
+
? upstream
|
|
9617
|
+
: 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);
|
|
9618
|
+
}
|
|
9619
|
+
/** What a run lets an agent do next. */
|
|
9620
|
+
function nextFor(run) {
|
|
9621
|
+
var _a;
|
|
9622
|
+
if ((_a = run.design) === null || _a === void 0 ? void 0 : _a.gate)
|
|
9623
|
+
return ['media_select', 'media_revise', 'media_export'];
|
|
9624
|
+
if (run.state === 'promoted')
|
|
9625
|
+
return ['media_export', 'media_edit', 'media_create'];
|
|
9626
|
+
if (run.state === 'parked' && run.parkReason === 'gate')
|
|
9627
|
+
return ['media_propose', 'media_export'];
|
|
9628
|
+
if (TERMINAL.has(run.state))
|
|
9629
|
+
return ['media_create'];
|
|
9630
|
+
return ['media_inspect'];
|
|
9631
|
+
}
|
|
9632
|
+
function candidateView(candidate) {
|
|
9633
|
+
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 } : {}));
|
|
9634
|
+
}
|
|
9635
|
+
function mediaAgentTools(appId, client = {
|
|
9636
|
+
submit: submit,
|
|
9637
|
+
get: get,
|
|
9638
|
+
decideGate: decideGate,
|
|
9639
|
+
media: media,
|
|
9640
|
+
mediaDownloadUrl: mediaDownloadUrl,
|
|
9641
|
+
}) {
|
|
9642
|
+
const run = async (runId) => (await client.get(appId, runId)).run;
|
|
9643
|
+
const submit = async (options) => {
|
|
9644
|
+
try {
|
|
9645
|
+
const submitted = await client.submit(appId, options);
|
|
9646
|
+
return { ok: true, data: { runId: submitted.runId, status: submitted.status }, next: ['media_inspect'] };
|
|
9647
|
+
}
|
|
9648
|
+
catch (error) {
|
|
9649
|
+
return failure(error);
|
|
9650
|
+
}
|
|
9651
|
+
};
|
|
9652
|
+
/** The open design review of a run, or the refusal that explains why there is none. */
|
|
9653
|
+
const openReview = async (input) => {
|
|
9654
|
+
var _a;
|
|
9655
|
+
const runId = text(input.runId, 128);
|
|
9656
|
+
if (!runId)
|
|
9657
|
+
return refuse('input_invalid', 'runId is required.');
|
|
9658
|
+
let current;
|
|
9659
|
+
try {
|
|
9660
|
+
current = await run(runId);
|
|
9661
|
+
}
|
|
9662
|
+
catch (error) {
|
|
9663
|
+
return failure(error);
|
|
9664
|
+
}
|
|
9665
|
+
const gate = (_a = current.design) === null || _a === void 0 ? void 0 : _a.gate;
|
|
9666
|
+
if (!gate) {
|
|
9667
|
+
return refuse('no_open_review', `Run ${runId} is ${current.state}${current.parkReason ? ` (${current.parkReason})` : ''}; no design round is waiting for a decision.`, nextFor(current));
|
|
9668
|
+
}
|
|
9669
|
+
return { run: current, gateId: gate.gateId };
|
|
9670
|
+
};
|
|
9671
|
+
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); };
|
|
9672
|
+
return [
|
|
9673
|
+
{
|
|
9674
|
+
name: 'media_create',
|
|
9675
|
+
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).',
|
|
9676
|
+
inputSchema: {
|
|
9677
|
+
type: 'object',
|
|
9678
|
+
additionalProperties: false,
|
|
9679
|
+
required: ['kind', 'prompt', 'idempotencyKey'],
|
|
9680
|
+
properties: {
|
|
9681
|
+
kind: { type: 'string', enum: ['image', 'video'] },
|
|
9682
|
+
prompt: { type: 'string', minLength: 1, maxLength: 4000, description: 'What to make.' },
|
|
9683
|
+
spec: SPEC,
|
|
9684
|
+
forkOf: {
|
|
9685
|
+
type: 'object',
|
|
9686
|
+
additionalProperties: false,
|
|
9687
|
+
required: ['assetId', 'releaseId'],
|
|
9688
|
+
properties: { assetId: { type: 'string' }, releaseId: { type: 'string' } },
|
|
9689
|
+
description: 'A retained release of this app to start from.',
|
|
9690
|
+
},
|
|
9691
|
+
idempotencyKey: KEY,
|
|
9692
|
+
},
|
|
9693
|
+
},
|
|
9694
|
+
async execute(raw) {
|
|
9695
|
+
const input = isRecord(raw) ? raw : {};
|
|
9696
|
+
const prompt = text(input.prompt, 4000);
|
|
9697
|
+
const key = text(input.idempotencyKey, 256);
|
|
9698
|
+
if ((input.kind !== 'image' && input.kind !== 'video') || !prompt || !key) {
|
|
9699
|
+
return refuse('input_invalid', 'kind (image or video), prompt and idempotencyKey are required.', []);
|
|
9700
|
+
}
|
|
9701
|
+
return submit({
|
|
9702
|
+
operation: 'create',
|
|
9703
|
+
prompt,
|
|
9704
|
+
deliverable: Object.assign(Object.assign({ kind: input.kind }, (isRecord(input.spec) ? { spec: input.spec } : {})), (isRecord(input.forkOf) ? { forkOf: input.forkOf } : {})),
|
|
9705
|
+
idempotencyKey: key,
|
|
9706
|
+
});
|
|
9707
|
+
},
|
|
9708
|
+
},
|
|
9709
|
+
{
|
|
9710
|
+
name: 'media_edit',
|
|
9711
|
+
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.',
|
|
9712
|
+
inputSchema: {
|
|
9713
|
+
type: 'object',
|
|
9714
|
+
additionalProperties: false,
|
|
9715
|
+
required: ['kind', 'assetId', 'expectedReleaseId', 'prompt', 'idempotencyKey'],
|
|
9716
|
+
properties: {
|
|
9717
|
+
kind: { type: 'string', enum: ['image', 'video'] },
|
|
9718
|
+
assetId: { type: 'string' },
|
|
9719
|
+
expectedReleaseId: { type: 'string' },
|
|
9720
|
+
prompt: { type: 'string', minLength: 1, maxLength: 4000, description: 'The change to make.' },
|
|
9721
|
+
spec: SPEC,
|
|
9722
|
+
idempotencyKey: KEY,
|
|
9723
|
+
},
|
|
9724
|
+
},
|
|
9725
|
+
async execute(raw) {
|
|
9726
|
+
const input = isRecord(raw) ? raw : {};
|
|
9727
|
+
const prompt = text(input.prompt, 4000);
|
|
9728
|
+
const key = text(input.idempotencyKey, 256);
|
|
9729
|
+
const assetId = text(input.assetId, 128);
|
|
9730
|
+
const expectedReleaseId = text(input.expectedReleaseId, 128);
|
|
9731
|
+
if ((input.kind !== 'image' && input.kind !== 'video') || !prompt || !key || !assetId || !expectedReleaseId) {
|
|
9732
|
+
return refuse('input_invalid', 'kind, assetId, expectedReleaseId, prompt and idempotencyKey are required.', []);
|
|
9733
|
+
}
|
|
9734
|
+
return submit({
|
|
9735
|
+
operation: 'edit',
|
|
9736
|
+
prompt,
|
|
9737
|
+
deliverable: Object.assign({ kind: input.kind, assetId,
|
|
9738
|
+
expectedReleaseId }, (isRecord(input.spec) ? { spec: input.spec } : {})),
|
|
9739
|
+
idempotencyKey: key,
|
|
9740
|
+
});
|
|
9741
|
+
},
|
|
9742
|
+
},
|
|
9743
|
+
{
|
|
9744
|
+
name: 'media_inspect',
|
|
9745
|
+
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.',
|
|
9746
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['runId'], properties: { runId: RUN_ID } },
|
|
9747
|
+
async execute(raw) {
|
|
9748
|
+
var _a, _b, _c, _d, _e;
|
|
9749
|
+
const runId = text(isRecord(raw) ? raw.runId : undefined, 128);
|
|
9750
|
+
if (!runId)
|
|
9751
|
+
return refuse('input_invalid', 'runId is required.', []);
|
|
9752
|
+
try {
|
|
9753
|
+
const current = await run(runId);
|
|
9754
|
+
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); });
|
|
9755
|
+
const media = current.state === 'promoted' || current.media ? await client.media(appId, runId) : undefined;
|
|
9756
|
+
return {
|
|
9757
|
+
ok: true,
|
|
9758
|
+
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
|
|
9759
|
+
? 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'
|
|
9760
|
+
? { waitingFor: 'funding: the payer adds funds and, where top-up is unavailable (topup_unavailable_payer_shard), submits the build again; an agent cannot' }
|
|
9761
|
+
: {})), (media ? { media: media.media, asset: media.asset } : {})),
|
|
9762
|
+
next: nextFor(current),
|
|
9763
|
+
};
|
|
9764
|
+
}
|
|
9765
|
+
catch (error) {
|
|
9766
|
+
return failure(error);
|
|
9767
|
+
}
|
|
9768
|
+
},
|
|
9769
|
+
},
|
|
9770
|
+
{
|
|
9771
|
+
name: 'media_revise',
|
|
9772
|
+
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.',
|
|
9773
|
+
inputSchema: {
|
|
9774
|
+
type: 'object',
|
|
9775
|
+
additionalProperties: false,
|
|
9776
|
+
required: ['runId', 'feedback', 'idempotencyKey'],
|
|
9777
|
+
properties: {
|
|
9778
|
+
runId: RUN_ID,
|
|
9779
|
+
feedback: { type: 'string', minLength: 1, maxLength: 4000, description: 'What to change.' },
|
|
9780
|
+
candidateId: { type: 'string', description: 'The candidate to revise; without it the whole round is redone from the feedback.' },
|
|
9781
|
+
sceneIds: { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 6 },
|
|
9782
|
+
region: REGION,
|
|
9783
|
+
idempotencyKey: KEY,
|
|
9784
|
+
},
|
|
9785
|
+
},
|
|
9786
|
+
async execute(raw) {
|
|
9787
|
+
var _a, _b;
|
|
9788
|
+
const input = isRecord(raw) ? raw : {};
|
|
9789
|
+
const feedback = text(input.feedback, 4000);
|
|
9790
|
+
const key = text(input.idempotencyKey, 256);
|
|
9791
|
+
if (!feedback || !key)
|
|
9792
|
+
return refuse('input_invalid', 'runId, feedback and idempotencyKey are required.', []);
|
|
9793
|
+
const review = await openReview(input);
|
|
9794
|
+
if ('ok' in review)
|
|
9795
|
+
return review;
|
|
9796
|
+
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'))) {
|
|
9797
|
+
return refuse('decision_not_allowed', 'This round takes no revision (it may be the last one): select a candidate instead.', ['media_select']);
|
|
9798
|
+
}
|
|
9799
|
+
const candidate = input.candidateId === undefined ? undefined : candidateOf(review.run, input.candidateId);
|
|
9800
|
+
if (input.candidateId !== undefined && !candidate) {
|
|
9801
|
+
return refuse('candidate_unknown', `No candidate ${String(input.candidateId)} in the round under review.`, ['media_inspect']);
|
|
9802
|
+
}
|
|
9803
|
+
const sceneIds = Array.isArray(input.sceneIds) ? input.sceneIds.filter((id) => typeof id === 'string') : undefined;
|
|
9804
|
+
if (sceneIds && (!(candidate === null || candidate === void 0 ? void 0 : candidate.scenes) || !sceneIds.every((id) => candidate.scenes.some((scene) => scene.id === id)))) {
|
|
9805
|
+
return refuse('scenes_unknown', 'sceneIds must name scenes of the multi-scene candidate being revised (candidateId).', ['media_inspect']);
|
|
9806
|
+
}
|
|
9807
|
+
const area = input.region === undefined ? undefined : region(input.region);
|
|
9808
|
+
if (input.region !== undefined
|
|
9809
|
+
&& (!area || (candidate === null || candidate === void 0 ? void 0 : candidate.mimeType) !== 'image/png' || area.x + area.width > candidate.width || area.y + area.height > candidate.height)) {
|
|
9810
|
+
return refuse('region_invalid', 'region must lie inside the PNG candidate being revised (candidateId).', ['media_inspect']);
|
|
9811
|
+
}
|
|
9812
|
+
try {
|
|
9813
|
+
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 }));
|
|
9814
|
+
return { ok: true, data: { runId: review.run.runId, state: decided.state }, next: ['media_inspect'] };
|
|
9815
|
+
}
|
|
9816
|
+
catch (error) {
|
|
9817
|
+
return failure(error);
|
|
9818
|
+
}
|
|
9819
|
+
},
|
|
9820
|
+
},
|
|
9821
|
+
{
|
|
9822
|
+
name: 'media_select',
|
|
9823
|
+
description: 'Choose a candidate of the round under review. The chosen candidate is what the build releases, through the app\'s landing policy.',
|
|
9824
|
+
inputSchema: {
|
|
9825
|
+
type: 'object',
|
|
9826
|
+
additionalProperties: false,
|
|
9827
|
+
required: ['runId', 'candidateId', 'idempotencyKey'],
|
|
9828
|
+
properties: { runId: RUN_ID, candidateId: { type: 'string' }, idempotencyKey: KEY },
|
|
9829
|
+
},
|
|
9830
|
+
async execute(raw) {
|
|
9831
|
+
const input = isRecord(raw) ? raw : {};
|
|
9832
|
+
const key = text(input.idempotencyKey, 256);
|
|
9833
|
+
if (!key)
|
|
9834
|
+
return refuse('input_invalid', 'runId, candidateId and idempotencyKey are required.', []);
|
|
9835
|
+
const review = await openReview(input);
|
|
9836
|
+
if ('ok' in review)
|
|
9837
|
+
return review;
|
|
9838
|
+
const candidate = candidateOf(review.run, input.candidateId);
|
|
9839
|
+
if (!candidate)
|
|
9840
|
+
return refuse('candidate_unknown', `No candidate ${String(input.candidateId)} in the round under review.`, ['media_inspect']);
|
|
9841
|
+
try {
|
|
9842
|
+
const decided = await client.decideGate(appId, review.run.runId, review.gateId, {
|
|
9843
|
+
decision: 'approve',
|
|
9844
|
+
selectedArtifactId: candidate.id,
|
|
9845
|
+
idempotencyKey: key,
|
|
9846
|
+
});
|
|
9847
|
+
return { ok: true, data: { runId: review.run.runId, state: decided.state, selectedArtifactId: candidate.id }, next: ['media_propose', 'media_inspect'] };
|
|
9848
|
+
}
|
|
9849
|
+
catch (error) {
|
|
9850
|
+
return failure(error);
|
|
9851
|
+
}
|
|
9852
|
+
},
|
|
9853
|
+
},
|
|
9854
|
+
{
|
|
9855
|
+
name: 'media_export',
|
|
9856
|
+
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.',
|
|
9857
|
+
inputSchema: {
|
|
9858
|
+
type: 'object',
|
|
9859
|
+
additionalProperties: false,
|
|
9860
|
+
required: ['runId', 'artifactId'],
|
|
9861
|
+
properties: { runId: RUN_ID, artifactId: { type: 'string' } },
|
|
9862
|
+
},
|
|
9863
|
+
async execute(raw) {
|
|
9864
|
+
var _a, _b;
|
|
9865
|
+
const input = isRecord(raw) ? raw : {};
|
|
9866
|
+
const runId = text(input.runId, 128);
|
|
9867
|
+
const artifactId = text(input.artifactId, 64);
|
|
9868
|
+
if (!runId || !artifactId)
|
|
9869
|
+
return refuse('input_invalid', 'runId and artifactId are required.', []);
|
|
9870
|
+
try {
|
|
9871
|
+
const view = await client.media(appId, runId);
|
|
9872
|
+
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);
|
|
9873
|
+
if (!artifact) {
|
|
9874
|
+
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']);
|
|
9875
|
+
}
|
|
9876
|
+
const signed = await client.mediaDownloadUrl(appId, runId, artifactId);
|
|
9877
|
+
return {
|
|
9878
|
+
ok: true,
|
|
9879
|
+
data: { runId, artifactId, url: signed.url, expiresAtMs: signed.expiresAtMs, sha256: artifact.sha256, mimeType: artifact.mimeType, bytes: artifact.bytes },
|
|
9880
|
+
next: ['media_inspect'],
|
|
9881
|
+
};
|
|
9882
|
+
}
|
|
9883
|
+
catch (error) {
|
|
9884
|
+
return failure(error);
|
|
9885
|
+
}
|
|
9886
|
+
},
|
|
9887
|
+
},
|
|
9888
|
+
{
|
|
9889
|
+
name: 'media_propose',
|
|
9890
|
+
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.',
|
|
9891
|
+
inputSchema: { type: 'object', additionalProperties: false, required: ['runId'], properties: { runId: RUN_ID } },
|
|
9892
|
+
async execute(raw) {
|
|
9893
|
+
var _a;
|
|
9894
|
+
const runId = text(isRecord(raw) ? raw.runId : undefined, 128);
|
|
9895
|
+
if (!runId)
|
|
9896
|
+
return refuse('input_invalid', 'runId is required.', []);
|
|
9897
|
+
try {
|
|
9898
|
+
const current = await run(runId);
|
|
9899
|
+
if (current.state === 'promoted') {
|
|
9900
|
+
const view = await client.media(appId, runId);
|
|
9901
|
+
return { ok: true, data: { runId, state: 'published', release: view.asset.currentRelease }, next: nextFor(current) };
|
|
9902
|
+
}
|
|
9903
|
+
if (current.state === 'parked' && current.parkReason === 'gate') {
|
|
9904
|
+
const gate = current.gates.find((entry) => !entry.decided);
|
|
9905
|
+
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'] };
|
|
9906
|
+
}
|
|
9907
|
+
if ((_a = current.design) === null || _a === void 0 ? void 0 : _a.gate) {
|
|
9908
|
+
return refuse('not_selected', 'Choose a candidate first (media_select); only a chosen candidate can be published.', ['media_select', 'media_revise']);
|
|
9909
|
+
}
|
|
9910
|
+
return refuse('not_proposable', `Run ${runId} is ${current.state}${current.parkReason ? ` (${current.parkReason})` : ''}; it has no candidate waiting for publication.`, nextFor(current));
|
|
9911
|
+
}
|
|
9912
|
+
catch (error) {
|
|
9913
|
+
return failure(error);
|
|
9914
|
+
}
|
|
9915
|
+
},
|
|
9916
|
+
},
|
|
9917
|
+
];
|
|
9918
|
+
}
|
|
9919
|
+
|
|
9685
9920
|
/**
|
|
9686
9921
|
* Registered first-party product surfaces only, with
|
|
9687
9922
|
* one exact Drafted exception for delegated review/decision routes. Other
|
|
@@ -9699,6 +9934,9 @@ const builds = {
|
|
|
9699
9934
|
uploadInput,
|
|
9700
9935
|
list: list$1,
|
|
9701
9936
|
watch,
|
|
9937
|
+
media,
|
|
9938
|
+
mediaDownloadUrl,
|
|
9939
|
+
rollbackMedia,
|
|
9702
9940
|
};
|
|
9703
9941
|
|
|
9704
9942
|
async function create(options = {}) {
|
|
@@ -10503,6 +10741,313 @@ function defaultInjectedEvmProvider() {
|
|
|
10503
10741
|
return null;
|
|
10504
10742
|
}
|
|
10505
10743
|
|
|
10744
|
+
/** Admission comes from an app-authenticated function invoking the Cloudflare
|
|
10745
|
+
* broadcast connector. No application membership is managed by this helper. */
|
|
10746
|
+
async function connectBroadcast(ticket, options) {
|
|
10747
|
+
var _a, _b, _c, _d;
|
|
10748
|
+
const url = new URL(ticket.url);
|
|
10749
|
+
if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))))
|
|
10750
|
+
throw new Error("Invalid broadcast URL");
|
|
10751
|
+
if (!/^[a-f0-9]{64}$/.test(ticket.token) || ticket.transport !== "webrtc-broadcast" || !Number.isFinite(ticket.expiresAt) || ticket.expiresAt <= Date.now()
|
|
10752
|
+
|| !Number.isInteger(ticket.maxSeconds) || ticket.maxSeconds < 15 || ticket.maxSeconds > 300
|
|
10753
|
+
|| !["publisher", "listener"].includes(ticket.role) || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted))
|
|
10754
|
+
throw new Error("Invalid or expired broadcast ticket");
|
|
10755
|
+
const publisher = ticket.role === "publisher";
|
|
10756
|
+
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]] : [];
|
|
10757
|
+
if (publisher && tracks.some(track => !track || track.readyState !== "live"))
|
|
10758
|
+
throw new Error("Microphone and assistant audio tracks are required");
|
|
10759
|
+
if (!publisher && !options.audio)
|
|
10760
|
+
throw new Error("Two playback elements are required");
|
|
10761
|
+
const peer = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.cloudflare.com:3478" }] });
|
|
10762
|
+
let stopped = false, stopPromise;
|
|
10763
|
+
let resolveClosed;
|
|
10764
|
+
const closed = new Promise(resolve => { resolveClosed = resolve; });
|
|
10765
|
+
let disconnectTimer;
|
|
10766
|
+
const request = async (method, body) => {
|
|
10767
|
+
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" }));
|
|
10768
|
+
if (!response.ok)
|
|
10769
|
+
throw new Error(`Broadcast request failed (${response.status})`);
|
|
10770
|
+
return response.json();
|
|
10771
|
+
};
|
|
10772
|
+
const connection = {
|
|
10773
|
+
closed,
|
|
10774
|
+
status: () => request("GET"),
|
|
10775
|
+
close() {
|
|
10776
|
+
var _a, _b;
|
|
10777
|
+
if (stopPromise)
|
|
10778
|
+
return stopPromise;
|
|
10779
|
+
stopped = true;
|
|
10780
|
+
clearTimeout(deadline);
|
|
10781
|
+
clearTimeout(disconnectTimer);
|
|
10782
|
+
peer.close();
|
|
10783
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", abort);
|
|
10784
|
+
tracks.forEach(t => t === null || t === void 0 ? void 0 : t.removeEventListener("ended", abort));
|
|
10785
|
+
(_b = options.audio) === null || _b === void 0 ? void 0 : _b.forEach(audio => { audio.pause(); audio.srcObject = null; });
|
|
10786
|
+
resolveClosed();
|
|
10787
|
+
// These tracks also belong to the primary voice connection. Closing the
|
|
10788
|
+
// broadcast must not stop the microphone or assistant's direct playback.
|
|
10789
|
+
stopPromise = (async () => {
|
|
10790
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
10791
|
+
try {
|
|
10792
|
+
await request("DELETE");
|
|
10793
|
+
return;
|
|
10794
|
+
}
|
|
10795
|
+
catch (error) {
|
|
10796
|
+
if (attempt === 2)
|
|
10797
|
+
throw error;
|
|
10798
|
+
await new Promise(resolve => setTimeout(resolve, 250 * (attempt + 1)));
|
|
10799
|
+
}
|
|
10800
|
+
}
|
|
10801
|
+
})();
|
|
10802
|
+
return stopPromise;
|
|
10803
|
+
},
|
|
10804
|
+
};
|
|
10805
|
+
const abort = () => { void connection.close().catch(() => { }); };
|
|
10806
|
+
const deadline = setTimeout(abort, ticket.maxSeconds * 1000);
|
|
10807
|
+
(_d = options.signal) === null || _d === void 0 ? void 0 : _d.addEventListener("abort", abort, { once: true });
|
|
10808
|
+
tracks.forEach(track => track === null || track === void 0 ? void 0 : track.addEventListener("ended", abort, { once: true }));
|
|
10809
|
+
let audioMids = [];
|
|
10810
|
+
peer.addEventListener("track", event => {
|
|
10811
|
+
var _a;
|
|
10812
|
+
const audio = (_a = options.audio) === null || _a === void 0 ? void 0 : _a[audioMids.indexOf(event.transceiver.mid || "")];
|
|
10813
|
+
if (!audio) {
|
|
10814
|
+
abort();
|
|
10815
|
+
return;
|
|
10816
|
+
}
|
|
10817
|
+
audio.srcObject = new MediaStream([event.track]);
|
|
10818
|
+
void audio.play().catch(abort);
|
|
10819
|
+
});
|
|
10820
|
+
peer.addEventListener("connectionstatechange", () => {
|
|
10821
|
+
clearTimeout(disconnectTimer);
|
|
10822
|
+
if (peer.connectionState === "failed")
|
|
10823
|
+
abort();
|
|
10824
|
+
else if (peer.connectionState === "disconnected")
|
|
10825
|
+
disconnectTimer = setTimeout(abort, 5000);
|
|
10826
|
+
});
|
|
10827
|
+
try {
|
|
10828
|
+
let result;
|
|
10829
|
+
if (publisher) {
|
|
10830
|
+
for (const track of tracks)
|
|
10831
|
+
peer.addTransceiver(track, { direction: "sendonly", sendEncodings: [{ maxBitrate: 32000 }] });
|
|
10832
|
+
await peer.setLocalDescription(await peer.createOffer());
|
|
10833
|
+
result = await request("POST", { sdp: peer.localDescription.sdp });
|
|
10834
|
+
if (stopped)
|
|
10835
|
+
throw new Error("Broadcast cancelled");
|
|
10836
|
+
await peer.setRemoteDescription(result.sessionDescription);
|
|
10837
|
+
}
|
|
10838
|
+
else {
|
|
10839
|
+
result = await request("POST", {});
|
|
10840
|
+
if (stopped)
|
|
10841
|
+
throw new Error("Broadcast cancelled");
|
|
10842
|
+
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) || ""; });
|
|
10843
|
+
if (audioMids.some(mid => !mid) || new Set(audioMids).size !== 2)
|
|
10844
|
+
throw new Error("Invalid broadcast audio tracks");
|
|
10845
|
+
await peer.setRemoteDescription(result.sessionDescription);
|
|
10846
|
+
await peer.setLocalDescription(await peer.createAnswer());
|
|
10847
|
+
await request("PUT", { sdp: peer.localDescription.sdp });
|
|
10848
|
+
}
|
|
10849
|
+
await new Promise((resolve, reject) => {
|
|
10850
|
+
var _a;
|
|
10851
|
+
const timer = setTimeout(() => done(new Error("Broadcast connection timed out")), 15000);
|
|
10852
|
+
const check = () => {
|
|
10853
|
+
if (stopped || ["failed", "closed"].includes(peer.connectionState))
|
|
10854
|
+
done(new Error("Broadcast connection ended"));
|
|
10855
|
+
else if (peer.connectionState === "connected")
|
|
10856
|
+
done();
|
|
10857
|
+
};
|
|
10858
|
+
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(); };
|
|
10859
|
+
peer.addEventListener("connectionstatechange", check);
|
|
10860
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.addEventListener("abort", check, { once: true });
|
|
10861
|
+
check();
|
|
10862
|
+
});
|
|
10863
|
+
if (stopped)
|
|
10864
|
+
throw new Error("Broadcast cancelled");
|
|
10865
|
+
return connection;
|
|
10866
|
+
}
|
|
10867
|
+
catch (error) {
|
|
10868
|
+
await connection.close().catch(() => { });
|
|
10869
|
+
throw error;
|
|
10870
|
+
}
|
|
10871
|
+
}
|
|
10872
|
+
|
|
10873
|
+
/** Attach browser media directly to the connector's provider. Bounded observes
|
|
10874
|
+
* usage independently; data-channel messages never count as billing receipts. */
|
|
10875
|
+
async function connectServiceSession(ticket, options) {
|
|
10876
|
+
var _a, _b, _c;
|
|
10877
|
+
const url = new URL(ticket.url);
|
|
10878
|
+
if (url.username || url.password || url.search || url.hash || (url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))))
|
|
10879
|
+
throw new Error("Invalid service session URL");
|
|
10880
|
+
if (!/^[a-f0-9]{64}$/.test(ticket.token) || ticket.transport !== "webrtc-session" || !Number.isFinite(ticket.expiresAt) || ticket.expiresAt <= Date.now())
|
|
10881
|
+
throw new Error("Invalid or expired service session ticket");
|
|
10882
|
+
if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted)
|
|
10883
|
+
throw new Error("Service session aborted");
|
|
10884
|
+
const peer = new RTCPeerConnection();
|
|
10885
|
+
const audioStream = new MediaStream();
|
|
10886
|
+
const channel = peer.createDataChannel("oai-events");
|
|
10887
|
+
let ready = false, finished = false, closing = false;
|
|
10888
|
+
let resolveClosed, rejectClosed;
|
|
10889
|
+
let resolveReady, rejectReady;
|
|
10890
|
+
let pollTimer;
|
|
10891
|
+
const closed = new Promise((resolve, reject) => { resolveClosed = resolve; rejectClosed = reject; });
|
|
10892
|
+
void closed.catch(() => { });
|
|
10893
|
+
const connected = new Promise((resolve, reject) => { resolveReady = resolve; rejectReady = reject; });
|
|
10894
|
+
void connected.catch(() => { });
|
|
10895
|
+
const request = async (method, body) => {
|
|
10896
|
+
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" }));
|
|
10897
|
+
if (!response.ok)
|
|
10898
|
+
throw new Error(`Service session request failed (${response.status})`);
|
|
10899
|
+
return response.json();
|
|
10900
|
+
};
|
|
10901
|
+
const cleanup = () => {
|
|
10902
|
+
var _a;
|
|
10903
|
+
clearTimeout(startTimer);
|
|
10904
|
+
clearTimeout(pollTimer);
|
|
10905
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", abort);
|
|
10906
|
+
options.stream.getTracks().forEach(track => track.stop());
|
|
10907
|
+
options.audio.pause();
|
|
10908
|
+
options.audio.srcObject = null;
|
|
10909
|
+
channel.close();
|
|
10910
|
+
peer.close();
|
|
10911
|
+
};
|
|
10912
|
+
const fail = (error) => {
|
|
10913
|
+
if (finished)
|
|
10914
|
+
return;
|
|
10915
|
+
finished = true;
|
|
10916
|
+
rejectReady(error);
|
|
10917
|
+
rejectClosed(error);
|
|
10918
|
+
cleanup();
|
|
10919
|
+
};
|
|
10920
|
+
const poll = async (until) => {
|
|
10921
|
+
if (finished)
|
|
10922
|
+
return;
|
|
10923
|
+
try {
|
|
10924
|
+
const state = await request("GET");
|
|
10925
|
+
if (state.state === "closed" && state.finalUsage === true && Number.isFinite(state.seconds) && state.seconds >= 0 && Number.isSafeInteger(state.chargedMicroUsd) && state.chargedMicroUsd >= 0) {
|
|
10926
|
+
finished = true;
|
|
10927
|
+
resolveClosed({ seconds: state.seconds, chargedMicroUsd: state.chargedMicroUsd, finalUsage: true });
|
|
10928
|
+
if (!ready)
|
|
10929
|
+
rejectReady(new Error("Service session ended before startup"));
|
|
10930
|
+
cleanup();
|
|
10931
|
+
return;
|
|
10932
|
+
}
|
|
10933
|
+
if (["waiting", "creating", "active"].includes(state.state))
|
|
10934
|
+
await request("DELETE");
|
|
10935
|
+
if (state.state === "attention") {
|
|
10936
|
+
fail(new Error("Service session requires reconciliation"));
|
|
10937
|
+
return;
|
|
10938
|
+
}
|
|
10939
|
+
}
|
|
10940
|
+
catch ( /* bounded retries; never invent a receipt after a network failure */_a) { /* bounded retries; never invent a receipt after a network failure */ }
|
|
10941
|
+
if (Date.now() >= until) {
|
|
10942
|
+
fail(new Error("Service session finalization unconfirmed; check session status"));
|
|
10943
|
+
return;
|
|
10944
|
+
}
|
|
10945
|
+
pollTimer = setTimeout(() => { void poll(until); }, 500);
|
|
10946
|
+
};
|
|
10947
|
+
const session = {
|
|
10948
|
+
audioStream,
|
|
10949
|
+
closed,
|
|
10950
|
+
send(event) {
|
|
10951
|
+
if (!ready || closing || finished || channel.readyState !== "open")
|
|
10952
|
+
throw new Error("Service session is not accepting messages");
|
|
10953
|
+
const json = JSON.stringify(event);
|
|
10954
|
+
if (new TextEncoder().encode(json).byteLength > 65536 || channel.bufferedAmount > 256000)
|
|
10955
|
+
throw new Error("Service session backpressure limit");
|
|
10956
|
+
channel.send(json);
|
|
10957
|
+
},
|
|
10958
|
+
close() {
|
|
10959
|
+
if (!closing && !finished) {
|
|
10960
|
+
closing = true;
|
|
10961
|
+
options.stream.getTracks().forEach(track => track.stop());
|
|
10962
|
+
options.audio.pause();
|
|
10963
|
+
options.audio.srcObject = null;
|
|
10964
|
+
// Keep WebRTC alive while the server collects final usage. HTTP close
|
|
10965
|
+
// also works when the provider data channel is already gone.
|
|
10966
|
+
void request("DELETE").catch(() => { }).then(() => poll(Date.now() + 45000));
|
|
10967
|
+
}
|
|
10968
|
+
return closed;
|
|
10969
|
+
},
|
|
10970
|
+
};
|
|
10971
|
+
const abort = () => { void session.close(); };
|
|
10972
|
+
const startTimer = setTimeout(() => { void request("DELETE").catch(() => { }); fail(new Error("Service session startup timed out")); }, 30000);
|
|
10973
|
+
(_b = options.signal) === null || _b === void 0 ? void 0 : _b.addEventListener("abort", abort, { once: true });
|
|
10974
|
+
peer.addEventListener("track", ({ track }) => { if (closing || finished)
|
|
10975
|
+
return; audioStream.addTrack(track); options.audio.srcObject = audioStream; void options.audio.play().catch(() => { void session.close(); fail(new Error("Audio playback was blocked")); }); });
|
|
10976
|
+
channel.addEventListener("message", ({ data }) => {
|
|
10977
|
+
var _a;
|
|
10978
|
+
if (finished || closing)
|
|
10979
|
+
return;
|
|
10980
|
+
let event;
|
|
10981
|
+
try {
|
|
10982
|
+
event = JSON.parse(String(data));
|
|
10983
|
+
}
|
|
10984
|
+
catch (_b) {
|
|
10985
|
+
return;
|
|
10986
|
+
}
|
|
10987
|
+
if ((event === null || event === void 0 ? void 0 : event.type) === "session.started" && !ready) {
|
|
10988
|
+
ready = true;
|
|
10989
|
+
clearTimeout(startTimer);
|
|
10990
|
+
resolveReady();
|
|
10991
|
+
}
|
|
10992
|
+
if ((event === null || event === void 0 ? void 0 : event.type) === "session.closed")
|
|
10993
|
+
void session.close();
|
|
10994
|
+
try {
|
|
10995
|
+
(_a = options.onEvent) === null || _a === void 0 ? void 0 : _a.call(options, event);
|
|
10996
|
+
}
|
|
10997
|
+
catch ( /* UI callback failure cannot own cleanup */_c) { /* UI callback failure cannot own cleanup */ }
|
|
10998
|
+
});
|
|
10999
|
+
peer.addEventListener("connectionstatechange", () => { if (["failed", "closed"].includes(peer.connectionState) && !finished)
|
|
11000
|
+
void session.close(); });
|
|
11001
|
+
channel.addEventListener("close", () => { if (!finished)
|
|
11002
|
+
void session.close(); });
|
|
11003
|
+
try {
|
|
11004
|
+
for (const track of options.stream.getAudioTracks())
|
|
11005
|
+
peer.addTrack(track, options.stream);
|
|
11006
|
+
if (!options.stream.getAudioTracks().length)
|
|
11007
|
+
throw new Error("An audio track is required");
|
|
11008
|
+
await peer.setLocalDescription(await peer.createOffer());
|
|
11009
|
+
if (peer.iceGatheringState !== "complete")
|
|
11010
|
+
await new Promise((resolve, reject) => {
|
|
11011
|
+
var _a;
|
|
11012
|
+
const timer = setTimeout(() => done(new Error("Service session ICE gathering timed out")), 10000);
|
|
11013
|
+
const done = (error) => {
|
|
11014
|
+
var _a;
|
|
11015
|
+
clearTimeout(timer);
|
|
11016
|
+
peer.removeEventListener("icegatheringstatechange", check);
|
|
11017
|
+
peer.removeEventListener("connectionstatechange", check);
|
|
11018
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.removeEventListener("abort", check);
|
|
11019
|
+
error ? reject(error) : resolve();
|
|
11020
|
+
};
|
|
11021
|
+
const check = () => {
|
|
11022
|
+
var _a;
|
|
11023
|
+
if (closing || finished || ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) || peer.connectionState === "closed")
|
|
11024
|
+
done(new Error("Service session aborted during ICE gathering"));
|
|
11025
|
+
else if (peer.iceGatheringState === "complete")
|
|
11026
|
+
done();
|
|
11027
|
+
};
|
|
11028
|
+
peer.addEventListener("icegatheringstatechange", check);
|
|
11029
|
+
peer.addEventListener("connectionstatechange", check);
|
|
11030
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.addEventListener("abort", check, { once: true });
|
|
11031
|
+
check();
|
|
11032
|
+
});
|
|
11033
|
+
if (closing || finished)
|
|
11034
|
+
throw new Error("Service session aborted before admission");
|
|
11035
|
+
if (!((_c = peer.localDescription) === null || _c === void 0 ? void 0 : _c.sdp.includes("\r\na=candidate:")))
|
|
11036
|
+
throw new Error("Service session has no usable ICE candidates");
|
|
11037
|
+
const answer = await request("POST", { sdp: peer.localDescription.sdp });
|
|
11038
|
+
if (closing || finished)
|
|
11039
|
+
throw new Error("Service session aborted during admission");
|
|
11040
|
+
await peer.setRemoteDescription({ type: "answer", sdp: answer.sdp });
|
|
11041
|
+
await connected;
|
|
11042
|
+
return session;
|
|
11043
|
+
}
|
|
11044
|
+
catch (error) {
|
|
11045
|
+
void request("DELETE").catch(() => { });
|
|
11046
|
+
fail(error instanceof Error ? error : new Error("Service session startup failed"));
|
|
11047
|
+
throw error;
|
|
11048
|
+
}
|
|
11049
|
+
}
|
|
11050
|
+
|
|
10506
11051
|
exports.BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA = BUILD_DELEGATED_REVIEW_CAPABILITY_SCHEMA;
|
|
10507
11052
|
exports.BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA = BUILD_REVIEW_CAPABILITY_REFRESH_SCHEMA;
|
|
10508
11053
|
exports.BUILD_REVIEW_CAPABILITY_SCHEMA = BUILD_REVIEW_CAPABILITY_SCHEMA;
|
|
@@ -10522,6 +11067,8 @@ exports.builds = builds;
|
|
|
10522
11067
|
exports.completeLoginFromRedirect = completeLoginFromRedirect;
|
|
10523
11068
|
exports.completeLoginInPopup = completeLoginInPopup;
|
|
10524
11069
|
exports.confirmAndCheckTransaction = confirmAndCheckTransaction;
|
|
11070
|
+
exports.connectBroadcast = connectBroadcast;
|
|
11071
|
+
exports.connectServiceSession = connectServiceSession;
|
|
10525
11072
|
exports.defaultInjectedEvmProvider = defaultInjectedEvmProvider;
|
|
10526
11073
|
exports.defaultInjectedProvider = defaultInjectedProvider;
|
|
10527
11074
|
exports.ensureSharedWalletLoginReady = ensureSharedWalletLoginReady;
|
|
@@ -10544,6 +11091,7 @@ exports.loginWithPrivy = loginWithPrivy;
|
|
|
10544
11091
|
exports.loginWithRedirect = loginWithRedirect;
|
|
10545
11092
|
exports.loginWithWallet = loginWithWallet;
|
|
10546
11093
|
exports.logout = logout;
|
|
11094
|
+
exports.mediaAgentTools = mediaAgentTools;
|
|
10547
11095
|
exports.normalizeSolanaRpcUrl = normalizeSolanaRpcUrl;
|
|
10548
11096
|
exports.onAuthLoadingChanged = onAuthLoadingChanged;
|
|
10549
11097
|
exports.onAuthStateChanged = onAuthStateChanged;
|
|
@@ -10571,4 +11119,4 @@ exports.useAuth = useAuth;
|
|
|
10571
11119
|
exports.useBuildRun = useBuildRun;
|
|
10572
11120
|
exports.useQuery = useQuery;
|
|
10573
11121
|
exports.waitForAuthReady = waitForAuthReady;
|
|
10574
|
-
//# sourceMappingURL=index-
|
|
11122
|
+
//# sourceMappingURL=index-Pyb2SLgv.js.map
|