opc-agent 2.0.0 → 2.0.2

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 (157) hide show
  1. package/README.md +545 -365
  2. package/dist/channels/email.d.ts +32 -26
  3. package/dist/channels/email.js +239 -62
  4. package/dist/channels/feishu.d.ts +21 -6
  5. package/dist/channels/feishu.js +225 -126
  6. package/dist/channels/websocket.d.ts +46 -3
  7. package/dist/channels/websocket.js +306 -37
  8. package/dist/channels/wechat.d.ts +33 -13
  9. package/dist/channels/wechat.js +229 -42
  10. package/dist/cli.js +712 -11
  11. package/dist/core/a2a.d.ts +17 -0
  12. package/dist/core/a2a.js +43 -1
  13. package/dist/core/agent.d.ts +16 -0
  14. package/dist/core/agent.js +108 -0
  15. package/dist/core/runtime.d.ts +6 -0
  16. package/dist/core/runtime.js +161 -2
  17. package/dist/core/sandbox.d.ts +26 -0
  18. package/dist/core/sandbox.js +117 -0
  19. package/dist/core/workflow-graph.d.ts +93 -0
  20. package/dist/core/workflow-graph.js +247 -0
  21. package/dist/doctor.d.ts +15 -0
  22. package/dist/doctor.js +183 -0
  23. package/dist/eval/index.d.ts +65 -0
  24. package/dist/eval/index.js +191 -0
  25. package/dist/index.d.ts +32 -6
  26. package/dist/index.js +63 -4
  27. package/dist/plugins/content-filter.d.ts +7 -0
  28. package/dist/plugins/content-filter.js +25 -0
  29. package/dist/plugins/index.d.ts +42 -0
  30. package/dist/plugins/index.js +108 -2
  31. package/dist/plugins/logger.d.ts +6 -0
  32. package/dist/plugins/logger.js +20 -0
  33. package/dist/plugins/rate-limiter.d.ts +7 -0
  34. package/dist/plugins/rate-limiter.js +35 -0
  35. package/dist/protocols/a2a/client.d.ts +25 -0
  36. package/dist/protocols/a2a/client.js +115 -0
  37. package/dist/protocols/a2a/index.d.ts +6 -0
  38. package/dist/protocols/a2a/index.js +12 -0
  39. package/dist/protocols/a2a/server.d.ts +41 -0
  40. package/dist/protocols/a2a/server.js +295 -0
  41. package/dist/protocols/a2a/types.d.ts +91 -0
  42. package/dist/protocols/a2a/types.js +15 -0
  43. package/dist/protocols/a2a/utils.d.ts +6 -0
  44. package/dist/protocols/a2a/utils.js +47 -0
  45. package/dist/protocols/agui/client.d.ts +10 -0
  46. package/dist/protocols/agui/client.js +75 -0
  47. package/dist/protocols/agui/index.d.ts +4 -0
  48. package/dist/protocols/agui/index.js +25 -0
  49. package/dist/protocols/agui/server.d.ts +37 -0
  50. package/dist/protocols/agui/server.js +191 -0
  51. package/dist/protocols/agui/types.d.ts +107 -0
  52. package/dist/protocols/agui/types.js +17 -0
  53. package/dist/protocols/index.d.ts +2 -0
  54. package/dist/protocols/index.js +19 -0
  55. package/dist/protocols/mcp/agent-tools.d.ts +11 -0
  56. package/dist/protocols/mcp/agent-tools.js +129 -0
  57. package/dist/protocols/mcp/index.d.ts +5 -0
  58. package/dist/protocols/mcp/index.js +11 -0
  59. package/dist/protocols/mcp/server.d.ts +31 -0
  60. package/dist/protocols/mcp/server.js +248 -0
  61. package/dist/protocols/mcp/types.d.ts +92 -0
  62. package/dist/protocols/mcp/types.js +17 -0
  63. package/dist/publish/index.d.ts +45 -0
  64. package/dist/publish/index.js +350 -0
  65. package/dist/schema/oad.d.ts +682 -65
  66. package/dist/schema/oad.js +36 -3
  67. package/dist/security/approval.d.ts +36 -0
  68. package/dist/security/approval.js +113 -0
  69. package/dist/security/index.d.ts +4 -0
  70. package/dist/security/index.js +8 -0
  71. package/dist/security/keys.d.ts +16 -0
  72. package/dist/security/keys.js +117 -0
  73. package/dist/studio/server.d.ts +63 -0
  74. package/dist/studio/server.js +625 -0
  75. package/dist/studio-ui/index.html +662 -0
  76. package/dist/telemetry/index.d.ts +93 -0
  77. package/dist/telemetry/index.js +285 -0
  78. package/package.json +5 -3
  79. package/scripts/install.ps1 +31 -0
  80. package/scripts/install.sh +40 -0
  81. package/src/channels/email.ts +351 -177
  82. package/src/channels/feishu.ts +349 -236
  83. package/src/channels/websocket.ts +399 -87
  84. package/src/channels/wechat.ts +329 -149
  85. package/src/cli.ts +783 -12
  86. package/src/core/a2a.ts +60 -0
  87. package/src/core/agent.ts +125 -0
  88. package/src/core/runtime.ts +127 -0
  89. package/src/core/sandbox.ts +143 -0
  90. package/src/core/workflow-graph.ts +365 -0
  91. package/src/doctor.ts +156 -0
  92. package/src/eval/index.ts +211 -0
  93. package/src/eval/suites/basic.json +16 -0
  94. package/src/eval/suites/memory.json +12 -0
  95. package/src/eval/suites/safety.json +14 -0
  96. package/src/index.ts +58 -6
  97. package/src/plugins/content-filter.ts +23 -0
  98. package/src/plugins/index.ts +133 -2
  99. package/src/plugins/logger.ts +18 -0
  100. package/src/plugins/rate-limiter.ts +38 -0
  101. package/src/protocols/a2a/client.ts +132 -0
  102. package/src/protocols/a2a/index.ts +8 -0
  103. package/src/protocols/a2a/server.ts +333 -0
  104. package/src/protocols/a2a/types.ts +88 -0
  105. package/src/protocols/a2a/utils.ts +50 -0
  106. package/src/protocols/agui/client.ts +83 -0
  107. package/src/protocols/agui/index.ts +4 -0
  108. package/src/protocols/agui/server.ts +218 -0
  109. package/src/protocols/agui/types.ts +153 -0
  110. package/src/protocols/index.ts +2 -0
  111. package/src/protocols/mcp/agent-tools.ts +134 -0
  112. package/src/protocols/mcp/index.ts +8 -0
  113. package/src/protocols/mcp/server.ts +262 -0
  114. package/src/protocols/mcp/types.ts +69 -0
  115. package/src/publish/index.ts +376 -0
  116. package/src/schema/oad.ts +39 -2
  117. package/src/security/approval.ts +131 -0
  118. package/src/security/index.ts +3 -0
  119. package/src/security/keys.ts +87 -0
  120. package/src/studio/server.ts +629 -0
  121. package/src/studio-ui/index.html +662 -0
  122. package/src/telemetry/index.ts +324 -0
  123. package/src/types/agent-workstation.d.ts +2 -0
  124. package/tests/a2a-protocol.test.ts +285 -0
  125. package/tests/agui-protocol.test.ts +246 -0
  126. package/tests/channels/discord.test.ts +79 -0
  127. package/tests/channels/email.test.ts +148 -0
  128. package/tests/channels/feishu.test.ts +123 -0
  129. package/tests/channels/telegram.test.ts +129 -0
  130. package/tests/channels/websocket.test.ts +53 -0
  131. package/tests/channels/wechat.test.ts +170 -0
  132. package/tests/chat-cli.test.ts +160 -0
  133. package/tests/daemon.test.ts +135 -0
  134. package/tests/deepbrain-wire.test.ts +234 -0
  135. package/tests/doctor.test.ts +38 -0
  136. package/tests/eval.test.ts +173 -0
  137. package/tests/init-role.test.ts +124 -0
  138. package/tests/mcp-client.test.ts +92 -0
  139. package/tests/mcp-server.test.ts +178 -0
  140. package/tests/plugin-a2a-enhanced.test.ts +230 -0
  141. package/tests/publish.test.ts +231 -0
  142. package/tests/scheduler.test.ts +200 -0
  143. package/tests/security-enhanced.test.ts +233 -0
  144. package/tests/skill-learner.test.ts +161 -0
  145. package/tests/studio.test.ts +229 -0
  146. package/tests/subagent.test.ts +63 -0
  147. package/tests/telemetry.test.ts +186 -0
  148. package/tests/tools/builtin-extended.test.ts +138 -0
  149. package/tests/workflow-graph.test.ts +279 -0
  150. package/tutorial/customer-service-agent/README.md +612 -0
  151. package/tutorial/customer-service-agent/SOUL.md +26 -0
  152. package/tutorial/customer-service-agent/agent.yaml +63 -0
  153. package/tutorial/customer-service-agent/package.json +19 -0
  154. package/tutorial/customer-service-agent/src/index.ts +69 -0
  155. package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
  156. package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
  157. package/tutorial/customer-service-agent/tsconfig.json +14 -0
