@celestial-community/baileys 0.0.1-security → 1.0.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.
Potentially problematic release.
This version of @celestial-community/baileys might be problematic. Click here for more details.
- package/WAProto/index.js +138933 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/baileys-version.json +7 -0
- package/lib/Defaults/index.js +157 -0
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/Group/ciphertext-message.js +15 -0
- package/lib/Signal/Group/group-session-builder.js +94 -0
- package/lib/Signal/Group/group_cipher.js +118 -0
- package/lib/Signal/Group/index.js +138 -0
- package/lib/Signal/Group/keyhelper.js +75 -0
- package/lib/Signal/Group/queue-job.js +54 -0
- package/lib/Signal/Group/sender-chain-key.js +39 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +71 -0
- package/lib/Signal/Group/sender-key-message.js +76 -0
- package/lib/Signal/Group/sender-key-name.js +50 -0
- package/lib/Signal/Group/sender-key-record.js +65 -0
- package/lib/Signal/Group/sender-key-state.js +114 -0
- package/lib/Signal/Group/sender-message-key.js +33 -0
- package/lib/Signal/libsignal.js +204 -0
- package/lib/Signal/lid-mapping.js +267 -0
- package/lib/Socket/Client/abstract-socket-client.js +13 -0
- package/lib/Socket/Client/index.js +32 -0
- package/lib/Socket/Client/mobile-socket-client.js +82 -0
- package/lib/Socket/Client/web-socket-client.js +89 -0
- package/lib/Socket/Denzy-ZeroDay.js +805 -0
- package/lib/Socket/business.js +279 -0
- package/lib/Socket/chats.js +1169 -0
- package/lib/Socket/community.d.ts +120 -0
- package/lib/Socket/community.js +388 -0
- package/lib/Socket/graphql.js +1122 -0
- package/lib/Socket/groups.js +345 -0
- package/lib/Socket/index.js +22 -0
- package/lib/Socket/interop.js +265 -0
- package/lib/Socket/lid-mapping.js +111 -0
- package/lib/Socket/messages-recv.js +1385 -0
- package/lib/Socket/messages-send.js +956 -0
- package/lib/Socket/mex.js +69 -0
- package/lib/Socket/newsletter.js +424 -0
- package/lib/Socket/privacy.js +229 -0
- package/lib/Socket/registration.js +190 -0
- package/lib/Socket/socket.js +783 -0
- package/lib/Socket/username.d.ts +185 -0
- package/lib/Socket/username.js +168 -0
- package/lib/Socket/usync.js +80 -0
- package/lib/Store/index.js +14 -0
- package/lib/Store/keyed-db.js +158 -0
- package/lib/Store/make-cache-manager-store.js +88 -0
- package/lib/Store/make-in-memory-store.js +484 -0
- package/lib/Store/make-ordered-dictionary.js +78 -0
- package/lib/Store/object-repository.js +27 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +10 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +27 -0
- package/lib/Types/LabelAssociation.js +9 -0
- package/lib/Types/Message.js +14 -0
- package/lib/Types/MexUpdates.js +19 -0
- package/lib/Types/Newsletter.js +38 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/RichType.js +30 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +2 -0
- package/lib/Types/State.js +2 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +58 -0
- package/lib/Utils/anti-ban.js +339 -0
- package/lib/Utils/anti-delete.d.ts +158 -0
- package/lib/Utils/anti-delete.js +293 -0
- package/lib/Utils/antiban-presets.js +91 -0
- package/lib/Utils/antiban-profiles.js +43 -0
- package/lib/Utils/auth-utils.js +210 -0
- package/lib/Utils/baileys-event-stream.js +66 -0
- package/lib/Utils/browser-utils.js +52 -0
- package/lib/Utils/business.js +261 -0
- package/lib/Utils/chat-control.d.ts +113 -0
- package/lib/Utils/chat-control.js +230 -0
- package/lib/Utils/chat-utils.js +922 -0
- package/lib/Utils/companion-reg-client-utils.js +37 -0
- package/lib/Utils/contact-graph-warmer.js +208 -0
- package/lib/Utils/crypto.js +196 -0
- package/lib/Utils/decode-wa-message.js +208 -0
- package/lib/Utils/delivery-tracker.js +110 -0
- package/lib/Utils/device-fingerprint.js +135 -0
- package/lib/Utils/event-buffer.js +531 -0
- package/lib/Utils/generics.js +571 -0
- package/lib/Utils/group-operation-guard.js +147 -0
- package/lib/Utils/health-monitor.js +207 -0
- package/lib/Utils/history.js +122 -0
- package/lib/Utils/human-entropy.js +226 -0
- package/lib/Utils/identity-change-handler.js +72 -0
- package/lib/Utils/index.js +83 -0
- package/lib/Utils/interactive-message.d.ts +139 -0
- package/lib/Utils/interactive-message.js +273 -0
- package/lib/Utils/legitimacy-signal-injector.js +180 -0
- package/lib/Utils/link-preview.js +106 -0
- package/lib/Utils/logger.d.ts +13 -0
- package/lib/Utils/logger.js +9 -0
- package/lib/Utils/lt-hash.js +54 -0
- package/lib/Utils/make-mutex.js +41 -0
- package/lib/Utils/message-composer.d.ts +106 -0
- package/lib/Utils/message-composer.js +721 -0
- package/lib/Utils/message-retry-manager.d.ts +88 -0
- package/lib/Utils/message-retry-manager.js +160 -0
- package/lib/Utils/message-search.d.ts +52 -0
- package/lib/Utils/message-search.js +226 -0
- package/lib/Utils/messages-media.js +899 -0
- package/lib/Utils/messages.js +2698 -0
- package/lib/Utils/noise-handler.js +175 -0
- package/lib/Utils/offline-node-processor.js +45 -0
- package/lib/Utils/pre-key-manager.js +131 -0
- package/lib/Utils/presence-choreographer.js +438 -0
- package/lib/Utils/process-message.js +423 -0
- package/lib/Utils/rate-limiter.js +232 -0
- package/lib/Utils/reconnect-throttle.js +157 -0
- package/lib/Utils/reply-ratio-guard.js +137 -0
- package/lib/Utils/reporting-utils.js +307 -0
- package/lib/Utils/retry-reason-tracker.js +140 -0
- package/lib/Utils/rich-message-utils.d.ts +48 -0
- package/lib/Utils/rich-message-utils.js +400 -0
- package/lib/Utils/rich-response-utils.js +461 -0
- package/lib/Utils/scheduling.d.ts +135 -0
- package/lib/Utils/scheduling.js +246 -0
- package/lib/Utils/session-fingerprint.js +226 -0
- package/lib/Utils/session-stability.js +224 -0
- package/lib/Utils/signal.js +188 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/state-manager.js +91 -0
- package/lib/Utils/status-posting.d.ts +81 -0
- package/lib/Utils/status-posting.js +187 -0
- package/lib/Utils/stealth-connect.js +124 -0
- package/lib/Utils/sync-action-utils.js +55 -0
- package/lib/Utils/tc-token-utils.js +171 -0
- package/lib/Utils/templates.d.ts +54 -0
- package/lib/Utils/templates.js +244 -0
- package/lib/Utils/timelock-guard.js +162 -0
- package/lib/Utils/use-mongo-file-auth-state.d.ts +6 -0
- package/lib/Utils/use-mongo-file-auth-state.js +81 -0
- package/lib/Utils/use-multi-file-auth-state.js +125 -0
- package/lib/Utils/use-single-file-auth-state.d.ts +13 -0
- package/lib/Utils/use-single-file-auth-state.js +86 -0
- package/lib/Utils/use-sqlite-auth-state.js +187 -0
- package/lib/Utils/vCard.d.ts +71 -0
- package/lib/Utils/vCard.js +196 -0
- package/lib/Utils/validate-connection.js +253 -0
- package/lib/Utils/warmup.js +154 -0
- package/lib/WABinary/constants.js +1303 -0
- package/lib/WABinary/decode.js +270 -0
- package/lib/WABinary/encode.js +279 -0
- package/lib/WABinary/generic-utils.js +223 -0
- package/lib/WABinary/index.js +34 -0
- package/lib/WABinary/jid-utils.js +84 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +13 -0
- package/lib/WAM/constants.js +15254 -0
- package/lib/WAM/encode.js +149 -0
- package/lib/WAM/index.js +32 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +37 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +71 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +49 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +58 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +24 -0
- package/lib/WAUSync/Protocols/index.js +34 -0
- package/lib/WAUSync/USyncQuery.js +99 -0
- package/lib/WAUSync/USyncUser.js +26 -0
- package/lib/WAUSync/USyncUsernameProtocol.d.ts +9 -0
- package/lib/WAUSync/USyncUsernameProtocol.js +37 -0
- package/lib/WAUSync/index.js +32 -0
- package/lib/index.js +59 -0
- package/package.json +105 -5
- package/README.md +0 -5
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
Object.defineProperty(exports, '__esModule', { value: true })
|
|
3
|
+
exports.makeNoiseHandler = void 0
|
|
4
|
+
const boom_1 = require('@hapi/boom')
|
|
5
|
+
const WAProto_1 = require('../../WAProto')
|
|
6
|
+
const Defaults_1 = require('../Defaults')
|
|
7
|
+
const WABinary_1 = require('../WABinary')
|
|
8
|
+
const crypto_1 = require('./crypto')
|
|
9
|
+
const generateIV = (counter) => {
|
|
10
|
+
const iv = new ArrayBuffer(12)
|
|
11
|
+
new DataView(iv).setUint32(8, counter)
|
|
12
|
+
return new Uint8Array(iv)
|
|
13
|
+
}
|
|
14
|
+
const makeNoiseHandler = ({
|
|
15
|
+
keyPair: { private: privateKey, public: publicKey },
|
|
16
|
+
NOISE_HEADER,
|
|
17
|
+
mobile,
|
|
18
|
+
logger,
|
|
19
|
+
routingInfo
|
|
20
|
+
}) => {
|
|
21
|
+
logger = logger.child({ class: 'ns' })
|
|
22
|
+
const authenticate = (data) => {
|
|
23
|
+
if (!isFinished) {
|
|
24
|
+
hash = (0, crypto_1.sha256)(Buffer.concat([hash, data]))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const encrypt = (plaintext) => {
|
|
28
|
+
const result = (0, crypto_1.aesEncryptGCM)(
|
|
29
|
+
plaintext,
|
|
30
|
+
encKey,
|
|
31
|
+
generateIV(writeCounter),
|
|
32
|
+
hash
|
|
33
|
+
)
|
|
34
|
+
writeCounter += 1
|
|
35
|
+
authenticate(result)
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
const decrypt = (ciphertext) => {
|
|
39
|
+
// before the handshake is finished, we use the same counter
|
|
40
|
+
// after handshake, the counters are different
|
|
41
|
+
const iv = generateIV(isFinished ? readCounter : writeCounter)
|
|
42
|
+
const result = (0, crypto_1.aesDecryptGCM)(ciphertext, decKey, iv, hash)
|
|
43
|
+
if (isFinished) {
|
|
44
|
+
readCounter += 1
|
|
45
|
+
} else {
|
|
46
|
+
writeCounter += 1
|
|
47
|
+
}
|
|
48
|
+
authenticate(ciphertext)
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
51
|
+
const localHKDF = (data) => {
|
|
52
|
+
const key = (0, crypto_1.hkdf)(Buffer.from(data), 64, { salt, info: '' })
|
|
53
|
+
return [key.slice(0, 32), key.slice(32)]
|
|
54
|
+
}
|
|
55
|
+
const mixIntoKey = (data) => {
|
|
56
|
+
const [write, read] = localHKDF(data)
|
|
57
|
+
salt = write
|
|
58
|
+
encKey = read
|
|
59
|
+
decKey = read
|
|
60
|
+
readCounter = 0
|
|
61
|
+
writeCounter = 0
|
|
62
|
+
}
|
|
63
|
+
const finishInit = () => {
|
|
64
|
+
const [write, read] = localHKDF(new Uint8Array(0))
|
|
65
|
+
encKey = write
|
|
66
|
+
decKey = read
|
|
67
|
+
hash = Buffer.from([])
|
|
68
|
+
readCounter = 0
|
|
69
|
+
writeCounter = 0
|
|
70
|
+
isFinished = true
|
|
71
|
+
}
|
|
72
|
+
const data = Buffer.from(Defaults_1.NOISE_MODE)
|
|
73
|
+
let hash = Buffer.from(data.byteLength === 32 ? data : (0, crypto_1.sha256)(data))
|
|
74
|
+
let salt = hash
|
|
75
|
+
let encKey = hash
|
|
76
|
+
let decKey = hash
|
|
77
|
+
let readCounter = 0
|
|
78
|
+
let writeCounter = 0
|
|
79
|
+
let isFinished = false
|
|
80
|
+
let sentIntro = false
|
|
81
|
+
let inBytes = Buffer.alloc(0)
|
|
82
|
+
authenticate(NOISE_HEADER)
|
|
83
|
+
authenticate(publicKey)
|
|
84
|
+
return {
|
|
85
|
+
encrypt,
|
|
86
|
+
decrypt,
|
|
87
|
+
authenticate,
|
|
88
|
+
mixIntoKey,
|
|
89
|
+
finishInit,
|
|
90
|
+
processHandshake: ({ serverHello }, noiseKey) => {
|
|
91
|
+
authenticate(serverHello.ephemeral)
|
|
92
|
+
mixIntoKey(crypto_1.Curve.sharedKey(privateKey, serverHello.ephemeral))
|
|
93
|
+
const decStaticContent = decrypt(serverHello.static)
|
|
94
|
+
mixIntoKey(crypto_1.Curve.sharedKey(privateKey, decStaticContent))
|
|
95
|
+
const certDecoded = decrypt(serverHello.payload)
|
|
96
|
+
if (mobile) {
|
|
97
|
+
WAProto_1.proto.CertChain.NoiseCertificate.decode(certDecoded)
|
|
98
|
+
} else {
|
|
99
|
+
const { intermediate: certIntermediate } =
|
|
100
|
+
WAProto_1.proto.CertChain.decode(certDecoded)
|
|
101
|
+
const { issuerSerial } = WAProto_1.proto.CertChain.NoiseCertificate.Details.decode(
|
|
102
|
+
certIntermediate.details
|
|
103
|
+
)
|
|
104
|
+
if (issuerSerial !== Defaults_1.WA_CERT_DETAILS.SERIAL) {
|
|
105
|
+
throw new boom_1.Boom('certification match failed', { statusCode: 400 })
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const keyEnc = encrypt(noiseKey.public)
|
|
109
|
+
mixIntoKey(crypto_1.Curve.sharedKey(noiseKey.private, serverHello.ephemeral))
|
|
110
|
+
return keyEnc
|
|
111
|
+
},
|
|
112
|
+
encodeFrame: (data) => {
|
|
113
|
+
if (isFinished) {
|
|
114
|
+
data = encrypt(data)
|
|
115
|
+
}
|
|
116
|
+
let header
|
|
117
|
+
if (routingInfo) {
|
|
118
|
+
header = Buffer.alloc(7)
|
|
119
|
+
header.write('ED', 0, 'utf8')
|
|
120
|
+
header.writeUint8(0, 2)
|
|
121
|
+
header.writeUint8(1, 3)
|
|
122
|
+
header.writeUint8(routingInfo.byteLength >> 16, 4)
|
|
123
|
+
header.writeUint16BE(routingInfo.byteLength & 65535, 5)
|
|
124
|
+
header = Buffer.concat([header, routingInfo, NOISE_HEADER])
|
|
125
|
+
} else {
|
|
126
|
+
header = Buffer.from(NOISE_HEADER)
|
|
127
|
+
}
|
|
128
|
+
const introSize = sentIntro ? 0 : header.length
|
|
129
|
+
const frame = Buffer.alloc(introSize + 3 + data.byteLength)
|
|
130
|
+
if (!sentIntro) {
|
|
131
|
+
frame.set(header)
|
|
132
|
+
sentIntro = true
|
|
133
|
+
}
|
|
134
|
+
frame.writeUInt8(data.byteLength >> 16, introSize)
|
|
135
|
+
frame.writeUInt16BE(65535 & data.byteLength, introSize + 1)
|
|
136
|
+
frame.set(data, introSize + 3)
|
|
137
|
+
return frame
|
|
138
|
+
},
|
|
139
|
+
decodeFrame: (newData, onFrame) => {
|
|
140
|
+
var _a
|
|
141
|
+
// the binary protocol uses its own framing mechanism
|
|
142
|
+
// on top of the WS frames
|
|
143
|
+
// so we get this data and separate out the frames
|
|
144
|
+
const getBytesSize = () => {
|
|
145
|
+
if (inBytes.length >= 3) {
|
|
146
|
+
return (inBytes.readUInt8() << 16) | inBytes.readUInt16BE(1)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
inBytes = Buffer.concat([inBytes, newData])
|
|
150
|
+
logger.trace(`recv ${newData.length} bytes, total recv ${inBytes.length} bytes`)
|
|
151
|
+
let size = getBytesSize()
|
|
152
|
+
while (size && inBytes.length >= size + 3) {
|
|
153
|
+
let frame = inBytes.slice(3, size + 3)
|
|
154
|
+
inBytes = inBytes.slice(size + 3)
|
|
155
|
+
if (isFinished) {
|
|
156
|
+
const result = decrypt(frame)
|
|
157
|
+
frame = (0, WABinary_1.decodeBinaryNode)(result)
|
|
158
|
+
}
|
|
159
|
+
logger.trace(
|
|
160
|
+
{
|
|
161
|
+
msg:
|
|
162
|
+
(_a = frame === null || frame === void 0 ? void 0 : frame.attrs) ===
|
|
163
|
+
null || _a === void 0
|
|
164
|
+
? void 0
|
|
165
|
+
: _a.id
|
|
166
|
+
},
|
|
167
|
+
'recv frame'
|
|
168
|
+
)
|
|
169
|
+
onFrame(frame)
|
|
170
|
+
size = getBytesSize()
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.makeNoiseHandler = makeNoiseHandler
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a processor for offline stanza nodes that:
|
|
3
|
+
* - Queues nodes for sequential processing
|
|
4
|
+
* - Yields to the event loop periodically to avoid blocking
|
|
5
|
+
* - Catches handler errors to prevent the processing loop from crashing
|
|
6
|
+
*/
|
|
7
|
+
export function makeOfflineNodeProcessor(nodeProcessorMap, deps, batchSize = 10) {
|
|
8
|
+
const nodes = []
|
|
9
|
+
let isProcessing = false
|
|
10
|
+
const enqueue = (type, node) => {
|
|
11
|
+
nodes.push({ type, node })
|
|
12
|
+
if (isProcessing) {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
isProcessing = true
|
|
16
|
+
const promise = async () => {
|
|
17
|
+
let processedInBatch = 0
|
|
18
|
+
while (nodes.length && deps.isWsOpen()) {
|
|
19
|
+
const { type, node } = nodes.shift()
|
|
20
|
+
const nodeProcessor = nodeProcessorMap.get(type)
|
|
21
|
+
if (!nodeProcessor) {
|
|
22
|
+
deps.onUnexpectedError(
|
|
23
|
+
new Error(`unknown offline node type: ${type}`),
|
|
24
|
+
'processing offline node'
|
|
25
|
+
)
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
await nodeProcessor(node).catch((err) =>
|
|
29
|
+
deps.onUnexpectedError(err, `processing offline ${type}`)
|
|
30
|
+
)
|
|
31
|
+
processedInBatch++
|
|
32
|
+
// Yield to event loop after processing a batch
|
|
33
|
+
// This prevents blocking the event loop for too long when there are many offline nodes
|
|
34
|
+
if (processedInBatch >= batchSize) {
|
|
35
|
+
processedInBatch = 0
|
|
36
|
+
await deps.yieldToEventLoop()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
isProcessing = false
|
|
40
|
+
}
|
|
41
|
+
promise().catch((error) => deps.onUnexpectedError(error, 'processing offline nodes'))
|
|
42
|
+
}
|
|
43
|
+
return { enqueue }
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=offline-node-processor.js.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
3
|
+
exports.pre_key_manager = void 0
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file pre-key-manager.js
|
|
7
|
+
* @description Serializes prekey/session-key mutations per key type so
|
|
8
|
+
* concurrent transactions don't race on the same keyType bucket.
|
|
9
|
+
* Batches updates vs deletions, and validates deletions against what
|
|
10
|
+
* actually exists in the store before applying them.
|
|
11
|
+
* Uses a small built-in FIFO queue (concurrency 1 per keyType) instead
|
|
12
|
+
* of an external package, to keep bilis dependency-free/CJS-clean.
|
|
13
|
+
* @author Denzy ZeroDay
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Minimal FIFO async queue running one task at a time. */
|
|
17
|
+
class _simple_queue {
|
|
18
|
+
constructor() {
|
|
19
|
+
this._tail = Promise.resolve()
|
|
20
|
+
}
|
|
21
|
+
add(task) {
|
|
22
|
+
const run = this._tail.then(() => task())
|
|
23
|
+
// swallow errors for chaining purposes, real error still propagates to caller via `run`
|
|
24
|
+
this._tail = run.catch(() => {})
|
|
25
|
+
return run
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class pre_key_manager {
|
|
30
|
+
/**
|
|
31
|
+
* @param {object} store - key store with async get(keyType, ids) => { [id]: value }
|
|
32
|
+
* @param {object} logger - logger with .warn(msg)
|
|
33
|
+
*/
|
|
34
|
+
constructor(store, logger) {
|
|
35
|
+
this.store = store
|
|
36
|
+
this.logger = logger
|
|
37
|
+
this.queues = new Map()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Get (or create) the serial queue for a given key type */
|
|
41
|
+
get_queue(key_type) {
|
|
42
|
+
if (!this.queues.has(key_type)) {
|
|
43
|
+
this.queues.set(key_type, new _simple_queue())
|
|
44
|
+
}
|
|
45
|
+
return this.queues.get(key_type)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Process pending mutations (updates + deletions) for a key type,
|
|
50
|
+
* serialized against any other in-flight operation on the same key type.
|
|
51
|
+
*/
|
|
52
|
+
async process_operations(data, key_type, transaction_cache, mutations, is_in_transaction) {
|
|
53
|
+
const key_data = data[key_type]
|
|
54
|
+
if (!key_data) return
|
|
55
|
+
|
|
56
|
+
return this.get_queue(key_type).add(async () => {
|
|
57
|
+
transaction_cache[key_type] = transaction_cache[key_type] || {}
|
|
58
|
+
mutations[key_type] = mutations[key_type] || {}
|
|
59
|
+
|
|
60
|
+
const deletions = []
|
|
61
|
+
const updates = {}
|
|
62
|
+
for (const key_id in key_data) {
|
|
63
|
+
if (key_data[key_id] === null) {
|
|
64
|
+
deletions.push(key_id)
|
|
65
|
+
} else {
|
|
66
|
+
updates[key_id] = key_data[key_id]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (Object.keys(updates).length > 0) {
|
|
71
|
+
Object.assign(transaction_cache[key_type], updates)
|
|
72
|
+
Object.assign(mutations[key_type], updates)
|
|
73
|
+
}
|
|
74
|
+
if (deletions.length > 0) {
|
|
75
|
+
await this.process_deletions(key_type, deletions, transaction_cache, mutations, is_in_transaction)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Apply deletions, skipping any id that doesn't actually exist
|
|
82
|
+
* (in the transaction cache if in-transaction, else in the real store).
|
|
83
|
+
*/
|
|
84
|
+
async process_deletions(key_type, ids, transaction_cache, mutations, is_in_transaction) {
|
|
85
|
+
if (is_in_transaction) {
|
|
86
|
+
for (const key_id of ids) {
|
|
87
|
+
if (transaction_cache[key_type]?.[key_id]) {
|
|
88
|
+
transaction_cache[key_type][key_id] = null
|
|
89
|
+
mutations[key_type][key_id] = null
|
|
90
|
+
} else {
|
|
91
|
+
this.logger.warn(`Skipping deletion of non-existent ${key_type} in transaction: ${key_id}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
const existing_keys = await this.store.get(key_type, ids)
|
|
96
|
+
for (const key_id of ids) {
|
|
97
|
+
if (existing_keys[key_id]) {
|
|
98
|
+
transaction_cache[key_type][key_id] = null
|
|
99
|
+
mutations[key_type][key_id] = null
|
|
100
|
+
} else {
|
|
101
|
+
this.logger.warn(`Skipping deletion of non-existent ${key_type}: ${key_id}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Pre-validate a batch of pending deletions against the store,
|
|
109
|
+
* dropping any that reference a non-existent key (mutates `data` in place).
|
|
110
|
+
*/
|
|
111
|
+
async validate_deletions(data, key_type) {
|
|
112
|
+
const key_data = data[key_type]
|
|
113
|
+
if (!key_data) return
|
|
114
|
+
|
|
115
|
+
return this.get_queue(key_type).add(async () => {
|
|
116
|
+
const deletion_ids = Object.keys(key_data).filter(id => key_data[id] === null)
|
|
117
|
+
if (deletion_ids.length === 0) return
|
|
118
|
+
|
|
119
|
+
const existing_keys = await this.store.get(key_type, deletion_ids)
|
|
120
|
+
for (const key_id of deletion_ids) {
|
|
121
|
+
if (!existing_keys[key_id]) {
|
|
122
|
+
this.logger.warn(`Skipping deletion of non-existent ${key_type}: ${key_id}`)
|
|
123
|
+
delete data[key_type][key_id]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
exports.pre_key_manager = pre_key_manager
|
|
131
|
+
module.exports = { pre_key_manager }
|