@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,438 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
Object.defineProperty(exports, '__esModule', { value: true })
|
|
3
|
+
exports.presence_choreographer = exports.get_circadian_multiplier = exports.ACTIVITY_CURVES = void 0
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file presence-choreographer.js
|
|
7
|
+
* @description Models a realistic human daily rhythm (circadian curve),
|
|
8
|
+
* Gaussian-variance typing speed with think-pauses, delayed/skipped read
|
|
9
|
+
* receipts, distraction pauses, and offline gaps. Produces a "typing plan"
|
|
10
|
+
* the caller executes step by step against sock.sendPresenceUpdate.
|
|
11
|
+
* Off by default.
|
|
12
|
+
* @author Denzy ZeroDay
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const default_config = {
|
|
16
|
+
enabled: false,
|
|
17
|
+
enable_circadian_rhythm: true,
|
|
18
|
+
timezone: 'UTC',
|
|
19
|
+
activity_curve: 'office',
|
|
20
|
+
circadian: { enabled: true, profile: 'default', timezone: 'UTC' },
|
|
21
|
+
distraction_pause_probability: 0.05,
|
|
22
|
+
distraction_pause_min_ms: 300000,
|
|
23
|
+
distraction_pause_max_ms: 1200000,
|
|
24
|
+
read_receipt_delay_min_ms: 3000,
|
|
25
|
+
read_receipt_delay_max_ms: 45000,
|
|
26
|
+
read_receipt_skip_probability: 0.15,
|
|
27
|
+
offline_gap_probability: 0.03,
|
|
28
|
+
offline_gap_min_ms: 300000,
|
|
29
|
+
offline_gap_max_ms: 900000,
|
|
30
|
+
enable_typing_model: true,
|
|
31
|
+
typing_wpm: 45,
|
|
32
|
+
typing_wpm_std_dev: 15,
|
|
33
|
+
think_pause_probability: 0.08,
|
|
34
|
+
think_pause_min_ms: 800,
|
|
35
|
+
think_pause_max_ms: 3500,
|
|
36
|
+
intermittent_paused_probability: 0.4,
|
|
37
|
+
typing_max_ms: 90000,
|
|
38
|
+
typing_min_ms: 600
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ACTIVITY_CURVES = {
|
|
42
|
+
office: [
|
|
43
|
+
0.1,
|
|
44
|
+
0.1,
|
|
45
|
+
0.1,
|
|
46
|
+
0.1,
|
|
47
|
+
0.1,
|
|
48
|
+
0.1,
|
|
49
|
+
0.1,
|
|
50
|
+
0.1, // 0-7: night quiet
|
|
51
|
+
0.5,
|
|
52
|
+
0.5, // 8-9: morning ramp
|
|
53
|
+
0.95,
|
|
54
|
+
0.95, // 10-11: morning peak
|
|
55
|
+
0.6, // 12: lunch dip
|
|
56
|
+
0.9,
|
|
57
|
+
0.9,
|
|
58
|
+
0.9,
|
|
59
|
+
0.9, // 13-16: afternoon
|
|
60
|
+
0.6,
|
|
61
|
+
0.6, // 17-18: wind-down
|
|
62
|
+
0.4,
|
|
63
|
+
0.4, // 19-20: evening
|
|
64
|
+
0.2,
|
|
65
|
+
0.2,
|
|
66
|
+
0.2,
|
|
67
|
+
0.2 // 21-24: taper
|
|
68
|
+
],
|
|
69
|
+
social: [
|
|
70
|
+
0.1,
|
|
71
|
+
0.1,
|
|
72
|
+
0.1,
|
|
73
|
+
0.1,
|
|
74
|
+
0.1,
|
|
75
|
+
0.1,
|
|
76
|
+
0.1,
|
|
77
|
+
0.1, // 0-7: night quiet
|
|
78
|
+
0.3,
|
|
79
|
+
0.4, // 8-9: slow start
|
|
80
|
+
0.7,
|
|
81
|
+
0.8, // 10-11: ramp up
|
|
82
|
+
0.5, // 12: lunch
|
|
83
|
+
0.7,
|
|
84
|
+
0.7, // 13-14: afternoon
|
|
85
|
+
0.4, // 15: tea time dip
|
|
86
|
+
0.8,
|
|
87
|
+
0.9,
|
|
88
|
+
0.9, // 16-18: active
|
|
89
|
+
0.6, // 19: dinner dip
|
|
90
|
+
0.8,
|
|
91
|
+
0.85,
|
|
92
|
+
0.9,
|
|
93
|
+
0.95,
|
|
94
|
+
1 // 20-24: evening peak
|
|
95
|
+
],
|
|
96
|
+
global: [
|
|
97
|
+
0.5,
|
|
98
|
+
0.5,
|
|
99
|
+
0.5,
|
|
100
|
+
0.5,
|
|
101
|
+
0.5,
|
|
102
|
+
0.5, // 0-5: night
|
|
103
|
+
0.4,
|
|
104
|
+
0.4, // 6-7: dawn dip
|
|
105
|
+
0.6,
|
|
106
|
+
0.7,
|
|
107
|
+
0.8,
|
|
108
|
+
0.8, // 8-11: morning
|
|
109
|
+
0.6, // 12: lunch
|
|
110
|
+
0.8,
|
|
111
|
+
0.8,
|
|
112
|
+
0.8,
|
|
113
|
+
0.8, // 13-16: afternoon
|
|
114
|
+
0.7,
|
|
115
|
+
0.7, // 17-18: evening
|
|
116
|
+
0.6,
|
|
117
|
+
0.5,
|
|
118
|
+
0.5,
|
|
119
|
+
0.5,
|
|
120
|
+
0.5,
|
|
121
|
+
0.5 // 19-24: night taper
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
exports.ACTIVITY_CURVES = ACTIVITY_CURVES
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Compute the circadian activity multiplier for a given moment.
|
|
128
|
+
* >1 = slower/less active (night), ~1 = normal, <1 would mean faster (not used here).
|
|
129
|
+
*/
|
|
130
|
+
function get_circadian_multiplier(date = new Date(), profile = 'default', timezone) {
|
|
131
|
+
if (profile === 'always_on') return 1
|
|
132
|
+
|
|
133
|
+
let hour
|
|
134
|
+
if (timezone) {
|
|
135
|
+
try {
|
|
136
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
137
|
+
timeZone: timezone,
|
|
138
|
+
hour: 'numeric',
|
|
139
|
+
hour12: false
|
|
140
|
+
})
|
|
141
|
+
const parts = formatter.formatToParts(date)
|
|
142
|
+
const hour_part = parts.find((p) => p.type === 'hour')
|
|
143
|
+
hour = hour_part ? parseInt(hour_part.value, 10) : date.getHours()
|
|
144
|
+
} catch {
|
|
145
|
+
hour = date.getHours()
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
hour = date.getHours()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let shifted_hour = hour
|
|
152
|
+
if (profile === 'nightOwl') shifted_hour = (hour - 3 + 24) % 24
|
|
153
|
+
else if (profile === 'earlyBird') shifted_hour = (hour + 2) % 24
|
|
154
|
+
|
|
155
|
+
if (shifted_hour >= 9 && shifted_hour < 22) {
|
|
156
|
+
const t = (shifted_hour - 9) / 13
|
|
157
|
+
return 1 + 0.2 * Math.cos(2 * Math.PI * t)
|
|
158
|
+
} else if (shifted_hour >= 22 && shifted_hour < 24) {
|
|
159
|
+
const t = (shifted_hour - 22) / 2
|
|
160
|
+
return 1.2 + 1.3 * t
|
|
161
|
+
} else if (shifted_hour >= 0 && shifted_hour < 2) {
|
|
162
|
+
const t = shifted_hour / 2
|
|
163
|
+
return 2.5 + 1.5 * t
|
|
164
|
+
} else if (shifted_hour >= 2 && shifted_hour < 6) {
|
|
165
|
+
const t = (shifted_hour - 2) / 4
|
|
166
|
+
return 5 + 1 * Math.cos(Math.PI * t)
|
|
167
|
+
} else {
|
|
168
|
+
const t = (shifted_hour - 6) / 3
|
|
169
|
+
return 4 - 3 * t
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.get_circadian_multiplier = get_circadian_multiplier
|
|
173
|
+
|
|
174
|
+
class presence_choreographer {
|
|
175
|
+
constructor(config = {}) {
|
|
176
|
+
this.config = {
|
|
177
|
+
...default_config,
|
|
178
|
+
...config,
|
|
179
|
+
circadian: { ...default_config.circadian, ...(config.circadian || {}) }
|
|
180
|
+
}
|
|
181
|
+
this.stats = {
|
|
182
|
+
distractionPausesInjected: 0,
|
|
183
|
+
offlineGapsInjected: 0,
|
|
184
|
+
readReceiptsDelayed: 0,
|
|
185
|
+
readReceiptsSkipped: 0,
|
|
186
|
+
typingPlansComputed: 0,
|
|
187
|
+
typingPlansExecuted: 0,
|
|
188
|
+
totalTypingTimeMs: 0
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get current activity factor (0.1 to 1.0).
|
|
194
|
+
* Higher = more active = shorter delays. If circadian disabled, returns 1.0.
|
|
195
|
+
*/
|
|
196
|
+
get_current_activity_factor() {
|
|
197
|
+
if (!this.config.enabled || !this.config.enable_circadian_rhythm) return 1
|
|
198
|
+
const hour = this.get_local_hour()
|
|
199
|
+
const curve = ACTIVITY_CURVES[this.config.activity_curve]
|
|
200
|
+
return curve[hour] || 0.5
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Check if should pause for distraction. Returns { pause, duration_ms } */
|
|
204
|
+
should_pause_for_distraction() {
|
|
205
|
+
if (!this.config.enabled) return { pause: false, duration_ms: 0 }
|
|
206
|
+
if (Math.random() < this.config.distraction_pause_probability) {
|
|
207
|
+
const duration_ms = this.random_between(
|
|
208
|
+
this.config.distraction_pause_min_ms,
|
|
209
|
+
this.config.distraction_pause_max_ms
|
|
210
|
+
)
|
|
211
|
+
this.stats.distractionPausesInjected++
|
|
212
|
+
return { pause: true, duration_ms }
|
|
213
|
+
}
|
|
214
|
+
return { pause: false, duration_ms: 0 }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Check if should take offline gap. Returns { offline, duration_ms } */
|
|
218
|
+
should_take_offline_gap() {
|
|
219
|
+
if (!this.config.enabled) return { offline: false, duration_ms: 0 }
|
|
220
|
+
if (Math.random() < this.config.offline_gap_probability) {
|
|
221
|
+
const duration_ms = this.random_between(
|
|
222
|
+
this.config.offline_gap_min_ms,
|
|
223
|
+
this.config.offline_gap_max_ms
|
|
224
|
+
)
|
|
225
|
+
this.stats.offlineGapsInjected++
|
|
226
|
+
return { offline: true, duration_ms }
|
|
227
|
+
}
|
|
228
|
+
return { offline: false, duration_ms: 0 }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check if should mark message as read.
|
|
233
|
+
* Returns { mark: false } if skip probability hit, else { mark: true, delay_ms }.
|
|
234
|
+
* Applies circadian multiplier to delay.
|
|
235
|
+
*/
|
|
236
|
+
should_mark_read() {
|
|
237
|
+
if (!this.config.enabled) return { mark: true, delay_ms: 0 }
|
|
238
|
+
if (Math.random() < this.config.read_receipt_skip_probability) {
|
|
239
|
+
this.stats.readReceiptsSkipped++
|
|
240
|
+
return { mark: false, delay_ms: 0 }
|
|
241
|
+
}
|
|
242
|
+
const base_delay_ms = this.random_between(
|
|
243
|
+
this.config.read_receipt_delay_min_ms,
|
|
244
|
+
this.config.read_receipt_delay_max_ms
|
|
245
|
+
)
|
|
246
|
+
let delay_ms = base_delay_ms
|
|
247
|
+
if (this.config.circadian.enabled) {
|
|
248
|
+
const multiplier = get_circadian_multiplier(
|
|
249
|
+
new Date(),
|
|
250
|
+
this.config.circadian.profile,
|
|
251
|
+
this.config.circadian.timezone
|
|
252
|
+
)
|
|
253
|
+
delay_ms = Math.floor(base_delay_ms * multiplier)
|
|
254
|
+
}
|
|
255
|
+
this.stats.readReceiptsDelayed++
|
|
256
|
+
return { mark: true, delay_ms }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Compute realistic typing duration for a message of given length.
|
|
261
|
+
* Includes Gaussian WPM variance + think-pause injection + circadian timing multiplier.
|
|
262
|
+
* Returns a "typing plan": array of { state, duration_ms } steps the caller should execute sequentially.
|
|
263
|
+
*
|
|
264
|
+
* plan = [
|
|
265
|
+
* { state: 'composing', duration_ms: 4200 },
|
|
266
|
+
* { state: 'paused', duration_ms: 950 }, // think pause
|
|
267
|
+
* { state: 'composing', duration_ms: 6800 },
|
|
268
|
+
* { state: 'paused', duration_ms: 600 }, // brief stop before send
|
|
269
|
+
* ]
|
|
270
|
+
*/
|
|
271
|
+
compute_typing_plan(message_length) {
|
|
272
|
+
if (!this.config.enabled || !this.config.enable_typing_model) {
|
|
273
|
+
return [{ state: 'composing', duration_ms: this.config.typing_min_ms }]
|
|
274
|
+
}
|
|
275
|
+
this.stats.typingPlansComputed++
|
|
276
|
+
if (message_length === 0) {
|
|
277
|
+
return [{ state: 'composing', duration_ms: this.config.typing_min_ms }]
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const wpm_sample = this.clamp(
|
|
281
|
+
this.gaussian_sample(this.config.typing_wpm, this.config.typing_wpm_std_dev),
|
|
282
|
+
10,
|
|
283
|
+
120
|
|
284
|
+
)
|
|
285
|
+
const cps = (wpm_sample * 5) / 60
|
|
286
|
+
const base_ms = (message_length / cps) * 1000
|
|
287
|
+
|
|
288
|
+
let circadian_multiplier = 1
|
|
289
|
+
if (this.config.circadian.enabled) {
|
|
290
|
+
circadian_multiplier = get_circadian_multiplier(
|
|
291
|
+
new Date(),
|
|
292
|
+
this.config.circadian.profile,
|
|
293
|
+
this.config.circadian.timezone
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const target_ms = this.clamp(
|
|
298
|
+
base_ms * circadian_multiplier,
|
|
299
|
+
this.config.typing_min_ms,
|
|
300
|
+
this.config.typing_max_ms
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
const plan = []
|
|
304
|
+
let remaining_budget = target_ms
|
|
305
|
+
let position = 0
|
|
306
|
+
const chunk_size = 10
|
|
307
|
+
const num_chunks = Math.max(1, Math.ceil(message_length / chunk_size))
|
|
308
|
+
|
|
309
|
+
for (let i = 0; i < num_chunks && remaining_budget > 0; i++) {
|
|
310
|
+
const chars_in_chunk = Math.min(chunk_size, message_length - position)
|
|
311
|
+
const remaining_chunks = num_chunks - i
|
|
312
|
+
const chunk_budget = remaining_budget / remaining_chunks
|
|
313
|
+
const chunk_typing_ms = Math.floor(Math.min(chunk_budget, remaining_budget))
|
|
314
|
+
if (chunk_typing_ms <= 0) break
|
|
315
|
+
|
|
316
|
+
if (
|
|
317
|
+
i > 0 &&
|
|
318
|
+
i < num_chunks - 1 &&
|
|
319
|
+
Math.random() < this.config.think_pause_probability
|
|
320
|
+
) {
|
|
321
|
+
plan.push({ state: 'composing', duration_ms: chunk_typing_ms })
|
|
322
|
+
remaining_budget -= chunk_typing_ms
|
|
323
|
+
const base_pause_ms = this.random_between(
|
|
324
|
+
this.config.think_pause_min_ms,
|
|
325
|
+
this.config.think_pause_max_ms
|
|
326
|
+
)
|
|
327
|
+
const pause_ms = Math.floor(base_pause_ms * circadian_multiplier)
|
|
328
|
+
plan.push({ state: 'paused', duration_ms: pause_ms })
|
|
329
|
+
} else {
|
|
330
|
+
if (plan.length === 0 || plan[plan.length - 1].state === 'paused') {
|
|
331
|
+
plan.push({ state: 'composing', duration_ms: chunk_typing_ms })
|
|
332
|
+
} else {
|
|
333
|
+
plan[plan.length - 1].duration_ms += chunk_typing_ms
|
|
334
|
+
}
|
|
335
|
+
remaining_budget -= chunk_typing_ms
|
|
336
|
+
}
|
|
337
|
+
position += chars_in_chunk
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (Math.random() < this.config.intermittent_paused_probability) {
|
|
341
|
+
const base_final_pause_ms = this.random_between(200, 800)
|
|
342
|
+
const final_pause_ms = Math.floor(base_final_pause_ms * circadian_multiplier)
|
|
343
|
+
plan.push({ state: 'paused', duration_ms: final_pause_ms })
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (plan.length === 0 || !plan.some((step) => step.state === 'composing')) {
|
|
347
|
+
return [{ state: 'composing', duration_ms: this.config.typing_min_ms }]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return plan
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Execute a typing plan against a Baileys-shaped sock with sendPresenceUpdate(state, jid).
|
|
355
|
+
* Awaits each step's duration. Updates stats.
|
|
356
|
+
*
|
|
357
|
+
* await choreographer.execute_typing_plan(sock, jid, plan)
|
|
358
|
+
* await sock.sendMessage(jid, content)
|
|
359
|
+
*/
|
|
360
|
+
async execute_typing_plan(sock, jid, plan, options) {
|
|
361
|
+
this.stats.typingPlansExecuted++
|
|
362
|
+
for (const step of plan) {
|
|
363
|
+
if (options?.signal?.aborted) {
|
|
364
|
+
await Promise.resolve(sock.sendPresenceUpdate('paused', jid))
|
|
365
|
+
throw new Error('Typing plan aborted')
|
|
366
|
+
}
|
|
367
|
+
await Promise.resolve(sock.sendPresenceUpdate(step.state, jid))
|
|
368
|
+
await this.sleep(step.duration_ms)
|
|
369
|
+
this.stats.totalTypingTimeMs += step.duration_ms
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/** Get statistics */
|
|
374
|
+
get_stats() {
|
|
375
|
+
return {
|
|
376
|
+
currentActivityFactor: this.get_current_activity_factor(),
|
|
377
|
+
distractionPausesInjected: this.stats.distractionPausesInjected,
|
|
378
|
+
offlineGapsInjected: this.stats.offlineGapsInjected,
|
|
379
|
+
readReceiptsDelayed: this.stats.readReceiptsDelayed,
|
|
380
|
+
readReceiptsSkipped: this.stats.readReceiptsSkipped,
|
|
381
|
+
currentHourLocal: this.get_local_hour(),
|
|
382
|
+
typingPlansComputed: this.stats.typingPlansComputed,
|
|
383
|
+
typingPlansExecuted: this.stats.typingPlansExecuted,
|
|
384
|
+
totalTypingTimeMs: this.stats.totalTypingTimeMs
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Reset statistics */
|
|
389
|
+
reset() {
|
|
390
|
+
this.stats = {
|
|
391
|
+
distractionPausesInjected: 0,
|
|
392
|
+
offlineGapsInjected: 0,
|
|
393
|
+
readReceiptsDelayed: 0,
|
|
394
|
+
readReceiptsSkipped: 0,
|
|
395
|
+
typingPlansComputed: 0,
|
|
396
|
+
typingPlansExecuted: 0,
|
|
397
|
+
totalTypingTimeMs: 0
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Private helpers
|
|
402
|
+
get_local_hour() {
|
|
403
|
+
try {
|
|
404
|
+
const formatter = new Intl.DateTimeFormat('en-US', {
|
|
405
|
+
timeZone: this.config.timezone,
|
|
406
|
+
hour: 'numeric',
|
|
407
|
+
hour12: false
|
|
408
|
+
})
|
|
409
|
+
const parts = formatter.formatToParts(new Date())
|
|
410
|
+
const hour_part = parts.find((p) => p.type === 'hour')
|
|
411
|
+
if (hour_part) return parseInt(hour_part.value, 10)
|
|
412
|
+
} catch {}
|
|
413
|
+
return new Date().getUTCHours()
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
random_between(min, max) {
|
|
417
|
+
return Math.floor(Math.random() * (max - min + 1)) + min
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
clamp(value, min, max) {
|
|
421
|
+
return Math.max(min, Math.min(max, value))
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** Generate Gaussian sample using Box-Muller transform. Returns a sample from N(mean, std_dev). */
|
|
425
|
+
gaussian_sample(mean, std_dev) {
|
|
426
|
+
const u1 = Math.random()
|
|
427
|
+
const u2 = Math.random()
|
|
428
|
+
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2)
|
|
429
|
+
return mean + z0 * std_dev
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
sleep(ms) {
|
|
433
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
exports.presence_choreographer = presence_choreographer
|
|
438
|
+
module.exports = { presence_choreographer, get_circadian_multiplier, ACTIVITY_CURVES }
|