@nerxa/socketon 0.0.0-stage → 1.21.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/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 +100 -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 +37 -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,96 @@
|
|
|
1
|
+
|
|
2
|
+
export const HTML_APP_MESSAGE_CEILING = 1024 * 1024;
|
|
3
|
+
|
|
4
|
+
export const HTML_APP_BYTE_BUDGET = 960 * 1024;
|
|
5
|
+
|
|
6
|
+
export const HTML_APP_BYTE_LIMIT = HTML_APP_BYTE_BUDGET;
|
|
7
|
+
|
|
8
|
+
export const wireBytes = (html) => Buffer.byteLength(
|
|
9
|
+
JSON.stringify(String(html)).replace(/[\u007f-\uffff]/g, (c) => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0')),
|
|
10
|
+
'utf-8'
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const STORAGE_APIS = ['localStorage', 'sessionStorage', 'indexedDB', 'document.cookie', 'caches'];
|
|
14
|
+
|
|
15
|
+
const strip = (html) => html
|
|
16
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
17
|
+
.replace(/data:[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]*;base64,[A-Za-z0-9+/=]+/gi, 'data:');
|
|
18
|
+
|
|
19
|
+
const hasVisibilityGuard = (source) => /document\.(hidden|visibilityState)|visibilitychange|IntersectionObserver|cancelAnimationFrame|clearInterval/.test(source);
|
|
20
|
+
|
|
21
|
+
export const checkHtmlApp = (html, { height, maxBytes = HTML_APP_BYTE_BUDGET } = {}) => {
|
|
22
|
+
if (typeof html !== 'string') {
|
|
23
|
+
throw new TypeError('checkHtmlApp requires an HTML string');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const bytes = Buffer.byteLength(html, 'utf-8');
|
|
27
|
+
const wire = wireBytes(html);
|
|
28
|
+
const source = strip(html);
|
|
29
|
+
const problems = [];
|
|
30
|
+
const warnings = [];
|
|
31
|
+
|
|
32
|
+
if (wire > maxBytes) {
|
|
33
|
+
problems.push(`${Math.round(wire / 1024)}KB on the wire, over the ${Math.round(maxBytes / 1024)}KB budget — a message past ${Math.round(HTML_APP_MESSAGE_CEILING / 1024)}KB is dropped by the receiving client, which logs it and renders nothing, so this one would arrive as silence`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (wire > bytes * 1.15) {
|
|
37
|
+
warnings.push(`escaping inflates this page from ${Math.round(bytes / 1024)}KB to ${Math.round(wire / 1024)}KB — every non-ASCII character is rewritten as \\uXXXX, so emoji and accents cost up to three times their size`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const remote = [...source.matchAll(/\b(?:src|href)\s*=\s*["']?(https?:)?\/\//gi)];
|
|
41
|
+
if (remote.length) {
|
|
42
|
+
problems.push(`${remote.length} remote subresource${remote.length === 1 ? '' : 's'} — the page runs in an opaque origin with no network, so every one of them fails silently; embed as data: URIs instead`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (/\bfetch\s*\(|XMLHttpRequest|navigator\.sendBeacon|new\s+EventSource/.test(source)) {
|
|
46
|
+
problems.push('a call over the HTTP stack — fetch, XHR, sendBeacon and EventSource were measured dead in this WebView, and no securitypolicyviolation fires to tell the page why');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const socket = /new\s+WebSocket/.test(source);
|
|
50
|
+
const peer = /RTCPeerConnection/.test(source);
|
|
51
|
+
if (socket && !/wss:\/\//.test(source)) {
|
|
52
|
+
problems.push('a WebSocket on something other than wss:// — the page is not a secure context, and a cleartext ws:// endpoint sends the room and every move in the open');
|
|
53
|
+
}
|
|
54
|
+
if ((socket || peer) && !hasVisibilityGuard(source)) {
|
|
55
|
+
warnings.push('a live connection with nothing closing it — the bubble outlives the screen, so close or pause the socket on visibilitychange');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const storage = STORAGE_APIS.filter(api => source.includes(api));
|
|
59
|
+
if (storage.length) {
|
|
60
|
+
problems.push(`${storage.join(', ')} — every storage API throws SecurityError in an opaque origin, so the catch branch always runs`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (/crypto\.subtle/.test(source)) {
|
|
64
|
+
problems.push('crypto.subtle needs a secure context and this page is not one');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const rafLoop = /requestAnimationFrame/.test(source);
|
|
68
|
+
const interval = /setInterval\s*\(/.test(source);
|
|
69
|
+
if ((rafLoop || interval) && !hasVisibilityGuard(source)) {
|
|
70
|
+
problems.push('an animation or timer loop with nothing to stop it — the bubble stays alive while the chat scrolls, so it keeps burning CPU and battery off-screen; gate it on document.hidden or an IntersectionObserver');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const reportsHeight = /AndroidBridge\s*\.\s*updateSize/.test(source);
|
|
74
|
+
if (height === undefined && !reportsHeight) {
|
|
75
|
+
const pinned = /(?:html|body)[^{}]*\{[^{}]*height\s*:\s*\d/i.test(source);
|
|
76
|
+
if (!pinned) {
|
|
77
|
+
warnings.push('no height settled — pass height or autoHeight to sendHtmlApp, or call AndroidBridge.updateSize yourself, or the host and the page measure each other and the card shudders');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (/aspect-ratio\s*:/i.test(source)) {
|
|
82
|
+
warnings.push('aspect-ratio makes the height depend on the width, which is the layout chase the host cannot settle');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (/<canvas[^>]*style\s*=\s*["'][^"']*height\s*:\s*auto/i.test(source)) {
|
|
86
|
+
warnings.push('a canvas at height:auto resizes with the bubble; give it pixel dimensions');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const dataUris = [...html.matchAll(/data:[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]*;base64,([A-Za-z0-9+/=]+)/gi)];
|
|
90
|
+
const embedded = dataUris.reduce((total, match) => total + match[1].length, 0);
|
|
91
|
+
if (embedded > bytes * 0.6 && dataUris.length) {
|
|
92
|
+
warnings.push(`${Math.round(embedded / 1024)}KB of the page is embedded media — shrink it before the byte budget forces you to`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { ok: problems.length === 0, bytes, wireBytes: wire, embeddedBytes: embedded, problems, warnings };
|
|
96
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface HtmlMultiplayerOptions {
|
|
2
|
+
url: string
|
|
3
|
+
room: string
|
|
4
|
+
seat?: string | number | null
|
|
5
|
+
reconnectMs?: number
|
|
6
|
+
maxReconnectMs?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export declare function htmlMultiplayerPrelude(options: HtmlMultiplayerOptions): string
|
|
10
|
+
export declare function withHtmlMultiplayer(html: string, options: HtmlMultiplayerOptions): string
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
|
|
2
|
+
const escapeForScript = (value) => JSON.stringify(value).replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
|
|
3
|
+
|
|
4
|
+
export const htmlMultiplayerPrelude = ({ url, room, seat, reconnectMs = 1500, maxReconnectMs = 15000 } = {}) => {
|
|
5
|
+
if (typeof url !== 'string' || !url.startsWith('wss://')) {
|
|
6
|
+
throw new TypeError('htmlMultiplayerPrelude requires a wss:// url, since the page is not a secure context');
|
|
7
|
+
}
|
|
8
|
+
if (typeof room !== 'string' || room.trim() === '') {
|
|
9
|
+
throw new TypeError('htmlMultiplayerPrelude requires a non-empty room id');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const config = escapeForScript({ url, room, seat: seat ?? null, reconnectMs, maxReconnectMs });
|
|
13
|
+
|
|
14
|
+
return `<script>
|
|
15
|
+
(function () {
|
|
16
|
+
var cfg = ${config};
|
|
17
|
+
var listeners = [];
|
|
18
|
+
var queue = [];
|
|
19
|
+
var sock = null;
|
|
20
|
+
var backoff = cfg.reconnectMs;
|
|
21
|
+
var closed = false;
|
|
22
|
+
|
|
23
|
+
var api = {
|
|
24
|
+
room: cfg.room,
|
|
25
|
+
seat: cfg.seat,
|
|
26
|
+
connected: false,
|
|
27
|
+
send: function (payload) {
|
|
28
|
+
var frame = JSON.stringify({ room: cfg.room, seat: cfg.seat, data: payload });
|
|
29
|
+
if (sock && sock.readyState === 1) sock.send(frame); else queue.push(frame);
|
|
30
|
+
},
|
|
31
|
+
on: function (fn) { listeners.push(fn); return function () { listeners = listeners.filter(function (f) { return f !== fn }) } },
|
|
32
|
+
close: function () { closed = true; if (sock) try { sock.close() } catch (e) {} }
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function emit(kind, detail) {
|
|
36
|
+
for (var i = 0; i < listeners.length; i++) {
|
|
37
|
+
try { listeners[i](kind, detail) } catch (e) {}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function open() {
|
|
42
|
+
if (closed || (sock && (sock.readyState === 0 || sock.readyState === 1))) return;
|
|
43
|
+
try { sock = new WebSocket(cfg.url) } catch (e) { emit('error', e); return schedule() }
|
|
44
|
+
|
|
45
|
+
sock.onopen = function () {
|
|
46
|
+
backoff = cfg.reconnectMs;
|
|
47
|
+
api.connected = true;
|
|
48
|
+
sock.send(JSON.stringify({ join: cfg.room, seat: cfg.seat }));
|
|
49
|
+
while (queue.length && sock.readyState === 1) sock.send(queue.shift());
|
|
50
|
+
emit('open', null);
|
|
51
|
+
};
|
|
52
|
+
sock.onmessage = function (event) {
|
|
53
|
+
var parsed = event.data;
|
|
54
|
+
try { parsed = JSON.parse(event.data) } catch (e) {}
|
|
55
|
+
emit('message', parsed);
|
|
56
|
+
};
|
|
57
|
+
sock.onclose = function (event) {
|
|
58
|
+
api.connected = false;
|
|
59
|
+
emit('close', event.code);
|
|
60
|
+
schedule();
|
|
61
|
+
};
|
|
62
|
+
sock.onerror = function () { api.connected = false };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function schedule() {
|
|
66
|
+
if (closed || document.hidden) return;
|
|
67
|
+
setTimeout(open, backoff);
|
|
68
|
+
backoff = Math.min(backoff * 2, cfg.maxReconnectMs);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
document.addEventListener('visibilitychange', function () {
|
|
72
|
+
if (document.hidden) {
|
|
73
|
+
if (sock) try { sock.close() } catch (e) {}
|
|
74
|
+
} else if (!closed) {
|
|
75
|
+
backoff = cfg.reconnectMs;
|
|
76
|
+
open();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
window.addEventListener('pagehide', function () { api.close() });
|
|
81
|
+
|
|
82
|
+
window.room = api;
|
|
83
|
+
open();
|
|
84
|
+
})();
|
|
85
|
+
</script>
|
|
86
|
+
`;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const withHtmlMultiplayer = (html, options) => {
|
|
90
|
+
if (typeof html !== 'string' || html.trim() === '') {
|
|
91
|
+
throw new TypeError('withHtmlMultiplayer requires an HTML string');
|
|
92
|
+
}
|
|
93
|
+
return htmlMultiplayerPrelude(options) + html;
|
|
94
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function handleIdentityChange(node: any, ctx: any): Promise<{
|
|
2
|
+
action: string;
|
|
3
|
+
device?: undefined;
|
|
4
|
+
error?: undefined;
|
|
5
|
+
} | {
|
|
6
|
+
action: string;
|
|
7
|
+
device: number;
|
|
8
|
+
error?: undefined;
|
|
9
|
+
} | {
|
|
10
|
+
action: string;
|
|
11
|
+
error: unknown;
|
|
12
|
+
device?: undefined;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { areJidsSameUser, getBinaryNodeChild, jidDecode } from '../WABinary/index.js';
|
|
2
|
+
import { isStringNullOrEmpty } from './generics.js';
|
|
3
|
+
export async function handleIdentityChange(node, ctx) {
|
|
4
|
+
const from = node.attrs.from;
|
|
5
|
+
if (!from) {
|
|
6
|
+
return { action: 'invalid_notification' };
|
|
7
|
+
}
|
|
8
|
+
const identityNode = getBinaryNodeChild(node, 'identity');
|
|
9
|
+
if (!identityNode) {
|
|
10
|
+
return { action: 'no_identity_node' };
|
|
11
|
+
}
|
|
12
|
+
ctx.logger.info({ jid: from }, 'identity changed');
|
|
13
|
+
const decoded = jidDecode(from);
|
|
14
|
+
if (decoded?.device && decoded.device !== 0) {
|
|
15
|
+
ctx.logger.debug({ jid: from, device: decoded.device }, 'ignoring identity change from companion device');
|
|
16
|
+
return { action: 'skipped_companion_device', device: decoded.device };
|
|
17
|
+
}
|
|
18
|
+
const isSelfPrimary = ctx.meId && (areJidsSameUser(from, ctx.meId) || (ctx.meLid && areJidsSameUser(from, ctx.meLid)));
|
|
19
|
+
if (isSelfPrimary) {
|
|
20
|
+
ctx.logger.info({ jid: from }, 'self primary identity changed');
|
|
21
|
+
return { action: 'skipped_self_primary' };
|
|
22
|
+
}
|
|
23
|
+
if (ctx.debounceCache.get(from)) {
|
|
24
|
+
ctx.logger.debug({ jid: from }, 'skipping identity assert (debounced)');
|
|
25
|
+
return { action: 'debounced' };
|
|
26
|
+
}
|
|
27
|
+
ctx.debounceCache.set(from, true);
|
|
28
|
+
const isOfflineNotification = !isStringNullOrEmpty(node.attrs.offline);
|
|
29
|
+
const hasExistingSession = await ctx.validateSession(from);
|
|
30
|
+
if (!hasExistingSession.exists) {
|
|
31
|
+
ctx.logger.debug({ jid: from }, 'no old session, skipping session refresh');
|
|
32
|
+
return { action: 'skipped_no_session' };
|
|
33
|
+
}
|
|
34
|
+
ctx.logger.debug({ jid: from }, 'old session exists, will refresh session');
|
|
35
|
+
if (isOfflineNotification) {
|
|
36
|
+
ctx.logger.debug({ jid: from }, 'skipping session refresh during offline processing');
|
|
37
|
+
return { action: 'skipped_offline' };
|
|
38
|
+
}
|
|
39
|
+
ctx.onBeforeSessionRefresh?.(from);
|
|
40
|
+
try {
|
|
41
|
+
await ctx.assertSessions([from], true);
|
|
42
|
+
return { action: 'session_refreshed' };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
ctx.logger.warn({ error, jid: from }, 'failed to assert sessions after identity change');
|
|
46
|
+
return { action: 'session_refresh_failed', error };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export * from "./generics.js";
|
|
2
|
+
export * from "./decode-wa-message.js";
|
|
3
|
+
export * from "./messages.js";
|
|
4
|
+
export * from "./messages-media.js";
|
|
5
|
+
export * from "./validate-connection.js";
|
|
6
|
+
export * from "./crypto.js";
|
|
7
|
+
export * from "./signal.js";
|
|
8
|
+
export * from "./noise-handler.js";
|
|
9
|
+
export * from "./history.js";
|
|
10
|
+
export * from "./chat-utils.js";
|
|
11
|
+
export * from "./lt-hash.js";
|
|
12
|
+
export * from "./auth-utils.js";
|
|
13
|
+
export * from "./use-multi-file-auth-state.js";
|
|
14
|
+
export * from "./use-single-file-auth-state.js";
|
|
15
|
+
export * from "./use-sqlite-auth-state.js";
|
|
16
|
+
export * from "./auth-store.js";
|
|
17
|
+
export * from "./use-postgres-auth-state.js";
|
|
18
|
+
export * from "./use-mysql-auth-state.js";
|
|
19
|
+
export * from "./use-mongo-auth-state.js";
|
|
20
|
+
export * from "./use-redis-auth-state.js";
|
|
21
|
+
export * from "./link-preview.js";
|
|
22
|
+
export * from "./event-buffer.js";
|
|
23
|
+
export * from "./process-message.js";
|
|
24
|
+
export * from "./message-retry-manager.js";
|
|
25
|
+
export * from "./ttl-cache.js";
|
|
26
|
+
export * from "./browser-utils.js";
|
|
27
|
+
export * from "./companion-reg-client-utils.js";
|
|
28
|
+
export * from "./identity-change-handler.js";
|
|
29
|
+
export * from "./stanza-ack.js";
|
|
30
|
+
export * from "./useNekoDBAuth.js";
|
|
31
|
+
export * from "./modern-messages.js";
|
|
32
|
+
export * from "./sender-key-memory.js";
|
|
33
|
+
export * from "./group-metadata-cache.js";
|
|
34
|
+
export * from "./newsletter-status.js";
|
|
35
|
+
export * from "./voice-recognition.js";
|
|
36
|
+
export * from "./username.js";
|
|
37
|
+
export * from "./scheduled-message.js";
|
|
38
|
+
export * from "./status-stickers.js";
|
|
39
|
+
export * from "./link-preview-metadata.js";
|
|
40
|
+
export * from "./payment-messages.js";
|
|
41
|
+
export * from "./native-flow.js";
|
|
42
|
+
export * from "./html-app.js";
|
|
43
|
+
export * from "./html-multiplayer.js";
|
|
44
|
+
export * from "./optional-media.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export * from './generics.js';
|
|
2
|
+
export * from './decode-wa-message.js';
|
|
3
|
+
export * from './messages.js';
|
|
4
|
+
export * from './messages-media.js';
|
|
5
|
+
export * from './validate-connection.js';
|
|
6
|
+
export * from './crypto.js';
|
|
7
|
+
export * from './signal.js';
|
|
8
|
+
export * from './noise-handler.js';
|
|
9
|
+
export * from './history.js';
|
|
10
|
+
export * from './chat-utils.js';
|
|
11
|
+
export * from './lt-hash.js';
|
|
12
|
+
export * from './auth-utils.js';
|
|
13
|
+
export * from './use-multi-file-auth-state.js';
|
|
14
|
+
export * from './use-single-file-auth-state.js';
|
|
15
|
+
export * from './use-sqlite-auth-state.js';
|
|
16
|
+
export * from './auth-store.js';
|
|
17
|
+
export * from './use-postgres-auth-state.js';
|
|
18
|
+
export * from './use-mysql-auth-state.js';
|
|
19
|
+
export * from './use-mongo-auth-state.js';
|
|
20
|
+
export * from './use-redis-auth-state.js';
|
|
21
|
+
export * from './link-preview.js';
|
|
22
|
+
export * from './event-buffer.js';
|
|
23
|
+
export * from './process-message.js';
|
|
24
|
+
export * from './message-retry-manager.js';
|
|
25
|
+
export * from './ttl-cache.js';
|
|
26
|
+
export * from './browser-utils.js';
|
|
27
|
+
export * from './companion-reg-client-utils.js';
|
|
28
|
+
export * from './identity-change-handler.js';
|
|
29
|
+
export * from './stanza-ack.js';
|
|
30
|
+
export * from "./useNekoDBAuth.js";
|
|
31
|
+
export * from './modern-messages.js';
|
|
32
|
+
export * from './sender-key-memory.js';
|
|
33
|
+
export * from './group-metadata-cache.js';
|
|
34
|
+
export * from './newsletter-status.js';
|
|
35
|
+
export * from './voice-recognition.js';
|
|
36
|
+
export * from './username.js';
|
|
37
|
+
export * from './scheduled-message.js';
|
|
38
|
+
export * from './status-stickers.js';
|
|
39
|
+
export * from './link-preview-metadata.js';
|
|
40
|
+
export * from './payment-messages.js';
|
|
41
|
+
export * from './native-flow.js';
|
|
42
|
+
export * from './html-app.js';
|
|
43
|
+
export * from './html-multiplayer.js';
|
|
44
|
+
export * from './optional-media.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { proto } from '../../WAProto/index.js';
|
|
2
|
+
|
|
3
|
+
export declare const SocialMediaPostType: Readonly<{
|
|
4
|
+
NONE: 0;
|
|
5
|
+
REEL: 1;
|
|
6
|
+
LIVE_VIDEO: 2;
|
|
7
|
+
LONG_VIDEO: 3;
|
|
8
|
+
SINGLE_IMAGE: 4;
|
|
9
|
+
CAROUSEL: 5;
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
export declare function videoEndCard(options?: {
|
|
13
|
+
username?: string;
|
|
14
|
+
caption?: string;
|
|
15
|
+
thumbnailUrl?: string;
|
|
16
|
+
profilePictureUrl?: string;
|
|
17
|
+
}): proto.Message.IVideoEndCard;
|
|
18
|
+
|
|
19
|
+
export interface SocialPreviewOptions {
|
|
20
|
+
postType?: number;
|
|
21
|
+
videoUrl?: string;
|
|
22
|
+
videoCaption?: string;
|
|
23
|
+
muted?: boolean;
|
|
24
|
+
/** Seconds, not milliseconds — the client stores link_media_duration_seconds. */
|
|
25
|
+
durationSeconds?: number;
|
|
26
|
+
experimentId?: number;
|
|
27
|
+
music?: proto.IEmbeddedMusic;
|
|
28
|
+
endCards?: proto.Message.IVideoEndCard[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export declare function buildSocialPreview(options?: SocialPreviewOptions): {
|
|
32
|
+
linkPreviewMetadata?: proto.Message.ILinkPreviewMetadata;
|
|
33
|
+
videoContentUrl?: string;
|
|
34
|
+
musicMetadata?: proto.IEmbeddedMusic;
|
|
35
|
+
endCardTiles?: proto.Message.IVideoEndCard[];
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export declare function readSocialPreview(msg: any): {
|
|
39
|
+
postType?: number;
|
|
40
|
+
durationSeconds?: number;
|
|
41
|
+
muted?: boolean;
|
|
42
|
+
videoUrl?: string;
|
|
43
|
+
videoCaption?: string;
|
|
44
|
+
music?: proto.IEmbeddedMusic;
|
|
45
|
+
experimentId?: number;
|
|
46
|
+
endCards?: proto.Message.IVideoEndCard[];
|
|
47
|
+
} | null;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
|
|
2
|
+
export const SocialMediaPostType = Object.freeze({
|
|
3
|
+
NONE: 0,
|
|
4
|
+
REEL: 1,
|
|
5
|
+
LIVE_VIDEO: 2,
|
|
6
|
+
LONG_VIDEO: 3,
|
|
7
|
+
SINGLE_IMAGE: 4,
|
|
8
|
+
CAROUSEL: 5
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const drop = (object) => {
|
|
12
|
+
for (const key of Object.keys(object)) {
|
|
13
|
+
if (object[key] === undefined || object[key] === null) {
|
|
14
|
+
delete object[key]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return object
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const videoEndCard = ({ username, caption, thumbnailUrl, profilePictureUrl } = {}) =>
|
|
21
|
+
drop({
|
|
22
|
+
username,
|
|
23
|
+
caption,
|
|
24
|
+
thumbnailImageUrl: thumbnailUrl,
|
|
25
|
+
profilePictureUrl
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The same video url and music node exist twice, once nested in
|
|
30
|
+
* LinkPreviewMetadata and once directly on ExtendedTextMessage. Which one the
|
|
31
|
+
* client reads is not visible from the client, so both carry the same value.
|
|
32
|
+
*/
|
|
33
|
+
export const buildSocialPreview = ({
|
|
34
|
+
postType,
|
|
35
|
+
videoUrl,
|
|
36
|
+
videoCaption,
|
|
37
|
+
muted,
|
|
38
|
+
durationSeconds,
|
|
39
|
+
experimentId,
|
|
40
|
+
music,
|
|
41
|
+
endCards
|
|
42
|
+
} = {}) => {
|
|
43
|
+
if (postType !== undefined && !Object.values(SocialMediaPostType).includes(postType)) {
|
|
44
|
+
throw new TypeError(`postType ${postType} is not one of ${Object.keys(SocialMediaPostType).join(', ')}`)
|
|
45
|
+
}
|
|
46
|
+
if (durationSeconds !== undefined && (!Number.isFinite(Number(durationSeconds)) || Number(durationSeconds) < 0)) {
|
|
47
|
+
throw new TypeError('durationSeconds must be a non-negative number of seconds, not milliseconds')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const metadata = drop({
|
|
51
|
+
socialMediaPostType: postType,
|
|
52
|
+
linkMediaDuration: durationSeconds === undefined ? undefined : Math.round(Number(durationSeconds)),
|
|
53
|
+
linkInlineVideoMuted: muted === undefined ? undefined : !!muted,
|
|
54
|
+
videoContentUrl: videoUrl,
|
|
55
|
+
videoContentCaption: videoCaption,
|
|
56
|
+
musicMetadata: music,
|
|
57
|
+
fbExperimentId: experimentId
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return drop({
|
|
61
|
+
linkPreviewMetadata: Object.keys(metadata).length ? metadata : undefined,
|
|
62
|
+
videoContentUrl: videoUrl,
|
|
63
|
+
musicMetadata: music,
|
|
64
|
+
endCardTiles: endCards?.length ? endCards : undefined
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const readSocialPreview = (msg) => {
|
|
69
|
+
const message = msg?.message ?? msg
|
|
70
|
+
const text = message?.extendedTextMessage
|
|
71
|
+
if (!text) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
const metadata = text.linkPreviewMetadata
|
|
75
|
+
if (!metadata && !text.endCardTiles?.length && !text.videoContentUrl) {
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
78
|
+
return drop({
|
|
79
|
+
postType: metadata?.socialMediaPostType,
|
|
80
|
+
durationSeconds: metadata?.linkMediaDuration,
|
|
81
|
+
muted: metadata?.linkInlineVideoMuted,
|
|
82
|
+
videoUrl: metadata?.videoContentUrl ?? text.videoContentUrl,
|
|
83
|
+
videoCaption: metadata?.videoContentCaption,
|
|
84
|
+
music: metadata?.musicMetadata ?? text.musicMetadata,
|
|
85
|
+
experimentId: metadata?.fbExperimentId,
|
|
86
|
+
endCards: text.endCardTiles?.length ? text.endCardTiles : undefined
|
|
87
|
+
})
|
|
88
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function getUrlInfo(text: any, opts?: {
|
|
2
|
+
thumbnailWidth: number;
|
|
3
|
+
fetchOpts: {
|
|
4
|
+
timeout: number;
|
|
5
|
+
};
|
|
6
|
+
}): Promise<{
|
|
7
|
+
'canonical-url': any;
|
|
8
|
+
'matched-text': any;
|
|
9
|
+
title: any;
|
|
10
|
+
description: any;
|
|
11
|
+
originalThumbnailUrl: any;
|
|
12
|
+
} | undefined>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { prepareWAMessageMedia } from './messages.js';
|
|
2
|
+
import { extractImageThumb, getHttpStream } from './messages-media.js';
|
|
3
|
+
const THUMBNAIL_WIDTH_PX = 192;
|
|
4
|
+
|
|
5
|
+
const getCompressedJpegThumbnail = async (url, { thumbnailWidth, fetchOpts }) => {
|
|
6
|
+
const stream = await getHttpStream(url, fetchOpts);
|
|
7
|
+
const result = await extractImageThumb(stream, thumbnailWidth);
|
|
8
|
+
return result;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getUrlInfo = async (text, opts = {
|
|
12
|
+
thumbnailWidth: THUMBNAIL_WIDTH_PX,
|
|
13
|
+
fetchOpts: { timeout: 3000 }
|
|
14
|
+
}) => {
|
|
15
|
+
try {
|
|
16
|
+
|
|
17
|
+
let retries = 0;
|
|
18
|
+
const maxRetry = 5;
|
|
19
|
+
const { getLinkPreview } = await import('link-preview-js');
|
|
20
|
+
let previewLink = text;
|
|
21
|
+
if (!text.startsWith('https://') && !text.startsWith('http://')) {
|
|
22
|
+
previewLink = 'https://' + previewLink;
|
|
23
|
+
}
|
|
24
|
+
const info = await getLinkPreview(previewLink, {
|
|
25
|
+
...opts.fetchOpts,
|
|
26
|
+
followRedirects: 'follow',
|
|
27
|
+
handleRedirects: (baseURL, forwardedURL) => {
|
|
28
|
+
const urlObj = new URL(baseURL);
|
|
29
|
+
const forwardedURLObj = new URL(forwardedURL);
|
|
30
|
+
if (retries >= maxRetry) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (forwardedURLObj.hostname === urlObj.hostname ||
|
|
34
|
+
forwardedURLObj.hostname === 'www.' + urlObj.hostname ||
|
|
35
|
+
'www.' + forwardedURLObj.hostname === urlObj.hostname) {
|
|
36
|
+
retries += 1;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
headers: opts.fetchOpts?.headers
|
|
44
|
+
});
|
|
45
|
+
if (info && 'title' in info && info.title) {
|
|
46
|
+
const [image] = info.images;
|
|
47
|
+
const urlInfo = {
|
|
48
|
+
'canonical-url': info.url,
|
|
49
|
+
'matched-text': text,
|
|
50
|
+
title: info.title,
|
|
51
|
+
description: info.description,
|
|
52
|
+
originalThumbnailUrl: image
|
|
53
|
+
};
|
|
54
|
+
if (opts.uploadImage) {
|
|
55
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: { url: image } }, {
|
|
56
|
+
upload: opts.uploadImage,
|
|
57
|
+
mediaTypeOverride: 'thumbnail-link',
|
|
58
|
+
options: opts.fetchOpts
|
|
59
|
+
});
|
|
60
|
+
urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
|
|
61
|
+
urlInfo.highQualityThumbnail = imageMessage || undefined;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
try {
|
|
65
|
+
urlInfo.jpegThumbnail = image ? (await getCompressedJpegThumbnail(image, opts)).buffer : undefined;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
opts.logger?.debug({ err: error.stack, url: previewLink }, 'error in generating thumbnail');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return urlInfo;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (!error.message.includes('receive a valid')) {
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LT Hash is a summation based hash algorithm that maintains the integrity of a piece of data
|
|
3
|
+
* over a series of mutations. You can add/remove mutations and it'll return a hash equal to
|
|
4
|
+
* if the same series of mutations was made sequentially.
|
|
5
|
+
*/
|
|
6
|
+
export const LT_HASH_ANTI_TAMPERING: any;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Mutex as AsyncMutex } from 'async-mutex';
|
|
2
|
+
export const makeMutex = () => {
|
|
3
|
+
const mutex = new AsyncMutex();
|
|
4
|
+
return {
|
|
5
|
+
mutex(code) {
|
|
6
|
+
return mutex.runExclusive(code);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export const makeKeyedMutex = () => {
|
|
11
|
+
const map = new Map();
|
|
12
|
+
return {
|
|
13
|
+
async mutex(key, task) {
|
|
14
|
+
let entry = map.get(key);
|
|
15
|
+
if (!entry) {
|
|
16
|
+
entry = { mutex: new AsyncMutex(), refCount: 0 };
|
|
17
|
+
map.set(key, entry);
|
|
18
|
+
}
|
|
19
|
+
entry.refCount++;
|
|
20
|
+
try {
|
|
21
|
+
return await entry.mutex.runExclusive(task);
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
entry.refCount--;
|
|
25
|
+
|
|
26
|
+
if (entry.refCount === 0 && map.get(key) === entry) {
|
|
27
|
+
map.delete(key);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
};
|