@@ -3,79 +3,348 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebSocketChannel = void 0;
4
4
  const index_1 = require("./index");
5
5
  const ws_1 = require("ws");
6
- /**
7
- * WebSocket channel — real-time bidirectional communication.
8
- */
9
6
  class WebSocketChannel extends index_1.BaseChannel {
10
7
  type = 'websocket';
11
8
  wss = null;
12
- port;
13
- clients = new Set();
14
- constructor(port = 3002) {
9
+ config;
10
+ clients = new Map(); // sessionId -> ClientInfo
11
+ rooms = new Map(); // roomId -> Set<sessionId>
12
+ heartbeatTimer = null;
13
+ constructor(configOrPort = 3002) {
15
14
  super();
16
- this.port = port;
15
+ if (typeof configOrPort === 'number') {
16
+ this.config = { port: configOrPort, heartbeatInterval: 30000, authTokens: [], maxClientsPerRoom: 100 };
17
+ }
18
+ else {
19
+ this.config = {
20
+ port: configOrPort.port ?? 3002,
21
+ heartbeatInterval: configOrPort.heartbeatInterval ?? 30000,
22
+ authTokens: configOrPort.authTokens ?? [],
23
+ maxClientsPerRoom: configOrPort.maxClientsPerRoom ?? 100,
24
+ };
25
+ }
17
26
  }
18
27
  async start() {
19
28
  return new Promise((resolve) => {
20
- this.wss = new ws_1.WebSocketServer({ port: this.port });
21
- this.wss.on('connection', (ws) => {
22
- this.clients.add(ws);
23
- ws.on('message', async (data) => {
24
- if (!this.handler)
29
+ this.wss = new ws_1.WebSocketServer({ port: this.config.port });
30
+ this.wss.on('connection', (ws, req) => {
31
+ const url = new URL(req.url ?? '/', `http://localhost:${this.config.port}`);
32
+ const token = url.searchParams.get('token');
33
+ const sessionId = url.searchParams.get('sessionId') ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
34
+ // Authentication check
35
+ if (this.config.authTokens.length > 0) {
36
+ if (!token || !this.config.authTokens.includes(token)) {
37
+ ws.close(4001, 'Unauthorized');
25
38
  return;
39
+ }
40
+ }
41
+ // Handle reconnection: if sessionId already exists, replace the connection
42
+ const existing = this.clients.get(sessionId);
43
+ if (existing) {
44
+ try {
45
+ existing.ws.close(4000, 'Replaced by new connection');
46
+ }
47
+ catch { }
48
+ }
49
+ const clientInfo = {
50
+ ws,
51
+ sessionId,
52
+ rooms: existing?.rooms ?? new Set(),
53
+ isAlive: true,
54
+ authenticated: true,
55
+ connectedAt: Date.now(),
56
+ lastMessageAt: Date.now(),
57
+ };
58
+ this.clients.set(sessionId, clientInfo);
59
+ // Re-register in rooms after reconnect
60
+ for (const roomId of clientInfo.rooms) {
61
+ const room = this.rooms.get(roomId);
62
+ if (room)
63
+ room.add(sessionId);
64
+ }
65
+ ws.on('pong', () => {
66
+ clientInfo.isAlive = true;
67
+ });
68
+ ws.on('message', async (data, isBinary) => {
69
+ clientInfo.lastMessageAt = Date.now();
70
+ clientInfo.isAlive = true;
71
+ if (isBinary) {
72
+ await this.handleBinaryMessage(clientInfo, data);
73
+ return;
74
+ }
26
75
  try {
27
76
  const parsed = JSON.parse(data.toString());
28
- const msg = {
29
- id: parsed.id ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
30
- role: 'user',
31
- content: parsed.content ?? parsed.message ?? data.toString(),
32
- timestamp: Date.now(),
33
- metadata: {
34
- sessionId: parsed.sessionId ?? 'ws-default',
35
- platform: 'websocket',
36
- },
37
- };
38
- const response = await this.handler(msg);
39
- ws.send(JSON.stringify({
40
- id: response.id,
41
- content: response.content,
42
- timestamp: response.timestamp,
43
- }));
77
+ await this.handleTextMessage(clientInfo, parsed);
44
78
  }
45
- catch (err) {
79
+ catch {
46
80
  ws.send(JSON.stringify({ error: 'Invalid message format' }));
47
81
  }
48
82
  });
49
83
  ws.on('close', () => {
50
- this.clients.delete(ws);
84
+ // Don't immediately remove - allow reconnection window
85
+ const info = this.clients.get(sessionId);
86
+ if (info && info.ws === ws) {
87
+ // Mark as disconnected but keep for potential reconnection
88
+ setTimeout(() => {
89
+ const current = this.clients.get(sessionId);
90
+ if (current && current.ws === ws) {
91
+ this.removeClient(sessionId);
92
+ }
93
+ }, 60000); // 60s reconnection window
94
+ }
51
95
  });
52
- ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));
96
+ ws.send(JSON.stringify({
97
+ type: 'connected',
98
+ sessionId,
99
+ timestamp: Date.now(),
100
+ }));
53
101
  });
102
+ // Start heartbeat
103
+ this.heartbeatTimer = setInterval(() => {
104
+ for (const [sessionId, info] of this.clients) {
105
+ if (!info.isAlive) {
106
+ try {
107
+ info.ws.terminate();
108
+ }
109
+ catch { }
110
+ this.removeClient(sessionId);
111
+ continue;
112
+ }
113
+ info.isAlive = false;
114
+ try {
115
+ info.ws.ping();
116
+ }
117
+ catch { }
118
+ }
119
+ }, this.config.heartbeatInterval);
54
120
  this.wss.on('listening', () => {
55
- console.log(`[WebSocketChannel] Listening on port ${this.port}`);
121
+ console.log(`[WebSocketChannel] Listening on port ${this.config.port}`);
56
122
  resolve();
57
123
  });
58
124
  });
59
125
  }
60
126
  async stop() {
61
- for (const client of this.clients) {
62
- client.close();
127
+ if (this.heartbeatTimer) {
128
+ clearInterval(this.heartbeatTimer);
129
+ this.heartbeatTimer = null;
130
+ }
131
+ for (const [, info] of this.clients) {
132
+ try {
133
+ info.ws.close();
134
+ }
135
+ catch { }
63
136
  }
64
137
  this.clients.clear();
138
+ this.rooms.clear();
65
139
  return new Promise((resolve, reject) => {
66
140
  if (!this.wss)
67
141
  return resolve();
68
142
  this.wss.close((err) => (err ? reject(err) : resolve()));
69
143
  });
70
144
  }
145
+ /** Handle text (JSON) messages */
146
+ async handleTextMessage(client, parsed) {
147
+ const type = parsed.type ?? 'message';
148
+ switch (type) {
149
+ case 'join': {
150
+ const roomId = parsed.room;
151
+ if (!roomId) {
152
+ client.ws.send(JSON.stringify({ error: 'room is required for join' }));
153
+ return;
154
+ }
155
+ this.joinRoom(client.sessionId, roomId);
156
+ client.ws.send(JSON.stringify({ type: 'joined', room: roomId, members: this.getRoomMembers(roomId).length }));
157
+ return;
158
+ }
159
+ case 'leave': {
160
+ const roomId = parsed.room;
161
+ if (roomId) {
162
+ this.leaveRoom(client.sessionId, roomId);
163
+ client.ws.send(JSON.stringify({ type: 'left', room: roomId }));
164
+ }
165
+ return;
166
+ }
167
+ case 'room_message': {
168
+ const roomId = parsed.room;
169
+ const content = parsed.content ?? parsed.message;
170
+ if (roomId && content) {
171
+ this.broadcastToRoom(roomId, {
172
+ type: 'room_message',
173
+ room: roomId,
174
+ from: client.sessionId,
175
+ content,
176
+ timestamp: Date.now(),
177
+ }, client.sessionId);
178
+ }
179
+ return;
180
+ }
181
+ case 'ping': {
182
+ client.ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
183
+ return;
184
+ }
185
+ default: {
186
+ // Regular chat message
187
+ if (!this.handler)
188
+ return;
189
+ const msg = {
190
+ id: parsed.id ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
191
+ role: 'user',
192
+ content: parsed.content ?? parsed.message ?? JSON.stringify(parsed),
193
+ timestamp: Date.now(),
194
+ metadata: {
195
+ sessionId: client.sessionId,
196
+ platform: 'websocket',
197
+ room: parsed.room,
198
+ },
199
+ };
200
+ const response = await this.handler(msg);
201
+ client.ws.send(JSON.stringify({
202
+ id: response.id,
203
+ content: response.content,
204
+ timestamp: response.timestamp,
205
+ }));
206
+ }
207
+ }
208
+ }
209
+ /** Handle binary messages */
210
+ async handleBinaryMessage(client, data) {
211
+ // Emit binary data with metadata
212
+ client.ws.send(JSON.stringify({
213
+ type: 'binary_ack',
214
+ size: data.length,
215
+ timestamp: Date.now(),
216
+ }));
217
+ // If handler exists, pass as base64
218
+ if (this.handler) {
219
+ const msg = {
220
+ id: `ws_bin_${Date.now()}`,
221
+ role: 'user',
222
+ content: `[binary:${data.length} bytes]`,
223
+ timestamp: Date.now(),
224
+ metadata: {
225
+ sessionId: client.sessionId,
226
+ platform: 'websocket',
227
+ binary: true,
228
+ binaryData: data.toString('base64'),
229
+ },
230
+ };
231
+ const response = await this.handler(msg);
232
+ client.ws.send(JSON.stringify({
233
+ id: response.id,
234
+ content: response.content,
235
+ timestamp: response.timestamp,
236
+ }));
237
+ }
238
+ }
239
+ /** Join a room */
240
+ joinRoom(sessionId, roomId) {
241
+ const client = this.clients.get(sessionId);
242
+ if (!client)
243
+ return false;
244
+ if (!this.rooms.has(roomId)) {
245
+ this.rooms.set(roomId, new Set());
246
+ }
247
+ const room = this.rooms.get(roomId);
248
+ if (room.size >= this.config.maxClientsPerRoom) {
249
+ client.ws.send(JSON.stringify({ error: 'Room is full', room: roomId }));
250
+ return false;
251
+ }
252
+ room.add(sessionId);
253
+ client.rooms.add(roomId);
254
+ // Notify other room members
255
+ this.broadcastToRoom(roomId, {
256
+ type: 'member_joined',
257
+ room: roomId,
258
+ sessionId,
259
+ members: room.size,
260
+ timestamp: Date.now(),
261
+ }, sessionId);
262
+ return true;
263
+ }
264
+ /** Leave a room */
265
+ leaveRoom(sessionId, roomId) {
266
+ const client = this.clients.get(sessionId);
267
+ if (client)
268
+ client.rooms.delete(roomId);
269
+ const room = this.rooms.get(roomId);
270
+ if (room) {
271
+ room.delete(sessionId);
272
+ if (room.size === 0) {
273
+ this.rooms.delete(roomId);
274
+ }
275
+ else {
276
+ this.broadcastToRoom(roomId, {
277
+ type: 'member_left',
278
+ room: roomId,
279
+ sessionId,
280
+ members: room.size,
281
+ timestamp: Date.now(),
282
+ });
283
+ }
284
+ }
285
+ }
286
+ /** Remove client completely */
287
+ removeClient(sessionId) {
288
+ const client = this.clients.get(sessionId);
289
+ if (!client)
290
+ return;
291
+ for (const roomId of client.rooms) {
292
+ this.leaveRoom(sessionId, roomId);
293
+ }
294
+ this.clients.delete(sessionId);
295
+ }
296
+ /** Get room member session IDs */
297
+ getRoomMembers(roomId) {
298
+ return [...(this.rooms.get(roomId) ?? [])];
299
+ }
300
+ /** Get all rooms */
301
+ getRooms() {
302
+ return [...this.rooms.keys()];
303
+ }
304
+ /** Broadcast to all clients */
71
305
  broadcast(content) {
72
306
  const msg = JSON.stringify({ type: 'broadcast', content, timestamp: Date.now() });
73
- for (const client of this.clients) {
74
- if (client.readyState === 1) { // OPEN
75
- client.send(msg);
307
+ for (const [, info] of this.clients) {
308
+ if (info.ws.readyState === 1) {
309
+ info.ws.send(msg);
310
+ }
311
+ }
312
+ }
313
+ /** Broadcast to all clients in a room */
314
+ broadcastToRoom(roomId, data, excludeSessionId) {
315
+ const room = this.rooms.get(roomId);
316
+ if (!room)
317
+ return;
318
+ const msg = typeof data === 'string' ? data : JSON.stringify(data);
319
+ for (const sessionId of room) {
320
+ if (sessionId === excludeSessionId)
321
+ continue;
322
+ const client = this.clients.get(sessionId);
323
+ if (client && client.ws.readyState === 1) {
324
+ client.ws.send(msg);
76
325
  }
77
326
  }
78
327
  }
328
+ /** Send to specific session */
329
+ sendToSession(sessionId, data) {
330
+ const client = this.clients.get(sessionId);
331
+ if (!client || client.ws.readyState !== 1)
332
+ return false;
333
+ client.ws.send(typeof data === 'string' ? data : JSON.stringify(data));
334
+ return true;
335
+ }
336
+ /** Get connection stats */
337
+ getStats() {
338
+ const roomDetails = {};
339
+ for (const [roomId, members] of this.rooms) {
340
+ roomDetails[roomId] = members.size;
341
+ }
342
+ return {
343
+ clients: this.clients.size,
344
+ rooms: this.rooms.size,
345
+ roomDetails,
346
+ };
347
+ }
79
348
  }
80
349
  exports.WebSocketChannel = WebSocketChannel;
81
350
  //# sourceMappingURL=websocket.js.map
@@ -1,7 +1,14 @@
1
1
  import { BaseChannel } from './index';
2
2
  /**
3
- * WeChat Channel (Stub) v0.8.0
4
- * WeChat Official Account message handling, template messages, QR code login.
3
+ * WeChat Official Account Channel — v1.0.0
4
+ *
5
+ * Handles:
6
+ * - GET verification (signature/timestamp/nonce/echostr)
7
+ * - POST XML message parsing and reply
8
+ * - Customer Service Message API for async replies
9
+ * - Access token management with caching
10
+ * - Template messages
11
+ * - Subscribe/unsubscribe events
5
12
  */
6
13
  export interface WeChatChannelConfig {
7
14
  /** WeChat Official Account AppID */
@@ -10,9 +17,9 @@ export interface WeChatChannelConfig {
10
17
  appSecret: string;
11
18
  /** Verification token for message validation */
12
19
  token: string;
13
- /** AES encoding key for encrypted messages */
20
+ /** AES encoding key for encrypted messages (optional) */
14
21
  encodingAESKey?: string;
15
- /** HTTP server port (default: 3002) */
22
+ /** HTTP server port (default: 8080) */
16
23
  port?: number;
17
24
  }
18
25
  export interface WeChatMessage {
@@ -39,24 +46,37 @@ export declare class WeChatChannel extends BaseChannel {
39
46
  private config;
40
47
  private accessToken;
41
48
  private tokenExpiry;
49
+ private server;
42
50
  constructor(config: WeChatChannelConfig);
43
51
  start(): Promise<void>;
44
52
  stop(): Promise<void>;
45
- /** Get or refresh access token */
46
- getAccessToken(): Promise<string>;
53
+ /** Verify WeChat signature for GET requests */
54
+ private handleVerification;
55
+ /** Handle incoming POST messages (XML) */
56
+ private handleIncoming;
57
+ /** Verify WeChat signature */
58
+ verifySignature(signature: string, timestamp: string, nonce: string): boolean;
59
+ /** Parse WeChat XML message using regex */
60
+ static parseXML(xml: string): WeChatMessage | null;
61
+ /** Format response as WeChat XML */
62
+ static formatXMLResponse(toUser: string, fromUser: string, content: string): string;
47
63
  /** Handle incoming WeChat message */
48
64
  handleMessage(wxMsg: WeChatMessage): Promise<string>;
49
- /** Handle WeChat events (subscribe, scan, etc.) */
65
+ /** Handle WeChat events */
50
66
  private handleEvent;
51
67
  /** Convert WeChat message to internal Message */
52
68
  private wechatToMessage;
69
+ /** Get or refresh access token */
70
+ getAccessToken(): Promise<string>;
71
+ /** Send customer service message */
72
+ sendMessage(openId: string, text: string): Promise<void>;
53
73
  /** Send template message */
54
74
  sendTemplateMessage(data: TemplateMessageData): Promise<boolean>;
55
- /** Generate QR code for login (stub) */
56
- generateLoginQR(): Promise<{
57
- ticket: string;
58
- url: string;
59
- expireSeconds: number;
60
- }>;
75
+ /** Read request body */
76
+ private readBody;
77
+ /** Simple HTTPS GET */
78
+ private httpsGet;
79
+ /** Simple HTTPS POST */
80
+ private httpsPost;
61
81
  }
62
82
  //# sourceMappingURL=wechat.d.ts.map