zapo-js 1.2.1 → 1.3.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 (38) hide show
  1. package/dist/client/WaClient.d.ts +84 -49
  2. package/dist/client/WaClient.js +70 -50
  3. package/dist/client/WaClientFactory.d.ts +7 -0
  4. package/dist/client/WaClientFactory.js +1 -0
  5. package/dist/client/plugins/define.d.ts +23 -0
  6. package/dist/client/plugins/define.js +22 -0
  7. package/dist/client/plugins/index.d.ts +4 -0
  8. package/dist/client/plugins/index.js +9 -0
  9. package/dist/client/plugins/install.d.ts +18 -0
  10. package/dist/client/plugins/install.js +83 -0
  11. package/dist/client/plugins/types.d.ts +76 -0
  12. package/dist/client/plugins/types.js +6 -0
  13. package/dist/client/types.d.ts +6 -0
  14. package/dist/esm/client/WaClient.js +70 -49
  15. package/dist/esm/client/WaClientFactory.js +1 -0
  16. package/dist/esm/client/plugins/define.js +19 -0
  17. package/dist/esm/client/plugins/index.js +3 -0
  18. package/dist/esm/client/plugins/install.js +80 -0
  19. package/dist/esm/client/plugins/types.js +3 -0
  20. package/dist/esm/index.js +2 -0
  21. package/dist/esm/infra/log/ConsoleLogger.js +3 -9
  22. package/dist/esm/infra/log/PinoLogger.js +24 -12
  23. package/dist/esm/infra/log/types.js +8 -1
  24. package/dist/esm/transport/index.js +2 -0
  25. package/dist/esm/util/index.js +1 -1
  26. package/dist/index.d.ts +4 -0
  27. package/dist/index.js +7 -2
  28. package/dist/infra/log/ConsoleLogger.d.ts +4 -2
  29. package/dist/infra/log/ConsoleLogger.js +5 -11
  30. package/dist/infra/log/PinoLogger.d.ts +4 -2
  31. package/dist/infra/log/PinoLogger.js +24 -12
  32. package/dist/infra/log/types.d.ts +8 -1
  33. package/dist/infra/log/types.js +9 -1
  34. package/dist/transport/index.d.ts +3 -0
  35. package/dist/transport/index.js +11 -1
  36. package/dist/util/index.d.ts +1 -1
  37. package/dist/util/index.js +4 -1
  38. package/package.json +1 -1
@@ -3,6 +3,7 @@ import { createIgnoreKeyFilter, validateIgnoreKey } from './messaging/ignore-key
3
3
  import { runHistorySyncNotification } from './persistence/history-sync.js';
4
4
  import { persistIncomingMailboxEntities } from './persistence/mailbox.js';
5
5
  import { WriteBehindPersistence } from './persistence/WriteBehindPersistence.js';
6
+ import { installWaClientPlugins } from './plugins/install.js';
6
7
  import { buildWaClientDependencies, resolveWaClientBase } from './WaClientFactory.js';
7
8
  import { ConsoleLogger } from '../infra/log/ConsoleLogger.js';
8
9
  import { proto } from '../proto.js';
@@ -19,55 +20,8 @@ const SYNC_RELATED_PROTOCOL_TYPES = new Set([
19
20
  proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE,
20
21
  proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE
21
22
  ]);
