@gakr-gakr/whatsapp 0.1.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 (159) hide show
  1. package/action-runtime-api.ts +1 -0
  2. package/action-runtime.runtime.ts +1 -0
  3. package/api.ts +67 -0
  4. package/auth-presence.ts +80 -0
  5. package/autobot.plugin.json +23 -0
  6. package/channel-config-api.ts +1 -0
  7. package/channel-plugin-api.ts +3 -0
  8. package/config-api.ts +4 -0
  9. package/constants.ts +1 -0
  10. package/contract-api.ts +29 -0
  11. package/directory-contract-api.ts +4 -0
  12. package/doctor-contract-api.ts +8 -0
  13. package/index.ts +16 -0
  14. package/legacy-session-surface-api.ts +6 -0
  15. package/legacy-state-migrations-api.ts +1 -0
  16. package/light-runtime-api.ts +12 -0
  17. package/login-qr-api.ts +1 -0
  18. package/login-qr-runtime.ts +23 -0
  19. package/outbound-payload-test-api.ts +1 -0
  20. package/package.json +76 -0
  21. package/runtime-api.ts +84 -0
  22. package/secret-contract-api.ts +4 -0
  23. package/security-contract-api.ts +4 -0
  24. package/setup-entry.ts +21 -0
  25. package/setup-plugin-api.ts +3 -0
  26. package/src/account-config.ts +77 -0
  27. package/src/account-ids.ts +17 -0
  28. package/src/account-types.ts +5 -0
  29. package/src/accounts.ts +176 -0
  30. package/src/action-runtime-target-auth.ts +27 -0
  31. package/src/action-runtime.ts +76 -0
  32. package/src/active-listener.ts +17 -0
  33. package/src/agent-tools-login.ts +113 -0
  34. package/src/approval-auth.ts +27 -0
  35. package/src/auth-store.runtime.ts +1 -0
  36. package/src/auth-store.ts +494 -0
  37. package/src/auto-reply/config.runtime.ts +16 -0
  38. package/src/auto-reply/constants.ts +1 -0
  39. package/src/auto-reply/deliver-reply.ts +332 -0
  40. package/src/auto-reply/loggers.ts +6 -0
  41. package/src/auto-reply/mentions.ts +131 -0
  42. package/src/auto-reply/monitor/ack-reaction.ts +99 -0
  43. package/src/auto-reply/monitor/audio-preflight.runtime.ts +9 -0
  44. package/src/auto-reply/monitor/broadcast.ts +153 -0
  45. package/src/auto-reply/monitor/commands.ts +19 -0
  46. package/src/auto-reply/monitor/echo.ts +64 -0
  47. package/src/auto-reply/monitor/group-activation.runtime.ts +1 -0
  48. package/src/auto-reply/monitor/group-activation.ts +73 -0
  49. package/src/auto-reply/monitor/group-gating.runtime.ts +8 -0
  50. package/src/auto-reply/monitor/group-gating.ts +218 -0
  51. package/src/auto-reply/monitor/group-members.ts +65 -0
  52. package/src/auto-reply/monitor/inbound-context.ts +92 -0
  53. package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +22 -0
  54. package/src/auto-reply/monitor/inbound-dispatch.ts +749 -0
  55. package/src/auto-reply/monitor/last-route.ts +61 -0
  56. package/src/auto-reply/monitor/listener-log.ts +28 -0
  57. package/src/auto-reply/monitor/message-line.runtime.ts +38 -0
  58. package/src/auto-reply/monitor/message-line.ts +54 -0
  59. package/src/auto-reply/monitor/on-message.ts +333 -0
  60. package/src/auto-reply/monitor/peer.ts +17 -0
  61. package/src/auto-reply/monitor/process-message.ts +584 -0
  62. package/src/auto-reply/monitor/runtime-api.ts +36 -0
  63. package/src/auto-reply/monitor/status-reaction.ts +108 -0
  64. package/src/auto-reply/monitor-state.ts +114 -0
  65. package/src/auto-reply/monitor.ts +720 -0
  66. package/src/auto-reply/reply-resolver.runtime.ts +1 -0
  67. package/src/auto-reply/types.ts +48 -0
  68. package/src/auto-reply/util.ts +62 -0
  69. package/src/auto-reply.impl.ts +6 -0
  70. package/src/auto-reply.ts +1 -0
  71. package/src/channel-actions.runtime.ts +7 -0
  72. package/src/channel-actions.ts +85 -0
  73. package/src/channel-outbound.ts +87 -0
  74. package/src/channel-react-action.runtime.ts +10 -0
  75. package/src/channel-react-action.ts +247 -0
  76. package/src/channel.runtime.ts +117 -0
  77. package/src/channel.setup.ts +32 -0
  78. package/src/channel.ts +356 -0
  79. package/src/command-policy.ts +7 -0
  80. package/src/config-accessors.ts +22 -0
  81. package/src/config-schema.ts +6 -0
  82. package/src/config-ui-hints.ts +24 -0
  83. package/src/connection-controller-registry.ts +49 -0
  84. package/src/connection-controller.ts +680 -0
  85. package/src/creds-files.ts +19 -0
  86. package/src/creds-persistence.ts +71 -0
  87. package/src/directory-config.ts +40 -0
  88. package/src/doctor-contract.ts +11 -0
  89. package/src/doctor.ts +56 -0
  90. package/src/document-filename.ts +17 -0
  91. package/src/group-intro.ts +15 -0
  92. package/src/group-policy.ts +40 -0
  93. package/src/group-session-contract.ts +20 -0
  94. package/src/group-session-key.ts +42 -0
  95. package/src/heartbeat.ts +34 -0
  96. package/src/identity.ts +164 -0
  97. package/src/inbound/access-control.ts +187 -0
  98. package/src/inbound/dedupe.ts +132 -0
  99. package/src/inbound/extract.ts +484 -0
  100. package/src/inbound/lifecycle.ts +39 -0
  101. package/src/inbound/media.ts +128 -0
  102. package/src/inbound/monitor.ts +1042 -0
  103. package/src/inbound/outbound-mentions.ts +260 -0
  104. package/src/inbound/runtime-api.ts +7 -0
  105. package/src/inbound/save-media.runtime.ts +1 -0
  106. package/src/inbound/send-api.ts +203 -0
  107. package/src/inbound/send-result.ts +109 -0
  108. package/src/inbound/types.ts +107 -0
  109. package/src/inbound-policy.ts +215 -0
  110. package/src/inbound.ts +9 -0
  111. package/src/login-qr.ts +542 -0
  112. package/src/login.ts +83 -0
  113. package/src/media.ts +10 -0
  114. package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +417 -0
  115. package/src/monitor-inbox.append-upsert.test-support.ts +133 -0
  116. package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +418 -0
  117. package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +308 -0
  118. package/src/monitor-inbox.streams-inbound-messages.test-support.ts +824 -0
  119. package/src/normalize-target.ts +148 -0
  120. package/src/normalize.ts +8 -0
  121. package/src/outbound-adapter.ts +36 -0
  122. package/src/outbound-base.ts +256 -0
  123. package/src/outbound-media-contract.ts +307 -0
  124. package/src/outbound-media.runtime.ts +41 -0
  125. package/src/outbound-send-deps.ts +1 -0
  126. package/src/outbound-test-support.ts +16 -0
  127. package/src/qa-driver.runtime.ts +189 -0
  128. package/src/qr-image.ts +1 -0
  129. package/src/qr-terminal.ts +1 -0
  130. package/src/quoted-message.ts +184 -0
  131. package/src/reaction-level.ts +24 -0
  132. package/src/reconnect.ts +55 -0
  133. package/src/resolve-outbound-target.ts +58 -0
  134. package/src/runtime-api.ts +59 -0
  135. package/src/runtime-group-policy.ts +16 -0
  136. package/src/runtime.ts +9 -0
  137. package/src/security-contract.ts +47 -0
  138. package/src/security-fix.ts +71 -0
  139. package/src/send.ts +342 -0
  140. package/src/session-contract.ts +43 -0
  141. package/src/session-errors.ts +125 -0
  142. package/src/session-route.ts +32 -0
  143. package/src/session.runtime.ts +8 -0
  144. package/src/session.ts +327 -0
  145. package/src/setup-core.ts +52 -0
  146. package/src/setup-finalize.ts +450 -0
  147. package/src/setup-surface.ts +71 -0
  148. package/src/setup-test-helpers.ts +217 -0
  149. package/src/shared.ts +291 -0
  150. package/src/socket-timing.ts +38 -0
  151. package/src/state-migrations.ts +55 -0
  152. package/src/status-issues.ts +185 -0
  153. package/src/system-prompt.ts +31 -0
  154. package/src/targets-runtime.ts +221 -0
  155. package/src/text-runtime.ts +18 -0
  156. package/src/vcard.ts +84 -0
  157. package/targets.ts +5 -0
  158. package/test-api.ts +2 -0
  159. package/tsconfig.json +16 -0
