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