zapo-js 1.2.1 → 1.4.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.
Files changed (67) hide show
  1. package/dist/auth/WaAuthClient.d.ts +15 -0
  2. package/dist/auth/WaAuthClient.js +47 -0
  3. package/dist/auth/pairing/WaShortcakeFlow.d.ts +93 -0
  4. package/dist/auth/pairing/WaShortcakeFlow.js +210 -0
  5. package/dist/auth/pairing/pairing-code-crypto.d.ts +1 -0
  6. package/dist/auth/pairing/pairing-code-crypto.js +3 -2
  7. package/dist/auth/pairing/shortcake-crypto.d.ts +59 -0
  8. package/dist/auth/pairing/shortcake-crypto.js +106 -0
  9. package/dist/client/WaClient.d.ts +84 -49
  10. package/dist/client/WaClient.js +70 -50
  11. package/dist/client/WaClientFactory.d.ts +7 -0
  12. package/dist/client/WaClientFactory.js +4 -1
  13. package/dist/client/coordinators/WaRetryCoordinator.js +1 -0
  14. package/dist/client/plugins/define.d.ts +23 -0
  15. package/dist/client/plugins/define.js +22 -0
  16. package/dist/client/plugins/index.d.ts +4 -0
  17. package/dist/client/plugins/index.js +9 -0
  18. package/dist/client/plugins/install.d.ts +18 -0
  19. package/dist/client/plugins/install.js +83 -0
  20. package/dist/client/plugins/types.d.ts +76 -0
  21. package/dist/client/plugins/types.js +6 -0
  22. package/dist/client/types.d.ts +25 -0
  23. package/dist/esm/auth/WaAuthClient.js +48 -1
  24. package/dist/esm/auth/pairing/WaShortcakeFlow.js +206 -0
  25. package/dist/esm/auth/pairing/pairing-code-crypto.js +2 -2
  26. package/dist/esm/auth/pairing/shortcake-crypto.js +99 -0
  27. package/dist/esm/client/WaClient.js +70 -49
  28. package/dist/esm/client/WaClientFactory.js +4 -1
  29. package/dist/esm/client/coordinators/WaRetryCoordinator.js +1 -0
  30. package/dist/esm/client/plugins/define.js +19 -0
  31. package/dist/esm/client/plugins/index.js +3 -0
  32. package/dist/esm/client/plugins/install.js +80 -0
  33. package/dist/esm/client/plugins/types.js +3 -0
  34. package/dist/esm/index.js +2 -0
  35. package/dist/esm/infra/log/ConsoleLogger.js +3 -9
  36. package/dist/esm/infra/log/PinoLogger.js +24 -12
  37. package/dist/esm/infra/log/types.js +8 -1
  38. package/dist/esm/protocol/nodes.js +2 -0
  39. package/dist/esm/protocol/notification.js +3 -1
  40. package/dist/esm/retry/replay.js +4 -12
  41. package/dist/esm/transport/index.js +2 -0
  42. package/dist/esm/transport/node/builders/shortcake.js +50 -0
  43. package/dist/esm/transport/noise/WaClientPayload.js +1 -1
  44. package/dist/esm/util/index.js +1 -1
  45. package/dist/index.d.ts +5 -0
  46. package/dist/index.js +7 -2
  47. package/dist/infra/log/ConsoleLogger.d.ts +4 -2
  48. package/dist/infra/log/ConsoleLogger.js +5 -11
  49. package/dist/infra/log/PinoLogger.d.ts +4 -2
  50. package/dist/infra/log/PinoLogger.js +24 -12
  51. package/dist/infra/log/types.d.ts +8 -1
  52. package/dist/infra/log/types.js +9 -1
  53. package/dist/protocol/nodes.d.ts +2 -0
  54. package/dist/protocol/nodes.js +2 -0
  55. package/dist/protocol/notification.d.ts +2 -0
  56. package/dist/protocol/notification.js +3 -1
  57. package/dist/retry/replay.d.ts +1 -0
  58. package/dist/retry/replay.js +4 -12
  59. package/dist/transport/index.d.ts +3 -0
  60. package/dist/transport/index.js +11 -1
  61. package/dist/transport/node/builders/shortcake.d.ts +19 -0
  62. package/dist/transport/node/builders/shortcake.js +57 -0
  63. package/dist/transport/noise/WaClientPayload.d.ts +2 -0
  64. package/dist/transport/noise/WaClientPayload.js +1 -0
  65. package/dist/util/index.d.ts +1 -1
  66. package/dist/util/index.js +4 -1
  67. package/package.json +1 -1
