@glyphteck/veyl 0.70.0 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1009,6 +1009,16 @@ function numberToBytesBE(n, len) {
1009
1009
  function numberToBytesLE(n, len) {
1010
1010
  return numberToBytesBE(n, len).reverse();
1011
1011
  }
1012
+ function equalBytes(a, b) {
1013
+ a = abytes2(a);
1014
+ b = abytes2(b);
1015
+ if (a.length !== b.length)
1016
+ return false;
1017
+ let diff = 0;
1018
+ for (let i = 0;i < a.length; i++)
1019
+ diff |= a[i] ^ b[i];
1020
+ return diff === 0;
1021
+ }
1012
1022
  function copyBytes2(bytes) {
1013
1023
  return Uint8Array.from(abytes2(bytes));
1014
1024
  }
@@ -4726,7 +4736,7 @@ function checkOpts2(defaults, opts) {
4726
4736
  const merged = Object.assign(defaults, opts);
4727
4737
  return merged;
4728
4738
  }
4729
- function equalBytes(a, b) {
4739
+ function equalBytes2(a, b) {
4730
4740
  a = abytes3(a);
4731
4741
  b = abytes3(b);
4732
4742
  if (a.length !== b.length)
@@ -5170,7 +5180,7 @@ var init_aes = __esm(() => {
5170
5180
  const passedTag = ciphertext.subarray(-tagLength);
5171
5181
  const tag = _computeTag(authKey, tagMask, data);
5172
5182
  toClean.push(tag);
5173
- if (!equalBytes(tag, passedTag)) {
5183
+ if (!equalBytes2(tag, passedTag)) {
5174
5184
  clean2(...toClean);
5175
5185
  throw new Error("aes-gcm: invalid tag");
5176
5186
  }
@@ -5857,7 +5867,7 @@ function sameText(left, right) {
5857
5867
  }
5858
5868
 
5859
5869
  // ../../core/config.js
5860
- 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, 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_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, CHAT_LIVE_RECONNECT_MIN_MS = 250, CHAT_LIVE_RECONNECT_MAX_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;
5870
+ 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, 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, CHAT_LIVE_RECONNECT_MIN_MS = 250, CHAT_LIVE_RECONNECT_MAX_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;
5861
5871
  var init_config = __esm(() => {
5862
5872
  MINUTE_MS = 60 * MS_PER_SECOND;
5863
5873
  HOUR_MS = 60 * MINUTE_MS;
@@ -5998,9 +6008,12 @@ function normalizeChatNotificationMode(value, manifest) {
5998
6008
  const mode = cleanText(value);
5999
6009
  if (!NOTIFICATION_MODES.has(mode))
6000
6010
  throw new Error("chat notification mode required");
6001
- if (manifest?.lineage !== "group")
6011
+ if (manifest?.lineage === "self")
6002
6012
  return CHAT_NOTIFICATION_MODES.ALL;
6003
- if (mode === CHAT_NOTIFICATION_MODES.ALL && manifest.members?.length > CHAT_ORDINARY_DELIVERY_MAX_MEMBERS) {
6013
+ if (manifest?.lineage === "direct" && mode === CHAT_NOTIFICATION_MODES.MENTIONS) {
6014
+ throw new Error("mentions notifications require a group chat");
6015
+ }
6016
+ if (mode === CHAT_NOTIFICATION_MODES.ALL && manifest?.lineage === "group" && manifest.members?.length > CHAT_ORDINARY_DELIVERY_MAX_MEMBERS) {
6004
6017
  return CHAT_NOTIFICATION_MODES.MENTIONS;
6005
6018
  }
6006
6019
  return mode;
@@ -7110,7 +7123,7 @@ var xchacha20, ZEROS162, updatePadded = (h, msg) => {
7110
7123
  const data = ciphertext.subarray(0, -tagLength);
7111
7124
  const passedTag = ciphertext.subarray(-tagLength);
7112
7125
  const tag = computeTag2(xorStream, key, nonce, data, AAD);
7113
- if (!equalBytes(passedTag, tag)) {
7126
+ if (!equalBytes2(passedTag, tag)) {
7114
7127
  clean2(tag);
7115
7128
  throw new Error("invalid tag");
7116
7129
  }
@@ -8850,35 +8863,68 @@ function chatAdmissionCapabilityCommitment(value) {
8850
8863
  cleanBytes(capability);
8851
8864
  }
8852
8865
  }
8853
- function directAdmissionCapabilityForPeer(chatPrivateKey, chatPK, profile) {
8854
- return deriveDirectAdmissionCapability(chatPrivateKey, chatPK, profile?.chatPK, profile?.chatPK);
8855
- }
8856
- function hasDirectAdmissionGrant(chatPrivateKey, chatPK, profile) {
8857
- const policy = normalizeChatAdmission(profile?.chatAdmission);
8858
- if (!policy.directGrants.length)
8859
- return false;
8860
- const capability = directAdmissionCapabilityForPeer(chatPrivateKey, chatPK, profile);
8861
- try {
8862
- return policy.directGrants.includes(chatAdmissionCapabilityCommitment(capability));
8863
- } finally {
8864
- cleanBytes(capability);
8865
- }
8866
+ function deriveDirectAdmissionCommitment(chatPrivateKey, chatPK, peerChatPK, recipientChatPK) {
8867
+ return chatAdmissionCapabilityCommitment(deriveDirectAdmissionCapability(chatPrivateKey, chatPK, peerChatPK, recipientChatPK));
8866
8868
  }
8867
- function directAdmissionForPeer(chatPrivateKey, chatPK, profile, ownAdmission = null) {
8868
- if (ownAdmission != null && normalizeChatAdmission(ownAdmission).direct === CHAT_DIRECT_ADMISSION_MODES.CLOSED && incomingChatAdmissionDecision(chatPrivateKey, chatPK, profile, ownAdmission, "direct") !== CHAT_ADMISSION_DECISIONS.ACCEPT)
8869
+ function directAdmissionDecision(chatPK, profile, ownAdmission, commitmentFor) {
8870
+ const ownPolicy = normalizeChatAdmission(ownAdmission);
8871
+ if (ownAdmission != null && ownPolicy.direct === CHAT_DIRECT_ADMISSION_MODES.CLOSED && !ownPolicy.directGrants.includes(commitmentFor(profile?.chatPK, chatPK)))
8869
8872
  return CHAT_ADMISSION_DECISIONS.REJECT;
8870
- if (hasDirectAdmissionGrant(chatPrivateKey, chatPK, profile)) {
8873
+ const policy = normalizeChatAdmission(profile?.chatAdmission);
8874
+ if (policy.directGrants.length && policy.directGrants.includes(commitmentFor(profile?.chatPK, profile?.chatPK))) {
8871
8875
  return CHAT_ADMISSION_DECISIONS.ACCEPT;
8872
8876
  }
8873
- const mode = normalizeChatAdmission(profile?.chatAdmission).direct;
8877
+ const mode = policy.direct;
8874
8878
  if (mode === CHAT_DIRECT_ADMISSION_MODES.OPEN)
8875
8879
  return CHAT_ADMISSION_DECISIONS.ACCEPT;
8876
8880
  if (mode === CHAT_DIRECT_ADMISSION_MODES.REQUESTS)
8877
8881
  return CHAT_ADMISSION_DECISIONS.REQUEST;
8878
8882
  return CHAT_ADMISSION_DECISIONS.REJECT;
8879
8883
  }
8880
- function canStartDirectChat(chatPrivateKey, chatPK, profile, ownAdmission = null) {
8881
- return directAdmissionForPeer(chatPrivateKey, chatPK, profile, ownAdmission) !== CHAT_ADMISSION_DECISIONS.REJECT;
8884
+ function directAdmissionForPeer(chatPrivateKey, chatPK, profile, ownAdmission = null) {
8885
+ return directAdmissionDecision(chatPK, profile, ownAdmission, (peerChatPK, recipientChatPK) => deriveDirectAdmissionCommitment(chatPrivateKey, chatPK, peerChatPK, recipientChatPK));
8886
+ }
8887
+ function createChatAdmission({ getIdentity, deriveCommitment = deriveDirectAdmissionCommitment }) {
8888
+ let chatPK = null;
8889
+ let privateKey = null;
8890
+ let privateKeyBytes = null;
8891
+ const peers = new Map;
8892
+ const reset = () => {
8893
+ peers.clear();
8894
+ cleanBytes(privateKeyBytes);
8895
+ chatPK = null;
8896
+ privateKey = null;
8897
+ privateKeyBytes = null;
8898
+ };
8899
+ const directAdmissionForPeer2 = (profile) => {
8900
+ const identity = getIdentity();
8901
+ if (chatPK !== identity.chatPK || privateKey !== identity.chatPrivateKey || privateKey instanceof Uint8Array && !equalBytes(privateKey, privateKeyBytes)) {
8902
+ reset();
8903
+ chatPK = identity.chatPK;
8904
+ privateKey = identity.chatPrivateKey;
8905
+ privateKeyBytes = privateKey instanceof Uint8Array ? new Uint8Array(privateKey) : null;
8906
+ }
8907
+ return directAdmissionDecision(chatPK, profile, identity.chatAdmission, (peerChatPK, recipientChatPK) => {
8908
+ let commitments = peers.get(peerChatPK);
8909
+ if (!commitments?.has(recipientChatPK)) {
8910
+ const commitment = deriveCommitment(privateKey, chatPK, peerChatPK, recipientChatPK);
8911
+ if (!commitments) {
8912
+ commitments = new Map;
8913
+ if (peers.size >= CHAT_ADMISSION_CACHE_PEERS)
8914
+ peers.delete(peers.keys().next().value);
8915
+ }
8916
+ commitments.set(recipientChatPK, commitment);
8917
+ }
8918
+ peers.delete(peerChatPK);
8919
+ peers.set(peerChatPK, commitments);
8920
+ return commitments.get(recipientChatPK);
8921
+ });
8922
+ };
8923
+ return {
8924
+ directAdmissionForPeer: directAdmissionForPeer2,
8925
+ canStartDirectChat: (profile) => directAdmissionForPeer2(profile) !== CHAT_ADMISSION_DECISIONS.REJECT,
8926
+ reset
8927
+ };
8882
8928
  }
8883
8929
  function canInviteToGroup(profile, ownAdmission = null) {
8884
8930
  return (ownAdmission == null || normalizeChatAdmission(ownAdmission).groups === CHAT_GROUP_ADMISSION_MODES.OPEN) && normalizeChatAdmission(profile?.chatAdmission).groups === CHAT_GROUP_ADMISSION_MODES.OPEN;
@@ -8939,6 +8985,8 @@ var CHAT_ADMISSION_VERSION = 1, CHAT_ADMISSION_GRANT_COUNT = 8, CHAT_ADMISSION_D
8939
8985
  var init_admission = __esm(() => {
8940
8986
  init_ed25519();
8941
8987
  init_sha2();
8988
+ init_utils2();
8989
+ init_config();
8942
8990
  init_core();
8943
8991
  init_kdf();
8944
8992
  init_manifest();
@@ -11143,6 +11191,29 @@ var init_transition = __esm(() => {
11143
11191
  TRANSITION_MEMBER_SCOPE = encoder.encode("veyl-chat-transition-member-v3");
11144
11192
  });
11145
11193
 
11194
+ // ../../core/chat/capabilities.js
11195
+ function memberCount(value) {
11196
+ const count = Number(value);
11197
+ if (!Number.isSafeInteger(count) || count < 1 || count > CHAT_MAX_MEMBERS) {
11198
+ throw new Error("invalid chat member count");
11199
+ }
11200
+ return count;
11201
+ }
11202
+ function chatCapabilities(value) {
11203
+ const members = memberCount(value);
11204
+ return Object.freeze({
11205
+ members,
11206
+ sharedReceipts: members <= CHAT_RECEIPT_MAX_MEMBERS,
11207
+ ordinaryDelivery: members <= CHAT_ORDINARY_DELIVERY_MAX_MEMBERS
11208
+ });
11209
+ }
11210
+ function chatEpochCapabilities(epochState) {
11211
+ return chatCapabilities(epochState?.manifest?.members?.length);
11212
+ }
11213
+ var init_capabilities = __esm(() => {
11214
+ init_config();
11215
+ });
11216
+
11146
11217
  // ../../core/chat/ttl.js
11147
11218
  function hasChatRetention(value) {
11148
11219
  const retention = cleanText(value);
@@ -11191,7 +11262,7 @@ function messageExpiryMs(retention, seenAt) {
11191
11262
  }
11192
11263
  return cleanChatRetention(retention) === CHAT_RETENTION_24H ? seenAt + AFTER_SEEN_MS : seenAt;
11193
11264
  }
11194
- var CHAT_RETENTION_SEEN = "seen", CHAT_RETENTION_24H = "24h", CHAT_RETENTION_FOREVER = "forever", DEFAULT_CHAT_RETENTION, CHAT_RETENTION_VALUES, CHAT_PROTOCOL_RETENTION_VALUES, CHAT_RETENTION_LABELS, MESSAGE_STORAGE_TTL_MS, AFTER_SEEN_MS;
11265
+ var CHAT_RETENTION_SEEN = "seen", CHAT_RETENTION_24H = "24h", CHAT_RETENTION_FOREVER = "forever", DEFAULT_CHAT_RETENTION, CHAT_RETENTION_VALUES, CHAT_PROTOCOL_RETENTION_VALUES, CHAT_RETENTION_LABELS, CHAT_RETENTION_DESCRIPTIONS, MESSAGE_STORAGE_TTL_MS, AFTER_SEEN_MS;
11195
11266
  var init_ttl = __esm(() => {
11196
11267
  init_config();
11197
11268
  init_time();
@@ -11203,6 +11274,10 @@ var init_ttl = __esm(() => {
11203
11274
  [CHAT_RETENTION_SEEN]: "delete after seen",
11204
11275
  [CHAT_RETENTION_24H]: "keep for 24h"
11205
11276
  });
11277
+ CHAT_RETENTION_DESCRIPTIONS = Object.freeze({
11278
+ [CHAT_RETENTION_SEEN]: "messages now delete after being seen",
11279
+ [CHAT_RETENTION_24H]: "messages now delete 24h after being seen"
11280
+ });
11206
11281
  MESSAGE_STORAGE_TTL_MS = CHAT_UNSAVED_TTL_MS;
11207
11282
  AFTER_SEEN_MS = CHAT_AFTER_SEEN_MS;
11208
11283
  });
@@ -11844,6 +11919,8 @@ async function prepareOwnChatMutation(identity, entryId, current, update) {
11844
11919
  open: (record) => openOwnChatMutationEntry(identity, entryId, record),
11845
11920
  prepare: async (record) => {
11846
11921
  if (!record) {
11922
+ if (current != null)
11923
+ throw makeChatUnavailableError();
11847
11924
  return prepareMutation(identity, entryId, null, update);
11848
11925
  }
11849
11926
  if (!record?.body || !Number.isSafeInteger(record.revision) || record.revision < 1) {
@@ -12681,29 +12758,6 @@ var init_chatstate = __esm(() => {
12681
12758
  STATE_SIGN_SCOPE = encoder.encode("veyl-chat-member-state-v3-sign");
12682
12759
  });
12683
12760
 
12684
- // ../../core/chat/capabilities.js
12685
- function memberCount(value) {
12686
- const count = Number(value);
12687
- if (!Number.isSafeInteger(count) || count < 1 || count > CHAT_MAX_MEMBERS) {
12688
- throw new Error("invalid chat member count");
12689
- }
12690
- return count;
12691
- }
12692
- function chatCapabilities(value) {
12693
- const members = memberCount(value);
12694
- return Object.freeze({
12695
- members,
12696
- sharedReceipts: members <= CHAT_RECEIPT_MAX_MEMBERS,
12697
- ordinaryDelivery: members <= CHAT_ORDINARY_DELIVERY_MAX_MEMBERS
12698
- });
12699
- }
12700
- function chatEpochCapabilities(epochState) {
12701
- return chatCapabilities(epochState?.manifest?.members?.length);
12702
- }
12703
- var init_capabilities = __esm(() => {
12704
- init_config();
12705
- });
12706
-
12707
12761
  // ../../core/chat/memberstate.js
12708
12762
  function openStateEpoch(epochState, actor = null) {
12709
12763
  if (!epochState?.manifest || !epochState?.epochSecret)
@@ -13894,7 +13948,8 @@ function getMsgReactions(msg) {
13894
13948
  continue;
13895
13949
  }
13896
13950
  seen.add(user);
13897
- reactions.push({ emoji, user });
13951
+ const ts = timestampMs(item.ts, null);
13952
+ reactions.push({ emoji, user, ...ts == null ? {} : { ts } });
13898
13953
  if (reactions.length >= MAX_REACTIONS) {
13899
13954
  break;
13900
13955
  }
@@ -13907,7 +13962,7 @@ function sameReactions(a, b) {
13907
13962
  if (left.length !== right.length) {
13908
13963
  return false;
13909
13964
  }
13910
- return left.every((reaction, index) => reaction.user === right[index]?.user && reaction.emoji === right[index]?.emoji);
13965
+ return left.every((reaction, index) => reaction.user === right[index]?.user && reaction.emoji === right[index]?.emoji && reaction.ts === right[index]?.ts);
13911
13966
  }
13912
13967
  function hasReactionControl(messages) {
13913
13968
  for (const msg of messages || []) {
@@ -13947,7 +14002,8 @@ function deriveMessageReactions(messages, chatPK, peerChatPK, memberChatPKs = nu
13947
14002
  byTarget.set(target, reactions);
13948
14003
  }
13949
14004
  if (hasText(msg.emoji)) {
13950
- reactions.set(user, { emoji: cleanReactionEmoji(msg.emoji), user });
14005
+ const ts = timestampMs(getMessageOrderMs(msg), null);
14006
+ reactions.set(user, { emoji: cleanReactionEmoji(msg.emoji), user, ...ts == null ? {} : { ts } });
13951
14007
  } else {
13952
14008
  reactions.delete(user);
13953
14009
  }
@@ -15076,7 +15132,7 @@ function senderIdentity(senderChatPK, senderPrivateKey, options) {
15076
15132
  notificationPrivateKey: options.notificationPrivateKey
15077
15133
  };
15078
15134
  }
15079
- function ownerPreview(senderChatPK, message, messageId, head, tsMs, ttlMs) {
15135
+ function ownerPreview(epoch, senderChatPK, message, messageId, head, tsMs, ttlMs) {
15080
15136
  return {
15081
15137
  ...message || {},
15082
15138
  s: senderChatPK,
@@ -15085,6 +15141,8 @@ function ownerPreview(senderChatPK, message, messageId, head, tsMs, ttlMs) {
15085
15141
  id: messageId,
15086
15142
  ts: tsMs,
15087
15143
  ttl: Number.isFinite(ttlMs) ? ttlMs : null,
15144
+ epochId: epoch.epochId,
15145
+ epochMemberChatPKs: epoch.manifest.members.map((member) => member.chatPK),
15088
15146
  pending: false,
15089
15147
  failed: false
15090
15148
  };
@@ -15301,7 +15359,7 @@ async function prepareMsgRecord(identity, epochState, message, options = {}) {
15301
15359
  msgId: messageId,
15302
15360
  cid: head.cid,
15303
15361
  record: { lane: epoch.messageLane, head, body, ttlMs },
15304
- message: ownerPreview(identity.chatPK, messagePayload, messageId, head, tsMs, ttlMs),
15362
+ message: ownerPreview(epoch, identity.chatPK, messagePayload, messageId, head, tsMs, ttlMs),
15305
15363
  mentionRecipientChatPKs: mentionTargets.recipientChatPKs,
15306
15364
  tsMs
15307
15365
  };
@@ -20021,12 +20079,6 @@ function dropCachedChats(cache, chatIds, currentPayload = null) {
20021
20079
  ...ids.map((chatId) => dropCachedMessageState(cache, chatId))
20022
20080
  ]));
20023
20081
  }
20024
- function dropCachedChat(cache, chatId) {
20025
- if (!chatId) {
20026
- return;
20027
- }
20028
- dropCachedChats(cache, [chatId]);
20029
- }
20030
20082
  var init_chats2 = __esm(() => {
20031
20083
  init_config();
20032
20084
  init_time();
@@ -24927,6 +24979,17 @@ function createRouteMemory(limit = CHAT_MESSAGE_VIEW_CACHE_SIZE) {
24927
24979
  }
24928
24980
  return {
24929
24981
  clear,
24982
+ dropChat(chatId) {
24983
+ const id = String(chatId || "").trim();
24984
+ if (!id)
24985
+ return;
24986
+ const keys = chatRouteMemoryKeys(id, [...states.keys(), ...retained.keys()]);
24987
+ for (const key of keys) {
24988
+ states.delete(key);
24989
+ retained.delete(key);
24990
+ }
24991
+ activeChats.delete(id);
24992
+ },
24930
24993
  resetAccount(nextAccountKey) {
24931
24994
  const next = nextAccountKey || "";
24932
24995
  if (accountKey === next) {
@@ -26531,6 +26594,9 @@ async function verifyOpenedPingEpoch(context) {
26531
26594
  const decision = await decideIncomingChat(context, epochState);
26532
26595
  if (decision === CHAT_ADMISSION_DECISIONS.REJECT)
26533
26596
  return "rejected";
26597
+ const unavailable = await checkOpenedWelcomeAvailability(context);
26598
+ if (unavailable)
26599
+ return unavailable;
26534
26600
  if (decision === CHAT_ADMISSION_DECISIONS.REQUEST)
26535
26601
  return "request";
26536
26602
  } else if (context.entry && (epochState.manifest.lineage === "direct" || epochState.manifest.lineage === "group")) {
@@ -26540,6 +26606,27 @@ async function verifyOpenedPingEpoch(context) {
26540
26606
  }
26541
26607
  return null;
26542
26608
  }
26609
+ async function checkOpenedWelcomeAvailability(context) {
26610
+ const { cloud, identity, options, uid, epochState } = context;
26611
+ assertInboxLease(options);
26612
+ try {
26613
+ await cloud.chat.state.transition(epochState.manifest.chatId, epochState.manifest.epochId, epochState.stateCapability);
26614
+ assertInboxLease(options);
26615
+ return null;
26616
+ } catch (error) {
26617
+ const code = cleanText(error?.code).toLowerCase();
26618
+ if (code !== "permission-denied" && !code.endsWith("/permission-denied"))
26619
+ throw error;
26620
+ try {
26621
+ await retireConfirmedDeletedChat(cloud, uid, identity, context.committedEntry || context.entry || makeOwnChatEntry(epochState), options);
26622
+ return "deleted";
26623
+ } catch (confirmationError) {
26624
+ if (isRetryableInboxError(confirmationError))
26625
+ throw confirmationError;
26626
+ throw error;
26627
+ }
26628
+ }
26629
+ }
26543
26630
  function startOpenedWelcomeHydration(context) {
26544
26631
  const membershipWelcome = (!context.entry || context.restoringMembership) && context.payload.kind === "welcome";
26545
26632
  if (!membershipWelcome)
@@ -26776,17 +26863,30 @@ async function settleOpenedPing(prepared, onAuthoritative) {
26776
26863
  const createsMembership = !context.entry && context.payload.kind === "welcome";
26777
26864
  const ownerPersistence = createsMembership ? captureAsync(persistOpenedPingOwner(context)) : null;
26778
26865
  const messageStartedAt = Date.now();
26779
- const result = await applyOpenedPingMessage(context);
26866
+ const messageOutcome = await captureAsync(applyOpenedPingMessage(context));
26780
26867
  markDiag(context.options.diag, "chat.inbox.settle.message.done", {
26781
26868
  elapsedMs: Date.now() - messageStartedAt
26782
26869
  });
26783
- if (result)
26784
- return result;
26785
- prepareOpenedPingActivity(context);
26786
26870
  if (ownerPersistence)
26787
26871
  await unwrapAsync(ownerPersistence);
26788
- else
26789
- await persistOpenedPingOwner(context);
26872
+ else if (messageOutcome.error)
26873
+ throw messageOutcome.error;
26874
+ if (messageOutcome.value)
26875
+ return messageOutcome.value;
26876
+ if (!messageOutcome.error) {
26877
+ prepareOpenedPingActivity(context);
26878
+ if (!ownerPersistence)
26879
+ await persistOpenedPingOwner(context);
26880
+ }
26881
+ if (context.membershipWelcome) {
26882
+ const unavailable = await checkOpenedWelcomeAvailability(context);
26883
+ if (unavailable) {
26884
+ await cleanupOpenedPing(context);
26885
+ return unavailable;
26886
+ }
26887
+ }
26888
+ if (messageOutcome.error)
26889
+ throw messageOutcome.error;
26790
26890
  publishOpenedPing(context);
26791
26891
  onAuthoritative?.();
26792
26892
  const phaseStartedAt = Date.now();
@@ -26913,6 +27013,7 @@ async function preparePreparedPing(cloud, uid, identity, prepared, options) {
26913
27013
  ping,
26914
27014
  uid
26915
27015
  });
27016
+ assertInboxLease(options);
26916
27017
  return { opened, releaseMutation };
26917
27018
  } catch (error) {
26918
27019
  releaseMutation();
@@ -27367,10 +27468,11 @@ async function prepareInboxWork(context, prepared, processingOptions = {}) {
27367
27468
  const { blockedUids, cloud, identity, options, state, uid } = context;
27368
27469
  const { document: document2, opened } = prepared;
27369
27470
  let announcement = null;
27471
+ let ping = null;
27370
27472
  try {
27371
27473
  const authenticated = await authenticateInboxPing(cloud, identity, document2, opened, state.currentChats, context.profileCache);
27372
27474
  assertInboxLease(options);
27373
- const ping = await preparePreparedPing(cloud, uid, identity, authenticated, {
27475
+ ping = await preparePreparedPing(cloud, uid, identity, authenticated, {
27374
27476
  ...options,
27375
27477
  blockedUids,
27376
27478
  currentChats: state.currentChats,
@@ -27387,9 +27489,11 @@ async function prepareInboxWork(context, prepared, processingOptions = {}) {
27387
27489
  if (ping.opened?.result === "request") {
27388
27490
  await hydrateOpenedChatRequest(ping.opened.context);
27389
27491
  }
27492
+ assertInboxLease(options);
27390
27493
  announcement = announcePreparedWelcome(context, authenticated, ping, document2, prepared.startedAt);
27391
27494
  return { announcement, document: document2, ping, prepared, processingOptions, status: null };
27392
27495
  } catch (error) {
27496
+ ping?.releaseMutation();
27393
27497
  state.revokeAnnouncement(announcement);
27394
27498
  if (processingOptions.deferUnknownWelcome === true && error?.message === "chat mls welcome required") {
27395
27499
  markDiag(options.diag, "chat.inbox.document.deferred", { reason: "welcome_required" });
@@ -27517,6 +27621,8 @@ function createInboxSettlementController(options = {}) {
27517
27621
  for (const job of lane.jobs) {
27518
27622
  if (job.settled)
27519
27623
  continue;
27624
+ if (job.state === "ready")
27625
+ job.discard?.(job.prepared);
27520
27626
  job.settled = true;
27521
27627
  job.state = "settled";
27522
27628
  job.deferred.reject(error);
@@ -27561,9 +27667,12 @@ function createInboxSettlementController(options = {}) {
27561
27667
  }
27562
27668
  job.state = "preparing";
27563
27669
  Promise.resolve().then(job.prepare).then((prepared) => {
27564
- if (job.settled)
27670
+ if (job.settled) {
27671
+ job.discard?.(prepared);
27565
27672
  return;
27673
+ }
27566
27674
  if (!hasLease()) {
27675
+ job.discard?.(prepared);
27567
27676
  finishJob(job, inboxLeaseError());
27568
27677
  return;
27569
27678
  }
@@ -27584,6 +27693,7 @@ function createInboxSettlementController(options = {}) {
27584
27693
  if (!job || job.settled)
27585
27694
  continue;
27586
27695
  if (!hasLease()) {
27696
+ job.discard?.(job.prepared);
27587
27697
  finishJob(job, inboxLeaseError());
27588
27698
  continue;
27589
27699
  }
@@ -27619,6 +27729,7 @@ function createInboxSettlementController(options = {}) {
27619
27729
  const job = {
27620
27730
  chatId,
27621
27731
  deferred: inboxDeferred(),
27732
+ discard: task.discard,
27622
27733
  lane,
27623
27734
  prepare: task.prepare,
27624
27735
  prepared: null,
@@ -27676,6 +27787,10 @@ async function processInboxDocuments(context, documents, processingOptions = {})
27676
27787
  const deferred = [];
27677
27788
  await Promise.all(groups.map((group) => context.settlementController.schedule(cleanText(group[0]?.opened?.payload?.chatId), {
27678
27789
  prepare: () => context.discoveryPool.run(() => prepareInboxWork(context, group[0], processingOptions)),
27790
+ discard: (work) => {
27791
+ work?.ping?.releaseMutation();
27792
+ context.state.revokeAnnouncement(work?.announcement);
27793
+ },
27679
27794
  settle: async (first, markAuthoritative) => {
27680
27795
  if (await settleInboxWork(context, first, markAuthoritative) === "deferred")
27681
27796
  deferred.push(first.document);
@@ -27987,6 +28102,7 @@ function listenToChats(cloud, uid, userChatPK, userPrivKey, onUpdate, onError, o
27987
28102
  nextAfterChat: snapshot.nextAfterChat,
27988
28103
  hasMore: snapshot.hasMore,
27989
28104
  ownerListToken: snapshot.ownerListToken,
28105
+ sourceRevision: snapshot.sourceRevision,
27990
28106
  source: "server"
27991
28107
  });
27992
28108
  deleteConfirmedUserChats(cloud, uid, page.deletedEntryIds);
@@ -28211,7 +28327,8 @@ function listenToChats(cloud, uid, userChatPK, userPrivKey, onUpdate, onError, o
28211
28327
  latestOwnerSnapshot = {
28212
28328
  docs: entries,
28213
28329
  nextAfterChat: meta.nextAfterChat ?? null,
28214
- hasMore: !!meta.hasMore
28330
+ hasMore: !!meta.hasMore,
28331
+ sourceRevision: options.getSourceRevision?.()
28215
28332
  };
28216
28333
  queueOwnerSnapshot();
28217
28334
  }, onError, { limitCount: pageSize });
@@ -28722,15 +28839,15 @@ function createChatListIndex({ cache, filterHiddenChats, getSources, isHiddenCha
28722
28839
  const ownerFor = (entry) => composeActivity(structuralOwnerFor(entry), entry);
28723
28840
  const cacheFor = (entry) => composeActivity(entry?.cache, entry);
28724
28841
  const sourceCanPublish = (chat, sourceRevision) => {
28842
+ const boundary = authorityBoundaries.get(chat?.id);
28843
+ if (boundary?.terminal)
28844
+ return false;
28725
28845
  if (!chat?.id || !Number.isSafeInteger(sourceRevision))
28726
28846
  return true;
28727
28847
  if (sourceRevision < sourceRevisionFloor)
28728
28848
  return false;
28729
- const boundary = authorityBoundaries.get(chat.id);
28730
28849
  if (!boundary)
28731
28850
  return true;
28732
- if (boundary.terminal)
28733
- return false;
28734
28851
  return sourceRevision >= boundary.revision || compareOwners(chat, boundary.owner) > 0;
28735
28852
  };
28736
28853
  const sourceCanRemove = (chatId, sourceRevision) => {
@@ -28870,21 +28987,33 @@ function createChatListIndex({ cache, filterHiddenChats, getSources, isHiddenCha
28870
28987
  updatePeers(shown);
28871
28988
  return shown;
28872
28989
  };
28990
+ const clearRemovedOwners = (chatIds) => {
28991
+ if (!chatIds.length)
28992
+ return;
28993
+ const sources = getSources();
28994
+ for (const chatId of chatIds)
28995
+ sources.pendingDeleteIdsRef.current.delete(chatId);
28996
+ sources.onOwnerRemoved?.(chatIds);
28997
+ cache.removeMany(chatIds);
28998
+ const removedIds = new Set(chatIds);
28999
+ sources.setSelectedChat((current) => removedIds.has(current) ? null : current);
29000
+ };
28873
29001
  const convergeCompleteOwnerSet = (incomingIds = null, sourceRevision = null) => {
28874
- const evictedCacheIds = [];
29002
+ const removedIds = [];
28875
29003
  for (const [chatId, entry] of entries) {
28876
- if (!entry.observedOwner && !entry.committedOwner && !entry.announcement) {
28877
- if (!sourceCanRemove(chatId, sourceRevision))
28878
- continue;
28879
- recordTerminal(chatId, cacheFor(entry));
28880
- if (entry.cache)
28881
- evictedCacheIds.push(chatId);
28882
- entries.delete(chatId);
28883
- } else if (!incomingIds || !incomingIds.has(chatId)) {
29004
+ if (incomingIds ? incomingIds.has(chatId) : entry.observedOwner)
29005
+ continue;
29006
+ if (!sourceCanRemove(chatId, sourceRevision))
29007
+ continue;
29008
+ if (entry.announcement && !authorityBoundaries.get(chatId)?.owner) {
28884
29009
  entry.cache = null;
29010
+ continue;
28885
29011
  }
29012
+ recordTerminal(chatId, ownerFor(entry) || cacheFor(entry));
29013
+ entries.delete(chatId);
29014
+ removedIds.push(chatId);
28886
29015
  }
28887
- cache.removeMany(evictedCacheIds);
29016
+ clearRemovedOwners(removedIds);
28888
29017
  };
28889
29018
  const observeOwnerChats = (rows, options = {}) => {
28890
29019
  const incoming = (rows || []).filter((chat) => chat?.id && sourceCanPublish(chat, options.sourceRevision));
@@ -28960,6 +29089,8 @@ function createChatListIndex({ cache, filterHiddenChats, getSources, isHiddenCha
28960
29089
  const announceWelcome = (announcement) => {
28961
29090
  if (!announcement?.chatId || !announcement?.token)
28962
29091
  return false;
29092
+ if (authorityBoundaries.get(announcement.chatId)?.terminal)
29093
+ return false;
28963
29094
  const sources = getSources();
28964
29095
  if (sources.pendingDeleteIdsRef.current.has(announcement.chatId))
28965
29096
  return false;
@@ -28996,7 +29127,6 @@ function createChatListIndex({ cache, filterHiddenChats, getSources, isHiddenCha
28996
29127
  return false;
28997
29128
  if (!sourceCanRemove(chatId, options.sourceRevision))
28998
29129
  return false;
28999
- recordTerminal(chatId, cacheFor(entry));
29000
29130
  entry.cache = null;
29001
29131
  entry.presentation = null;
29002
29132
  cache.remove(chatId);
@@ -29006,15 +29136,12 @@ function createChatListIndex({ cache, filterHiddenChats, getSources, isHiddenCha
29006
29136
  return true;
29007
29137
  };
29008
29138
  const removeOwner = (chatId, options = {}) => {
29009
- const sources = getSources();
29010
29139
  if (!chatId)
29011
29140
  return false;
29012
29141
  recordTerminal(chatId, ownerFor(entries.get(chatId)) || cacheFor(entries.get(chatId)));
29013
- sources.pendingDeleteIdsRef.current.delete(chatId);
29014
29142
  const removed = entries.delete(chatId);
29015
- cache.remove(chatId);
29143
+ clearRemovedOwners([chatId]);
29016
29144
  publishOwners({ ...options, warm: false });
29017
- sources.setSelectedChat((current) => current === chatId ? null : current);
29018
29145
  return removed;
29019
29146
  };
29020
29147
  const removeInboxOwner = (chatId, options = {}) => {
@@ -29371,7 +29498,7 @@ function createChatListListener({
29371
29498
  sync();
29372
29499
  }, CHAT_LIST_LISTENER_RETRY_MS);
29373
29500
  };
29374
- const subscription = subscribe(sources.cloud, sources.uid, sources.chatPK, sources.chatPrivateKey, (nextChats, _nextPeers, meta = {}) => handleUpdate(nextChats, meta, listenStartedAt, index.getAuthorityRevision()), (error) => {
29501
+ const subscription = subscribe(sources.cloud, sources.uid, sources.chatPK, sources.chatPrivateKey, (nextChats, _nextPeers, meta = {}) => handleUpdate(nextChats, meta, listenStartedAt, meta.sourceRevision), (error) => {
29375
29502
  const current = getSources();
29376
29503
  state.setIsChatListLive(false);
29377
29504
  markError(current.diag, "chat.provider.listen", listenStartedAt, error);
@@ -29382,6 +29509,7 @@ function createChatListListener({
29382
29509
  retry(error);
29383
29510
  }, {
29384
29511
  limitCount: CHAT_LIST_LIVE_COUNT,
29512
+ getSourceRevision: index.getAuthorityRevision,
29385
29513
  onInboxAnnouncement: index.announceWelcome,
29386
29514
  onInboxRevoke: index.revokeAnnouncement,
29387
29515
  onInboxCommit: index.commitOwner,
@@ -31040,7 +31168,7 @@ function patchMessageFromCachedMessage(message, cached) {
31040
31168
  const patch = {};
31041
31169
  let changed = false;
31042
31170
  const cachedReactions = getMsgReactions(cached);
31043
- if (cachedReactions.length && !sameReactionProjection(message, cached)) {
31171
+ if (cachedReactions.length && !sameReactions(message.reactions, cached.reactions)) {
31044
31172
  patch.reactions = cachedReactions;
31045
31173
  changed = true;
31046
31174
  }
@@ -31066,19 +31194,6 @@ function patchMessageFromCachedMessage(message, cached) {
31066
31194
  }
31067
31195
  return changed ? { ...message, ...patch } : message;
31068
31196
  }
31069
- function sameReactionProjection(a, b) {
31070
- const left = getMsgReactions(a);
31071
- const right = getMsgReactions(b);
31072
- if (left.length !== right.length) {
31073
- return false;
31074
- }
31075
- for (let index = 0;index < left.length; index += 1) {
31076
- if (left[index].user !== right[index]?.user || left[index].emoji !== right[index]?.emoji) {
31077
- return false;
31078
- }
31079
- }
31080
- return true;
31081
- }
31082
31197
  function patchMessagesFromCachedWindow(messages, cachedMessages) {
31083
31198
  if (!messages?.length || !cachedMessages?.length) {
31084
31199
  return messages || [];
@@ -31735,6 +31850,7 @@ async function createGroupChat(cloud, identityValue, memberValues, settings = {}
31735
31850
  if (!identity.chatSigningSecret)
31736
31851
  throw new Error("unlocked chat signing identity required");
31737
31852
  const mls = await lifecycle.mls?.open?.();
31853
+ lifecycle.assertCurrent?.();
31738
31854
  if (!mls)
31739
31855
  throw new Error("mls engine required");
31740
31856
  const selfLeafId = lifecycle.selfLeafId || randomBytes3(32);
@@ -31755,7 +31871,7 @@ async function createGroupChat(cloud, identityValue, memberValues, settings = {}
31755
31871
  if (additions.length)
31756
31872
  mlsGroup = await mls.stageChange(mlsGroup.snapshot, { adds: additions });
31757
31873
  const material = deriveChatMlsEpochMaterial(mlsGroup.epochKey, { chatId, epochVersion: 1 });
31758
- const lineage = members.length === 1 ? CHAT_LINEAGES.SELF : members.length === 2 ? CHAT_LINEAGES.DIRECT : CHAT_LINEAGES.GROUP;
31874
+ const lineage = lifecycle.lineage || (members.length === 1 ? CHAT_LINEAGES.SELF : members.length === 2 ? CHAT_LINEAGES.DIRECT : CHAT_LINEAGES.GROUP);
31759
31875
  const manifest = makeInitialEpochManifest({
31760
31876
  chatId,
31761
31877
  epochId: material.epochId,
@@ -31818,6 +31934,7 @@ async function createGroupChat(cloud, identityValue, memberValues, settings = {}
31818
31934
  });
31819
31935
  initial.backend.membershipOutbox = queuedWelcomes.map(({ outboxId: outboxId2, sealed }) => ({ outboxId: outboxId2, sealed }));
31820
31936
  stage = "owner";
31937
+ lifecycle.assertCurrent?.();
31821
31938
  const registration = registerInitialDelivery(cloud, identity, initialState);
31822
31939
  const stateId = chatMlsStateId(identity.chatPrivateKey, chatId, initial.transitionCommitment);
31823
31940
  const ownerMlsState = await sealChatMlsState(identity.chatPrivateKey, stateId, { v: 1, chatId, transitionCommitment: initial.transitionCommitment }, mlsGroup.snapshot);
@@ -31829,6 +31946,8 @@ async function createGroupChat(cloud, identityValue, memberValues, settings = {}
31829
31946
  let stateError = null;
31830
31947
  try {
31831
31948
  stage = "state";
31949
+ lifecycle.assertCurrent?.();
31950
+ lifecycle.onCreateDispatched?.(initial.manifest.chatId);
31832
31951
  await cloud.chat.state.create({
31833
31952
  ...initial.backend,
31834
31953
  ownerEntry: owner.write,
@@ -32183,21 +32302,23 @@ function createChatSessionLaunches({
32183
32302
  if (!opened?.chatId || !opened?.entry)
32184
32303
  return "";
32185
32304
  const chat = projectOwnChatEntry(opened.entry, opened.entryId || "", operation.identity.chatPK, opened.tsMs || Date.now());
32186
- operation.listOwner.commitOwner(chat);
32305
+ if (!operation.listOwner.commitOwner(chat))
32306
+ throw makeChatUnavailableError();
32187
32307
  return opened.chatId;
32188
32308
  };
32189
32309
  const presentOpenedChat = (opened, operation) => {
32190
32310
  assertCurrent(operation);
32191
32311
  if (!opened?.chatId || !opened?.entry)
32192
32312
  return "";
32193
- operation.pendingOwner.adoptOpenedChatId(opened.chatId);
32194
32313
  const chatId = commitOpenedChat(opened, operation);
32314
+ operation.pendingOwner.adoptOpenedChatId(chatId);
32195
32315
  pendingPeerSelect = null;
32196
32316
  setSelectedChat(chatId);
32197
32317
  return chatId;
32198
32318
  };
32199
32319
  const createChat = async (profiles, settings, lifecycle, adoptOpenedChat, operation, { profilesCurrent = false } = {}) => {
32200
32320
  assertCurrent(operation);
32321
+ lifecycle.assertCurrent?.();
32201
32322
  const { blocked, chatPK, chatPrivateKey } = operation.identity;
32202
32323
  let profileList = Array.isArray(profiles) ? profiles : [profiles];
32203
32324
  if (!profilesCurrent && profileList.length) {
@@ -32205,9 +32326,10 @@ function createChatSessionLaunches({
32205
32326
  }
32206
32327
  const blockedSet = new Set(blocked);
32207
32328
  const requestedMembers = profileList.map(profileMember);
32208
- if (profileList.length === 1) {
32329
+ const expectedLineage = lifecycle.lineage || (requestedMembers.length === 0 ? "self" : requestedMembers.length === 1 ? "direct" : "group");
32330
+ if (expectedLineage === "direct") {
32209
32331
  assertDirectAdmission(profileList[0], operation);
32210
- } else if (profileList.length > 1) {
32332
+ } else if (expectedLineage === "group") {
32211
32333
  if (normalizeChatAdmission(operation.identity.chatAdmission).groups === CHAT_GROUP_ADMISSION_MODES.CLOSED) {
32212
32334
  throw new Error("group chats are closed");
32213
32335
  }
@@ -32221,8 +32343,7 @@ function createChatSessionLaunches({
32221
32343
  if (blockedSet.has(member.uid))
32222
32344
  throw new Error("blocked peer cannot be added");
32223
32345
  }
32224
- const canonicalChatId = lifecycle.chatId || (requestedMembers.length === 0 ? deriveSelfChatId(chatPrivateKey, chatPK) : "");
32225
- const expectedLineage = requestedMembers.length === 0 ? "self" : requestedMembers.length === 1 ? "direct" : "group";
32346
+ const canonicalChatId = lifecycle.chatId || (expectedLineage === "self" ? deriveSelfChatId(chatPrivateKey, chatPK) : "");
32226
32347
  const expectedMemberKeys = [chatPK, ...requestedMembers.map((member) => member.chatPK)].sort();
32227
32348
  const matchingExistingChat = () => {
32228
32349
  assertCurrent(operation);
@@ -32261,6 +32382,7 @@ function createChatSessionLaunches({
32261
32382
  markDiag(diag, "chat.group.create.prekeys.start", { members: requestedMembers.length });
32262
32383
  const additions = await prepareMlsAdditions(profileList);
32263
32384
  assertCurrent(operation);
32385
+ lifecycle.assertCurrent?.();
32264
32386
  markDiag(diag, "chat.group.create.prekeys.done", { members: requestedMembers.length, elapsedMs: Date.now() - prekeyStartedAt });
32265
32387
  if (!additions.length && requestedMembers.length)
32266
32388
  throw new Error("peer mls key package required");
@@ -32270,15 +32392,23 @@ function createChatSessionLaunches({
32270
32392
  const created = await createGroupChat(cloud, operation.transitionIdentity, [...byKey.values()], settings, {
32271
32393
  mls,
32272
32394
  chatId: canonicalChatId || undefined,
32395
+ lineage: expectedLineage,
32273
32396
  wakeMessageId: lifecycle.wakeMessageId,
32397
+ assertCurrent: () => {
32398
+ assertCurrent(operation);
32399
+ lifecycle.assertCurrent?.();
32400
+ },
32401
+ onCreateDispatched: lifecycle.onCreateDispatched,
32274
32402
  onStateReady: (opened) => {
32275
32403
  assertCurrent(operation);
32404
+ lifecycle.assertCurrent?.();
32276
32405
  stateReady = true;
32277
32406
  const chatId = adoptOpenedChat(opened);
32278
32407
  lifecycle.onStateReady?.(chatId, opened, { created: true });
32279
32408
  },
32280
32409
  onOwnerReady: async (opened) => {
32281
32410
  assertCurrent(operation);
32411
+ lifecycle.assertCurrent?.();
32282
32412
  const chatId = adoptOpenedChat(opened);
32283
32413
  const result = await lifecycle.onOwnerReady?.(chatId, opened, { created: true });
32284
32414
  assertCurrent(operation);
@@ -32289,7 +32419,7 @@ function createChatSessionLaunches({
32289
32419
  return adoptOpenedChat(created);
32290
32420
  } catch (error) {
32291
32421
  assertCurrent(operation);
32292
- if (stateReady || !canonicalChatId || requestedMembers.length > 0)
32422
+ if (stateReady || !canonicalChatId)
32293
32423
  throw error;
32294
32424
  await ensureChat(canonicalChatId);
32295
32425
  assertCurrent(operation);
@@ -32303,6 +32433,10 @@ function createChatSessionLaunches({
32303
32433
  const operation = operationContext();
32304
32434
  return createChat(profiles, settings, lifecycle, (opened) => presentOpenedChat(opened, operation), operation);
32305
32435
  };
32436
+ const materializeGroupChat = (profiles, settings = {}, lifecycle = {}) => {
32437
+ const operation = operationContext();
32438
+ return createChat(profiles, settings, lifecycle, (opened) => commitOpenedChat(opened, operation), operation);
32439
+ };
32306
32440
  const runExistingDirectLifecycle = async (chatId, lifecycle, operation) => {
32307
32441
  assertCurrent(operation);
32308
32442
  const existing = getOwnerChat(chatId);
@@ -32374,6 +32508,7 @@ function createChatSessionLaunches({
32374
32508
  getOpenOperation: (chatId) => directOpens.get(chatId)?.promise || null,
32375
32509
  getPeerChatId,
32376
32510
  materializeDirectChat,
32511
+ materializeGroupChat,
32377
32512
  openDirectChat,
32378
32513
  openNotesChat,
32379
32514
  releaseOpenOperation: (chatId) => {
@@ -32501,16 +32636,21 @@ function createChatSessionPending({
32501
32636
  getPeerProfile,
32502
32637
  resolvePeerProfile,
32503
32638
  setLocalByChat,
32504
- getLocalByChat = () => new Map
32639
+ getLocalByChat = () => new Map,
32640
+ retireMaterializedChat = () => {}
32505
32641
  }) {
32642
+ const admission = createChatAdmission({ getIdentity });
32506
32643
  let pendingLaunch = null;
32507
32644
  const pendingOperations = new Map;
32508
32645
  let generation = 0;
32646
+ const operationForChat = (chatId) => pendingOperations.get(chatId) || [...pendingOperations.values()].find((state) => state.canonicalChatId === chatId) || null;
32647
+ const launchForChat = (chatId) => pendingLaunch && [pendingLaunch.id, pendingLaunch.canonicalChatId].includes(chatId) ? pendingLaunch : operationForChat(chatId)?.launch || storedLaunch(chatId);
32509
32648
  const storedLaunch = (chatId) => getLocalByChat().get(chatId)?.find((message) => message.chatDraft)?.chatDraft || null;
32510
32649
  const getPendingLaunch = () => {
32511
32650
  if (!pendingLaunch)
32512
32651
  return null;
32513
- const messages = getLocalByChat().get(pendingLaunch.id) || [];
32652
+ const localByChat = getLocalByChat();
32653
+ const messages = localByChat.get(pendingLaunch.id) || localByChat.get(pendingLaunch.canonicalChatId) || [];
32514
32654
  const message = messages[messages.length - 1] || null;
32515
32655
  return { ...pendingLaunch, messages, message, chat: {
32516
32656
  ...pendingLaunch.chat,
@@ -32518,23 +32658,33 @@ function createChatSessionPending({
32518
32658
  ts: message ? timestampMs(message.ts, null) : null
32519
32659
  } };
32520
32660
  };
32661
+ const resolvePendingChatId = (chatId) => {
32662
+ const canonicalId = operationForChat(chatId)?.canonicalChatId || launchForChat(chatId)?.canonicalChatId;
32663
+ return canonicalId && getOwnerChat(canonicalId) ? canonicalId : chatId;
32664
+ };
32521
32665
  const finish = (launchId) => {
32522
32666
  if (pendingLaunch?.id !== launchId)
32523
32667
  return;
32668
+ if (pendingLaunch.canonicalChatId !== launchId) {
32669
+ publish();
32670
+ return;
32671
+ }
32524
32672
  pendingLaunch = null;
32525
32673
  pendingOperations.delete(launchId);
32526
32674
  publish();
32527
32675
  };
32528
32676
  const track = (launchId, operation) => {
32529
32677
  const tracked = Promise.resolve(operation);
32530
- pendingOperations.set(launchId, tracked);
32678
+ const state = pendingOperations.get(launchId) || { active: true, promise: null };
32679
+ state.promise = tracked;
32680
+ pendingOperations.set(launchId, state);
32531
32681
  tracked.then(() => {
32532
- if (pendingOperations.get(launchId) !== tracked)
32682
+ if (pendingOperations.get(launchId) !== state || state.promise !== tracked)
32533
32683
  return;
32534
32684
  pendingOperations.delete(launchId);
32535
32685
  finish(launchId);
32536
32686
  }, () => {
32537
- if (pendingOperations.get(launchId) !== tracked)
32687
+ if (pendingOperations.get(launchId) !== state || state.promise !== tracked)
32538
32688
  return;
32539
32689
  pendingOperations.delete(launchId);
32540
32690
  if (pendingLaunch?.id !== launchId)
@@ -32546,6 +32696,12 @@ function createChatSessionPending({
32546
32696
  });
32547
32697
  return tracked;
32548
32698
  };
32699
+ const cancelOperation = (launchId) => {
32700
+ const operation = pendingOperations.get(launchId);
32701
+ if (operation)
32702
+ operation.active = false;
32703
+ pendingOperations.delete(launchId);
32704
+ };
32549
32705
  const show = (launch) => {
32550
32706
  if (pendingLaunch?.id && pendingLaunch.id !== launch.id && !pendingOperations.has(pendingLaunch.id)) {
32551
32707
  getRouteOwner().releaseOpenOperation?.(pendingLaunch.id);
@@ -32641,7 +32797,7 @@ function createChatSessionPending({
32641
32797
  return cached;
32642
32798
  return (fallbackProfiles || []).find((profile) => profileMatchesPeer(profile, peer)) || null;
32643
32799
  };
32644
- const profileAcceptsDirect = (identity, profile) => !!identity?.chatPK && !!identity?.chatPrivateKey && directAdmissionForPeer(identity.chatPrivateKey, identity.chatPK, profile, identity.chatAdmission) !== CHAT_ADMISSION_DECISIONS.REJECT;
32800
+ const profileAcceptsDirect = (identity, profile) => !!identity?.chatPK && !!identity?.chatPrivateKey && admission.directAdmissionForPeer(profile) !== CHAT_ADMISSION_DECISIONS.REJECT;
32645
32801
  const isChatAdmitted = (chat, fallbackProfiles = []) => {
32646
32802
  const identity = getIdentity();
32647
32803
  if (!chat)
@@ -32774,18 +32930,29 @@ function createChatSessionPending({
32774
32930
  throw error;
32775
32931
  }
32776
32932
  };
32777
- const sendDurableAttachment = async (chatId, attachment, options = {}) => {
32778
- const target = await admittedSendTarget(chatId, options);
32779
- return getSendActions().sendAttachment(target.routeAnchor, attachment, target.options);
32780
- };
32781
- const sendDurableSharedAttachment = async (chatId, attachment, options = {}) => {
32933
+ const withReadyAttachmentTarget = async (chatId, options, send) => {
32934
+ const attemptGeneration = generation;
32935
+ await waitForSend(chatId, { expiresAt: options.expiresAt, signal: options.signal });
32936
+ if (attemptGeneration !== generation)
32937
+ throw makeChatUnavailableError();
32782
32938
  const target = await admittedSendTarget(chatId, options);
32783
- return getSendActions().sendSharedAttachment(target.routeAnchor, attachment, target.options);
32939
+ if (attemptGeneration !== generation)
32940
+ throw makeChatUnavailableError();
32941
+ return send(target);
32784
32942
  };
32943
+ const sendDurableAttachment = (chatId, attachment, options = {}) => withReadyAttachmentTarget(chatId, options, (target) => getSendActions().sendAttachment(target.routeAnchor, attachment, target.options));
32944
+ const sendDurableSharedAttachment = (chatId, attachment, options = {}) => withReadyAttachmentTarget(chatId, options, (target) => getSendActions().sendSharedAttachment(target.routeAnchor, attachment, target.options));
32785
32945
  const stagePendingMessage = (launchId, local) => {
32786
- if (!pendingLaunch || pendingLaunch.id !== launchId)
32946
+ const launch = launchForChat(launchId);
32947
+ if (!launch || launch.id !== launchId)
32787
32948
  throw makeChatUnavailableError();
32788
- const { id, profiles: profiles2, settings, chat } = pendingLaunch;
32949
+ const { id, profiles: profiles2, settings, chat } = launch;
32950
+ const canonicalId = resolvePendingChatId(launchId);
32951
+ if (getOwnerChat(canonicalId)) {
32952
+ const { chatDraft: _draft, ...content } = local;
32953
+ setLocalByChat((current) => addLocalMessage(current, canonicalId, content));
32954
+ return;
32955
+ }
32789
32956
  const chatDraft = { id, canonicalChatId: id, profiles: profiles2, settings, chat };
32790
32957
  setLocalByChat((current) => addLocalMessage(current, launchId, { ...local, chatDraft }));
32791
32958
  };
@@ -32797,6 +32964,8 @@ function createChatSessionPending({
32797
32964
  const canonical = targetId !== launchId ? current.get(targetId) || [] : [];
32798
32965
  const writerIds = new Set(canonical.map((message) => message.cid));
32799
32966
  const staged = (current.get(launchId) || []).filter((message) => !writerIds.has(message.cid));
32967
+ if (!canonical.length && !staged.length)
32968
+ return current;
32800
32969
  next.set(targetId, [...canonical, ...staged].map((message) => {
32801
32970
  const { chatDraft, ...content } = message;
32802
32971
  return {
@@ -32812,14 +32981,22 @@ function createChatSessionPending({
32812
32981
  if (getOwnerChat(canonicalId) && pendingLaunch?.id === launchId)
32813
32982
  setSelectedChat(canonicalId);
32814
32983
  };
32815
- const retirePeer = (peerChatPK) => {
32816
- const launch = pendingLaunch;
32817
- if (!launch?.chat?.members?.some((member) => member?.chatPK === peerChatPK))
32984
+ const dropChat = (chatId) => {
32985
+ const launch = launchForChat(chatId);
32986
+ if (!launch || launch.id !== chatId && launch.canonicalChatId !== chatId)
32818
32987
  return false;
32819
32988
  beginSelection();
32820
32989
  getRouteOwner().releaseOpenOperation?.(launch.id);
32821
- pendingLaunch = null;
32822
- pendingOperations.delete(launch.id);
32990
+ if (pendingLaunch?.id === launch.id)
32991
+ pendingLaunch = null;
32992
+ cancelOperation(launch.id);
32993
+ setLocalByChat((current) => {
32994
+ if (!current.has(launch.id))
32995
+ return current;
32996
+ const next = new Map(current);
32997
+ next.delete(launch.id);
32998
+ return next;
32999
+ });
32823
33000
  if (getSelectedChatId() === launch.id || getSelectedChatId() === launch.canonicalChatId) {
32824
33001
  setSelectedChat(null);
32825
33002
  } else {
@@ -32827,25 +33004,74 @@ function createChatSessionPending({
32827
33004
  }
32828
33005
  return true;
32829
33006
  };
33007
+ const retirePeer = (peerChatPK) => pendingLaunch?.chat?.members?.some((member) => member?.chatPK === peerChatPK) ? dropChat(pendingLaunch.id) : false;
33008
+ const discardChat = async (chatId) => {
33009
+ const state = operationForChat(chatId);
33010
+ if (!state?.dispatched)
33011
+ return { discarded: dropChat(chatId), chat: null };
33012
+ state.discarding = true;
33013
+ if (pendingLaunch?.id === state.launch.id)
33014
+ pendingLaunch = null;
33015
+ if ([state.launch.id, state.canonicalChatId].includes(getSelectedChatId()))
33016
+ setSelectedChat(null);
33017
+ else
33018
+ publish();
33019
+ state.retirementTarget ||= getOwnerChat(state.canonicalChatId) || null;
33020
+ if (state.retirementTarget)
33021
+ retireMaterializedChat(state.canonicalChatId);
33022
+ const attemptGeneration = generation;
33023
+ await state.promise.catch(() => null);
33024
+ if (attemptGeneration !== generation)
33025
+ throw makeChatUnavailableError();
33026
+ if (!state.retirementTarget) {
33027
+ if (!getOwnerChat(state.canonicalChatId))
33028
+ await ensureChat(state.canonicalChatId);
33029
+ state.retirementTarget = getOwnerChat(state.canonicalChatId) || null;
33030
+ }
33031
+ if (attemptGeneration !== generation || !state.retirementTarget)
33032
+ throw makeChatUnavailableError();
33033
+ retireMaterializedChat(state.canonicalChatId);
33034
+ return { discarded: true, chat: state.retirementTarget };
33035
+ };
32830
33036
  const materialize = (launchId, wakeMessageId, sendInitial) => {
32831
33037
  const launch = pendingLaunch;
32832
33038
  if (!launch || launch.id !== launchId || pendingOperations.has(launchId))
32833
33039
  throw makeChatUnavailableError();
32834
33040
  const attemptGeneration = generation;
33041
+ const state = { active: true, promise: null, launch, canonicalChatId: launchId };
33042
+ pendingOperations.set(launchId, state);
33043
+ const assertCurrent = () => {
33044
+ if (attemptGeneration !== generation || !state.active)
33045
+ throw makeChatUnavailableError();
33046
+ };
32835
33047
  const expiresAt = Date.now() + CHAT_SEND_CONNECTION_WAIT_MS;
32836
33048
  let canonicalId = launchId;
32837
33049
  const operation = (async () => {
32838
33050
  await waitForSend(launchId, { expiresAt });
32839
- if (attemptGeneration !== generation)
32840
- throw makeChatUnavailableError();
33051
+ assertCurrent();
32841
33052
  let initialResult = null;
32842
33053
  const lifecycle = {
32843
33054
  wakeMessageId,
33055
+ assertCurrent,
33056
+ onCreateDispatched: (chatId) => {
33057
+ assertCurrent();
33058
+ state.dispatched = true;
33059
+ state.canonicalChatId = chatId;
33060
+ state.launch = { ...state.launch, canonicalChatId: chatId };
33061
+ },
32844
33062
  onStateReady: (chatId) => {
33063
+ assertCurrent();
32845
33064
  canonicalId = chatId;
33065
+ state.canonicalChatId = chatId;
33066
+ state.launch = { ...state.launch, canonicalChatId: chatId };
32846
33067
  adoptOpenedChatId(chatId, launchId);
33068
+ if (state.discarding) {
33069
+ state.retirementTarget = getOwnerChat(chatId);
33070
+ retireMaterializedChat(chatId);
33071
+ }
32847
33072
  },
32848
33073
  onOwnerReady: async (chatId, _opened, context) => {
33074
+ assertCurrent();
32849
33075
  canonicalId = chatId;
32850
33076
  initialResult = await sendInitial(chatId, { ...context, expiresAt });
32851
33077
  return initialResult;
@@ -32860,18 +33086,20 @@ function createChatSessionPending({
32860
33086
  canonicalId = resolvedChatId;
32861
33087
  initialResult = await sendInitial(resolvedChatId, { created: false, expiresAt });
32862
33088
  } else {
32863
- canonicalId = await getRouteOwner().createGroupChat(launch.profiles, launch.settings, {
33089
+ canonicalId = await getRouteOwner().materializeGroupChat(launch.profiles, launch.settings, {
32864
33090
  ...lifecycle,
32865
- chatId: launchId
33091
+ chatId: launch.canonicalChatId,
33092
+ lineage: launch.chat.lineage
32866
33093
  });
32867
33094
  }
32868
33095
  }
32869
33096
  if (attemptGeneration !== generation)
32870
33097
  throw makeChatUnavailableError();
32871
- settleMaterialization(launchId, canonicalId);
33098
+ if (state.active)
33099
+ settleMaterialization(launchId, canonicalId);
32872
33100
  return { ...initialResult || {}, chatId: canonicalId };
32873
33101
  })().catch((error) => {
32874
- if (attemptGeneration === generation)
33102
+ if (attemptGeneration === generation && state.active)
32875
33103
  settleMaterialization(launchId, canonicalId, true);
32876
33104
  throw error;
32877
33105
  });
@@ -32882,10 +33110,74 @@ function createChatSessionPending({
32882
33110
  ...context?.expiresAt ? { expiresAt: context.expiresAt } : {},
32883
33111
  ...context?.created === true ? { deliverRecipients: false, ownerImmediate: true } : {}
32884
33112
  });
33113
+ const runChatMutation = (chatId, mutate, { initialProfiles } = {}) => {
33114
+ const launch = launchForChat(chatId);
33115
+ const canonicalId = resolvePendingChatId(chatId);
33116
+ const active = launch && pendingOperations.get(launch.id);
33117
+ if (active?.discarding)
33118
+ throw makeChatUnavailableError();
33119
+ if (!active && getOwnerChat(canonicalId))
33120
+ return mutate(canonicalId, { created: false });
33121
+ if (!launch || getIdentity().chatBanned)
33122
+ throw makeChatUnavailableError();
33123
+ const attemptGeneration = generation;
33124
+ const perform = async (id, context) => {
33125
+ if (attemptGeneration !== generation)
33126
+ throw makeChatUnavailableError();
33127
+ const value = await mutate(id, context);
33128
+ if (attemptGeneration !== generation)
33129
+ throw makeChatUnavailableError();
33130
+ const ownerEntry = getOwnerChat(id)?.ownEntry;
33131
+ if (!ownerEntry)
33132
+ throw makeChatUnavailableError();
33133
+ return { value, ownerEntry };
33134
+ };
33135
+ if (active) {
33136
+ return track(launch.id, active.promise.then(async (result) => {
33137
+ if (!active.active)
33138
+ throw makeChatUnavailableError();
33139
+ const id = result?.chatId || launch.canonicalChatId;
33140
+ return { ...await perform(id, { created: false }), chatId: id };
33141
+ })).then((result) => result.value);
33142
+ }
33143
+ pendingLaunch = launch;
33144
+ if (initialProfiles) {
33145
+ if (launch.chat.lineage === "self")
33146
+ throw new Error("self chat membership is fixed");
33147
+ const profiles2 = initialProfiles(launch.profiles);
33148
+ if (profiles2 === launch.profiles)
33149
+ return Promise.resolve({ unchanged: true });
33150
+ const members = profiles2.map(profileMember);
33151
+ chatCapabilities(members.length + 1);
33152
+ const self2 = memberFromChatIdentity(transitionIdentity());
33153
+ if (members.some((member) => member.chatPK === self2.chatPK))
33154
+ throw new Error("current user is already a chat member");
33155
+ const lineage = launch.chat.lineage === "group" || members.length !== 1 ? "group" : launch.chat.lineage;
33156
+ pendingLaunch = {
33157
+ ...launch,
33158
+ canonicalChatId: lineage === "group" && launch.chat.lineage !== "group" ? randomChatId() : launch.canonicalChatId,
33159
+ profiles: profiles2.map((profile, index) => pendingProfile(profile, members[index])),
33160
+ chat: {
33161
+ ...launch.chat,
33162
+ lineage,
33163
+ peerChatPK: lineage === "direct" ? members[0]?.chatPK || null : null,
33164
+ members: [self2, ...members],
33165
+ memberCount: members.length + 1,
33166
+ memberChatPKs: [self2.chatPK, ...members.map((member) => member.chatPK)],
33167
+ memberUids: [self2.uid, ...members.map((member) => member.uid)]
33168
+ }
33169
+ };
33170
+ publish();
33171
+ }
33172
+ return materialize(launch.id, "", (id, context) => perform(id, {
33173
+ ...context,
33174
+ ...initialSendOptions({}, context)
33175
+ })).then((result) => result.value);
33176
+ };
32885
33177
  const sendPendingMessage = (launchId, message, options = {}) => {
32886
33178
  const { chatPK } = getIdentity();
32887
- const launch = pendingLaunch;
32888
- const previousOperation = pendingOperations.get(launchId);
33179
+ const launch = launchForChat(launchId);
33180
+ const previousOperation = pendingOperations.get(launchId)?.promise;
32889
33181
  if (!launch || launch.id !== launchId)
32890
33182
  throw makeChatUnavailableError();
32891
33183
  const routeAnchor = launch.chat?.members?.find((member) => member.chatPK !== chatPK)?.chatPK || chatPK;
@@ -32904,8 +33196,8 @@ function createChatSessionPending({
32904
33196
  };
32905
33197
  const sendPendingAttachment = (launchId, attachment, options = {}) => {
32906
33198
  const { chatPK } = getIdentity();
32907
- const launch = pendingLaunch;
32908
- const previousOperation = pendingOperations.get(launchId);
33199
+ const launch = launchForChat(launchId);
33200
+ const previousOperation = pendingOperations.get(launchId)?.promise;
32909
33201
  if (!launch || launch.id !== launchId)
32910
33202
  throw makeChatUnavailableError();
32911
33203
  const routeAnchor = launch.chat?.members?.find((member) => member.chatPK !== chatPK)?.chatPK || chatPK;
@@ -32920,8 +33212,8 @@ function createChatSessionPending({
32920
33212
  };
32921
33213
  const sendPendingSharedAttachment = (launchId, attachment, options = {}) => {
32922
33214
  const { chatPK } = getIdentity();
32923
- const launch = pendingLaunch;
32924
- const previousOperation = pendingOperations.get(launchId);
33215
+ const launch = launchForChat(launchId);
33216
+ const previousOperation = pendingOperations.get(launchId)?.promise;
32925
33217
  if (!launch || launch.id !== launchId)
32926
33218
  throw makeChatUnavailableError();
32927
33219
  const routeAnchor = launch.chat?.members?.find((member) => member.chatPK !== chatPK)?.chatPK || chatPK;
@@ -32934,6 +33226,12 @@ function createChatSessionPending({
32934
33226
  return track(launchId, previousOperation.then((result) => sendDurableSharedAttachment(result?.chatId || launchId, queuedAttachment, options)));
32935
33227
  };
32936
33228
  const sendChatMessage = (chatId, message, options = {}) => {
33229
+ const operation = operationForChat(chatId);
33230
+ if (operation?.discarding)
33231
+ throw makeChatUnavailableError();
33232
+ if (operation)
33233
+ return sendPendingMessage(operation.launch.id, message, options);
33234
+ chatId = resolvePendingChatId(chatId);
32937
33235
  if (!getOwnerChat(chatId)) {
32938
33236
  if (!pendingLaunch)
32939
33237
  pendingLaunch = storedLaunch(chatId);
@@ -32944,9 +33242,10 @@ function createChatSessionPending({
32944
33242
  return sendDurableMessage(chatId, message, options);
32945
33243
  };
32946
33244
  const retryMessage = (chatId, cid) => {
33245
+ chatId = resolvePendingChatId(chatId);
32947
33246
  const attemptGeneration = generation;
32948
33247
  const launch = pendingLaunch && (pendingLaunch.id === chatId || pendingLaunch.canonicalChatId === chatId) ? pendingLaunch : storedLaunch(chatId);
32949
- const failed = getLocalByChat().get(launch?.id || chatId)?.find((message) => message.cid === cid && message.failed);
33248
+ const failed = getLocalByChat().get(chatId)?.find((message) => message.cid === cid && message.failed);
32950
33249
  if (!failed)
32951
33250
  return false;
32952
33251
  if (launch && !getOwnerChat(chatId)) {
@@ -32983,8 +33282,24 @@ function createChatSessionPending({
32983
33282
  getSendActions().discardLocalMessage(chatId, cid);
32984
33283
  return true;
32985
33284
  };
32986
- const sendChatAttachment = (chatId, attachment, options = {}) => pendingLaunch?.id === chatId && !getOwnerChat(chatId) ? sendPendingAttachment(chatId, attachment, options) : sendDurableAttachment(chatId, attachment, options);
32987
- const sendChatSharedAttachment = (chatId, attachment, options = {}) => pendingLaunch?.id === chatId && !getOwnerChat(chatId) ? sendPendingSharedAttachment(chatId, attachment, options) : sendDurableSharedAttachment(chatId, attachment, options);
33285
+ const sendChatAttachment = (chatId, attachment, options = {}) => {
33286
+ const operation = operationForChat(chatId);
33287
+ if (operation?.discarding)
33288
+ throw makeChatUnavailableError();
33289
+ if (operation)
33290
+ return sendPendingAttachment(operation.launch.id, attachment, options);
33291
+ chatId = resolvePendingChatId(chatId);
33292
+ return pendingLaunch?.id === chatId && !getOwnerChat(chatId) ? sendPendingAttachment(chatId, attachment, options) : sendDurableAttachment(chatId, attachment, options);
33293
+ };
33294
+ const sendChatSharedAttachment = (chatId, attachment, options = {}) => {
33295
+ const operation = operationForChat(chatId);
33296
+ if (operation?.discarding)
33297
+ throw makeChatUnavailableError();
33298
+ if (operation)
33299
+ return sendPendingSharedAttachment(operation.launch.id, attachment, options);
33300
+ chatId = resolvePendingChatId(chatId);
33301
+ return pendingLaunch?.id === chatId && !getOwnerChat(chatId) ? sendPendingSharedAttachment(chatId, attachment, options) : sendDurableSharedAttachment(chatId, attachment, options);
33302
+ };
32988
33303
  const sendDirectAttachment = async (profile, attachment, options = {}) => sendChatAttachment(await getRouteOwner().openDirectChat(profile), attachment, options);
32989
33304
  const sendMaterializedDirect = async (profile, payload, options, send) => {
32990
33305
  const queuedPayload = { ...payload, cid: makeSendCid(payload) };
@@ -33031,6 +33346,10 @@ function createChatSessionPending({
33031
33346
  return settleNormalizedTargets(normalizedTargets, (target) => sendPickerTarget(target, (chatId) => sendChatSharedAttachment(chatId, attachment), (profile) => sendPickerDirectSharedAttachment(profile, attachment)));
33032
33347
  };
33033
33348
  return {
33349
+ directAdmissionForPeer: admission.directAdmissionForPeer,
33350
+ dropChat,
33351
+ discardChat,
33352
+ canStartDirectChat: admission.canStartDirectChat,
33034
33353
  adoptOpenedChatId,
33035
33354
  adoptResolved,
33036
33355
  beginPendingChat,
@@ -33038,8 +33357,11 @@ function createChatSessionPending({
33038
33357
  canSendToChat,
33039
33358
  isChatAdmitted,
33040
33359
  isPendingLaunchAdmitted,
33041
- isPendingChat: (chatId) => pendingLaunch?.id === chatId || !!storedLaunch(chatId),
33360
+ isPendingChat: (chatId) => !!launchForChat(chatId),
33042
33361
  getPendingLaunch,
33362
+ getActionChat: (chatId) => getOwnerChat(resolvePendingChatId(chatId)) || launchForChat(chatId)?.chat || null,
33363
+ hasPendingChatOperation: (chatId) => !!operationForChat(chatId),
33364
+ runChatMutation,
33043
33365
  openNewChat,
33044
33366
  retirePeer,
33045
33367
  reconcileAdmission: () => {
@@ -33049,7 +33371,7 @@ function createChatSessionPending({
33049
33371
  beginSelection();
33050
33372
  getRouteOwner().clearOpenOperations?.();
33051
33373
  pendingLaunch = null;
33052
- pendingOperations.delete(launch.id);
33374
+ cancelOperation(launch.id);
33053
33375
  if (getSelectedChatId() === launch.id || getSelectedChatId() === launch.canonicalChatId) {
33054
33376
  setSelectedChat(null);
33055
33377
  } else {
@@ -33059,10 +33381,13 @@ function createChatSessionPending({
33059
33381
  },
33060
33382
  reset: () => {
33061
33383
  generation += 1;
33384
+ admission.reset();
33062
33385
  beginSelection();
33063
33386
  if (pendingLaunch?.id)
33064
33387
  getRouteOwner().releaseOpenOperation?.(pendingLaunch.id);
33065
33388
  pendingLaunch = null;
33389
+ for (const operation of pendingOperations.values())
33390
+ operation.active = false;
33066
33391
  pendingOperations.clear();
33067
33392
  },
33068
33393
  selectChat: (chatId, { flushPrevious }) => {
@@ -33075,9 +33400,14 @@ function createChatSessionPending({
33075
33400
  const selectResolved = () => {
33076
33401
  if (!isSelectionCurrent(selection) || getIdentity().chatBanned)
33077
33402
  return false;
33078
- if (pendingLaunch && chatId !== pendingLaunch.id && !pendingOperations.has(pendingLaunch.id)) {
33403
+ if (pendingLaunch && chatId !== pendingLaunch.id) {
33404
+ if (chatId === pendingLaunch.canonicalChatId) {
33405
+ settleMaterialization(pendingLaunch.id, chatId);
33406
+ }
33079
33407
  getRouteOwner().releaseOpenOperation?.(pendingLaunch.id);
33080
33408
  pendingLaunch = null;
33409
+ if (getSelectedChatId() === chatId)
33410
+ publish();
33081
33411
  }
33082
33412
  const previousChatId = getSelectedChatId();
33083
33413
  if (previousChatId && previousChatId !== chatId)
@@ -33132,6 +33462,7 @@ var init_sessionpending = __esm(() => {
33132
33462
  init_messages();
33133
33463
  init_state();
33134
33464
  init_targets();
33465
+ init_capabilities();
33135
33466
  });
33136
33467
 
33137
33468
  // ../../core/chat/sessionmembership.js
@@ -33626,7 +33957,6 @@ function createChatDelete({
33626
33957
  for (const chatId of chatIds || []) {
33627
33958
  if (!chatId)
33628
33959
  continue;
33629
- dropCachedChat(localCache, chatId);
33630
33960
  closeMessageBatchRef.current?.(chatId);
33631
33961
  if (localForRender.has(chatId)) {
33632
33962
  if (!localChanged)
@@ -33658,6 +33988,7 @@ function createChatDelete({
33658
33988
  keepSelectedDeletedChatIdsRef.current.delete(chatId);
33659
33989
  }
33660
33990
  }
33991
+ dropCachedChats(localCache, ids);
33661
33992
  clearDeletedChatState(ids);
33662
33993
  renderVisibleChats();
33663
33994
  setSelectedChat((current) => current && ids.includes(current) && !options?.keepSelected ? null : current);
@@ -33715,9 +34046,7 @@ function createChatDelete({
33715
34046
  const dropChat = (chatId) => {
33716
34047
  if (!chatId)
33717
34048
  return;
33718
- clearDeletedChatState([chatId]);
33719
34049
  listActionsRef.current?.removeOwner?.(chatId, { warm: false });
33720
- setSelectedChat((current) => current === chatId ? null : current);
33721
34050
  };
33722
34051
  const dropLeftChat = (chatId) => {
33723
34052
  if (!chatId)
@@ -35138,8 +35467,6 @@ async function setOwnChatNotificationMode(cloud, identity, entryId, entry, value
35138
35467
  if (!current?.current || current.retirement)
35139
35468
  throw makeChatUnavailableError();
35140
35469
  const manifest = current.current.manifest;
35141
- if (manifest.lineage !== "group")
35142
- throw new Error("group chat required");
35143
35470
  const requestedMode = cleanText(value);
35144
35471
  const notificationMode = normalizeChatNotificationMode(requestedMode, manifest);
35145
35472
  if (notificationMode !== requestedMode) {
@@ -35199,20 +35526,20 @@ function createChatSessionNotifications({
35199
35526
  throw makeChatUnavailableError();
35200
35527
  }
35201
35528
  };
35202
- const requireOwnerChat = (chatId, operation, { group = false } = {}) => {
35529
+ const requireOwnerChat = (chatId, operation) => {
35203
35530
  assertCurrent(operation);
35204
35531
  const chat = getOwnerChat(chatId);
35205
- if (operation.identity.chatBanned || canWriteChat(chatId) !== true || group && chat?.lineage !== "group" || !chat.ownEntry || chat.ownEntry.retirement || !chat.entryId) {
35532
+ if (operation.identity.chatBanned || canWriteChat(chatId) !== true || !chat?.ownEntry || chat.ownEntry.retirement || !chat.entryId) {
35206
35533
  throw makeChatUnavailableError();
35207
35534
  }
35208
35535
  return chat;
35209
35536
  };
35210
35537
  const setChatNotificationMode = async (chatId, mode) => {
35211
35538
  const operation = operationContext();
35212
- requireOwnerChat(chatId, operation, { group: true });
35539
+ requireOwnerChat(chatId, operation);
35213
35540
  const releaseMutation = await operation.mutationGate.acquireExclusive(chatId);
35214
35541
  try {
35215
- const chat = requireOwnerChat(chatId, operation, { group: true });
35542
+ const chat = requireOwnerChat(chatId, operation);
35216
35543
  const committed = await writeMode(cloud, operation.identity, chat.entryId, chat.ownEntry, mode);
35217
35544
  assertCurrent(operation);
35218
35545
  const projected = projectOwnChatEntry(committed, chat.entryId, operation.identity.chatPK, chat.ts);
@@ -35605,7 +35932,7 @@ function createChatSession({
35605
35932
  const owner = getOwnerChat(chatId);
35606
35933
  if (owner)
35607
35934
  return !isChatMembershipRemoved(owner);
35608
- return pendingOwner?.getPendingLaunch()?.id === chatId;
35935
+ return pendingOwner?.isPendingChat(chatId) === true;
35609
35936
  };
35610
35937
  const requireOnline = () => {
35611
35938
  if (!online)
@@ -35620,10 +35947,6 @@ function createChatSession({
35620
35947
  if (chatId && !isMutableChat(chatId))
35621
35948
  throw makeChatUnavailableError();
35622
35949
  };
35623
- const gateChatMutation = (fn) => (chatId, ...rest) => {
35624
- requireMutableChat(chatId);
35625
- return fn(chatId, ...rest);
35626
- };
35627
35950
  const gateAdmittedChatMutation = (fn) => (chatId, ...rest) => {
35628
35951
  requireMutableChat(chatId);
35629
35952
  return Promise.resolve(pendingOwner.assertChatAdmission(chatId)).then(() => fn(chatId, ...rest));
@@ -35825,7 +36148,8 @@ function createChatSession({
35825
36148
  getPeerProfile,
35826
36149
  resolvePeerProfile,
35827
36150
  setLocalByChat,
35828
- getLocalByChat: () => localByChatRef.current
36151
+ getLocalByChat: () => localByChatRef.current,
36152
+ retireMaterializedChat: (chatId) => actionOwner.deleteActions.beginRetirement(chatId)
35829
36153
  });
35830
36154
  launchOwner = createChatSessionLaunches({
35831
36155
  cloud,
@@ -35865,29 +36189,79 @@ function createChatSession({
35865
36189
  const openDirectChat = (...args) => launchOwner.openDirectChat(...args);
35866
36190
  const openNotesChat = (...args) => launchOwner.openNotesChat(...args);
35867
36191
  const openNewChat = (...args) => pendingOwner.openNewChat(...args);
35868
- const directAdmissionForPeer2 = (profile) => directAdmissionForPeer(chatPrivateKey, chatPK, profile, chatAdmission);
35869
- const canStartDirectChat2 = (profile) => canStartDirectChat(chatPrivateKey, chatPK, profile, chatAdmission);
36192
+ const { directAdmissionForPeer: directAdmissionForPeer2, canStartDirectChat } = pendingOwner;
35870
36193
  const canInviteToGroup2 = (profile) => canInviteToGroup(profile, chatAdmission);
35871
36194
  const createGroupChat2 = (...args) => launchOwner.createGroupChat(...args);
35872
36195
  const selectLocalChat = (...args) => launchOwner.selectLocalChat(...args);
35873
- const addChatMembers = async (chatId, profiles2) => {
36196
+ const mutateMaterializedChat = (chatId, mutate, options) => {
35874
36197
  requireMutableChat(chatId);
35875
- await pendingOwner.assertChatAdmission(chatId);
35876
- return membershipOwner.addChatMembers(chatId, profiles2);
36198
+ return pendingOwner.runChatMutation(chatId, async (id, context) => {
36199
+ await pendingOwner.assertChatAdmission(id);
36200
+ return mutate(id, context);
36201
+ }, options);
35877
36202
  };
35878
- const kickChatMember = async (chatId, memberChatPK) => {
35879
- requireMutableChat(chatId);
35880
- await pendingOwner.assertChatAdmission(chatId);
35881
- return membershipOwner.kickChatMember(chatId, memberChatPK);
36203
+ const addChatMembers = (chatId, profiles2) => {
36204
+ const additions = Array.isArray(profiles2) ? profiles2 : [profiles2];
36205
+ additions.forEach(membershipOwner.profileMember);
36206
+ return mutateMaterializedChat(chatId, (id, context) => context.created ? { entry: getOwnerChat(id).ownEntry } : membershipOwner.addChatMembers(id, additions), {
36207
+ initialProfiles: (current) => {
36208
+ const next = new Map(current.map((profile) => [profile.chatPK, profile]));
36209
+ for (const profile of additions)
36210
+ next.set(profile.chatPK, profile);
36211
+ return next.size === current.length ? current : [...next.values()];
36212
+ }
36213
+ });
36214
+ };
36215
+ const kickChatMember = (chatId, memberChatPK) => {
36216
+ const target = cleanText(memberChatPK);
36217
+ if (!target)
36218
+ throw new Error("chat member required");
36219
+ if (target === chatPK && pendingOwner.isPendingChat(chatId)) {
36220
+ return deleteChat(chatId);
36221
+ }
36222
+ return mutateMaterializedChat(chatId, (id, context) => context.created ? { entry: getOwnerChat(id).ownEntry } : membershipOwner.kickChatMember(id, target), {
36223
+ initialProfiles: (current) => current.some((profile) => profile.chatPK === target) ? current.filter((profile) => profile.chatPK !== target) : current
36224
+ });
35882
36225
  };
35883
36226
  const leaveChat = (chatId) => {
36227
+ if (pendingOwner.isPendingChat(chatId)) {
36228
+ return deleteChat(chatId);
36229
+ }
35884
36230
  requireMutableChat(chatId);
35885
36231
  return membershipOwner.leaveChat(chatId);
35886
36232
  };
35887
36233
  const leaveOwnedChat = (...args) => membershipOwner.leaveOwnedChat(...args);
35888
- const updateChatSettings2 = gateAdmittedChatMutation((...args) => settingsOwner.updateChatSettings(...args));
35889
- const updateChatAvatar = gateAdmittedChatMutation((...args) => settingsOwner.updateChatAvatar(...args));
35890
- const setChatNotificationMode = gateAdmittedChatMutation((...args) => notificationsOwner.setChatNotificationMode(...args));
36234
+ const sharedSettingsChat = (chatId) => {
36235
+ const chat = pendingOwner.getActionChat(chatId);
36236
+ if (chat?.lineage === "self")
36237
+ throw new Error("self chat identity follows your profile");
36238
+ return chat;
36239
+ };
36240
+ const updateChatSettings2 = async (chatId, settings) => {
36241
+ const chat = sharedSettingsChat(chatId);
36242
+ const requested = normalizeChatSettingsInput({ ...chat?.settings, ...settings });
36243
+ const changes = ["title", "avatarRef", "retention"].filter((key) => Object.prototype.hasOwnProperty.call(settings, key));
36244
+ const patch = Object.fromEntries(changes.map((key) => [key, requested[key]]));
36245
+ if (chat && !pendingOwner.hasPendingChatOperation(chatId) && changes.every((key) => chat.settings?.[key] === requested[key])) {
36246
+ return Promise.resolve({ unchanged: true });
36247
+ }
36248
+ return mutateMaterializedChat(chatId, (id) => settingsOwner.updateChatSettings(id, patch));
36249
+ };
36250
+ const updateChatAvatar = async (chatId, data) => {
36251
+ assertChatAvatarBytes(data);
36252
+ const chat = sharedSettingsChat(chatId);
36253
+ if (chat?.lineage !== "group")
36254
+ throw new Error("group chat required");
36255
+ return mutateMaterializedChat(chatId, (id) => settingsOwner.updateChatAvatar(id, data));
36256
+ };
36257
+ const setChatNotificationMode = async (chatId, mode) => {
36258
+ const chat = pendingOwner.getActionChat(chatId);
36259
+ if (chat && normalizeChatNotificationMode(mode, chat) !== mode)
36260
+ throw new Error("all notifications are unavailable in large groups");
36261
+ if (chat && !pendingOwner.hasPendingChatOperation(chatId) && (chat.notificationMode || defaultChatNotificationMode(chat)) === mode)
36262
+ return mode;
36263
+ return mutateMaterializedChat(chatId, (id) => notificationsOwner.setChatNotificationMode(id, mode));
36264
+ };
35891
36265
  const updateMessage = async (chatId, original, changes) => {
35892
36266
  if (chatBanned)
35893
36267
  throw makeChatUnavailableError();
@@ -36041,7 +36415,27 @@ function createChatSession({
36041
36415
  };
36042
36416
  const dropChat = (...args) => actionOwner.deleteActions.dropChat(...args);
36043
36417
  const dropUnavailableChat = (...args) => actionOwner.deleteActions.dropUnavailableChat(...args);
36044
- const deleteChat = gateOnlineMutation((...args) => actionOwner.deleteActions.deleteChat(...args));
36418
+ const deleteChat = async (value, options) => {
36419
+ const inputs = Array.isArray(value) ? value : [value];
36420
+ const durable = [];
36421
+ let discarded = 0;
36422
+ for (const input of inputs) {
36423
+ const id = cleanText(typeof input === "string" ? input : input?.chatId || input?.id);
36424
+ if (pendingOwner.hasPendingChatOperation(id) || !getOwnerChat(id) && pendingOwner.isPendingChat(id)) {
36425
+ const result = await pendingOwner.discardChat(id);
36426
+ if (result.chat)
36427
+ durable.push(result.chat);
36428
+ else if (result.discarded)
36429
+ discarded += 1;
36430
+ } else
36431
+ durable.push(input);
36432
+ }
36433
+ if (!durable.length)
36434
+ return Array.isArray(value) ? discarded : discarded > 0;
36435
+ requireOnline();
36436
+ const deleted = await actionOwner.deleteActions.deleteChat(Array.isArray(value) ? durable : durable[0], options);
36437
+ return Array.isArray(value) ? discarded + Number(deleted) : deleted;
36438
+ };
36045
36439
  const purgePeerChats = async (affected, operation) => {
36046
36440
  const identity = operation.identity;
36047
36441
  for (const chat of affected) {
@@ -36146,14 +36540,14 @@ function createChatSession({
36146
36540
  const sendPendingChatMessage = (...args) => pendingOwner.sendPendingChatMessage(...args);
36147
36541
  const sendChatMessage = sendMessage;
36148
36542
  const sendDirectAttachment = gateOnlineMutation((...args) => pendingOwner.sendDirectAttachment(...args));
36149
- const sendChatAttachment = gateChatMutation((...args) => pendingOwner.sendChatAttachment(...args));
36543
+ const sendChatAttachment = gateOnlineMutation((...args) => pendingOwner.sendChatAttachment(...args));
36150
36544
  const retryMessage = async (...args) => {
36151
36545
  const result = await pendingOwner.retryMessage(...args);
36152
36546
  if (online)
36153
36547
  drainMembershipOutbox();
36154
36548
  return result;
36155
36549
  };
36156
- const sendAttachment = gateChatMutation((...args) => pendingOwner.sendChatAttachment(...args));
36550
+ const sendAttachment = gateOnlineMutation((...args) => pendingOwner.sendChatAttachment(...args));
36157
36551
  const sendChatImage = (chatId, image, options = {}) => sendChatAttachment(chatId, { ...image, type: image?.type || "img" }, options);
36158
36552
  const sendAttachmentMany = gateOnlineMutation((...args) => pendingOwner.sendAttachmentMany(...args));
36159
36553
  const sendImageMany = (targets, image, options = {}) => sendAttachmentMany(targets, { ...image, type: image?.type || "img" }, options);
@@ -36211,7 +36605,11 @@ function createChatSession({
36211
36605
  });
36212
36606
  return state;
36213
36607
  };
36214
- const setChatTtl = gateAdmittedChatMutation((...args) => settingsOwner.setChatTtl(...args));
36608
+ const setChatTtl = async (chatId, retention) => {
36609
+ const next = cleanChatRetention(retention);
36610
+ await updateChatSettings2(chatId, { retention: next });
36611
+ return next;
36612
+ };
36215
36613
  const makeMessagePermanent = gateAdmittedChatMutation((...args) => actionOwner.saveActions.makeMessagePermanent(...args));
36216
36614
  const makeMessageTemporary = gateAdmittedChatMutation((...args) => actionOwner.saveActions.makeMessageTemporary(...args));
36217
36615
  const readMessageFile = (...args) => actionOwner.saveActions.readMessageFile(...args);
@@ -36314,6 +36712,17 @@ function createChatSession({
36314
36712
  chatsRef,
36315
36713
  reconcileMessageBatches: (...args) => messageBatchOwner.reconcileChats(...args),
36316
36714
  warmChats: (...args) => messageBatchOwner.warm(...args),
36715
+ onOwnerRemoved: (chatIds) => {
36716
+ for (const chatId of chatIds)
36717
+ pendingOwner.dropChat(chatId);
36718
+ actionOwner.deleteActions.clearDeletedChatState(chatIds);
36719
+ for (const chatId of chatIds) {
36720
+ actionOwner.liveActions.closeChatActivity(chatId);
36721
+ historyOwner.clear(chatId);
36722
+ messageBatchOwner.routeMemory.dropChat(chatId);
36723
+ routeMemoryScopes.delete(chatId);
36724
+ }
36725
+ },
36317
36726
  onTransition: stageCommittedMembershipMessage,
36318
36727
  onRemoved: (removedChatId, _epochVersion, retiredEntry) => {
36319
36728
  const applied = chatListOwner.applyMembershipRemoval(removedChatId, retiredEntry);
@@ -36370,7 +36779,7 @@ function createChatSession({
36370
36779
  openNotesChat,
36371
36780
  openNewChat,
36372
36781
  directAdmissionForPeer: directAdmissionForPeer2,
36373
- canStartDirectChat: canStartDirectChat2,
36782
+ canStartDirectChat,
36374
36783
  canInviteToGroup: canInviteToGroup2,
36375
36784
  createGroupChat: createGroupChat2,
36376
36785
  addChatMembers,
@@ -36664,6 +37073,10 @@ var init_session3 = __esm(() => {
36664
37073
  init_sessionsources();
36665
37074
  init_entry();
36666
37075
  init_admission();
37076
+ init_avatar2();
37077
+ init_settings2();
37078
+ init_ttl();
37079
+ init_notifications();
36667
37080
  init_write();
36668
37081
  DEFAULT_READ_WRITE_INTERVAL_MS = CHAT_READ_WRITE_INTERVAL_MS;
36669
37082
  EMPTY_LOCAL_MESSAGES = Object.freeze([]);
@@ -36846,7 +37259,7 @@ function createPresence({ cloud, diag = null, now = Date.now } = {}) {
36846
37259
  let expiryTimer = null;
36847
37260
  let command = null;
36848
37261
  let authenticating = null;
36849
- let snapshot = Object.freeze({ visibility: null, ready: false, pending: false, error: null, ...UNKNOWN_PRESENCE });
37262
+ let snapshot = Object.freeze({ visibility: null, ready: false, pending: false, pendingVisibility: null, error: null, ...UNKNOWN_PRESENCE });
36850
37263
  function topic() {
36851
37264
  return sources.uid ? derivePresenceTopic(realm2, sources.uid) : null;
36852
37265
  }
@@ -36854,7 +37267,13 @@ function createPresence({ cloud, diag = null, now = Date.now } = {}) {
36854
37267
  return Boolean(channel && challenge && policy && sources.enabled && !closed);
36855
37268
  }
36856
37269
  function publish(patch = {}) {
36857
- const next = { ...snapshot, ...patch, ready: isReady() };
37270
+ const next = {
37271
+ ...snapshot,
37272
+ ...patch,
37273
+ ready: isReady(),
37274
+ pending: Boolean(command),
37275
+ pendingVisibility: command?.policy.visibility ?? null
37276
+ };
36858
37277
  if (Object.keys(next).every((key) => Object.is(next[key], snapshot[key])))
36859
37278
  return;
36860
37279
  snapshot = Object.freeze(next);
@@ -36910,7 +37329,7 @@ function createPresence({ cloud, diag = null, now = Date.now } = {}) {
36910
37329
  const pending = command;
36911
37330
  command = null;
36912
37331
  clearTimeout(pending.timer);
36913
- publish({ pending: false, error });
37332
+ publish({ error });
36914
37333
  if (error)
36915
37334
  pending.reject(error);
36916
37335
  else
@@ -37150,12 +37569,14 @@ function createPresence({ cloud, diag = null, now = Date.now } = {}) {
37150
37569
  listener();
37151
37570
  }
37152
37571
  function update(next) {
37153
- const identityChanged = sources.uid !== next.uid || sources.identity?.publicKey !== next.identity?.publicKey;
37572
+ const accountChanged = sources.uid !== next.uid;
37573
+ const identityChanged = accountChanged || sources.identity?.publicKey !== next.identity?.publicKey;
37154
37574
  if (identityChanged) {
37155
37575
  stop();
37156
37576
  policy = null;
37157
37577
  records.clear();
37158
- peers.clear();
37578
+ if (accountChanged)
37579
+ peers.clear();
37159
37580
  publish({ visibility: null, error: null, ...UNKNOWN_PRESENCE });
37160
37581
  }
37161
37582
  sources = next;
@@ -37185,7 +37606,7 @@ function createPresence({ cloud, diag = null, now = Date.now } = {}) {
37185
37606
  reject,
37186
37607
  timer: setTimeout(() => finishCommand(new Error("could not confirm activity setting; reconnect to check")), COMMAND_TIMEOUT_MS)
37187
37608
  };
37188
- publish({ pending: true, error: null });
37609
+ publish({ error: null });
37189
37610
  if (!channel.send(presenceShard(topic()), { type: "policy", expectedRevision: policy.revision, policy: nextPolicy })) {
37190
37611
  finishCommand(new Error("could not update activity while offline"));
37191
37612
  }
@@ -40971,6 +41392,7 @@ function createPeerList({ peerApi, presence, diag, onMissingPeers }) {
40971
41392
  let profilesLoading = false;
40972
41393
  let hydratedCacheKey = "";
40973
41394
  let avatarHydrateKey = "";
41395
+ let avatarPublishSession = null;
40974
41396
  let profilesReady = false;
40975
41397
  let blockedPeersReady = false;
40976
41398
  let discoveredPeerUids = new Set;
@@ -41381,12 +41803,21 @@ function createPeerList({ peerApi, presence, diag, onMissingPeers }) {
41381
41803
  const session = lifecycle;
41382
41804
  const startedAt = Date.now();
41383
41805
  const requested = walletPKs.length + chatPeerPKs.length;
41384
- hydrateCachedAvatars(walletPKs, chatPeerPKs).then((changed) => {
41806
+ hydrateCachedAvatars(walletPKs, chatPeerPKs, () => {
41807
+ if (!isCurrent(session) || avatarPublishSession === session)
41808
+ return;
41809
+ avatarPublishSession = session;
41810
+ queueMicrotask(() => {
41811
+ if (avatarPublishSession !== session)
41812
+ return;
41813
+ avatarPublishSession = null;
41814
+ if (isCurrent(session))
41815
+ rebuild({ base: true, persist: false });
41816
+ });
41817
+ }).then((changed) => {
41385
41818
  if (!isCurrent(session))
41386
41819
  return;
41387
41820
  markDiag(diag, "peers.avatars.hydrate", { requested, changed, elapsedMs: Date.now() - startedAt });
41388
- if (changed)
41389
- rebuild({ base: true });
41390
41821
  }).catch((error) => {
41391
41822
  if (!isCurrent(session))
41392
41823
  return;
@@ -41990,7 +42421,7 @@ function createPeersApi({ cloud, network, avatarCache = null }) {
41990
42421
  function uniqueLookupKeys(keys) {
41991
42422
  return uniqueValues(keys);
41992
42423
  }
41993
- async function hydrateCachedAvatars(walletPKs, chatPKs) {
42424
+ async function hydrateCachedAvatars(walletPKs, chatPKs, onHydrated) {
41994
42425
  if (typeof avatarCache?.read !== "function")
41995
42426
  return false;
41996
42427
  const profiles2 = new Map;
@@ -42009,21 +42440,18 @@ function createPeersApi({ cloud, network, avatarCache = null }) {
42009
42440
  queue(key, "chat");
42010
42441
  if (!profiles2.size)
42011
42442
  return false;
42012
- const cached = await Promise.all(Array.from(profiles2.values()).map(async ({ uid, version }) => ({
42013
- avatar: await readCachedAvatar(uid, version),
42014
- uid,
42015
- version
42016
- })));
42017
42443
  let changed = false;
42018
- for (const entry of cached) {
42019
- if (!entry.avatar)
42020
- continue;
42021
- const current = profileCache.get(entry.uid);
42022
- if (!current || current.avatarVersion !== entry.version || current.avatar === entry.avatar)
42023
- continue;
42024
- storeProfile({ ...current, avatar: entry.avatar });
42444
+ await Promise.all(Array.from(profiles2.values()).map(async ({ uid, version }) => {
42445
+ const avatar = await readCachedAvatar(uid, version);
42446
+ if (!avatar)
42447
+ return;
42448
+ const current = profileCache.get(uid);
42449
+ if (!current || current.avatarVersion !== version || current.avatar === avatar)
42450
+ return;
42451
+ storeProfile({ ...current, avatar });
42025
42452
  changed = true;
42026
- }
42453
+ onHydrated?.();
42454
+ }));
42027
42455
  return changed;
42028
42456
  }
42029
42457
  function needsAvatarResolve(profile) {
@@ -44693,6 +45121,7 @@ function createPayment({
44693
45121
  throw new Error("bitcoin payment must be reviewed before sending");
44694
45122
  }
44695
45123
  const payment = paymentInput?.state === PAYMENT_STATE_PREPARED ? normalizePreparedPayment(paymentInput, wallet, network) : await preparePayment(paymentInput);
45124
+ assertReady();
44696
45125
  const startedAt = Date.now();
44697
45126
  const diagKind = payment.kind;
44698
45127
  markDiag(diag, "wallet.payment.start", { kind: diagKind });
@@ -53577,20 +54006,7 @@ function sameMessageList(a, b) {
53577
54006
  for (let i = 0;i < a.length; i += 1) {
53578
54007
  const left = a[i];
53579
54008
  const right = b[i];
53580
- if (getMessageKey(left) !== getMessageKey(right) || getMessageOrderMs(left) !== getMessageOrderMs(right) || hasMessageTtl(left) !== hasMessageTtl(right) || timestampKey(left?.ttl ?? null) !== timestampKey(right?.ttl ?? null) || !sameMessageReactions(left, right)) {
53581
- return false;
53582
- }
53583
- }
53584
- return true;
53585
- }
53586
- function sameMessageReactions(a, b) {
53587
- const left = getMsgReactions(a);
53588
- const right = getMsgReactions(b);
53589
- if (left.length !== right.length) {
53590
- return false;
53591
- }
53592
- for (let index2 = 0;index2 < left.length; index2 += 1) {
53593
- if (left[index2].user !== right[index2]?.user || left[index2].emoji !== right[index2]?.emoji) {
54009
+ if (getMessageKey(left) !== getMessageKey(right) || getMessageOrderMs(left) !== getMessageOrderMs(right) || hasMessageTtl(left) !== hasMessageTtl(right) || timestampKey(left?.ttl ?? null) !== timestampKey(right?.ttl ?? null) || !sameReactions(left?.reactions, right?.reactions)) {
53594
54010
  return false;
53595
54011
  }
53596
54012
  }
@@ -54009,7 +54425,7 @@ function cacheMessageSignature(message) {
54009
54425
  if (!message)
54010
54426
  return "";
54011
54427
  const hasTtl = hasMessageTtl(message);
54012
- const reactions = getMsgReactions(message).map((reaction) => `${reaction.user}:${reaction.emoji}`).join(",");
54428
+ const reactions = getMsgReactions(message).map((reaction) => `${reaction.user}:${reaction.emoji}:${reaction.ts ?? ""}`).join(",");
54013
54429
  return [
54014
54430
  cacheKeySignature(messageKeys(message)),
54015
54431
  getMessageOrderMs(message) || 0,
@@ -60625,7 +61041,7 @@ var package_default;
60625
61041
  var init_package2 = __esm(() => {
60626
61042
  package_default = {
60627
61043
  name: "veyl",
60628
- version: "0.70.0",
61044
+ version: "0.71.0",
60629
61045
  packageManager: "bun@1.4.0",
60630
61046
  private: true,
60631
61047
  license: "UNLICENSED",
@@ -79010,7 +79426,7 @@ function ensureBytes(title, hex3, expectedLength) {
79010
79426
  throw new Error(title + " of length " + expectedLength + " expected, got " + len);
79011
79427
  return res;
79012
79428
  }
79013
- function equalBytes2(a, b) {
79429
+ function equalBytes3(a, b) {
79014
79430
  if (a.length !== b.length)
79015
79431
  return false;
79016
79432
  let diff = 0;
@@ -109821,7 +110237,7 @@ var init_legacy = __esm(() => {
109821
110237
  });
109822
110238
 
109823
110239
  // ../../node_modules/.bun/micro-packed@0.7.3/node_modules/micro-packed/lib/esm/index.js
109824
- function equalBytes3(a, b) {
110240
+ function equalBytes4(a, b) {
109825
110241
  if (a.length !== b.length)
109826
110242
  return false;
109827
110243
  for (let i = 0;i < a.length; i++)
@@ -109996,7 +110412,7 @@ class _Reader {
109996
110412
  const leftBytes = this.data.length - idx;
109997
110413
  if (leftBytes < needle.length)
109998
110414
  return;
109999
- if (equalBytes3(needle, this.data.subarray(idx, idx + needle.length)))
110415
+ if (equalBytes4(needle, this.data.subarray(idx, idx + needle.length)))
110000
110416
  return idx;
110001
110417
  }
110002
110418
  return;
@@ -110348,7 +110764,7 @@ function magic(inner, constant, check = true) {
110348
110764
  encodeStream: (w, _value) => inner.encodeStream(w, constant),
110349
110765
  decodeStream: (r) => {
110350
110766
  const value = inner.decodeStream(r);
110351
- if (check && typeof value !== "object" && value !== constant || isBytes6(constant) && !equalBytes3(constant, value)) {
110767
+ if (check && typeof value !== "object" && value !== constant || isBytes6(constant) && !equalBytes4(constant, value)) {
110352
110768
  throw r.err(`magic: invalid value: ${value} !== ${constant}`);
110353
110769
  }
110354
110770
  return;
@@ -110455,7 +110871,7 @@ function array(len, inner) {
110455
110871
  if (len.length > _w.pos - startPos)
110456
110872
  return;
110457
110873
  const data = _w.finish(false).subarray(startPos, _w.pos);
110458
- if (equalBytes3(data.subarray(0, len.length), len))
110874
+ if (equalBytes4(data.subarray(0, len.length), len))
110459
110875
  throw _w.err(`array: inner element encoding same as separator. elm=${elm} data=${data}`);
110460
110876
  }
110461
110877
  });
@@ -110475,7 +110891,7 @@ function array(len, inner) {
110475
110891
  }
110476
110892
  } else if (isBytes6(len)) {
110477
110893
  for (let i = 0;; i++) {
110478
- if (equalBytes3(r.bytes(len.length, true), len)) {
110894
+ if (equalBytes4(r.bytes(len.length, true), len)) {
110479
110895
  r.bytes(len.length);
110480
110896
  break;
110481
110897
  }
@@ -110688,7 +111104,7 @@ var EMPTY2, NULL, createView4 = (arr) => new DataView(arr.buffer, arr.byteOffset
110688
111104
  decodeStream: (r) => {
110689
111105
  let hasFlag = r.leftBytes >= flagValue.length;
110690
111106
  if (hasFlag) {
110691
- hasFlag = equalBytes3(r.bytes(flagValue.length, true), flagValue);
111107
+ hasFlag = equalBytes4(r.bytes(flagValue.length, true), flagValue);
110692
111108
  if (hasFlag)
110693
111109
  r.bytes(flagValue.length);
110694
111110
  }
@@ -110706,7 +111122,7 @@ var init_esm2 = __esm(() => {
110706
111122
  EMPTY2 = /* @__PURE__ */ new Uint8Array;
110707
111123
  NULL = /* @__PURE__ */ new Uint8Array([0]);
110708
111124
  utils2 = {
110709
- equalBytes: equalBytes3,
111125
+ equalBytes: equalBytes4,
110710
111126
  isBytes: isBytes6,
110711
111127
  isCoder,
110712
111128
  checkBounds,
@@ -110948,7 +111364,7 @@ function compareBytes(a, b) {
110948
111364
  return Math.sign(a[i] - b[i]);
110949
111365
  return Math.sign(a.length - b.length);
110950
111366
  }
110951
- var Point, CURVE_ORDER, isBytes7, concatBytes7, equalBytes4, hash160 = (msg) => ripemd160(sha2562(msg)), sha256x2 = (...msgs) => sha2562(sha2562(concatBytes7(...msgs))), randomPrivateKeyBytes, pubSchnorr, pubECDSA, hasLowR = (sig) => sig.r < CURVE_ORDER / 2n, signSchnorr, tagSchnorr, PubT, TAPROOT_UNSPENDABLE_KEY, NETWORK, TEST_NETWORK;
111367
+ var Point, CURVE_ORDER, isBytes7, concatBytes7, equalBytes5, hash160 = (msg) => ripemd160(sha2562(msg)), sha256x2 = (...msgs) => sha2562(sha2562(concatBytes7(...msgs))), randomPrivateKeyBytes, pubSchnorr, pubECDSA, hasLowR = (sig) => sig.r < CURVE_ORDER / 2n, signSchnorr, tagSchnorr, PubT, TAPROOT_UNSPENDABLE_KEY, NETWORK, TEST_NETWORK;
110952
111368
  var init_utils6 = __esm(() => {
110953
111369
  init_secp256k1();
110954
111370
  init_legacy();
@@ -110958,7 +111374,7 @@ var init_utils6 = __esm(() => {
110958
111374
  CURVE_ORDER = secp256k1.CURVE.n;
110959
111375
  isBytes7 = utils2.isBytes;
110960
111376
  concatBytes7 = utils2.concatBytes;
110961
- equalBytes4 = utils2.equalBytes;
111377
+ equalBytes5 = utils2.equalBytes;
110962
111378
  randomPrivateKeyBytes = schnorr.utils.randomPrivateKey;
110963
111379
  pubSchnorr = schnorr.getPublicKey;
110964
111380
  pubECDSA = secp256k1.getPublicKey;
@@ -111477,7 +111893,7 @@ function mergeKeyMap(psbtEnum, val, cur, allowedFields, allowUnknown) {
111477
111893
  } else if (typeof res[k] === "string") {
111478
111894
  res[k] = vC.decode(hex3.decode(res[k]));
111479
111895
  } else if (cannotChange && k in val && cur && cur[k] !== undefined) {
111480
- if (!equalBytes4(vC.encode(val[k]), vC.encode(cur[k])))
111896
+ if (!equalBytes5(vC.encode(val[k]), vC.encode(cur[k])))
111481
111897
  throw new Error(`Cannot change signed field=${k}`);
111482
111898
  }
111483
111899
  }
@@ -111676,7 +112092,7 @@ function isValidPubkey(pub, type) {
111676
112092
  }
111677
112093
  }
111678
112094
  function checkWSH(s, witnessScript) {
111679
- if (!equalBytes4(s.hash, sha2562(witnessScript)))
112095
+ if (!equalBytes5(s.hash, sha2562(witnessScript)))
111680
112096
  throw new Error("checkScript: wsh wrong witnessScript hash");
111681
112097
  const w = OutScript.decode(witnessScript);
111682
112098
  if (w.type === "tr" || w.type === "tr_ns" || w.type === "tr_ms")
@@ -111690,7 +112106,7 @@ function checkScript(script, redeemScript, witnessScript) {
111690
112106
  if (s.type === "tr_ns" || s.type === "tr_ms" || s.type === "ms" || s.type == "pk")
111691
112107
  throw new Error(`checkScript: non-wrapped ${s.type}`);
111692
112108
  if (s.type === "sh" && redeemScript) {
111693
- if (!equalBytes4(s.hash, hash160(redeemScript)))
112109
+ if (!equalBytes5(s.hash, hash160(redeemScript)))
111694
112110
  throw new Error("checkScript: sh wrong redeemScript hash");
111695
112111
  const r = OutScript.decode(redeemScript);
111696
112112
  if (r.type === "tr" || r.type === "tr_ns" || r.type === "tr_ms")
@@ -111727,9 +112143,9 @@ function checkTaprootScript(script, internalPubKey, allowUnknownOutputs = false,
111727
112143
  const outms = out;
111728
112144
  if (!allowUnknownOutputs && outms.pubkeys) {
111729
112145
  for (const p of outms.pubkeys) {
111730
- if (equalBytes4(p, TAPROOT_UNSPENDABLE_KEY))
112146
+ if (equalBytes5(p, TAPROOT_UNSPENDABLE_KEY))
111731
112147
  throw new Error("Unspendable taproot key in leaf script");
111732
- if (equalBytes4(p, internalPubKey)) {
112148
+ if (equalBytes5(p, internalPubKey)) {
111733
112149
  throw new Error("Using P2TR with leaf script with same key as internal key is not supported");
111734
112150
  }
111735
112151
  }
@@ -111780,7 +112196,7 @@ function taprootHashTree(tree, internalPubKey, allowUnknownOutputs = false, cust
111780
112196
  tree = tree[0];
111781
112197
  if (!Array.isArray(tree)) {
111782
112198
  const { leafVersion: version, script: leafScript } = tree;
111783
- if (tree.tapLeafScript || tree.tapMerkleRoot && !equalBytes4(tree.tapMerkleRoot, EMPTY2))
112199
+ if (tree.tapLeafScript || tree.tapMerkleRoot && !equalBytes5(tree.tapMerkleRoot, EMPTY2))
111784
112200
  throw new Error("P2TR: tapRoot leafScript cannot have tree");
111785
112201
  const script = typeof leafScript === "string" ? hex3.decode(leafScript) : leafScript;
111786
112202
  if (!isBytes7(script))
@@ -112159,7 +112575,7 @@ function cloneDeep(obj) {
112159
112575
  throw new Error(`cloneDeep: unknown type=${obj} (${typeof obj})`);
112160
112576
  }
112161
112577
  function getTaprootKeys(privKey, pubKey, internalKey, merkleRoot = EMPTY2) {
112162
- if (equalBytes4(internalKey, pubKey)) {
112578
+ if (equalBytes5(internalKey, pubKey)) {
112163
112579
  privKey = taprootTweakPrivKey(privKey, merkleRoot);
112164
112580
  pubKey = pubSchnorr(privKey);
112165
112581
  }
@@ -112255,7 +112671,7 @@ function validateInput(i) {
112255
112671
  if (i.index > last)
112256
112672
  throw new Error(`validateInput: index(${i.index}) not in nonWitnessUtxo`);
112257
112673
  const prevOut = i.nonWitnessUtxo.outputs[i.index];
112258
- if (i.witnessUtxo && (!equalBytes4(i.witnessUtxo.script, prevOut.script) || i.witnessUtxo.amount !== prevOut.amount))
112674
+ if (i.witnessUtxo && (!equalBytes5(i.witnessUtxo.script, prevOut.script) || i.witnessUtxo.amount !== prevOut.amount))
112259
112675
  throw new Error("validateInput: witnessUtxo different from nonWitnessUtxo");
112260
112676
  if (i.txid) {
112261
112677
  const outputs = i.nonWitnessUtxo.outputs;
@@ -112811,7 +113227,7 @@ class Transaction {
112811
113227
  let s = privateKey;
112812
113228
  for (const i of path)
112813
113229
  s = s.deriveChild(i);
112814
- if (!equalBytes4(s.publicKey, pubKey))
113230
+ if (!equalBytes5(s.publicKey, pubKey))
112815
113231
  throw new Error("bip32Derivation: wrong pubKey");
112816
113232
  if (!s.privateKey)
112817
113233
  throw new Error("bip32Derivation: no privateKey");
@@ -112848,7 +113264,7 @@ class Transaction {
112848
113264
  if (input.tapInternalKey) {
112849
113265
  const { pubKey, privKey } = getTaprootKeys(privateKey, schnorrPub, input.tapInternalKey, merkleRoot);
112850
113266
  const [taprootPubKey, _] = taprootTweakPubkey(input.tapInternalKey, merkleRoot);
112851
- if (equalBytes4(taprootPubKey, pubKey)) {
113267
+ if (equalBytes5(taprootPubKey, pubKey)) {
112852
113268
  const hash = this.preimageWitnessV1(idx, prevOutScript, sighash, amount);
112853
113269
  const sig = concatBytes7(signSchnorr(hash, privKey, _auxRand), sighash !== SignatureHash.DEFAULT ? new Uint8Array([sighash]) : EMPTY2);
112854
113270
  this.updateInput(idx, { tapKeySig: sig }, true);
@@ -112862,7 +113278,7 @@ class Transaction {
112862
113278
  const scriptDecoded = Script.decode(script);
112863
113279
  const ver = _script[_script.length - 1];
112864
113280
  const hash = tapLeafHash(script, ver);
112865
- const pos = scriptDecoded.findIndex((i) => isBytes7(i) && equalBytes4(i, schnorrPub));
113281
+ const pos = scriptDecoded.findIndex((i) => isBytes7(i) && equalBytes5(i, schnorrPub));
112866
113282
  if (pos === -1)
112867
113283
  continue;
112868
113284
  const msg = this.preimageWitnessV1(idx, prevOutScript, sighash, amount, undefined, script, ver);
@@ -112879,7 +113295,7 @@ class Transaction {
112879
113295
  let hasPubkey = false;
112880
113296
  const pubKeyHash = hash160(pubKey);
112881
113297
  for (const i of Script.decode(inputType.lastScript)) {
112882
- if (isBytes7(i) && (equalBytes4(i, pubKey) || equalBytes4(i, pubKeyHash)))
113298
+ if (isBytes7(i) && (equalBytes5(i, pubKey) || equalBytes5(i, pubKeyHash)))
112883
113299
  hasPubkey = true;
112884
113300
  }
112885
113301
  if (!hasPubkey)
@@ -112929,14 +113345,14 @@ class Transaction {
112929
113345
  const ver = _script[_script.length - 1];
112930
113346
  const outScript = OutScript.decode(script);
112931
113347
  const hash = tapLeafHash(script, ver);
112932
- const scriptSig = input.tapScriptSig.filter((i) => equalBytes4(i[0].leafHash, hash));
113348
+ const scriptSig = input.tapScriptSig.filter((i) => equalBytes5(i[0].leafHash, hash));
112933
113349
  let signatures = [];
112934
113350
  if (outScript.type === "tr_ms") {
112935
113351
  const m = outScript.m;
112936
113352
  const pubkeys = outScript.pubkeys;
112937
113353
  let added = 0;
112938
113354
  for (const pub of pubkeys) {
112939
- const sigIdx = scriptSig.findIndex((i) => equalBytes4(i[0].pubKey, pub));
113355
+ const sigIdx = scriptSig.findIndex((i) => equalBytes5(i[0].pubKey, pub));
112940
113356
  if (added === m || sigIdx === -1) {
112941
113357
  signatures.push(EMPTY2);
112942
113358
  continue;
@@ -112948,7 +113364,7 @@ class Transaction {
112948
113364
  continue;
112949
113365
  } else if (outScript.type === "tr_ns") {
112950
113366
  for (const pub of outScript.pubkeys) {
112951
- const sigIdx = scriptSig.findIndex((i) => equalBytes4(i[0].pubKey, pub));
113367
+ const sigIdx = scriptSig.findIndex((i) => equalBytes5(i[0].pubKey, pub));
112952
113368
  if (sigIdx === -1)
112953
113369
  continue;
112954
113370
  signatures.push(scriptSig[sigIdx][1]);
@@ -112958,7 +113374,7 @@ class Transaction {
112958
113374
  } else if (outScript.type === "unknown" && this.opts.allowUnknownInputs) {
112959
113375
  const scriptDecoded = Script.decode(script);
112960
113376
  signatures = scriptSig.map(([{ pubKey }, signature]) => {
112961
- const pos = scriptDecoded.findIndex((i) => isBytes7(i) && equalBytes4(i, pubKey));
113377
+ const pos = scriptDecoded.findIndex((i) => isBytes7(i) && equalBytes5(i, pubKey));
112962
113378
  if (pos === -1)
112963
113379
  throw new Error("finalize/taproot: cannot find position of pubkey in script");
112964
113380
  return { signature, pos };
@@ -113006,7 +113422,7 @@ class Transaction {
113006
113422
  const pubkeys = inputType.last.pubkeys;
113007
113423
  let signatures = [];
113008
113424
  for (const pub of pubkeys) {
113009
- const sign3 = input.partialSig.find((s) => equalBytes4(pub, s[0]));
113425
+ const sign3 = input.partialSig.find((s) => equalBytes5(pub, s[0]));
113010
113426
  if (!sign3)
113011
113427
  continue;
113012
113428
  signatures.push(sign3[1]);
@@ -113080,7 +113496,7 @@ class Transaction {
113080
113496
  }
113081
113497
  const thisUnsigned = this.global.unsignedTx ? RawOldTx.encode(this.global.unsignedTx) : EMPTY2;
113082
113498
  const otherUnsigned = other.global.unsignedTx ? RawOldTx.encode(other.global.unsignedTx) : EMPTY2;
113083
- if (!equalBytes4(thisUnsigned, otherUnsigned))
113499
+ if (!equalBytes5(thisUnsigned, otherUnsigned))
113084
113500
  throw new Error(`Transaction/combine: different unsigned tx`);
113085
113501
  this.global = mergeKeyMap(PSBTGlobal, this.global, other.global, undefined, this.opts.allowUnknown);
113086
113502
  for (let i = 0;i < this.inputs.length; i++)
@@ -117913,7 +118329,7 @@ function validateCoopExitPayoutTransaction({ rawCoopExitTransaction, expectedCoo
117913
118329
  const output = tx.getOutput(i);
117914
118330
  if (!output?.script || output.amount === undefined)
117915
118331
  continue;
117916
- if (!equalBytes4(output.script, expectedScript))
118332
+ if (!equalBytes5(output.script, expectedScript))
117917
118333
  continue;
117918
118334
  if (output.amount >= BigInt(expectedPayoutAmountSats))
117919
118335
  return;
@@ -118331,7 +118747,7 @@ function createSenderSpendTx({ htlcTx, network, hash, hashLockDestinationPubkey,
118331
118747
  const entry = p2.tapLeafScript.find(([, scriptWithVer]) => Buffer.compare(scriptWithVer.slice(0, -1), sequenceLockScript) === 0);
118332
118748
  const controlBlockBytes = TaprootControlBlock.encode(entry[0]);
118333
118749
  const seqLeafEntry = p2.tapLeafScript.find(([_, leaf]) => {
118334
- return equalBytes2(leaf.subarray(0, leaf.length - 1), sequenceLockScript);
118750
+ return equalBytes3(leaf.subarray(0, leaf.length - 1), sequenceLockScript);
118335
118751
  });
118336
118752
  const sighash = senderSpendTx.preimageWitnessV1(0, [sequenceLockScript], SigHash.DEFAULT, [htlcAmount]);
118337
118753
  senderSpendTx.updateInput(0, {
@@ -118381,7 +118797,7 @@ function createReceiverSpendTx({ htlcTx, network, hash, hashLockDestinationPubke
118381
118797
  script: sequenceLockScript
118382
118798
  }]), network, true);
118383
118799
  const hashLeafEntry = p2.tapLeafScript.find(([_, leaf]) => {
118384
- return equalBytes2(leaf.subarray(0, leaf.length - 1), hashLockScript);
118800
+ return equalBytes3(leaf.subarray(0, leaf.length - 1), hashLockScript);
118385
118801
  });
118386
118802
  spendTx.updateInput(0, {
118387
118803
  witnessUtxo: {
@@ -121131,7 +121547,7 @@ async function withRetry(operation, options = {}) {
121131
121547
  function scopeTransferLeavesToReceiver(transfer, receiverIdentityPublicKey) {
121132
121548
  if (transfer.receivers.length <= 1)
121133
121549
  return transfer;
121134
- const ownReceiver = transfer.receivers.find((receiver) => equalBytes2(receiver.identityPublicKey, receiverIdentityPublicKey));
121550
+ const ownReceiver = transfer.receivers.find((receiver) => equalBytes3(receiver.identityPublicKey, receiverIdentityPublicKey));
121135
121551
  if (!ownReceiver?.id)
121136
121552
  throw new SparkValidationError("Cannot scope claim: wallet is not a receiver of this multi-receiver transfer");
121137
121553
  const ownLeaves = transfer.leaves.filter((leaf) => leaf.transferReceiverId === ownReceiver.id);
@@ -121146,7 +121562,7 @@ function isReceiverLegComplete(transfer, receiverIdentityPublicKey) {
121146
121562
  const wholeComplete = transfer.status === TransferStatus.TRANSFER_STATUS_COMPLETED;
121147
121563
  if (transfer.receivers.length <= 1)
121148
121564
  return wholeComplete;
121149
- const ownReceiver = transfer.receivers.find((receiver) => equalBytes2(receiver.identityPublicKey, receiverIdentityPublicKey));
121565
+ const ownReceiver = transfer.receivers.find((receiver) => equalBytes3(receiver.identityPublicKey, receiverIdentityPublicKey));
121150
121566
  if (!ownReceiver)
121151
121567
  return false;
121152
121568
  return ownReceiver.status === TransferReceiverStatus.TRANSFER_RECEIVER_STATUS_COMPLETED || wholeComplete;
@@ -121892,7 +122308,7 @@ function isReceiverTransferStreamEvent(event2) {
121892
122308
  function findOutputPayingScript(tx, script) {
121893
122309
  for (let i = 0;i < tx.outputsLength; i++) {
121894
122310
  const outputScript = tx.getOutput(i).script;
121895
- if (outputScript && equalBytes2(outputScript, script))
122311
+ if (outputScript && equalBytes3(outputScript, script))
121896
122312
  return i;
121897
122313
  }
121898
122314
  }
@@ -121923,7 +122339,7 @@ function resolveRecoverableOutput(leaf, nodes, network, recoveryTxid, outputInde
121923
122339
  const prevOut = tx.getOutput(outputIndex);
121924
122340
  if (prevOut.amount === undefined)
121925
122341
  continue;
121926
- if (!prevOut.script || !equalBytes2(prevOut.script, leafScript))
122342
+ if (!prevOut.script || !equalBytes3(prevOut.script, leafScript))
121927
122343
  continue;
121928
122344
  return {
121929
122345
  txid,
@@ -123212,9 +123628,9 @@ var import_nice_grpc_common, import_light_bolt11_decoder, SparkFrostBase = class
123212
123628
  }
123213
123629
  signTransactionIndex(tx, index2, publicKey) {
123214
123630
  let privateKey;
123215
- if (equalBytes2(publicKey, this.identityKey?.publicKey ?? new Uint8Array))
123631
+ if (equalBytes3(publicKey, this.identityKey?.publicKey ?? new Uint8Array))
123216
123632
  privateKey = this.identityKey?.privateKey;
123217
- else if (equalBytes2(publicKey, this.depositKey?.publicKey ?? new Uint8Array))
123633
+ else if (equalBytes3(publicKey, this.depositKey?.publicKey ?? new Uint8Array))
123218
123634
  privateKey = this.depositKey?.privateKey;
123219
123635
  if (!privateKey)
123220
123636
  throw new SparkValidationError("Private key not found for public key", {
@@ -124055,7 +124471,7 @@ var import_nice_grpc_common, import_light_bolt11_decoder, SparkFrostBase = class
124055
124471
  return response.transfer;
124056
124472
  }
124057
124473
  compareTransfers(transfer1, transfer2) {
124058
- return transfer1.id === transfer2.id && equalBytes2(transfer1.senderIdentityPublicKey, transfer2.senderIdentityPublicKey) && transfer1.status === transfer2.status && transfer1.totalValue === transfer2.totalValue && transfer1.expiryTime?.getTime() === transfer2.expiryTime?.getTime() && transfer1.leaves.length === transfer2.leaves.length;
124474
+ return transfer1.id === transfer2.id && equalBytes3(transfer1.senderIdentityPublicKey, transfer2.senderIdentityPublicKey) && transfer1.status === transfer2.status && transfer1.totalValue === transfer2.totalValue && transfer1.expiryTime?.getTime() === transfer2.expiryTime?.getTime() && transfer1.leaves.length === transfer2.leaves.length;
124059
124475
  }
124060
124476
  }, TransferService, CoopExitService, DENOMINATIONS, Swap = class {
124061
124477
  inLeaves;
@@ -124579,7 +124995,7 @@ var import_nice_grpc_common, import_light_bolt11_decoder, SparkFrostBase = class
124579
124995
  }
124580
124996
  }
124581
124997
  async handleTransferEvent(transfer) {
124582
- if (!this.identityPublicKey || !equalBytes2(transfer.senderIdentityPublicKey, this.identityPublicKey))
124998
+ if (!this.identityPublicKey || !equalBytes3(transfer.senderIdentityPublicKey, this.identityPublicKey))
124583
124999
  return;
124584
125000
  const leafIds = transfer.leaves.flatMap((leaf) => leaf.leaf ? [leaf.leaf.id] : []);
124585
125001
  this.log("handleTransferEvent", `transfer=${transfer.id} type=${transfer.type} status=${transfer.status} leaves=[${leafIds.join(",")}]`);
@@ -125209,12 +125625,12 @@ var import_nice_grpc_common, import_light_bolt11_decoder, SparkFrostBase = class
125209
125625
  return pendingTransfer ? await this.transferService.claimTransfer(pendingTransfer) : [];
125210
125626
  }
125211
125627
  verifyKey(pubkey1, pubkey2, verifyingKey) {
125212
- return equalBytes2(addPublicKeys(pubkey1, pubkey2), verifyingKey);
125628
+ return equalBytes3(addPublicKeys(pubkey1, pubkey2), verifyingKey);
125213
125629
  }
125214
125630
  isLeafConsistent(leaf, opLeaf) {
125215
125631
  if (!opLeaf)
125216
125632
  return false;
125217
- return leaf.status === opLeaf.status && !!leaf.signingKeyshare && !!opLeaf.signingKeyshare && equalBytes2(leaf.signingKeyshare.publicKey, opLeaf.signingKeyshare.publicKey) && equalBytes2(leaf.nodeTx, opLeaf.nodeTx);
125633
+ return leaf.status === opLeaf.status && !!leaf.signingKeyshare && !!opLeaf.signingKeyshare && equalBytes3(leaf.signingKeyshare.publicKey, opLeaf.signingKeyshare.publicKey) && equalBytes3(leaf.nodeTx, opLeaf.nodeTx);
125218
125634
  }
125219
125635
  restoreLocalLockedToAvailable(leafIds) {
125220
125636
  let changed = false;
@@ -134357,7 +134773,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
134357
134773
  if (traceId)
134358
134774
  this.logEvent(`handleStreamEvent: Receiver transfer ${transfer.id} traceId=${traceId}`);
134359
134775
  const { senderIdentityPublicKey, receiverIdentityPublicKey } = transfer;
134360
- const isSelf = equalBytes2(senderIdentityPublicKey, receiverIdentityPublicKey);
134776
+ const isSelf = equalBytes3(senderIdentityPublicKey, receiverIdentityPublicKey);
134361
134777
  this.logEvent(`handleStreamEvent: Receiver transfer: id=${transfer.id} type=${transfer.type} status=${transfer.status} totalValue=${transfer.totalValue} leaves=${transfer.leaves.length} selfTransfer=${isSelf}`);
134362
134778
  if (!isSelf) {
134363
134779
  const incomingLeaves = transfer.leaves.map((l) => l.leaf).filter((l) => !!l);
@@ -135340,7 +135756,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
135340
135756
  const network = this.config.getNetwork();
135341
135757
  const identityPublicKey = await this.config.signer.getIdentityPublicKey();
135342
135758
  const nodes = await this.leafManager.queryWatchtowerExitedNodes();
135343
- return nodes.filter((node) => node.refundTx.length > 0 && equalBytes2(node.ownerIdentityPublicKey, identityPublicKey)).map((leaf) => {
135759
+ return nodes.filter((node) => node.refundTx.length > 0 && equalBytes3(node.ownerIdentityPublicKey, identityPublicKey)).map((leaf) => {
135344
135760
  const recoverable = resolveRecoverableOutput(leaf, nodes, network);
135345
135761
  return {
135346
135762
  leafId: leaf.id,
@@ -135754,7 +136170,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
135754
136170
  }
135755
136171
  const transfer = await this.transferService.sendTransferV3(allLeafKeyTweaks);
135756
136172
  const signerIdentityPublicKey = await this.config.signer.getIdentityPublicKey();
135757
- if (decodedReceivers.some((r) => equalBytes2(r.identityPublicKey, signerIdentityPublicKey))) {
136173
+ if (decodedReceivers.some((r) => equalBytes3(r.identityPublicKey, signerIdentityPublicKey))) {
135758
136174
  const pending = await this.transferService.queryTransfer(transfer.id);
135759
136175
  if (pending)
135760
136176
  await this.claimTransfer({ transfer: pending });
@@ -135798,7 +136214,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
135798
136214
  return await Promise.all(jobs.map(async (job) => {
135799
136215
  try {
135800
136216
  const transfer = await this.transferService.sendTransferWithKeyTweaks(job.leafKeyTweaks, job.sparkInvoice, job.transferId);
135801
- if (equalBytes2(signerIdentityPublicKey, job.receiverIdentityPubkey)) {
136217
+ if (equalBytes3(signerIdentityPublicKey, job.receiverIdentityPubkey)) {
135802
136218
  const pending = await this.transferService.queryTransfer(transfer.id);
135803
136219
  if (pending)
135804
136220
  await this.claimTransfer({ transfer: pending });
@@ -136473,7 +136889,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
136473
136889
  if (!transfer)
136474
136890
  throw new Error("Failed to provide preimage");
136475
136891
  const receiverIdentityPublicKey = transfer.receiverIdentityPublicKey;
136476
- if (equalBytes2(receiverIdentityPublicKey, await this.config.signer.getIdentityPublicKey()))
136892
+ if (equalBytes3(receiverIdentityPublicKey, await this.config.signer.getIdentityPublicKey()))
136477
136893
  await this.claimTransfer({
136478
136894
  transfer,
136479
136895
  emit: true
@@ -136513,7 +136929,7 @@ var init_spark_wallet_CIYOesd9 = __esm(() => {
136513
136929
  fee
136514
136930
  });
136515
136931
  this.config.signer.signTransactionIndex(spendTx, 0, await this.config.signer.getIdentityPublicKey());
136516
- const sig = spendTx.getInput(0).tapScriptSig.find(([ref2]) => equalBytes2(ref2.leafHash, leafHash))?.[1];
136932
+ const sig = spendTx.getInput(0).tapScriptSig.find(([ref2]) => equalBytes3(ref2.leafHash, leafHash))?.[1];
136517
136933
  spendTx.updateInput(0, { finalScriptWitness: [
136518
136934
  sig,
136519
136935
  hexToBytes4(preimage),