zapo-js 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/appstate/types.d.ts +1 -2
- package/dist/auth/WaAuthClient.d.ts +10 -0
- package/dist/auth/WaAuthClient.js +17 -8
- package/dist/auth/credentials-flow.d.ts +8 -0
- package/dist/auth/credentials-flow.js +35 -2
- package/dist/auth/pairing/companion-host.d.ts +105 -0
- package/dist/auth/pairing/companion-host.js +148 -0
- package/dist/auth/types.d.ts +20 -9
- package/dist/client/WaClient.d.ts +15 -5
- package/dist/client/WaClient.js +46 -12
- package/dist/client/WaClientFactory.d.ts +3 -0
- package/dist/client/WaClientFactory.js +24 -6
- package/dist/client/coordinators/WaAppStateMutationCoordinator.d.ts +8 -0
- package/dist/client/coordinators/WaAppStateMutationCoordinator.js +37 -1
- package/dist/client/coordinators/WaGroupCoordinator.js +6 -1
- package/dist/client/coordinators/WaMessageDispatchCoordinator.d.ts +3 -1
- package/dist/client/coordinators/WaMessageDispatchCoordinator.js +13 -3
- package/dist/client/coordinators/WaMobileCoordinator.d.ts +192 -0
- package/dist/client/coordinators/WaMobileCoordinator.js +645 -0
- package/dist/client/messaging/companion-host.d.ts +43 -0
- package/dist/client/messaging/companion-host.js +61 -0
- package/dist/client/messaging/key-protocol.js +25 -1
- package/dist/client/persistence/companion-host.d.ts +36 -0
- package/dist/client/persistence/companion-host.js +57 -0
- package/dist/client/plugins/install.d.ts +2 -1
- package/dist/client/plugins/install.js +44 -11
- package/dist/client/types.d.ts +71 -7
- package/dist/esm/auth/WaAuthClient.js +18 -9
- package/dist/esm/auth/credentials-flow.js +36 -3
- package/dist/esm/auth/pairing/companion-host.js +140 -0
- package/dist/esm/client/WaClient.js +46 -12
- package/dist/esm/client/WaClientFactory.js +25 -7
- package/dist/esm/client/coordinators/WaAppStateMutationCoordinator.js +37 -1
- package/dist/esm/client/coordinators/WaGroupCoordinator.js +6 -1
- package/dist/esm/client/coordinators/WaMessageDispatchCoordinator.js +14 -4
- package/dist/esm/client/coordinators/WaMobileCoordinator.js +641 -0
- package/dist/esm/client/messaging/companion-host.js +56 -0
- package/dist/esm/client/messaging/key-protocol.js +25 -1
- package/dist/esm/client/persistence/companion-host.js +54 -0
- package/dist/esm/client/plugins/install.js +44 -11
- package/dist/esm/index.js +5 -2
- package/dist/esm/message/WaMessageClient.js +3 -2
- package/dist/esm/message/context-info.js +4 -0
- package/dist/esm/protocol/constants.js +4 -3
- package/dist/esm/protocol/device-identity.js +18 -0
- package/dist/esm/protocol/group.js +6 -0
- package/dist/esm/protocol/message.js +12 -0
- package/dist/esm/protocol/nodes.js +15 -1
- package/dist/esm/retry/replay.js +3 -3
- package/dist/esm/signal/attestation/WaAdvSignature.js +67 -2
- package/dist/esm/signal/attestation/constants.js +2 -0
- package/dist/esm/signal/index.js +1 -0
- package/dist/esm/transport/index.js +1 -1
- package/dist/esm/transport/node/builders/group.js +4 -3
- package/dist/esm/transport/node/builders/mobile.js +113 -0
- package/dist/esm/transport/noise/WaClientPayload.js +16 -7
- package/dist/esm/transport/wa-version-fetcher.js +152 -0
- package/dist/esm/util/index.js +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.js +13 -4
- package/dist/message/WaMessageClient.js +2 -1
- package/dist/message/context-info.d.ts +2 -0
- package/dist/message/context-info.js +5 -0
- package/dist/protocol/constants.d.ts +6 -4
- package/dist/protocol/constants.js +8 -2
- package/dist/protocol/device-identity.d.ts +25 -0
- package/dist/protocol/device-identity.js +21 -0
- package/dist/protocol/group.d.ts +6 -0
- package/dist/protocol/group.js +7 -1
- package/dist/protocol/message.d.ts +14 -0
- package/dist/protocol/message.js +13 -1
- package/dist/protocol/nodes.d.ts +14 -0
- package/dist/protocol/nodes.js +15 -1
- package/dist/retry/replay.js +2 -2
- package/dist/signal/attestation/WaAdvSignature.d.ts +50 -1
- package/dist/signal/attestation/WaAdvSignature.js +71 -1
- package/dist/signal/attestation/constants.d.ts +2 -0
- package/dist/signal/attestation/constants.js +3 -1
- package/dist/signal/index.d.ts +1 -0
- package/dist/signal/index.js +13 -1
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +4 -3
- package/dist/transport/node/builders/group.js +4 -3
- package/dist/transport/node/builders/mobile.d.ts +68 -0
- package/dist/transport/node/builders/mobile.js +120 -0
- package/dist/transport/noise/WaClientPayload.js +16 -7
- package/dist/transport/wa-version-fetcher.d.ts +92 -0
- package/dist/transport/wa-version-fetcher.js +156 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/index.js +3 -1
- package/package.json +1 -1
- package/dist/esm/transport/wa-web-version-fetcher.js +0 -91
- package/dist/transport/wa-web-version-fetcher.d.ts +0 -44
- package/dist/transport/wa-web-version-fetcher.js +0 -94
|
@@ -14,6 +14,7 @@ import { WaIncomingNodeCoordinator } from './coordinators/WaIncomingNodeCoordina
|
|
|
14
14
|
import { type WaLowLevelCoordinator } from './coordinators/WaLowLevelCoordinator';
|
|
15
15
|
import { WaMessageCoordinator } from './coordinators/WaMessageCoordinator';
|
|
16
16
|
import { WaMessageDispatchCoordinator } from './coordinators/WaMessageDispatchCoordinator';
|
|
17
|
+
import { WaMobileCoordinator } from './coordinators/WaMobileCoordinator';
|
|
17
18
|
import { type WaNewsletterCoordinator } from './coordinators/WaNewsletterCoordinator';
|
|
18
19
|
import { WaPassiveTasksCoordinator } from './coordinators/WaPassiveTasksCoordinator';
|
|
19
20
|
import { type WaPresenceCoordinator } from './coordinators/WaPresenceCoordinator';
|
|
@@ -119,6 +120,8 @@ export interface WaClientDependencies {
|
|
|
119
120
|
readonly trustedContactToken: WaTrustedContactTokenCoordinator;
|
|
120
121
|
readonly abPropsCoordinator: WaAbPropsCoordinator;
|
|
121
122
|
readonly peerDataOperation: PeerDataOperationRequester;
|
|
123
|
+
readonly mobileCoordinator: WaMobileCoordinator;
|
|
124
|
+
readonly isMobilePrimary: () => boolean;
|
|
122
125
|
}
|
|
123
126
|
export declare function resolveWaClientBase(options: WaClientOptions, logger: Logger): WaClientBase;
|
|
124
127
|
export declare function buildWaClientDependencies(input: {
|
|
@@ -17,6 +17,7 @@ const WaIncomingNodeCoordinator_1 = require("./coordinators/WaIncomingNodeCoordi
|
|
|
17
17
|
const WaLowLevelCoordinator_1 = require("./coordinators/WaLowLevelCoordinator");
|
|
18
18
|
const WaMessageCoordinator_1 = require("./coordinators/WaMessageCoordinator");
|
|
19
19
|
const WaMessageDispatchCoordinator_1 = require("./coordinators/WaMessageDispatchCoordinator");
|
|
20
|
+
const WaMobileCoordinator_1 = require("./coordinators/WaMobileCoordinator");
|
|
20
21
|
const WaNewsletterCoordinator_1 = require("./coordinators/WaNewsletterCoordinator");
|
|
21
22
|
const WaOfflineResumeCoordinator_1 = require("./coordinators/WaOfflineResumeCoordinator");
|
|
22
23
|
const WaPassiveTasksCoordinator_1 = require("./coordinators/WaPassiveTasksCoordinator");
|
|
@@ -65,7 +66,6 @@ const WaNodeTransport_1 = require("../transport/node/WaNodeTransport");
|
|
|
65
66
|
const proxy_1 = require("../transport/proxy");
|
|
66
67
|
const clock_1 = require("../util/clock");
|
|
67
68
|
const primitives_1 = require("../util/primitives");
|
|
68
|
-
const runtime_1 = require("../util/runtime");
|
|
69
69
|
function assertProxyTransport(value, path) {
|
|
70
70
|
if (value === undefined) {
|
|
71
71
|
return;
|
|
@@ -89,7 +89,7 @@ function validateProxyOptions(options) {
|
|
|
89
89
|
}
|
|
90
90
|
function resolveWaClientBase(options, logger) {
|
|
91
91
|
validateProxyOptions(options);
|
|
92
|
-
const
|
|
92
|
+
const device = (0, constants_1.resolveWaDeviceIdentity)(options);
|
|
93
93
|
const sessionId = options.sessionId.trim();
|
|
94
94
|
if (sessionId.length === 0) {
|
|
95
95
|
throw new Error('sessionId must be a non-empty string');
|
|
@@ -98,9 +98,9 @@ function resolveWaClientBase(options, logger) {
|
|
|
98
98
|
const normalizedOptions = Object.freeze({
|
|
99
99
|
...options,
|
|
100
100
|
sessionId,
|
|
101
|
-
deviceBrowser,
|
|
102
|
-
deviceOsDisplayName:
|
|
103
|
-
devicePlatform:
|
|
101
|
+
deviceBrowser: device.browser,
|
|
102
|
+
deviceOsDisplayName: device.osDisplayName,
|
|
103
|
+
devicePlatform: device.platform,
|
|
104
104
|
urls: options.urls ?? options.chatSocketUrls ?? constants_1.WA_DEFAULTS.CHAT_SOCKET_URLS,
|
|
105
105
|
iqTimeoutMs: options.iqTimeoutMs ?? constants_1.WA_DEFAULTS.IQ_TIMEOUT_MS,
|
|
106
106
|
nodeQueryTimeoutMs: options.nodeQueryTimeoutMs ?? constants_1.WA_DEFAULTS.NODE_QUERY_TIMEOUT_MS,
|
|
@@ -455,6 +455,7 @@ function buildWaClientDependencies(input) {
|
|
|
455
455
|
});
|
|
456
456
|
messageDispatch = new WaMessageDispatchCoordinator_1.WaMessageDispatchCoordinator({
|
|
457
457
|
logger,
|
|
458
|
+
emitMessageSend: (event) => runtime.emitEvent('message_send', event),
|
|
458
459
|
messageClient,
|
|
459
460
|
retryTracker,
|
|
460
461
|
sessionResolver,
|
|
@@ -591,6 +592,7 @@ function buildWaClientDependencies(input) {
|
|
|
591
592
|
serverClock,
|
|
592
593
|
emitSnapshotMutations: options.chatEvents?.emitSnapshotMutations === true,
|
|
593
594
|
emitMutation: (event) => runtime.emitEvent('mutation', event),
|
|
595
|
+
emitMutationSend: (event) => runtime.emitEvent('mutation_send', event),
|
|
594
596
|
nctSaltSink: (salt) => trustedContactToken.handleNctSaltSync(salt),
|
|
595
597
|
contactSink: runtime.persistContact,
|
|
596
598
|
pushNameSink: (name) => {
|
|
@@ -1017,6 +1019,20 @@ function buildWaClientDependencies(input) {
|
|
|
1017
1019
|
isConnected: () => connectionManager?.isConnected() ?? false,
|
|
1018
1020
|
defaultIqTimeoutMs: options.iqTimeoutMs
|
|
1019
1021
|
});
|
|
1022
|
+
const mobileCoordinator = new WaMobileCoordinator_1.WaMobileCoordinator({
|
|
1023
|
+
logger,
|
|
1024
|
+
authClient,
|
|
1025
|
+
messageDispatch,
|
|
1026
|
+
chatCoordinator: appStateMutations,
|
|
1027
|
+
deviceSync: signalDeviceSync,
|
|
1028
|
+
appStateStore: sessionStore.appState,
|
|
1029
|
+
queryWithContext: runtime.queryWithContext,
|
|
1030
|
+
emitEvent: runtime.emitEvent,
|
|
1031
|
+
registerIncomingHandler: (registration) => incomingNode.registerIncomingHandler(registration),
|
|
1032
|
+
isMobilePrimary,
|
|
1033
|
+
persistence: options.companionHost?.persistence,
|
|
1034
|
+
includePem: options.companionHost?.includePem
|
|
1035
|
+
});
|
|
1020
1036
|
return {
|
|
1021
1037
|
nodeTransport,
|
|
1022
1038
|
nodeOrchestrator,
|
|
@@ -1057,6 +1073,8 @@ function buildWaClientDependencies(input) {
|
|
|
1057
1073
|
connectionManager,
|
|
1058
1074
|
trustedContactToken,
|
|
1059
1075
|
abPropsCoordinator,
|
|
1060
|
-
peerDataOperation
|
|
1076
|
+
peerDataOperation,
|
|
1077
|
+
mobileCoordinator,
|
|
1078
|
+
isMobilePrimary
|
|
1061
1079
|
};
|
|
1062
1080
|
}
|
|
@@ -33,6 +33,7 @@ interface WaAppStateMutationCoordinatorOptions {
|
|
|
33
33
|
readonly serverClock: ServerClock;
|
|
34
34
|
readonly archiveRangeLimit?: number;
|
|
35
35
|
readonly emitMutation?: (event: WaAppStateMutationEvent) => void;
|
|
36
|
+
readonly emitMutationSend?: (event: WaAppStateMutationEvent) => void;
|
|
36
37
|
readonly emitSnapshotMutations?: boolean;
|
|
37
38
|
readonly nctSaltSink?: (salt: Uint8Array | null) => Promise<void>;
|
|
38
39
|
/**
|
|
@@ -79,6 +80,7 @@ export declare class WaAppStateMutationCoordinator {
|
|
|
79
80
|
private readonly serverClock;
|
|
80
81
|
private readonly archiveRangeLimit;
|
|
81
82
|
private readonly emitMutation?;
|
|
83
|
+
private readonly emitMutationSend?;
|
|
82
84
|
private readonly emitSnapshotMutations;
|
|
83
85
|
private readonly nctSaltSink?;
|
|
84
86
|
private readonly contactSink?;
|
|
@@ -160,6 +162,12 @@ export declare class WaAppStateMutationCoordinator {
|
|
|
160
162
|
*/
|
|
161
163
|
flushMutations(): Promise<void>;
|
|
162
164
|
private enqueueAndFlush;
|
|
165
|
+
/**
|
|
166
|
+
* Surfaces an action this client is sending via the outbound `mutation_send`
|
|
167
|
+
* event, so consumers can observe their own change at action time. Parse
|
|
168
|
+
* failures are swallowed (best-effort).
|
|
169
|
+
*/
|
|
170
|
+
private emitLocalMutation;
|
|
163
171
|
private enqueueMutation;
|
|
164
172
|
private takePendingMutationsBatch;
|
|
165
173
|
private flushPendingMutationsLoop;
|
|
@@ -14,6 +14,8 @@ const WA_APP_STATE_MUTATION_FLUSH_SUCCESS_STATES = new Set([
|
|
|
14
14
|
constants_1.WA_APP_STATE_COLLECTION_STATES.SUCCESS_HAS_MORE
|
|
15
15
|
]);
|
|
16
16
|
const WA_APP_STATE_ARCHIVE_RANGE_DEFAULT_LIMIT = 256;
|
|
17
|
+
/** Placeholder MACs for locally-emitted mutation events (the parser ignores them). */
|
|
18
|
+
const WA_EMPTY_MUTATION_MAC = new Uint8Array(0);
|
|
17
19
|
function buildMutationIndexFromSchema(schema, indexArgs) {
|
|
18
20
|
const parts = new Array(schema.indexParts.length);
|
|
19
21
|
const args = indexArgs;
|
|
@@ -160,7 +162,6 @@ function buildRemoveMutationFromSchema(input) {
|
|
|
160
162
|
collection: input.schema.collection,
|
|
161
163
|
operation: 'remove',
|
|
162
164
|
index: buildMutationIndexFromSchema(input.schema, input.indexArgs),
|
|
163
|
-
previousValue: { timestamp: input.timestamp },
|
|
164
165
|
version: input.schema.version,
|
|
165
166
|
timestamp: input.timestamp
|
|
166
167
|
};
|
|
@@ -180,6 +181,7 @@ class WaAppStateMutationCoordinator {
|
|
|
180
181
|
this.serverClock = options.serverClock;
|
|
181
182
|
this.archiveRangeLimit = (0, coercion_1.resolvePositive)(options.archiveRangeLimit, WA_APP_STATE_ARCHIVE_RANGE_DEFAULT_LIMIT, 'WaAppStateMutationCoordinatorOptions.archiveRangeLimit');
|
|
182
183
|
this.emitMutation = options.emitMutation;
|
|
184
|
+
this.emitMutationSend = options.emitMutationSend;
|
|
183
185
|
this.emitSnapshotMutations = options.emitSnapshotMutations === true;
|
|
184
186
|
this.nctSaltSink = options.nctSaltSink;
|
|
185
187
|
this.contactSink = options.contactSink;
|
|
@@ -617,9 +619,43 @@ class WaAppStateMutationCoordinator {
|
|
|
617
619
|
async enqueueAndFlush(mutations) {
|
|
618
620
|
for (const mutation of mutations) {
|
|
619
621
|
this.enqueueMutation(mutation);
|
|
622
|
+
this.emitLocalMutation(mutation);
|
|
620
623
|
}
|
|
621
624
|
await this.flushMutations();
|
|
622
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* Surfaces an action this client is sending via the outbound `mutation_send`
|
|
628
|
+
* event, so consumers can observe their own change at action time. Parse
|
|
629
|
+
* failures are swallowed (best-effort).
|
|
630
|
+
*/
|
|
631
|
+
emitLocalMutation(input) {
|
|
632
|
+
if (!this.emitMutationSend)
|
|
633
|
+
return;
|
|
634
|
+
const value = input.operation === 'set' ? input.value : null;
|
|
635
|
+
try {
|
|
636
|
+
const event = (0, appstate_mutation_1.parseAppStateMutationEvent)({
|
|
637
|
+
collection: input.collection,
|
|
638
|
+
operation: input.operation,
|
|
639
|
+
source: 'local',
|
|
640
|
+
index: input.index,
|
|
641
|
+
value,
|
|
642
|
+
version: input.version,
|
|
643
|
+
indexMac: WA_EMPTY_MUTATION_MAC,
|
|
644
|
+
valueMac: WA_EMPTY_MUTATION_MAC,
|
|
645
|
+
keyId: WA_EMPTY_MUTATION_MAC,
|
|
646
|
+
timestamp: input.timestamp
|
|
647
|
+
});
|
|
648
|
+
if (event)
|
|
649
|
+
this.emitMutationSend(event);
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
this.logger.debug('failed to emit local app-state mutation event', {
|
|
653
|
+
collection: input.collection,
|
|
654
|
+
index: input.index,
|
|
655
|
+
message: (0, primitives_1.toError)(error).message
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
623
659
|
enqueueMutation(mutation) {
|
|
624
660
|
const key = `${mutation.collection}\u0001${mutation.index}`;
|
|
625
661
|
if (this.pendingMutations.has(key)) {
|
|
@@ -5,6 +5,7 @@ const group_1 = require("../events/group");
|
|
|
5
5
|
const defaults_1 = require("../../protocol/defaults");
|
|
6
6
|
const group_2 = require("../../protocol/group");
|
|
7
7
|
const jid_1 = require("../../protocol/jid");
|
|
8
|
+
const message_1 = require("../../protocol/message");
|
|
8
9
|
const nodes_1 = require("../../protocol/nodes");
|
|
9
10
|
const notification_1 = require("../../protocol/notification");
|
|
10
11
|
const account_sync_1 = require("../../transport/node/builders/account-sync");
|
|
@@ -90,7 +91,11 @@ function parseGroupCommons(target) {
|
|
|
90
91
|
? (0, helpers_1.findNodeChild)(membershipApprovalNode, nodes_1.WA_NODE_TAGS.GROUP_JOIN)
|
|
91
92
|
: undefined;
|
|
92
93
|
const addressingModeRaw = attrs.addressing_mode;
|
|
93
|
-
const addressingMode = addressingModeRaw ===
|
|
94
|
+
const addressingMode = addressingModeRaw === message_1.WA_ADDRESSING_MODES.LID
|
|
95
|
+
? message_1.WA_ADDRESSING_MODES.LID
|
|
96
|
+
: addressingModeRaw === message_1.WA_ADDRESSING_MODES.PN
|
|
97
|
+
? message_1.WA_ADDRESSING_MODES.PN
|
|
98
|
+
: undefined;
|
|
94
99
|
const rawJid = attrs.id ?? attrs.jid ?? '';
|
|
95
100
|
const jid = rawJid && !rawJid.includes('@') ? `${rawJid}@${defaults_1.WA_DEFAULTS.GROUP_SERVER}` : rawJid;
|
|
96
101
|
return {
|
|
@@ -3,7 +3,7 @@ import type { WaAuthCredentials } from '../../auth/types';
|
|
|
3
3
|
import type { DeviceFanoutResolver } from '../messaging/fanout';
|
|
4
4
|
import type { GroupMetadataCache } from '../messaging/group-metadata';
|
|
5
5
|
import type { AppStateSyncKeyProtocol } from '../messaging/key-protocol';
|
|
6
|
-
import type { WaGroupEvent, WaSendMessageOptions, WaSignalMessagePublishInput } from '../types';
|
|
6
|
+
import type { WaGroupEvent, WaOutgoingMessageEvent, WaSendMessageOptions, WaSignalMessagePublishInput } from '../types';
|
|
7
7
|
import type { Logger } from '../../infra/log/types';
|
|
8
8
|
import { type WaSendContextInfo } from '../../message/context-info';
|
|
9
9
|
import { type IcdcMeta } from '../../message/crypto/icdc';
|
|
@@ -26,6 +26,8 @@ import type { BinaryNode } from '../../transport/types';
|
|
|
26
26
|
import type { ServerClock } from '../../util/clock';
|
|
27
27
|
interface WaMessageDispatchCoordinatorOptions {
|
|
28
28
|
readonly logger: Logger;
|
|
29
|
+
/** Emits the outbound decrypted message (`message_send` event); best-effort. */
|
|
30
|
+
readonly emitMessageSend?: (event: WaOutgoingMessageEvent) => void;
|
|
29
31
|
readonly messageClient: WaMessageClient;
|
|
30
32
|
readonly retryTracker: OutboundRetryTracker;
|
|
31
33
|
readonly sessionResolver: SignalSessionResolver;
|
|
@@ -203,6 +203,16 @@ class WaMessageDispatchCoordinator {
|
|
|
203
203
|
}
|
|
204
204
|
: withViewOnce;
|
|
205
205
|
const upload = built.upload;
|
|
206
|
+
if (this.deps.emitMessageSend) {
|
|
207
|
+
try {
|
|
208
|
+
this.deps.emitMessageSend({ to: recipientJid, id: sendOptions.id, message });
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
this.deps.logger.debug('message_send emit failed', {
|
|
212
|
+
message: (0, primitives_2.toError)(error).message
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
206
216
|
const messageWithOverride = options.messageSecret
|
|
207
217
|
? {
|
|
208
218
|
...message,
|
|
@@ -894,17 +904,17 @@ class WaMessageDispatchCoordinator {
|
|
|
894
904
|
resolveGroupAddressingMode(participantUserJids, groupJid) {
|
|
895
905
|
for (let index = 0; index < participantUserJids.length; index += 1) {
|
|
896
906
|
if ((0, jid_1.isLidJid)(participantUserJids[index])) {
|
|
897
|
-
return
|
|
907
|
+
return constants_1.WA_ADDRESSING_MODES.LID;
|
|
898
908
|
}
|
|
899
909
|
}
|
|
900
910
|
this.deps.logger.trace('group addressing mode resolved to pn (default)', {
|
|
901
911
|
groupJid,
|
|
902
912
|
participants: participantUserJids.length
|
|
903
913
|
});
|
|
904
|
-
return
|
|
914
|
+
return constants_1.WA_ADDRESSING_MODES.PN;
|
|
905
915
|
}
|
|
906
916
|
resolveSenderForAddressingMode(addressingMode, meJid) {
|
|
907
|
-
if (addressingMode ===
|
|
917
|
+
if (addressingMode === constants_1.WA_ADDRESSING_MODES.LID) {
|
|
908
918
|
const meLid = this.deps.getCurrentCredentials()?.meLid;
|
|
909
919
|
if (meLid && meLid.includes('@')) {
|
|
910
920
|
try {
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type PhoneNumberToLidMapping } from '../messaging/companion-host';
|
|
2
|
+
import type { CompanionHostPersistence, CompanionRecord } from '../persistence/companion-host';
|
|
3
|
+
import type { WaClientPluginContext } from '../plugins/types';
|
|
4
|
+
import type { WaClientEventMap } from '../types';
|
|
5
|
+
import type { WaClientDependencies } from '../WaClientFactory';
|
|
6
|
+
import type { Logger } from '../../infra/log/types';
|
|
7
|
+
type WaMobileEmit = <K extends keyof WaClientEventMap>(event: K, ...args: Parameters<WaClientEventMap[K]>) => void;
|
|
8
|
+
/** Result of a successful {@link WaMobileCoordinator.linkCompanion}. */
|
|
9
|
+
export interface LinkCompanionResult {
|
|
10
|
+
readonly deviceJid: string;
|
|
11
|
+
readonly keyIndex: number;
|
|
12
|
+
}
|
|
13
|
+
/** Dependencies for {@link WaMobileCoordinator}, injected by the client factory. */
|
|
14
|
+
export interface WaMobileCoordinatorDeps {
|
|
15
|
+
readonly logger: Logger;
|
|
16
|
+
readonly authClient: WaClientDependencies['authClient'];
|
|
17
|
+
readonly messageDispatch: WaClientDependencies['messageDispatch'];
|
|
18
|
+
readonly chatCoordinator: WaClientDependencies['chatCoordinator'];
|
|
19
|
+
readonly deviceSync: WaClientDependencies['signalDeviceSync'];
|
|
20
|
+
readonly appStateStore: WaClientPluginContext['stores']['appState'];
|
|
21
|
+
readonly queryWithContext: WaClientPluginContext['queryWithContext'];
|
|
22
|
+
readonly emitEvent: WaMobileEmit;
|
|
23
|
+
readonly registerIncomingHandler: WaClientPluginContext['registerIncomingHandler'];
|
|
24
|
+
readonly isMobilePrimary: () => boolean;
|
|
25
|
+
readonly persistence?: CompanionHostPersistence;
|
|
26
|
+
readonly includePem?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Hosts companion devices from a mobile-primary session: signs a companion's
|
|
30
|
+
* device identity, uploads `pair-device`, tracks the linked set, and can revoke
|
|
31
|
+
* a device. Exposed at `client.mobile`; requires a registered primary session.
|
|
32
|
+
* Supports the QR ({@link linkCompanion}) and pairing-code
|
|
33
|
+
* ({@link linkCompanionByCode}) flows.
|
|
34
|
+
*/
|
|
35
|
+
export declare class WaMobileCoordinator {
|
|
36
|
+
private readonly authClient;
|
|
37
|
+
private readonly messageDispatch;
|
|
38
|
+
private readonly chatCoordinator;
|
|
39
|
+
private readonly deviceSync;
|
|
40
|
+
private readonly appStateStore;
|
|
41
|
+
private readonly queryWithContext;
|
|
42
|
+
private readonly emitEvent;
|
|
43
|
+
private readonly isMobilePrimary;
|
|
44
|
+
private readonly logger;
|
|
45
|
+
private readonly persistence?;
|
|
46
|
+
private readonly includePem;
|
|
47
|
+
private epoch;
|
|
48
|
+
private pendingCompanionHello;
|
|
49
|
+
private pendingFinish;
|
|
50
|
+
private accountKeyIndexes;
|
|
51
|
+
private pushNameSeeded;
|
|
52
|
+
constructor(deps: WaMobileCoordinatorDeps);
|
|
53
|
+
/**
|
|
54
|
+
* Links the companion from its pairing QR: signs the device identity, uploads
|
|
55
|
+
* `pair-device`, and returns the server-assigned device jid.
|
|
56
|
+
*
|
|
57
|
+
* @throws when there is no primary session or the server rejects the upload
|
|
58
|
+
* (e.g. the linked-device cap is reached).
|
|
59
|
+
*/
|
|
60
|
+
linkCompanion(qr: string): Promise<LinkCompanionResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Links a companion via its 8-character pairing code (the "link with phone
|
|
63
|
+
* number" flow). The companion must have requested a code for this account
|
|
64
|
+
* first (its `companion_hello` is recorded); this drives `primary_hello`,
|
|
65
|
+
* awaits `companion_finish`, and completes the same `pair-device` upload as
|
|
66
|
+
* the QR path.
|
|
67
|
+
*
|
|
68
|
+
* @throws when there is no primary session, no companion is pending, the code
|
|
69
|
+
* is wrong, or the handshake times out.
|
|
70
|
+
*/
|
|
71
|
+
linkCompanionByCode(pairingCode: string): Promise<LinkCompanionResult>;
|
|
72
|
+
/** Re-signs and republishes the key-index list for the current device set. */
|
|
73
|
+
publishKeyIndexList(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Unlinks a companion this primary linked: sends the `remove-companion-device`
|
|
76
|
+
* IQ, drops it from the tracked set, and republishes the key-index list for
|
|
77
|
+
* the reduced device set.
|
|
78
|
+
*
|
|
79
|
+
* @throws when there is no registered primary session, the companion is not
|
|
80
|
+
* tracked, or the server rejects the removal.
|
|
81
|
+
*/
|
|
82
|
+
revokeCompanion(companionDeviceJid: string, reason?: string): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Unlinks EVERY companion from the account in a single `remove-companion-device`
|
|
85
|
+
* `all="true"` stanza (the phone's "log out all companion devices"), clears the
|
|
86
|
+
* tracked set, and republishes the key-index list for the primary alone.
|
|
87
|
+
* `excludeHostedCompanion` spares companions this account itself hosts.
|
|
88
|
+
*
|
|
89
|
+
* @throws when there is no registered primary session or the server rejects
|
|
90
|
+
* the removal.
|
|
91
|
+
*/
|
|
92
|
+
revokeAllCompanions(reason?: string, options?: {
|
|
93
|
+
readonly excludeHostedCompanion?: boolean;
|
|
94
|
+
}): Promise<void>;
|
|
95
|
+
/** Returns the companions this primary has linked in the current epoch. */
|
|
96
|
+
listCompanions(): Promise<readonly CompanionRecord[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Reconciles the tracked companion set against the account's live device list
|
|
99
|
+
* on the server (`usync`). Drops companions the server no longer lists - one
|
|
100
|
+
* the user unlinked, or one that self-removed while the primary was offline -
|
|
101
|
+
* then persists and emits `companion_host_revoked` for each. Runs on connect
|
|
102
|
+
* and on `account_sync`; safe to call manually. A no-op (no server query, no
|
|
103
|
+
* epoch created) when no companions are tracked. Returns the removed jids.
|
|
104
|
+
*/
|
|
105
|
+
reconcileCompanions(): Promise<readonly string[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Prunes tracked companions to those whose device slot is still in
|
|
108
|
+
* `serverDeviceIndexes`, persisting + emitting `companion_host_revoked` for
|
|
109
|
+
* each drop. Shared by the connect-time (`usync`) and `account_sync` paths.
|
|
110
|
+
*/
|
|
111
|
+
private pruneCompanionsToDevices;
|
|
112
|
+
/**
|
|
113
|
+
* Reconciles from an `account_sync` notification's `<devices>` payload - the
|
|
114
|
+
* fresh, authoritative device set - so a companion the user just unlinked is
|
|
115
|
+
* pruned immediately (no `usync` round-trip, which would read a stale cache).
|
|
116
|
+
*/
|
|
117
|
+
private reconcileFromAccountSync;
|
|
118
|
+
/**
|
|
119
|
+
* Shares the primary's active app-state sync key with a linked companion via
|
|
120
|
+
* an `APP_STATE_SYNC_KEY_SHARE` peer message so it can decrypt app-state.
|
|
121
|
+
* Establishes the outbound Signal session on demand, so call it once the
|
|
122
|
+
* companion is online (prekeys uploaded), not at link time.
|
|
123
|
+
*
|
|
124
|
+
* @throws when there is no primary session or no active sync key.
|
|
125
|
+
*/
|
|
126
|
+
shareAppStateSyncKeys(companionDeviceJid: string): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Pushes the `INITIAL_BOOTSTRAP` history sync to a linked companion as a
|
|
129
|
+
* `HISTORY_SYNC_NOTIFICATION` peer message. Flips the companion's
|
|
130
|
+
* `initialChatHistory` bootstrap flag; without it the companion self-removes
|
|
131
|
+
* with `HistorySyncTimeout`. Requires the companion online with prekeys.
|
|
132
|
+
*
|
|
133
|
+
* @throws when there is no registered primary session.
|
|
134
|
+
*/
|
|
135
|
+
sendHistorySyncBootstrap(companionDeviceJid: string, options?: {
|
|
136
|
+
readonly phoneNumberToLidMappings?: readonly PhoneNumberToLidMapping[];
|
|
137
|
+
}): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* `ClientPairingProps` for the `<client-props>` pair-device element. A
|
|
140
|
+
* LID-native primary declares the chat DB LID-migrated + pure-LID session so
|
|
141
|
+
* the companion runs `setIsLidMigrated` at pair time and does not self-remove
|
|
142
|
+
* on its LID-addressed blocklist.
|
|
143
|
+
*/
|
|
144
|
+
private buildClientPairingProps;
|
|
145
|
+
/**
|
|
146
|
+
* Seeds the primary's own `setting_pushName` into the `critical_block`
|
|
147
|
+
* app-state collection, once per session. The companion's critical bootstrap
|
|
148
|
+
* completes only when it finds an applied `SettingPushName` action; without
|
|
149
|
+
* one it self-removes with `syncd_timeout`. Falls back to the account phone
|
|
150
|
+
* number when no push name is set. Idempotent and best-effort.
|
|
151
|
+
*/
|
|
152
|
+
private ensureAccountPushNameAppState;
|
|
153
|
+
private completeLink;
|
|
154
|
+
/**
|
|
155
|
+
* Best-effort background provisioning after a companion links: pushes the
|
|
156
|
+
* history-sync bootstrap and shares the app-state sync key. Fire-and-forget
|
|
157
|
+
* and retried, because the companion needs a moment to upload prekeys before
|
|
158
|
+
* the outbound Signal session these peer messages ride on can be established.
|
|
159
|
+
*/
|
|
160
|
+
private provisionLinkedCompanion;
|
|
161
|
+
private provisionLinkedCompanionWithRetry;
|
|
162
|
+
private handleNotification;
|
|
163
|
+
/**
|
|
164
|
+
* Tracks the account's live device key-indexes from an `account_sync`
|
|
165
|
+
* notification so a new companion gets a non-colliding key index and the
|
|
166
|
+
* published key-index list keeps every existing device valid.
|
|
167
|
+
*/
|
|
168
|
+
private updateAccountKeyIndexes;
|
|
169
|
+
private forgetAccountKeyIndex;
|
|
170
|
+
/**
|
|
171
|
+
* The key indexes currently valid for this account - index 0 (the primary),
|
|
172
|
+
* the account's own live devices, and every tracked companion. Sorted
|
|
173
|
+
* ascending. Deliberately excludes `epoch.currentKeyIndex`, which is an
|
|
174
|
+
* allocation high-water mark, not proof a device still exists: after revoking
|
|
175
|
+
* the last-linked companion its index must drop out of the published list.
|
|
176
|
+
*/
|
|
177
|
+
private validKeyIndexes;
|
|
178
|
+
/**
|
|
179
|
+
* Allocates the next companion key index, advancing strictly past both the
|
|
180
|
+
* epoch's monotonic high-water mark and every currently-valid index so a
|
|
181
|
+
* revoked index is never reused (reuse breaks previously linked devices).
|
|
182
|
+
*/
|
|
183
|
+
private nextKeyIndex;
|
|
184
|
+
private storeCompanionHello;
|
|
185
|
+
private resolveCompanionFinish;
|
|
186
|
+
private nodeBytes;
|
|
187
|
+
private requirePrimaryIdentityKeyPair;
|
|
188
|
+
private ensureEpoch;
|
|
189
|
+
private generateRawId;
|
|
190
|
+
private persist;
|
|
191
|
+
}
|
|
192
|
+
export {};
|