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