@glyphteck/veyl 0.32.1 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +585 -353
  2. package/dist/index.js +585 -353
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -118,9 +118,10 @@ var init_links = __esm(() => {
118
118
  });
119
119
 
120
120
  // ../../shared/community.js
121
- var COMMUNITY_RULES_VERSION = "2026-05-11.1", COMMUNITY_SECTIONS;
121
+ var COMMUNITY_RULES_VERSION = "2026-05-11.1", COMMUNITY_SUPPORT_EMAIL, COMMUNITY_SECTIONS;
122
122
  var init_community = __esm(() => {
123
123
  init_links();
124
+ COMMUNITY_SUPPORT_EMAIL = links.contact.replace("mailto:", "");
124
125
  COMMUNITY_SECTIONS = [
125
126
  {
126
127
  title: "Use veyl directly and lawfully",
@@ -160,7 +161,7 @@ var init_community = __esm(() => {
160
161
  {
161
162
  title: "Reporting and support",
162
163
  body: [
163
- `If someone is abusing veyl, contact us at ${links.contact.replace("mailto:", "")} and include the username, profile details, screenshots, or any evidence you choose to provide from your own device.`,
164
+ `If someone is abusing veyl, contact us at ${COMMUNITY_SUPPORT_EMAIL} and include the username, profile details, screenshots, or any evidence you choose to provide from your own device.`,
164
165
  "Because veyl uses end-to-end encryption, we may rely on reports, account-level signals, and evidence you submit when reviewing abuse."
165
166
  ]
166
167
  }
@@ -979,7 +980,7 @@ var package_default;
979
980
  var init_package = __esm(() => {
980
981
  package_default = {
981
982
  name: "veyl",
982
- version: "0.32.1",
983
+ version: "0.35.0",
983
984
  private: true,
984
985
  license: "Apache-2.0",
985
986
  workspaces: {
@@ -995,16 +996,16 @@ var init_package = __esm(() => {
995
996
  "@noble/curves": "^2.2.0",
996
997
  "@noble/hashes": "^2.2.0",
997
998
  "@scure/bip39": "^2.2.0",
998
- "@tailwindcss/postcss": "^4.3.2",
999
+ "@tailwindcss/postcss": "^4.3.3",
999
1000
  bech32: "^2.0.0",
1000
1001
  firebase: "^12.16.0",
1001
1002
  "lucide-react": "^1.24.0",
1002
1003
  next: "16.3.0-preview.6",
1003
1004
  "next-themes": "^0.4.6",
1004
- postcss: "^8.5.19",
1005
- react: "19.2.7",
1006
- "react-dom": "19.2.7",
1007
- tailwindcss: "^4.3.2",
1005
+ postcss: "^8.5.22",
1006
+ react: "19.2.8",
1007
+ "react-dom": "19.2.8",
1008
+ tailwindcss: "^4.3.3",
1008
1009
  "tw-animate-css": "^1.4.0"
1009
1010
  }
1010
1011
  },
@@ -104534,7 +104535,7 @@ var init_seed = __esm(() => {
104534
104535
  });
104535
104536
 
104536
104537
  // ../../shared/config.js
104537
- 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 = 12, PASSWORD_MAX_CHARS = 64, AUTOLOCK_MIN_MINUTES = 1, AUTOLOCK_MAX_MINUTES = 60, 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_AVATAR_CACHE_MAX_BYTES, LOCAL_AVATAR_CACHE_MAX_AGE_MS, AVATAR_IMAGE_MAX_BYTES, CHAT_READY_DOWNLOAD_MAX_BYTES, 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 = 768000, CHAT_VIDEO_TRANSCODE_AUDIO_BITRATE_BPS, CHAT_MESSAGE_BATCH_SIZE = 40, CHAT_MESSAGE_QUERY_MAX_DOCS = 120, CHAT_TTL_CLIENT_DELETE_GRACE_MS, CHAT_TTL_DELETE_CHUNK_SIZE = 40, CHAT_DELETE_SCAN_BATCH_SIZE = 200, CHAT_TTL_WRITE_BATCH_SIZE = 400, CHAT_DELETE_WRITE_BATCH_SIZE = 400, CHAT_BATCH_CLEANUP_IDLE_TIMEOUT_MS = 1500, CHAT_BATCH_CLEANUP_IDLE_DELAY_MS = 250, CHAT_LIST_PAGE_SIZE = 20, CHAT_LIST_LIVE_COUNT, CHAT_INBOX_PING_PAGE_SIZE = 25, CHAT_LIST_CACHE_WRITE_DELAY_MS = 1500, CHAT_LIST_SNAPSHOT_COALESCE_MS = 80, CHAT_LIST_STATUS_CACHE_MS, 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_SEND_QUEUE_RATE_LIMIT_COUNT = 12, CHAT_SEND_QUEUE_RATE_LIMIT_WINDOW_MS, CHAT_MESSAGE_BODY_MAX_BYTES, CHAT_LAST_MESSAGE_BODY_MAX_BYTES, CHAT_SETTINGS_BODY_MAX_BYTES, BOT_WALLET_CLAIM_POLL_MS, BOT_WALLET_IDLE_CLAIM_POLL_MS, CHAT_MAX_TEXT_CHARS = 2048, CHAT_MAX_REACTIONS = 2, CHAT_PAIR_CACHE_LIMIT = 256, 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_INTERVAL_MS, 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_IDLE_ACTIVE_TRANSFER_REFRESH_MS, WALLET_VISIBLE_TRANSFER_DISCOVERY_WINDOW_MS, WALLET_ACTIVE_TRANSFER_EMPTY_SCAN_LIMIT = 8, 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_CACHE_LIMIT = 1e4, 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;
104538
+ 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 = 12, PASSWORD_MAX_CHARS = 64, AUTOLOCK_MIN_MINUTES = 1, AUTOLOCK_MAX_MINUTES = 60, 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_AVATAR_CACHE_MAX_BYTES, LOCAL_AVATAR_CACHE_MAX_AGE_MS, AVATAR_IMAGE_MAX_BYTES, CHAT_READY_DOWNLOAD_MAX_BYTES, 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_TTL_CLIENT_DELETE_GRACE_MS, CHAT_TTL_DELETE_CHUNK_SIZE = 40, CHAT_DELETE_SCAN_BATCH_SIZE = 200, CHAT_TTL_WRITE_BATCH_SIZE = 400, CHAT_DELETE_WRITE_BATCH_SIZE = 400, CHAT_BATCH_CLEANUP_IDLE_TIMEOUT_MS = 1500, CHAT_BATCH_CLEANUP_IDLE_DELAY_MS = 250, CHAT_LIST_PAGE_SIZE = 20, CHAT_LIST_LIVE_COUNT, CHAT_INBOX_PING_PAGE_SIZE = 25, CHAT_LIST_CACHE_WRITE_DELAY_MS = 1500, CHAT_LIST_SNAPSHOT_COALESCE_MS = 80, CHAT_LIST_STATUS_CACHE_MS, 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_SEND_QUEUE_RATE_LIMIT_COUNT = 12, CHAT_SEND_QUEUE_RATE_LIMIT_WINDOW_MS, CHAT_MESSAGE_BODY_MAX_BYTES, CHAT_LAST_MESSAGE_BODY_MAX_BYTES, CHAT_SETTINGS_BODY_MAX_BYTES, BOT_WALLET_CLAIM_POLL_MS, BOT_WALLET_IDLE_CLAIM_POLL_MS, CHAT_MAX_TEXT_CHARS = 2048, CHAT_MAX_REACTIONS = 2, CHAT_PAIR_CACHE_LIMIT = 256, 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_INTERVAL_MS, 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_IDLE_ACTIVE_TRANSFER_REFRESH_MS, WALLET_VISIBLE_TRANSFER_DISCOVERY_WINDOW_MS, WALLET_ACTIVE_TRANSFER_EMPTY_SCAN_LIMIT = 8, 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_CACHE_LIMIT = 1e4, 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;
104538
104539
  var init_config = __esm(() => {
104539
104540
  MINUTE_MS = 60 * MS_PER_SECOND;
104540
104541
  HOUR_MS = 60 * MINUTE_MS;
@@ -105980,20 +105981,17 @@ function expectedSigningKeys(pair, signingKeysByChatKey) {
105980
105981
  }
105981
105982
  return values;
105982
105983
  }
105983
- async function verifyExpectedSignatureBeforeOpen(pair, sig, bytes, options = {}) {
105984
+ async function preverifyExpectedSigner(pair, sig, bytes, options = {}) {
105984
105985
  if (!options?.crypto?.preverifyBeforeOpen) {
105985
- return true;
105986
- }
105987
- const signingKeysByChatKey = expectedSigningKeys(pair, options?.signingKeysByChatKey);
105988
- if (signingKeysByChatKey.length < 2) {
105989
- return true;
105986
+ return "";
105990
105987
  }
105991
- for (const signingPublicKey of signingKeysByChatKey) {
105988
+ const signingPublicKeys = expectedSigningKeys(pair, options?.signingKeysByChatKey);
105989
+ for (const signingPublicKey of signingPublicKeys) {
105992
105990
  if (await verifyMsgSignature(signingPublicKey, sig, bytes, options)) {
105993
- return true;
105991
+ return signingPublicKey;
105994
105992
  }
105995
105993
  }
105996
- return false;
105994
+ return null;
105997
105995
  }
105998
105996
  async function sealMsg(pair, message, options = {}) {
105999
105997
  const head = getHead(pair, message);
@@ -106014,14 +106012,16 @@ async function openMsg(pair, data, options = {}) {
106014
106012
  const { suite, flags, nonce, sig, ct } = unpackMsgBody(data.body);
106015
106013
  const aad = getMsgAad(pair, head, suite, flags);
106016
106014
  const signatureInput = getSignatureInput(aad, nonce, ct);
106017
- if (!await verifyExpectedSignatureBeforeOpen(pair, sig, signatureInput, options)) {
106015
+ const preverifiedSigner = await preverifyExpectedSigner(pair, sig, signatureInput, options);
106016
+ if (preverifiedSigner == null) {
106018
106017
  throw new Error("invalid chat action signature");
106019
106018
  }
106020
106019
  const plaintext = await openMsgPlaintext(pair, nonce, ct, aad, options);
106021
106020
  try {
106022
106021
  const action = JSON.parse(decoder.decode(plaintext));
106023
106022
  const normalized = normalizeOpenedAction(pair, head, action, options);
106024
- if (!await verifyMsgSignature(normalized.signingPublicKey, sig, signatureInput, options)) {
106023
+ const validSignature = preverifiedSigner ? normalized.signingPublicKey === preverifiedSigner : await verifyMsgSignature(normalized.signingPublicKey, sig, signatureInput, options);
106024
+ if (!validSignature) {
106025
106025
  throw new Error("invalid chat action signature");
106026
106026
  }
106027
106027
  return {
@@ -106095,40 +106095,120 @@ var init_protocol = __esm(() => {
106095
106095
  });
106096
106096
 
106097
106097
  // ../../shared/chat/pairs.js
106098
+ function accountGeneration(chatPK) {
106099
+ return accountGenerations.get(cleanText(chatPK)) || 0;
106100
+ }
106098
106101
  function getChatPairKey(chatPK, peerChatPK, chatId = "") {
106099
106102
  if (!chatPK || !peerChatPK)
106100
106103
  return null;
106101
106104
  return `${cleanText(chatPK)}|${cleanText(peerChatPK)}|${cleanText(chatId)}`;
106102
106105
  }
106103
- function clearChatPairCache() {
106104
- for (const pair of pairCache.values()) {
106105
- closeChatPair(pair);
106106
+ function closeEntry(entry) {
106107
+ if (!entry || entry.closed || entry.leases > 0) {
106108
+ return;
106109
+ }
106110
+ entry.closed = true;
106111
+ closeChatPair(entry.pair);
106112
+ }
106113
+ function retireEntry(entry) {
106114
+ if (!entry || entry.retired) {
106115
+ return;
106116
+ }
106117
+ entry.retired = true;
106118
+ closeEntry(entry);
106119
+ }
106120
+ function releaseEntry(entry) {
106121
+ if (!entry || entry.leases <= 0) {
106122
+ return;
106123
+ }
106124
+ entry.leases -= 1;
106125
+ if (entry.retired) {
106126
+ closeEntry(entry);
106106
106127
  }
106107
- pairCache.clear();
106108
106128
  }
106109
- async function getCachedPair(chatPK, chatPrivKey, peerChatPK, options = {}) {
106129
+ function evictOverflow() {
106130
+ while (pairCache.size > MAX_PAIR_CACHE) {
106131
+ const firstKey = pairCache.keys().next().value;
106132
+ if (!firstKey) {
106133
+ return;
106134
+ }
106135
+ const entry = pairCache.get(firstKey);
106136
+ pairCache.delete(firstKey);
106137
+ retireEntry(entry);
106138
+ }
106139
+ }
106140
+ function clearChatPairCache(chatPK = "") {
106141
+ const account = cleanText(chatPK);
106142
+ if (!account) {
106143
+ cacheGeneration += 1;
106144
+ accountGenerations.clear();
106145
+ for (const entry of pairCache.values()) {
106146
+ retireEntry(entry);
106147
+ }
106148
+ pairCache.clear();
106149
+ return;
106150
+ }
106151
+ accountGenerations.set(account, accountGeneration(account) + 1);
106152
+ for (const [key, entry] of pairCache) {
106153
+ if (entry.account !== account) {
106154
+ continue;
106155
+ }
106156
+ pairCache.delete(key);
106157
+ retireEntry(entry);
106158
+ }
106159
+ }
106160
+ async function acquireCachedPair(chatPK, chatPrivKey, peerChatPK, options = {}) {
106161
+ const account = cleanText(chatPK);
106110
106162
  const chatId = cleanText(options?.chatId);
106111
106163
  const key = getChatPairKey(chatPK, peerChatPK, chatId);
106164
+ const generation = cacheGeneration;
106165
+ const accountVersion = accountGeneration(account);
106112
106166
  if (!key) {
106113
- return openChatPair(chatPK, chatPrivKey, peerChatPK, { chatId });
106167
+ const pair = await openChatPair(chatPK, chatPrivKey, peerChatPK, { chatId });
106168
+ const entry2 = { pair, leases: 1, retired: true, closed: false };
106169
+ return {
106170
+ pair,
106171
+ release: () => releaseEntry(entry2)
106172
+ };
106114
106173
  }
106115
- const cached = pairCache.get(key);
106116
- if (cached)
106117
- return cached;
106118
- const pair = await openChatPair(chatPK, chatPrivKey, peerChatPK, { chatId });
106119
- pairCache.set(key, pair);
106120
- if (pairCache.size > MAX_PAIR_CACHE) {
106121
- const firstKey = pairCache.keys().next().value;
106122
- if (firstKey) {
106123
- closeChatPair(pairCache.get(firstKey));
106124
- pairCache.delete(firstKey);
106174
+ let entry = pairCache.get(key);
106175
+ if (!entry) {
106176
+ const pair = await openChatPair(chatPK, chatPrivKey, peerChatPK, { chatId });
106177
+ if (generation !== cacheGeneration || accountVersion !== accountGeneration(account)) {
106178
+ const staleEntry = { pair, leases: 1, retired: true, closed: false };
106179
+ return {
106180
+ pair,
106181
+ release: () => releaseEntry(staleEntry)
106182
+ };
106125
106183
  }
106184
+ entry = pairCache.get(key);
106185
+ if (entry) {
106186
+ closeChatPair(pair);
106187
+ } else {
106188
+ entry = { account, pair, leases: 0, retired: false, closed: false };
106189
+ pairCache.set(key, entry);
106190
+ evictOverflow();
106191
+ }
106192
+ } else {
106193
+ pairCache.delete(key);
106194
+ pairCache.set(key, entry);
106195
+ }
106196
+ entry.leases += 1;
106197
+ return {
106198
+ pair: entry.pair,
106199
+ release: () => releaseEntry(entry)
106200
+ };
106201
+ }
106202
+ async function withCachedPair(chatPK, chatPrivKey, peerChatPK, options, runWithPair) {
106203
+ const { pair, release } = await acquireCachedPair(chatPK, chatPrivKey, peerChatPK, options);
106204
+ try {
106205
+ return await runWithPair(pair);
106206
+ } finally {
106207
+ release();
106126
106208
  }
106127
- return pair;
106128
106209
  }
106129
106210
  async function resolveLinkId(chatPK, chatPrivKey, peerChatPK) {
106130
- const pair = await getCachedPair(chatPK, chatPrivKey, peerChatPK);
106131
- return pair?.linkId || null;
106211
+ return withCachedPair(chatPK, chatPrivKey, peerChatPK, {}, (pair) => pair?.linkId || null);
106132
106212
  }
106133
106213
  async function resolvePeerChat(cloud, chatPK, chatPrivateKey, peerChatPK, options = {}) {
106134
106214
  const existingChatId = cleanText(options?.chatId);
@@ -106159,13 +106239,14 @@ async function resolvePeerChat(cloud, chatPK, chatPrivateKey, peerChatPK, option
106159
106239
  exists: linkChat?.exists === true
106160
106240
  };
106161
106241
  }
106162
- var pairCache, MAX_PAIR_CACHE;
106242
+ var pairCache, MAX_PAIR_CACHE, cacheGeneration = 0, accountGenerations;
106163
106243
  var init_pairs = __esm(() => {
106164
106244
  init_config();
106165
106245
  init_chat();
106166
106246
  init_protocol();
106167
106247
  pairCache = new Map;
106168
106248
  MAX_PAIR_CACHE = CHAT_PAIR_CACHE_LIMIT;
106249
+ accountGenerations = new Map;
106169
106250
  });
106170
106251
 
106171
106252
  // ../../shared/utils/diagnostics.js
@@ -106318,14 +106399,16 @@ function lockWallet(wallet) {
106318
106399
  cleanup?.catch?.(() => {});
106319
106400
  } catch {}
106320
106401
  }
106321
- function lockChat(chatPrivateKey) {
106402
+ function lockChat(chatPrivateKey, chatPK = "") {
106322
106403
  try {
106323
106404
  if (chatPrivateKey) {
106324
106405
  chatPrivateKey.fill(0);
106325
106406
  }
106326
106407
  } catch {}
106327
106408
  try {
106328
- clearChatPairCache();
106409
+ if (chatPK) {
106410
+ clearChatPairCache(chatPK);
106411
+ }
106329
106412
  } catch {}
106330
106413
  }
106331
106414
  var init_vault = __esm(() => {
@@ -106345,7 +106428,7 @@ function walletPubkey(value) {
106345
106428
  }
106346
106429
  return key;
106347
106430
  }
106348
- function closeSessionResources({ wallet, chatPrivateKey, localCache, vaultAccess, vaultSigner } = {}) {
106431
+ function closeSessionResources({ wallet, chatPK, chatPrivateKey, localCache, vaultAccess, vaultSigner } = {}) {
106349
106432
  try {
106350
106433
  vaultAccess?.close?.();
106351
106434
  } catch {}
@@ -106356,7 +106439,7 @@ function closeSessionResources({ wallet, chatPrivateKey, localCache, vaultAccess
106356
106439
  localCache?.close?.();
106357
106440
  } catch {}
106358
106441
  lockWallet(wallet);
106359
- lockChat(chatPrivateKey);
106442
+ lockChat(chatPrivateKey, chatPK);
106360
106443
  }
106361
106444
  function createAccountSession(resources = {}) {
106362
106445
  let closed = false;
@@ -106447,6 +106530,32 @@ function notifySeedDecrypted(callback, markDiag2, source) {
106447
106530
  failed(error);
106448
106531
  }
106449
106532
  }
106533
+ function startWalletBoot(bootWallet2, walletMnemonic, user, options) {
106534
+ let closed = false;
106535
+ let handedOff = false;
106536
+ let wallet = null;
106537
+ const result = Promise.resolve().then(() => bootWallet2(walletMnemonic, user, options)).then((identity) => {
106538
+ wallet = identity?.wallet || null;
106539
+ if (closed && wallet) {
106540
+ lockWallet(wallet);
106541
+ }
106542
+ return identity;
106543
+ });
106544
+ return {
106545
+ result,
106546
+ handoff() {
106547
+ handedOff = true;
106548
+ },
106549
+ close() {
106550
+ if (closed)
106551
+ return;
106552
+ closed = true;
106553
+ if (wallet && !handedOff) {
106554
+ lockWallet(wallet);
106555
+ }
106556
+ }
106557
+ };
106558
+ }
106450
106559
  async function openVaultAccountSession(vault, password, options = {}) {
106451
106560
  const {
106452
106561
  uid,
@@ -106488,6 +106597,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
106488
106597
  throw new Error("unlockSettings missing");
106489
106598
  const { decryptSeed: decryptSeed2, unpackVaultSeedData } = vaultCrypto;
106490
106599
  let wallet = null;
106600
+ let chatPK = "";
106491
106601
  let chatPrivateKey = null;
106492
106602
  let localCache = null;
106493
106603
  let masterSeed = null;
@@ -106498,6 +106608,7 @@ async function openVaultAccountSession(vault, password, options = {}) {
106498
106608
  let vaultSigner = null;
106499
106609
  let vaultAccess = null;
106500
106610
  let vaultAccessResult = null;
106611
+ let walletBoot = null;
106501
106612
  let network;
106502
106613
  try {
106503
106614
  onStage?.("unlocking");
@@ -106566,46 +106677,18 @@ async function openVaultAccountSession(vault, password, options = {}) {
106566
106677
  onStage?.("wallet");
106567
106678
  const walletStartedAt = Date.now();
106568
106679
  mark(diag, "vault.unlock.wallet.start", { source });
106569
- const walletIdentity = await bootWallet2(walletMnemonic, user, { network, diag });
106570
- wallet = walletIdentity?.wallet;
106571
- const walletPK = walletPubkey(walletIdentity?.walletPK);
106572
- mark(diag, "vault.unlock.wallet.done", { elapsedMs: Date.now() - walletStartedAt, source });
106573
- requireCurrent(isCurrent);
106680
+ walletBoot = startWalletBoot(bootWallet2, walletMnemonic, user, { network, diag });
106574
106681
  onStage?.("chat");
106575
106682
  const chatStartedAt = Date.now();
106576
106683
  mark(diag, "vault.unlock.chat.start", { source });
106577
106684
  const chatIdentity = await bootChat2(chatSeed, user, { diag });
106578
106685
  chatPrivateKey = chatIdentity?.chatPrivateKey;
106579
- const chatPK = cleanText(chatIdentity?.chatPK);
106686
+ chatPK = cleanText(chatIdentity?.chatPK);
106580
106687
  if (!chatPrivateKey || !chatPK)
106581
106688
  throw new Error("chat identity missing");
106582
106689
  chatSeed = null;
106583
106690
  mark(diag, "vault.unlock.chat.done", { elapsedMs: Date.now() - chatStartedAt, source });
106584
106691
  requireCurrent(isCurrent);
106585
- const identityPayload = {};
106586
- if (walletIdentity?.walletPKNeedsWrite) {
106587
- identityPayload.walletPK = walletPK;
106588
- identityPayload.network = network;
106589
- }
106590
- if (chatIdentity?.chatPKNeedsWrite) {
106591
- identityPayload.chatPK = chatPK;
106592
- }
106593
- const identityFields = Object.keys(identityPayload);
106594
- let identityResult = null;
106595
- if (identityFields.length) {
106596
- const identitiesStartedAt = Date.now();
106597
- mark(diag, "vault.unlock.identities.start", { source, fields: identityFields });
106598
- identityResult = cloud.user.profile.identity.write(identityPayload).then(() => {
106599
- mark(diag, "vault.unlock.identities.done", {
106600
- elapsedMs: Date.now() - identitiesStartedAt,
106601
- source,
106602
- fields: identityFields
106603
- });
106604
- return { error: null };
106605
- }, (error) => ({ error }));
106606
- } else {
106607
- mark(diag, "vault.unlock.identities.skip", { source });
106608
- }
106609
106692
  const cacheStartedAt = Date.now();
106610
106693
  mark(diag, "vault.unlock.localCache.start", { source });
106611
106694
  localCache = await openLocalCache(cacheKey, { uid, network });
@@ -106613,20 +106696,16 @@ async function openVaultAccountSession(vault, password, options = {}) {
106613
106696
  cleanBytes(cacheKey);
106614
106697
  cacheKey = null;
106615
106698
  requireCurrent(isCurrent);
106616
- const identityWrite = await identityResult;
106617
- if (identityWrite?.error)
106618
- throw identityWrite.error;
106619
- requireCurrent(isCurrent);
106620
106699
  const signatureResult = await vaultAccessResult;
106621
106700
  if (signatureResult.error)
106622
106701
  throw signatureResult.error;
106623
106702
  vaultAccess = signatureResult.access;
106624
106703
  requireCurrent(isCurrent);
106625
- return createAccountSession({
106704
+ const session = createAccountSession({
106626
106705
  uid,
106627
106706
  network,
106628
- wallet,
106629
- walletPK,
106707
+ wallet: null,
106708
+ walletPK: null,
106630
106709
  chatPK,
106631
106710
  chatPrivateKey,
106632
106711
  localCache,
@@ -106634,12 +106713,56 @@ async function openVaultAccountSession(vault, password, options = {}) {
106634
106713
  vaultAccess,
106635
106714
  vaultPK: vaultSigner.publicKey
106636
106715
  });
106716
+ session.own(walletBoot);
106717
+ const walletReady = walletBoot.result.then(async (walletIdentity) => {
106718
+ if (session.closed)
106719
+ throw new Error("account session closed");
106720
+ const readyWallet = walletIdentity?.wallet;
106721
+ const walletPK = walletPubkey(walletIdentity?.walletPK);
106722
+ if (!readyWallet)
106723
+ throw new Error("wallet missing");
106724
+ mark(diag, "vault.unlock.wallet.done", { elapsedMs: Date.now() - walletStartedAt, source });
106725
+ const identityPayload = {};
106726
+ if (walletIdentity?.walletPKNeedsWrite) {
106727
+ identityPayload.walletPK = walletPK;
106728
+ identityPayload.network = network;
106729
+ }
106730
+ if (chatIdentity?.chatPKNeedsWrite) {
106731
+ identityPayload.chatPK = chatPK;
106732
+ }
106733
+ const identityFields = Object.keys(identityPayload);
106734
+ if (identityFields.length) {
106735
+ const identitiesStartedAt = Date.now();
106736
+ mark(diag, "vault.unlock.identities.start", { source, fields: identityFields });
106737
+ await cloud.user.profile.identity.write(identityPayload);
106738
+ mark(diag, "vault.unlock.identities.done", {
106739
+ elapsedMs: Date.now() - identitiesStartedAt,
106740
+ source,
106741
+ fields: identityFields
106742
+ });
106743
+ } else {
106744
+ mark(diag, "vault.unlock.identities.skip", { source });
106745
+ }
106746
+ if (session.closed)
106747
+ throw new Error("account session closed");
106748
+ walletBoot.handoff();
106749
+ session.wallet = readyWallet;
106750
+ session.walletPK = walletPK;
106751
+ return { wallet: readyWallet, walletPK };
106752
+ }).catch((error) => {
106753
+ walletBoot.close();
106754
+ throw error;
106755
+ });
106756
+ walletReady.catch(() => {});
106757
+ session.walletReady = walletReady;
106758
+ return session;
106637
106759
  } catch (error) {
106760
+ walletBoot?.close();
106638
106761
  if (vaultAccessResult && !vaultAccess) {
106639
106762
  const signatureResult = await vaultAccessResult;
106640
106763
  vaultAccess = signatureResult.access;
106641
106764
  }
106642
- closeSessionResources({ wallet, chatPrivateKey, localCache, vaultAccess, vaultSigner });
106765
+ closeSessionResources({ wallet, chatPK, chatPrivateKey, localCache, vaultAccess, vaultSigner });
106643
106766
  throw error;
106644
106767
  } finally {
106645
106768
  cleanBytes(masterSeed, walletEntropy, chatSeed, cacheKey, settingsKey);
@@ -106654,6 +106777,7 @@ async function openAccountSessionFromSecrets(walletEntropy, chatSeed, masterSeed
106654
106777
  }
106655
106778
  const walletMnemonic = mnemonicFromWalletEntropy(walletEntropy);
106656
106779
  let wallet = null;
106780
+ let chatPK = "";
106657
106781
  let chatPrivateKey = null;
106658
106782
  let chatPubKey = null;
106659
106783
  let vaultSigner = null;
@@ -106682,10 +106806,11 @@ async function openAccountSessionFromSecrets(walletEntropy, chatSeed, masterSeed
106682
106806
  throw new Error("vault signature uid missing");
106683
106807
  vaultAccess = await cloud.auth.vaultSignature.open(vaultSigner);
106684
106808
  }
106809
+ chatPK = toHex(chatPubKey);
106685
106810
  return createAccountSession({
106686
106811
  wallet,
106687
106812
  walletPK,
106688
- chatPK: toHex(chatPubKey),
106813
+ chatPK,
106689
106814
  chatPrivateKey,
106690
106815
  localCache,
106691
106816
  network,
@@ -106694,7 +106819,7 @@ async function openAccountSessionFromSecrets(walletEntropy, chatSeed, masterSeed
106694
106819
  vaultPK: vaultSigner.publicKey
106695
106820
  });
106696
106821
  } catch (error) {
106697
- closeSessionResources({ wallet, chatPrivateKey, localCache, vaultAccess, vaultSigner });
106822
+ closeSessionResources({ wallet, chatPK, chatPrivateKey, localCache, vaultAccess, vaultSigner });
106698
106823
  throw error;
106699
106824
  } finally {
106700
106825
  cleanBytes(chatSeed, chatPubKey);
@@ -107770,7 +107895,7 @@ function getSubtleCrypto() {
107770
107895
  async function importAesKey(key, usages) {
107771
107896
  return getSubtleCrypto().importKey("raw", toBytes32(key, "file key"), { name: "AES-GCM" }, false, usages);
107772
107897
  }
107773
- async function sealFile(_pair, key, bytes, scope) {
107898
+ async function sealFile(key, bytes, scope) {
107774
107899
  const fileKey = new Uint8Array(toBytes32(key, "file key"));
107775
107900
  try {
107776
107901
  const cryptoKey = await importAesKey(fileKey, ["encrypt"]);
@@ -107933,20 +108058,22 @@ async function toUploadBytes(data) {
107933
108058
  }
107934
108059
  return toBytes2(data, "upload bytes");
107935
108060
  }
107936
- async function makeChatFileUploadPayload(pair, cid, data, { cacheControl = "private, max-age=0, no-transform" } = {}) {
107937
- const chatId = cleanMediaChatId(pair?.chatId);
108061
+ async function makeChatFileUploadPayload(chatId, cid, data, { cacheControl = "private, max-age=0, no-transform" } = {}) {
108062
+ const nextChatId = cleanMediaChatId(chatId);
107938
108063
  const mediaId = makeChatMediaId();
107939
- const path = mediaFilePath(chatId, mediaId);
108064
+ const path = mediaFilePath(nextChatId, mediaId);
107940
108065
  const expiresAt = Date.now() + CHAT_MEDIA_TTL_MS2;
107941
108066
  const key = createFileKey();
107942
108067
  try {
107943
108068
  const uploadBytes = await toUploadBytes(data);
107944
108069
  assertChatUploadByteSize(uploadBytes);
108070
+ const body = await sealFile(key, uploadBytes, path);
108071
+ assertChatUploadByteSize(body);
107945
108072
  return {
107946
- chatId,
108073
+ chatId: nextChatId,
107947
108074
  mediaId,
107948
108075
  path,
107949
- body: await sealFile(pair, key, uploadBytes, path),
108076
+ body,
107950
108077
  metadata: {
107951
108078
  contentType: "application/octet-stream",
107952
108079
  cacheControl
@@ -107975,10 +108102,12 @@ async function makeSharedFileUploadPayload(data, { contentType = "application/oc
107975
108102
  try {
107976
108103
  const uploadBytes = await toUploadBytes(data);
107977
108104
  assertChatUploadByteSize(uploadBytes);
108105
+ const body = await sealFile(key, uploadBytes, path);
108106
+ assertChatUploadByteSize(body);
107978
108107
  return {
107979
108108
  sharedId,
107980
108109
  path,
107981
- body: await sealFile(null, key, uploadBytes, path),
108110
+ body,
107982
108111
  metadata: {
107983
108112
  contentType,
107984
108113
  cacheControl
@@ -109904,10 +110033,19 @@ function sortedUniqueValues(items) {
109904
110033
  }
109905
110034
 
109906
110035
  // ../../shared/chat/chats.js
110036
+ function sameSigningKeys(left, right) {
110037
+ if (left === right)
110038
+ return true;
110039
+ const leftKeys = Object.keys(left || {});
110040
+ const rightKeys = Object.keys(right || {});
110041
+ if (leftKeys.length !== rightKeys.length)
110042
+ return false;
110043
+ return leftKeys.every((key) => left[key] === right[key]);
110044
+ }
109907
110045
  function sameChatShape(a, b) {
109908
110046
  if (!a || !b)
109909
110047
  return a === b;
109910
- return a.id === b.id && a.protocol === b.protocol && a.linkId === b.linkId && a.ts === b.ts && a.startMs === b.startMs && a.unseen === b.unseen && a.settings?.retention === b.settings?.retention && sameChatPreview(a.preview, b.preview);
110048
+ return a.id === b.id && a.protocol === b.protocol && a.linkId === b.linkId && a.entryId === b.entryId && a.peerChatPK === b.peerChatPK && a.peerUid === b.peerUid && sameSigningKeys(a.signingKeysByChatKey, b.signingKeysByChatKey) && a.ts === b.ts && a.startMs === b.startMs && a.unseen === b.unseen && a.settings?.retention === b.settings?.retention && sameChatPreview(a.preview, b.preview);
109911
110049
  }
109912
110050
  function sameChats(prev, next) {
109913
110051
  if (prev.length !== next.length)
@@ -111470,8 +111608,14 @@ function mediaAad(uid, network, id) {
111470
111608
  function partAad(uid, network, part) {
111471
111609
  return encoder.encode(JSON.stringify(["veyl-local-cache-part", CACHE_PART_ENVELOPE_VERSION, String(uid || ""), String(network || ""), String(part || "")]));
111472
111610
  }
111611
+ function encodePayloadData(payload) {
111612
+ return encoder.encode(JSON.stringify({ ...normalizePayload(payload), savedAt: Date.now() }));
111613
+ }
111614
+ function decodePayloadData(raw) {
111615
+ return JSON.parse(decoder.decode(toBytes2(raw, "cache payload")));
111616
+ }
111473
111617
  async function sealPayload(key, payload, uid, network) {
111474
- const body = encoder.encode(JSON.stringify({ ...normalizePayload(payload), savedAt: Date.now() }));
111618
+ const body = encodePayloadData(payload);
111475
111619
  try {
111476
111620
  const { iv, ct } = await sealAes(key, body, cacheAad(uid, network));
111477
111621
  return JSON.stringify({
@@ -111493,7 +111637,7 @@ async function openPayloadData(key, raw, uid, network) {
111493
111637
  }
111494
111638
  const plain = await openAes(key, fromHexBytes(envelope.iv, "cache iv"), fromHexBytes(envelope.ct, "cache ciphertext"), cacheAad(uid, network));
111495
111639
  try {
111496
- return JSON.parse(decoder.decode(plain));
111640
+ return decodePayloadData(plain);
111497
111641
  } finally {
111498
111642
  cleanBytes(plain);
111499
111643
  }
@@ -111554,6 +111698,14 @@ function mediaCrypto(uid, network, id, keyBytes) {
111554
111698
  ivBytes: AES_IV_BYTES
111555
111699
  };
111556
111700
  }
111701
+ function payloadCrypto(uid, network, keyBytes) {
111702
+ return {
111703
+ key: keyBytes,
111704
+ aad: cacheAad(uid, network),
111705
+ version: LOCAL_DATA_CACHE_VERSION,
111706
+ ivBytes: AES_IV_BYTES
111707
+ };
111708
+ }
111557
111709
  var MEDIA_ENVELOPE_VERSION = 1, CACHE_PART_ENVELOPE_VERSION = 1;
111558
111710
  var init_crypto = __esm(() => {
111559
111711
  init_aes2();
@@ -111589,11 +111741,32 @@ async function openVaultCache({ key, storage, uid, network }) {
111589
111741
  let writeTimer = null;
111590
111742
  let writeTask = Promise.resolve();
111591
111743
  const partWriteTasks = new Map;
111744
+ let storedPayload = null;
111592
111745
  try {
111593
- const rawPayload = await openPayloadData(cacheKey, await storage.read(), uid, network);
111594
- payload = normalizePayload(rawPayload);
111746
+ storedPayload = await storage.read();
111747
+ if (!storedPayload) {
111748
+ payload = emptyPayload();
111749
+ } else if (typeof storage.openPayload === "function") {
111750
+ const readKey = new Uint8Array(cacheKey);
111751
+ let plain;
111752
+ try {
111753
+ plain = await storage.openPayload(storedPayload, payloadCrypto(uid, network, readKey));
111754
+ payload = normalizePayload(decodePayloadData(plain));
111755
+ } finally {
111756
+ cleanBytes(plain, readKey);
111757
+ }
111758
+ } else {
111759
+ payload = normalizePayload(await openPayloadData(cacheKey, storedPayload, uid, network));
111760
+ }
111595
111761
  } catch {
111596
111762
  payload = emptyPayload();
111763
+ if (storedPayload) {
111764
+ await Promise.all([
111765
+ storage.remove().catch(() => {}),
111766
+ storage.removeAllMedia().catch(() => {}),
111767
+ storage.removeAllParts().catch(() => {})
111768
+ ]);
111769
+ }
111597
111770
  }
111598
111771
  const writeNow = () => {
111599
111772
  if (closed) {
@@ -111611,10 +111784,12 @@ async function openVaultCache({ key, storage, uid, network }) {
111611
111784
  return;
111612
111785
  }
111613
111786
  const writeKey = new Uint8Array(cacheKey);
111787
+ let body;
111614
111788
  try {
111615
- await storage.write(await sealPayload(writeKey, payload, uid, network));
111789
+ const raw = typeof storage.sealPayload === "function" ? await storage.sealPayload(body = encodePayloadData(payload), payloadCrypto(uid, network, writeKey)) : await sealPayload(writeKey, payload, uid, network);
111790
+ await storage.write(raw);
111616
111791
  } finally {
111617
- cleanBytes(writeKey);
111792
+ cleanBytes(body, writeKey);
111618
111793
  }
111619
111794
  }).catch(() => {});
111620
111795
  return writeTask;
@@ -112417,9 +112592,9 @@ function setErrorStage(error, stage, extra = {}) {
112417
112592
  Object.assign(error, extra);
112418
112593
  return error;
112419
112594
  }
112420
- async function makeChatFileUpload(pair, cid, data, { cacheControl = "private, max-age=0, no-transform" } = {}) {
112595
+ async function makeChatFileUpload(chatId, cid, data, { cacheControl = "private, max-age=0, no-transform" } = {}) {
112421
112596
  try {
112422
- return await makeChatFileUploadPayload(pair, cid, data, {
112597
+ return await makeChatFileUploadPayload(chatId, cid, data, {
112423
112598
  cacheControl
112424
112599
  });
112425
112600
  } catch (error) {
@@ -112429,8 +112604,8 @@ async function makeChatFileUpload(pair, cid, data, { cacheControl = "private, ma
112429
112604
  });
112430
112605
  }
112431
112606
  }
112432
- async function putChatFile(pair, cid, data, options) {
112433
- const upload = await makeChatFileUpload(pair, cid, data, options);
112607
+ async function putChatFile(chatId, cid, data, options) {
112608
+ const upload = await makeChatFileUpload(chatId, cid, data, options);
112434
112609
  try {
112435
112610
  if (typeof options?.uploadChatMedia !== "function") {
112436
112611
  throw new Error("chat media upload required");
@@ -112465,7 +112640,7 @@ async function putSharedFile(data, options = {}) {
112465
112640
  throw setErrorStage(error, "upload", { path: upload.path });
112466
112641
  }
112467
112642
  }
112468
- async function readChatFile(readChatMedia, _pair, file) {
112643
+ async function readChatFile(readChatMedia, file) {
112469
112644
  let body;
112470
112645
  try {
112471
112646
  if (typeof readChatMedia !== "function") {
@@ -112523,8 +112698,8 @@ function buildAttachmentMsg(type, file) {
112523
112698
  return makeAttachment(type, file);
112524
112699
  }
112525
112700
  }
112526
- async function putAttachment(pair, cid, type, data, meta = {}) {
112527
- const file = await putChatFile(pair, cid, data, meta);
112701
+ async function putAttachment(chatId, cid, type, data, meta = {}) {
112702
+ const file = await putChatFile(chatId, cid, data, meta);
112528
112703
  return buildAttachmentMsg(type, {
112529
112704
  ...file,
112530
112705
  ...pickAttachmentMeta(meta)
@@ -112537,26 +112712,26 @@ async function putSharedAttachment(type, data, meta = {}) {
112537
112712
  ...pickAttachmentMeta(meta)
112538
112713
  });
112539
112714
  }
112540
- async function putImg(pair, cid, data, meta = {}) {
112541
- return putAttachment(pair, cid, "img", data, meta);
112715
+ async function putImg(chatId, cid, data, meta = {}) {
112716
+ return putAttachment(chatId, cid, "img", data, meta);
112542
112717
  }
112543
- async function putGif(pair, cid, data, meta = {}) {
112544
- return putAttachment(pair, cid, "gif", data, meta);
112718
+ async function putGif(chatId, cid, data, meta = {}) {
112719
+ return putAttachment(chatId, cid, "gif", data, meta);
112545
112720
  }
112546
- async function putM4a(pair, cid, data, meta = {}) {
112547
- return putAttachment(pair, cid, "m4a", data, meta);
112721
+ async function putM4a(chatId, cid, data, meta = {}) {
112722
+ return putAttachment(chatId, cid, "m4a", data, meta);
112548
112723
  }
112549
- async function putMp4(pair, cid, data, meta = {}) {
112550
- return putAttachment(pair, cid, "mp4", data, meta);
112724
+ async function putMp4(chatId, cid, data, meta = {}) {
112725
+ return putAttachment(chatId, cid, "mp4", data, meta);
112551
112726
  }
112552
- async function putFile(pair, cid, data, meta = {}) {
112553
- return putAttachment(pair, cid, "file", data, meta);
112727
+ async function putFile(chatId, cid, data, meta = {}) {
112728
+ return putAttachment(chatId, cid, "file", data, meta);
112554
112729
  }
112555
- function readMsgAttachment(readChatMedia, pair, msg) {
112556
- return readChatFile(readChatMedia, pair, msg);
112730
+ function readMsgAttachment(readChatMedia, msg) {
112731
+ return readChatFile(readChatMedia, msg);
112557
112732
  }
112558
- function readMsgFile(readChatMedia, pair, msg) {
112559
- return readMsgAttachment(readChatMedia, pair, msg);
112733
+ function readMsgFile(readChatMedia, msg) {
112734
+ return readMsgAttachment(readChatMedia, msg);
112560
112735
  }
112561
112736
  var init_media2 = __esm(() => {
112562
112737
  init_files2();
@@ -112805,14 +112980,6 @@ function ownerEditedPreview(senderPubkey, message) {
112805
112980
  failed: false
112806
112981
  };
112807
112982
  }
112808
- function messageFileChatId(message) {
112809
- try {
112810
- const ref = getMediaFileRef(message?.p);
112811
- return ref?.type === "chat" ? ref.chatId : "";
112812
- } catch {
112813
- return "";
112814
- }
112815
- }
112816
112983
  async function recipientForSend(cloud, receiverChatPK, options, needed) {
112817
112984
  if (!needed) {
112818
112985
  return null;
@@ -112833,50 +113000,51 @@ async function sendMsg(cloud, senderPubkey, senderPrivkey, receiverChatPK, messa
112833
113000
  if (!chatId) {
112834
113001
  throw new Error("chat id required");
112835
113002
  }
112836
- const pair = await getCachedPair(senderPubkey, senderPrivkey, receiverChatPK, { chatId });
112837
- if (options?.linkId && cleanText(options.linkId) !== pair.linkId) {
112838
- throw new Error("link mismatch");
112839
- }
112840
- const retention = cleanChatRetention(options?.retention ?? options?.ttlMode);
112841
- const tsMs = Date.now();
112842
- const messagePayload = withMessageRetention(message, retention);
112843
- const actionOp = actionOpForPayload(messagePayload);
112844
- const { head, body } = await sealMsg(pair, messagePayload, { op: actionOp, ts: tsMs });
112845
- const ttlMs = actionOp === CHAT_ACTION_OPS.CREATE ? newStorageTtlMs() : null;
112846
- const messageId = head.cid;
112847
- const msgData = {
112848
- head,
112849
- body,
112850
- ttlMs
112851
- };
112852
- const recipientProfile = await recipientForSend(cloud, receiverChatPK, options, updatePreview || options?.ping === true);
112853
- const sentMessage = ownerPreview(senderPubkey, messagePayload, messageId, head, tsMs, ttlMs);
112854
- const preview2 = updatePreview ? sentMessage : null;
112855
- const ownerEntry = updatePreview ? await ownEntryWrite(cloud, cleanText(options?.senderUid), senderPrivkey, pair, {
112856
- peerUid: recipientProfile?.uid || cleanText(options?.receiverUid),
112857
- peerSigningPublicKey: recipientProfile?.signingPublicKey,
112858
- entry: options?.ownEntry,
112859
- settings: options?.chatSettings,
112860
- preview: preview2,
112861
- ts: tsMs
112862
- }) : null;
112863
- const pingKind = updatePreview ? "message" : cleanText(options?.pingKind) || "ping";
112864
- const ping = recipientProfile?.uid && (updatePreview || options?.ping === true) ? await sealPing(senderPubkey, senderPrivkey, receiverChatPK, {
112865
- kind: pingKind,
112866
- chatId,
112867
- senderUid: cleanText(options?.senderUid),
112868
- messageId,
112869
- ts: tsMs
112870
- }) : null;
112871
- const write = await cloud.chat.messages.send({
112872
- chatId,
112873
- messageId,
112874
- message: msgData,
112875
- ownerEntry,
112876
- inbox: ping ? { recipientUid: recipientProfile?.uid, ping } : null,
112877
- onCommitted: typeof options?.onCommitted === "function" ? (committed) => options.onCommitted({ ...committed, message: sentMessage, preview: preview2 }) : undefined
113003
+ return withCachedPair(senderPubkey, senderPrivkey, receiverChatPK, { chatId }, async (pair) => {
113004
+ if (options?.linkId && cleanText(options.linkId) !== pair.linkId) {
113005
+ throw new Error("link mismatch");
113006
+ }
113007
+ const retention = cleanChatRetention(options?.retention ?? options?.ttlMode);
113008
+ const tsMs = Date.now();
113009
+ const messagePayload = withMessageRetention(message, retention);
113010
+ const actionOp = actionOpForPayload(messagePayload);
113011
+ const { head, body } = await sealMsg(pair, messagePayload, { op: actionOp, ts: tsMs });
113012
+ const ttlMs = actionOp === CHAT_ACTION_OPS.CREATE ? newStorageTtlMs() : null;
113013
+ const messageId = head.cid;
113014
+ const msgData = {
113015
+ head,
113016
+ body,
113017
+ ttlMs
113018
+ };
113019
+ const recipientProfile = await recipientForSend(cloud, receiverChatPK, options, updatePreview || options?.ping === true);
113020
+ const sentMessage = ownerPreview(senderPubkey, messagePayload, messageId, head, tsMs, ttlMs);
113021
+ const preview2 = updatePreview ? sentMessage : null;
113022
+ const ownerEntry = updatePreview ? await ownEntryWrite(cloud, cleanText(options?.senderUid), senderPrivkey, pair, {
113023
+ peerUid: recipientProfile?.uid || cleanText(options?.receiverUid),
113024
+ peerSigningPublicKey: recipientProfile?.signingPublicKey,
113025
+ entry: options?.ownEntry,
113026
+ settings: options?.chatSettings,
113027
+ preview: preview2,
113028
+ ts: tsMs
113029
+ }) : null;
113030
+ const pingKind = updatePreview ? "message" : cleanText(options?.pingKind) || "ping";
113031
+ const ping = recipientProfile?.uid && (updatePreview || options?.ping === true) ? await sealPing(senderPubkey, senderPrivkey, receiverChatPK, {
113032
+ kind: pingKind,
113033
+ chatId,
113034
+ senderUid: cleanText(options?.senderUid),
113035
+ messageId,
113036
+ ts: tsMs
113037
+ }) : null;
113038
+ const write = await cloud.chat.messages.send({
113039
+ chatId,
113040
+ messageId,
113041
+ message: msgData,
113042
+ ownerEntry,
113043
+ inbox: ping ? { recipientUid: recipientProfile?.uid, ping } : null,
113044
+ onCommitted: typeof options?.onCommitted === "function" ? (committed) => options.onCommitted({ ...committed, message: sentMessage, preview: preview2 }) : undefined
113045
+ });
113046
+ return { chatId, msgId: messageId, cid: head.cid, message: sentMessage, preview: preview2, ...write?.skipped ? { skipped: true } : {} };
112878
113047
  });
112879
- return { chatId, msgId: messageId, cid: head.cid, message: sentMessage, preview: preview2, ...write?.skipped ? { skipped: true } : {} };
112880
113048
  }
112881
113049
  async function sendReadReceipt(cloud, senderPubkey, senderPrivkey, receiverChatPK, target, options = {}) {
112882
113050
  const receipt = {
@@ -112986,27 +113154,28 @@ async function setChatRetention(cloud, chatId, senderPubkey, senderPrivkey, peer
112986
113154
  throw new Error("vault locked");
112987
113155
  }
112988
113156
  const nextRetention = cleanChatRetention(retention);
112989
- const pair = await getCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId });
112990
- if (chatId && pair.chatId !== chatId) {
112991
- throw new Error("chat mismatch");
112992
- }
112993
- const systemMessage = {
112994
- ...makeRetentionSystemMsg(nextRetention),
112995
- cid: cleanText(options?.cid) || makeCid(),
112996
- s: senderPubkey
112997
- };
112998
- await sendMsg(cloud, senderPubkey, senderPrivkey, peerChatPK, systemMessage, {
112999
- chatId,
113000
- linkId: pair.linkId,
113001
- updatePreview: true,
113002
- retention: nextRetention,
113003
- chatExists: true,
113004
- senderUid: options?.senderUid,
113005
- ownEntry: options?.ownEntry,
113006
- chatSettings: { retention: nextRetention },
113007
- onCommitted: options?.onCommitted
113157
+ return withCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId }, async (pair) => {
113158
+ if (chatId && pair.chatId !== chatId) {
113159
+ throw new Error("chat mismatch");
113160
+ }
113161
+ const systemMessage = {
113162
+ ...makeRetentionSystemMsg(nextRetention),
113163
+ cid: cleanText(options?.cid) || makeCid(),
113164
+ s: senderPubkey
113165
+ };
113166
+ await sendMsg(cloud, senderPubkey, senderPrivkey, peerChatPK, systemMessage, {
113167
+ chatId,
113168
+ linkId: pair.linkId,
113169
+ updatePreview: true,
113170
+ retention: nextRetention,
113171
+ chatExists: true,
113172
+ senderUid: options?.senderUid,
113173
+ ownEntry: options?.ownEntry,
113174
+ chatSettings: { retention: nextRetention },
113175
+ onCommitted: options?.onCommitted
113176
+ });
113177
+ return nextRetention;
113008
113178
  });
113009
- return nextRetention;
113010
113179
  }
113011
113180
  async function uploadAttachmentMsg(_cloud, senderPubkey, senderPrivkey, receiverChatPK, attachment = {}) {
113012
113181
  if (!senderPrivkey || !senderPubkey) {
@@ -113020,95 +113189,96 @@ async function uploadAttachmentMsg(_cloud, senderPubkey, senderPrivkey, receiver
113020
113189
  if (!chatId) {
113021
113190
  throw new Error("chat id required");
113022
113191
  }
113023
- const pair = await getCachedPair(senderPubkey, senderPrivkey, receiverChatPK, { chatId });
113024
113192
  const type = cleanText(attachment?.type) || "file";
113025
113193
  const data = attachment?.data;
113026
113194
  const meta = attachment?.meta || {};
113027
113195
  switch (type) {
113028
113196
  case "img":
113029
- return putImg(pair, nextCid, data, meta);
113197
+ return putImg(chatId, nextCid, data, meta);
113030
113198
  case "gif":
113031
- return putGif(pair, nextCid, data, meta);
113199
+ return putGif(chatId, nextCid, data, meta);
113032
113200
  case "m4a":
113033
- return putM4a(pair, nextCid, data, meta);
113201
+ return putM4a(chatId, nextCid, data, meta);
113034
113202
  case "mp4":
113035
- return putMp4(pair, nextCid, data, meta);
113203
+ return putMp4(chatId, nextCid, data, meta);
113036
113204
  case "file":
113037
- return putFile(pair, nextCid, data, meta);
113205
+ return putFile(chatId, nextCid, data, meta);
113038
113206
  default:
113039
- return putAttachment(pair, nextCid, type, data, meta);
113207
+ return putAttachment(chatId, nextCid, type, data, meta);
113040
113208
  }
113041
113209
  }
113042
113210
  async function updateMsg(cloud, chatId, msgId, senderPubkey, senderPrivkey, receiverChatPK, newMessage, options = {}) {
113043
113211
  if (!senderPubkey || !senderPrivkey)
113044
113212
  throw new Error("vault locked");
113045
- const pair = await getCachedPair(senderPubkey, senderPrivkey, receiverChatPK, { chatId });
113046
- if (pair.chatId !== chatId) {
113047
- throw new Error("chat mismatch");
113048
- }
113049
- const target = cleanText(newMessage?.cid) || cleanText(msgId);
113050
- if (!target) {
113051
- throw new Error("message target required");
113052
- }
113053
- const op = newMessage?.t === "req" && cleanText(newMessage?.tx) ? CHAT_ACTION_OPS.PAY_CONFIRM : CHAT_ACTION_OPS.EDIT;
113054
- const tsMs = Date.now();
113055
- const action = {
113056
- ...newMessage || {},
113057
- cid: makeCid(),
113058
- s: senderPubkey
113059
- };
113060
- const { head, body } = await sealMsg(pair, action, { op, target, ts: tsMs });
113061
- const messageId = head.cid;
113062
- const updatePreview = options?.updatePreview === true;
113063
- const preview2 = updatePreview ? ownerEditedPreview(senderPubkey, newMessage) : null;
113064
- const ownerEntry = updatePreview ? await ownEntryWrite(cloud, cleanText(options?.senderUid), senderPrivkey, pair, {
113065
- peerUid: cleanText(options?.receiverUid),
113066
- peerSigningPublicKey: cleanText(options?.peerSigningPublicKey),
113067
- entry: options?.ownEntry,
113068
- preview: preview2,
113069
- ts: preview2?.ts ?? tsMs
113070
- }) : null;
113071
- await cloud.chat.messages.send({
113072
- chatId,
113073
- messageId,
113074
- message: {
113075
- head,
113076
- body,
113077
- ttlMs: null
113078
- },
113079
- ownerEntry,
113080
- inbox: null
113213
+ return withCachedPair(senderPubkey, senderPrivkey, receiverChatPK, { chatId }, async (pair) => {
113214
+ if (pair.chatId !== chatId) {
113215
+ throw new Error("chat mismatch");
113216
+ }
113217
+ const target = cleanText(newMessage?.cid) || cleanText(msgId);
113218
+ if (!target) {
113219
+ throw new Error("message target required");
113220
+ }
113221
+ const op = newMessage?.t === "req" && cleanText(newMessage?.tx) ? CHAT_ACTION_OPS.PAY_CONFIRM : CHAT_ACTION_OPS.EDIT;
113222
+ const tsMs = Date.now();
113223
+ const action = {
113224
+ ...newMessage || {},
113225
+ cid: makeCid(),
113226
+ s: senderPubkey
113227
+ };
113228
+ const { head, body } = await sealMsg(pair, action, { op, target, ts: tsMs });
113229
+ const messageId = head.cid;
113230
+ const updatePreview = options?.updatePreview === true;
113231
+ const preview2 = updatePreview ? ownerEditedPreview(senderPubkey, newMessage) : null;
113232
+ const ownerEntry = updatePreview ? await ownEntryWrite(cloud, cleanText(options?.senderUid), senderPrivkey, pair, {
113233
+ peerUid: cleanText(options?.receiverUid),
113234
+ peerSigningPublicKey: cleanText(options?.peerSigningPublicKey),
113235
+ entry: options?.ownEntry,
113236
+ preview: preview2,
113237
+ ts: preview2?.ts ?? tsMs
113238
+ }) : null;
113239
+ await cloud.chat.messages.send({
113240
+ chatId,
113241
+ messageId,
113242
+ message: {
113243
+ head,
113244
+ body,
113245
+ ttlMs: null
113246
+ },
113247
+ ownerEntry,
113248
+ inbox: null
113249
+ });
113250
+ return {
113251
+ chatId,
113252
+ msgId: messageId,
113253
+ cid: head.cid,
113254
+ preview: preview2
113255
+ };
113081
113256
  });
113082
- return {
113083
- chatId,
113084
- msgId: messageId,
113085
- cid: head.cid,
113086
- preview: preview2
113087
- };
113088
113257
  }
113089
113258
  async function deleteMsg(cloud, chatId, messageOrId, senderPubkey, senderPrivkey, peerChatPK, options = {}) {
113090
113259
  if (!cloud || !chatId || !messageOrId || !senderPubkey || !senderPrivkey || !peerChatPK) {
113091
113260
  return false;
113092
113261
  }
113093
- const pair = await getCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId });
113094
- if (pair.chatId !== chatId) {
113095
- return false;
113096
- }
113097
- const item = messageDeleteItems([messageOrId])[0];
113098
- const target = cleanText(options?.docId) || cleanText(item?.id);
113099
- if (!target || target.startsWith("local:")) {
113100
- return false;
113101
- }
113102
- const deleteTarget = cleanText(options?.target) || cleanText(getMessageKey(messageOrId)) || target;
113103
- await sendDeleteAction(cloud, senderPubkey, senderPrivkey, peerChatPK, deleteTarget, {
113104
- chatId,
113105
- linkId: options?.linkId,
113106
- senderUid: options?.senderUid
113107
- });
113108
- await cloud.chat.messages.delete(chatId, target, {
113109
- mediaPaths: item?.mediaPath ? [item.mediaPath] : []
113262
+ return withCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId }, async (pair) => {
113263
+ if (pair.chatId !== chatId) {
113264
+ return false;
113265
+ }
113266
+ const item = messageDeleteItems([messageOrId])[0];
113267
+ const target = cleanText(options?.docId) || cleanText(item?.id);
113268
+ if (!target || target.startsWith("local:")) {
113269
+ return false;
113270
+ }
113271
+ const deleteTarget = cleanText(options?.target) || cleanText(getMessageKey(messageOrId)) || target;
113272
+ await sendDeleteAction(cloud, senderPubkey, senderPrivkey, peerChatPK, deleteTarget, {
113273
+ chatId,
113274
+ linkId: options?.linkId,
113275
+ senderUid: options?.senderUid
113276
+ });
113277
+ await cloud.chat.messages.delete(chatId, target, {
113278
+ mediaPaths: item?.mediaPath ? [item.mediaPath] : []
113279
+ });
113280
+ return true;
113110
113281
  });
113111
- return true;
113112
113282
  }
113113
113283
  async function deleteMsgs(cloud, chatId, messages, senderPubkey, senderPrivkey, peerChatPK) {
113114
113284
  if (!cloud || !chatId || !senderPubkey || !senderPrivkey || !peerChatPK) {
@@ -113118,31 +113288,31 @@ async function deleteMsgs(cloud, chatId, messages, senderPubkey, senderPrivkey,
113118
113288
  if (!items.length) {
113119
113289
  return 0;
113120
113290
  }
113121
- const pair = await getCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId });
113122
- if (pair.chatId !== chatId) {
113123
- return 0;
113124
- }
113125
- let deleted = 0;
113126
- for (let index = 0;index < items.length; index += DELETE_WRITE_BATCH_SIZE) {
113127
- const chunk = items.slice(index, index + DELETE_WRITE_BATCH_SIZE);
113128
- const targets = chunk.map((item) => cleanText(item.id)).filter((target) => target && !target.startsWith("local:"));
113129
- const mediaPaths = chunk.map((item) => cleanText(item.mediaPath)).filter(Boolean);
113130
- deleted += await cloud.chat.messages.deleteMany(chatId, targets, { mediaPaths });
113131
- }
113132
- return deleted;
113291
+ return withCachedPair(senderPubkey, senderPrivkey, peerChatPK, { chatId }, async (pair) => {
113292
+ if (pair.chatId !== chatId) {
113293
+ return 0;
113294
+ }
113295
+ let deleted = 0;
113296
+ for (let index = 0;index < items.length; index += DELETE_WRITE_BATCH_SIZE) {
113297
+ const chunk = items.slice(index, index + DELETE_WRITE_BATCH_SIZE);
113298
+ const targets = chunk.map((item) => cleanText(item.id)).filter((target) => target && !target.startsWith("local:"));
113299
+ const mediaPaths = chunk.map((item) => cleanText(item.mediaPath)).filter(Boolean);
113300
+ deleted += await cloud.chat.messages.deleteMany(chatId, targets, { mediaPaths });
113301
+ }
113302
+ return deleted;
113303
+ });
113133
113304
  }
113134
- async function readMsgMedia(readChatMedia, userChatPK, userPrivKey, peerChatPK, msg) {
113135
- return readMsgAttachment2(readChatMedia, userChatPK, userPrivKey, peerChatPK, msg);
113305
+ async function readMsgMedia(readChatMedia, msg) {
113306
+ return readMsgAttachment2(readChatMedia, msg);
113136
113307
  }
113137
- async function readMsgAttachment2(readChatMedia, userChatPK, userPrivKey, peerChatPK, msg) {
113308
+ async function readMsgAttachment2(readChatMedia, msg) {
113138
113309
  if (typeof readChatMedia !== "function") {
113139
113310
  throw new Error("chat media read required");
113140
113311
  }
113141
- if (!userChatPK || !userPrivKey || !peerChatPK || !msg) {
113312
+ if (!msg) {
113142
113313
  return null;
113143
113314
  }
113144
- const pair = await getCachedPair(userChatPK, userPrivKey, peerChatPK, { chatId: msg?.chatId || messageFileChatId(msg) });
113145
- return readMsgFile(readChatMedia, pair, msg);
113315
+ return readMsgFile(readChatMedia, msg);
113146
113316
  }
113147
113317
  var DELETE_WRITE_BATCH_SIZE;
113148
113318
  var init_write = __esm(() => {
@@ -113385,14 +113555,14 @@ function hasInvalidStoredMediaRef(message) {
113385
113555
  return true;
113386
113556
  }
113387
113557
  }
113388
- function readMessageMedia(cloud, media, chatPK, chatPrivateKey, peerChatPK, message) {
113558
+ function readMessageMedia(cloud, media, message) {
113389
113559
  const readChatMedia = cloud?.chat?.media?.read;
113390
113560
  if (typeof media?.readMessageFile === "function") {
113391
- return media.readMessageFile(readChatMedia, chatPK, chatPrivateKey, peerChatPK, message);
113561
+ return media.readMessageFile(readChatMedia, message);
113392
113562
  }
113393
- return readMsgMedia(readChatMedia, chatPK, chatPrivateKey, peerChatPK, message);
113563
+ return readMsgMedia(readChatMedia, message);
113394
113564
  }
113395
- function createChatSave({ cloud, media = {}, chatBanned, chatPK, chatPrivateKey, localCache }) {
113565
+ function createChatSave({ cloud, media = {}, chatBanned, localCache }) {
113396
113566
  const makeMessagePermanent = async (chatId, message) => {
113397
113567
  if (chatBanned) {
113398
113568
  throw makeChatUnavailableError();
@@ -113410,7 +113580,7 @@ function createChatSave({ cloud, media = {}, chatBanned, chatPK, chatPrivateKey,
113410
113580
  const updated = await makeMsgTemporary(cloud, chatId, list, ttl);
113411
113581
  return { updated, ttl };
113412
113582
  };
113413
- const readMessageFile = async (peerChatPK, message) => {
113583
+ const readMessageFile = async (_peerChatPK, message) => {
113414
113584
  if (chatBanned) {
113415
113585
  throw makeChatUnavailableError();
113416
113586
  }
@@ -113432,7 +113602,7 @@ function createChatSave({ cloud, media = {}, chatBanned, chatPK, chatPrivateKey,
113432
113602
  throw makeFileGoneError();
113433
113603
  }
113434
113604
  try {
113435
- const bytes = await readMessageMedia(cloud, media, chatPK, chatPrivateKey, peerChatPK, message);
113605
+ const bytes = await readMessageMedia(cloud, media, message);
113436
113606
  saveMedia(localCache, message, bytes, message);
113437
113607
  return bytes;
113438
113608
  } catch (error) {
@@ -114078,8 +114248,11 @@ function withSharedMediaUpload(cloud, media, meta = {}) {
114078
114248
  };
114079
114249
  }
114080
114250
  function uploadMessageAttachment(cloud, media, senderPubkey, senderPrivkey, receiverChatPK, attachment = {}) {
114251
+ if (!senderPubkey || !senderPrivkey) {
114252
+ throw new Error("vault locked");
114253
+ }
114081
114254
  if (typeof media?.uploadAttachment === "function") {
114082
- return media.uploadAttachment(senderPubkey, senderPrivkey, receiverChatPK, attachment);
114255
+ return media.uploadAttachment(attachment);
114083
114256
  }
114084
114257
  return uploadAttachmentMsg(cloud, senderPubkey, senderPrivkey, receiverChatPK, withMediaUpload(cloud, media, attachment));
114085
114258
  }
@@ -114377,17 +114550,21 @@ ${cid}` : "";
114377
114550
  const requiredPreview = previewRequired || sendOptions.chatExists !== true;
114378
114551
  let local = await showLocalMessage(peerChatPK, message, sendOptions);
114379
114552
  let committed = false;
114553
+ let sent = false;
114554
+ const markSent = () => {
114555
+ if (sent)
114556
+ return;
114557
+ sent = true;
114558
+ sentChatIdsRef.current.add(local.chatId);
114559
+ markLocalStatus(local.chatId, local.cid, LOCAL_SENT);
114560
+ };
114380
114561
  const markCommitted = () => {
114381
114562
  if (committed)
114382
114563
  return;
114383
114564
  committed = true;
114384
- sentChatIdsRef.current.add(local.chatId);
114565
+ markSent();
114385
114566
  markDone(diag, "chat.send.commit", startedAt, { type: local?.t || "txt", previewRequired: !!requiredPreview });
114386
114567
  };
114387
- const markSent = () => {
114388
- sentChatIdsRef.current.add(local.chatId);
114389
- markLocalStatus(local.chatId, local.cid, LOCAL_SENT);
114390
- };
114391
114568
  return await new Promise((resolve2, reject) => {
114392
114569
  const job = {
114393
114570
  previewKey: local.chatId,
@@ -114605,7 +114782,8 @@ ${cid}` : "";
114605
114782
  linkId: local.linkId,
114606
114783
  version: local.version,
114607
114784
  sendOptions,
114608
- nextAttachment: prepared.nextAttachment
114785
+ nextAttachment: prepared.nextAttachment,
114786
+ committed: false
114609
114787
  };
114610
114788
  }));
114611
114789
  return await new Promise((resolve2, reject) => {
@@ -114614,7 +114792,9 @@ ${cid}` : "";
114614
114792
  reject,
114615
114793
  onError: () => {
114616
114794
  for (const item of locals) {
114617
- markLocalStatus(item.chatId, item.cid, LOCAL_FAILED);
114795
+ if (!item.committed) {
114796
+ markLocalStatus(item.chatId, item.cid, LOCAL_FAILED);
114797
+ }
114618
114798
  }
114619
114799
  },
114620
114800
  run: async () => {
@@ -114629,6 +114809,7 @@ ${cid}` : "";
114629
114809
  results.push({ peerChatPK: item.peerChatPK, ok: false, error: uploadError });
114630
114810
  continue;
114631
114811
  }
114812
+ let sentMessage;
114632
114813
  try {
114633
114814
  let uploaded = uploads.get(uploadKey);
114634
114815
  if (!uploaded) {
@@ -114641,17 +114822,32 @@ ${cid}` : "";
114641
114822
  cid: item.cid,
114642
114823
  s: chatPK
114643
114824
  };
114644
- const sentMessage = withMessageRetention(sent, item.sendOptions.retention);
114825
+ sentMessage = withMessageRetention(sent, item.sendOptions.retention);
114645
114826
  rememberCachedLocalMedia(item.chatId, item.cid, sentMessage);
114646
- await sendMsg(cloud, chatPK, chatPrivateKey, item.peerChatPK, sentMessage, { ...item.sendOptions, chatId: item.chatId, linkId: item.linkId, senderUid: uid });
114647
- markLocalStatus(item.chatId, item.cid, LOCAL_SENT);
114827
+ await sendMsg(cloud, chatPK, chatPrivateKey, item.peerChatPK, sentMessage, {
114828
+ ...item.sendOptions,
114829
+ chatId: item.chatId,
114830
+ linkId: item.linkId,
114831
+ senderUid: uid,
114832
+ onCommitted: () => {
114833
+ if (item.committed)
114834
+ return;
114835
+ item.committed = true;
114836
+ sentChatIdsRef.current.add(item.chatId);
114837
+ markLocalStatus(item.chatId, item.cid, LOCAL_SENT);
114838
+ }
114839
+ });
114648
114840
  results.push({ peerChatPK: item.peerChatPK, ok: true, message: sentMessage });
114649
114841
  } catch (error) {
114650
114842
  if (!uploads.has(uploadKey)) {
114651
114843
  uploadErrors.set(uploadKey, error);
114652
114844
  }
114653
- markLocalStatus(item.chatId, item.cid, LOCAL_FAILED);
114654
- results.push({ peerChatPK: item.peerChatPK, ok: false, error });
114845
+ if (item.committed) {
114846
+ results.push({ peerChatPK: item.peerChatPK, ok: true, message: sentMessage });
114847
+ } else {
114848
+ markLocalStatus(item.chatId, item.cid, LOCAL_FAILED);
114849
+ results.push({ peerChatPK: item.peerChatPK, ok: false, error });
114850
+ }
114655
114851
  }
114656
114852
  }
114657
114853
  return results;
@@ -115458,7 +115654,6 @@ async function decryptRecordEntries(records, userChatPK, userPrivKey, peerChatPK
115458
115654
  return [];
115459
115655
  }
115460
115656
  const signingKeysVersion = signingKeysFingerprint(options?.signingKeysByChatKey);
115461
- const pair = await getCachedPair(userChatPK, userPrivKey, peerChatPK, { chatId: options?.chatId });
115462
115657
  const entryOptions = { ...options, signingKeysVersion };
115463
115658
  const shouldYield = positiveInt(options?.yieldEvery, 0) > 0;
115464
115659
  const entries = new Array(source.length).fill(null);
@@ -115475,38 +115670,40 @@ async function decryptRecordEntries(records, userChatPK, userPrivKey, peerChatPK
115475
115670
  }
115476
115671
  pending.push({ record, index });
115477
115672
  };
115478
- const openPending = async (pending) => {
115479
- if (!pending.length) {
115480
- return;
115481
- }
115482
- const opened = await decryptRecordBatchWithPair(pending.map((item) => item.record), pair, cache, entryOptions);
115483
- for (let index = 0;index < opened.length; index += 1) {
115484
- const entry = opened[index];
115485
- if (entry) {
115486
- entries[pending[index].index] = entry;
115673
+ return withCachedPair(userChatPK, userPrivKey, peerChatPK, { chatId: options?.chatId }, async (pair) => {
115674
+ const openPending = async (pending) => {
115675
+ if (!pending.length) {
115676
+ return;
115677
+ }
115678
+ const opened = await decryptRecordBatchWithPair(pending.map((item) => item.record), pair, cache, entryOptions);
115679
+ for (let index = 0;index < opened.length; index += 1) {
115680
+ const entry = opened[index];
115681
+ if (entry) {
115682
+ entries[pending[index].index] = entry;
115683
+ }
115684
+ }
115685
+ };
115686
+ if (!options?.signal && !shouldYield) {
115687
+ const pending = [];
115688
+ for (let index = 0;index < source.length; index += 1) {
115689
+ collectRecord(source[index], index, pending);
115487
115690
  }
115691
+ await openPending(pending);
115692
+ return entries.filter(Boolean);
115488
115693
  }
115489
- };
115490
- if (!options?.signal && !shouldYield) {
115491
- const pending = [];
115492
- for (let index = 0;index < source.length; index += 1) {
115493
- collectRecord(source[index], index, pending);
115694
+ const chunkSize = positiveInt(options?.yieldEvery, source.length || 1);
115695
+ for (let index = 0;index < source.length; index += chunkSize) {
115696
+ throwIfAborted(options?.signal);
115697
+ const chunk = source.slice(index, index + chunkSize);
115698
+ const pending = [];
115699
+ for (let offset = 0;offset < chunk.length; offset += 1) {
115700
+ collectRecord(chunk[offset], index + offset, pending);
115701
+ }
115702
+ await openPending(pending);
115703
+ await maybeYield(index + chunk.length, options);
115494
115704
  }
115495
- await openPending(pending);
115496
115705
  return entries.filter(Boolean);
115497
- }
115498
- const chunkSize = positiveInt(options?.yieldEvery, source.length || 1);
115499
- for (let index = 0;index < source.length; index += chunkSize) {
115500
- throwIfAborted(options?.signal);
115501
- const chunk = source.slice(index, index + chunkSize);
115502
- const pending = [];
115503
- for (let offset = 0;offset < chunk.length; offset += 1) {
115504
- collectRecord(chunk[offset], index + offset, pending);
115505
- }
115506
- await openPending(pending);
115507
- await maybeYield(index + chunk.length, options);
115508
- }
115509
- return entries.filter(Boolean);
115706
+ });
115510
115707
  }
115511
115708
  function messageQueryLimit(pageSize) {
115512
115709
  return positiveInt(pageSize, MSG_BATCH_SIZE);
@@ -115852,9 +116049,10 @@ async function decryptMsg(msgData, userChatPK, userPrivKey, peerChatPK, options
115852
116049
  return null;
115853
116050
  }
115854
116051
  try {
115855
- const pair = await getCachedPair(userChatPK, userPrivKey, peerChatPK, { chatId: options?.chatId });
115856
- const message = await openMsg(pair, msgData, { signingKeysByChatKey: options?.signingKeysByChatKey, crypto: options?.crypto });
115857
- return normalizeDecryptedMsg(msgData, message);
116052
+ return await withCachedPair(userChatPK, userPrivKey, peerChatPK, { chatId: options?.chatId }, async (pair) => {
116053
+ const message = await openMsg(pair, msgData, { signingKeysByChatKey: options?.signingKeysByChatKey, crypto: options?.crypto });
116054
+ return normalizeDecryptedMsg(msgData, message);
116055
+ });
115858
116056
  } catch {
115859
116057
  return null;
115860
116058
  }
@@ -116924,12 +117122,12 @@ function warmKeyStore(ref) {
116924
117122
  }
116925
117123
  return ref.current;
116926
117124
  }
116927
- function readMessageMedia2(cloud, media, chatPK, chatPrivateKey, peerChatPK, message) {
117125
+ function readMessageMedia2(cloud, media, message) {
116928
117126
  const readChatMedia = cloud?.chat?.media?.read;
116929
117127
  if (typeof media?.readMessageFile === "function") {
116930
- return media.readMessageFile(readChatMedia, chatPK, chatPrivateKey, peerChatPK, message);
117128
+ return media.readMessageFile(readChatMedia, message);
116931
117129
  }
116932
- return readMsgMedia(readChatMedia, chatPK, chatPrivateKey, peerChatPK, message);
117130
+ return readMsgMedia(readChatMedia, message);
116933
117131
  }
116934
117132
  function isDenied3(error) {
116935
117133
  return error?.code === "permission-denied";
@@ -117136,12 +117334,12 @@ function createChatMessageBatches({ cloud, media = {}, chatPK, chatPrivateKey, c
117136
117334
  return;
117137
117335
  }
117138
117336
  const tasks = buildMediaTasks();
117139
- const readFile4 = async (peerChatPK, message) => {
117337
+ const readFile4 = async (_peerChatPK, message) => {
117140
117338
  const cached = await readCachedMedia(localCache, message);
117141
117339
  if (cached?.byteLength) {
117142
117340
  return cached;
117143
117341
  }
117144
- const bytes = await readMessageMedia2(cloud, media, chatPK, chatPrivateKey, peerChatPK, message);
117342
+ const bytes = await readMessageMedia2(cloud, media, message);
117145
117343
  if (bytes?.byteLength) {
117146
117344
  saveMedia(localCache, message, bytes, message);
117147
117345
  }
@@ -117888,6 +118086,16 @@ function pingSigningKeys(ping, existing) {
117888
118086
  [ping.payload.senderChatPK]: ping.payload.signingPublicKey
117889
118087
  };
117890
118088
  }
118089
+ function chatSettingsFromPreview(settings, preview2) {
118090
+ const current = normalizeChatSettings(settings);
118091
+ if (!isSystemMsg(preview2)) {
118092
+ return current;
118093
+ }
118094
+ return {
118095
+ ...current,
118096
+ retention: cleanChatRetention(preview2.retention)
118097
+ };
118098
+ }
117891
118099
  function chatFromPing(ping, entryId, existing, preview2, userChatPK, ms, options = {}) {
117892
118100
  const ts = timestampMs(ms, null) ?? timestampMs(existing?.ts, null) ?? timestampMs(preview2?.ts, null) ?? 0;
117893
118101
  if (!ts) {
@@ -117904,7 +118112,7 @@ function chatFromPing(ping, entryId, existing, preview2, userChatPK, ms, options
117904
118112
  peerChatPK: ping.payload.senderChatPK,
117905
118113
  peerUid: existing?.peerUid || cleanText(ping.payload.senderUid) || null,
117906
118114
  signingKeysByChatKey: pingSigningKeys(ping, existing),
117907
- settings: existing?.settings,
118115
+ settings: chatSettingsFromPreview(existing?.settings, preview2),
117908
118116
  saved: existing?.saved || null,
117909
118117
  readMs,
117910
118118
  startMs,
@@ -117963,7 +118171,7 @@ async function savePing(cloud, uid, userChatPK, userPrivKey, ping, options = {})
117963
118171
  peerUid: peerUid2 || existing?.peerUid,
117964
118172
  peerSigningPublicKey: ping.payload.signingPublicKey || existing?.signingKeysByChatKey?.[ping.payload.senderChatPK],
117965
118173
  signingKeysByChatKey,
117966
- settings: existing?.settings,
118174
+ settings: chatSettingsFromPreview(existing?.settings, preview2),
117967
118175
  preview: preview2 || existing?.preview,
117968
118176
  readMs: existing?.readMs,
117969
118177
  startMs: existing ? existing.startMs : timestampMs(options.startPreview?.ts ?? preview2?.ts, null, { positive: true })
@@ -118152,6 +118360,7 @@ var init_inbox = __esm(() => {
118152
118360
  init_ping();
118153
118361
  init_query();
118154
118362
  init_chats();
118363
+ init_ttl();
118155
118364
  init_time();
118156
118365
  init_protocol();
118157
118366
  });
@@ -118647,6 +118856,7 @@ function createChatList({
118647
118856
  let chats = [];
118648
118857
  let peers = [];
118649
118858
  let isChatDataReady = false;
118859
+ let isChatListLive = false;
118650
118860
  let chatSourceReady = false;
118651
118861
  let lastChat = null;
118652
118862
  let serverChatIds = [];
@@ -118683,6 +118893,7 @@ function createChatList({
118683
118893
  chats,
118684
118894
  peers,
118685
118895
  isChatDataReady,
118896
+ isChatListLive,
118686
118897
  hasChats: chats.length > 0,
118687
118898
  previewNow,
118688
118899
  lastChat,
@@ -118716,6 +118927,13 @@ function createChatList({
118716
118927
  isChatDataReady = value;
118717
118928
  publish();
118718
118929
  };
118930
+ const setIsChatListLive = (next) => {
118931
+ const value = nextValue(isChatListLive, next);
118932
+ if (Object.is(isChatListLive, value))
118933
+ return;
118934
+ isChatListLive = value;
118935
+ publish();
118936
+ };
118719
118937
  const setLastChat = (next) => {
118720
118938
  const value = nextValue(lastChat, next);
118721
118939
  if (Object.is(lastChat, value))
@@ -118925,6 +119143,7 @@ function createChatList({
118925
119143
  const resetChatList = (ready = false) => {
118926
119144
  chatSourceReady = ready;
118927
119145
  syncChatDataReady();
119146
+ setIsChatListLive(false);
118928
119147
  setChats((prev) => prev.length ? [] : prev);
118929
119148
  setPeers((prev) => prev.length ? [] : prev);
118930
119149
  setLastChat((prev) => prev ? null : prev);
@@ -119014,6 +119233,7 @@ function createChatList({
119014
119233
  resetAllChatState();
119015
119234
  return;
119016
119235
  }
119236
+ setIsChatListLive(false);
119017
119237
  let cancelled = false;
119018
119238
  const hydrateKey = localCache?.id ? `${localCache.id}:${chatPK}` : "";
119019
119239
  if (hydrateKey && lastHydratedCacheKeyRef.current !== hydrateKey) {
@@ -119113,6 +119333,7 @@ function createChatList({
119113
119333
  writeCache: true,
119114
119334
  serverEndReached: cachedHistoryEndRef.current
119115
119335
  });
119336
+ setIsChatListLive(true);
119116
119337
  listenUpdateSeqRef.current += 1;
119117
119338
  markDiag(diag, "chat.provider.listen.update", {
119118
119339
  seq: listenUpdateSeqRef.current,
@@ -119155,6 +119376,7 @@ function createChatList({
119155
119376
  markChatSourceReady();
119156
119377
  fillVisibleChatPage();
119157
119378
  }, (error) => {
119379
+ setIsChatListLive(false);
119158
119380
  markError(diag, "chat.provider.listen", listenStartedAt, error);
119159
119381
  if (shouldResetChatListAfterListenError(error)) {
119160
119382
  resetAllChatState();
@@ -122844,11 +123066,6 @@ function createWalletPrivacy({ wallet, ghostWallet, diag }) {
122844
123066
  const startedAt = Date.now();
122845
123067
  const desired = desiredPrivacy;
122846
123068
  markDiag(diag, "wallet.privacy.start", { ghostWallet: desired });
122847
- const current = typeof wallet.getWalletSettings === "function" ? await wallet.getWalletSettings() : null;
122848
- if (closed || requestRevision !== revision || current?.privateEnabled === true === desired) {
122849
- markDone(diag, "wallet.privacy", startedAt, { changed: false, cancelled: closed || requestRevision !== revision });
122850
- return;
122851
- }
122852
123069
  await wallet.setPrivacyEnabled(desired);
122853
123070
  markDone(diag, "wallet.privacy", startedAt, { changed: true });
122854
123071
  }).catch((error) => {
@@ -123698,7 +123915,7 @@ function adaptiveClaimBatchSize(maxBatchSize, queueDepth) {
123698
123915
  }
123699
123916
  return 1;
123700
123917
  }
123701
- function createWalletTransferSession({ wallet, walletPK, localCache, claimIncomingTransfers, pendingClaimBatchSize = null, eagerOutgoingStatusRefresh = false, transferStore, appState = null, deferBackgroundWork = null, backgroundSignal = null, diag }) {
123918
+ function createWalletTransferSession({ wallet, walletPK, localCache, claimIncomingTransfers, pendingClaimBatchSize = null, eagerOutgoingStatusRefresh = false, eagerCacheHistory = true, transferStore, appState = null, deferBackgroundWork = null, backgroundSignal = null, diag }) {
123702
123919
  if (!transferStore || typeof transferStore.subscribe !== "function" || typeof transferStore.getSnapshot !== "function" || typeof transferStore.getCacheState !== "function" || typeof transferStore.setHistory !== "function") {
123703
123920
  throw new Error("createWalletTransferSession requires transferStore");
123704
123921
  }
@@ -123712,6 +123929,7 @@ function createWalletTransferSession({ wallet, walletPK, localCache, claimIncomi
123712
123929
  const initialTransfers = canUseInitialStore ? transferStore.getTransfers() : [];
123713
123930
  const initialHistoryTransfers = canUseInitialStore ? transferStore.getHistoryTransfers() : [];
123714
123931
  const initialTxReady = canUseInitialStore && (initialStoreSnapshot.ready || initialTransfers.length > 0 || initialHistoryTransfers.length > 0);
123932
+ const initialCacheReady = initialTxReady && (eagerCacheHistory === false || initialStoreSnapshot.serverEndReached === true && initialHistoryTransfers.length >= initialStoreSnapshot.historyCount);
123715
123933
  const listeners = new Set;
123716
123934
  let isTxLoading = false;
123717
123935
  let publishedSnapshot = null;
@@ -125428,6 +125646,9 @@ function createWalletTransferSession({ wallet, walletPK, localCache, claimIncomi
125428
125646
  if (!wallet || !localCache || !walletPKRef.current) {
125429
125647
  return;
125430
125648
  }
125649
+ if (initialCacheReady) {
125650
+ return;
125651
+ }
125431
125652
  const hydrateKey = `${localCache.id || "cache"}:${walletPKRef.current}`;
125432
125653
  if (cacheHydrateKeyRef.current === hydrateKey) {
125433
125654
  return;
@@ -125452,7 +125673,7 @@ function createWalletTransferSession({ wallet, walletPK, localCache, claimIncomi
125452
125673
  return;
125453
125674
  }
125454
125675
  const hydratedHead = applyCachedTransferState(cachedHead, { label: "wallet.provider.cache.hydrate", publish: true, startedAt: hydrateStartedAt });
125455
- if (cancelled)
125676
+ if (cancelled || !eagerCacheHistory)
125456
125677
  return;
125457
125678
  await loadFullTransferCache({ label: "wallet.provider.cache.fullHydrate", publish: !hydratedHead });
125458
125679
  }).catch((error) => {
@@ -125861,6 +126082,7 @@ function createWalletSession({
125861
126082
  pendingClaimBatchSize = null,
125862
126083
  activeTransferRefreshMs = null,
125863
126084
  eagerOutgoingStatusRefresh = false,
126085
+ eagerCacheHistory = true,
125864
126086
  sentTransferRefreshDelayMs = null,
125865
126087
  deferBackgroundWork = null,
125866
126088
  appState = null,
@@ -125889,6 +126111,7 @@ function createWalletSession({
125889
126111
  claimIncomingTransfers,
125890
126112
  pendingClaimBatchSize,
125891
126113
  eagerOutgoingStatusRefresh,
126114
+ eagerCacheHistory,
125892
126115
  transferStore,
125893
126116
  appState,
125894
126117
  deferBackgroundWork,
@@ -125999,7 +126222,7 @@ function createWalletSession({
125999
126222
  balanceReady: balanceState.balanceReady,
126000
126223
  isBalanceLoading: balanceState.isBalanceLoading,
126001
126224
  isWalletDataReady: true,
126002
- isWalletDataLoaded: balanceState.balanceReady && currentTransferState.txReady,
126225
+ isWalletDataLoaded: balanceState.balanceReady || currentTransferState.txReady,
126003
126226
  refresh: claims.refresh,
126004
126227
  requestTransferDiscoveryHotWindow: polling.requestTransferDiscoveryHotWindow,
126005
126228
  claimDeposits: claims.claimDeposits,
@@ -169941,7 +170164,12 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
169941
170164
  "Content-Type": upload?.metadata?.contentType || "application/octet-stream"
169942
170165
  };
169943
170166
  if (typeof uploadSignedStorageBytes === "function") {
169944
- await uploadSignedStorageBytes(url, upload?.body, { ...signed, method, headers, metadata: upload?.metadata || {}, path: upload?.path || "" });
170167
+ await uploadSignedStorageBytes(url, upload?.body, { ...signed, method, headers, metadata: upload?.metadata || {}, path: upload?.path || "" }).catch((error) => {
170168
+ if (error?.status === 412 && (headers["X-Goog-If-Generation-Match"] === "0" || headers["x-goog-if-generation-match"] === "0")) {
170169
+ return true;
170170
+ }
170171
+ throw error;
170172
+ });
169945
170173
  return true;
169946
170174
  }
169947
170175
  const payload = typeof Blob !== "undefined" && upload?.body instanceof Blob ? upload.body : toBytes2(upload?.body, "upload bytes");
@@ -169950,6 +170178,9 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
169950
170178
  headers,
169951
170179
  body: payload
169952
170180
  });
170181
+ if (response.status === 412 && (headers["X-Goog-If-Generation-Match"] === "0" || headers["x-goog-if-generation-match"] === "0")) {
170182
+ return true;
170183
+ }
169953
170184
  if (!response.ok) {
169954
170185
  const error = new Error(`signed upload failed (${response.status || 0})`);
169955
170186
  error.status = response.status || 0;
@@ -170464,20 +170695,12 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
170464
170695
  const snapshot = await getDocs(roleQuery);
170465
170696
  return peerRecordsFromSnapshot(snapshot);
170466
170697
  }
170467
- async function uploadChatMedia(upload) {
170698
+ async function uploadMedia(upload) {
170468
170699
  const path = upload?.path;
170469
170700
  if (!path)
170470
170701
  throw new Error("media path required");
170471
- getChatMediaFileRef(path);
170472
- await uploadStorageFile(path, upload?.body, upload?.metadata || {});
170473
- return true;
170474
- }
170475
- async function uploadSharedMedia(upload) {
170476
- const path = upload?.path;
170477
- if (!path)
170478
- throw new Error("shared media path required");
170479
- const signed = await callFunction("reserveSharedMediaUpload", {
170480
- sharedId: upload?.sharedId,
170702
+ getMediaFileRef(path);
170703
+ const signed = await callFunction("reserveMediaUpload", {
170481
170704
  path,
170482
170705
  size: uploadByteSize(upload?.body),
170483
170706
  contentType: upload?.metadata?.contentType || "application/octet-stream"
@@ -170485,6 +170708,14 @@ function createFirebaseCloud({ db, auth: auth2, getAuth: getAuth2, functions: fu
170485
170708
  await uploadSignedStorageFile(upload, signed?.upload);
170486
170709
  return true;
170487
170710
  }
170711
+ async function uploadChatMedia(upload) {
170712
+ getChatMediaFileRef(upload?.path);
170713
+ return uploadMedia(upload);
170714
+ }
170715
+ async function uploadSharedMedia(upload) {
170716
+ getSharedMediaFileRef(upload?.path);
170717
+ return uploadMedia(upload);
170718
+ }
170488
170719
  async function readChatMedia(path) {
170489
170720
  if (!path)
170490
170721
  throw new Error("media path required");
@@ -175688,6 +175919,7 @@ class VeylHeadlessClient {
175688
175919
  this.userOwner.setNetwork(network);
175689
175920
  }
175690
175921
  });
175922
+ await opened.walletReady;
175691
175923
  this.userSnapshot = this.userOwner.getSnapshot();
175692
175924
  } catch (error) {
175693
175925
  if (opened)