@shenhh/popo-native 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.
package/src/team.ts ADDED
@@ -0,0 +1,460 @@
1
+ import type { ClawdbotConfig } from "openclaw/plugin-sdk";
2
+ import type { PopoNativeConfig } from "./types.js";
3
+ import { popoNativeRequest } from "./client.js";
4
+
5
+ // ==================== Team (Group) APIs ====================
6
+
7
+ export type CreateTeamParams = {
8
+ cfg: ClawdbotConfig;
9
+ uid: string; // Group owner email
10
+ name?: string;
11
+ uidList: string[]; // Member emails
12
+ photoUrl?: string;
13
+ };
14
+
15
+ export type CreateTeamResult = {
16
+ success: boolean;
17
+ tid?: string;
18
+ passNum?: number;
19
+ failList?: Record<string, string>;
20
+ error?: string;
21
+ };
22
+
23
+ /**
24
+ * Create a new team (group) in POPO using Native API.
25
+ * POST /open-apis/team/v1/create-team?uid={uid}
26
+ */
27
+ export async function createTeam(params: CreateTeamParams): Promise<CreateTeamResult> {
28
+ const { cfg, uid, name, uidList, photoUrl } = params;
29
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
30
+ if (!popoCfg) {
31
+ throw new Error("POPO Native channel not configured");
32
+ }
33
+
34
+ const body: Record<string, unknown> = { uidList };
35
+ if (name) body.name = name;
36
+ if (photoUrl) body.photoUrl = photoUrl;
37
+
38
+ const response = await popoNativeRequest<{
39
+ tid?: string;
40
+ passNum?: number;
41
+ failList?: Record<string, string>;
42
+ }>({
43
+ cfg: popoCfg,
44
+ method: "POST",
45
+ path: "/open-apis/team/v1/create-team",
46
+ query: { uid },
47
+ body,
48
+ });
49
+
50
+ if (response.errcode !== 0) {
51
+ return {
52
+ success: false,
53
+ error: response.errmsg || `errcode ${response.errcode}`,
54
+ };
55
+ }
56
+
57
+ return {
58
+ success: true,
59
+ tid: response.data?.tid,
60
+ passNum: response.data?.passNum,
61
+ failList: response.data?.failList,
62
+ };
63
+ }
64
+
65
+ export type InviteToTeamParams = {
66
+ cfg: ClawdbotConfig;
67
+ uid: string; // Operator email
68
+ tid: string;
69
+ inviteList: string[];
70
+ type?: "1" | "2"; // 1=normal user (default), 2=robot
71
+ text?: string; // Application reason
72
+ };
73
+
74
+ export type InviteToTeamResult = {
75
+ success: boolean;
76
+ type?: number; // 0=joined directly, 1=application
77
+ failList?: Record<string, string>;
78
+ error?: string;
79
+ };
80
+
81
+ /**
82
+ * Invite users or robots to join a team.
83
+ * POST /open-apis/team/v1/team-set/invite
84
+ */
85
+ export async function inviteToTeam(params: InviteToTeamParams): Promise<InviteToTeamResult> {
86
+ const { cfg, uid, tid, inviteList, type = "1", text } = params;
87
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
88
+ if (!popoCfg) {
89
+ throw new Error("POPO Native channel not configured");
90
+ }
91
+
92
+ const body: Record<string, unknown> = { uid, tid, inviteList, type };
93
+ if (text) body.text = text;
94
+
95
+ const response = await popoNativeRequest<{
96
+ type?: number;
97
+ failList?: Record<string, string>;
98
+ }>({
99
+ cfg: popoCfg,
100
+ method: "POST",
101
+ path: "/open-apis/team/v1/team-set/invite",
102
+ body,
103
+ });
104
+
105
+ if (response.errcode !== 0) {
106
+ return {
107
+ success: false,
108
+ error: response.errmsg || `errcode ${response.errcode}`,
109
+ };
110
+ }
111
+
112
+ return {
113
+ success: true,
114
+ type: response.data?.type,
115
+ failList: response.data?.failList,
116
+ };
117
+ }
118
+
119
+ export type DropTeamParams = {
120
+ cfg: ClawdbotConfig;
121
+ uid: string; // Operator email
122
+ tid: string;
123
+ };
124
+
125
+ export type DropTeamResult = {
126
+ success: boolean;
127
+ error?: string;
128
+ };
129
+
130
+ /**
131
+ * Disband (delete) a team.
132
+ * POST /open-apis/team/v1/team-set/drop
133
+ */
134
+ export async function dropTeam(params: DropTeamParams): Promise<DropTeamResult> {
135
+ const { cfg, uid, tid } = params;
136
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
137
+ if (!popoCfg) {
138
+ throw new Error("POPO Native channel not configured");
139
+ }
140
+
141
+ const response = await popoNativeRequest<unknown>({
142
+ cfg: popoCfg,
143
+ method: "POST",
144
+ path: "/open-apis/team/v1/team-set/drop",
145
+ body: { uid, tid },
146
+ });
147
+
148
+ if (response.errcode !== 0) {
149
+ return {
150
+ success: false,
151
+ error: response.errmsg || `errcode ${response.errcode}`,
152
+ };
153
+ }
154
+
155
+ return { success: true };
156
+ }
157
+
158
+ export type TeamMember = {
159
+ uid: string;
160
+ name: string;
161
+ nickName?: string;
162
+ teamNickName?: string;
163
+ };
164
+
165
+ export type GetTeamMembersParams = {
166
+ cfg: ClawdbotConfig;
167
+ uid: string; // Operator email
168
+ tid: string;
169
+ page?: number;
170
+ limit?: number;
171
+ };
172
+
173
+ export type GetTeamMembersResult = {
174
+ success: boolean;
175
+ records?: TeamMember[];
176
+ total?: number;
177
+ page?: number;
178
+ limit?: number;
179
+ error?: string;
180
+ };
181
+
182
+ /**
183
+ * Get member list of a team.
184
+ * GET /open-apis/team/v1/team-members?tid={tid}&uid={uid}
185
+ */
186
+ export async function getTeamMembers(params: GetTeamMembersParams): Promise<GetTeamMembersResult> {
187
+ const { cfg, uid, tid, page = 1, limit = 20 } = params;
188
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
189
+ if (!popoCfg) {
190
+ throw new Error("POPO Native channel not configured");
191
+ }
192
+
193
+ const response = await popoNativeRequest<{
194
+ records?: TeamMember[];
195
+ total?: number;
196
+ page?: number;
197
+ limit?: number;
198
+ }>({
199
+ cfg: popoCfg,
200
+ method: "GET",
201
+ path: "/open-apis/team/v1/team-members",
202
+ query: { tid, uid, page: String(page), limit: String(limit) },
203
+ });
204
+
205
+ if (response.errcode !== 0) {
206
+ return {
207
+ success: false,
208
+ error: response.errmsg || `errcode ${response.errcode}`,
209
+ };
210
+ }
211
+
212
+ return {
213
+ success: true,
214
+ records: response.data?.records,
215
+ total: response.data?.total,
216
+ page: response.data?.page,
217
+ limit: response.data?.limit,
218
+ };
219
+ }
220
+
221
+ export type TeamInfo = {
222
+ name: string;
223
+ desc?: string;
224
+ board?: string;
225
+ };
226
+
227
+ export type GetTeamInfoParams = {
228
+ cfg: ClawdbotConfig;
229
+ uid: string; // Operator email
230
+ tid: string;
231
+ scopes?: string[]; // e.g., ["board"] to get announcement
232
+ };
233
+
234
+ export type GetTeamInfoResult = {
235
+ success: boolean;
236
+ info?: TeamInfo;
237
+ error?: string;
238
+ };
239
+
240
+ /**
241
+ * Get basic information of a team.
242
+ * GET /open-apis/team/v1/team-info?tid={tid}&uid={uid}&scopes={scopes}
243
+ */
244
+ export async function getTeamInfo(params: GetTeamInfoParams): Promise<GetTeamInfoResult> {
245
+ const { cfg, uid, tid, scopes } = params;
246
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
247
+ if (!popoCfg) {
248
+ throw new Error("POPO Native channel not configured");
249
+ }
250
+
251
+ const query: Record<string, string> = { tid, uid };
252
+ if (scopes && scopes.length > 0) {
253
+ query.scopes = scopes.join(",");
254
+ }
255
+
256
+ const response = await popoNativeRequest<TeamInfo>({
257
+ cfg: popoCfg,
258
+ method: "GET",
259
+ path: "/open-apis/team/v1/team-info",
260
+ query,
261
+ });
262
+
263
+ if (response.errcode !== 0) {
264
+ return {
265
+ success: false,
266
+ error: response.errmsg || `errcode ${response.errcode}`,
267
+ };
268
+ }
269
+
270
+ return {
271
+ success: true,
272
+ info: response.data,
273
+ };
274
+ }
275
+
276
+ export type UpdateTeamInfoParams = {
277
+ cfg: ClawdbotConfig;
278
+ uid: string; // Operator email
279
+ tid: string;
280
+ name: string;
281
+ board: string;
282
+ type?: number; // 1=notification only, 2=card announcement
283
+ };
284
+
285
+ export type UpdateTeamInfoResult = {
286
+ success: boolean;
287
+ error?: string;
288
+ };
289
+
290
+ /**
291
+ * Update basic information of a team.
292
+ * Note: Native API may have different endpoint for this.
293
+ * This is a placeholder implementation.
294
+ */
295
+ export async function updateTeamInfo(params: UpdateTeamInfoParams): Promise<UpdateTeamInfoResult> {
296
+ const { cfg, uid, tid, name, board, type } = params;
297
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
298
+ if (!popoCfg) {
299
+ throw new Error("POPO Native channel not configured");
300
+ }
301
+
302
+ // Native API team update endpoint may differ
303
+ // Using a generic approach
304
+ const body: Record<string, unknown> = { uid, tid, name, board };
305
+ if (type !== undefined) body.type = type;
306
+
307
+ const response = await popoNativeRequest<unknown>({
308
+ cfg: popoCfg,
309
+ method: "POST",
310
+ path: "/open-apis/team/v1/team-set/update",
311
+ body,
312
+ });
313
+
314
+ if (response.errcode !== 0) {
315
+ return {
316
+ success: false,
317
+ error: response.errmsg || `errcode ${response.errcode}`,
318
+ };
319
+ }
320
+
321
+ return { success: true };
322
+ }
323
+
324
+ export type UpdateTeamManagementParams = {
325
+ cfg: ClawdbotConfig;
326
+ uid: string; // Operator email
327
+ tid: string;
328
+ type: number; // Setting item type (1-8)
329
+ value: number; // Setting value
330
+ };
331
+
332
+ export type UpdateTeamManagementResult = {
333
+ success: boolean;
334
+ error?: string;
335
+ };
336
+
337
+ /**
338
+ * Update team management settings.
339
+ * Note: Native API may have different endpoint for this.
340
+ *
341
+ * Setting types:
342
+ * 1 - Only owner/admin can edit group info (1=on, 2=off)
343
+ * 2 - Only owner/admin can add members (1=on, 2=off)
344
+ * 3 - Allow apply to join (1=on, 2=off)
345
+ * 4 - Members can view chat history (1=on, 2=off)
346
+ * 5 - New member join notification (1=all, 2=owner/admin only, 3=none)
347
+ * 6 - Member leave notification (1=all, 2=owner/admin only, 3=none)
348
+ * 7 - Allow modify nickname in group (1=on, 2=off)
349
+ * 8 - Allow external accounts to join (1=on, 2=off)
350
+ */
351
+ export async function updateTeamManagement(
352
+ params: UpdateTeamManagementParams
353
+ ): Promise<UpdateTeamManagementResult> {
354
+ const { cfg, uid, tid, type, value } = params;
355
+ const popoCfg = cfg.channels?.["popo-native"] as PopoNativeConfig | undefined;
356
+ if (!popoCfg) {
357
+ throw new Error("POPO Native channel not configured");
358
+ }
359
+
360
+ const response = await popoNativeRequest<unknown>({
361
+ cfg: popoCfg,
362
+ method: "POST",
363
+ path: "/open-apis/team/v1/team-set/management",
364
+ body: { uid, tid, type, value },
365
+ });
366
+
367
+ if (response.errcode !== 0) {
368
+ return {
369
+ success: false,
370
+ error: response.errmsg || `errcode ${response.errcode}`,
371
+ };
372
+ }
373
+
374
+ return { success: true };
375
+ }
376
+
377
+ // ==================== View Scope APIs ====================
378
+
379
+ export type ViewScopeRecord = {
380
+ scopeType: string; // "PERSONAL" or "DEPARTMENT"
381
+ scopeValue: string;
382
+ };
383
+
384
+ export type GetViewScopeParams = {
385
+ cfg: ClawdbotConfig;
386
+ scopeType?: "PERSONAL" | "DEPARTMENT";
387
+ current?: number;
388
+ limit?: number;
389
+ };
390
+
391
+ export type GetViewScopeResult = {
392
+ success: boolean;
393
+ records?: ViewScopeRecord[];
394
+ viewScopeType?: number; // 1=all visible, 2=partial visible
395
+ total?: number;
396
+ size?: number;
397
+ current?: number;
398
+ error?: string;
399
+ };
400
+
401
+ /**
402
+ * Query robot's visible scope.
403
+ * Note: Native API may not have this endpoint.
404
+ */
405
+ export async function getViewScope(params: GetViewScopeParams): Promise<GetViewScopeResult> {
406
+ // Native API may not support view scope
407
+ return {
408
+ success: false,
409
+ error: "View scope not supported in POPO Native API",
410
+ };
411
+ }
412
+
413
+ export type ModifyViewScopeParams = {
414
+ cfg: ClawdbotConfig;
415
+ operationType: 1 | 2; // 1=add, 2=delete
416
+ scopeType: "PERSONAL" | "DEPARTMENT";
417
+ scopeValues: string[];
418
+ };
419
+
420
+ export type ModifyViewScopeResult = {
421
+ success: boolean;
422
+ successNum?: number;
423
+ failNum?: number;
424
+ failMsg?: Record<string, string>;
425
+ error?: string;
426
+ };
427
+
428
+ /**
429
+ * Modify robot's visible scope.
430
+ * Note: Native API may not have this endpoint.
431
+ */
432
+ export async function modifyViewScope(params: ModifyViewScopeParams): Promise<ModifyViewScopeResult> {
433
+ // Native API may not support view scope modification
434
+ return {
435
+ success: false,
436
+ error: "View scope modification not supported in POPO Native API",
437
+ };
438
+ }
439
+
440
+ export type PublishRobotParams = {
441
+ cfg: ClawdbotConfig;
442
+ uid: string; // Applicant email
443
+ };
444
+
445
+ export type PublishRobotResult = {
446
+ success: boolean;
447
+ error?: string;
448
+ };
449
+
450
+ /**
451
+ * Apply to publish robot.
452
+ * Note: Native API may not have this endpoint.
453
+ */
454
+ export async function publishRobot(params: PublishRobotParams): Promise<PublishRobotResult> {
455
+ // Native API may not support robot publishing
456
+ return {
457
+ success: false,
458
+ error: "Robot publishing not supported in POPO Native API",
459
+ };
460
+ }
package/src/types.ts ADDED
@@ -0,0 +1,104 @@
1
+ import type { PopoNativeConfigSchema, z } from "./config-schema.js";
2
+
3
+ export type PopoNativeConfig = z.infer<typeof PopoNativeConfigSchema>;
4
+
5
+ export type ResolvedPopoNativeAccount = {
6
+ accountId: string;
7
+ enabled: boolean;
8
+ configured: boolean;
9
+ appId?: string;
10
+ };
11
+
12
+ export type PopoNativeReceiverType = "email" | "groupId";
13
+
14
+ export type PopoNativeMessageContext = {
15
+ sessionId: string;
16
+ messageId: string;
17
+ senderId: string;
18
+ senderEmail: string;
19
+ senderName?: string;
20
+ chatType: "p2p" | "group";
21
+ content: string;
22
+ contentType: string;
23
+ fileId?: string;
24
+ };
25
+
26
+ export type PopoNativeSendResult = {
27
+ messageId?: string;
28
+ sessionId: string;
29
+ };
30
+
31
+ export type PopoNativeProbeResult = {
32
+ ok: boolean;
33
+ error?: string;
34
+ appId?: string;
35
+ };
36
+
37
+ export type PopoNativeMediaInfo = {
38
+ path: string;
39
+ contentType?: string;
40
+ placeholder: string;
41
+ };
42
+
43
+ // Native API token structure (different from robot API)
44
+ export type PopoNativeToken = {
45
+ openAccessToken: string;
46
+ accessExpiredAt: number;
47
+ // No refresh token in native API
48
+ };
49
+
50
+ // Native API event types
51
+ export type PopoNativeMsgSendEvent = {
52
+ eventType: "MSG_SEND";
53
+ eventData: {
54
+ sessionType: 1 | 3; // 1=P2P, 3=Group
55
+ sessionId: string; // User email or Team ID
56
+ msgType: number; // 1=text, 142=video, 171=file, 161=merge, 211=quote
57
+ from: string; // Sender email
58
+ to: string; // Recipient email or Team ID
59
+ uuid: string; // Message ID
60
+ notify: string; // Message content
61
+ addtime: string; // Timestamp
62
+ atType?: 0 | 1 | 2; // 0=none, 1=@users, 2=@all
63
+ atList?: string[]; // @mentioned users
64
+ fileInfo?: {
65
+ fileId: string;
66
+ fileName: string;
67
+ fileSize: number;
68
+ fileType: string;
69
+ };
70
+ videoInfo?: {
71
+ videoId: string;
72
+ duration: number;
73
+ width: number;
74
+ height: number;
75
+ };
76
+ quoteInfo?: {
77
+ uuid: string;
78
+ from: string;
79
+ notify: string;
80
+ };
81
+ };
82
+ };
83
+
84
+ export type PopoNativeMsgRecallEvent = {
85
+ eventType: "MSG_RECALL";
86
+ eventData: {
87
+ sessionType: 1 | 3;
88
+ sessionId: string;
89
+ uuid: string;
90
+ from: string;
91
+ };
92
+ };
93
+
94
+ export type PopoNativeActionEvent = {
95
+ eventType: "ACTION";
96
+ eventData: {
97
+ actionId: string;
98
+ userId: string;
99
+ cardId: string;
100
+ data?: Record<string, unknown>;
101
+ };
102
+ };
103
+
104
+ export type PopoNativeEvent = PopoNativeMsgSendEvent | PopoNativeMsgRecallEvent | PopoNativeActionEvent;