@gamalan/pi-gateway 1.0.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/README.md +366 -0
- package/config/config.default.json +51 -0
- package/dist/adapters/base.d.ts +85 -0
- package/dist/adapters/base.js +34 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/discord.d.ts +53 -0
- package/dist/adapters/discord.js +224 -0
- package/dist/adapters/discord.js.map +1 -0
- package/dist/adapters/index.d.ts +13 -0
- package/dist/adapters/index.js +8 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/slack.d.ts +49 -0
- package/dist/adapters/slack.js +231 -0
- package/dist/adapters/slack.js.map +1 -0
- package/dist/adapters/telegram.d.ts +64 -0
- package/dist/adapters/telegram.js +274 -0
- package/dist/adapters/telegram.js.map +1 -0
- package/dist/adapters/twitch.d.ts +75 -0
- package/dist/adapters/twitch.js +222 -0
- package/dist/adapters/twitch.js.map +1 -0
- package/dist/adapters/websocket.d.ts +30 -0
- package/dist/adapters/websocket.js +132 -0
- package/dist/adapters/websocket.js.map +1 -0
- package/dist/adapters/whatsapp.d.ts +49 -0
- package/dist/adapters/whatsapp.js +251 -0
- package/dist/adapters/whatsapp.js.map +1 -0
- package/dist/background/index.d.ts +1 -0
- package/dist/background/index.js +2 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/manager.d.ts +70 -0
- package/dist/background/manager.js +291 -0
- package/dist/background/manager.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1275 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +39 -0
- package/dist/logger.js.map +1 -0
- package/dist/paths.d.ts +14 -0
- package/dist/paths.js +32 -0
- package/dist/paths.js.map +1 -0
- package/dist/security/auth.d.ts +91 -0
- package/dist/security/auth.js +316 -0
- package/dist/security/auth.js.map +1 -0
- package/dist/security/index.d.ts +1 -0
- package/dist/security/index.js +2 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/tool-policy.d.ts +66 -0
- package/dist/security/tool-policy.js +467 -0
- package/dist/security/tool-policy.js.map +1 -0
- package/dist/sessions/index.d.ts +1 -0
- package/dist/sessions/index.js +2 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/store.d.ts +64 -0
- package/dist/sessions/store.js +247 -0
- package/dist/sessions/store.js.map +1 -0
- package/package.json +57 -0
- package/src/adapters/base.ts +124 -0
- package/src/adapters/discord.ts +270 -0
- package/src/adapters/index.ts +13 -0
- package/src/adapters/slack.ts +313 -0
- package/src/adapters/telegram.ts +394 -0
- package/src/adapters/twitch.ts +316 -0
- package/src/adapters/websocket.ts +158 -0
- package/src/adapters/whatsapp.ts +296 -0
- package/src/background/index.ts +1 -0
- package/src/background/manager.ts +395 -0
- package/src/index.ts +1665 -0
- package/src/logger.ts +43 -0
- package/src/paths.ts +40 -0
- package/src/security/auth.ts +458 -0
- package/src/security/index.ts +1 -0
- package/src/security/tool-policy.ts +568 -0
- package/src/sessions/index.ts +1 -0
- package/src/sessions/store.ts +360 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Adapter - For web clients and other WebSocket-based platforms
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { BaseAdapter, type PlatformMessage, type PlatformConfig } from "./base.js";
|
|
6
|
+
import { logger } from "../logger.js";
|
|
7
|
+
|
|
8
|
+
export interface WebSocketConfig extends PlatformConfig {
|
|
9
|
+
platform: "websocket";
|
|
10
|
+
clientId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class WebSocketAdapter extends BaseAdapter {
|
|
14
|
+
readonly platform = "websocket" as const;
|
|
15
|
+
config: WebSocketConfig;
|
|
16
|
+
private client: WebSocket | null = null;
|
|
17
|
+
private reconnectAttempts = 0;
|
|
18
|
+
private maxReconnectAttempts = 5;
|
|
19
|
+
private reconnectDelay = 1000;
|
|
20
|
+
|
|
21
|
+
constructor(config: WebSocketConfig) {
|
|
22
|
+
super();
|
|
23
|
+
this.config = config;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async initialize(): Promise<void> {
|
|
27
|
+
logger.info(`[WebSocket] Adapter initialized for client ${this.config.clientId}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async start(callbacks): Promise<void> {
|
|
31
|
+
await super.start(callbacks);
|
|
32
|
+
// For server-side: this would be handled by the main gateway
|
|
33
|
+
// This adapter is more for client-side connections
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async connect(url: string, token?: string): Promise<void> {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const headers: Record<string, string> = {};
|
|
39
|
+
if (token) {
|
|
40
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.client = new WebSocket(url, { headers });
|
|
44
|
+
|
|
45
|
+
this.client.onopen = () => {
|
|
46
|
+
logger.info(`[WebSocket] Connected to ${url}`);
|
|
47
|
+
this.reconnectAttempts = 0;
|
|
48
|
+
resolve();
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
this.client.onmessage = (event) => {
|
|
52
|
+
try {
|
|
53
|
+
const data = JSON.parse(event.data);
|
|
54
|
+
|
|
55
|
+
if (data.type === "message") {
|
|
56
|
+
const message: PlatformMessage = {
|
|
57
|
+
id: this.generateMessageId(),
|
|
58
|
+
platform: this.platform,
|
|
59
|
+
channelId: this.config.clientId,
|
|
60
|
+
userId: this.config.clientId,
|
|
61
|
+
content: data.content,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
metadata: data.metadata,
|
|
64
|
+
};
|
|
65
|
+
this.emitMessage(message);
|
|
66
|
+
}
|
|
67
|
+
} catch (err) {
|
|
68
|
+
logger.error("[WebSocket] Failed to parse message:", err);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
this.client.onclose = () => {
|
|
73
|
+
logger.info("[WebSocket] Connection closed");
|
|
74
|
+
this.callbacks?.onDisconnect?.();
|
|
75
|
+
this.attemptReconnect(url, token);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
this.client.onerror = (err) => {
|
|
79
|
+
logger.error("[WebSocket] Error:", err);
|
|
80
|
+
reject(err);
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private attemptReconnect(url: string, token?: string): void {
|
|
86
|
+
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
87
|
+
this.reconnectAttempts++;
|
|
88
|
+
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
|
|
89
|
+
logger.info(`[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
90
|
+
setTimeout(() => this.connect(url, token), delay);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async sendMessage(channelId: string, content: string): Promise<string> {
|
|
95
|
+
if (!this.client || this.client.readyState !== WebSocket.OPEN) {
|
|
96
|
+
throw new Error("WebSocket not connected");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const id = this.generateMessageId();
|
|
100
|
+
this.client.send(JSON.stringify({
|
|
101
|
+
type: "message",
|
|
102
|
+
id,
|
|
103
|
+
content,
|
|
104
|
+
channelId,
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
return id;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async editMessage(channelId: string, messageId: string, content: string): Promise<void> {
|
|
111
|
+
if (!this.client || this.client.readyState !== WebSocket.OPEN) {
|
|
112
|
+
throw new Error("WebSocket not connected");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.client.send(JSON.stringify({
|
|
116
|
+
type: "edit",
|
|
117
|
+
id: messageId,
|
|
118
|
+
content,
|
|
119
|
+
channelId,
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async deleteMessage(channelId: string, messageId: string): Promise<void> {
|
|
124
|
+
if (!this.client || this.client.readyState !== WebSocket.OPEN) {
|
|
125
|
+
throw new Error("WebSocket not connected");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.client.send(JSON.stringify({
|
|
129
|
+
type: "delete",
|
|
130
|
+
id: messageId,
|
|
131
|
+
channelId,
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async setTyping(channelId: string, isTyping: boolean): Promise<void> {
|
|
136
|
+
if (!this.client || this.client.readyState !== WebSocket.OPEN) return;
|
|
137
|
+
|
|
138
|
+
this.client.send(JSON.stringify({
|
|
139
|
+
type: "typing",
|
|
140
|
+
channelId,
|
|
141
|
+
isTyping,
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getStatus(): Promise<{ connected: boolean; latency?: number }> {
|
|
146
|
+
return {
|
|
147
|
+
connected: this.client?.readyState === WebSocket.OPEN,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async stop(): Promise<void> {
|
|
152
|
+
if (this.client) {
|
|
153
|
+
this.client.close();
|
|
154
|
+
this.client = null;
|
|
155
|
+
}
|
|
156
|
+
await super.stop();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WhatsApp Adapter - Hermes-style WhatsApp platform adapter
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - WhatsApp Web protocol via Baileys
|
|
6
|
+
* - QR code authentication
|
|
7
|
+
* - Contact and group management
|
|
8
|
+
* - Media messaging
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BaseAdapter, type PlatformMessage, type PlatformConfig } from "./base.js";
|
|
12
|
+
import { logger } from "../logger.js";
|
|
13
|
+
|
|
14
|
+
export interface WhatsAppConfig extends PlatformConfig {
|
|
15
|
+
platform: "whatsapp";
|
|
16
|
+
sessionPath?: string;
|
|
17
|
+
printQr?: boolean; // Print QR to console
|
|
18
|
+
maxMessageLength?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface WhatsAppContact {
|
|
22
|
+
id: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
isGroup: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class WhatsAppAdapter extends BaseAdapter {
|
|
28
|
+
readonly platform = "whatsapp" as const;
|
|
29
|
+
config: WhatsAppConfig;
|
|
30
|
+
|
|
31
|
+
private sock: any = null;
|
|
32
|
+
private connected = false;
|
|
33
|
+
private qrCode: string | null = null;
|
|
34
|
+
|
|
35
|
+
constructor(config: WhatsAppConfig) {
|
|
36
|
+
super();
|
|
37
|
+
this.config = {
|
|
38
|
+
enabled: true,
|
|
39
|
+
platform: "whatsapp",
|
|
40
|
+
sessionPath: "./whatsapp-session",
|
|
41
|
+
printQr: true,
|
|
42
|
+
maxMessageLength: 4096,
|
|
43
|
+
...config,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async initialize(): Promise<void> {
|
|
48
|
+
try {
|
|
49
|
+
const baileys = await import("@whiskeysockets/baileys");
|
|
50
|
+
|
|
51
|
+
const { state, saveCreds } = await baileys.useMultiFileAuthState(this.config.sessionPath || "./whatsapp-session");
|
|
52
|
+
|
|
53
|
+
this.sock = baileys.makeWASocket({
|
|
54
|
+
auth: state,
|
|
55
|
+
printQRInTerminal: this.config.printQr,
|
|
56
|
+
defaultQueryTimeoutMs: 60 * 1000,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Handle QR code
|
|
60
|
+
this.sock.ev.on("qr", (qr: string) => {
|
|
61
|
+
this.qrCode = qr;
|
|
62
|
+
logger.info("[WhatsApp] QR Code received - scan with WhatsApp app");
|
|
63
|
+
logger.info(qr);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Handle connection update
|
|
67
|
+
this.sock.ev.on("connection.update", ({ qr, connection }: any) => {
|
|
68
|
+
if (qr) {
|
|
69
|
+
this.qrCode = qr;
|
|
70
|
+
}
|
|
71
|
+
if (connection === "open") {
|
|
72
|
+
this.connected = true;
|
|
73
|
+
this.qrCode = null;
|
|
74
|
+
logger.info("[WhatsApp] Connected!");
|
|
75
|
+
}
|
|
76
|
+
if (connection === "close") {
|
|
77
|
+
this.connected = false;
|
|
78
|
+
logger.info("[WhatsApp] Disconnected");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Handle credentials update
|
|
83
|
+
this.sock.ev.on("creds.update", saveCreds);
|
|
84
|
+
|
|
85
|
+
// Handle messages
|
|
86
|
+
this.sock.ev.on("messages.upsert", ({ messages }: any) => {
|
|
87
|
+
this.handleMessages(messages);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
logger.info("[WhatsApp] Initializing...");
|
|
91
|
+
} catch (err) {
|
|
92
|
+
logger.error("[WhatsApp] Failed to initialize:", err);
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private handleMessages(messages: any[]): void {
|
|
98
|
+
for (const msg of messages) {
|
|
99
|
+
// Skip messages sent by us
|
|
100
|
+
if (msg.key.fromMe) continue;
|
|
101
|
+
|
|
102
|
+
const jid = msg.key.remoteJid;
|
|
103
|
+
const isGroup = jid?.endsWith("@g.us");
|
|
104
|
+
|
|
105
|
+
// Get message content
|
|
106
|
+
const content =
|
|
107
|
+
msg.message?.conversation ||
|
|
108
|
+
msg.message?.extendedTextMessage?.text ||
|
|
109
|
+
msg.message?.imageMessage?.caption ||
|
|
110
|
+
"";
|
|
111
|
+
|
|
112
|
+
if (!content) continue;
|
|
113
|
+
|
|
114
|
+
const message: PlatformMessage = {
|
|
115
|
+
id: msg.key.id || this.generateMessageId(),
|
|
116
|
+
platform: "whatsapp",
|
|
117
|
+
channelId: jid,
|
|
118
|
+
userId: msg.key.participant || jid,
|
|
119
|
+
content,
|
|
120
|
+
timestamp: msg.messageTimestamp ? msg.messageTimestamp * 1000 : Date.now(),
|
|
121
|
+
metadata: {
|
|
122
|
+
isGroup,
|
|
123
|
+
messageType: msg.message ? Object.keys(msg.message)[0] : "unknown",
|
|
124
|
+
pushName: msg.pushName,
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
this.emitMessage(message);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async start(callbacks): Promise<void> {
|
|
133
|
+
await super.start(callbacks);
|
|
134
|
+
|
|
135
|
+
// Wait for connection
|
|
136
|
+
let attempts = 0;
|
|
137
|
+
while (!this.connected && attempts < 30) {
|
|
138
|
+
await this.sleep(1000);
|
|
139
|
+
attempts++;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!this.connected) {
|
|
143
|
+
logger.warn("[WhatsApp] Not yet connected - waiting for QR scan");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private sleep(ms: number): Promise<void> {
|
|
148
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async stop(): Promise<void> {
|
|
152
|
+
if (this.sock) {
|
|
153
|
+
await this.sock.logout();
|
|
154
|
+
this.sock = null;
|
|
155
|
+
}
|
|
156
|
+
this.connected = false;
|
|
157
|
+
await super.stop();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async sendMessage(channelId: string, content: string): Promise<string> {
|
|
161
|
+
if (!this.sock || !this.connected) {
|
|
162
|
+
throw new Error("WhatsApp not connected");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Truncate if too long
|
|
166
|
+
const text = content.length > (this.config.maxMessageLength || 4096)
|
|
167
|
+
? content.slice(0, this.config.maxMessageLength - 3) + "..."
|
|
168
|
+
: content;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const result = await this.sock.sendMessage(channelId, { text });
|
|
172
|
+
return result?.key?.id || this.generateMessageId();
|
|
173
|
+
} catch (err) {
|
|
174
|
+
logger.error("[WhatsApp] Send error:", err);
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async sendImage(channelId: string, imageUrl: string, caption?: string): Promise<string> {
|
|
180
|
+
if (!this.sock || !this.connected) {
|
|
181
|
+
throw new Error("WhatsApp not connected");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
const result = await this.sock.sendMessage(channelId, {
|
|
186
|
+
image: { url: imageUrl },
|
|
187
|
+
caption,
|
|
188
|
+
});
|
|
189
|
+
return result?.key?.id || this.generateMessageId();
|
|
190
|
+
} catch (err) {
|
|
191
|
+
logger.error("[WhatsApp] Send image error:", err);
|
|
192
|
+
throw err;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async sendReaction(channelId: string, messageId: string, emoji: string): Promise<void> {
|
|
197
|
+
if (!this.sock || !this.connected) {
|
|
198
|
+
throw new Error("WhatsApp not connected");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
await this.sock.sendMessage(channelId, {
|
|
203
|
+
react: { text: emoji, key: { remoteJid: channelId, id: messageId } },
|
|
204
|
+
});
|
|
205
|
+
} catch (err) {
|
|
206
|
+
logger.error("[WhatsApp] Reaction error:", err);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async reply(channelId: string, content: string, messageId: string): Promise<string> {
|
|
211
|
+
if (!this.sock || !this.connected) {
|
|
212
|
+
throw new Error("WhatsApp not connected");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const result = await this.sock.sendMessage(channelId, {
|
|
217
|
+
text: content,
|
|
218
|
+
contextInfo: {
|
|
219
|
+
stanzaId: messageId,
|
|
220
|
+
remoteJid: channelId,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
return result?.key?.id || this.generateMessageId();
|
|
224
|
+
} catch (err) {
|
|
225
|
+
logger.error("[WhatsApp] Reply error:", err);
|
|
226
|
+
throw err;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async editMessage(channelId: string, messageId: string, content: string): Promise<void> {
|
|
231
|
+
if (!this.sock || !this.connected) {
|
|
232
|
+
throw new Error("WhatsApp not connected");
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
await this.sock.relayMessage(channelId, {
|
|
237
|
+
protocolMessage: {
|
|
238
|
+
type: 6, // MESSAGE_EDIT
|
|
239
|
+
key: { remoteJid: channelId, id: messageId },
|
|
240
|
+
editedMessage: { conversation: [{ text: content }] },
|
|
241
|
+
},
|
|
242
|
+
}, {});
|
|
243
|
+
} catch (err) {
|
|
244
|
+
logger.error("[WhatsApp] Edit error:", err);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async deleteMessage(channelId: string, messageId: string): Promise<void> {
|
|
249
|
+
if (!this.sock || !this.connected) {
|
|
250
|
+
throw new Error("WhatsApp not connected");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
await this.sock.sendMessage(channelId, {
|
|
255
|
+
delete: { remoteJid: channelId, id: messageId },
|
|
256
|
+
});
|
|
257
|
+
} catch (err) {
|
|
258
|
+
logger.error("[WhatsApp] Delete error:", err);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async setTyping(channelId: string, isTyping: boolean): Promise<void> {
|
|
263
|
+
if (!this.sock || !this.connected) return;
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
await this.sock.sendPresenceUpdate(isTyping ? "composing" : "available", channelId);
|
|
267
|
+
} catch (err) {
|
|
268
|
+
// Ignore presence errors
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async getStatus(): Promise<{ connected: boolean; latency?: number }> {
|
|
273
|
+
return { connected: this.connected };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async getContacts(): Promise<WhatsAppContact[]> {
|
|
277
|
+
if (!this.sock?.store?.contacts) {
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return Object.entries(this.sock.store.contacts).map(([id, contact]: [string, any]) => ({
|
|
282
|
+
id,
|
|
283
|
+
name: contact?.name || contact?.notify || id.split("@")[0],
|
|
284
|
+
isGroup: id.endsWith("@g.us"),
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async getContact(jid: string): Promise<WhatsAppContact | null> {
|
|
289
|
+
const contacts = await this.getContacts();
|
|
290
|
+
return contacts.find(c => c.id === jid) || null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
getQrCode(): string | null {
|
|
294
|
+
return this.qrCode;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initBackgroundTasks, startBackgroundTask, getPendingResultsForSession, markTaskDelivered, listTasks, cancelTask, type BackgroundTask, type BackgroundStatus } from "./manager.js";
|