@shenhh/popo 0.1.8 → 0.1.10

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": "@shenhh/popo",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "OpenClaw POPO channel plugin",
6
6
  "license": "MIT",
package/src/accounts.ts CHANGED
@@ -17,7 +17,7 @@ export function resolvePopoCredentials(cfg?: PopoConfig): {
17
17
  appSecret,
18
18
  token: cfg?.token?.trim() || undefined,
19
19
  aesKey: cfg?.aesKey?.trim() || undefined,
20
- server: cfg?.server ?? "https://open.popo.netease.com/open-apis/robots/v1",
20
+ server: cfg?.server ?? "https://open.popo.netease.com",
21
21
  };
22
22
  }
23
23
 
package/src/auth.ts CHANGED
@@ -54,7 +54,7 @@ async function fetchNewToken(cfg: PopoConfig): Promise<PopoToken> {
54
54
  throw new Error("POPO credentials not configured");
55
55
  }
56
56
 
57
- const response = await fetch(`${creds.server}/auth/token`, {
57
+ const response = await fetch(`${creds.server}/open-apis/robots/v1/token`, {
58
58
  method: "POST",
59
59
  headers: {
60
60
  "Content-Type": "application/json",
@@ -70,9 +70,9 @@ async function fetchNewToken(cfg: PopoConfig): Promise<PopoToken> {
70
70
  }
71
71
 
72
72
  const data = (await response.json()) as {
73
- code?: number;
74
- message?: string;
75
- result?: {
73
+ errcode?: number;
74
+ errmsg?: string;
75
+ data?: {
76
76
  accessToken: string;
77
77
  accessExpiredAt: number;
78
78
  refreshToken: string;
@@ -80,15 +80,15 @@ async function fetchNewToken(cfg: PopoConfig): Promise<PopoToken> {
80
80
  };
81
81
  };
82
82
 
83
- if (data.code !== 200 || !data.result) {
84
- throw new Error(`POPO token request failed: ${data.message || "unknown error"}`);
83
+ if (data.errcode !== 0 || !data.data) {
84
+ throw new Error(`POPO token request failed: ${data.errmsg || "unknown error"}`);
85
85
  }
86
86
 
87
87
  return {
88
- accessToken: data.result.accessToken,
89
- accessExpiredAt: data.result.accessExpiredAt,
90
- refreshToken: data.result.refreshToken,
91
- refreshExpiredAt: data.result.refreshExpiredAt,
88
+ accessToken: data.data.accessToken,
89
+ accessExpiredAt: data.data.accessExpiredAt,
90
+ refreshToken: data.data.refreshToken,
91
+ refreshExpiredAt: data.data.refreshExpiredAt,
92
92
  };
93
93
  }
94
94
 
@@ -104,7 +104,7 @@ export async function refreshAccessToken(
104
104
  throw new Error("POPO credentials not configured");
105
105
  }
106
106
 
107
- const response = await fetch(`${creds.server}/auth/refresh`, {
107
+ const response = await fetch(`${creds.server}/open-apis/robots/v1/token/refresh`, {
108
108
  method: "POST",
109
109
  headers: {
110
110
  "Content-Type": "application/json",
@@ -120,9 +120,9 @@ export async function refreshAccessToken(
120
120
  }
121
121
 
122
122
  const data = (await response.json()) as {
123
- code?: number;
124
- message?: string;
125
- result?: {
123
+ errcode?: number;
124
+ errmsg?: string;
125
+ data?: {
126
126
  accessToken: string;
127
127
  accessExpiredAt: number;
128
128
  refreshToken: string;
@@ -130,15 +130,15 @@ export async function refreshAccessToken(
130
130
  };
131
131
  };
132
132
 
133
- if (data.code !== 200 || !data.result) {
134
- throw new Error(`POPO token refresh failed: ${data.message || "unknown error"}`);
133
+ if (data.errcode !== 0 || !data.data) {
134
+ throw new Error(`POPO token refresh failed: ${data.errmsg || "unknown error"}`);
135
135
  }
136
136
 
137
137
  return {
138
- accessToken: data.result.accessToken,
139
- accessExpiredAt: data.result.accessExpiredAt,
140
- refreshToken: data.result.refreshToken,
141
- refreshExpiredAt: data.result.refreshExpiredAt,
138
+ accessToken: data.data.accessToken,
139
+ accessExpiredAt: data.data.accessExpiredAt,
140
+ refreshToken: data.data.refreshToken,
141
+ refreshExpiredAt: data.data.refreshExpiredAt,
142
142
  };
143
143
  }
144
144
 
package/src/client.ts CHANGED
@@ -3,9 +3,9 @@ import { resolvePopoCredentials } from "./accounts.js";
3
3
  import { getAccessToken } from "./auth.js";
4
4
 
5
5
  export type PopoApiResponse<T = unknown> = {
6
- code: number;
7
- message: string;
8
- result?: T;
6
+ errcode: number;
7
+ errmsg: string;
8
+ data?: T;
9
9
  };
10
10
 
11
11
  /**
@@ -27,7 +27,7 @@ export async function popoRequest<T = unknown>(params: {
27
27
  const url = `${creds.server}${path}`;
28
28
 
29
29
  const headers: Record<string, string> = {
30
- Authorization: `Bearer ${accessToken}`,
30
+ "Open-Access-Token": accessToken,
31
31
  "Content-Type": "application/json",
32
32
  };
33
33
 
@@ -64,7 +64,7 @@ export async function popoUploadRequest<T = unknown>(params: {
64
64
  const response = await fetch(url, {
65
65
  method: "POST",
66
66
  headers: {
67
- Authorization: `Bearer ${accessToken}`,
67
+ "Open-Access-Token": accessToken,
68
68
  // Don't set Content-Type for FormData - fetch will set it with boundary
69
69
  },
70
70
  body: formData,
@@ -96,7 +96,7 @@ export async function popoDownloadRequest(params: {
96
96
  const response = await fetch(url, {
97
97
  method: "GET",
98
98
  headers: {
99
- Authorization: `Bearer ${accessToken}`,
99
+ "Open-Access-Token": accessToken,
100
100
  },
101
101
  });
102
102
 
@@ -46,7 +46,7 @@ export const PopoConfigSchema = z
46
46
  server: z
47
47
  .string()
48
48
  .optional()
49
- .default("https://open.popo.netease.com/open-apis/robots/v1"),
49
+ .default("https://open.popo.netease.com"),
50
50
  webhookPath: z.string().optional().default("/popo/events"),
51
51
  webhookPort: z.number().int().positive().optional(),
52
52
  dmPolicy: DmPolicySchema.optional().default("pairing"),
package/src/media.ts CHANGED
@@ -67,19 +67,19 @@ export async function uploadFilePopo(params: {
67
67
  const blob = new Blob([fileBuffer as unknown as ArrayBuffer], { type: fileType || "application/octet-stream" });
68
68
  formData.append("file", blob, fileName);
69
69
 
70
- const response = await popoUploadRequest<{ fileId: string; fileName: string }>({
70
+ const response = await popoUploadRequest<{ fileKey: string; fileName: string }>({
71
71
  cfg: popoCfg,
72
- path: "/im/file/upload",
72
+ path: "/open-apis/robots/v1/im/file/upload",
73
73
  formData,
74
74
  });
75
75
 
76
- if (response.code !== 200 || !response.result) {
77
- throw new Error(`POPO file upload failed: ${response.message || "unknown error"}`);
76
+ if (response.errcode !== 0 || !response.data) {
77
+ throw new Error(`POPO file upload failed: ${response.errmsg || "unknown error"}`);
78
78
  }
79
79
 
80
80
  return {
81
- fileId: response.result.fileId,
82
- fileName: response.result.fileName,
81
+ fileId: response.data.fileKey,
82
+ fileName: response.data.fileName,
83
83
  };
84
84
  }
85
85
 
@@ -147,23 +147,26 @@ export async function sendImagePopo(params: {
147
147
  const receiverType = detectReceiverType(receiver);
148
148
  const receiverKey = receiverType === "email" ? "receiver" : "groupId";
149
149
 
150
- const response = await popoRequest<{ msgId?: string }>({
150
+ const response = await popoRequest<{ msgInfo?: Record<string, string> }>({
151
151
  cfg: popoCfg,
152
152
  method: "POST",
153
- path: "/im/send-msg",
153
+ path: "/open-apis/robots/v1/im/send-msg",
154
154
  body: {
155
155
  [receiverKey]: receiver,
156
156
  msgType: "image",
157
- message: { fileId },
157
+ message: { fileKey: fileId },
158
158
  },
159
159
  });
160
160
 
161
- if (response.code !== 200) {
162
- throw new Error(`POPO image send failed: ${response.message || `code ${response.code}`}`);
161
+ if (response.errcode !== 0) {
162
+ throw new Error(`POPO image send failed: ${response.errmsg || `errcode ${response.errcode}`}`);
163
163
  }
164
164
 
165
+ const msgInfo = response.data?.msgInfo ?? {};
166
+ const messageId = msgInfo[receiver];
167
+
165
168
  return {
166
- messageId: response.result?.msgId,
169
+ messageId,
167
170
  sessionId: receiver,
168
171
  };
169
172
  }
@@ -190,23 +193,26 @@ export async function sendFilePopo(params: {
190
193
  const receiverType = detectReceiverType(receiver);
191
194
  const receiverKey = receiverType === "email" ? "receiver" : "groupId";
192
195
 
193
- const response = await popoRequest<{ msgId?: string }>({
196
+ const response = await popoRequest<{ msgInfo?: Record<string, string> }>({
194
197
  cfg: popoCfg,
195
198
  method: "POST",
196
- path: "/im/send-msg",
199
+ path: "/open-apis/robots/v1/im/send-msg",
197
200
  body: {
198
201
  [receiverKey]: receiver,
199
202
  msgType: "file",
200
- message: { fileId },
203
+ message: { fileKey: fileId },
201
204
  },
202
205
  });
203
206
 
204
- if (response.code !== 200) {
205
- throw new Error(`POPO file send failed: ${response.message || `code ${response.code}`}`);
207
+ if (response.errcode !== 0) {
208
+ throw new Error(`POPO file send failed: ${response.errmsg || `errcode ${response.errcode}`}`);
206
209
  }
207
210
 
211
+ const msgInfo = response.data?.msgInfo ?? {};
212
+ const messageId = msgInfo[receiver];
213
+
208
214
  return {
209
- messageId: response.result?.msgId,
215
+ messageId,
210
216
  sessionId: receiver,
211
217
  };
212
218
  }
package/src/outbound.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk";
2
2
  import { getPopoRuntime } from "./runtime.js";
3
- import { sendMessagePopo } from "./send.js";
3
+ import { sendMessagePopo, sendCardPopo } from "./send.js";
4
4
  import { sendMediaPopo } from "./media.js";
5
5
 
6
6
  export const popoOutbound: ChannelOutboundAdapter = {
@@ -37,4 +37,14 @@ export const popoOutbound: ChannelOutboundAdapter = {
37
37
  const result = await sendMessagePopo({ cfg, to, text: text ?? "" });
38
38
  return { channel: "popo", ...result };
39
39
  },
40
+
41
+ sendCard: async ({ cfg, to, card }) => {
42
+ const { templateUuid, instanceUuid, publicVariableMap } = card as {
43
+ templateUuid: string;
44
+ instanceUuid: string;
45
+ publicVariableMap?: Record<string, unknown>;
46
+ };
47
+ const result = await sendCardPopo({ cfg, to, templateUuid, instanceUuid, publicVariableMap });
48
+ return { channel: "popo", ...result };
49
+ },
40
50
  };
package/src/send.ts CHANGED
@@ -40,10 +40,10 @@ export async function sendMessagePopo(params: SendPopoMessageParams): Promise<Po
40
40
  message.isAtAll = true;
41
41
  }
42
42
 
43
- const response = await popoRequest<{ msgId?: string }>({
43
+ const response = await popoRequest<{ msgInfo?: Record<string, string> }>({
44
44
  cfg: popoCfg,
45
45
  method: "POST",
46
- path: "/im/send-msg",
46
+ path: "/open-apis/robots/v1/im/send-msg",
47
47
  body: {
48
48
  [receiverKey]: receiver,
49
49
  msgType: "text",
@@ -51,12 +51,15 @@ export async function sendMessagePopo(params: SendPopoMessageParams): Promise<Po
51
51
  },
52
52
  });
53
53
 
54
- if (response.code !== 200) {
55
- throw new Error(`POPO send failed: ${response.message || `code ${response.code}`}`);
54
+ if (response.errcode !== 0) {
55
+ throw new Error(`POPO send failed: ${response.errmsg || `errcode ${response.errcode}`}`);
56
56
  }
57
57
 
58
+ const msgInfo = response.data?.msgInfo ?? {};
59
+ const messageId = msgInfo[receiver];
60
+
58
61
  return {
59
- messageId: response.result?.msgId,
62
+ messageId,
60
63
  sessionId: receiver,
61
64
  };
62
65
  }
@@ -85,10 +88,10 @@ export async function sendRichTextPopo(params: SendPopoRichTextParams): Promise<
85
88
  const receiverType = detectReceiverType(receiver);
86
89
  const receiverKey = receiverType === "email" ? "receiver" : "groupId";
87
90
 
88
- const response = await popoRequest<{ msgId?: string }>({
91
+ const response = await popoRequest<{ msgInfo?: Record<string, string> }>({
89
92
  cfg: popoCfg,
90
93
  method: "POST",
91
- path: "/im/send-msg",
94
+ path: "/open-apis/robots/v1/im/send-msg",
92
95
  body: {
93
96
  [receiverKey]: receiver,
94
97
  msgType: "rich_text",
@@ -96,12 +99,15 @@ export async function sendRichTextPopo(params: SendPopoRichTextParams): Promise<
96
99
  },
97
100
  });
98
101
 
99
- if (response.code !== 200) {
100
- throw new Error(`POPO rich text send failed: ${response.message || `code ${response.code}`}`);
102
+ if (response.errcode !== 0) {
103
+ throw new Error(`POPO rich text send failed: ${response.errmsg || `errcode ${response.errcode}`}`);
101
104
  }
102
105
 
106
+ const msgInfo = response.data?.msgInfo ?? {};
107
+ const messageId = msgInfo[receiver];
108
+
103
109
  return {
104
- messageId: response.result?.msgId,
110
+ messageId,
105
111
  sessionId: receiver,
106
112
  };
107
113
  }
@@ -132,10 +138,10 @@ export async function sendCardPopo(params: SendPopoCardParams): Promise<PopoSend
132
138
  const receiverType = detectReceiverType(receiver);
133
139
  const receiverKey = receiverType === "email" ? "receiver" : "groupId";
134
140
 
135
- const response = await popoRequest<{ msgId?: string }>({
141
+ const response = await popoRequest<{ msgInfo?: Record<string, string> }>({
136
142
  cfg: popoCfg,
137
143
  method: "POST",
138
- path: "/im/send-msg",
144
+ path: "/open-apis/robots/v1/im/send-msg",
139
145
  body: {
140
146
  [receiverKey]: receiver,
141
147
  msgType: "card",
@@ -147,12 +153,15 @@ export async function sendCardPopo(params: SendPopoCardParams): Promise<PopoSend
147
153
  },
148
154
  });
149
155
 
150
- if (response.code !== 200) {
151
- throw new Error(`POPO card send failed: ${response.message || `code ${response.code}`}`);
156
+ if (response.errcode !== 0) {
157
+ throw new Error(`POPO card send failed: ${response.errmsg || `errcode ${response.errcode}`}`);
152
158
  }
153
159
 
160
+ const msgInfo = response.data?.msgInfo ?? {};
161
+ const messageId = msgInfo[receiver];
162
+
154
163
  return {
155
- messageId: response.result?.msgId,
164
+ messageId,
156
165
  sessionId: receiver,
157
166
  };
158
167
  }