@nerxa/socketon 0.0.0-stage → 1.21.1
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/EXPERIMENTAL.md +350 -0
- package/LICENSE +24 -0
- package/README.md +6317 -2
- package/WAProto/index.d.ts +17301 -0
- package/WAProto/index.js +125088 -0
- package/engine-requirements.js +14 -0
- package/package.json +125 -4
- package/src/Defaults/index.d.ts +152 -0
- package/src/Defaults/index.js +164 -0
- package/src/MessageBuilder/bot-signature.d.ts +22 -0
- package/src/MessageBuilder/bot-signature.js +122 -0
- package/src/MessageBuilder/extras.d.ts +449 -0
- package/src/MessageBuilder/extras.js +1356 -0
- package/src/MessageBuilder/index.d.ts +210 -0
- package/src/MessageBuilder/index.js +3594 -0
- package/src/MessageBuilder/metaai.d.ts +438 -0
- package/src/MessageBuilder/metaai.js +890 -0
- package/src/Signal/Group/ciphertext-message.d.ts +9 -0
- package/src/Signal/Group/ciphertext-message.js +11 -0
- package/src/Signal/Group/group-session-builder.d.ts +7 -0
- package/src/Signal/Group/group-session-builder.js +27 -0
- package/src/Signal/Group/group_cipher.d.ts +11 -0
- package/src/Signal/Group/group_cipher.js +78 -0
- package/src/Signal/Group/index.d.ts +11 -0
- package/src/Signal/Group/index.js +11 -0
- package/src/Signal/Group/keyhelper.d.ts +6 -0
- package/src/Signal/Group/keyhelper.js +17 -0
- package/src/Signal/Group/sender-chain-key.d.ts +13 -0
- package/src/Signal/Group/sender-chain-key.js +25 -0
- package/src/Signal/Group/sender-key-distribution-message.d.ts +16 -0
- package/src/Signal/Group/sender-key-distribution-message.js +62 -0
- package/src/Signal/Group/sender-key-message.d.ts +18 -0
- package/src/Signal/Group/sender-key-message.js +65 -0
- package/src/Signal/Group/sender-key-name.d.ts +11 -0
- package/src/Signal/Group/sender-key-name.js +47 -0
- package/src/Signal/Group/sender-key-record.d.ts +12 -0
- package/src/Signal/Group/sender-key-record.js +40 -0
- package/src/Signal/Group/sender-key-state.d.ts +16 -0
- package/src/Signal/Group/sender-key-state.js +83 -0
- package/src/Signal/Group/sender-message-key.d.ts +11 -0
- package/src/Signal/Group/sender-message-key.js +25 -0
- package/src/Signal/libsignal.d.ts +54 -0
- package/src/Signal/libsignal.js +427 -0
- package/src/Signal/lid-mapping.d.ts +20 -0
- package/src/Signal/lid-mapping.js +274 -0
- package/src/Socket/Client/index.d.ts +2 -0
- package/src/Socket/Client/index.js +3 -0
- package/src/Socket/Client/tcp.js +177 -0
- package/src/Socket/Client/types.d.ts +5 -0
- package/src/Socket/Client/types.js +9 -0
- package/src/Socket/Client/websocket.d.ts +12 -0
- package/src/Socket/Client/websocket.js +53 -0
- package/src/Socket/business.d.ts +431 -0
- package/src/Socket/business.js +379 -0
- package/src/Socket/chats.d.ts +247 -0
- package/src/Socket/chats.js +1484 -0
- package/src/Socket/communities.d.ts +598 -0
- package/src/Socket/communities.js +421 -0
- package/src/Socket/email.js +145 -0
- package/src/Socket/groups.d.ts +298 -0
- package/src/Socket/groups.js +339 -0
- package/src/Socket/index.d.ts +581 -0
- package/src/Socket/index.js +77 -0
- package/src/Socket/messages-recv.d.ts +370 -0
- package/src/Socket/messages-recv.js +1864 -0
- package/src/Socket/messages-send.d.ts +390 -0
- package/src/Socket/messages-send.js +1574 -0
- package/src/Socket/mex.d.ts +1 -0
- package/src/Socket/mex.js +44 -0
- package/src/Socket/mobile-builders.js +72 -0
- package/src/Socket/mobile.js +424 -0
- package/src/Socket/newsletter.d.ts +468 -0
- package/src/Socket/newsletter.js +671 -0
- package/src/Socket/socket.d.ts +77 -0
- package/src/Socket/socket.js +1106 -0
- package/src/Store/index.d.ts +3 -0
- package/src/Store/index.js +3 -0
- package/src/Store/make-in-memory-store.d.ts +62 -0
- package/src/Store/make-in-memory-store.js +396 -0
- package/src/Store/make-ordered-dictionary.d.ts +12 -0
- package/src/Store/make-ordered-dictionary.js +78 -0
- package/src/Store/object-repository.d.ts +10 -0
- package/src/Store/object-repository.js +23 -0
- package/src/Types/Auth.d.ts +1 -0
- package/src/Types/Auth.js +1 -0
- package/src/Types/Bussines.d.ts +1 -0
- package/src/Types/Bussines.js +1 -0
- package/src/Types/Call.d.ts +1 -0
- package/src/Types/Call.js +1 -0
- package/src/Types/Chat.d.ts +2 -0
- package/src/Types/Chat.js +24 -0
- package/src/Types/Contact.d.ts +1 -0
- package/src/Types/Contact.js +1 -0
- package/src/Types/Events.d.ts +1 -0
- package/src/Types/Events.js +0 -0
- package/src/Types/GroupMetadata.d.ts +5 -0
- package/src/Types/GroupMetadata.js +6 -0
- package/src/Types/Label.d.ts +2 -0
- package/src/Types/Label.js +24 -0
- package/src/Types/LabelAssociation.d.ts +2 -0
- package/src/Types/LabelAssociation.js +6 -0
- package/src/Types/Message.d.ts +13 -0
- package/src/Types/Message.js +23 -0
- package/src/Types/Mex.d.ts +2 -0
- package/src/Types/Mex.js +95 -0
- package/src/Types/Product.d.ts +1 -0
- package/src/Types/Product.js +1 -0
- package/src/Types/Signal.d.ts +1 -0
- package/src/Types/Signal.js +0 -0
- package/src/Types/Socket.d.ts +1 -0
- package/src/Types/Socket.js +0 -0
- package/src/Types/State.d.ts +5 -0
- package/src/Types/State.js +54 -0
- package/src/Types/USync.d.ts +1 -0
- package/src/Types/USync.js +0 -0
- package/src/Types/index.d.ts +13 -0
- package/src/Types/index.js +25 -0
- package/src/Utils/auth-store.d.ts +29 -0
- package/src/Utils/auth-store.js +76 -0
- package/src/Utils/auth-utils.d.ts +58 -0
- package/src/Utils/auth-utils.js +273 -0
- package/src/Utils/browser-utils.d.ts +9 -0
- package/src/Utils/browser-utils.js +28 -0
- package/src/Utils/business.d.ts +49 -0
- package/src/Utils/business.js +226 -0
- package/src/Utils/chat-utils.d.ts +408 -0
- package/src/Utils/chat-utils.js +846 -0
- package/src/Utils/companion-reg-client-utils.d.ts +4 -0
- package/src/Utils/companion-reg-client-utils.js +39 -0
- package/src/Utils/crypto.d.ts +39 -0
- package/src/Utils/crypto.js +110 -0
- package/src/Utils/decode-wa-message.d.ts +99 -0
- package/src/Utils/decode-wa-message.js +373 -0
- package/src/Utils/event-buffer.d.ts +22 -0
- package/src/Utils/event-buffer.js +624 -0
- package/src/Utils/generics.d.ts +63 -0
- package/src/Utils/generics.js +375 -0
- package/src/Utils/group-metadata-cache.d.ts +4 -0
- package/src/Utils/group-metadata-cache.js +25 -0
- package/src/Utils/history.d.ts +75 -0
- package/src/Utils/history.js +131 -0
- package/src/Utils/html-app.d.ts +19 -0
- package/src/Utils/html-app.js +96 -0
- package/src/Utils/html-multiplayer.d.ts +10 -0
- package/src/Utils/html-multiplayer.js +94 -0
- package/src/Utils/identity-change-handler.d.ts +13 -0
- package/src/Utils/identity-change-handler.js +48 -0
- package/src/Utils/index.d.ts +44 -0
- package/src/Utils/index.js +44 -0
- package/src/Utils/link-preview-metadata.d.ts +47 -0
- package/src/Utils/link-preview-metadata.js +88 -0
- package/src/Utils/link-preview.d.ts +12 -0
- package/src/Utils/link-preview.js +79 -0
- package/src/Utils/logger.d.ts +2 -0
- package/src/Utils/logger.js +2 -0
- package/src/Utils/lt-hash.d.ts +6 -0
- package/src/Utils/lt-hash.js +3 -0
- package/src/Utils/make-mutex.d.ts +6 -0
- package/src/Utils/make-mutex.js +32 -0
- package/src/Utils/message-retry-manager.d.ts +79 -0
- package/src/Utils/message-retry-manager.js +255 -0
- package/src/Utils/messages-media.d.ts +136 -0
- package/src/Utils/messages-media.js +814 -0
- package/src/Utils/messages.d.ts +62 -0
- package/src/Utils/messages.js +2223 -0
- package/src/Utils/mobile-companion-crypto.js +191 -0
- package/src/Utils/modern-messages.d.ts +150 -0
- package/src/Utils/modern-messages.js +496 -0
- package/src/Utils/native-flow.d.ts +11 -0
- package/src/Utils/native-flow.js +115 -0
- package/src/Utils/newsletter-status.d.ts +158 -0
- package/src/Utils/newsletter-status.js +651 -0
- package/src/Utils/noise-handler.d.ts +20 -0
- package/src/Utils/noise-handler.js +200 -0
- package/src/Utils/offline-node-processor.d.ts +9 -0
- package/src/Utils/offline-node-processor.js +33 -0
- package/src/Utils/optional-media.d.ts +3 -0
- package/src/Utils/optional-media.js +45 -0
- package/src/Utils/payment-messages.d.ts +66 -0
- package/src/Utils/payment-messages.js +160 -0
- package/src/Utils/pre-key-manager.d.ts +25 -0
- package/src/Utils/pre-key-manager.js +95 -0
- package/src/Utils/process-message.d.ts +60 -0
- package/src/Utils/process-message.js +688 -0
- package/src/Utils/reporting-utils.d.ts +12 -0
- package/src/Utils/reporting-utils.js +256 -0
- package/src/Utils/scheduled-message.d.ts +51 -0
- package/src/Utils/scheduled-message.js +112 -0
- package/src/Utils/sender-key-memory.d.ts +19 -0
- package/src/Utils/sender-key-memory.js +51 -0
- package/src/Utils/signal.d.ts +82 -0
- package/src/Utils/signal.js +193 -0
- package/src/Utils/stanza-ack.d.ts +16 -0
- package/src/Utils/stanza-ack.js +30 -0
- package/src/Utils/status-stickers.d.ts +127 -0
- package/src/Utils/status-stickers.js +260 -0
- package/src/Utils/sync-action-utils.d.ts +2 -0
- package/src/Utils/sync-action-utils.js +44 -0
- package/src/Utils/tc-token-utils.d.ts +29 -0
- package/src/Utils/tc-token-utils.js +155 -0
- package/src/Utils/ttl-cache.d.ts +28 -0
- package/src/Utils/ttl-cache.js +120 -0
- package/src/Utils/use-mongo-auth-state.d.ts +21 -0
- package/src/Utils/use-mongo-auth-state.js +67 -0
- package/src/Utils/use-multi-file-auth-state.d.ts +11 -0
- package/src/Utils/use-multi-file-auth-state.js +106 -0
- package/src/Utils/use-mysql-auth-state.d.ts +19 -0
- package/src/Utils/use-mysql-auth-state.js +79 -0
- package/src/Utils/use-postgres-auth-state.d.ts +19 -0
- package/src/Utils/use-postgres-auth-state.js +79 -0
- package/src/Utils/use-redis-auth-state.d.ts +19 -0
- package/src/Utils/use-redis-auth-state.js +89 -0
- package/src/Utils/use-single-file-auth-state.d.ts +10 -0
- package/src/Utils/use-single-file-auth-state.js +108 -0
- package/src/Utils/use-sqlite-auth-state.d.ts +12 -0
- package/src/Utils/use-sqlite-auth-state.js +120 -0
- package/src/Utils/useNekoDBAuth.d.ts +19 -0
- package/src/Utils/useNekoDBAuth.js +111 -0
- package/src/Utils/username.d.ts +12 -0
- package/src/Utils/username.js +58 -0
- package/src/Utils/validate-connection.d.ts +43 -0
- package/src/Utils/validate-connection.js +277 -0
- package/src/Utils/voice-recognition.d.ts +53 -0
- package/src/Utils/voice-recognition.js +219 -0
- package/src/Voip/audio-feeder.d.ts +24 -0
- package/src/Voip/audio-feeder.js +268 -0
- package/src/Voip/index.d.ts +88 -0
- package/src/Voip/index.js +936 -0
- package/src/Voip/relay-transport.d.ts +5 -0
- package/src/Voip/relay-transport.js +824 -0
- package/src/Voip/signaling.d.ts +11 -0
- package/src/Voip/signaling.js +1099 -0
- package/src/Voip/types.d.ts +2 -0
- package/src/Voip/types.js +12 -0
- package/src/Voip/video-feeder.d.ts +24 -0
- package/src/Voip/video-feeder.js +268 -0
- package/src/Voip/wasm-engine.d.ts +26 -0
- package/src/Voip/wasm-engine.js +1307 -0
- package/src/Voip/worker-bootstrap.js +1023 -0
- package/src/WABinary/constants.d.ts +22 -0
- package/src/WABinary/constants.js +1300 -0
- package/src/WABinary/decode.d.ts +9 -0
- package/src/WABinary/decode.js +261 -0
- package/src/WABinary/encode.d.ts +2 -0
- package/src/WABinary/encode.js +219 -0
- package/src/WABinary/generic-utils.d.ts +76 -0
- package/src/WABinary/generic-utils.js +214 -0
- package/src/WABinary/index.d.ts +5 -0
- package/src/WABinary/index.js +5 -0
- package/src/WABinary/jid-utils.d.ts +30 -0
- package/src/WABinary/jid-utils.js +97 -0
- package/src/WABinary/types.d.ts +1 -0
- package/src/WABinary/types.js +0 -0
- package/src/WAM/BinaryInfo.d.ts +7 -0
- package/src/WAM/BinaryInfo.js +9 -0
- package/src/WAM/constants.d.ts +34926 -0
- package/src/WAM/constants.js +22852 -0
- package/src/WAM/encode.d.ts +1 -0
- package/src/WAM/encode.js +148 -0
- package/src/WAM/index.d.ts +3 -0
- package/src/WAM/index.js +3 -0
- package/src/WAUSync/Protocols/USyncContactProtocol.d.ts +36 -0
- package/src/WAUSync/Protocols/USyncContactProtocol.js +50 -0
- package/src/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -0
- package/src/WAUSync/Protocols/USyncDeviceProtocol.js +51 -0
- package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -0
- package/src/WAUSync/Protocols/USyncDisappearingModeProtocol.js +26 -0
- package/src/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -0
- package/src/WAUSync/Protocols/USyncStatusProtocol.js +37 -0
- package/src/WAUSync/Protocols/USyncUsernameProtocol.d.ts +9 -0
- package/src/WAUSync/Protocols/USyncUsernameProtocol.js +23 -0
- package/src/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +38 -0
- package/src/WAUSync/Protocols/UsyncBotProfileProtocol.js +49 -0
- package/src/WAUSync/Protocols/UsyncLIDProtocol.d.ts +14 -0
- package/src/WAUSync/Protocols/UsyncLIDProtocol.js +28 -0
- package/src/WAUSync/Protocols/index.d.ts +5 -0
- package/src/WAUSync/Protocols/index.js +5 -0
- package/src/WAUSync/USyncQuery.d.ts +20 -0
- package/src/WAUSync/USyncQuery.js +93 -0
- package/src/WAUSync/USyncUser.d.ts +16 -0
- package/src/WAUSync/USyncUser.js +30 -0
- package/src/WAUSync/index.d.ts +3 -0
- package/src/WAUSync/index.js +3 -0
- package/src/assets/wasm/README.md +76 -0
- package/src/assets/wasm/loader.js +5 -0
- package/src/assets/wasm/whatsapp.wasm +0 -0
- package/src/assets/wasm/worker-modules.js +273 -0
- package/src/index.d.ts +43 -0
- package/src/index.js +48 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { createHash, randomUUID } from 'crypto';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import { KEY_BUNDLE_TYPE, WA_ADV_ACCOUNT_SIG_PREFIX, WA_ADV_DEVICE_SIG_PREFIX, WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX } from '../Defaults/index.js';
|
|
5
|
+
import { getBinaryNodeChild, jidDecode, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
6
|
+
import { Curve, hmacSign } from './crypto.js';
|
|
7
|
+
import { encodeBigEndian } from './generics.js';
|
|
8
|
+
import { createSignalIdentity } from './signal.js';
|
|
9
|
+
const getUserAgent = (config) => {
|
|
10
|
+
return {
|
|
11
|
+
appVersion: {
|
|
12
|
+
primary: config.version[0],
|
|
13
|
+
secondary: config.version[1],
|
|
14
|
+
tertiary: config.version[2]
|
|
15
|
+
},
|
|
16
|
+
platform: config.browser[1].toLocaleLowerCase().includes('android')
|
|
17
|
+
? proto.ClientPayload.UserAgent.Platform.ANDROID
|
|
18
|
+
: proto.ClientPayload.UserAgent.Platform.WEB,
|
|
19
|
+
releaseChannel: proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
|
|
20
|
+
osVersion: '0.1',
|
|
21
|
+
device: 'Desktop',
|
|
22
|
+
osBuildNumber: '0.1',
|
|
23
|
+
localeLanguageIso6391: 'en',
|
|
24
|
+
mnc: '000',
|
|
25
|
+
mcc: '000',
|
|
26
|
+
localeCountryIso31661Alpha2: config.countryCode
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
const PLATFORM_MAP = {
|
|
30
|
+
'Mac OS': proto.ClientPayload.WebInfo.WebSubPlatform.DARWIN,
|
|
31
|
+
Windows: proto.ClientPayload.WebInfo.WebSubPlatform.WIN32
|
|
32
|
+
};
|
|
33
|
+
const getWebInfo = (config) => {
|
|
34
|
+
let webSubPlatform = proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER;
|
|
35
|
+
if (config.syncFullHistory &&
|
|
36
|
+
PLATFORM_MAP[config.browser[0]] &&
|
|
37
|
+
config.browser[1] === 'Desktop') {
|
|
38
|
+
webSubPlatform = PLATFORM_MAP[config.browser[0]];
|
|
39
|
+
}
|
|
40
|
+
return { webSubPlatform };
|
|
41
|
+
};
|
|
42
|
+
const getClientPayload = (config) => {
|
|
43
|
+
const payload = {
|
|
44
|
+
connectType: proto.ClientPayload.ConnectType.WIFI_UNKNOWN,
|
|
45
|
+
connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
|
|
46
|
+
userAgent: getUserAgent(config)
|
|
47
|
+
};
|
|
48
|
+
if (!config.browser[1].toLocaleLowerCase().includes('android')) {
|
|
49
|
+
payload.webInfo = getWebInfo(config);
|
|
50
|
+
}
|
|
51
|
+
if (config.pushName) {
|
|
52
|
+
payload.pushName = config.pushName;
|
|
53
|
+
}
|
|
54
|
+
return payload;
|
|
55
|
+
};
|
|
56
|
+
const buildMobileLoginPayload = (userJid, config, deviceInfo) => {
|
|
57
|
+
if (!deviceInfo) {
|
|
58
|
+
throw new Boom('mobile login requires deviceInfo', { statusCode: 400 });
|
|
59
|
+
}
|
|
60
|
+
const { user, device } = jidDecode(userJid);
|
|
61
|
+
const username = +user;
|
|
62
|
+
if (!Number.isSafeInteger(username) || username <= 0) {
|
|
63
|
+
throw new Boom('mobile login requires a valid numeric username', { statusCode: 400 });
|
|
64
|
+
}
|
|
65
|
+
const parseAppVersion = (version) => {
|
|
66
|
+
const parts = String(version || '').split('.');
|
|
67
|
+
const at = (i) => {
|
|
68
|
+
const n = Number(parts[i]);
|
|
69
|
+
return Number.isFinite(n) ? n : undefined;
|
|
70
|
+
};
|
|
71
|
+
return { primary: at(0) ?? 2, secondary: at(1) ?? 0, tertiary: at(2) ?? 0, quaternary: at(3) };
|
|
72
|
+
};
|
|
73
|
+
const version = parseAppVersion(deviceInfo.appVersion);
|
|
74
|
+
const isIos = deviceInfo.os === 'ios';
|
|
75
|
+
const platform = isIos
|
|
76
|
+
? (deviceInfo.business ? proto.ClientPayload.UserAgent.Platform.SMB_IOS : proto.ClientPayload.UserAgent.Platform.IOS)
|
|
77
|
+
: (deviceInfo.business ? proto.ClientPayload.UserAgent.Platform.SMB_ANDROID : proto.ClientPayload.UserAgent.Platform.ANDROID);
|
|
78
|
+
const distributionChannelMap = {
|
|
79
|
+
website: proto.ClientPayload.UserAgent.DistributionChannel.WEBSITE,
|
|
80
|
+
testflight: proto.ClientPayload.UserAgent.DistributionChannel.TESTFLIGHT,
|
|
81
|
+
internal: proto.ClientPayload.UserAgent.DistributionChannel.INTERNAL,
|
|
82
|
+
appstore: proto.ClientPayload.UserAgent.DistributionChannel.APPSTORE
|
|
83
|
+
};
|
|
84
|
+
const userAgent = {
|
|
85
|
+
platform,
|
|
86
|
+
releaseChannel: proto.ClientPayload.UserAgent.ReleaseChannel.RELEASE,
|
|
87
|
+
appVersion: version,
|
|
88
|
+
osVersion: deviceInfo.osVersion,
|
|
89
|
+
manufacturer: deviceInfo.manufacturer,
|
|
90
|
+
device: deviceInfo.device,
|
|
91
|
+
osBuildNumber: deviceInfo.osBuildNumber,
|
|
92
|
+
phoneId: deviceInfo.phoneId || randomUUID(),
|
|
93
|
+
localeLanguageIso6391: deviceInfo.localeLanguageIso6391 || 'en',
|
|
94
|
+
localeCountryIso31661Alpha2: deviceInfo.localeCountryIso31661Alpha2 || 'US',
|
|
95
|
+
deviceType: proto.ClientPayload.UserAgent.DeviceType.PHONE,
|
|
96
|
+
deviceModelType: deviceInfo.deviceModelType
|
|
97
|
+
};
|
|
98
|
+
if (isIos) {
|
|
99
|
+
userAgent.distributionChannel = distributionChannelMap[deviceInfo.distributionChannel || 'appstore'] || distributionChannelMap.appstore;
|
|
100
|
+
} else {
|
|
101
|
+
userAgent.mcc = deviceInfo.mcc || '000';
|
|
102
|
+
userAgent.mnc = deviceInfo.mnc || '000';
|
|
103
|
+
userAgent.deviceBoard = deviceInfo.deviceBoard;
|
|
104
|
+
}
|
|
105
|
+
const payload = {
|
|
106
|
+
passive: config.mobileTransport?.passive === true || deviceInfo.passive === true,
|
|
107
|
+
pull: true,
|
|
108
|
+
product: proto.ClientPayload.Product.WHATSAPP,
|
|
109
|
+
connectType: proto.ClientPayload.ConnectType.CELLULAR_UNKNOWN,
|
|
110
|
+
connectReason: proto.ClientPayload.ConnectReason.USER_ACTIVATED,
|
|
111
|
+
userAgent,
|
|
112
|
+
username,
|
|
113
|
+
device: device || 0,
|
|
114
|
+
lidDbMigrated: false,
|
|
115
|
+
pushName: config.mobileTransport?.pushName || config.pushName
|
|
116
|
+
};
|
|
117
|
+
if (config.mobileTransport?.yearClass) payload.yearClass = config.mobileTransport.yearClass;
|
|
118
|
+
if (config.mobileTransport?.memClass) payload.memClass = config.mobileTransport.memClass;
|
|
119
|
+
return proto.ClientPayload.fromObject(payload);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const generateLoginNode = (userJid, config, deviceInfo) => {
|
|
123
|
+
if (deviceInfo || config?.mobileDeviceInfo || config?.mobileTransport?.deviceInfo) {
|
|
124
|
+
const di = deviceInfo || config?.mobileDeviceInfo || config?.mobileTransport?.deviceInfo;
|
|
125
|
+
return buildMobileLoginPayload(userJid, { ...config, mobileTransport: config?.mobileTransport }, di);
|
|
126
|
+
}
|
|
127
|
+
const { user, device } = jidDecode(userJid);
|
|
128
|
+
const payload = {
|
|
129
|
+
...getClientPayload(config),
|
|
130
|
+
passive: true,
|
|
131
|
+
pull: true,
|
|
132
|
+
username: +user,
|
|
133
|
+
device: device,
|
|
134
|
+
|
|
135
|
+
lidDbMigrated: false
|
|
136
|
+
};
|
|
137
|
+
return proto.ClientPayload.fromObject(payload);
|
|
138
|
+
};
|
|
139
|
+
const getPlatformType = (platform) => {
|
|
140
|
+
const platformType = platform.toUpperCase();
|
|
141
|
+
if (platformType === 'ANDROID') {
|
|
142
|
+
return proto.DeviceProps.PlatformType.ANDROID_PHONE;
|
|
143
|
+
}
|
|
144
|
+
return (proto.DeviceProps.PlatformType[platformType] ||
|
|
145
|
+
proto.DeviceProps.PlatformType.CHROME);
|
|
146
|
+
};
|
|
147
|
+
export const generateRegistrationNode = ({ registrationId, signedPreKey, signedIdentityKey }, config) => {
|
|
148
|
+
|
|
149
|
+
const appVersionBuf = createHash('md5')
|
|
150
|
+
.update(config.version.join('.'))
|
|
151
|
+
.digest();
|
|
152
|
+
const companion = {
|
|
153
|
+
os: config.browser[0],
|
|
154
|
+
platformType: getPlatformType(config.browser[1]),
|
|
155
|
+
requireFullSync: config.syncFullHistory,
|
|
156
|
+
historySyncConfig: {
|
|
157
|
+
storageQuotaMb: 10240,
|
|
158
|
+
inlineInitialPayloadInE2EeMsg: true,
|
|
159
|
+
recentSyncDaysLimit: undefined,
|
|
160
|
+
supportCallLogHistory: false,
|
|
161
|
+
supportBotUserAgentChatHistory: true,
|
|
162
|
+
supportCagReactionsAndPolls: true,
|
|
163
|
+
supportBizHostedMsg: true,
|
|
164
|
+
supportRecentSyncChunkMessageCountTuning: true,
|
|
165
|
+
supportHostedGroupMsg: true,
|
|
166
|
+
supportFbidBotChatHistory: true,
|
|
167
|
+
supportAddOnHistorySyncMigration: undefined,
|
|
168
|
+
supportMessageAssociation: true,
|
|
169
|
+
supportGroupHistory: false,
|
|
170
|
+
onDemandReady: undefined,
|
|
171
|
+
supportGuestChat: undefined
|
|
172
|
+
},
|
|
173
|
+
version: {
|
|
174
|
+
primary: 10,
|
|
175
|
+
secondary: 15,
|
|
176
|
+
tertiary: 7
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const companionProto = proto.DeviceProps.encode(companion).finish();
|
|
180
|
+
const registerPayload = {
|
|
181
|
+
...getClientPayload(config),
|
|
182
|
+
passive: false,
|
|
183
|
+
pull: false,
|
|
184
|
+
devicePairingData: {
|
|
185
|
+
buildHash: appVersionBuf,
|
|
186
|
+
deviceProps: companionProto,
|
|
187
|
+
eRegid: encodeBigEndian(registrationId),
|
|
188
|
+
eKeytype: KEY_BUNDLE_TYPE,
|
|
189
|
+
eIdent: signedIdentityKey.public,
|
|
190
|
+
eSkeyId: encodeBigEndian(signedPreKey.keyId, 3),
|
|
191
|
+
eSkeyVal: signedPreKey.keyPair.public,
|
|
192
|
+
eSkeySig: signedPreKey.signature
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
return proto.ClientPayload.fromObject(registerPayload);
|
|
196
|
+
};
|
|
197
|
+
export const configureSuccessfulPairing = (stanza, { advSecretKey, signedIdentityKey, signalIdentities }) => {
|
|
198
|
+
const msgId = stanza.attrs.id;
|
|
199
|
+
const pairSuccessNode = getBinaryNodeChild(stanza, 'pair-success');
|
|
200
|
+
const deviceIdentityNode = getBinaryNodeChild(pairSuccessNode, 'device-identity');
|
|
201
|
+
const platformNode = getBinaryNodeChild(pairSuccessNode, 'platform');
|
|
202
|
+
const deviceNode = getBinaryNodeChild(pairSuccessNode, 'device');
|
|
203
|
+
const businessNode = getBinaryNodeChild(pairSuccessNode, 'biz');
|
|
204
|
+
if (!deviceIdentityNode || !deviceNode) {
|
|
205
|
+
throw new Boom('Missing device-identity or device in pair success node', { data: stanza });
|
|
206
|
+
}
|
|
207
|
+
const bizName = businessNode?.attrs.name;
|
|
208
|
+
const jid = deviceNode.attrs.jid;
|
|
209
|
+
const lid = deviceNode.attrs.lid;
|
|
210
|
+
const { details, hmac, accountType } = proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content);
|
|
211
|
+
let hmacPrefix = Buffer.from([]);
|
|
212
|
+
if (accountType !== undefined && accountType === proto.ADVEncryptionType.HOSTED) {
|
|
213
|
+
hmacPrefix = WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX;
|
|
214
|
+
}
|
|
215
|
+
const advSign = hmacSign(Buffer.concat([hmacPrefix, details]), Buffer.from(advSecretKey, 'base64'));
|
|
216
|
+
if (Buffer.compare(hmac, advSign) !== 0) {
|
|
217
|
+
throw new Boom('Invalid account signature');
|
|
218
|
+
}
|
|
219
|
+
const account = proto.ADVSignedDeviceIdentity.decode(details);
|
|
220
|
+
const { accountSignatureKey, accountSignature, details: deviceDetails } = account;
|
|
221
|
+
const deviceIdentity = proto.ADVDeviceIdentity.decode(deviceDetails);
|
|
222
|
+
const accountSignaturePrefix = deviceIdentity.deviceType === proto.ADVEncryptionType.HOSTED
|
|
223
|
+
? WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX
|
|
224
|
+
: WA_ADV_ACCOUNT_SIG_PREFIX;
|
|
225
|
+
const accountMsg = Buffer.concat([accountSignaturePrefix, deviceDetails, signedIdentityKey.public]);
|
|
226
|
+
if (!Curve.verify(accountSignatureKey, accountMsg, accountSignature)) {
|
|
227
|
+
throw new Boom('Failed to verify account signature');
|
|
228
|
+
}
|
|
229
|
+
const deviceMsg = Buffer.concat([
|
|
230
|
+
WA_ADV_DEVICE_SIG_PREFIX,
|
|
231
|
+
deviceDetails,
|
|
232
|
+
signedIdentityKey.public,
|
|
233
|
+
accountSignatureKey
|
|
234
|
+
]);
|
|
235
|
+
account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg);
|
|
236
|
+
const identity = createSignalIdentity(lid, accountSignatureKey);
|
|
237
|
+
const accountEnc = encodeSignedDeviceIdentity(account, false);
|
|
238
|
+
const reply = {
|
|
239
|
+
tag: 'iq',
|
|
240
|
+
attrs: {
|
|
241
|
+
to: S_WHATSAPP_NET,
|
|
242
|
+
type: 'result',
|
|
243
|
+
id: msgId
|
|
244
|
+
},
|
|
245
|
+
content: [
|
|
246
|
+
{
|
|
247
|
+
tag: 'pair-device-sign',
|
|
248
|
+
attrs: {},
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
tag: 'device-identity',
|
|
252
|
+
attrs: { 'key-index': deviceIdentity.keyIndex.toString() },
|
|
253
|
+
content: accountEnc
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
};
|
|
259
|
+
const authUpdate = {
|
|
260
|
+
account,
|
|
261
|
+
me: { id: jid, name: bizName, lid },
|
|
262
|
+
signalIdentities: [...(signalIdentities || []), identity],
|
|
263
|
+
platform: platformNode?.attrs.name
|
|
264
|
+
};
|
|
265
|
+
return {
|
|
266
|
+
creds: authUpdate,
|
|
267
|
+
reply
|
|
268
|
+
};
|
|
269
|
+
};
|
|
270
|
+
export const encodeSignedDeviceIdentity = (account, includeSignatureKey) => {
|
|
271
|
+
account = { ...account };
|
|
272
|
+
|
|
273
|
+
if (!includeSignatureKey || !account.accountSignatureKey?.length) {
|
|
274
|
+
account.accountSignatureKey = null;
|
|
275
|
+
}
|
|
276
|
+
return proto.ADVSignedDeviceIdentity.encode(account).finish();
|
|
277
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type VoiceRecognitionContext = {
|
|
2
|
+
message: any;
|
|
3
|
+
audioMessage: any;
|
|
4
|
+
chatJid: string;
|
|
5
|
+
senderJid: string;
|
|
6
|
+
isGroup: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type VoiceTranscriptionInput = VoiceRecognitionContext & {
|
|
9
|
+
buffer: Buffer;
|
|
10
|
+
mimetype: string;
|
|
11
|
+
};
|
|
12
|
+
export type VoiceTranscriptionResult = string | {
|
|
13
|
+
text?: string;
|
|
14
|
+
transcript?: string;
|
|
15
|
+
language?: string;
|
|
16
|
+
confidence?: number;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
};
|
|
19
|
+
export type VoiceRecognitionOptions = {
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
transcribe: (input: VoiceTranscriptionInput) => VoiceTranscriptionResult | Promise<VoiceTranscriptionResult>;
|
|
22
|
+
wakePhrases?: string | string[];
|
|
23
|
+
getWakePhrases?: (context: VoiceRecognitionContext) => string | string[] | undefined | Promise<string | string[] | undefined>;
|
|
24
|
+
shouldProcess?: (context: VoiceRecognitionContext) => boolean | Promise<boolean>;
|
|
25
|
+
allowQuotedActivation?: boolean;
|
|
26
|
+
pttOnly?: boolean;
|
|
27
|
+
maxDuration?: number;
|
|
28
|
+
maxBytes?: number;
|
|
29
|
+
downloadOptions?: any;
|
|
30
|
+
};
|
|
31
|
+
export type VoiceRecognitionEvent = VoiceRecognitionContext & {
|
|
32
|
+
transcript: string;
|
|
33
|
+
commandText: string;
|
|
34
|
+
activation: 'quoted' | 'wake-phrase' | null;
|
|
35
|
+
wakePhrase: string | null;
|
|
36
|
+
language?: string;
|
|
37
|
+
confidence?: number;
|
|
38
|
+
[key: string]: any;
|
|
39
|
+
};
|
|
40
|
+
export function normalizeVoiceText(value: any): string;
|
|
41
|
+
export function matchVoiceWakePhrase(transcript: any, phrases?: string | string[]): {
|
|
42
|
+
phrase: string;
|
|
43
|
+
normalizedPhrase: string;
|
|
44
|
+
normalizedTranscript: string;
|
|
45
|
+
} | null;
|
|
46
|
+
export function removeVoiceWakePhrase(transcript: any, wakePhrase: any): string;
|
|
47
|
+
export function bindVoiceRecognition(sock: any, config?: {
|
|
48
|
+
voiceRecognition?: VoiceRecognitionOptions;
|
|
49
|
+
getMessage?: (key: any) => Promise<any>;
|
|
50
|
+
logger?: any;
|
|
51
|
+
}, dependencies?: {
|
|
52
|
+
downloadContentFromMessage?: (...args: any[]) => Promise<any>;
|
|
53
|
+
}): () => void;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { downloadContentFromMessage } from './messages-media.js';
|
|
2
|
+
import { normalizeMessageContent } from './messages.js';
|
|
3
|
+
import { areJidsSameUser, isJidGroup, jidNormalizedUser } from '../WABinary/index.js';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_MAX_DURATION = 60;
|
|
6
|
+
const DEFAULT_MAX_BYTES = 16 * 1024 * 1024;
|
|
7
|
+
|
|
8
|
+
const streamToBuffer = async (stream, maxBytes) => {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
let total = 0;
|
|
11
|
+
for await (const chunk of stream) {
|
|
12
|
+
const buffer = Buffer.from(chunk);
|
|
13
|
+
total += buffer.length;
|
|
14
|
+
if (maxBytes && total > maxBytes) {
|
|
15
|
+
throw new Error('voice message exceeds maxBytes');
|
|
16
|
+
}
|
|
17
|
+
chunks.push(buffer);
|
|
18
|
+
}
|
|
19
|
+
return Buffer.concat(chunks);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const normalizeVoiceText = value => String(value ?? '')
|
|
23
|
+
.normalize('NFKD')
|
|
24
|
+
.replace(/\p{M}/gu, '')
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
|
27
|
+
.replace(/\s+/g, ' ')
|
|
28
|
+
.trim();
|
|
29
|
+
|
|
30
|
+
export const matchVoiceWakePhrase = (transcript, phrases = []) => {
|
|
31
|
+
const normalizedTranscript = normalizeVoiceText(transcript);
|
|
32
|
+
if (!normalizedTranscript) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const candidates = [...new Map((Array.isArray(phrases) ? phrases : [phrases])
|
|
36
|
+
.map(phrase => ({ raw: String(phrase ?? '').trim(), normalized: normalizeVoiceText(phrase) }))
|
|
37
|
+
.filter(phrase => phrase.normalized)
|
|
38
|
+
.map(phrase => [phrase.normalized, phrase])).values()]
|
|
39
|
+
.sort((a, b) => b.normalized.length - a.normalized.length);
|
|
40
|
+
for (const phrase of candidates) {
|
|
41
|
+
const index = ` ${normalizedTranscript} `.indexOf(` ${phrase.normalized} `);
|
|
42
|
+
if (index >= 0) {
|
|
43
|
+
return {
|
|
44
|
+
phrase: phrase.raw,
|
|
45
|
+
normalizedPhrase: phrase.normalized,
|
|
46
|
+
normalizedTranscript
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const removeVoiceWakePhrase = (transcript, wakePhrase) => {
|
|
54
|
+
const normalizedTranscript = normalizeVoiceText(transcript);
|
|
55
|
+
const normalizedPhrase = normalizeVoiceText(wakePhrase);
|
|
56
|
+
if (!normalizedPhrase) {
|
|
57
|
+
return normalizedTranscript;
|
|
58
|
+
}
|
|
59
|
+
const words = normalizedTranscript.split(' ');
|
|
60
|
+
const phraseWords = normalizedPhrase.split(' ');
|
|
61
|
+
for (let index = 0; index <= words.length - phraseWords.length; index += 1) {
|
|
62
|
+
if (phraseWords.every((word, offset) => words[index + offset] === word)) {
|
|
63
|
+
words.splice(index, phraseWords.length);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return words.join(' ').trim();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const getVoiceSenderJid = message => jidNormalizedUser(message?.key?.participantAlt ||
|
|
71
|
+
message?.key?.participant ||
|
|
72
|
+
message?.key?.remoteJidAlt ||
|
|
73
|
+
message?.key?.remoteJid);
|
|
74
|
+
|
|
75
|
+
const isQuotedToSelf = async ({ message, audioMessage, meId, meLid, getMessage }) => {
|
|
76
|
+
const contextInfo = audioMessage?.contextInfo;
|
|
77
|
+
if (!contextInfo?.quotedMessage && !contextInfo?.stanzaId) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const quotedAuthor = contextInfo.participantAlt || contextInfo.participant;
|
|
81
|
+
if (quotedAuthor && (areJidsSameUser(quotedAuthor, meId) || areJidsSameUser(quotedAuthor, meLid))) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (!contextInfo.stanzaId || typeof getMessage !== 'function') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const target = await getMessage({
|
|
88
|
+
remoteJid: message.key.remoteJid,
|
|
89
|
+
remoteJidAlt: message.key.remoteJidAlt,
|
|
90
|
+
participant: quotedAuthor,
|
|
91
|
+
id: contextInfo.stanzaId
|
|
92
|
+
});
|
|
93
|
+
return target?.key?.fromMe === true;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const normalizeTranscriptionResult = value => {
|
|
97
|
+
if (typeof value === 'string') {
|
|
98
|
+
return { text: value };
|
|
99
|
+
}
|
|
100
|
+
if (value && typeof value === 'object') {
|
|
101
|
+
return {
|
|
102
|
+
...value,
|
|
103
|
+
text: String(value.text ?? value.transcript ?? '')
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return { text: '' };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const getWakePhrases = async (voiceRecognition, context) => {
|
|
110
|
+
const staticPhrases = Array.isArray(voiceRecognition.wakePhrases)
|
|
111
|
+
? voiceRecognition.wakePhrases
|
|
112
|
+
: voiceRecognition.wakePhrases
|
|
113
|
+
? [voiceRecognition.wakePhrases]
|
|
114
|
+
: [];
|
|
115
|
+
const dynamicPhrases = typeof voiceRecognition.getWakePhrases === 'function'
|
|
116
|
+
? await voiceRecognition.getWakePhrases(context)
|
|
117
|
+
: [];
|
|
118
|
+
return [...new Set([
|
|
119
|
+
...staticPhrases,
|
|
120
|
+
...(Array.isArray(dynamicPhrases) ? dynamicPhrases : dynamicPhrases ? [dynamicPhrases] : [])
|
|
121
|
+
].map(value => String(value ?? '').trim()).filter(Boolean))];
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const bindVoiceRecognition = (sock, config = {}, dependencies = {}) => {
|
|
125
|
+
const voiceRecognition = config.voiceRecognition;
|
|
126
|
+
if (!voiceRecognition?.enabled || typeof voiceRecognition.transcribe !== 'function') {
|
|
127
|
+
return () => undefined;
|
|
128
|
+
}
|
|
129
|
+
const downloadContent = dependencies.downloadContentFromMessage || downloadContentFromMessage;
|
|
130
|
+
const getMessage = config.getMessage;
|
|
131
|
+
const logger = config.logger;
|
|
132
|
+
const handler = async ({ messages, type }) => {
|
|
133
|
+
if (type !== 'notify') {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
for (const message of messages || []) {
|
|
137
|
+
try {
|
|
138
|
+
if (
|
|
139
|
+
!message?.message ||
|
|
140
|
+
(message.key?.fromMe && !voiceRecognition.allowFromMe)
|
|
141
|
+
) {
|
|
142
|
+
continue
|
|
143
|
+
}
|
|
144
|
+
const content = normalizeMessageContent(message.message);
|
|
145
|
+
const audioMessage = content?.audioMessage;
|
|
146
|
+
if (!audioMessage) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if ((voiceRecognition.pttOnly ?? true) && !audioMessage.ptt) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const maxDuration = Number.isFinite(voiceRecognition.maxDuration)
|
|
153
|
+
? Math.max(0, Number(voiceRecognition.maxDuration))
|
|
154
|
+
: DEFAULT_MAX_DURATION;
|
|
155
|
+
if (maxDuration && Number(audioMessage.seconds || 0) > maxDuration) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const chatJid = jidNormalizedUser(message.key.remoteJid);
|
|
159
|
+
const senderJid = getVoiceSenderJid(message);
|
|
160
|
+
const context = {
|
|
161
|
+
message,
|
|
162
|
+
audioMessage,
|
|
163
|
+
chatJid,
|
|
164
|
+
senderJid,
|
|
165
|
+
isGroup: isJidGroup(chatJid)
|
|
166
|
+
};
|
|
167
|
+
if (typeof voiceRecognition.shouldProcess === 'function' && !(await voiceRecognition.shouldProcess(context))) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const maxBytes = Number.isFinite(voiceRecognition.maxBytes)
|
|
171
|
+
? Math.max(0, Number(voiceRecognition.maxBytes))
|
|
172
|
+
: DEFAULT_MAX_BYTES;
|
|
173
|
+
const declaredBytes = Number(audioMessage.fileLength?.toString?.() || audioMessage.fileLength || 0);
|
|
174
|
+
if (maxBytes && declaredBytes > maxBytes) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const stream = await downloadContent(audioMessage, 'audio', voiceRecognition.downloadOptions || {});
|
|
178
|
+
const buffer = await streamToBuffer(stream, maxBytes);
|
|
179
|
+
const transcription = normalizeTranscriptionResult(await voiceRecognition.transcribe({
|
|
180
|
+
...context,
|
|
181
|
+
buffer,
|
|
182
|
+
mimetype: audioMessage.mimetype || 'audio/ogg; codecs=opus'
|
|
183
|
+
}));
|
|
184
|
+
const transcript = transcription.text.trim();
|
|
185
|
+
if (!transcript) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const meId = sock.authState?.creds?.me?.id;
|
|
189
|
+
const meLid = sock.authState?.creds?.me?.lid;
|
|
190
|
+
const quoted = (voiceRecognition.allowQuotedActivation ?? true)
|
|
191
|
+
? await isQuotedToSelf({ message, audioMessage, meId, meLid, getMessage })
|
|
192
|
+
: false;
|
|
193
|
+
const phrases = quoted ? [] : await getWakePhrases(voiceRecognition, context);
|
|
194
|
+
const wake = quoted ? null : matchVoiceWakePhrase(transcript, phrases);
|
|
195
|
+
const activation = quoted ? 'quoted' : wake ? 'wake-phrase' : null;
|
|
196
|
+
const commandText = wake
|
|
197
|
+
? removeVoiceWakePhrase(transcript, wake.normalizedPhrase)
|
|
198
|
+
: normalizeVoiceText(transcript);
|
|
199
|
+
const event = {
|
|
200
|
+
...context,
|
|
201
|
+
...transcription,
|
|
202
|
+
transcript,
|
|
203
|
+
commandText,
|
|
204
|
+
activation,
|
|
205
|
+
wakePhrase: wake?.phrase || null
|
|
206
|
+
};
|
|
207
|
+
sock.ev.emit('voice.transcription', event);
|
|
208
|
+
if (activation) {
|
|
209
|
+
sock.ev.emit('voice.command', event);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
logger?.warn({ err: error, key: message?.key }, 'voice recognition failed');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
sock.ev.on('messages.upsert', handler);
|
|
218
|
+
return () => sock.ev.off('messages.upsert', handler);
|
|
219
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class AudioFeeder {
|
|
2
|
+
constructor(sampleRate: number, channels: number, framesPerChunk: number, onChunk: (chunk: Float32Array) => void, source?: string, hooks?: {
|
|
3
|
+
onTrackStart?: (track: string) => void;
|
|
4
|
+
onTrackEnd?: (track: string) => void;
|
|
5
|
+
onIdle?: () => void;
|
|
6
|
+
ffmpegPath?: string;
|
|
7
|
+
});
|
|
8
|
+
readonly queuedChunks: number;
|
|
9
|
+
droppedChunks: number;
|
|
10
|
+
underflowChunks: number;
|
|
11
|
+
rebuffers: number;
|
|
12
|
+
bytesProduced: number;
|
|
13
|
+
chunksEmitted: number;
|
|
14
|
+
readonly playlistLength: number;
|
|
15
|
+
readonly currentTrack: string | null;
|
|
16
|
+
readonly idle: boolean;
|
|
17
|
+
tracksPlayed: number;
|
|
18
|
+
enqueue(source: string | string[]): number;
|
|
19
|
+
clearPlaylist(): void;
|
|
20
|
+
skip(): boolean;
|
|
21
|
+
start(playlist?: string[]): void;
|
|
22
|
+
stop(): void;
|
|
23
|
+
}
|
|
24
|
+
export default AudioFeeder;
|