@@ -0,0 +1,108 @@
1
+ import {
2
+ createStatusReactionController,
3
+ shouldAckReactionForWhatsApp,
4
+ type StatusReactionController,
5
+ } from "autobot/plugin-sdk/channel-feedback";
6
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
7
+ import { logVerbose } from "autobot/plugin-sdk/runtime-env";
8
+ import { getSenderIdentity } from "../../identity.js";
9
+ import { resolveWhatsAppReactionLevel } from "../../reaction-level.js";
10
+ import { sendReactionWhatsApp } from "../../send.js";
11
+ import type { WebInboundMsg } from "../types.js";
12
+ import { resolveGroupActivationFor } from "./group-activation.js";
13
+
14
+ export type { StatusReactionController };
15
+
16
+ export type WhatsAppStatusReactionParams = {
17
+ cfg: AutoBotConfig;
18
+ msg: WebInboundMsg;
19
+ agentId: string;
20
+ sessionKey: string;
21
+ conversationId: string;
22
+ verbose: boolean;
23
+ accountId?: string;
24
+ };
25
+
26
+ export async function createWhatsAppStatusReactionController(
27
+ params: WhatsAppStatusReactionParams,
28
+ ): Promise<StatusReactionController | null> {
29
+ if (!params.msg.id) {
30
+ return null;
31
+ }
32
+
33
+ const statusReactionsConfig = params.cfg.messages?.statusReactions;
34
+ if (statusReactionsConfig?.enabled !== true) {
35
+ return null;
36
+ }
37
+
38
+ const reactionLevel = resolveWhatsAppReactionLevel({
39
+ cfg: params.cfg,
40
+ accountId: params.accountId,
41
+ });
42
+ if (reactionLevel.level === "off") {
43
+ return null;
44
+ }
45
+
46
+ const ackConfig = params.cfg.channels?.whatsapp?.ackReaction;
47
+ const ackEmoji = (ackConfig?.emoji ?? "").trim();
48
+ if (!ackEmoji) {
49
+ return null;
50
+ }
51
+ const directEnabled = ackConfig?.direct ?? true;
52
+ const groupMode = ackConfig?.group ?? "mentions";
53
+ const conversationIdForCheck = params.msg.conversationId ?? params.msg.from;
54
+
55
+ const activation =
56
+ params.msg.chatType === "group"
57
+ ? await resolveGroupActivationFor({
58
+ cfg: params.cfg,
59
+ accountId: params.accountId,
60
+ agentId: params.agentId,
61
+ sessionKey: params.sessionKey,
62
+ conversationId: conversationIdForCheck,
63
+ })
64
+ : null;
65
+
66
+ const shouldUseStatusReaction = shouldAckReactionForWhatsApp({
67
+ emoji: ackEmoji,
68
+ isDirect: params.msg.chatType === "direct",
69
+ isGroup: params.msg.chatType === "group",
70
+ directEnabled,
71
+ groupMode,
72
+ wasMentioned: params.msg.wasMentioned === true,
73
+ groupActivated: activation === "always",
74
+ });
75
+
76
+ if (!shouldUseStatusReaction) {
77
+ return null;
78
+ }
79
+
80
+ const sender = getSenderIdentity(params.msg);
81
+ const reactionOptions = {
82
+ verbose: params.verbose,
83
+ fromMe: false,
84
+ ...(sender.jid ? { participant: sender.jid } : {}),
85
+ ...(params.accountId ? { accountId: params.accountId } : {}),
86
+ cfg: params.cfg,
87
+ };
88
+ const chatId = params.msg.chatId;
89
+ const msgId = params.msg.id;
90
+
91
+ return createStatusReactionController({
92
+ enabled: true,
93
+ adapter: {
94
+ setReaction: async (emoji: string) => {
95
+ await sendReactionWhatsApp(chatId, msgId, emoji, reactionOptions);
96
+ },
97
+ clearReaction: async () => {
98
+ await sendReactionWhatsApp(chatId, msgId, "", reactionOptions);
99
+ },
100
+ },
101
+ initialEmoji: ackEmoji,
102
+ emojis: statusReactionsConfig.emojis,
103
+ timing: statusReactionsConfig.timing,
104
+ onError: (err) => {
105
+ logVerbose(`WhatsApp status-reaction error for chat ${chatId}/${msgId}: ${String(err)}`);
106
+ },
107
+ });
108
+ }
@@ -0,0 +1,114 @@
1
+ import {
2
+ createConnectedChannelStatusPatch,
3
+ createTransportActivityStatusPatch,
4
+ } from "autobot/plugin-sdk/gateway-runtime";
5
+ import type { WebChannelHealthState, WebChannelStatus } from "./types.js";
6
+
7
+ function cloneStatus(status: WebChannelStatus): WebChannelStatus {
8
+ return {
9
+ ...status,
10
+ lastDisconnect: status.lastDisconnect ? { ...status.lastDisconnect } : null,
11
+ };
12
+ }
13
+
14
+ function isTerminalHealthState(healthState: WebChannelHealthState | undefined): boolean {
15
+ return healthState === "conflict" || healthState === "logged-out" || healthState === "stopped";
16
+ }
17
+
18
+ export function createWebChannelStatusController(statusSink?: (status: WebChannelStatus) => void) {
19
+ let lastDisconnectWasWatchdogRecovery = false;
20
+ const status: WebChannelStatus = {
21
+ running: true,
22
+ connected: false,
23
+ reconnectAttempts: 0,
24
+ lastConnectedAt: null,
25
+ lastDisconnect: null,
26
+ lastInboundAt: null,
27
+ lastMessageAt: null,
28
+ lastEventAt: null,
29
+ lastError: null,
30
+ healthState: "starting",
31
+ };
32
+
33
+ const emit = () => {
34
+ statusSink?.(cloneStatus(status));
35
+ };
36
+
37
+ return {
38
+ emit,
39
+ snapshot: () => status,
40
+ noteConnected(at = Date.now()) {
41
+ Object.assign(status, createConnectedChannelStatusPatch(at));
42
+ Object.assign(status, createTransportActivityStatusPatch(at));
43
+ if (lastDisconnectWasWatchdogRecovery) {
44
+ status.lastDisconnect = null;
45
+ status.reconnectAttempts = 0;
46
+ lastDisconnectWasWatchdogRecovery = false;
47
+ }
48
+ status.lastError = null;
49
+ status.healthState = "healthy";
50
+ emit();
51
+ },
52
+ noteInbound(at = Date.now()) {
53
+ status.lastInboundAt = at;
54
+ status.lastMessageAt = at;
55
+ status.lastEventAt = at;
56
+ Object.assign(status, createTransportActivityStatusPatch(at));
57
+ if (status.connected) {
58
+ status.healthState = "healthy";
59
+ }
60
+ emit();
61
+ },
62
+ noteTransportActivity(at = Date.now()) {
63
+ if (status.lastTransportActivityAt === at) {
64
+ return;
65
+ }
66
+ Object.assign(status, createTransportActivityStatusPatch(at));
67
+ emit();
68
+ },
69
+ noteWatchdogStale(at = Date.now()) {
70
+ status.lastEventAt = at;
71
+ if (status.connected) {
72
+ status.healthState = "stale";
73
+ }
74
+ emit();
75
+ },
76
+ noteReconnectAttempts(reconnectAttempts: number) {
77
+ status.reconnectAttempts = reconnectAttempts;
78
+ emit();
79
+ },
80
+ noteClose(params: {
81
+ at?: number;
82
+ statusCode?: number;
83
+ loggedOut?: boolean;
84
+ error?: string;
85
+ reconnectAttempts: number;
86
+ healthState: WebChannelHealthState;
87
+ watchdogRecovery?: boolean;
88
+ }) {
89
+ const at = params.at ?? Date.now();
90
+ lastDisconnectWasWatchdogRecovery = params.watchdogRecovery === true;
91
+ status.connected = false;
92
+ status.lastEventAt = at;
93
+ status.lastDisconnect = {
94
+ at,
95
+ status: params.statusCode,
96
+ error: params.error,
97
+ loggedOut: Boolean(params.loggedOut),
98
+ };
99
+ status.lastError = params.error ?? null;
100
+ status.reconnectAttempts = params.reconnectAttempts;
101
+ status.healthState = params.healthState;
102
+ emit();
103
+ },
104
+ markStopped(at = Date.now()) {
105
+ status.running = false;
106
+ status.connected = false;
107
+ status.lastEventAt = at;
108
+ if (!isTerminalHealthState(status.healthState)) {
109
+ status.healthState = "stopped";
110
+ }
111
+ emit();
112
+ },
113
+ };
114
+ }