@@ -0,0 +1,80 @@
1
+ import { isWaClientExposePluginDefinition } from '../plugins/types.js';
2
+ import { toError } from '../../util/primitives.js';
3
+ /**
4
+ * Installs {@link WaClientOptions.plugins} on `client`. Returns a dispose
5
+ * function invoked by {@link WaClient.disconnect}.
6
+ */
7
+ export function installWaClientPlugins(client, input, plugins) {
8
+ const seenIds = new Set();
9
+ const seenExposeAs = new Set();
10
+ const disposeCallbacks = [];
11
+ const registerDispose = (fn) => {
12
+ disposeCallbacks[disposeCallbacks.length] = fn;
13
+ };
14
+ const baseCtx = {
15
+ client,
16
+ options: input.options,
17
+ logger: input.logger,
18
+ stores: input.stores,
19
+ deps: input.deps,
20
+ emit: client.emit.bind(client),
21
+ on: client.on.bind(client),
22
+ off: client.off.bind(client),
23
+ once: client.once.bind(client),
24
+ queryWithContext: input.queryWithContext,
25
+ registerIncomingHandler: (registration) => input.deps.lowLevelCoordinator.registerIncomingHandler(registration),
26
+ registerIncomingStanzaFilter: (filter) => input.deps.lowLevelCoordinator.registerIncomingStanzaFilter(filter),
27
+ registerDispose
28
+ };
29
+ for (let index = 0; index < plugins.length; index += 1) {
30
+ const plugin = plugins[index];
31
+ if (seenIds.has(plugin.id)) {
32
+ throw new Error(`duplicate wa client plugin id: ${plugin.id}`);
33
+ }
34
+ seenIds.add(plugin.id);
35
+ const pluginCtx = {
36
+ ...baseCtx,
37
+ logger: input.logger.child({ plugin: plugin.id })
38
+ };
39
+ if (isWaClientExposePluginDefinition(plugin)) {
40
+ if (seenExposeAs.has(plugin.exposeAs)) {
41
+ throw new Error(`duplicate wa client plugin exposeAs: ${plugin.exposeAs}`);
42
+ }
43
+ seenExposeAs.add(plugin.exposeAs);
44
+ if (plugin.exposeAs in client) {
45
+ throw new Error(`wa client plugin exposeAs "${plugin.exposeAs}" collides with a reserved client member`);
46
+ }
47
+ const instance = plugin.setup(pluginCtx);
48
+ Object.defineProperty(client, plugin.exposeAs, {
49
+ get: () => instance,
50
+ enumerable: true,
51
+ configurable: false
52
+ });
53
+ if (plugin.dispose) {
54
+ const dispose = plugin.dispose;
55
+ registerDispose(() => dispose(instance, pluginCtx));
56
+ }
57
+ pluginCtx.logger.debug('wa client plugin installed', { exposeAs: plugin.exposeAs });
58
+ }
59
+ else {
60
+ plugin.setup(pluginCtx);
61
+ if (plugin.dispose) {
62
+ const dispose = plugin.dispose;
63
+ registerDispose(() => dispose(undefined, pluginCtx));
64
+ }
65
+ pluginCtx.logger.debug('wa client plugin installed');
66
+ }
67
+ }
68
+ return async () => {
69
+ for (let index = disposeCallbacks.length - 1; index >= 0; index -= 1) {
70
+ try {
71
+ await disposeCallbacks[index]();
72
+ }
73
+ catch (error) {
74
+ input.logger.warn('wa client plugin dispose failed', {
75
+ message: toError(error).message
76
+ });
77
+ }
78
+ }
79
+ };
80
+ }
@@ -0,0 +1,3 @@
1
+ export function isWaClientExposePluginDefinition(plugin) {
2
+ return plugin.exposeAs !== undefined && plugin.exposeAs.length > 0;
3
+ }
package/dist/esm/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  export { WaClient } from './client/index.js';
2
+ export { defineWaClientPlugin } from './client/plugins/index.js';
2
3
  export { downloadMediaMessage } from './client/media.js';
3
4
  export { parseUsyncResultEnvelope } from './transport/node/builders/usync.js';
4
5
  export { getContentType, resolveMessageTarget } from './message/encode/content.js';
5
6
  export { resolveMediaPayload } from './message/encode/media-payload.js';
7
+ export { unpadPkcs7, writeRandomPadMax16 } from './message/encode/padding.js';
6
8
  export { fetchLatestWaWebVersion } from './transport/wa-web-version-fetcher.js';
7
9
  export { ConsoleLogger } from './infra/log/ConsoleLogger.js';
8
10
  export { PinoLogger, createPinoLogger } from './infra/log/PinoLogger.js';
