@zlr_236/popo 0.0.3 → 0.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zlr_236/popo",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "description": "OpenClaw POPO channel plugin",
6
6
  "license": "MIT",
package/src/bot.ts CHANGED
@@ -27,7 +27,7 @@ export type PopoMessageEvent = {
27
27
  from: string; // Sender email
28
28
  sessionId: string; // P2P=email, group=groupId
29
29
  notify: string; // Message content
30
- msgType?: string; // text, image, file, etc.
30
+ msgType?: string | number; // text, image, file, etc.
31
31
  fileId?: string; // File message ID
32
32
  timestamp?: number;
33
33
  groupId?: string;
@@ -51,7 +51,10 @@ export type PopoActionEvent = {
51
51
  };
52
52
  };
53
53
 
54
- function parseMessageContent(notify: string, msgType?: string): string {
54
+ function parseMessageContent(
55
+ notify: string,
56
+ msgType?: string | number,
57
+ ): string {
55
58
  if (msgType === "text" || !msgType) {
56
59
  return notify;
57
60
  }
@@ -62,15 +65,19 @@ function parseMessageContent(notify: string, msgType?: string): string {
62
65
  /**
63
66
  * Infer placeholder text based on message type.
64
67
  */
65
- function inferPlaceholder(msgType?: string): string {
68
+ function inferPlaceholder(msgType?: string | number): string {
66
69
  switch (msgType) {
67
70
  case "image":
71
+ case 171:
68
72
  return "<media:image>";
69
73
  case "file":
74
+ case 171:
70
75
  return "<media:document>";
71
76
  case "audio":
77
+ case 171:
72
78
  return "<media:audio>";
73
79
  case "video":
80
+ case 142:
74
81
  return "<media:video>";
75
82
  default:
76
83
  return "";
@@ -88,21 +95,26 @@ async function resolvePopoMediaList(params: {
88
95
  }): Promise<PopoMediaInfo[]> {
89
96
  const { cfg, event, maxBytes, log } = params;
90
97
  const { msgType, fileId, fileInfo } = event.eventData;
91
- // Write urlResult to res.txt
92
- const __filename = fileURLToPath(import.meta.url);
93
- const __dirname = dirname(__filename);
94
- const resFilePath = join(__dirname, "res.txt");
95
- await fs.writeFile(
96
- resFilePath,
97
- JSON.stringify(event.eventData, null, 2),
98
- "utf-8",
99
- );
98
+ try {
99
+ // Write urlResult to res.txt
100
+ const __filename = fileURLToPath(import.meta.url);
101
+ const __dirname = dirname(__filename);
102
+ const resFilePath = join(__dirname, "res.txt");
103
+ await fs.writeFile(
104
+ resFilePath,
105
+ JSON.stringify(event.eventData, null, 2),
106
+ "utf-8",
107
+ );
108
+ } catch (e) {
109
+ log?.(`popo: DEBUG failed to write event data: ${String(e)}`);
110
+ }
111
+
100
112
  // Only process media message types
101
- const mediaTypes = ["image", "file", "audio", "video", 171];
113
+ const mediaTypes = ["image", "file", "audio", "video", 171, 142];
102
114
  if (
103
115
  !msgType ||
104
116
  !mediaTypes.includes(msgType) ||
105
- (!fileId && !fileInfo.fileId)
117
+ (!fileId && !fileInfo?.fileId)
106
118
  ) {
107
119
  return [];
108
120
  }
@@ -114,18 +126,22 @@ async function resolvePopoMediaList(params: {
114
126
  // First, get download URL using downloadMessageFilePopo
115
127
  const urlResult = await downloadMessageFilePopo({
116
128
  cfg,
117
- fileId: fileId || fileInfo.fileId,
129
+ fileId: fileId || fileInfo?.fileId,
118
130
  });
119
131
 
120
- // Write urlResult to res.txt
121
- const __filename = fileURLToPath(import.meta.url);
122
- const __dirname = dirname(__filename);
123
- const resFilePath = join(__dirname, "res.txt");
124
- await fs.writeFile(
125
- resFilePath,
126
- JSON.stringify(urlResult, null, 2),
127
- "utf-8",
128
- );
132
+ try {
133
+ // Write urlResult to res.txt
134
+ const __filename = fileURLToPath(import.meta.url);
135
+ const __dirname = dirname(__filename);
136
+ const resFilePath = join(__dirname, "res.txt");
137
+ await fs.writeFile(
138
+ resFilePath,
139
+ JSON.stringify(urlResult, null, 2),
140
+ "utf-8",
141
+ );
142
+ } catch (e) {
143
+ log?.(`popo: DEBUG failed to write event data: ${String(e)}`);
144
+ }
129
145
 
130
146
  if (!urlResult.success || !urlResult.downloadUrl) {
131
147
  throw new Error(urlResult.error || "Failed to get download URL");
@@ -209,7 +225,7 @@ export function parsePopoMessageEvent(
209
225
  chatType: isGroup ? "group" : "p2p",
210
226
  content,
211
227
  contentType: eventData.msgType ?? "text",
212
- fileId: eventData.fileId,
228
+ fileId: eventData.fileId || eventData.fileInfo?.fileId,
213
229
  };
214
230
  }
215
231
 
@@ -227,6 +243,15 @@ export async function handlePopoMessage(params: {
227
243
  const ctx = parsePopoMessageEvent(event);
228
244
  const isGroup = ctx.chatType === "group";
229
245
 
246
+ // Debug: write raw event at handler entry
247
+ await fs
248
+ .writeFile(
249
+ "/home/node/.openclaw/workspace/popo_handler_debug.json",
250
+ JSON.stringify({ ts: new Date().toISOString(), event }, null, 2),
251
+ "utf-8",
252
+ )
253
+ .catch(() => {});
254
+
230
255
  log(
231
256
  `popo: received message from ${ctx.senderEmail} in ${ctx.sessionId} (${ctx.chatType})`,
232
257
  );
package/src/monitor.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import http from "http";
2
- import { registerPluginHttpRoute, normalizePluginHttpPath } from "openclaw/plugin-sdk";
3
- import type { ClawdbotConfig, RuntimeEnv, HistoryEntry } from "openclaw/plugin-sdk";
2
+ import {
3
+ registerPluginHttpRoute,
4
+ normalizePluginHttpPath,
5
+ } from "openclaw/plugin-sdk";
6
+ import type {
7
+ ClawdbotConfig,
8
+ RuntimeEnv,
9
+ HistoryEntry,
10
+ } from "openclaw/plugin-sdk";
4
11
  import type { PopoConfig } from "./types.js";
5
12
  import { resolvePopoCredentials } from "./accounts.js";
6
13
  import { verifySignature, decryptMessage, encryptMessage } from "./crypto.js";
@@ -24,7 +31,9 @@ function readRequestBody(req: http.IncomingMessage): Promise<string> {
24
31
  });
25
32
  }
26
33
 
27
- export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<void> {
34
+ export async function monitorPopoProvider(
35
+ opts: MonitorPopoOpts = {},
36
+ ): Promise<void> {
28
37
  const cfg = opts.config;
29
38
  if (!cfg) {
30
39
  throw new Error("Config is required for POPO monitor");
@@ -33,7 +42,9 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
33
42
  const popoCfg = cfg.channels?.popo as PopoConfig | undefined;
34
43
  const creds = resolvePopoCredentials(popoCfg);
35
44
  if (!creds) {
36
- throw new Error("POPO credentials not configured (appKey, appSecret required)");
45
+ throw new Error(
46
+ "POPO credentials not configured (appKey, appSecret required)",
47
+ );
37
48
  }
38
49
 
39
50
  const log = opts.runtime?.log ?? console.log;
@@ -50,7 +61,8 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
50
61
  const chatHistories = new Map<string, HistoryEntry[]>();
51
62
 
52
63
  // Normalize path
53
- const normalizedPath = normalizePluginHttpPath(webhookPath, "/popo/events") ?? "/popo/events";
64
+ const normalizedPath =
65
+ normalizePluginHttpPath(webhookPath, "/popo/events") ?? "/popo/events";
54
66
 
55
67
  // Register HTTP route to gateway
56
68
  const unregisterHttp = registerPluginHttpRoute({
@@ -79,7 +91,9 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
79
91
  const timestamp = url.searchParams.get("timestamp");
80
92
  const signature = url.searchParams.get("signature");
81
93
 
82
- log(`popo: URL validation attempt - nonce=${nonce}, timestamp=${timestamp}, signature=${signature}`);
94
+ log(
95
+ `popo: URL validation attempt - nonce=${nonce}, timestamp=${timestamp}, signature=${signature}`,
96
+ );
83
97
 
84
98
  if (nonce && timestamp && signature && creds.token) {
85
99
  const valid = verifySignature({
@@ -141,6 +155,31 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
141
155
  }
142
156
 
143
157
  const event = eventData as { eventType?: string };
158
+ // Debug: write ALL events before any filtering
159
+ try {
160
+ const fsDebug = await import("node:fs/promises");
161
+ const debugPath =
162
+ "/home/node/.openclaw/workspace/popo_raw_event.json";
163
+ await fsDebug.writeFile(
164
+ debugPath,
165
+ JSON.stringify(
166
+ {
167
+ ts: new Date().toISOString(),
168
+ eventType: event.eventType,
169
+ eventData,
170
+ },
171
+ null,
172
+ 2,
173
+ ),
174
+ "utf-8",
175
+ );
176
+ log(`popo: DEBUG wrote raw event to ${debugPath}`);
177
+ } catch (e) {
178
+ log(`popo: DEBUG write failed: ${String(e)}`);
179
+ }
180
+ log(
181
+ `popo: DEBUG eventType=${event.eventType} eventData=${JSON.stringify(eventData).slice(0, 500)}`,
182
+ );
144
183
 
145
184
  // Handle valid_url event
146
185
  if (event.eventType === "valid_url") {
@@ -148,7 +187,10 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
148
187
  const response = { eventType: "valid_url" };
149
188
 
150
189
  if (creds.aesKey) {
151
- const encrypted = encryptMessage(JSON.stringify(response), creds.aesKey);
190
+ const encrypted = encryptMessage(
191
+ JSON.stringify(response),
192
+ creds.aesKey,
193
+ );
152
194
  res.writeHead(200, { "Content-Type": "application/json" });
153
195
  res.end(JSON.stringify({ encrypt: encrypted }));
154
196
  } else {
@@ -186,7 +228,10 @@ export async function monitorPopoProvider(opts: MonitorPopoOpts = {}): Promise<v
186
228
  // Return success response
187
229
  const successResponse = { success: true };
188
230
  if (creds.aesKey) {
189
- const encrypted = encryptMessage(JSON.stringify(successResponse), creds.aesKey);
231
+ const encrypted = encryptMessage(
232
+ JSON.stringify(successResponse),
233
+ creds.aesKey,
234
+ );
190
235
  res.writeHead(200, { "Content-Type": "application/json" });
191
236
  res.end(JSON.stringify({ encrypt: encrypted }));
192
237
  } else {
package/src/types.ts CHANGED
@@ -19,7 +19,7 @@ export type PopoMessageContext = {
19
19
  senderName?: string;
20
20
  chatType: "p2p" | "group";
21
21
  content: string;
22
- contentType: string;
22
+ contentType: string | number;
23
23
  fileId?: string;
24
24
  };
25
25