@glyphteck/veyl 0.73.0 → 0.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account.js +524 -182
- package/dist/accountprofiles.js +1 -0
- package/dist/auth.js +3 -1
- package/dist/cli.js +745 -229
- package/dist/index.js +745 -229
- package/examples/bot-fleet/voice.js +4 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5855,7 +5855,7 @@ var init_canonical = __esm(() => {
|
|
|
5855
5855
|
});
|
|
5856
5856
|
|
|
5857
5857
|
// ../../core/config.js
|
|
5858
|
-
var MS_PER_SECOND = 1000, MINUTE_MS, HOUR_MS, DAY_MS, KIB_BYTES = 1024, MIB_BYTES, SATS_PER_BITCOIN = 100000000n, USERNAME_MAX_CHARS = 12, PASSWORD_MIN_CHARS = 15, PASSWORD_MAX_CHARS = 64, PASSWORD_MAX_BYTES, ACCOUNT_CONNECTION_SLOW_MS, ACCOUNT_CONNECTION_UNAVAILABLE_MS, ACCOUNT_CONNECTION_RETRY_MIN_MS, ACCOUNT_CONNECTION_RETRY_MAX_MS, AUTOLOCK_MIN_MINUTES = 1, AUTOLOCK_MAX_MINUTES = 60, BTC_PRICE_FALLBACK = 80000, CHAT_MESSAGE_EDIT_WINDOW_MS, CHAT_SEND_CONNECTION_WAIT_MS, CALL_SPEAKING_THRESHOLD = 0.02, CALL_SPEAKING_HOLD_MS = 320, LOCAL_CACHE_WRITE_DELAY_MS = 350, LOCAL_MEDIA_CACHE_MAX_BYTES, LOCAL_MEDIA_CACHE_MAX_ITEMS = 1000, LOCAL_MEDIA_ACCESS_TOUCH_MIN_MS, LOCAL_PROFILE_CACHE_MAX_ITEMS = 500, LOCAL_PROFILE_CACHE_MAX_AGE_MS, LOCAL_CHAT_CACHE_MAX_ITEMS = 1000, LOCAL_CHAT_MESSAGE_CACHE_MAX_VISIBLE = 1000, LOCAL_CHAT_MESSAGE_CACHE_WRITE_DELAY_MS = 2500, LOCAL_AVATAR_CACHE_MAX_BYTES, LOCAL_AVATAR_CACHE_MAX_AGE_MS, AVATAR_IMAGE_MAX_BYTES, AVATAR_IMAGE_QUALITY_ATTEMPTS, CHAT_AVATAR_IMAGE_MAX_BYTES, CHAT_AVATAR_REF_MAX_CHARS = 256, CHAT_MESSAGE_FILE_CACHE_MAX_BYTES, IDLE_CALLBACK_MIN_TIMEOUT_MS = 50, ATTACHMENT_CACHE_IDLE_TIMEOUT_MS = 2500, ATTACHMENT_CACHE_FALLBACK_DELAY_MS = 250, CHAT_UNSAVED_TTL_DAYS = 21, CHAT_UNSAVED_TTL_MS, CHAT_AFTER_SEEN_MS, CHAT_MEDIA_TTL_DAYS, CHAT_MEDIA_TTL_MS, CHAT_UPLOAD_MAX_BYTES, CHAT_AUDIO_TRANSCODE_BITRATE_BPS = 128000, CHAT_VIDEO_TRANSCODE_VIDEO_BITRATE_BPS = 3000000, CHAT_VIDEO_TRANSCODE_AUDIO_BITRATE_BPS, CHAT_MESSAGE_BATCH_SIZE = 40, CHAT_MESSAGE_QUERY_MAX_DOCS = 120, CHAT_MESSAGE_MUTATION_MAX_ITEMS = 256, CHAT_TTL_CLIENT_DELETE_GRACE_MS, CHAT_BATCH_CLEANUP_IDLE_TIMEOUT_MS = 1500, CHAT_BATCH_CLEANUP_IDLE_DELAY_MS = 250, CHAT_LIST_PAGE_SIZE = 20, CHAT_ADMISSION_CACHE_PEERS = 1024, CHAT_LIST_LIVE_COUNT, CHAT_INBOX_PING_PAGE_SIZE = 25, CHAT_INBOX_DISCOVERY_PARALLEL_CHATS, CHAT_INBOX_SETTLEMENT_PARALLEL_CHATS = 4, CHAT_INBOX_CURSOR_OVERLAP_MS, CHAT_LIST_CACHE_WRITE_DELAY_MS = 1500, CHAT_LIST_SNAPSHOT_COALESCE_MS = 80, CHAT_LIST_COMPLETE_SYNC_DELAY_MS = 250, CHAT_LIST_LISTENER_RETRY_MS = 1000, CHAT_TOP_WARM_COUNT = 0, CHAT_EAGER_WARM_COUNT = 0, CHAT_WARM_DELAY_MS = 3000, CHAT_WARM_BATCH_SIZE, CHAT_MESSAGE_VIEW_CACHE_SIZE = 30, CHAT_MEDIA_WARM_MESSAGES_PER_CHAT, CHAT_MEDIA_WARM_START_DELAY_MS = 600, CHAT_MEDIA_WARM_STEP_DELAY_MS = 120, CHAT_MEDIA_WARM_TYPES, CHAT_MEDIA_WARM_MAX_BYTES = 0, CHAT_READ_WRITE_INTERVAL_MS, CHAT_READ_WRITE_MAX_WAIT_MS, CHAT_LIVE_PING_INTERVAL_MS, CHAT_LIVE_SWEEP_INTERVAL_MS, CHAT_LIVE_STALE_AFTER_MS, LIVE_RECONNECT_MIN_MS = 500, LIVE_RECONNECT_MAX_MS, LIVE_RECONNECT_STABLE_MS, LIVE_READY_TIMEOUT_MS, CHAT_LIVE_TYPING_IDLE_MS, CHAT_LIVE_TYPING_RENEW_MS, CHAT_LIVE_COMPOSITION_HANDOFF_MS, CHAT_LIVE_READ_SEND_INTERVAL_MS = 120, CHAT_LIVE_READ_SEND_MAX_WAIT_MS = 500, CHAT_LIVE_READ_WRITE_INTERVAL_MS, CHAT_LIVE_READ_WRITE_MAX_WAIT_MS, CHAT_SEND_QUEUE_RATE_LIMIT_COUNT = 12, CHAT_SEND_QUEUE_RATE_LIMIT_WINDOW_MS, CHAT_SETTINGS_BODY_MAX_BYTES, CHAT_TITLE_STATE_MAX_CHARS = 128, CHAT_MANIFEST_MAX_BYTES, CHAT_RECEIPT_MAX_MEMBERS = 32, CHAT_ORDINARY_DELIVERY_MAX_MEMBERS = 128, CHAT_MAX_MEMBERS = 256, CHAT_LARGE_GROUP_MENTION_MAX_TARGETS = 16, CHAT_MAX_TEXT_CHARS = 2048, CHAT_TITLE_INPUT_MAX_CHARS = 16, CHAT_MAX_REACTIONS, SEARCH_DEBOUNCE_MS = 300, SEARCH_USERNAME_LIMIT = 15, SEARCH_ROLE_LIMIT = 15, RECENT_PEER_REFRESH_LIMIT = 50, RECENT_PEER_REFRESH_DELAY_MS = 250, RECENT_PEER_REFRESH_THROTTLE_MS = 120, BAN_REFRESH_GRACE_MS = 50, REQUEST_MONEY_MAX_SATS, WALLET_TRANSFER_POLL_MS, WALLET_ACTIVE_TRANSFER_REFRESH_MS, WALLET_CACHE_HYDRATE_DELAY_MS = 0, WALLET_BOOT_REFRESH_DELAY_MS = 500, WALLET_BOOT_CACHED_REFRESH_DELAY_MS = 2500, WALLET_REGTEST_DEPOSIT_CLAIM_POLL_MS, WALLET_MAINNET_DEPOSIT_CLAIM_POLL_MS, WALLET_BALANCE_EVENT_COALESCE_MS, WALLET_INCOMING_UPDATE_COALESCE_MS = 250, WALLET_AUTO_CLAIM_MAX_FEE_SATS = 5000, WALLET_CLAIM_PAGE_SIZE = 100, WALLET_PENDING_TRANSFER_CLAIM_BATCH_SIZE = 50, WALLET_PENDING_TRANSFER_STATUS_BATCH_SIZE = 2, WALLET_PENDING_TRANSFER_COLD_REFRESH_BATCH_SIZE = 50, WALLET_PENDING_TRANSFER_COLD_REFRESH_INTERVAL_MS, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_SMALL_QUEUE = 3, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_LARGE_QUEUE = 10, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_SMALL_SIZE = 2, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_LARGE_SIZE = 3, WALLET_PENDING_TRANSFER_SLOW_CLAIM_MS, WALLET_PENDING_TRANSFER_CLAIM_COOLDOWN_MS, WALLET_SDK_BACKGROUND_QUIET_MS, WALLET_RECENT_TRANSFER_LIMIT = 100, WALLET_TRANSFER_PAGE_LIMIT = 100, WALLET_TRANSFER_FETCH_THROTTLE_MS = 150, WALLET_PENDING_TRANSFER_CLAIM_RETRY_MS, WALLET_SENT_TRANSFER_REFRESH_DELAY_MS, WALLET_PENDING_TRANSFER_BOOT_GRACE_MS, WALLET_PENDING_TRANSFER_HOT_AGE_MS, WALLET_PENDING_TRANSFER_WARM_AGE_MS, WALLET_PENDING_TRANSFER_WARM_RETRY_MS, WALLET_PENDING_TRANSFER_STALE_RETRY_MS, WALLET_PENDING_TRANSFER_STUCK_RETRY_MS, WALLET_PENDING_TRANSFER_DORMANT_RETRY_MS, WALLET_TRANSFER_CACHE_WRITE_DELAY_MS;
|
|
5858
|
+
var MS_PER_SECOND = 1000, MINUTE_MS, HOUR_MS, DAY_MS, KIB_BYTES = 1024, MIB_BYTES, SATS_PER_BITCOIN = 100000000n, USERNAME_MAX_CHARS = 12, PASSWORD_MIN_CHARS = 15, PASSWORD_MAX_CHARS = 64, PASSWORD_MAX_BYTES, ACCOUNT_CONNECTION_SLOW_MS, ACCOUNT_CONNECTION_UNAVAILABLE_MS, ACCOUNT_CONNECTION_RETRY_MIN_MS, ACCOUNT_CONNECTION_RETRY_MAX_MS, AUTOLOCK_MIN_MINUTES = 1, AUTOLOCK_MAX_MINUTES = 60, BTC_PRICE_FALLBACK = 80000, CHAT_MESSAGE_EDIT_WINDOW_MS, CHAT_SEND_CONNECTION_WAIT_MS, CALL_SPEAKING_THRESHOLD = 0.02, CALL_SPEAKING_HOLD_MS = 320, LOCAL_CACHE_WRITE_DELAY_MS = 350, LOCAL_MEDIA_CACHE_MAX_BYTES, LOCAL_MEDIA_CACHE_MAX_ITEMS = 1000, LOCAL_MEDIA_ACCESS_TOUCH_MIN_MS, LOCAL_PROFILE_CACHE_MAX_ITEMS = 500, LOCAL_PROFILE_CACHE_MAX_AGE_MS, LOCAL_CHAT_CACHE_MAX_ITEMS = 1000, LOCAL_CHAT_MESSAGE_CACHE_MAX_VISIBLE = 1000, LOCAL_CHAT_MESSAGE_CACHE_WRITE_DELAY_MS = 2500, LOCAL_AVATAR_CACHE_MAX_BYTES, LOCAL_AVATAR_CACHE_MAX_AGE_MS, AVATAR_IMAGE_MAX_BYTES, AVATAR_IMAGE_QUALITY_ATTEMPTS, CHAT_AVATAR_IMAGE_MAX_BYTES, CHAT_AVATAR_REF_MAX_CHARS = 256, CHAT_MESSAGE_FILE_CACHE_MAX_BYTES, IDLE_CALLBACK_MIN_TIMEOUT_MS = 50, ATTACHMENT_CACHE_IDLE_TIMEOUT_MS = 2500, ATTACHMENT_CACHE_FALLBACK_DELAY_MS = 250, CHAT_UNSAVED_TTL_DAYS = 21, CHAT_UNSAVED_TTL_MS, CHAT_AFTER_SEEN_MS, CHAT_MEDIA_TTL_DAYS, CHAT_MEDIA_TTL_MS, CHAT_UPLOAD_MAX_BYTES, CHAT_AUDIO_TRANSCODE_BITRATE_BPS = 128000, CHAT_VIDEO_TRANSCODE_VIDEO_BITRATE_BPS = 3000000, CHAT_VIDEO_TRANSCODE_AUDIO_BITRATE_BPS, CHAT_MESSAGE_BATCH_SIZE = 40, CHAT_MESSAGE_QUERY_MAX_DOCS = 120, CHAT_MESSAGE_MUTATION_MAX_ITEMS = 256, CHAT_TTL_CLIENT_DELETE_GRACE_MS, CHAT_BATCH_CLEANUP_IDLE_TIMEOUT_MS = 1500, CHAT_BATCH_CLEANUP_IDLE_DELAY_MS = 250, CHAT_LIST_PAGE_SIZE = 20, CHAT_ADMISSION_CACHE_PEERS = 1024, CHAT_LIST_LIVE_COUNT, CHAT_INBOX_PING_PAGE_SIZE = 25, CHAT_INBOX_DISCOVERY_PARALLEL_CHATS, CHAT_INBOX_SETTLEMENT_PARALLEL_CHATS = 4, CHAT_INBOX_CURSOR_OVERLAP_MS, CHAT_LIST_CACHE_WRITE_DELAY_MS = 1500, CHAT_LIST_SNAPSHOT_COALESCE_MS = 80, CHAT_LIST_COMPLETE_SYNC_DELAY_MS = 250, CHAT_LIST_LISTENER_RETRY_MS = 1000, CHAT_TOP_WARM_COUNT = 0, CHAT_EAGER_WARM_COUNT = 0, CHAT_WARM_DELAY_MS = 3000, CHAT_WARM_BATCH_SIZE, CHAT_MESSAGE_VIEW_CACHE_SIZE = 30, CHAT_MEDIA_WARM_MESSAGES_PER_CHAT, CHAT_MEDIA_WARM_START_DELAY_MS = 600, CHAT_MEDIA_WARM_STEP_DELAY_MS = 120, CHAT_MEDIA_WARM_TYPES, CHAT_MEDIA_WARM_MAX_BYTES = 0, CHAT_READ_WRITE_INTERVAL_MS, CHAT_READ_WRITE_MAX_WAIT_MS, CHAT_LIVE_PING_INTERVAL_MS, CHAT_LIVE_SWEEP_INTERVAL_MS, CHAT_LIVE_STALE_AFTER_MS, LIVE_RECONNECT_MIN_MS = 500, LIVE_RECONNECT_MAX_MS, LIVE_RECONNECT_STABLE_MS, LIVE_READY_TIMEOUT_MS, CHAT_LIVE_TYPING_IDLE_MS, CHAT_LIVE_TYPING_RENEW_MS, CHAT_LIVE_COMPOSITION_HANDOFF_MS, CHAT_LIVE_READ_SEND_INTERVAL_MS = 120, CHAT_LIVE_READ_SEND_MAX_WAIT_MS = 500, CHAT_LIVE_READ_WRITE_INTERVAL_MS, CHAT_LIVE_READ_WRITE_MAX_WAIT_MS, CHAT_SEND_QUEUE_RATE_LIMIT_COUNT = 12, CHAT_SEND_QUEUE_RATE_LIMIT_WINDOW_MS, CHAT_SETTINGS_BODY_MAX_BYTES, CHAT_TITLE_STATE_MAX_CHARS = 128, CHAT_MANIFEST_MAX_BYTES, CHAT_RECEIPT_MAX_MEMBERS = 32, CHAT_ORDINARY_DELIVERY_MAX_MEMBERS = 128, CHAT_MAX_MEMBERS = 256, CHAT_LARGE_GROUP_MENTION_MAX_TARGETS = 16, CHAT_MAX_TEXT_CHARS = 2048, CHAT_TITLE_INPUT_MAX_CHARS = 16, CHAT_MAX_REACTIONS, SEARCH_DEBOUNCE_MS = 300, SEARCH_USERNAME_LIMIT = 15, SEARCH_ROLE_LIMIT = 15, RECENT_PEER_REFRESH_LIMIT = 50, RECENT_PEER_REFRESH_DELAY_MS = 250, RECENT_PEER_REFRESH_THROTTLE_MS = 120, BAN_REFRESH_GRACE_MS = 50, REQUEST_MONEY_MAX_SATS, WALLET_TRANSFER_POLL_MS, WALLET_ACTIVE_TRANSFER_REFRESH_MS, WALLET_CACHE_HYDRATE_DELAY_MS = 0, WALLET_BOOT_REFRESH_DELAY_MS = 500, WALLET_BOOT_CACHED_REFRESH_DELAY_MS = 2500, WALLET_REGTEST_DEPOSIT_CLAIM_POLL_MS, WALLET_MAINNET_DEPOSIT_CLAIM_POLL_MS, WALLET_BALANCE_EVENT_COALESCE_MS, WALLET_INCOMING_UPDATE_COALESCE_MS = 250, WALLET_AUTO_CLAIM_MAX_FEE_SATS = 5000, WALLET_CLAIM_PAGE_SIZE = 100, WALLET_PENDING_TRANSFER_CLAIM_BATCH_SIZE = 50, WALLET_PENDING_TRANSFER_STATUS_BATCH_SIZE = 2, WALLET_PENDING_TRANSFER_COLD_REFRESH_BATCH_SIZE = 50, WALLET_PENDING_TRANSFER_COLD_REFRESH_INTERVAL_MS, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_SMALL_QUEUE = 3, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_LARGE_QUEUE = 10, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_SMALL_SIZE = 2, WALLET_PENDING_TRANSFER_ADAPTIVE_BATCH_LARGE_SIZE = 3, WALLET_PENDING_TRANSFER_SLOW_CLAIM_MS, WALLET_PENDING_TRANSFER_CLAIM_COOLDOWN_MS, WALLET_SDK_BACKGROUND_QUIET_MS, WALLET_RECENT_TRANSFER_LIMIT = 100, WALLET_TRANSFER_PAGE_LIMIT = 100, WALLET_TRANSFER_FETCH_THROTTLE_MS = 150, WALLET_PENDING_TRANSFER_CLAIM_RETRY_MS, WALLET_SENT_TRANSFER_REFRESH_DELAY_MS, WALLET_PENDING_TRANSFER_BOOT_GRACE_MS, WALLET_PENDING_TRANSFER_HOT_AGE_MS, WALLET_PENDING_TRANSFER_WARM_AGE_MS, WALLET_PENDING_TRANSFER_WARM_RETRY_MS, WALLET_PENDING_TRANSFER_STALE_RETRY_MS, WALLET_PENDING_TRANSFER_STUCK_RETRY_MS, WALLET_PENDING_TRANSFER_DORMANT_RETRY_MS, WALLET_TRANSFER_CACHE_WRITE_DELAY_MS, BITCOIN_POLL_MS = 60000, BITCOIN_FETCH_TIMEOUT_MS = 8000, BITCOIN_FEES_MAX_AGE_MS;
|
|
5859
5859
|
var init_config = __esm(() => {
|
|
5860
5860
|
MINUTE_MS = 60 * MS_PER_SECOND;
|
|
5861
5861
|
HOUR_MS = 60 * MINUTE_MS;
|
|
@@ -5927,6 +5927,7 @@ var init_config = __esm(() => {
|
|
|
5927
5927
|
WALLET_PENDING_TRANSFER_STUCK_RETRY_MS = 10 * MINUTE_MS;
|
|
5928
5928
|
WALLET_PENDING_TRANSFER_DORMANT_RETRY_MS = HOUR_MS;
|
|
5929
5929
|
WALLET_TRANSFER_CACHE_WRITE_DELAY_MS = 3 * MS_PER_SECOND;
|
|
5930
|
+
BITCOIN_FEES_MAX_AGE_MS = 5 * 60000;
|
|
5930
5931
|
});
|
|
5931
5932
|
|
|
5932
5933
|
// ../../core/calls/wire.js
|
|
@@ -6835,7 +6836,7 @@ function getVeylDevWebOrigin(port) {
|
|
|
6835
6836
|
}
|
|
6836
6837
|
return `https://${domains.veylDev}:${value}`;
|
|
6837
6838
|
}
|
|
6838
|
-
var ROOT_DOMAIN = "glyphteck.com", VEYL_DEV_WEB_PORT_MIN = 3000, VEYL_DEV_WEB_PORT_MAX = 3015, domains, veylDevWebOrigins, origins, liveEndpoints, appDomains, appLinkDomains;
|
|
6839
|
+
var ROOT_DOMAIN = "glyphteck.com", VEYL_DEV_WEB_PORT_MIN = 3000, VEYL_DEV_WEB_PORT_MAX = 3015, domains, veylDevWebOrigins, origins, liveEndpoints, bitcoinEndpoint, appDomains, appLinkDomains;
|
|
6839
6840
|
var init_origins = __esm(() => {
|
|
6840
6841
|
domains = Object.freeze({
|
|
6841
6842
|
root: ROOT_DOMAIN,
|
|
@@ -6843,7 +6844,8 @@ var init_origins = __esm(() => {
|
|
|
6843
6844
|
veyl: `veyl.${ROOT_DOMAIN}`,
|
|
6844
6845
|
veylDev: `dev.veyl.${ROOT_DOMAIN}`,
|
|
6845
6846
|
live: `live.veyl.${ROOT_DOMAIN}`,
|
|
6846
|
-
liveDev: `live.dev.veyl.${ROOT_DOMAIN}
|
|
6847
|
+
liveDev: `live.dev.veyl.${ROOT_DOMAIN}`,
|
|
6848
|
+
bitcoin: `bitcoin.veyl.${ROOT_DOMAIN}`
|
|
6847
6849
|
});
|
|
6848
6850
|
veylDevWebOrigins = Object.freeze(Array.from({ length: VEYL_DEV_WEB_PORT_MAX - VEYL_DEV_WEB_PORT_MIN + 1 }, (_, index) => getVeylDevWebOrigin(VEYL_DEV_WEB_PORT_MIN + index)));
|
|
6849
6851
|
origins = Object.freeze({
|
|
@@ -6857,6 +6859,7 @@ var init_origins = __esm(() => {
|
|
|
6857
6859
|
prod: `wss://${domains.live}`,
|
|
6858
6860
|
dev: `wss://${domains.liveDev}`
|
|
6859
6861
|
});
|
|
6862
|
+
bitcoinEndpoint = `https://${domains.bitcoin}/current`;
|
|
6860
6863
|
appDomains = Object.freeze([
|
|
6861
6864
|
domains.veyl
|
|
6862
6865
|
]);
|
|
@@ -6950,9 +6953,14 @@ function normalizeSettings(settings, base = defaultSettings) {
|
|
|
6950
6953
|
};
|
|
6951
6954
|
next.autolock = normalizeAutolock(settings.autolock, current.autolock);
|
|
6952
6955
|
next.walletNetwork = normalizeWalletNetworkSetting(next.walletNetwork);
|
|
6956
|
+
next.peerAudio = normalizePeerAudio(settings.peerAudio, current.peerAudio);
|
|
6957
|
+
next.callAudio = normalizeCallAudio(settings.callAudio, current.callAudio);
|
|
6953
6958
|
if (!MONEY_FORMATS.includes(next.moneyFormat)) {
|
|
6954
6959
|
throw new Error("bad moneyFormat");
|
|
6955
6960
|
}
|
|
6961
|
+
if (!WEB_LAYOUTS.includes(next.webLayout)) {
|
|
6962
|
+
throw new Error("bad webLayout");
|
|
6963
|
+
}
|
|
6956
6964
|
if (typeof next.glass !== "boolean") {
|
|
6957
6965
|
throw new Error("glass must be boolean");
|
|
6958
6966
|
}
|
|
@@ -6976,14 +6984,42 @@ function normalizeSettings(settings, base = defaultSettings) {
|
|
|
6976
6984
|
}
|
|
6977
6985
|
return next;
|
|
6978
6986
|
}
|
|
6979
|
-
|
|
6987
|
+
function normalizeCallAudio(patch, base = defaultSettings.callAudio) {
|
|
6988
|
+
if (patch !== undefined && (!patch || typeof patch !== "object" || Array.isArray(patch)))
|
|
6989
|
+
throw new Error("bad call audio settings");
|
|
6990
|
+
const { muted, deafened } = { ...defaultSettings.callAudio, ...base, ...patch };
|
|
6991
|
+
if (typeof muted !== "boolean" || typeof deafened !== "boolean")
|
|
6992
|
+
throw new Error("bad call audio settings");
|
|
6993
|
+
return { muted, deafened };
|
|
6994
|
+
}
|
|
6995
|
+
function normalizePeerAudio(patch, base = {}) {
|
|
6996
|
+
if (patch === undefined)
|
|
6997
|
+
return base;
|
|
6998
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch))
|
|
6999
|
+
throw new Error("bad peer audio settings");
|
|
7000
|
+
const entries = new Map(Object.entries(base));
|
|
7001
|
+
for (const [chatPK, audio] of Object.entries(patch)) {
|
|
7002
|
+
if (!/^[a-f0-9]{64}$/u.test(chatPK) || !audio || typeof audio !== "object" || Array.isArray(audio)) {
|
|
7003
|
+
throw new Error("bad peer audio settings");
|
|
7004
|
+
}
|
|
7005
|
+
const { volume = 100, muted = false } = { ...entries.get(chatPK), ...audio };
|
|
7006
|
+
if (!Number.isFinite(volume) || volume < 1 || volume > 200 || typeof muted !== "boolean") {
|
|
7007
|
+
throw new Error("bad peer audio settings");
|
|
7008
|
+
}
|
|
7009
|
+
entries.set(chatPK, { volume, muted });
|
|
7010
|
+
}
|
|
7011
|
+
return Object.fromEntries(entries);
|
|
7012
|
+
}
|
|
7013
|
+
var SEND_ON_SCAN_ENABLED = false, WEB_LAYOUTS, WALLET_NETWORKS, defaultSettings;
|
|
6980
7014
|
var init_settings = __esm(() => {
|
|
6981
7015
|
init_config();
|
|
6982
7016
|
init_money();
|
|
6983
7017
|
init_network();
|
|
7018
|
+
WEB_LAYOUTS = ["floating", "sidebar"];
|
|
6984
7019
|
WALLET_NETWORKS = new Set([MAINNET_NETWORK, REGTEST_NETWORK]);
|
|
6985
7020
|
defaultSettings = {
|
|
6986
7021
|
glass: true,
|
|
7022
|
+
webLayout: "floating",
|
|
6987
7023
|
moneyFormat: "usd",
|
|
6988
7024
|
ghostWallet: true,
|
|
6989
7025
|
showChatPreviews: true,
|
|
@@ -6991,6 +7027,8 @@ var init_settings = __esm(() => {
|
|
|
6991
7027
|
confirmSend: false,
|
|
6992
7028
|
faceID: null,
|
|
6993
7029
|
walletNetwork: null,
|
|
7030
|
+
peerAudio: {},
|
|
7031
|
+
callAudio: { muted: false, deafened: false },
|
|
6994
7032
|
autolock: {
|
|
6995
7033
|
timer: "never",
|
|
6996
7034
|
onHide: false,
|
|
@@ -8109,6 +8147,9 @@ function normalizeBitcoinPaymentFeeQuote(feeQuote) {
|
|
|
8109
8147
|
};
|
|
8110
8148
|
}
|
|
8111
8149
|
function getFeeRateSatsPerVbyte(bitcoin, speed = DEFAULT_FEE_RATE_SPEED) {
|
|
8150
|
+
const observedAt = Date.parse(bitcoin?.fees?.updatedAtIso);
|
|
8151
|
+
if (!Number.isFinite(observedAt) || Date.now() - observedAt > BITCOIN_FEES_MAX_AGE_MS || observedAt > Date.now() + 60000)
|
|
8152
|
+
return null;
|
|
8112
8153
|
const rates = bitcoin?.fees?.satPerVbyte;
|
|
8113
8154
|
const key = String(speed || DEFAULT_FEE_RATE_SPEED);
|
|
8114
8155
|
const keys = FEE_RATE_FALLBACKS[key] ?? [key, ...FEE_RATE_FALLBACKS.default];
|
|
@@ -8209,6 +8250,7 @@ function normalizeLightningPaymentResult(result) {
|
|
|
8209
8250
|
}
|
|
8210
8251
|
var DEFAULT_EXIT_SPEED = "MEDIUM", EXIT_SPEEDS, UNILATERAL_EXIT_PARENT_TX_FALLBACK_VBYTES = 191, UNILATERAL_EXIT_FEE_BUMP_TX_VBYTES = 151, UNILATERAL_EXIT_PACKAGES_PER_LEAF = 2, UNILATERAL_EXIT_PREVIEW_VBYTES, DEFAULT_FEE_RATE_SPEED = "medium", FEE_RATE_FALLBACKS, BITCOIN_PAYMENT_FEE_FIELDS;
|
|
8211
8252
|
var init_fees = __esm(() => {
|
|
8253
|
+
init_config();
|
|
8212
8254
|
EXIT_SPEEDS = Object.freeze(["SLOW", "MEDIUM", "FAST"]);
|
|
8213
8255
|
UNILATERAL_EXIT_PREVIEW_VBYTES = UNILATERAL_EXIT_PACKAGES_PER_LEAF * (UNILATERAL_EXIT_PARENT_TX_FALLBACK_VBYTES + UNILATERAL_EXIT_FEE_BUMP_TX_VBYTES);
|
|
8214
8256
|
FEE_RATE_FALLBACKS = Object.freeze({
|
|
@@ -9375,6 +9417,9 @@ function readAccountType(profile) {
|
|
|
9375
9417
|
function hasPeerKeys(profile) {
|
|
9376
9418
|
return !!(profile?.walletPK || profile?.chatPK);
|
|
9377
9419
|
}
|
|
9420
|
+
function hasChatIdentity(profile) {
|
|
9421
|
+
return !!(profile?.uid && profile?.chatPK && profile?.chatSigningPK && profile?.notificationPK);
|
|
9422
|
+
}
|
|
9378
9423
|
function readProfileChatIdentity(profile) {
|
|
9379
9424
|
const chat = profile?.identities?.chat;
|
|
9380
9425
|
return {
|
|
@@ -9389,7 +9434,7 @@ function peerUid(peer) {
|
|
|
9389
9434
|
return typeof peer === "string" ? cleanText(peer) : cleanText(peer?.uid);
|
|
9390
9435
|
}
|
|
9391
9436
|
function isFullProfile(profile) {
|
|
9392
|
-
return !!(profile?.uid && (
|
|
9437
|
+
return !!(profile?.uid && hasPeerKeys(profile) && ["username", "walletPK", "chatPK", "chatSigningPK", "notificationPK"].every((key) => (key in profile)) && (!profile.chatPK || hasChatIdentity(profile)));
|
|
9393
9438
|
}
|
|
9394
9439
|
function normalizeProfile(profile, uid = profile?.uid || null) {
|
|
9395
9440
|
return {
|
|
@@ -9464,6 +9509,8 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
9464
9509
|
let authSession = 0;
|
|
9465
9510
|
let userUid = null;
|
|
9466
9511
|
let settingsKey = null;
|
|
9512
|
+
let settingsWriter = null;
|
|
9513
|
+
let openedSettingsBody;
|
|
9467
9514
|
let agreementStored = null;
|
|
9468
9515
|
let agreementOverride = null;
|
|
9469
9516
|
let agreementAcceptance = null;
|
|
@@ -9852,6 +9899,7 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
9852
9899
|
settingsBody: privateData.settings ?? null,
|
|
9853
9900
|
settingsFromCache: false
|
|
9854
9901
|
}));
|
|
9902
|
+
refreshUnlockedSettings();
|
|
9855
9903
|
}), current((error) => {
|
|
9856
9904
|
markError(diag, "user.settings.snapshot", authStartedAt, error);
|
|
9857
9905
|
if (revokeAuthenticationError(authUser, error, "settings-listener"))
|
|
@@ -10067,10 +10115,12 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
10067
10115
|
throw new Error("settings key required");
|
|
10068
10116
|
if (state.settingsBody === undefined)
|
|
10069
10117
|
throw new Error("settings not available");
|
|
10070
|
-
const
|
|
10118
|
+
const body = state.settingsBody;
|
|
10119
|
+
const nextSettings = body === null ? settingsState() : await openSettings(key, uid, body);
|
|
10071
10120
|
if (!isCurrentUser(uid, session))
|
|
10072
10121
|
return nextSettings;
|
|
10073
10122
|
setSettingsKey(key);
|
|
10123
|
+
openedSettingsBody = body;
|
|
10074
10124
|
setState((user) => ({
|
|
10075
10125
|
...user,
|
|
10076
10126
|
settings: settingsState(nextSettings)
|
|
@@ -10091,15 +10141,59 @@ function createUser({ cloud, network, avatarCache = null, diag = null, onSession
|
|
|
10091
10141
|
throw new Error("auth");
|
|
10092
10142
|
if (!settingsKey)
|
|
10093
10143
|
throw new Error("settings locked");
|
|
10094
|
-
|
|
10095
|
-
if (!
|
|
10096
|
-
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10144
|
+
normalizeSettings(patch, state.settings);
|
|
10145
|
+
if (!settingsWriter || settingsWriter.key !== settingsKey) {
|
|
10146
|
+
settingsWriter = { key: settingsKey, uid, session, pending: [], running: false };
|
|
10147
|
+
}
|
|
10148
|
+
const writer = settingsWriter;
|
|
10149
|
+
const result = new Promise((resolve, reject) => writer.pending.push({ patch, resolve, reject }));
|
|
10150
|
+
writeSettings(writer);
|
|
10151
|
+
return result;
|
|
10152
|
+
}
|
|
10153
|
+
async function writeSettings(writer) {
|
|
10154
|
+
if (writer.running)
|
|
10155
|
+
return;
|
|
10156
|
+
writer.running = true;
|
|
10157
|
+
const current = () => settingsKey === writer.key && isCurrentUser(writer.uid, writer.session);
|
|
10158
|
+
while (writer.pending.length) {
|
|
10159
|
+
const batch = writer.pending.splice(0);
|
|
10160
|
+
try {
|
|
10161
|
+
if (!current())
|
|
10162
|
+
throw new Error("settings locked");
|
|
10163
|
+
const desired = batch.reduce((settings2, { patch }) => normalizeSettings(patch, settings2), state.settings);
|
|
10164
|
+
const { settings, body } = await cloud.user.settings.write(writer.uid, desired, { currentSettings: state.settings, key: writer.key });
|
|
10165
|
+
if (!current())
|
|
10166
|
+
throw new Error("settings locked");
|
|
10167
|
+
openedSettingsBody = body;
|
|
10168
|
+
setState((user) => ({ ...user, settingsReady: true, settings: settingsState(settings), settingsBody: body }));
|
|
10169
|
+
for (const request of batch)
|
|
10170
|
+
request.resolve(settings);
|
|
10171
|
+
} catch (error) {
|
|
10172
|
+
for (const request of batch)
|
|
10173
|
+
request.reject(error);
|
|
10174
|
+
}
|
|
10175
|
+
}
|
|
10176
|
+
writer.running = false;
|
|
10177
|
+
if (settingsWriter === writer)
|
|
10178
|
+
settingsWriter = null;
|
|
10179
|
+
refreshUnlockedSettings();
|
|
10180
|
+
}
|
|
10181
|
+
async function refreshUnlockedSettings() {
|
|
10182
|
+
const key = settingsKey;
|
|
10183
|
+
const body = state.settingsBody;
|
|
10184
|
+
if (!key || body === undefined || body === openedSettingsBody || settingsWriter?.key === key)
|
|
10185
|
+
return;
|
|
10186
|
+
const uid = state.uid;
|
|
10187
|
+
try {
|
|
10188
|
+
const settings = body === null ? settingsState() : await openSettings(key, uid, body);
|
|
10189
|
+
if (settingsKey !== key || state.settingsBody !== body || settingsWriter?.key === key)
|
|
10190
|
+
return;
|
|
10191
|
+
openedSettingsBody = body;
|
|
10192
|
+
setState((user) => ({ ...user, settings: settingsState(settings) }));
|
|
10193
|
+
} catch (error) {
|
|
10194
|
+
if (settingsKey === key && state.settingsBody === body)
|
|
10195
|
+
markError(diag, "user.settings.open", Date.now(), error);
|
|
10196
|
+
}
|
|
10103
10197
|
}
|
|
10104
10198
|
function isBlocked(peer) {
|
|
10105
10199
|
const nextPeerUid = peerUid(peer);
|
|
@@ -26097,7 +26191,7 @@ function groupEvidence(messages, byKey, memberStatesByEpoch) {
|
|
|
26097
26191
|
const target = byKey.get(reference);
|
|
26098
26192
|
addEvidence(evidence, messageEpochId(target), actor, messageOrderMs(target), seenAt);
|
|
26099
26193
|
}
|
|
26100
|
-
if (canShowMsg(message)
|
|
26194
|
+
if (canShowMsg(message)) {
|
|
26101
26195
|
addEvidence(evidence, messageEpochId(message), actor, seenAt, seenAt);
|
|
26102
26196
|
}
|
|
26103
26197
|
}
|
|
@@ -26125,11 +26219,12 @@ function analyzeMessageExpiry(messages, selfChatPublicKey, _peerChatPublicKey, o
|
|
|
26125
26219
|
const shorten = [];
|
|
26126
26220
|
let nextExpiryAt = null;
|
|
26127
26221
|
const latestStart = latestCallStartKey(projectedMessages.filter(isServerConfirmedMsg));
|
|
26222
|
+
const endedCalls = new Set(projectedMessages.filter(isServerConfirmedMsg).filter((message) => readCallMessage(message)?.event === "ended").map((message) => message.callId));
|
|
26128
26223
|
for (const message of projectedMessages) {
|
|
26129
26224
|
if (!isServerConfirmedMsg(message) || !canShowMsg(message) || message.ttl == null)
|
|
26130
26225
|
continue;
|
|
26131
26226
|
const call = readCallMessage(message);
|
|
26132
|
-
if (call?.event === "started" && getMessageKey(message) === latestStart && (options.activeCallId === undefined || options.activeCallId === call.callId))
|
|
26227
|
+
if (call?.event === "started" && getMessageKey(message) === latestStart && (options.activeCallId === undefined && !endedCalls.has(call.callId) || options.activeCallId === call.callId))
|
|
26133
26228
|
continue;
|
|
26134
26229
|
const messageMs = messageOrderMs(message);
|
|
26135
26230
|
const epochId = messageEpochId(message);
|
|
@@ -27700,7 +27795,7 @@ function partitionExpiredMessageRecords(records, expiredKeys, cache, now = Date.
|
|
|
27700
27795
|
return { activeRecords, expiredRecords };
|
|
27701
27796
|
}
|
|
27702
27797
|
function canHideExpiredMessage(message, chatPK) {
|
|
27703
|
-
return isServerConfirmedMsg(message) && isPeerMsg(message, chatPK) && canShowMsg(message) &&
|
|
27798
|
+
return isServerConfirmedMsg(message) && isPeerMsg(message, chatPK) && canShowMsg(message) && message.ttl != null && message.permanent !== true;
|
|
27704
27799
|
}
|
|
27705
27800
|
function hiddenMessageKeys(messages, chatPK, peerChatPK, options = {}) {
|
|
27706
27801
|
if (!chatPK || !peerChatPK || !Array.isArray(messages) || !messages.length)
|
|
@@ -44129,27 +44224,23 @@ function createChatSessionLaunches({
|
|
|
44129
44224
|
const openDirectChat = async (profile) => {
|
|
44130
44225
|
const operation = operationContext();
|
|
44131
44226
|
const { chatPK, blocked } = operation.identity;
|
|
44132
|
-
|
|
44133
|
-
|
|
44227
|
+
if (!profile?.uid || !profile?.chatPK)
|
|
44228
|
+
throw new Error("peer identity required");
|
|
44229
|
+
if (profile.chatPK === chatPK)
|
|
44134
44230
|
return openNotesChat(operation);
|
|
44135
|
-
if (new Set(blocked).has(
|
|
44231
|
+
if (new Set(blocked).has(profile.uid))
|
|
44136
44232
|
throw new Error("blocked peer cannot be opened");
|
|
44137
44233
|
assertDirectAdmission(profile, operation);
|
|
44138
|
-
const existingChatId = getPeerChatId(
|
|
44234
|
+
const existingChatId = getPeerChatId(profile.chatPK, operation);
|
|
44139
44235
|
if (existingChatId) {
|
|
44140
44236
|
setSelectedChat(existingChatId);
|
|
44141
44237
|
return existingChatId;
|
|
44142
44238
|
}
|
|
44239
|
+
const member = { uid: profile.uid, chatPK: profile.chatPK };
|
|
44143
44240
|
const routeId = directRouteIdForPeer(member.chatPK, operation);
|
|
44144
44241
|
if (operation.pendingOwner.getPendingLaunch()?.id === routeId)
|
|
44145
44242
|
return routeId;
|
|
44146
|
-
operation.pendingOwner.showEmpty(routeId, [
|
|
44147
|
-
...member,
|
|
44148
|
-
username: profile?.username || null,
|
|
44149
|
-
avatar: profile?.avatar || null,
|
|
44150
|
-
accountType: profile?.accountType || null,
|
|
44151
|
-
chatAdmission: normalizeChatAdmission(profile?.chatAdmission)
|
|
44152
|
-
}], [member], "direct");
|
|
44243
|
+
operation.pendingOwner.showEmpty(routeId, [profile], [member], "direct");
|
|
44153
44244
|
const materialization = directMaterializations.get(routeId);
|
|
44154
44245
|
if (materialization && isCurrent(materialization.operation)) {
|
|
44155
44246
|
materialization.promise.then((chatId) => {
|
|
@@ -49837,6 +49928,11 @@ function openCallMailbox({ cloud, capability, endpoint, protocol, onChange, onEr
|
|
|
49837
49928
|
}
|
|
49838
49929
|
return Object.freeze({
|
|
49839
49930
|
getSnapshot: () => candidate || record,
|
|
49931
|
+
async ready() {
|
|
49932
|
+
const response = await channel.ready();
|
|
49933
|
+
await consume(response.record);
|
|
49934
|
+
return record;
|
|
49935
|
+
},
|
|
49840
49936
|
async read() {
|
|
49841
49937
|
const response = await channel.request({ type: "read", cursor, headDigest: record?.headDigest ?? null });
|
|
49842
49938
|
await consume(response.record);
|
|
@@ -49943,6 +50039,7 @@ function openAccountCallLease({ cloud, capability: accountCapability, endpoint,
|
|
|
49943
50039
|
let expiry2 = null;
|
|
49944
50040
|
let generation = 0;
|
|
49945
50041
|
let acquiring = false;
|
|
50042
|
+
let rotating = Promise.resolve();
|
|
49946
50043
|
const attempts = new Set;
|
|
49947
50044
|
const waiters = new Set;
|
|
49948
50045
|
const current = () => !closed;
|
|
@@ -50043,6 +50140,7 @@ function openAccountCallLease({ cloud, capability: accountCapability, endpoint,
|
|
|
50043
50140
|
async function grant(command) {
|
|
50044
50141
|
if (closed)
|
|
50045
50142
|
throw new Error("call lease closed");
|
|
50143
|
+
const requestedAt = clock();
|
|
50046
50144
|
const attempt = createCallLeaseAttempt(command, clock);
|
|
50047
50145
|
const started = generation;
|
|
50048
50146
|
attempts.add(attempt);
|
|
@@ -50062,6 +50160,8 @@ function openAccountCallLease({ cloud, capability: accountCapability, endpoint,
|
|
|
50062
50160
|
onLost?.();
|
|
50063
50161
|
}, Math.max(0, deadline.wallDeadline - Date.now()));
|
|
50064
50162
|
clearTimeout(renewal);
|
|
50163
|
+
const now = clock();
|
|
50164
|
+
const elapsed = Math.max(now.wall - requestedAt.wall, now.monotonic - requestedAt.monotonic);
|
|
50065
50165
|
renewal = setTimeout(() => {
|
|
50066
50166
|
if (!owned)
|
|
50067
50167
|
return;
|
|
@@ -50073,14 +50173,35 @@ function openAccountCallLease({ cloud, capability: accountCapability, endpoint,
|
|
|
50073
50173
|
onLost?.();
|
|
50074
50174
|
onError?.(error);
|
|
50075
50175
|
});
|
|
50076
|
-
}, 5000);
|
|
50176
|
+
}, Math.max(0, 5000 - elapsed));
|
|
50077
50177
|
return value;
|
|
50078
50178
|
} finally {
|
|
50079
50179
|
attempts.delete(attempt);
|
|
50080
50180
|
attempt.cancel();
|
|
50081
50181
|
}
|
|
50082
50182
|
}
|
|
50183
|
+
async function rotateMedia() {
|
|
50184
|
+
if (closed || acquiring || !owned || !renewalRemaining(generation))
|
|
50185
|
+
throw new Error("call ownership unavailable");
|
|
50186
|
+
const previous = stop();
|
|
50187
|
+
const started = generation;
|
|
50188
|
+
await request2({ type: "release", holder: endpoint.holder, revision: previous.revision });
|
|
50189
|
+
if (closed || started !== generation)
|
|
50190
|
+
throw new Error("call transfer cancelled");
|
|
50191
|
+
return grant({
|
|
50192
|
+
type: "claim",
|
|
50193
|
+
holder: endpoint.holder,
|
|
50194
|
+
expectedRevision: previous.revision,
|
|
50195
|
+
payload: previous.payload,
|
|
50196
|
+
takeover: false
|
|
50197
|
+
});
|
|
50198
|
+
}
|
|
50083
50199
|
return Object.freeze({
|
|
50200
|
+
rotateMedia() {
|
|
50201
|
+
const next = rotating.then(rotateMedia);
|
|
50202
|
+
rotating = next.catch(() => {});
|
|
50203
|
+
return next;
|
|
50204
|
+
},
|
|
50084
50205
|
async acquire(descriptor) {
|
|
50085
50206
|
if (closed)
|
|
50086
50207
|
throw new Error("call lease closed");
|
|
@@ -50089,7 +50210,7 @@ function openAccountCallLease({ cloud, capability: accountCapability, endpoint,
|
|
|
50089
50210
|
acquiring = true;
|
|
50090
50211
|
const started = generation;
|
|
50091
50212
|
try {
|
|
50092
|
-
await
|
|
50213
|
+
await accept((await channel.ready()).record);
|
|
50093
50214
|
const payload = await capability.seal(descriptor);
|
|
50094
50215
|
if (closed || started !== generation)
|
|
50095
50216
|
throw new Error("call transfer cancelled");
|
|
@@ -50534,7 +50655,7 @@ function openCallRoom({
|
|
|
50534
50655
|
pulseTimer = setTimeout(pulse, 1e4);
|
|
50535
50656
|
}
|
|
50536
50657
|
async function beginStart(create) {
|
|
50537
|
-
const record = await mailbox.
|
|
50658
|
+
const record = await mailbox.ready();
|
|
50538
50659
|
if (closed || departing)
|
|
50539
50660
|
throw cancelled2();
|
|
50540
50661
|
if (!create && !record?.head)
|
|
@@ -50693,7 +50814,7 @@ function createCallActivity({ holder, onSpeaking, now = Date.now, setTimer = set
|
|
|
50693
50814
|
return;
|
|
50694
50815
|
const admitted = new Map(peers.map((peer) => [peer.holder, peer]));
|
|
50695
50816
|
local = admitted.has(holder) && !muted && !deafened;
|
|
50696
|
-
direct = mode === "direct" && directPeer !== holder && admitted.has(directPeer)
|
|
50817
|
+
direct = mode === "direct" && directPeer !== holder && admitted.has(directPeer) ? directPeer : null;
|
|
50697
50818
|
const nextSources = new Map(local ? [[holder, "local"]] : []);
|
|
50698
50819
|
const nextRoutes2 = new Map;
|
|
50699
50820
|
const ambiguous = new Set;
|
|
@@ -50701,7 +50822,7 @@ function createCallActivity({ holder, onSpeaking, now = Date.now, setTimer = set
|
|
|
50701
50822
|
nextSources.set(direct, "direct");
|
|
50702
50823
|
if (mode === "group") {
|
|
50703
50824
|
for (const [id, mid] of received) {
|
|
50704
|
-
if (id === holder || !admitted.has(id) ||
|
|
50825
|
+
if (id === holder || !admitted.has(id) || typeof mid !== "string" || !mid)
|
|
50705
50826
|
continue;
|
|
50706
50827
|
if (nextRoutes2.has(mid)) {
|
|
50707
50828
|
nextSources.delete(nextRoutes2.get(mid));
|
|
@@ -50767,13 +50888,14 @@ var init_activity = __esm(() => {
|
|
|
50767
50888
|
});
|
|
50768
50889
|
|
|
50769
50890
|
// ../../core/calls/media.js
|
|
50770
|
-
function createCallMediaSession({ port, mode, holder, provider, signal, publish, onState, onError, onExpired, onSpeaking }) {
|
|
50891
|
+
function createCallMediaSession({ port, mode, holder, preparation, provider, signal, publish, onState, onError, onExpired, onSpeaking, diag }) {
|
|
50771
50892
|
let media = null;
|
|
50772
50893
|
let closed = false;
|
|
50773
50894
|
let deadline = null;
|
|
50774
50895
|
let keys = null;
|
|
50775
50896
|
let peers = [];
|
|
50776
50897
|
let sessionId = null;
|
|
50898
|
+
let published = false;
|
|
50777
50899
|
let started = false;
|
|
50778
50900
|
let directPeer = null;
|
|
50779
50901
|
let offered = false;
|
|
@@ -50896,7 +51018,11 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
50896
51018
|
for (const id of pendingPeerAudio.keys())
|
|
50897
51019
|
settlePeerAudio(id, new Error("call media closed"));
|
|
50898
51020
|
pendingSignals.length = incomingSignals.length = 0;
|
|
50899
|
-
const operations = [
|
|
51021
|
+
const operations = [
|
|
51022
|
+
disposeConnection(previous),
|
|
51023
|
+
retiringConnection,
|
|
51024
|
+
openingConnection?.then((opened) => opened !== previous ? disposeConnection(opened) : undefined, () => {})
|
|
51025
|
+
];
|
|
50900
51026
|
closing = Promise.allSettled(operations).then((results) => {
|
|
50901
51027
|
const failed = results.find((result) => result.status === "rejected");
|
|
50902
51028
|
if (failed)
|
|
@@ -50909,22 +51035,24 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
50909
51035
|
const live = () => !closed && generation === connectionGeneration;
|
|
50910
51036
|
await retiringConnection;
|
|
50911
51037
|
current(generation);
|
|
50912
|
-
|
|
50913
|
-
|
|
50914
|
-
|
|
50915
|
-
iceServers = configuration.iceServers;
|
|
50916
|
-
}
|
|
51038
|
+
const startedAt = Date.now();
|
|
51039
|
+
const prepared = preparation;
|
|
51040
|
+
preparation = null;
|
|
50917
51041
|
const opening = port.open({
|
|
50918
51042
|
id: holder,
|
|
50919
51043
|
mode,
|
|
50920
|
-
|
|
51044
|
+
preparation: prepared,
|
|
50921
51045
|
onState: (value) => {
|
|
50922
51046
|
if (!live())
|
|
50923
51047
|
return;
|
|
50924
51048
|
connectionState = value.state;
|
|
50925
|
-
if (connectionState === "connected")
|
|
51049
|
+
if (connectionState === "connected") {
|
|
50926
51050
|
settleConnection();
|
|
50927
|
-
|
|
51051
|
+
serialize(async () => {
|
|
51052
|
+
if (live())
|
|
51053
|
+
await media?.startSource?.();
|
|
51054
|
+
});
|
|
51055
|
+
} else if (["failed", "closed"].includes(connectionState))
|
|
50928
51056
|
settleConnection(new Error("call connection failed"));
|
|
50929
51057
|
onState?.(value);
|
|
50930
51058
|
},
|
|
@@ -50961,34 +51089,51 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
50961
51089
|
}
|
|
50962
51090
|
});
|
|
50963
51091
|
openingConnection = opening;
|
|
50964
|
-
|
|
51092
|
+
const preparing = opening.then(async (opened) => {
|
|
51093
|
+
current(generation);
|
|
51094
|
+
media = opened;
|
|
51095
|
+
await opened.mute(muted);
|
|
51096
|
+
current(generation);
|
|
51097
|
+
await opened.deafen(deafened);
|
|
51098
|
+
current(generation);
|
|
51099
|
+
if (microphoneVolume !== 1) {
|
|
51100
|
+
await opened.setMicrophoneVolume(microphoneVolume);
|
|
51101
|
+
current(generation);
|
|
51102
|
+
}
|
|
51103
|
+
await opened.prepare();
|
|
51104
|
+
current(generation);
|
|
51105
|
+
markDone(diag, "call.media.setup", startedAt, { stage: "local" });
|
|
51106
|
+
return opened;
|
|
51107
|
+
});
|
|
50965
51108
|
try {
|
|
50966
|
-
opened = await
|
|
50967
|
-
|
|
50968
|
-
|
|
50969
|
-
|
|
50970
|
-
|
|
50971
|
-
|
|
50972
|
-
|
|
51109
|
+
const [opened, configuration] = await Promise.all([
|
|
51110
|
+
preparing,
|
|
51111
|
+
Promise.resolve().then(() => iceServers ? { iceServers, sessionId } : provider(mode === "group" ? "session/new" : "turn", {})).then((value) => {
|
|
51112
|
+
current(generation);
|
|
51113
|
+
markDone(diag, "call.media.setup", startedAt, { stage: "provider" });
|
|
51114
|
+
return value;
|
|
51115
|
+
})
|
|
51116
|
+
]);
|
|
50973
51117
|
current(generation);
|
|
50974
|
-
|
|
50975
|
-
|
|
50976
|
-
|
|
50977
|
-
|
|
50978
|
-
await opened.deafen(deafened);
|
|
50979
|
-
current(generation);
|
|
50980
|
-
if (microphoneVolume !== 1) {
|
|
50981
|
-
await opened.setMicrophoneVolume(microphoneVolume);
|
|
51118
|
+
iceServers = configuration.iceServers;
|
|
51119
|
+
if (mode === "group")
|
|
51120
|
+
sessionId = configuration.sessionId;
|
|
51121
|
+
await opened.configure(iceServers);
|
|
50982
51122
|
current(generation);
|
|
50983
|
-
|
|
50984
|
-
|
|
50985
|
-
|
|
50986
|
-
|
|
50987
|
-
await
|
|
51123
|
+
if (deadline) {
|
|
51124
|
+
await opened.grant(deadline);
|
|
51125
|
+
current(generation);
|
|
51126
|
+
}
|
|
51127
|
+
await updateKeys();
|
|
50988
51128
|
current(generation);
|
|
51129
|
+
markDone(diag, "call.media.setup", startedAt, { stage: "ready" });
|
|
51130
|
+
} catch (error) {
|
|
51131
|
+
await disposeConnection(await opening.catch(() => null));
|
|
51132
|
+
throw error;
|
|
51133
|
+
} finally {
|
|
51134
|
+
if (openingConnection === opening)
|
|
51135
|
+
openingConnection = null;
|
|
50989
51136
|
}
|
|
50990
|
-
await updateKeys();
|
|
50991
|
-
current(generation);
|
|
50992
51137
|
}
|
|
50993
51138
|
async function applyDescription(result, required = false) {
|
|
50994
51139
|
current();
|
|
@@ -51051,10 +51196,7 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
51051
51196
|
if (!started || !keys)
|
|
51052
51197
|
return;
|
|
51053
51198
|
if (mode === "group") {
|
|
51054
|
-
if (!
|
|
51055
|
-
const session = await provider("session/new", {});
|
|
51056
|
-
current();
|
|
51057
|
-
sessionId = session.sessionId;
|
|
51199
|
+
if (!published) {
|
|
51058
51200
|
const offer = await media.offer();
|
|
51059
51201
|
current();
|
|
51060
51202
|
const sendMid = media.sendMid;
|
|
@@ -51073,48 +51215,15 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
51073
51215
|
current();
|
|
51074
51216
|
await connected();
|
|
51075
51217
|
current();
|
|
51076
|
-
await
|
|
51077
|
-
|
|
51078
|
-
|
|
51079
|
-
|
|
51080
|
-
|
|
51081
|
-
|
|
51082
|
-
|
|
51083
|
-
|
|
51084
|
-
|
|
51085
|
-
sessionId: peer.media.sessionId,
|
|
51086
|
-
trackName: peer.media.trackName
|
|
51087
|
-
})) });
|
|
51088
|
-
current();
|
|
51089
|
-
if (!Array.isArray(result.tracks) || result.tracks.length !== additions.length)
|
|
51090
|
-
throw new Error("peer audio subscription failed");
|
|
51091
|
-
const mappings = [];
|
|
51092
|
-
const occupied = new Set([media.sendMid, ...received.values()]);
|
|
51093
|
-
for (const peer of additions) {
|
|
51094
|
-
const track = result.tracks?.find((item) => item.sessionId === peer.media.sessionId && item.trackName === peer.media.trackName);
|
|
51095
|
-
if (!validMid(track?.mid) || track.errorCode || occupied.has(track.mid))
|
|
51096
|
-
throw new Error("peer audio subscription failed");
|
|
51097
|
-
occupied.add(track.mid);
|
|
51098
|
-
mappings.push([peer.holder, track.mid]);
|
|
51099
|
-
}
|
|
51100
|
-
for (const [peer, mid] of mappings)
|
|
51101
|
-
received.set(peer, mid);
|
|
51102
|
-
updateActivity();
|
|
51103
|
-
await applyPeerAudio();
|
|
51104
|
-
current();
|
|
51105
|
-
await updateKeys();
|
|
51106
|
-
current();
|
|
51107
|
-
await applyDescription(result);
|
|
51108
|
-
}
|
|
51109
|
-
const removals = [...received].filter(([peer]) => !peers.some((item) => item.holder === peer));
|
|
51110
|
-
if (removals.length) {
|
|
51111
|
-
for (const [peer] of removals)
|
|
51112
|
-
received.delete(peer);
|
|
51113
|
-
updateActivity();
|
|
51114
|
-
await updateKeys();
|
|
51115
|
-
current();
|
|
51116
|
-
const result = await provider("tracks/close", { sessionId, tracks: removals.map(([, mid]) => ({ mid })) });
|
|
51117
|
-
await applyDescription(result);
|
|
51218
|
+
await Promise.all([
|
|
51219
|
+
publish({ sessionId, trackName }).then(() => {
|
|
51220
|
+
current();
|
|
51221
|
+
published = true;
|
|
51222
|
+
}),
|
|
51223
|
+
receiveGroupTracks()
|
|
51224
|
+
]);
|
|
51225
|
+
} else {
|
|
51226
|
+
await receiveGroupTracks();
|
|
51118
51227
|
}
|
|
51119
51228
|
} else {
|
|
51120
51229
|
const peer = peers.find((item) => item.holder !== holder);
|
|
@@ -51142,6 +51251,48 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
51142
51251
|
}
|
|
51143
51252
|
}
|
|
51144
51253
|
}
|
|
51254
|
+
async function receiveGroupTracks() {
|
|
51255
|
+
const additions = peers.filter((peer) => peer.holder !== holder && peer.media?.sessionId && peer.media?.trackName && !received.has(peer.holder));
|
|
51256
|
+
if (additions.length) {
|
|
51257
|
+
await connected();
|
|
51258
|
+
current();
|
|
51259
|
+
const result = await provider("tracks/new", { sessionId, tracks: additions.map((peer) => ({
|
|
51260
|
+
location: "remote",
|
|
51261
|
+
sessionId: peer.media.sessionId,
|
|
51262
|
+
trackName: peer.media.trackName
|
|
51263
|
+
})) });
|
|
51264
|
+
current();
|
|
51265
|
+
if (!Array.isArray(result.tracks) || result.tracks.length !== additions.length)
|
|
51266
|
+
throw new Error("peer audio subscription failed");
|
|
51267
|
+
const mappings = [];
|
|
51268
|
+
const occupied = new Set([media.sendMid, ...received.values()]);
|
|
51269
|
+
for (const peer of additions) {
|
|
51270
|
+
const track = result.tracks?.find((item) => item.sessionId === peer.media.sessionId && item.trackName === peer.media.trackName);
|
|
51271
|
+
if (!validMid(track?.mid) || track.errorCode || occupied.has(track.mid))
|
|
51272
|
+
throw new Error("peer audio subscription failed");
|
|
51273
|
+
occupied.add(track.mid);
|
|
51274
|
+
mappings.push([peer.holder, track.mid]);
|
|
51275
|
+
}
|
|
51276
|
+
for (const [peer, mid] of mappings)
|
|
51277
|
+
received.set(peer, mid);
|
|
51278
|
+
updateActivity();
|
|
51279
|
+
await applyPeerAudio();
|
|
51280
|
+
current();
|
|
51281
|
+
await updateKeys();
|
|
51282
|
+
current();
|
|
51283
|
+
await applyDescription(result);
|
|
51284
|
+
}
|
|
51285
|
+
const removals = [...received].filter(([peer]) => !peers.some((item) => item.holder === peer));
|
|
51286
|
+
if (removals.length) {
|
|
51287
|
+
for (const [peer] of removals)
|
|
51288
|
+
received.delete(peer);
|
|
51289
|
+
updateActivity();
|
|
51290
|
+
await updateKeys();
|
|
51291
|
+
current();
|
|
51292
|
+
const result = await provider("tracks/close", { sessionId, tracks: removals.map(([, mid]) => ({ mid })) });
|
|
51293
|
+
await applyDescription(result);
|
|
51294
|
+
}
|
|
51295
|
+
}
|
|
51145
51296
|
return Object.freeze({
|
|
51146
51297
|
async open() {
|
|
51147
51298
|
current();
|
|
@@ -51197,13 +51348,19 @@ function createCallMediaSession({ port, mode, holder, provider, signal, publish,
|
|
|
51197
51348
|
},
|
|
51198
51349
|
mute(value) {
|
|
51199
51350
|
current();
|
|
51200
|
-
|
|
51351
|
+
const next = value === true;
|
|
51352
|
+
if (muted === next)
|
|
51353
|
+
return;
|
|
51354
|
+
muted = next;
|
|
51201
51355
|
updateActivity();
|
|
51202
51356
|
return media?.mute(muted);
|
|
51203
51357
|
},
|
|
51204
51358
|
deafen(value) {
|
|
51205
51359
|
current();
|
|
51206
|
-
|
|
51360
|
+
const next = value === true;
|
|
51361
|
+
if (deafened === next)
|
|
51362
|
+
return;
|
|
51363
|
+
deafened = next;
|
|
51207
51364
|
updateActivity();
|
|
51208
51365
|
return media?.deafen(deafened);
|
|
51209
51366
|
},
|
|
@@ -51394,7 +51551,7 @@ var init_observation = __esm(() => {
|
|
|
51394
51551
|
});
|
|
51395
51552
|
|
|
51396
51553
|
// ../../core/calls/session.js
|
|
51397
|
-
function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
51554
|
+
function createCallSession({ cloud, chat, media: mediaPort, mls, savePeerAudio, saveAudio, diag }) {
|
|
51398
51555
|
const listeners = new Set;
|
|
51399
51556
|
const discoveries = new Map;
|
|
51400
51557
|
const discoveryReads = new Map;
|
|
@@ -51402,11 +51559,16 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51402
51559
|
const retiring = new Set;
|
|
51403
51560
|
let state = initial();
|
|
51404
51561
|
const confirmedPeerAudio = new Map;
|
|
51562
|
+
const pendingPeerAudio = new Map;
|
|
51563
|
+
let peerAudioSource = null;
|
|
51564
|
+
let audioSource = normalizeCallAudio();
|
|
51565
|
+
let pendingAudio = null;
|
|
51405
51566
|
let identity = null;
|
|
51406
51567
|
let endpoint = null;
|
|
51407
51568
|
let leaseEndpoint = null;
|
|
51408
51569
|
let lease = null;
|
|
51409
51570
|
let active = null;
|
|
51571
|
+
let participation = null;
|
|
51410
51572
|
let focused = null;
|
|
51411
51573
|
let generation = 0;
|
|
51412
51574
|
let joinIntent = 0;
|
|
@@ -51481,6 +51643,8 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51481
51643
|
emit({ available: next });
|
|
51482
51644
|
}
|
|
51483
51645
|
function closeDiscovery(entry) {
|
|
51646
|
+
if ([...retiring].some((call2) => call2.discovery === entry))
|
|
51647
|
+
return;
|
|
51484
51648
|
entry.mailbox.close();
|
|
51485
51649
|
entry.observation?.close();
|
|
51486
51650
|
entry.observation = null;
|
|
@@ -51606,8 +51770,14 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51606
51770
|
throw Object.assign(new Error("chat unavailable"), { code: "unavailable" });
|
|
51607
51771
|
if (!epochState)
|
|
51608
51772
|
throw Object.assign(new Error("chat unavailable"), { code: "calls/chat-not-ready" });
|
|
51773
|
+
if (chat.getSnapshot().getOwnerChat(chatId)?.epochState?.manifest.epochId !== epochId)
|
|
51774
|
+
throw cancelled2();
|
|
51775
|
+
const existing = discoveries.get(chatId);
|
|
51609
51776
|
const entry = discovery(chatId, epochState);
|
|
51610
|
-
|
|
51777
|
+
if (entry === existing)
|
|
51778
|
+
await entry.mailbox.read();
|
|
51779
|
+
else
|
|
51780
|
+
await entry.mailbox.ready();
|
|
51611
51781
|
current(token);
|
|
51612
51782
|
return entry;
|
|
51613
51783
|
}).finally(() => {
|
|
@@ -51641,49 +51811,68 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51641
51811
|
prune();
|
|
51642
51812
|
};
|
|
51643
51813
|
}
|
|
51644
|
-
async function joinAttempt(chatId, intent, expectedCallId, onlyExisting) {
|
|
51814
|
+
async function joinAttempt(chatId, intent, expectedCallId, onlyExisting, continuation = null) {
|
|
51645
51815
|
if (!identity || !mediaPort || !mls || !cloud.calls)
|
|
51646
51816
|
throw new Error("calling unavailable");
|
|
51647
|
-
if (!foreground)
|
|
51648
|
-
throw new Error("open veyl to join a call");
|
|
51649
51817
|
if (active?.chatId === chatId)
|
|
51650
51818
|
return chatId;
|
|
51651
51819
|
const token = generation;
|
|
51652
51820
|
const startedAt = Date.now();
|
|
51653
51821
|
const step = (stage) => diag?.("call.join.stage", { stage, elapsedMs: Date.now() - startedAt });
|
|
51822
|
+
let preflightActive = true;
|
|
51654
51823
|
const check = () => {
|
|
51655
51824
|
current(token);
|
|
51656
|
-
if (intent !== joinIntent
|
|
51825
|
+
if (!preflightActive || intent !== joinIntent)
|
|
51657
51826
|
throw cancelled2();
|
|
51658
51827
|
};
|
|
51659
|
-
|
|
51660
|
-
|
|
51661
|
-
check();
|
|
51662
|
-
step("permission");
|
|
51663
|
-
if (!onlyExisting)
|
|
51664
|
-
chatId = await chat.getSnapshot().materializeChat(chatId);
|
|
51665
|
-
check();
|
|
51666
|
-
joining.chatId = chatId;
|
|
51667
|
-
step("chat");
|
|
51828
|
+
const operation = joining;
|
|
51829
|
+
let preparation;
|
|
51668
51830
|
let call2;
|
|
51669
51831
|
try {
|
|
51670
|
-
|
|
51671
|
-
|
|
51672
|
-
|
|
51832
|
+
emit({ ...!active && !continuation ? { phase: "joining", chatId } : {}, error: null });
|
|
51833
|
+
const permission = (async () => {
|
|
51834
|
+
const value = continuation ? undefined : await mediaPort.prepare?.();
|
|
51835
|
+
try {
|
|
51836
|
+
check();
|
|
51837
|
+
} catch (error) {
|
|
51838
|
+
value?.close();
|
|
51839
|
+
throw error;
|
|
51840
|
+
}
|
|
51841
|
+
preparation = value;
|
|
51842
|
+
operation.preparation = value;
|
|
51843
|
+
step("permission");
|
|
51844
|
+
})();
|
|
51845
|
+
const destination = (async () => {
|
|
51846
|
+
if (!onlyExisting && !continuation)
|
|
51847
|
+
chatId = await chat.getSnapshot().materializeChat(chatId);
|
|
51848
|
+
check();
|
|
51849
|
+
joining.chatId = chatId;
|
|
51850
|
+
step("chat");
|
|
51851
|
+
const epochState = continuation ? chat.getSnapshot().getOwnerChat(chatId)?.epochState : await chat.getSnapshot().prepareCall(chatId);
|
|
51852
|
+
check();
|
|
51853
|
+
if (!epochState)
|
|
51854
|
+
throw cancelled2();
|
|
51855
|
+
const entry2 = await readDiscovery(chatId, epochState);
|
|
51856
|
+
check();
|
|
51857
|
+
step("discovery");
|
|
51858
|
+
return entry2;
|
|
51859
|
+
})();
|
|
51860
|
+
const [, entry] = await Promise.all([permission, destination]);
|
|
51673
51861
|
check();
|
|
51674
51862
|
const discoveryRecord = entry.mailbox.getSnapshot();
|
|
51675
|
-
step("discovery");
|
|
51676
51863
|
const create = !entry.descriptor;
|
|
51677
51864
|
if (expectedCallId && (onlyExisting || entry.epochState.manifest.lineage === "direct") && entry.descriptor?.callId !== expectedCallId)
|
|
51678
51865
|
throw ended();
|
|
51679
51866
|
const descriptor = entry.descriptor || {
|
|
51680
|
-
callId: toHex(randomBytes3(32)),
|
|
51867
|
+
callId: continuation?.callId || toHex(randomBytes3(32)),
|
|
51681
51868
|
secret: toHex(randomBytes3(32)),
|
|
51682
51869
|
mode: entry.epochState.manifest.lineage,
|
|
51683
51870
|
participants: 1,
|
|
51684
|
-
startedAt: Date.now()
|
|
51871
|
+
startedAt: continuation?.startedAt ?? Date.now()
|
|
51685
51872
|
};
|
|
51686
|
-
|
|
51873
|
+
if (continuation && descriptor.callId !== continuation.callId)
|
|
51874
|
+
throw ended();
|
|
51875
|
+
const callEndpoint = continuation?.endpoint || createCallEndpoint();
|
|
51687
51876
|
call2 = {
|
|
51688
51877
|
chatId,
|
|
51689
51878
|
callId: descriptor.callId,
|
|
@@ -51704,6 +51893,7 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51704
51893
|
muteTail: Promise.resolve()
|
|
51705
51894
|
};
|
|
51706
51895
|
joining.candidate = call2;
|
|
51896
|
+
call2.owner = continuation?.owner || createLease(identity, callEndpoint);
|
|
51707
51897
|
const protocol = createCallProtocol({ realm: cloud.environment, epochState: entry.epochState, identity, endpoint: callEndpoint, callId: descriptor.callId });
|
|
51708
51898
|
call2.protocol = protocol;
|
|
51709
51899
|
const ownMember = (value) => {
|
|
@@ -51723,6 +51913,7 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51723
51913
|
if (!create)
|
|
51724
51914
|
cleanBytes(callMember.snapshot);
|
|
51725
51915
|
check();
|
|
51916
|
+
step("identity");
|
|
51726
51917
|
const admission = protocol.sign("join", { keyPackage: member.keyPackage ? encodeCallBytes(member.keyPackage) : "", signaturePK: toHex(member.signaturePK) });
|
|
51727
51918
|
const secret = fromHexBytes(descriptor.secret);
|
|
51728
51919
|
const capability = createCallCapability(secret, cloud.environment, "signaling", [descriptor.callId]);
|
|
@@ -51754,8 +51945,10 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51754
51945
|
};
|
|
51755
51946
|
call2.media = createCallMediaSession({
|
|
51756
51947
|
port: mediaPort,
|
|
51948
|
+
preparation,
|
|
51757
51949
|
mode: descriptor.mode,
|
|
51758
51950
|
holder: callEndpoint.holder,
|
|
51951
|
+
diag,
|
|
51759
51952
|
provider: (...args) => call2.owner.provider(...args),
|
|
51760
51953
|
signal: (...args) => call2.room.signal(...args),
|
|
51761
51954
|
publish: (value) => call2.room.publishMedia(value),
|
|
@@ -51770,6 +51963,8 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51770
51963
|
participants: call2.participants.length
|
|
51771
51964
|
});
|
|
51772
51965
|
if (value.state === "connected") {
|
|
51966
|
+
if (state.phase !== "connected")
|
|
51967
|
+
step("connected");
|
|
51773
51968
|
clearTimeout(call2.joinTimer);
|
|
51774
51969
|
call2.joinTimer = null;
|
|
51775
51970
|
emit({ phase: "connected", transport: value.transport || (descriptor.mode === "group" ? "relay" : null) });
|
|
@@ -51866,7 +52061,8 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51866
52061
|
throw error;
|
|
51867
52062
|
}
|
|
51868
52063
|
checkCall();
|
|
51869
|
-
|
|
52064
|
+
if (!continuation)
|
|
52065
|
+
announce(chatId, descriptor.callId, "started");
|
|
51870
52066
|
} else {
|
|
51871
52067
|
await entry.mailbox.read();
|
|
51872
52068
|
checkCall();
|
|
@@ -51876,16 +52072,21 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51876
52072
|
throw Object.assign(new Error("the call room changed"), { code: "calls/discovery-conflict" });
|
|
51877
52073
|
}
|
|
51878
52074
|
}
|
|
52075
|
+
step("publication");
|
|
51879
52076
|
call2.published = true;
|
|
51880
|
-
|
|
51881
|
-
|
|
51882
|
-
|
|
51883
|
-
|
|
52077
|
+
if (!continuation) {
|
|
52078
|
+
await stopCall();
|
|
52079
|
+
checkCall();
|
|
52080
|
+
mountLease(identity, callEndpoint, call2.owner);
|
|
52081
|
+
participation = { chatId, callId: descriptor.callId, startedAt: descriptor.startedAt, endpoint: callEndpoint, owner: lease };
|
|
52082
|
+
}
|
|
52083
|
+
step("predecessor");
|
|
52084
|
+
call2.owner = participation.owner;
|
|
51884
52085
|
active = call2;
|
|
51885
52086
|
observeRoster(entry);
|
|
51886
52087
|
available();
|
|
51887
52088
|
emit({
|
|
51888
|
-
phase: state.elsewhere ? "transferring" : "joining",
|
|
52089
|
+
phase: continuation ? "connecting" : state.elsewhere ? "transferring" : "joining",
|
|
51889
52090
|
chatId,
|
|
51890
52091
|
callId: descriptor.callId,
|
|
51891
52092
|
mode: descriptor.mode,
|
|
@@ -51898,7 +52099,10 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51898
52099
|
if (preference)
|
|
51899
52100
|
call2.media.setPeerAudio(peer.holder, { volume: preference.volume / 100, muted: preference.muted }).catch((error) => diag?.("call.peer.audio.error", { code: error?.code || "calls/audio" }));
|
|
51900
52101
|
}
|
|
51901
|
-
|
|
52102
|
+
if (continuation)
|
|
52103
|
+
await participation.owner.rotateMedia();
|
|
52104
|
+
else
|
|
52105
|
+
await lease.acquire({ chatId, callId: descriptor.callId });
|
|
51902
52106
|
check();
|
|
51903
52107
|
step("ownership");
|
|
51904
52108
|
if (!valid())
|
|
@@ -51958,6 +52162,11 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51958
52162
|
throw Object.assign(new Error("the call room is restarting"), { code: "calls/discovery-conflict" });
|
|
51959
52163
|
}
|
|
51960
52164
|
throw error;
|
|
52165
|
+
} finally {
|
|
52166
|
+
preflightActive = false;
|
|
52167
|
+
preparation?.close();
|
|
52168
|
+
if (operation.preparation === preparation)
|
|
52169
|
+
operation.preparation = null;
|
|
51961
52170
|
}
|
|
51962
52171
|
}
|
|
51963
52172
|
async function join(chatId, expectedCallId = null, onlyExisting = false) {
|
|
@@ -51966,21 +52175,31 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51966
52175
|
throw ended();
|
|
51967
52176
|
return chatId;
|
|
51968
52177
|
}
|
|
52178
|
+
if (!foreground)
|
|
52179
|
+
throw new Error("open veyl to join a call");
|
|
52180
|
+
return runJoin(chatId, expectedCallId, onlyExisting);
|
|
52181
|
+
}
|
|
52182
|
+
async function runJoin(chatId, expectedCallId = null, onlyExisting = false, continuation = null) {
|
|
51969
52183
|
const intent = ++joinIntent;
|
|
51970
|
-
const operation = { predecessor: active, chatId, candidate: null };
|
|
52184
|
+
const operation = { predecessor: active, chatId, candidate: null, continuation };
|
|
51971
52185
|
const previous = joining;
|
|
51972
52186
|
joining = operation;
|
|
52187
|
+
previous?.preparation?.close();
|
|
51973
52188
|
emit({ joiningChatId: chatId });
|
|
51974
52189
|
if (previous?.candidate && previous.candidate !== active)
|
|
51975
52190
|
disposeCall(previous.candidate);
|
|
51976
52191
|
try {
|
|
51977
52192
|
for (let attempt = 0;attempt < 3; attempt += 1) {
|
|
51978
52193
|
try {
|
|
51979
|
-
return await joinAttempt(chatId, intent, expectedCallId, onlyExisting);
|
|
52194
|
+
return await joinAttempt(chatId, intent, expectedCallId, onlyExisting, continuation);
|
|
51980
52195
|
} catch (error) {
|
|
51981
52196
|
if (intent !== joinIntent || !identity || closed)
|
|
51982
52197
|
throw cancelled2();
|
|
51983
52198
|
if (error?.code !== "calls/discovery-conflict" || attempt === 2) {
|
|
52199
|
+
if (continuation) {
|
|
52200
|
+
fail(error);
|
|
52201
|
+
throw error;
|
|
52202
|
+
}
|
|
51984
52203
|
const target = operation.chatId;
|
|
51985
52204
|
emit({ ...!active ? { phase: "error", chatId: target } : {}, error: callError(chatId, error) });
|
|
51986
52205
|
throw error;
|
|
@@ -51997,6 +52216,7 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
51997
52216
|
}
|
|
51998
52217
|
function leave() {
|
|
51999
52218
|
joinIntent += 1;
|
|
52219
|
+
joining?.preparation?.close();
|
|
52000
52220
|
const candidate = joining?.candidate;
|
|
52001
52221
|
joining = null;
|
|
52002
52222
|
emit({ joiningChatId: null });
|
|
@@ -52011,6 +52231,7 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52011
52231
|
if (!operation)
|
|
52012
52232
|
return Promise.resolve();
|
|
52013
52233
|
joinIntent += 1;
|
|
52234
|
+
operation.preparation?.close();
|
|
52014
52235
|
joining = null;
|
|
52015
52236
|
emit({ joiningChatId: null });
|
|
52016
52237
|
const pending = operation.candidate && operation.candidate !== active ? disposeCall(operation.candidate) : null;
|
|
@@ -52020,6 +52241,14 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52020
52241
|
}
|
|
52021
52242
|
function stopCall() {
|
|
52022
52243
|
const call2 = active;
|
|
52244
|
+
const authority = participation;
|
|
52245
|
+
participation = null;
|
|
52246
|
+
if (!call2 && authority) {
|
|
52247
|
+
authority.owner.retire();
|
|
52248
|
+
const retired = [...retiring].filter((room) => room.endpoint === authority.endpoint);
|
|
52249
|
+
const released = Promise.all(retired.map((room) => room.stopped)).then(() => authority.owner.release());
|
|
52250
|
+
leaving = retired.length ? Promise.race([released, Promise.all(retired.map((room) => room.closing))]) : released;
|
|
52251
|
+
}
|
|
52023
52252
|
if (!call2) {
|
|
52024
52253
|
emit({ phase: "idle", chatId: null, callId: null, mode: null, transport: null, participants: [], speaking: [] });
|
|
52025
52254
|
return leaving;
|
|
@@ -52039,7 +52268,9 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52039
52268
|
return;
|
|
52040
52269
|
try {
|
|
52041
52270
|
await entry.mailbox.commit(null, [], { expectedRevision: snapshot.revision });
|
|
52042
|
-
|
|
52271
|
+
if (chat.getSnapshot().getOwnerChat(call2.chatId)?.epochState?.manifest.epochId === entry.epochState.manifest.epochId) {
|
|
52272
|
+
announce(call2.chatId, call2.callId, "ended");
|
|
52273
|
+
}
|
|
52043
52274
|
} catch (error) {
|
|
52044
52275
|
if (error?.code !== "calls/conflict")
|
|
52045
52276
|
throw error;
|
|
@@ -52059,11 +52290,13 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52059
52290
|
clearTimeout(call2.timer);
|
|
52060
52291
|
clearTimeout(call2.joinTimer);
|
|
52061
52292
|
const stopping = call2.media?.close();
|
|
52062
|
-
call2.
|
|
52293
|
+
call2.stopped = Promise.resolve(stopping);
|
|
52294
|
+
const releasedOwner = participation?.endpoint === call2.endpoint ? null : call2.owner;
|
|
52295
|
+
releasedOwner?.retire();
|
|
52063
52296
|
const departing = call2.room?.leave();
|
|
52064
52297
|
const draining = (async () => {
|
|
52065
52298
|
try {
|
|
52066
|
-
const [, departure] = await Promise.allSettled([Promise.resolve(stopping).then(() =>
|
|
52299
|
+
const [, departure] = await Promise.allSettled([Promise.resolve(stopping).then(() => releasedOwner?.release()), departing]);
|
|
52067
52300
|
if (departure.status === "fulfilled" && departure.value?.ended && call2.published && call2.discovery.descriptor?.callId === call2.callId) {
|
|
52068
52301
|
await retireDiscovery(call2);
|
|
52069
52302
|
}
|
|
@@ -52083,9 +52316,13 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52083
52316
|
call2.room?.close();
|
|
52084
52317
|
call2.protocol?.close();
|
|
52085
52318
|
cleanBytes(call2.member?.snapshot);
|
|
52319
|
+
if (call2.owner !== lease && call2.owner !== participation?.owner)
|
|
52320
|
+
call2.owner?.close();
|
|
52086
52321
|
if (call2.endpoint !== leaseEndpoint)
|
|
52087
52322
|
call2.endpoint.close();
|
|
52088
52323
|
retiring.delete(call2);
|
|
52324
|
+
if (discoveries.get(call2.chatId) !== call2.discovery)
|
|
52325
|
+
closeDiscovery(call2.discovery);
|
|
52089
52326
|
prune();
|
|
52090
52327
|
});
|
|
52091
52328
|
return call2.closing;
|
|
@@ -52101,6 +52338,27 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52101
52338
|
return result;
|
|
52102
52339
|
}
|
|
52103
52340
|
async function setAudio(patch) {
|
|
52341
|
+
const value = normalizeCallAudio(patch, state);
|
|
52342
|
+
if (value.muted === state.muted && value.deafened === state.deafened && value.muted === audioSource.muted && value.deafened === audioSource.deafened)
|
|
52343
|
+
return;
|
|
52344
|
+
const token = generation;
|
|
52345
|
+
pendingAudio = value;
|
|
52346
|
+
const saving = Promise.resolve().then(() => {
|
|
52347
|
+
if (generation !== token)
|
|
52348
|
+
throw cancelled2();
|
|
52349
|
+
return saveAudio(value);
|
|
52350
|
+
}).then(() => {
|
|
52351
|
+
if (generation === token)
|
|
52352
|
+
audioSource = value;
|
|
52353
|
+
});
|
|
52354
|
+
try {
|
|
52355
|
+
await Promise.all([saving, applyAudioPreferences(value)]);
|
|
52356
|
+
} finally {
|
|
52357
|
+
if (generation === token && pendingAudio === value)
|
|
52358
|
+
pendingAudio = null;
|
|
52359
|
+
}
|
|
52360
|
+
}
|
|
52361
|
+
async function applyAudioPreferences(patch) {
|
|
52104
52362
|
emit(patch);
|
|
52105
52363
|
const calls = new Set([active, joining?.candidate].filter((call2) => call2?.media && call2.room && !call2.leaving));
|
|
52106
52364
|
await Promise.all([...calls].map((call2) => applyAudio(call2).catch((error) => {
|
|
@@ -52111,6 +52369,13 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52111
52369
|
throw error;
|
|
52112
52370
|
})));
|
|
52113
52371
|
}
|
|
52372
|
+
function syncAudio(source) {
|
|
52373
|
+
audioSource = normalizeCallAudio(source);
|
|
52374
|
+
const value = pendingAudio || audioSource;
|
|
52375
|
+
if (state.muted === value.muted && state.deafened === value.deafened)
|
|
52376
|
+
return;
|
|
52377
|
+
applyAudioPreferences(value).catch((error) => diag?.("call.audio.settings.error", { code: error?.code || "calls/audio" }));
|
|
52378
|
+
}
|
|
52114
52379
|
async function setPeerAudio(chatPK, patch) {
|
|
52115
52380
|
const call2 = active;
|
|
52116
52381
|
if (!identity || typeof chatPK !== "string" || !chatPK || chatPK === identity.chatPK)
|
|
@@ -52119,11 +52384,15 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52119
52384
|
const peer = call2?.participants.find((peer2) => peer2.chatPK === chatPK);
|
|
52120
52385
|
const previous = state.peerAudio[chatPK];
|
|
52121
52386
|
const value = { volume: 100, muted: false, ...previous, ...patch };
|
|
52387
|
+
pendingPeerAudio.set(chatPK, value);
|
|
52122
52388
|
emit({ peerAudio: { ...state.peerAudio, [chatPK]: value } });
|
|
52123
52389
|
try {
|
|
52124
52390
|
if (peer)
|
|
52125
52391
|
await call2.media.setPeerAudio(peer.holder, { volume: value.volume / 100, muted: value.muted });
|
|
52126
|
-
if (generation
|
|
52392
|
+
if (generation !== token || pendingPeerAudio.get(chatPK) !== value)
|
|
52393
|
+
return;
|
|
52394
|
+
await savePeerAudio(chatPK, value);
|
|
52395
|
+
if (generation === token)
|
|
52127
52396
|
confirmedPeerAudio.set(chatPK, value);
|
|
52128
52397
|
} catch (error) {
|
|
52129
52398
|
if (generation === token && state.peerAudio[chatPK] === value) {
|
|
@@ -52134,8 +52403,39 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52134
52403
|
else
|
|
52135
52404
|
delete peerAudio[chatPK];
|
|
52136
52405
|
emit({ peerAudio });
|
|
52406
|
+
if (peer && active === call2)
|
|
52407
|
+
call2.media.setPeerAudio(peer.holder, {
|
|
52408
|
+
volume: (confirmed?.volume ?? 100) / 100,
|
|
52409
|
+
muted: confirmed?.muted ?? false
|
|
52410
|
+
}).catch(() => {});
|
|
52137
52411
|
}
|
|
52138
52412
|
throw error;
|
|
52413
|
+
} finally {
|
|
52414
|
+
if (generation === token && pendingPeerAudio.get(chatPK) === value)
|
|
52415
|
+
pendingPeerAudio.delete(chatPK);
|
|
52416
|
+
}
|
|
52417
|
+
}
|
|
52418
|
+
function syncPeerAudio(source = {}) {
|
|
52419
|
+
if (source === peerAudioSource)
|
|
52420
|
+
return;
|
|
52421
|
+
peerAudioSource = source;
|
|
52422
|
+
const peerAudio = { ...source };
|
|
52423
|
+
for (const [chatPK, value] of pendingPeerAudio)
|
|
52424
|
+
peerAudio[chatPK] = value;
|
|
52425
|
+
confirmedPeerAudio.clear();
|
|
52426
|
+
for (const [chatPK, value] of Object.entries(source))
|
|
52427
|
+
confirmedPeerAudio.set(chatPK, value);
|
|
52428
|
+
const changed = new Set([...Object.keys(state.peerAudio), ...Object.keys(peerAudio)].filter((chatPK) => state.peerAudio[chatPK]?.volume !== peerAudio[chatPK]?.volume || state.peerAudio[chatPK]?.muted !== peerAudio[chatPK]?.muted));
|
|
52429
|
+
if (!changed.size)
|
|
52430
|
+
return;
|
|
52431
|
+
emit({ peerAudio });
|
|
52432
|
+
for (const call2 of new Set([active, joining?.candidate].filter((call3) => call3?.media && !call3.leaving))) {
|
|
52433
|
+
for (const peer of call2.participants) {
|
|
52434
|
+
if (!changed.has(peer.chatPK))
|
|
52435
|
+
continue;
|
|
52436
|
+
const audio = peerAudio[peer.chatPK];
|
|
52437
|
+
call2.media.setPeerAudio(peer.holder, { volume: (audio?.volume ?? 100) / 100, muted: audio?.muted ?? false }).catch((error) => diag?.("call.peer.audio.error", { code: error?.code || "calls/audio" }));
|
|
52438
|
+
}
|
|
52139
52439
|
}
|
|
52140
52440
|
}
|
|
52141
52441
|
async function setMicrophoneVolume(volume) {
|
|
@@ -52153,13 +52453,9 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52153
52453
|
throw error;
|
|
52154
52454
|
}
|
|
52155
52455
|
}
|
|
52156
|
-
function
|
|
52157
|
-
lease?.close();
|
|
52158
|
-
if (leaseEndpoint && leaseEndpoint !== endpoint && leaseEndpoint !== callEndpoint)
|
|
52159
|
-
leaseEndpoint.close();
|
|
52160
|
-
leaseEndpoint = callEndpoint;
|
|
52456
|
+
function createLease(session, callEndpoint) {
|
|
52161
52457
|
const ownsLease = () => identity === session && leaseEndpoint === callEndpoint;
|
|
52162
|
-
|
|
52458
|
+
return openAccountCallLease({
|
|
52163
52459
|
cloud,
|
|
52164
52460
|
capability: session.callIdentity,
|
|
52165
52461
|
endpoint: callEndpoint,
|
|
@@ -52184,9 +52480,22 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52184
52480
|
}
|
|
52185
52481
|
});
|
|
52186
52482
|
}
|
|
52187
|
-
function
|
|
52188
|
-
|
|
52483
|
+
function mountLease(session, callEndpoint = endpoint, prepared = null) {
|
|
52484
|
+
lease?.close();
|
|
52485
|
+
if (leaseEndpoint && leaseEndpoint !== endpoint && leaseEndpoint !== callEndpoint)
|
|
52486
|
+
leaseEndpoint.close();
|
|
52487
|
+
leaseEndpoint = callEndpoint;
|
|
52488
|
+
lease = prepared || createLease(session, callEndpoint);
|
|
52489
|
+
}
|
|
52490
|
+
function setSources(session, settings = {}) {
|
|
52491
|
+
const peerAudio = settings.peerAudio || {};
|
|
52492
|
+
if (identity === session) {
|
|
52493
|
+
if (session) {
|
|
52494
|
+
syncPeerAudio(peerAudio);
|
|
52495
|
+
syncAudio(settings.callAudio);
|
|
52496
|
+
}
|
|
52189
52497
|
return drainingSources;
|
|
52498
|
+
}
|
|
52190
52499
|
const token = ++generation;
|
|
52191
52500
|
const previousLease = lease;
|
|
52192
52501
|
const previousEndpoint = endpoint;
|
|
@@ -52218,7 +52527,13 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52218
52527
|
if (generation !== token || identity !== session)
|
|
52219
52528
|
return retirement;
|
|
52220
52529
|
confirmedPeerAudio.clear();
|
|
52221
|
-
|
|
52530
|
+
pendingPeerAudio.clear();
|
|
52531
|
+
pendingAudio = null;
|
|
52532
|
+
audioSource = normalizeCallAudio(settings.callAudio);
|
|
52533
|
+
peerAudioSource = session ? peerAudio : null;
|
|
52534
|
+
for (const [chatPK, value] of Object.entries(peerAudioSource || {}))
|
|
52535
|
+
confirmedPeerAudio.set(chatPK, value);
|
|
52536
|
+
emit({ ...initial(), ...session ? audioSource : {}, peerAudio: peerAudioSource || {} });
|
|
52222
52537
|
available();
|
|
52223
52538
|
if (generation !== token || identity !== session)
|
|
52224
52539
|
return retirement;
|
|
@@ -52239,10 +52554,35 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52239
52554
|
if (!identity)
|
|
52240
52555
|
return;
|
|
52241
52556
|
for (const [chatId, entry] of discoveries) {
|
|
52242
|
-
const
|
|
52243
|
-
if (
|
|
52557
|
+
const epochState = chat.getSnapshot().getOwnerChat(chatId)?.epochState;
|
|
52558
|
+
if (epochState?.manifest.epochId === entry.epochState.manifest.epochId)
|
|
52244
52559
|
continue;
|
|
52245
|
-
|
|
52560
|
+
const retained = epochState?.manifest.members.some((member) => member.chatSigningPK === identity.chatSigningPK);
|
|
52561
|
+
if (participation?.chatId === chatId && retained) {
|
|
52562
|
+
const continuation = participation;
|
|
52563
|
+
const intent = ++joinIntent;
|
|
52564
|
+
const previous = active || joining?.candidate;
|
|
52565
|
+
active = null;
|
|
52566
|
+
joining = null;
|
|
52567
|
+
if (previous)
|
|
52568
|
+
disposeCall(previous);
|
|
52569
|
+
const members = new Set(epochState.manifest.members.map((member) => member.chatPK));
|
|
52570
|
+
emit({
|
|
52571
|
+
phase: "connecting",
|
|
52572
|
+
joiningChatId: chatId,
|
|
52573
|
+
speaking: [],
|
|
52574
|
+
participants: state.participants.filter((member) => members.has(member.chatPK))
|
|
52575
|
+
});
|
|
52576
|
+
diag?.("call.epoch.transition", { stage: "starting", participants: state.participants.length });
|
|
52577
|
+
Promise.resolve(previous?.stopped).then(() => {
|
|
52578
|
+
if (intent !== joinIntent || participation !== continuation)
|
|
52579
|
+
return;
|
|
52580
|
+
return runJoin(chatId, null, false, continuation);
|
|
52581
|
+
}).catch((error) => {
|
|
52582
|
+
if (intent === joinIntent && participation === continuation)
|
|
52583
|
+
fail(error);
|
|
52584
|
+
});
|
|
52585
|
+
} else if (active?.chatId === chatId || participation?.chatId === chatId)
|
|
52246
52586
|
leave();
|
|
52247
52587
|
else if (joining?.chatId === chatId)
|
|
52248
52588
|
cancelJoin();
|
|
@@ -52301,8 +52641,6 @@ function createCallSession({ cloud, chat, media: mediaPort, mls, diag }) {
|
|
|
52301
52641
|
},
|
|
52302
52642
|
setForeground(value) {
|
|
52303
52643
|
foreground = value === true;
|
|
52304
|
-
if (!foreground && joining)
|
|
52305
|
-
cancelJoin();
|
|
52306
52644
|
},
|
|
52307
52645
|
setOnline(value) {
|
|
52308
52646
|
const reconnecting = !online && value === true;
|
|
@@ -52340,6 +52678,7 @@ var init_session5 = __esm(() => {
|
|
|
52340
52678
|
init_wire();
|
|
52341
52679
|
init_call();
|
|
52342
52680
|
init_ownership();
|
|
52681
|
+
init_settings();
|
|
52343
52682
|
});
|
|
52344
52683
|
|
|
52345
52684
|
// ../../node_modules/.bun/@zxcvbn-ts+core@4.2.0/node_modules/@zxcvbn-ts/core/dist/utils/helper.cjs
|
|
@@ -55759,15 +56098,17 @@ var init_paymentrequest = __esm(() => {
|
|
|
55759
56098
|
});
|
|
55760
56099
|
|
|
55761
56100
|
// ../../core/wallet/bitcoin.js
|
|
55762
|
-
function normalizeBitcoinData(data, current = DEFAULT_BITCOIN
|
|
56101
|
+
function normalizeBitcoinData(data, current = DEFAULT_BITCOIN) {
|
|
55763
56102
|
if (!data)
|
|
55764
56103
|
return current;
|
|
56104
|
+
const observedAt = timestampMs(data.priceUpdatedAt, null, { positive: true });
|
|
56105
|
+
const usePrice = hasBitcoinPrice(data.price) && observedAt != null && observedAt >= (current.priceUpdatedAt ?? 0);
|
|
55765
56106
|
return {
|
|
55766
|
-
price:
|
|
55767
|
-
priceUpdatedAt:
|
|
55768
|
-
priceFromCache:
|
|
56107
|
+
price: usePrice ? data.price : current.price,
|
|
56108
|
+
priceUpdatedAt: usePrice ? observedAt : current.priceUpdatedAt,
|
|
56109
|
+
priceFromCache: usePrice ? false : current.priceFromCache,
|
|
55769
56110
|
block: data.block ?? current?.block ?? null,
|
|
55770
|
-
fees: data.fees ??
|
|
56111
|
+
fees: data.fees ?? null,
|
|
55771
56112
|
updatedAt: data.updatedAt ?? current?.updatedAt ?? null,
|
|
55772
56113
|
ready: true,
|
|
55773
56114
|
error: null
|
|
@@ -55817,20 +56158,15 @@ function createBitcoin({ cloud, priceStorage = null, diag = null }) {
|
|
|
55817
56158
|
const priceUpdatedAt = timestampMs(cached.updatedAt, null, { positive: true });
|
|
55818
56159
|
if (!priceUpdatedAt)
|
|
55819
56160
|
return;
|
|
55820
|
-
if (bitcoin.priceUpdatedAt != null &&
|
|
56161
|
+
if (bitcoin.priceUpdatedAt != null && bitcoin.priceUpdatedAt >= priceUpdatedAt)
|
|
55821
56162
|
return;
|
|
55822
56163
|
publish({ ...bitcoin, price: cached.price, priceUpdatedAt, priceFromCache: true });
|
|
55823
56164
|
}).catch((error) => diag?.("bitcoin.price.cache.read.error", { code: error?.code || "" }));
|
|
55824
|
-
unsubscribe = cloud.bitcoin.watch((data
|
|
55825
|
-
if (session !== generation
|
|
56165
|
+
unsubscribe = cloud.bitcoin.watch((data) => {
|
|
56166
|
+
if (session !== generation)
|
|
55826
56167
|
return;
|
|
55827
|
-
const next = normalizeBitcoinData(data, bitcoin
|
|
55828
|
-
if (
|
|
55829
|
-
next.price = bitcoin.price;
|
|
55830
|
-
next.priceUpdatedAt = bitcoin.priceUpdatedAt;
|
|
55831
|
-
next.priceFromCache = bitcoin.priceFromCache;
|
|
55832
|
-
}
|
|
55833
|
-
if (priceStorage && hasBitcoinPrice(data?.price) && !info.fromCache && (next.price !== bitcoin.price || next.priceUpdatedAt !== bitcoin.priceUpdatedAt || bitcoin.priceFromCache)) {
|
|
56168
|
+
const next = normalizeBitcoinData(data, bitcoin);
|
|
56169
|
+
if (priceStorage && next.priceUpdatedAt != null && !next.priceFromCache && (next.price !== bitcoin.price || next.priceUpdatedAt !== bitcoin.priceUpdatedAt || bitcoin.priceFromCache)) {
|
|
55834
56170
|
const cached = { price: next.price, updatedAt: next.priceUpdatedAt };
|
|
55835
56171
|
priceWrite = priceWrite.catch(NOOP3).then(() => priceStorage.write(cached));
|
|
55836
56172
|
priceWrite.catch((error) => diag?.("bitcoin.price.cache.write.error", { code: error?.code || "" }));
|
|
@@ -56991,8 +57327,9 @@ function createPeersApi({ cloud, network, avatarCache = null }) {
|
|
|
56991
57327
|
async function fetchProfileByUid(uid) {
|
|
56992
57328
|
if (!uid)
|
|
56993
57329
|
return null;
|
|
56994
|
-
|
|
56995
|
-
|
|
57330
|
+
const cached = profileCache.get(uid);
|
|
57331
|
+
if (isFullProfile(cached))
|
|
57332
|
+
return cached;
|
|
56996
57333
|
try {
|
|
56997
57334
|
const record = await cloud.peer.read(uid);
|
|
56998
57335
|
if (!record)
|
|
@@ -57040,11 +57377,11 @@ function createPeersApi({ cloud, network, avatarCache = null }) {
|
|
|
57040
57377
|
return null;
|
|
57041
57378
|
if (field === "walletPK" && walletToUid.has(value)) {
|
|
57042
57379
|
const uid = walletToUid.get(value);
|
|
57043
|
-
return
|
|
57380
|
+
return fetchProfileByUid(uid);
|
|
57044
57381
|
}
|
|
57045
57382
|
if (field === "chatPK" && chatToUid.has(value)) {
|
|
57046
57383
|
const uid = chatToUid.get(value);
|
|
57047
|
-
return
|
|
57384
|
+
return fetchProfileByUid(uid);
|
|
57048
57385
|
}
|
|
57049
57386
|
try {
|
|
57050
57387
|
const record = field === "walletPK" ? await cloud.search.peer.byWalletPK(value, { network: walletNetwork }) : field === "chatPK" ? await cloud.search.peer.byChatPK(value) : await cloud.search.peer.byUsername(value);
|
|
@@ -64591,7 +64928,14 @@ function openAccount(options = {}) {
|
|
|
64591
64928
|
maintenance: messageMaintenance,
|
|
64592
64929
|
resolveActiveCall: (chatId) => calls.resolveActiveCall(chatId)
|
|
64593
64930
|
}, chatSources());
|
|
64594
|
-
const calls = createCallSession({
|
|
64931
|
+
const calls = createCallSession({
|
|
64932
|
+
cloud,
|
|
64933
|
+
chat,
|
|
64934
|
+
...options.calls,
|
|
64935
|
+
diag,
|
|
64936
|
+
savePeerAudio: (chatPK, audio) => user.getSnapshot().updateSettings({ peerAudio: { [chatPK]: audio } }),
|
|
64937
|
+
saveAudio: (callAudio) => user.getSnapshot().updateSettings({ callAudio })
|
|
64938
|
+
});
|
|
64595
64939
|
const wallet = openWallet({
|
|
64596
64940
|
...options.wallet || {},
|
|
64597
64941
|
network: state.network,
|
|
@@ -64665,7 +65009,7 @@ function openAccount(options = {}) {
|
|
|
64665
65009
|
syncPresence();
|
|
64666
65010
|
syncPeers();
|
|
64667
65011
|
calls.setOnline(state.online);
|
|
64668
|
-
calls.setSources(state.lockState === "unlocked" ? state.session : null);
|
|
65012
|
+
calls.setSources(state.lockState === "unlocked" ? state.session : null, state.user?.settings);
|
|
64669
65013
|
}
|
|
64670
65014
|
function syncPresence() {
|
|
64671
65015
|
const session = state.session;
|
|
@@ -75870,7 +76214,7 @@ var package_default;
|
|
|
75870
76214
|
var init_package2 = __esm(() => {
|
|
75871
76215
|
package_default = {
|
|
75872
76216
|
name: "veyl",
|
|
75873
|
-
version: "0.
|
|
76217
|
+
version: "0.74.0",
|
|
75874
76218
|
packageManager: "bun@1.4.0",
|
|
75875
76219
|
private: true,
|
|
75876
76220
|
license: "UNLICENSED",
|
|
@@ -75937,6 +76281,7 @@ var init_package2 = __esm(() => {
|
|
|
75937
76281
|
"@noble/hashes": "catalog:",
|
|
75938
76282
|
"@scure/bip39": "catalog:",
|
|
75939
76283
|
"@veyl/core": "workspace:*",
|
|
76284
|
+
"@veyl/bitcoin": "workspace:*",
|
|
75940
76285
|
"@veyl/firebase": "workspace:*",
|
|
75941
76286
|
"@veyl/live": "workspace:*",
|
|
75942
76287
|
"@veyl/product": "workspace:*",
|
|
@@ -223421,7 +223766,7 @@ function createFirebaseCloud({
|
|
|
223421
223766
|
const nextSettings = normalizeSettings(settings, base2);
|
|
223422
223767
|
const body = await sealSettings(key, uid, nextSettings);
|
|
223423
223768
|
await callVaultFunction("setSettings", VAULT_SIGNATURE_PURPOSES.SET_SETTINGS, { settings: bytesBase64(body) });
|
|
223424
|
-
return nextSettings;
|
|
223769
|
+
return { settings: nextSettings, body };
|
|
223425
223770
|
}
|
|
223426
223771
|
async function addUserPush(payload = {}) {
|
|
223427
223772
|
await callFunction("setPush", payload);
|
|
@@ -223453,15 +223798,6 @@ function createFirebaseCloud({
|
|
|
223453
223798
|
});
|
|
223454
223799
|
}, onError);
|
|
223455
223800
|
}
|
|
223456
|
-
function watchBitcoin(onUpdate, onError) {
|
|
223457
|
-
return onSnapshot2(doc3(db, "bitcoin", "current"), { includeMetadataChanges: true }, (snap) => {
|
|
223458
|
-
onUpdate?.(snap.exists() ? snap.data() : null, {
|
|
223459
|
-
exists: snap.exists(),
|
|
223460
|
-
fromCache: snap.metadata.fromCache,
|
|
223461
|
-
pending: snap.metadata.hasPendingWrites
|
|
223462
|
-
});
|
|
223463
|
-
}, onError);
|
|
223464
|
-
}
|
|
223465
223801
|
async function readPeer(uid) {
|
|
223466
223802
|
requireUid(uid);
|
|
223467
223803
|
const snap = await getDocFromServer2(doc3(db, "profiles", uid));
|
|
@@ -225215,9 +225551,6 @@ function createFirebaseCloud({
|
|
|
225215
225551
|
watch: watchAdmin
|
|
225216
225552
|
}
|
|
225217
225553
|
},
|
|
225218
|
-
bitcoin: {
|
|
225219
|
-
watch: watchBitcoin
|
|
225220
|
-
},
|
|
225221
225554
|
peer: {
|
|
225222
225555
|
read: readPeer,
|
|
225223
225556
|
avatar: {
|
|
@@ -225362,10 +225695,11 @@ var init_cloud = __esm(() => {
|
|
|
225362
225695
|
});
|
|
225363
225696
|
|
|
225364
225697
|
// ../../core/cloud.js
|
|
225365
|
-
function createCloud({ data, live, presence, calls, connection } = {}) {
|
|
225698
|
+
function createCloud({ data, bitcoin, live, presence, calls, connection } = {}) {
|
|
225366
225699
|
if (!data?.environment)
|
|
225367
225700
|
throw new Error("cloud data adapter required");
|
|
225368
225701
|
const channels = new Set;
|
|
225702
|
+
const watches = new Set;
|
|
225369
225703
|
let disposed = false;
|
|
225370
225704
|
const controlled = connection?.enabled === true;
|
|
225371
225705
|
const transportPort = (transport, { watchable = false, requestable = false } = {}) => transport && Object.freeze({
|
|
@@ -225400,6 +225734,9 @@ function createCloud({ data, live, presence, calls, connection } = {}) {
|
|
|
225400
225734
|
return channel?.send(...args) ?? false;
|
|
225401
225735
|
},
|
|
225402
225736
|
...requestable ? {
|
|
225737
|
+
ready() {
|
|
225738
|
+
return channel.ready();
|
|
225739
|
+
},
|
|
225403
225740
|
request(...args) {
|
|
225404
225741
|
return channel.request(...args);
|
|
225405
225742
|
},
|
|
@@ -225439,6 +225776,19 @@ function createCloud({ data, live, presence, calls, connection } = {}) {
|
|
|
225439
225776
|
});
|
|
225440
225777
|
return Object.freeze({
|
|
225441
225778
|
...data,
|
|
225779
|
+
bitcoin: bitcoin && Object.freeze({
|
|
225780
|
+
watch(next, error) {
|
|
225781
|
+
if (disposed)
|
|
225782
|
+
throw new Error("cloud closed");
|
|
225783
|
+
const unsubscribe = bitcoin.watch(next, error);
|
|
225784
|
+
const stop = () => {
|
|
225785
|
+
if (watches.delete(stop))
|
|
225786
|
+
unsubscribe();
|
|
225787
|
+
};
|
|
225788
|
+
watches.add(stop);
|
|
225789
|
+
return stop;
|
|
225790
|
+
}
|
|
225791
|
+
}),
|
|
225442
225792
|
availability: Object.freeze({
|
|
225443
225793
|
getSnapshot: () => controlled && connection.getSnapshot() !== "off" ? false : null,
|
|
225444
225794
|
subscribe: (listener) => controlled ? connection.subscribe(listener) : () => {}
|
|
@@ -225452,11 +225802,112 @@ function createCloud({ data, live, presence, calls, connection } = {}) {
|
|
|
225452
225802
|
disposed = true;
|
|
225453
225803
|
for (const channel of [...channels])
|
|
225454
225804
|
channel.close();
|
|
225805
|
+
for (const stop of [...watches])
|
|
225806
|
+
stop();
|
|
225455
225807
|
calls?.close();
|
|
225456
225808
|
}
|
|
225457
225809
|
});
|
|
225458
225810
|
}
|
|
225459
225811
|
|
|
225812
|
+
// ../../adapters/bitcoin/transport.js
|
|
225813
|
+
function createBitcoinTransport({ endpoint = bitcoinEndpoint, fetcher = globalThis.fetch, appState = null, connection = null } = {}) {
|
|
225814
|
+
const listeners = new Set;
|
|
225815
|
+
let snapshot2 = null;
|
|
225816
|
+
let fetchedAt = 0;
|
|
225817
|
+
let timer = null;
|
|
225818
|
+
let pending = null;
|
|
225819
|
+
let activitySubscription = null;
|
|
225820
|
+
let stopConnection = null;
|
|
225821
|
+
let initialized2 = connection?.enabled !== true;
|
|
225822
|
+
const active = () => listeners.size > 0 && initialized2 && (!appState || appState.currentState === "active") && (!connection?.enabled || connection.getSnapshot() === "off");
|
|
225823
|
+
function cancel() {
|
|
225824
|
+
clearTimeout(timer);
|
|
225825
|
+
timer = null;
|
|
225826
|
+
const previous = pending;
|
|
225827
|
+
pending = null;
|
|
225828
|
+
previous?.abort();
|
|
225829
|
+
}
|
|
225830
|
+
async function refresh() {
|
|
225831
|
+
if (!active() || pending)
|
|
225832
|
+
return;
|
|
225833
|
+
const controller = new AbortController;
|
|
225834
|
+
pending = controller;
|
|
225835
|
+
const timeout = setTimeout(() => controller.abort(), BITCOIN_FETCH_TIMEOUT_MS);
|
|
225836
|
+
try {
|
|
225837
|
+
const response = await fetcher(endpoint, { signal: controller.signal, credentials: "omit" });
|
|
225838
|
+
if (!response.ok)
|
|
225839
|
+
throw new Error(`bitcoin data unavailable (${response.status})`);
|
|
225840
|
+
const value = await response.json();
|
|
225841
|
+
if (!value || !Number.isFinite(value.updatedAt) || value.updatedAt <= 0)
|
|
225842
|
+
throw new Error("invalid bitcoin snapshot");
|
|
225843
|
+
if (pending !== controller)
|
|
225844
|
+
return;
|
|
225845
|
+
fetchedAt = Date.now();
|
|
225846
|
+
if (!snapshot2 || value.updatedAt > snapshot2.updatedAt)
|
|
225847
|
+
snapshot2 = value;
|
|
225848
|
+
for (const entry of listeners)
|
|
225849
|
+
entry.next(snapshot2);
|
|
225850
|
+
} catch (error) {
|
|
225851
|
+
if (pending === controller)
|
|
225852
|
+
for (const entry of listeners)
|
|
225853
|
+
entry.error?.(error);
|
|
225854
|
+
} finally {
|
|
225855
|
+
clearTimeout(timeout);
|
|
225856
|
+
if (pending === controller) {
|
|
225857
|
+
pending = null;
|
|
225858
|
+
if (active())
|
|
225859
|
+
timer = setTimeout(refresh, BITCOIN_POLL_MS);
|
|
225860
|
+
}
|
|
225861
|
+
}
|
|
225862
|
+
}
|
|
225863
|
+
function sync() {
|
|
225864
|
+
if (!active()) {
|
|
225865
|
+
cancel();
|
|
225866
|
+
return;
|
|
225867
|
+
}
|
|
225868
|
+
if (pending)
|
|
225869
|
+
return;
|
|
225870
|
+
clearTimeout(timer);
|
|
225871
|
+
const delay = Math.max(0, BITCOIN_POLL_MS - (Date.now() - fetchedAt));
|
|
225872
|
+
if (delay)
|
|
225873
|
+
timer = setTimeout(refresh, delay);
|
|
225874
|
+
else
|
|
225875
|
+
refresh();
|
|
225876
|
+
}
|
|
225877
|
+
return Object.freeze({
|
|
225878
|
+
watch(next, error) {
|
|
225879
|
+
const entry = { next, error };
|
|
225880
|
+
listeners.add(entry);
|
|
225881
|
+
if (snapshot2)
|
|
225882
|
+
next(snapshot2);
|
|
225883
|
+
if (listeners.size === 1) {
|
|
225884
|
+
activitySubscription = appState?.addEventListener("change", sync);
|
|
225885
|
+
stopConnection = connection?.enabled ? connection.subscribe(sync) : null;
|
|
225886
|
+
if (!initialized2)
|
|
225887
|
+
connection.ready.then(() => {
|
|
225888
|
+
initialized2 = true;
|
|
225889
|
+
sync();
|
|
225890
|
+
});
|
|
225891
|
+
sync();
|
|
225892
|
+
}
|
|
225893
|
+
return () => {
|
|
225894
|
+
listeners.delete(entry);
|
|
225895
|
+
if (listeners.size)
|
|
225896
|
+
return;
|
|
225897
|
+
cancel();
|
|
225898
|
+
activitySubscription?.remove();
|
|
225899
|
+
stopConnection?.();
|
|
225900
|
+
activitySubscription = null;
|
|
225901
|
+
stopConnection = null;
|
|
225902
|
+
};
|
|
225903
|
+
}
|
|
225904
|
+
});
|
|
225905
|
+
}
|
|
225906
|
+
var init_transport = __esm(() => {
|
|
225907
|
+
init_config();
|
|
225908
|
+
init_origins();
|
|
225909
|
+
});
|
|
225910
|
+
|
|
225460
225911
|
// ../../adapters/live/retry.js
|
|
225461
225912
|
function createSocketRetry({ plane, realm: realm2, staleAfter, diag }) {
|
|
225462
225913
|
let closed = false;
|
|
@@ -225757,7 +226208,7 @@ function createLiveTransport({ endpoint: endpointValue, realm: realm2, WebSocket
|
|
|
225757
226208
|
});
|
|
225758
226209
|
}
|
|
225759
226210
|
var ROOM_RE;
|
|
225760
|
-
var
|
|
226211
|
+
var init_transport2 = __esm(() => {
|
|
225761
226212
|
init_config();
|
|
225762
226213
|
init_wire2();
|
|
225763
226214
|
init_retry();
|
|
@@ -226074,6 +226525,8 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226074
226525
|
lifetime.signal.addEventListener("abort", abort, { once: true });
|
|
226075
226526
|
activity?.addEventListener("abort", abort, { once: true });
|
|
226076
226527
|
const timer = setTimeout(abort, REQUEST_MS);
|
|
226528
|
+
const startedAt = Date.now();
|
|
226529
|
+
let status = 0;
|
|
226077
226530
|
try {
|
|
226078
226531
|
const response = await fetcher(`${http}${path}`, {
|
|
226079
226532
|
method: "POST",
|
|
@@ -226082,6 +226535,7 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226082
226535
|
body: JSON.stringify(body),
|
|
226083
226536
|
signal: controller.signal
|
|
226084
226537
|
});
|
|
226538
|
+
status = response.status;
|
|
226085
226539
|
const data = await readResponse(response);
|
|
226086
226540
|
if (closed)
|
|
226087
226541
|
throw callWireError("closed");
|
|
@@ -226097,6 +226551,12 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226097
226551
|
throw error;
|
|
226098
226552
|
throw callWireError(controller.signal.aborted ? "timeout" : "connection");
|
|
226099
226553
|
} finally {
|
|
226554
|
+
markDone(diag, "call.transport.http", startedAt, {
|
|
226555
|
+
kind: body.request?.kind || "ticket",
|
|
226556
|
+
type: body.request?.body?.type || "ticket",
|
|
226557
|
+
stage: body.request?.body?.action || "",
|
|
226558
|
+
status
|
|
226559
|
+
});
|
|
226100
226560
|
clearTimeout(timer);
|
|
226101
226561
|
lifetime.signal.removeEventListener("abort", abort);
|
|
226102
226562
|
activity?.removeEventListener("abort", abort);
|
|
@@ -226142,6 +226602,7 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226142
226602
|
let socket = null;
|
|
226143
226603
|
let generation = 0;
|
|
226144
226604
|
let ready2 = false;
|
|
226605
|
+
let snapshot2 = null;
|
|
226145
226606
|
let deadline = null;
|
|
226146
226607
|
let heartbeat = null;
|
|
226147
226608
|
let lastEvidenceAt = 0;
|
|
@@ -226176,6 +226637,7 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226176
226637
|
const previous = socket;
|
|
226177
226638
|
socket = null;
|
|
226178
226639
|
ready2 = false;
|
|
226640
|
+
snapshot2 = null;
|
|
226179
226641
|
generation += 1;
|
|
226180
226642
|
clearTimeout(deadline);
|
|
226181
226643
|
clearInterval(heartbeat);
|
|
@@ -226205,11 +226667,13 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226205
226667
|
}
|
|
226206
226668
|
const version7 = ++generation;
|
|
226207
226669
|
retry.opening();
|
|
226670
|
+
const startedAt = Date.now();
|
|
226208
226671
|
const current = () => !stopped2 && !closed && !suspended && version7 === generation;
|
|
226209
226672
|
try {
|
|
226210
226673
|
const frame = await wrap3({ type: "observe", ...getCheckpoint?.() || { cursor: 0 } });
|
|
226211
226674
|
if (!current())
|
|
226212
226675
|
return;
|
|
226676
|
+
markDone(diag, "call.transport.open", startedAt, { kind: capability.kind, stage: "authentication" });
|
|
226213
226677
|
const auth2 = encodeCallBytes(new TextEncoder().encode(JSON.stringify(frame))).replace(/\+/gu, "-").replace(/\//gu, "_").replace(/=+$/u, "");
|
|
226214
226678
|
if (auth2.length > 8000)
|
|
226215
226679
|
throw callWireError("too-large");
|
|
@@ -226222,6 +226686,11 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226222
226686
|
return;
|
|
226223
226687
|
}
|
|
226224
226688
|
const liveSocket = socket;
|
|
226689
|
+
const socketStartedAt = Date.now();
|
|
226690
|
+
liveSocket.onopen = () => {
|
|
226691
|
+
if (current())
|
|
226692
|
+
markDone(diag, "call.transport.open", socketStartedAt, { kind: capability.kind, stage: "upgrade" });
|
|
226693
|
+
};
|
|
226225
226694
|
deadline = setTimeout(() => {
|
|
226226
226695
|
if (current())
|
|
226227
226696
|
disconnect("timeout");
|
|
@@ -226239,7 +226708,9 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226239
226708
|
throw callWireError("invalid-frame");
|
|
226240
226709
|
const frame = JSON.parse(event2.data);
|
|
226241
226710
|
if (frame.type === "snapshot") {
|
|
226711
|
+
snapshot2 = { record: frame.record, now: frame.now };
|
|
226242
226712
|
if (!ready2) {
|
|
226713
|
+
markDone(diag, "call.transport.open", socketStartedAt, { kind: capability.kind, stage: "snapshot" });
|
|
226243
226714
|
ready2 = true;
|
|
226244
226715
|
clearTimeout(deadline);
|
|
226245
226716
|
retry.ready();
|
|
@@ -226310,37 +226781,79 @@ function createCallTransport({ endpoint: value, realm: realm2, getToken, fetcher
|
|
|
226310
226781
|
});
|
|
226311
226782
|
}
|
|
226312
226783
|
const channel = Object.freeze({
|
|
226784
|
+
async ready() {
|
|
226785
|
+
if (!stream2)
|
|
226786
|
+
throw callWireError("invalid-request");
|
|
226787
|
+
const startedAt = Date.now();
|
|
226788
|
+
let code = "";
|
|
226789
|
+
try {
|
|
226790
|
+
await waitReady();
|
|
226791
|
+
if (!ready2 || !snapshot2 || stopped2 || closed || suspended)
|
|
226792
|
+
throw callWireError("connection");
|
|
226793
|
+
return snapshot2;
|
|
226794
|
+
} catch (error) {
|
|
226795
|
+
code = error?.code || "calls/unavailable";
|
|
226796
|
+
throw error;
|
|
226797
|
+
} finally {
|
|
226798
|
+
markDone(diag, "call.transport.ready", startedAt, { kind: capability.kind, code });
|
|
226799
|
+
}
|
|
226800
|
+
},
|
|
226313
226801
|
async request(body) {
|
|
226314
226802
|
if (!stream2 && body?.type !== "read")
|
|
226315
226803
|
throw callWireError("invalid-request");
|
|
226316
|
-
|
|
226317
|
-
|
|
226318
|
-
|
|
226319
|
-
|
|
226320
|
-
|
|
226321
|
-
|
|
226322
|
-
|
|
226804
|
+
const startedAt = Date.now();
|
|
226805
|
+
let readyAt = null;
|
|
226806
|
+
let authenticatedAt = null;
|
|
226807
|
+
let stage = "ready";
|
|
226808
|
+
let code = "";
|
|
226809
|
+
try {
|
|
226810
|
+
await waitReady();
|
|
226811
|
+
readyAt = Date.now();
|
|
226812
|
+
stage = "authentication";
|
|
226813
|
+
const requestActivity = activity;
|
|
226814
|
+
const frame = await wrap3(body);
|
|
226815
|
+
authenticatedAt = Date.now();
|
|
226816
|
+
stage = "response";
|
|
226817
|
+
if (!stream2) {
|
|
226818
|
+
if (stopped2 || closed)
|
|
226819
|
+
throw callWireError("closed");
|
|
226820
|
+
if (suspended || requestActivity !== activity)
|
|
226821
|
+
throw callWireError("connection");
|
|
226822
|
+
return await post(path, frame, {}, requestActivity.signal);
|
|
226823
|
+
}
|
|
226824
|
+
if (!ready2 || stopped2 || closed || suspended || socket?.readyState !== 1)
|
|
226323
226825
|
throw callWireError("connection");
|
|
226324
|
-
|
|
226826
|
+
const text2 = JSON.stringify(frame);
|
|
226827
|
+
if (text2.length > CALL_REQUEST_MAX_BYTES)
|
|
226828
|
+
throw callWireError("too-large");
|
|
226829
|
+
return await new Promise((resolve, reject) => {
|
|
226830
|
+
const nonce = frame.request.nonce;
|
|
226831
|
+
const timer = setTimeout(() => {
|
|
226832
|
+
pending.delete(nonce);
|
|
226833
|
+
reject(callWireError("timeout"));
|
|
226834
|
+
}, REQUEST_MS);
|
|
226835
|
+
pending.set(nonce, { resolve, reject, timer });
|
|
226836
|
+
try {
|
|
226837
|
+
socket.send(text2);
|
|
226838
|
+
} catch {
|
|
226839
|
+
disconnect("send");
|
|
226840
|
+
}
|
|
226841
|
+
});
|
|
226842
|
+
} catch (error) {
|
|
226843
|
+
code = error?.code || "calls/unavailable";
|
|
226844
|
+
throw error;
|
|
226845
|
+
} finally {
|
|
226846
|
+
const now = Date.now();
|
|
226847
|
+
markDone(diag, "call.transport.request", startedAt, {
|
|
226848
|
+
kind: capability.kind,
|
|
226849
|
+
type: body?.type,
|
|
226850
|
+
stage,
|
|
226851
|
+
code,
|
|
226852
|
+
readyMs: (readyAt ?? now) - startedAt,
|
|
226853
|
+
authenticationMs: readyAt === null ? 0 : (authenticatedAt ?? now) - readyAt,
|
|
226854
|
+
responseMs: authenticatedAt === null ? 0 : now - authenticatedAt
|
|
226855
|
+
});
|
|
226325
226856
|
}
|
|
226326
|
-
if (!ready2 || stopped2 || closed || suspended || socket?.readyState !== 1)
|
|
226327
|
-
throw callWireError("connection");
|
|
226328
|
-
const text2 = JSON.stringify(frame);
|
|
226329
|
-
if (text2.length > CALL_REQUEST_MAX_BYTES)
|
|
226330
|
-
throw callWireError("too-large");
|
|
226331
|
-
return new Promise((resolve, reject) => {
|
|
226332
|
-
const nonce = frame.request.nonce;
|
|
226333
|
-
const timer = setTimeout(() => {
|
|
226334
|
-
pending.delete(nonce);
|
|
226335
|
-
reject(callWireError("timeout"));
|
|
226336
|
-
}, REQUEST_MS);
|
|
226337
|
-
pending.set(nonce, { resolve, reject, timer });
|
|
226338
|
-
try {
|
|
226339
|
-
socket.send(text2);
|
|
226340
|
-
} catch {
|
|
226341
|
-
disconnect("send");
|
|
226342
|
-
}
|
|
226343
|
-
});
|
|
226344
226857
|
},
|
|
226345
226858
|
async provider(body) {
|
|
226346
226859
|
if (!stream2)
|
|
@@ -226453,6 +226966,7 @@ function createCloudRuntime(options2 = {}) {
|
|
|
226453
226966
|
const db = environment.databaseId === "(default)" ? getFirestore(app2) : getFirestore(app2, environment.databaseId);
|
|
226454
226967
|
const functions2 = getFunctions(app2, region);
|
|
226455
226968
|
const cloud = createCloud({
|
|
226969
|
+
bitcoin,
|
|
226456
226970
|
data: createFirebaseCloud({ db, auth: auth2, environment: environment.name, functions: functions2, onOperation: options2.onOperation }),
|
|
226457
226971
|
live: options2.live === undefined ? createLiveTransport({ endpoint: liveEndpoints[environment.name], realm: environment.name, diag: options2.diag, WebSocketClass: observeWebSocket(globalThis.WebSocket, options2.onOperation, "chat") }) : options2.live,
|
|
226458
226972
|
presence: options2.presence === undefined ? createPresenceTransport({ endpoint: liveEndpoints[environment.name], realm: environment.name, diag: options2.diag, WebSocketClass: observeWebSocket(globalThis.WebSocket, options2.onOperation, "presence") }) : options2.presence,
|
|
@@ -226487,19 +227001,21 @@ async function signOutRuntime(auth2) {
|
|
|
226487
227001
|
await signOut(auth2);
|
|
226488
227002
|
}
|
|
226489
227003
|
}
|
|
226490
|
-
var DEFAULT_FUNCTION_REGION = "us-central1";
|
|
227004
|
+
var DEFAULT_FUNCTION_REGION = "us-central1", bitcoin;
|
|
226491
227005
|
var init_cloud2 = __esm(() => {
|
|
226492
227006
|
init_dist4();
|
|
226493
227007
|
init_dist5();
|
|
226494
227008
|
init_dist6();
|
|
226495
227009
|
init_dist7();
|
|
226496
227010
|
init_cloud();
|
|
226497
|
-
init_origins();
|
|
226498
227011
|
init_transport();
|
|
227012
|
+
init_origins();
|
|
227013
|
+
init_transport2();
|
|
226499
227014
|
init_presence();
|
|
226500
227015
|
init_calls();
|
|
226501
227016
|
init_observe2();
|
|
226502
227017
|
init_config3();
|
|
227018
|
+
bitcoin = createBitcoinTransport();
|
|
226503
227019
|
});
|
|
226504
227020
|
|
|
226505
227021
|
// src/runtime/kdf-worker.js
|