@@ -1,10 +1,4 @@
1
- const LOG_LEVEL_PRIORITY = {
2
- trace: 10,
3
- debug: 20,
4
- info: 30,
5
- warn: 40,
6
- error: 50
7
- };
1
+ import { LOG_LEVEL_PRIORITY } from '../log/types.js';
8
2
  const CONSOLE_WRITERS = {
9
3
  trace: (...args) => console.debug(...args),
10
4
  debug: (...args) => console.debug(...args),
@@ -48,9 +42,9 @@ export class ConsoleLogger {
48
42
  * Returns a derived logger with `bindings` merged into the parent's
49
43
  * bindings. Per-call context still wins on key conflicts.
50
44
  */
51
- child(bindings) {
45
+ child(bindings, options) {
52
46
  const merged = this.bindings ? { ...this.bindings, ...bindings } : { ...bindings };
53
- return new ConsoleLogger(this.level, merged);
47
+ return new ConsoleLogger(options?.level ?? this.level, merged);
54
48
  }
55
49
  write(level, message, context) {
56
50
  if (LOG_LEVEL_PRIORITY[level] < this.minLevelPriority) {
@@ -1,3 +1,4 @@
1
+ import { LOG_LEVEL_PRIORITY } from '../log/types.js';
1
2
  const PINO_MODULE = 'pino';
2
3
  const PINO_PRETTY_MODULE = 'pino-pretty';
3
4
  async function loadPinoFactory() {
@@ -57,11 +58,11 @@ export class PinoLogger {
57
58
  * call's context. Delegates to the underlying pino `child()` when
58
59
  * available; otherwise wraps with a parent + bindings merge.
59
60
  */
60
- child(bindings) {
61
+ child(bindings, options) {
61
62
  if (typeof this.logger.child === 'function') {
62
- return new PinoLogger(this.logger.child(bindings), this.level);
63
+ return new PinoLogger(this.logger.child(bindings), options?.level ?? this.level);
63
64
  }
64
- return new BoundLogger(this, bindings);
65
+ return new BoundLogger(this, bindings, options?.level);
65
66
  }
66
67
  write(level, message, context) {
67
68
  if (context === null || context === undefined) {
@@ -83,28 +84,39 @@ export class PinoLogger {
83
84
  * underlying logger does not support `child()` natively.
84
85
  */
85
86
  class BoundLogger {
86
- constructor(parent, bindings) {
87
+ constructor(parent, bindings, level) {
87
88
  this.parent = parent;
88
- this.level = parent.level;
89
+ this.level = level ?? parent.level;
89
90
  this.bindings = bindings;
91
+ this.minPriority = LOG_LEVEL_PRIORITY[this.level];
90
92
  }
91
93
  trace(message, context) {
92
- this.parent.trace(message, this.merge(context));
94
+ if (LOG_LEVEL_PRIORITY.trace >= this.minPriority) {
95
+ this.parent.trace(message, this.merge(context));
96
+ }
93
97
  }
94
98
  debug(message, context) {
95
- this.parent.debug(message, this.merge(context));
99
+ if (LOG_LEVEL_PRIORITY.debug >= this.minPriority) {
100
+ this.parent.debug(message, this.merge(context));
101
+ }
96
102
  }
97
103
  info(message, context) {
98
- this.parent.info(message, this.merge(context));
104
+ if (LOG_LEVEL_PRIORITY.info >= this.minPriority) {
105
+ this.parent.info(message, this.merge(context));
106
+ }
99
107
  }
100
108
  warn(message, context) {
101
- this.parent.warn(message, this.merge(context));
109
+ if (LOG_LEVEL_PRIORITY.warn >= this.minPriority) {
110
+ this.parent.warn(message, this.merge(context));
111
+ }
102
112
  }
103
113
  error(message, context) {
104
- this.parent.error(message, this.merge(context));
114
+ if (LOG_LEVEL_PRIORITY.error >= this.minPriority) {
115
+ this.parent.error(message, this.merge(context));
116
+ }
105
117
  }
106
- child(bindings) {
107
- return new BoundLogger(this.parent, { ...this.bindings, ...bindings });
118
+ child(bindings, options) {
119
+ return new BoundLogger(this.parent, { ...this.bindings, ...bindings }, options?.level ?? this.level);
108
120
  }
109
121
  merge(context) {
110
122
  return context ? { ...this.bindings, ...context } : this.bindings;
@@ -1,3 +1,10 @@
1
+ export const LOG_LEVEL_PRIORITY = {
2
+ trace: 10,
3
+ debug: 20,
4
+ info: 30,
5
+ warn: 40,
6
+ error: 50
7
+ };
1
8
  function noop() { }
2
9
  export function createNoopLogger(level = 'trace') {
3
10
  const logger = {
@@ -7,7 +14,7 @@ export function createNoopLogger(level = 'trace') {
7
14
  info: noop,
8
15
  warn: noop,
9
16
  error: noop,
10
- child: () => logger
17
+ child: (_bindings, options) => (options?.level ? createNoopLogger(options.level) : logger)
11
18
  };
12
19
  return logger;
13
20
  }
@@ -50,6 +50,8 @@ export const WA_NODE_TAGS = Object.freeze({
50
50
  COUNTRY_CODE: 'country_code',
51
51
  DEVICE_IDENTITY: 'device-identity',
52
52
  PLATFORM: 'platform',
53
+ PASSKEY_REQUEST_OPTIONS: 'passkey_request_options',
54
+ PRIMARY_EPHEMERAL_IDENTITY: 'primary_ephemeral_identity',
53
55
  SUBJECT: 'subject',
54
56
  BODY: 'body',
55
57
  PARTICIPANT: 'participant',
@@ -6,7 +6,9 @@ export const WA_NOTIFICATION_TYPES = Object.freeze({
6
6
  REGISTRATION: 'registration',
7
7
  NEWSLETTER: 'newsletter',
8
8
  BUSINESS: 'business',
9
- PICTURE: 'picture'
9
+ PICTURE: 'picture',
10
+ PASSKEY_PROLOGUE_REQUEST: 'passkey_prologue_request',
11
+ CRSC_CONTINUATION: 'crsc_continuation'
10
12
  });
11
13
  export const WA_BUSINESS_NOTIFICATION_TAGS = Object.freeze({
12
14
  VERIFIED_NAME: 'verified_name',
@@ -85,9 +85,9 @@ export class WaRetryReplayService {
85
85
  resolveSignedDeviceIdentity(context) {
86
86
  const signedIdentity = this.options.getCurrentCredentials()?.signedIdentity;
87
87
  if (!signedIdentity) {
88
- this.options.logger.warn('retry request missing signed identity for pkmsg envelope', {
89
- context
90
- });
88
+ if (!this.options.isMobilePrimary?.()) {
89
+ this.options.logger.warn('retry request missing signed identity for pkmsg envelope', { context });
90
+ }
91
91
  return undefined;
92
92
  }
93
93
  return proto.ADVSignedDeviceIdentity.encode(signedIdentity).finish();
@@ -179,15 +179,7 @@ export class WaRetryReplayService {
179
179
  logContext: 'group'
180
180
  })) ?? payload.plaintext;
181
181
  const encrypted = await this.options.signalProtocol.encryptMessage(requesterAddress, plaintext);
182
- let deviceIdentity;
183
- if (encrypted.type === 'pkmsg') {
184
- const signedIdentity = this.options.getCurrentCredentials()?.signedIdentity;
185
- if (!signedIdentity) {
186
- this.options.logger.warn('retry request rejected: missing signed identity for pkmsg group retry');
187
- return 'ineligible';
188
- }
189
- deviceIdentity = proto.ADVSignedDeviceIdentity.encode(signedIdentity).finish();
190
- }
182
+ const deviceIdentity = encrypted.type === 'pkmsg' ? this.resolveSignedDeviceIdentity('group') : undefined;
191
183
  const isStatus = isStatusBroadcastJid(payload.to);
192
184
  const metaAttrs = {};
193
185
  if (isStatus) {
@@ -12,3 +12,5 @@ export { WaNodeTransport } from './node/WaNodeTransport.js';
12
12
  export { WaMobileTcpSocket, WaMobileTcpSocketCtor } from './node/WaMobileTcpSocket.js';
13
13
  export { buildMobileLoginPayload } from './noise/WaMobileClientPayload.js';
14
14
  export { assertIqResult, buildIqNode, parseIqError, queryWithContext } from './node/query.js';
15
+ export { buildAckNode, buildReceiptNode } from './node/builders/global.js';
16
+ export { findNodeChild, getFirstNodeChild, getNodeChildren, getNodeChildrenByTag, getNodeTextContent, hasNodeChild } from './node/helpers.js';
@@ -0,0 +1,50 @@
1
+ import { WA_DEFAULTS, WA_IQ_TYPES, WA_NODE_TAGS, WA_XMLNS } from '../../../protocol/constants.js';
2
+ import { buildIqNode } from '../../node/query.js';
3
+ /**
4
+ * IQ builders for the WhatsApp "Shortcake" companion-linking protocol
5
+ * (`xmlns="md"`). Wire shapes mirror the official client's
6
+ * `WASmaxOutMd…Request` builders. The stanza `id` is assigned by the socket
7
+ * query layer, matching the other pairing builders.
8
+ */
9
+ function mdIq(type, content) {
10
+ return buildIqNode(type, WA_DEFAULTS.HOST_DOMAIN, WA_XMLNS.MD, content);
11
+ }
12
+ /** `<iq type="get" xmlns="md"><passkey_request_options/></iq>` */
13
+ export function buildGetPasskeyRequestOptionsRequestNode() {
14
+ return mdIq(WA_IQ_TYPES.GET, [
15
+ { tag: WA_NODE_TAGS.PASSKEY_REQUEST_OPTIONS, attrs: {}, content: undefined }
16
+ ]);
17
+ }
18
+ /** `<iq type="get" xmlns="md"><ref/></iq>` */
19
+ export function buildShortcakeGetRefRequestNode() {
20
+ return mdIq(WA_IQ_TYPES.GET, [{ tag: WA_NODE_TAGS.REF, attrs: {}, content: undefined }]);
21
+ }
22
+ /**
23
+ * `<iq type="set" xmlns="md"><passkey_prologue><credential_id/><webauthn_assertion/>`
24
+ * `<prologue_payload/>[<pairing_handoff_proof/>]</passkey_prologue></iq>`
25
+ */
26
+ export function buildSetPasskeyPrologueRequestNode(args) {
27
+ const children = [
28
+ { tag: 'credential_id', attrs: {}, content: args.credentialId },
29
+ { tag: 'webauthn_assertion', attrs: {}, content: args.webauthnAssertion },
30
+ { tag: 'prologue_payload', attrs: {}, content: args.prologuePayload }
31
+ ];
32
+ if (args.pairingHandoffProof) {
33
+ children.push({
34
+ tag: 'pairing_handoff_proof',
35
+ attrs: {},
36
+ content: args.pairingHandoffProof
37
+ });
38
+ }
39
+ return mdIq(WA_IQ_TYPES.SET, [{ tag: 'passkey_prologue', attrs: {}, content: children }]);
40
+ }
41
+ /** `<iq type="set" xmlns="md"><companion_nonce/></iq>` */
42
+ export function buildSetCompanionNonceRequestNode(companionNonce) {
43
+ return mdIq(WA_IQ_TYPES.SET, [{ tag: 'companion_nonce', attrs: {}, content: companionNonce }]);
44
+ }
45
+ /** `<iq type="set" xmlns="md"><encrypted_pairing_request/></iq>` */
46
+ export function buildSetEncryptedPairingRequestRequestNode(encryptedPairingRequest) {
47
+ return mdIq(WA_IQ_TYPES.SET, [
48
+ { tag: 'encrypted_pairing_request', attrs: {}, content: encryptedPairingRequest }
49
+ ]);
50
+ }
@@ -33,7 +33,7 @@ function resolveLocale() {
33
33
  function defaultWebSubPlatform() {
34
34
  return proto.ClientPayload.WebInfo.WebSubPlatform.WEB_BROWSER;
35
35
  }
36
- function resolveDevicePropsPlatformType(deviceBrowser) {
36
+ export function resolveDevicePropsPlatformType(deviceBrowser) {
37
37
  const normalized = deviceBrowser?.trim().toLowerCase();
38
38
  switch (normalized) {
39
39
  case 'chrome':
@@ -1,4 +1,4 @@
1
- export { base64ToBytes, bytesToBase64, bytesToBase64UrlSafe, bytesToHex, decodeBase64Url, hexToBytes, TEXT_DECODER, toBytesView, uint8Equal, uint8TimingSafeEqual } from './bytes.js';
1
+ export { base64ToBytes, bytesToBase64, bytesToBase64UrlSafe, bytesToHex, concatBytes, decodeBase64Url, EMPTY_BYTES, hexToBytes, TEXT_DECODER, TEXT_ENCODER, toBytesView, uint8Equal, uint8TimingSafeEqual } from './bytes.js';
2
2
  export { asBytes, asNumber, asOptionalBytes, asOptionalNumber, asOptionalString, asString, resolvePositive, toBoolOrUndef } from './coercion.js';
3
3
  export { normalizeQueryLimit } from './collections.js';
4
4
  export { toError, toSafeNumber } from './primitives.js';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export { WaClient } from './client';
2
+ export { defineWaClientPlugin } from './client/plugins';
3
+ export type { WaClientDependencies } from './client/WaClientFactory';
2
4
  export type { WaClientEventMap, WaClientOptions, WaClientProxyOptions, WaDownloadMediaOptions, WaHistorySyncChunkEvent, WaHistorySyncOptions, WaWriteBehindOptions } from './client/types';
5
+ export type { WaClientPluginContext, WaClientPluginDefinition } from './client/plugins';
3
6
  export type { WaMessageCoordinator } from './client/coordinators/WaMessageCoordinator';
4
7
  export type { WaAccountTakeoverNoticeEvent, WaAppStateMutationEvent, WaAppStateMutationSource, WaBusinessEvent, WaBusinessEventAction, WaBusinessProfileResult, WaConnectionEvent, WaGroupEvent, WaGroupEventAction, WaGroupEventLinkedGroup, WaGroupEventMembershipRequest, WaGroupEventParticipant, WaGroupEventSubgroupSuggestion, WaIgnoreKey, WaIgnoreKeyContext, WaIgnoreKeyPredicate, WaIgnoreStanzaKind, WaIncomingAddonEvent, WaIncomingBaseEvent, WaIncomingBotChunkEvent, WaIncomingCallEvent, WaIncomingChatstateEvent, WaIncomingErrorStanzaEvent, WaIncomingFailureEvent, WaIncomingMessageEvent, WaIncomingMessageKey, WaIncomingNewsletterEvent, WaIncomingNewsletterMessageUpdateEvent, WaIncomingNodeHandler, WaIncomingNodeHandlerRegistration, WaIncomingNotificationEvent, WaIncomingPresenceEvent, WaIncomingProtocolMessageEvent, WaIncomingReceiptEvent, WaIncomingStanzaFilter, WaIncomingUnavailableMessageEvent, WaIncomingUnhandledStanzaEvent, WaMexLidChangeEvent, WaMexMessageCappingEvent, WaMexMessageCappingStatus, WaMexNotificationEvent, WaMexNotificationGraphQlError, WaMexNotificationOperationName, WaMexNotificationUnknownEvent, WaMexOwnUsernameSyncEvent, WaMexTextStatusUpdateEvent, WaMexTextStatusUpdateHintEvent, WaMexUsernameDeleteEvent, WaMexUsernameSetEvent, WaMexUsernameUpdateHintEvent, WaOfflineResumeEvent, WaPictureEvent, WaPictureEventAction, WaPrivacyTokenUpdateEvent, WaReceiptStatus, WaRegistrationCodeEvent, WaSendMessageOptions, WaUnavailableMessageKind, WaVerifiedNameResult, WaAddonKind, WaNewsletterEventAction, WaNewsletterMessageUpdate, WaNewsletterPollVoteEntry, WaNewsletterReactionEntry } from './client/types';
5
8
  export type { WaAppStateMutationCoordinator, WaBroadcastListParticipant, WaSetBroadcastListInput, WaSetStatusPrivacyInput } from './client/coordinators/WaAppStateMutationCoordinator';
@@ -21,11 +24,13 @@ export type { WaSendStatusInput, WaStatusCoordinator } from './client/coordinato
21
24
  export type { WaEncryptedMessageInput, WaMessageAckMetadata, WaMessageKey, WaMessagePublishOptions, WaMessagePublishResult, WaMessageRef, WaMessageTargetInput, WaSendEditKey, WaSendEventLocation, WaSendEventMessage, WaSendEventParent, WaSendEventResponseMessage, WaSendEventResponseType, WaSendKeepMessage, WaSendMediaMessage, WaSendMessageContent, WaSendPinMessage, WaSendPollMessage, WaSendPollOptionInput, WaSendPollParent, WaSendPollVoteMessage, WaSendReactionMessage, WaSendReceiptEventOptions, WaSendReceiptInput, WaSendReceiptOptions, WaSendRevokeMessage, WaSendStickerPackMessage, WaSendStickerPackStickerInput, WaSendStickerPackTrayIcon, WaSendTextMessage } from './message/types';
22
25
  export { getContentType, resolveMessageTarget } from './message/encode/content';
23
26
  export { resolveMediaPayload } from './message/encode/media-payload';
27
+ export { unpadPkcs7, writeRandomPadMax16 } from './message/encode/padding';
24
28
  export type { WaResolvedMediaPayload } from './message/encode/media-payload';
25
29
  export type { WaSendContextInfo } from './message/context-info';
26
30
  export type { WaLinkPreviewFetcher, WaLinkPreviewOptions, WaLinkPreviewOverride, WaLinkPreviewResolved, WaLinkPreviewThumbnailBytes, WaLinkPreviewThumbnailInput, WaLinkPreviewThumbnailStream, WaLinkPreviewType } from './message/addons/link-preview/types';
27
31
  export type { SignalLidSyncResult } from './signal/api/SignalDeviceSyncApi';
28
32
  export type { WaAuthCredentials, WaVersionResolver } from './auth/types';
33
+ export type { WaShortcakeAssertionSigner } from './auth/pairing/WaShortcakeFlow';
29
34
  export type { BinaryNode } from './transport/types';
30
35
  export { fetchLatestWaWebVersion } from './transport/wa-web-version-fetcher';
31
36
  export type { WaFetchLatestWebVersionOptions, WaLatestWebVersion } from './transport/wa-web-version-fetcher';
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WA_COMPANION_PLATFORM_IDS = exports.WA_BUSINESS_HOURS_MODES = exports.WA_BUSINESS_HOURS_DAYS = exports.WA_BROWSERS = exports.WA_APP_STATE_SYNC_DATA_TYPE = exports.WA_APP_STATE_KEY_TYPES = exports.WA_APP_STATE_KDF_INFO = exports.WA_APP_STATE_ERROR_CODES = exports.WA_APP_STATE_COLLECTION_STATES = exports.WA_APP_STATE_COLLECTIONS = exports.WA_ACCOUNT_SYNC_PROTOCOLS = exports.toUserJid = exports.splitJid = exports.signalAddressKey = exports.parseSignalAddressFromJid = exports.parsePhoneJid = exports.parseJidFull = exports.normalizeRecipientJid = exports.normalizeDeviceJid = exports.isUserJid = exports.isStatusBroadcastJid = exports.isNewsletterJid = exports.isLidJid = exports.isHostedServer = exports.isHostedDeviceJid = exports.isHostedDeviceId = exports.isGroupOrBroadcastJid = exports.isGroupJid = exports.isBroadcastJid = exports.isBotJid = exports.getWaMediaHkdfInfo = exports.getWaCompanionPlatformId = exports.getLoginIdentity = exports.canonicalizeSignalServer = exports.canonicalizeSignalJid = exports.buildDeviceJid = exports.delay = exports.WaAuthMemoryStore = exports.createStore = exports.createNoopLogger = exports.createPinoLogger = exports.PinoLogger = exports.ConsoleLogger = exports.fetchLatestWaWebVersion = exports.resolveMediaPayload = exports.resolveMessageTarget = exports.getContentType = exports.parseUsyncResultEnvelope = exports.downloadMediaMessage = exports.WaClient = void 0;
4
- exports.proto = exports.WA_XMLNS = exports.WA_PRIVACY_VALUES = exports.WA_PRIVACY_TAGS = exports.WA_PRIVACY_SETTING_TO_CATEGORY = exports.WA_PRIVACY_DISALLOWED_LIST_CATEGORIES = exports.WA_PRIVACY_CATEGORY_TO_SETTING = exports.WA_PRIVACY_CATEGORIES = exports.WA_SUPPORTED_DIRTY_TYPES = exports.WA_STREAM_SIGNALING = exports.WA_SIGNALING = exports.WA_RETRYABLE_ACK_CODES = exports.WA_READY_STATES = exports.WA_PREVIEW_MEDIA_HKDF_INFO = exports.WA_PAIRING_KDF_INFO = exports.WA_NODE_TAGS = exports.WA_MEDIA_HKDF_INFO = exports.WA_MESSAGE_TYPES = exports.WA_MESSAGE_TAGS = exports.WA_LOGOUT_REASONS = exports.WA_IQ_TYPES = exports.WA_DISCONNECT_REASONS = exports.WA_DIRTY_TYPES = exports.WA_DIRTY_PROTOCOLS = exports.WA_DEFAULTS = void 0;
3
+ exports.WA_BROWSERS = exports.WA_APP_STATE_SYNC_DATA_TYPE = exports.WA_APP_STATE_KEY_TYPES = exports.WA_APP_STATE_KDF_INFO = exports.WA_APP_STATE_ERROR_CODES = exports.WA_APP_STATE_COLLECTION_STATES = exports.WA_APP_STATE_COLLECTIONS = exports.WA_ACCOUNT_SYNC_PROTOCOLS = exports.toUserJid = exports.splitJid = exports.signalAddressKey = exports.parseSignalAddressFromJid = exports.parsePhoneJid = exports.parseJidFull = exports.normalizeRecipientJid = exports.normalizeDeviceJid = exports.isUserJid = exports.isStatusBroadcastJid = exports.isNewsletterJid = exports.isLidJid = exports.isHostedServer = exports.isHostedDeviceJid = exports.isHostedDeviceId = exports.isGroupOrBroadcastJid = exports.isGroupJid = exports.isBroadcastJid = exports.isBotJid = exports.getWaMediaHkdfInfo = exports.getWaCompanionPlatformId = exports.getLoginIdentity = exports.canonicalizeSignalServer = exports.canonicalizeSignalJid = exports.buildDeviceJid = exports.delay = exports.WaAuthMemoryStore = exports.createStore = exports.createNoopLogger = exports.createPinoLogger = exports.PinoLogger = exports.ConsoleLogger = exports.fetchLatestWaWebVersion = exports.writeRandomPadMax16 = exports.unpadPkcs7 = exports.resolveMediaPayload = exports.resolveMessageTarget = exports.getContentType = exports.parseUsyncResultEnvelope = exports.downloadMediaMessage = exports.defineWaClientPlugin = exports.WaClient = void 0;
4
+ exports.proto = exports.WA_XMLNS = exports.WA_PRIVACY_VALUES = exports.WA_PRIVACY_TAGS = exports.WA_PRIVACY_SETTING_TO_CATEGORY = exports.WA_PRIVACY_DISALLOWED_LIST_CATEGORIES = exports.WA_PRIVACY_CATEGORY_TO_SETTING = exports.WA_PRIVACY_CATEGORIES = exports.WA_SUPPORTED_DIRTY_TYPES = exports.WA_STREAM_SIGNALING = exports.WA_SIGNALING = exports.WA_RETRYABLE_ACK_CODES = exports.WA_READY_STATES = exports.WA_PREVIEW_MEDIA_HKDF_INFO = exports.WA_PAIRING_KDF_INFO = exports.WA_NODE_TAGS = exports.WA_MEDIA_HKDF_INFO = exports.WA_MESSAGE_TYPES = exports.WA_MESSAGE_TAGS = exports.WA_LOGOUT_REASONS = exports.WA_IQ_TYPES = exports.WA_DISCONNECT_REASONS = exports.WA_DIRTY_TYPES = exports.WA_DIRTY_PROTOCOLS = exports.WA_DEFAULTS = exports.WA_COMPANION_PLATFORM_IDS = exports.WA_BUSINESS_HOURS_MODES = exports.WA_BUSINESS_HOURS_DAYS = void 0;
5
5
  var _client_1 = require("./client");
6
6
  Object.defineProperty(exports, "WaClient", { enumerable: true, get: function () { return _client_1.WaClient; } });
7
+ var plugins_1 = require("./client/plugins");
8
+ Object.defineProperty(exports, "defineWaClientPlugin", { enumerable: true, get: function () { return plugins_1.defineWaClientPlugin; } });
7
9
  var media_1 = require("./client/media");
8
10
  Object.defineProperty(exports, "downloadMediaMessage", { enumerable: true, get: function () { return media_1.downloadMediaMessage; } });
9
11
  var usync_1 = require("./transport/node/builders/usync");
@@ -13,6 +15,9 @@ Object.defineProperty(exports, "getContentType", { enumerable: true, get: functi
13
15
  Object.defineProperty(exports, "resolveMessageTarget", { enumerable: true, get: function () { return content_1.resolveMessageTarget; } });
14
16
  var media_payload_1 = require("./message/encode/media-payload");
15
17
  Object.defineProperty(exports, "resolveMediaPayload", { enumerable: true, get: function () { return media_payload_1.resolveMediaPayload; } });
18
+ var padding_1 = require("./message/encode/padding");
19
+ Object.defineProperty(exports, "unpadPkcs7", { enumerable: true, get: function () { return padding_1.unpadPkcs7; } });
20
+ Object.defineProperty(exports, "writeRandomPadMax16", { enumerable: true, get: function () { return padding_1.writeRandomPadMax16; } });
16
21
  var wa_web_version_fetcher_1 = require("./transport/wa-web-version-fetcher");
17
22
  Object.defineProperty(exports, "fetchLatestWaWebVersion", { enumerable: true, get: function () { return wa_web_version_fetcher_1.fetchLatestWaWebVersion; } });
18
23
  var ConsoleLogger_1 = require("./infra/log/ConsoleLogger");
@@ -1,4 +1,4 @@
1
- import type { Logger, LogLevel } from '../log/types';
1
+ import { type Logger, type LogLevel } from '../log/types';
2
2
  /**
3
3
  * Default zero-dependency {@link Logger} that writes structured records to
4
4
  * the standard `console` sinks. Messages below the configured `level` are
@@ -24,6 +24,8 @@ export declare class ConsoleLogger implements Logger {
24
24
  * Returns a derived logger with `bindings` merged into the parent's
25
25
  * bindings. Per-call context still wins on key conflicts.
26
26
  */
27
- child(bindings: Readonly<Record<string, unknown>>): Logger;
27
+ child(bindings: Readonly<Record<string, unknown>>, options?: {
28
+ readonly level?: LogLevel;
29
+ }): Logger;
28
30
  private write;
29
31
  }
@@ -1,13 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConsoleLogger = void 0;
4
- const LOG_LEVEL_PRIORITY = {
5
- trace: 10,
6
- debug: 20,
7
- info: 30,
8
- warn: 40,
9
- error: 50
10
- };
4
+ const types_1 = require("../log/types");
11
5
  const CONSOLE_WRITERS = {
12
6
  trace: (...args) => console.debug(...args),
13
7
  debug: (...args) => console.debug(...args),
@@ -24,7 +18,7 @@ class ConsoleLogger {
24
18
  /** @param level Minimum level to emit. Defaults to `'info'`. */
25
19
  constructor(level = 'info', bindings = null) {
26
20
  this.level = level;
27
- this.minLevelPriority = LOG_LEVEL_PRIORITY[level];
21
+ this.minLevelPriority = types_1.LOG_LEVEL_PRIORITY[level];
28
22
  this.bindings = bindings;
29
23
  }
30
24
  /** Emits a `trace` record. */
@@ -51,12 +45,12 @@ class ConsoleLogger {
51
45
  * Returns a derived logger with `bindings` merged into the parent's
52
46
  * bindings. Per-call context still wins on key conflicts.
53
47
  */
54
- child(bindings) {
48
+ child(bindings, options) {
55
49
  const merged = this.bindings ? { ...this.bindings, ...bindings } : { ...bindings };
56
- return new ConsoleLogger(this.level, merged);
50
+ return new ConsoleLogger(options?.level ?? this.level, merged);
57
51
  }
58
52
  write(level, message, context) {
59
- if (LOG_LEVEL_PRIORITY[level] < this.minLevelPriority) {
53
+ if (types_1.LOG_LEVEL_PRIORITY[level] < this.minLevelPriority) {
60
54
  return;
61
55
  }
62
56
  if (this.bindings) {
@@ -1,4 +1,4 @@
1
- import type { Logger, LogLevel } from '../log/types';
1
+ import { type Logger, type LogLevel } from '../log/types';
2
2
  type PinoLikeLogger = {
3
3
  level: string;
4
4
  trace: (...args: unknown[]) => void;
@@ -72,7 +72,9 @@ export declare class PinoLogger implements Logger {
72
72
  * call's context. Delegates to the underlying pino `child()` when
73
73
  * available; otherwise wraps with a parent + bindings merge.
74
74
  */
75
- child(bindings: Readonly<Record<string, unknown>>): Logger;
75
+ child(bindings: Readonly<Record<string, unknown>>, options?: {
76
+ readonly level?: LogLevel;
77
+ }): Logger;
76
78
  private write;
77
79
  }
78
80
  /**
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.PinoLogger = void 0;
37
37
  exports.createPinoLogger = createPinoLogger;
38
+ const types_1 = require("../log/types");
38
39
  const PINO_MODULE = 'pino';
39
40
  const PINO_PRETTY_MODULE = 'pino-pretty';
40
41
  async function loadPinoFactory() {
@@ -94,11 +95,11 @@ class PinoLogger {
94
95
  * call's context. Delegates to the underlying pino `child()` when
95
96
  * available; otherwise wraps with a parent + bindings merge.
96
97
  */
97
- child(bindings) {
98
+ child(bindings, options) {
98
99
  if (typeof this.logger.child === 'function') {
99
- return new PinoLogger(this.logger.child(bindings), this.level);
100
+ return new PinoLogger(this.logger.child(bindings), options?.level ?? this.level);
100
101
  }
101
- return new BoundLogger(this, bindings);
102
+ return new BoundLogger(this, bindings, options?.level);
102
103
  }
103
104
  write(level, message, context) {
104
105
  if (context === null || context === undefined) {
@@ -121,28 +122,39 @@ exports.PinoLogger = PinoLogger;
121
122
  * underlying logger does not support `child()` natively.
122
123
  */
123
124
  class BoundLogger {
124
- constructor(parent, bindings) {
125
+ constructor(parent, bindings, level) {
125
126
  this.parent = parent;
126
- this.level = parent.level;
127
+ this.level = level ?? parent.level;
127
128
  this.bindings = bindings;
129
+ this.minPriority = types_1.LOG_LEVEL_PRIORITY[this.level];
128
130
  }
129
131
  trace(message, context) {
130
- this.parent.trace(message, this.merge(context));
132
+ if (types_1.LOG_LEVEL_PRIORITY.trace >= this.minPriority) {
133
+ this.parent.trace(message, this.merge(context));
134
+ }
131
135
  }
132
136
  debug(message, context) {
133
- this.parent.debug(message, this.merge(context));
137
+ if (types_1.LOG_LEVEL_PRIORITY.debug >= this.minPriority) {
138
+ this.parent.debug(message, this.merge(context));
139
+ }
134
140
  }
135
141
  info(message, context) {
136
- this.parent.info(message, this.merge(context));
142
+ if (types_1.LOG_LEVEL_PRIORITY.info >= this.minPriority) {
143
+ this.parent.info(message, this.merge(context));
144
+ }
137
145
  }
138
146
  warn(message, context) {
139
- this.parent.warn(message, this.merge(context));
147
+ if (types_1.LOG_LEVEL_PRIORITY.warn >= this.minPriority) {
148
+ this.parent.warn(message, this.merge(context));
149
+ }
140
150
  }
141
151
  error(message, context) {
142
- this.parent.error(message, this.merge(context));
152
+ if (types_1.LOG_LEVEL_PRIORITY.error >= this.minPriority) {
153
+ this.parent.error(message, this.merge(context));
154
+ }
143
155
  }
144
- child(bindings) {
145
- return new BoundLogger(this.parent, { ...this.bindings, ...bindings });
156
+ child(bindings, options) {
157
+ return new BoundLogger(this.parent, { ...this.bindings, ...bindings }, options?.level ?? this.level);
146
158
  }
147
159
  merge(context) {
148
160
  return context ? { ...this.bindings, ...context } : this.bindings;
@@ -1,4 +1,9 @@
1
1
  export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
2
+ export declare const LOG_LEVEL_PRIORITY: Readonly<Record<LogLevel, number>>;
3
+ export interface LoggerChildOptions {
4
+ /** Minimum level the derived logger emits; defaults to the parent's level. */
5
+ readonly level?: LogLevel;
6
+ }
2
7
  export interface Logger {
3
8
  readonly level: LogLevel;
4
9
  trace(message: string, context?: Readonly<Record<string, unknown>>): void;
@@ -10,7 +15,9 @@ export interface Logger {
10
15
  * Returns a derived logger that pre-binds `bindings` into every log
11
16
  * call's context object. Bindings stack: `parent.child(a).child(b)`
12
17
  * merges `{ ...a, ...b }`. Per-call context wins on key conflicts.
18
+ * Pass `options.level` to give the child its own minimum level
19
+ * (independent of the parent), e.g. to quiet a noisy subsystem.
13
20
  */
14
- child(bindings: Readonly<Record<string, unknown>>): Logger;
21
+ child(bindings: Readonly<Record<string, unknown>>, options?: LoggerChildOptions): Logger;
15
22
  }
16
23
  export declare function createNoopLogger(level?: LogLevel): Logger;
@@ -1,6 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOG_LEVEL_PRIORITY = void 0;
3
4
  exports.createNoopLogger = createNoopLogger;
5
+ exports.LOG_LEVEL_PRIORITY = {
6
+ trace: 10,
7
+ debug: 20,
8
+ info: 30,
9
+ warn: 40,
10
+ error: 50
11
+ };
4
12
  function noop() { }
5
13
  function createNoopLogger(level = 'trace') {
6
14
  const logger = {
@@ -10,7 +18,7 @@ function createNoopLogger(level = 'trace') {
10
18
  info: noop,
11
19
  warn: noop,
12
20
  error: noop,
13
- child: () => logger
21
+ child: (_bindings, options) => (options?.level ? createNoopLogger(options.level) : logger)
14
22
  };
15
23
  return logger;
16
24
  }
@@ -50,6 +50,8 @@ export declare const WA_NODE_TAGS: Readonly<{
50
50
  readonly COUNTRY_CODE: "country_code";
51
51
  readonly DEVICE_IDENTITY: "device-identity";
52
52
  readonly PLATFORM: "platform";
53
+ readonly PASSKEY_REQUEST_OPTIONS: "passkey_request_options";
54
+ readonly PRIMARY_EPHEMERAL_IDENTITY: "primary_ephemeral_identity";
53
55
  readonly SUBJECT: "subject";
54
56
  readonly BODY: "body";
55
57
  readonly PARTICIPANT: "participant";
@@ -53,6 +53,8 @@ exports.WA_NODE_TAGS = Object.freeze({
53
53
  COUNTRY_CODE: 'country_code',
54
54
  DEVICE_IDENTITY: 'device-identity',
55
55
  PLATFORM: 'platform',
56
+ PASSKEY_REQUEST_OPTIONS: 'passkey_request_options',
57
+ PRIMARY_EPHEMERAL_IDENTITY: 'primary_ephemeral_identity',
56
58
  SUBJECT: 'subject',
57
59
  BODY: 'body',
58
60
  PARTICIPANT: 'participant',
@@ -7,6 +7,8 @@ export declare const WA_NOTIFICATION_TYPES: Readonly<{
7
7
  readonly NEWSLETTER: "newsletter";
8
8
  readonly BUSINESS: "business";
9
9
  readonly PICTURE: "picture";
10
+ readonly PASSKEY_PROLOGUE_REQUEST: "passkey_prologue_request";
11
+ readonly CRSC_CONTINUATION: "crsc_continuation";
10
12
  }>;
11
13
  export declare const WA_BUSINESS_NOTIFICATION_TAGS: Readonly<{
12
14
  readonly VERIFIED_NAME: "verified_name";
@@ -9,7 +9,9 @@ exports.WA_NOTIFICATION_TYPES = Object.freeze({
9
9
  REGISTRATION: 'registration',
10
10
  NEWSLETTER: 'newsletter',
11
11
  BUSINESS: 'business',
12
- PICTURE: 'picture'
12
+ PICTURE: 'picture',
13
+ PASSKEY_PROLOGUE_REQUEST: 'passkey_prologue_request',
14
+ CRSC_CONTINUATION: 'crsc_continuation'
13
15
  });
14
16
  exports.WA_BUSINESS_NOTIFICATION_TAGS = Object.freeze({
15
17
  VERIFIED_NAME: 'verified_name',