22
- /**
23
- * Top-level WhatsApp client. Owns the transport, auth, signal, and per-feature
24
- * coordinators (accessible via getters such as {@link message}, {@link group},
25
- * {@link newsletter}, etc.) and re-emits every {@link WaClientEventMap} event.
26
- *
27
- * Lifecycle: construct with {@link WaClientOptions}, call {@link connect} to
28
- * open the socket, react to `connection`/`auth_qr`/`auth_pairing_code` events,
29
- * then use the coordinator getters to drive the session. Call {@link disconnect}
30
- * to shut down cleanly or {@link logout} to remove the companion device.
31
- *
32
- * @example
33
- * ```ts
34
- * import { createPinoLogger, createStore, WaClient } from '..'
35
- * import { createSqliteStore } from '@zapo-js/store-sqlite'
36
- *
37
- * const store = createStore({
38
- * backends: { sqlite: createSqliteStore({ path: '.auth/state.sqlite' }) },
39
- * providers: {
40
- * auth: 'sqlite',
41
- * signal: 'sqlite',
42
- * preKey: 'sqlite',
43
- * session: 'sqlite',
44
- * identity: 'sqlite',
45
- * senderKey: 'sqlite',
46
- * appState: 'sqlite',
47
- * privacyToken: 'sqlite',
48
- * messages: 'sqlite',
49
- * threads: 'sqlite',
50
- * contacts: 'sqlite'
51
- * }
52
- * })
53
- *
54
- * const client = new WaClient(
55
- * { store, sessionId: 'default' },
56
- * await createPinoLogger({ level: 'info', pretty: true })
57
- * )
58
- *
59
- * client.on('auth_qr', ({ qr, ttlMs }) => console.log('scan:', qr, ttlMs))
60
- * client.on('connection', (event) => console.log('connection', event))
61
- * client.on('message', async (event) => {
62
- * if (event.message?.conversation === 'ping') {
63
- * await client.message.send(event.chatJid!, 'pong')
64
- * }
65
- * })
66
- *
67
- * await client.connect()
68
- * ```
69
- */
70
- export class WaClient extends EventEmitter {
23
+ /** @internal Implementation backing the exported {@link WaClient}. */
24
+ class WaClientImpl extends EventEmitter {
71
25
  /**
72
26
  * @param options Client configuration (store, transport, addons, history...).
73
27
  * @param logger Optional structured logger. Defaults to a `ConsoleLogger('info')`.
@@ -78,6 +32,7 @@ export class WaClient extends EventEmitter {
78
32
  this.acceptingIncomingEvents = true;
79
33
  this.activeIncomingHandlers = 0;
80
34
  this.incomingHandlersDrainedWaiters = [];
35
+ this.disposePlugins = null;
81
36
  const base = resolveWaClientBase(options, logger);
82
37
  this.options = base.options;
83
38
  this.logger = base.logger;
@@ -115,6 +70,13 @@ export class WaClient extends EventEmitter {
115
70
  this.deps = dependencies;
116
71
  this.appStateSync = dependencies.appStateSync;
117
72
  this.mediaTransfer = dependencies.mediaTransfer;
73
+ this.disposePlugins = installWaClientPlugins(this, {
74
+ options: this.options,
75
+ logger: this.logger,
76
+ stores: this.stores,
77
+ deps: this.deps,
78
+ queryWithContext: this.queryWithContext.bind(this)
79
+ }, this.options.plugins ?? []);
118
80
  this.bindNodeTransportEvents();
119
81
  this.on('connection', (event) => {
120
82
  if (event.status !== 'close')
@@ -381,6 +343,11 @@ export class WaClient extends EventEmitter {
381
343
  remaining: writeBehindFlush.remaining
382
344
  });
383
345
  }
346
+ if (this.disposePlugins) {
347
+ const dispose = this.disposePlugins;
348
+ this.disposePlugins = null;
349
+ await dispose();
350
+ }
384
351
  await this.deps.connectionManager.disconnect();
385
352
  this.emit('connection', {
386
353
  status: 'close',
@@ -603,3 +570,57 @@ export class WaClient extends EventEmitter {
603
570
  this.emit('debug_client_error', { error });
604
571
  }
605
572
  }
573
+ /**
574
+ * Top-level WhatsApp client. Owns the transport, auth, signal, and per-feature
575
+ * coordinators (accessible via getters such as {@link message}, {@link group},
576
+ * {@link newsletter}, etc.) and re-emits every {@link WaClientEventMap} event.
577
+ *
578
+ * Lifecycle: construct with {@link WaClientOptions}, call {@link connect} to
579
+ * open the socket, react to `connection`/`auth_qr`/`auth_pairing_code` events,
580
+ * then use the coordinator getters to drive the session. Call {@link disconnect}
581
+ * to shut down cleanly or {@link logout} to remove the companion device.
582
+ *
583
+ * Pass `plugins` to expose plugin getters and events on the returned client,
584
+ * typed from the values you pass: e.g. `plugins: [voipPlugin()]` adds
585
+ * `client.voip` and the `voip_*` events, and only then. See
586
+ * {@link WaClientConstructor}.
587
+ *
588
+ * @example
589
+ * ```ts
590
+ * import { createPinoLogger, createStore, WaClient } from '..'
591
+ * import { createSqliteStore } from '@zapo-js/store-sqlite'
592
+ *
593
+ * const store = createStore({
594
+ * backends: { sqlite: createSqliteStore({ path: '.auth/state.sqlite' }) },
595
+ * providers: {
596
+ * auth: 'sqlite',
597
+ * signal: 'sqlite',
598
+ * preKey: 'sqlite',
599
+ * session: 'sqlite',
600
+ * identity: 'sqlite',
601
+ * senderKey: 'sqlite',
602
+ * appState: 'sqlite',
603
+ * privacyToken: 'sqlite',
604
+ * messages: 'sqlite',
605
+ * threads: 'sqlite',
606
+ * contacts: 'sqlite'
607
+ * }
608
+ * })
609
+ *
610
+ * const client = new WaClient(
611
+ * { store, sessionId: 'default' },
612
+ * await createPinoLogger({ level: 'info', pretty: true })
613
+ * )
614
+ *
615
+ * client.on('auth_qr', ({ qr, ttlMs }) => console.log('scan:', qr, ttlMs))
616
+ * client.on('connection', (event) => console.log('connection', event))
617
+ * client.on('message', async (event) => {
618
+ * if (event.message?.conversation === 'ping') {
619
+ * await client.message.send(event.chatJid!, 'pong')
620
+ * }
621
+ * })
622
+ *
623
+ * await client.connect()
624
+ * ```
625
+ */
626
+ export const WaClient = WaClientImpl;
@@ -1026,6 +1026,7 @@ export function buildWaClientDependencies(input) {
1026
1026
  signalMissingPreKeysSync,
1027
1027
  signalRotateKey,
1028
1028
  signalSessionSync,
1029
+ sessionResolver,
1029
1030
  authClient,
1030
1031
  messageDispatch,
1031
1032
  messageCoordinator,
@@ -0,0 +1,19 @@
1
+ export function defineWaClientPlugin(input) {
2
+ if ('exposeAs' in input && input.exposeAs !== undefined) {
3
+ const exposeInput = input;
4
+ return {
5
+ id: exposeInput.id,
6
+ exposeAs: exposeInput.exposeAs,
7
+ setup: exposeInput.setup,
8
+ dispose: exposeInput.dispose
9
+ ? (instance, ctx) => exposeInput.dispose(instance, ctx)
10
+ : undefined
11
+ };
12
+ }
13
+ const behaviorInput = input;
14
+ return {
15
+ id: behaviorInput.id,
16
+ setup: behaviorInput.setup,
17
+ dispose: behaviorInput.dispose ? (_instance, ctx) => behaviorInput.dispose(ctx) : undefined
18
+ };
19
+ }
@@ -0,0 +1,3 @@
1
+ export { defineWaClientPlugin } from '../plugins/define.js';
2
+ export { installWaClientPlugins } from '../plugins/install.js';
3
+ export { isWaClientExposePluginDefinition } from '../plugins/types.js';
@@ -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
  }
@@ -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';
@@ -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,6 +24,7 @@ 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';
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;