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