@nextclaw/channel-plugin-feishu 0.2.29-beta.0 → 0.2.29-beta.1

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 (114) hide show
  1. package/dist/index.d.ts +23 -0
  2. package/dist/index.js +45 -0
  3. package/dist/src/accounts.js +141 -0
  4. package/dist/src/app-scope-checker.js +36 -0
  5. package/dist/src/async.js +34 -0
  6. package/dist/src/auth-errors.js +72 -0
  7. package/dist/src/bitable.js +495 -0
  8. package/dist/src/bot.d.ts +35 -0
  9. package/dist/src/bot.js +941 -0
  10. package/dist/src/calendar-calendar.js +54 -0
  11. package/dist/src/calendar-event-attendee.js +98 -0
  12. package/dist/src/calendar-event.js +193 -0
  13. package/dist/src/calendar-freebusy.js +40 -0
  14. package/dist/src/calendar-shared.js +23 -0
  15. package/dist/src/calendar.js +16 -0
  16. package/dist/src/card-action.js +49 -0
  17. package/dist/src/channel.d.ts +7 -0
  18. package/dist/src/channel.js +413 -0
  19. package/dist/src/chat-schema.js +25 -0
  20. package/dist/src/chat.js +87 -0
  21. package/dist/src/client.d.ts +16 -0
  22. package/dist/src/client.js +112 -0
  23. package/dist/src/config-schema.d.ts +357 -0
  24. package/dist/src/dedup.js +126 -0
  25. package/dist/src/device-flow.js +109 -0
  26. package/dist/src/directory.js +101 -0
  27. package/dist/src/doc-schema.js +148 -0
  28. package/dist/src/docx-batch-insert.js +104 -0
  29. package/dist/src/docx-color-text.js +80 -0
  30. package/dist/src/docx-table-ops.js +197 -0
  31. package/dist/src/docx.js +858 -0
  32. package/dist/src/domains.js +14 -0
  33. package/dist/src/drive-schema.js +41 -0
  34. package/dist/src/drive.js +126 -0
  35. package/dist/src/dynamic-agent.js +93 -0
  36. package/dist/src/external-keys.js +13 -0
  37. package/dist/src/feishu-fetch.js +12 -0
  38. package/dist/src/identity.js +92 -0
  39. package/dist/src/lark-ticket.js +11 -0
  40. package/dist/src/media.d.ts +75 -0
  41. package/dist/src/media.js +304 -0
  42. package/dist/src/mention.d.ts +52 -0
  43. package/dist/src/mention.js +82 -0
  44. package/dist/src/monitor.account.d.ts +1 -0
  45. package/dist/src/monitor.account.js +393 -0
  46. package/dist/src/monitor.d.ts +11 -0
  47. package/dist/src/monitor.js +58 -0
  48. package/dist/src/monitor.startup.js +24 -0
  49. package/dist/src/monitor.state.d.ts +1 -0
  50. package/dist/src/monitor.state.js +80 -0
  51. package/dist/src/monitor.transport.js +167 -0
  52. package/dist/src/nextclaw-sdk/account-id.js +15 -0
  53. package/dist/src/nextclaw-sdk/core-channel.js +150 -0
  54. package/dist/src/nextclaw-sdk/core-pairing.js +151 -0
  55. package/dist/src/nextclaw-sdk/dedupe.js +164 -0
  56. package/dist/src/nextclaw-sdk/feishu.d.ts +1 -0
  57. package/dist/src/nextclaw-sdk/feishu.js +14 -0
  58. package/dist/src/nextclaw-sdk/history.js +69 -0
  59. package/dist/src/nextclaw-sdk/network-body.js +180 -0
  60. package/dist/src/nextclaw-sdk/network-fetch.js +63 -0
  61. package/dist/src/nextclaw-sdk/network-webhook.js +126 -0
  62. package/dist/src/nextclaw-sdk/network.js +4 -0
  63. package/dist/src/nextclaw-sdk/runtime-store.js +21 -0
  64. package/dist/src/nextclaw-sdk/secrets-config.js +65 -0
  65. package/dist/src/nextclaw-sdk/secrets-core.d.ts +1 -0
  66. package/dist/src/nextclaw-sdk/secrets-core.js +68 -0
  67. package/dist/src/nextclaw-sdk/secrets-prompt.js +193 -0
  68. package/dist/src/nextclaw-sdk/secrets.d.ts +1 -0
  69. package/dist/src/nextclaw-sdk/secrets.js +4 -0
  70. package/dist/src/nextclaw-sdk/types.d.ts +242 -0
  71. package/dist/src/oauth.js +171 -0
  72. package/dist/src/onboarding.js +381 -0
  73. package/dist/src/outbound.js +150 -0
  74. package/dist/src/perm-schema.js +49 -0
  75. package/dist/src/perm.js +90 -0
  76. package/dist/src/policy.js +61 -0
  77. package/dist/src/post.js +160 -0
  78. package/dist/src/probe.d.ts +11 -0
  79. package/dist/src/probe.js +85 -0
  80. package/dist/src/raw-request.js +24 -0
  81. package/dist/src/reactions.d.ts +67 -0
  82. package/dist/src/reactions.js +91 -0
  83. package/dist/src/reply-dispatcher.js +250 -0
  84. package/dist/src/runtime.js +5 -0
  85. package/dist/src/secret-input.js +3 -0
  86. package/dist/src/send-result.js +12 -0
  87. package/dist/src/send-target.js +22 -0
  88. package/dist/src/send.d.ts +51 -0
  89. package/dist/src/send.js +265 -0
  90. package/dist/src/sheets-shared.js +193 -0
  91. package/dist/src/sheets.js +95 -0
  92. package/dist/src/streaming-card.js +263 -0
  93. package/dist/src/targets.js +39 -0
  94. package/dist/src/task-comment.js +76 -0
  95. package/dist/src/task-shared.js +13 -0
  96. package/dist/src/task-subtask.js +79 -0
  97. package/dist/src/task-task.js +144 -0
  98. package/dist/src/task-tasklist.js +136 -0
  99. package/dist/src/task.js +16 -0
  100. package/dist/src/token-store.js +154 -0
  101. package/dist/src/tool-account.js +65 -0
  102. package/dist/src/tool-result.js +18 -0
  103. package/dist/src/tool-scopes.js +62 -0
  104. package/dist/src/tools-config.js +30 -0
  105. package/dist/src/types.d.ts +43 -0
  106. package/dist/src/typing.js +145 -0
  107. package/dist/src/uat-client.js +102 -0
  108. package/dist/src/user-tool-client.js +132 -0
  109. package/dist/src/user-tool-helpers.js +110 -0
  110. package/dist/src/user-tool-result.js +10 -0
  111. package/dist/src/wiki-schema.js +45 -0
  112. package/dist/src/wiki.js +144 -0
  113. package/package.json +8 -4
  114. package/index.ts +0 -75
@@ -0,0 +1,357 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/config-schema.d.ts
4
+ declare const FeishuConfigSchema: z.ZodObject<{
5
+ dmPolicy: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
6
+ open: "open";
7
+ pairing: "pairing";
8
+ allowlist: "allowlist";
9
+ }>>>;
10
+ reactionNotifications: z.ZodDefault<z.ZodOptional<z.ZodOptional<z.ZodEnum<{
11
+ off: "off";
12
+ own: "own";
13
+ all: "all";
14
+ }>>>>;
15
+ groupPolicy: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
16
+ disabled: "disabled";
17
+ open: "open";
18
+ allowlist: "allowlist";
19
+ }>, z.ZodPipe<z.ZodLiteral<"allowall">, z.ZodTransform<"open", "allowall">>]>>>;
20
+ requireMention: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
21
+ groupSessionScope: z.ZodOptional<z.ZodEnum<{
22
+ group: "group";
23
+ group_sender: "group_sender";
24
+ group_topic: "group_topic";
25
+ group_topic_sender: "group_topic_sender";
26
+ }>>;
27
+ topicSessionMode: z.ZodOptional<z.ZodEnum<{
28
+ enabled: "enabled";
29
+ disabled: "disabled";
30
+ }>>;
31
+ dynamicAgentCreation: z.ZodOptional<z.ZodObject<{
32
+ enabled: z.ZodOptional<z.ZodBoolean>;
33
+ workspaceTemplate: z.ZodOptional<z.ZodString>;
34
+ agentDirTemplate: z.ZodOptional<z.ZodString>;
35
+ maxAgents: z.ZodOptional<z.ZodNumber>;
36
+ }, z.core.$strict>>;
37
+ typingIndicator: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
38
+ resolveSenderNames: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
39
+ accounts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
40
+ groupSessionScope: z.ZodOptional<z.ZodEnum<{
41
+ group: "group";
42
+ group_sender: "group_sender";
43
+ group_topic: "group_topic";
44
+ group_topic_sender: "group_topic_sender";
45
+ }>>;
46
+ topicSessionMode: z.ZodOptional<z.ZodEnum<{
47
+ enabled: "enabled";
48
+ disabled: "disabled";
49
+ }>>;
50
+ webhookHost: z.ZodOptional<z.ZodString>;
51
+ webhookPort: z.ZodOptional<z.ZodNumber>;
52
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
+ markdown: z.ZodOptional<z.ZodObject<{
54
+ mode: z.ZodOptional<z.ZodEnum<{
55
+ native: "native";
56
+ escape: "escape";
57
+ strip: "strip";
58
+ }>>;
59
+ tableMode: z.ZodOptional<z.ZodEnum<{
60
+ native: "native";
61
+ ascii: "ascii";
62
+ simple: "simple";
63
+ }>>;
64
+ }, z.core.$strict>>;
65
+ configWrites: z.ZodOptional<z.ZodBoolean>;
66
+ dmPolicy: z.ZodOptional<z.ZodEnum<{
67
+ open: "open";
68
+ pairing: "pairing";
69
+ allowlist: "allowlist";
70
+ }>>;
71
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
72
+ groupPolicy: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
73
+ disabled: "disabled";
74
+ open: "open";
75
+ allowlist: "allowlist";
76
+ }>, z.ZodPipe<z.ZodLiteral<"allowall">, z.ZodTransform<"open", "allowall">>]>>;
77
+ groupAllowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
78
+ groupSenderAllowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
79
+ requireMention: z.ZodOptional<z.ZodBoolean>;
80
+ groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
81
+ requireMention: z.ZodOptional<z.ZodBoolean>;
82
+ tools: z.ZodOptional<z.ZodObject<{
83
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
84
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
85
+ }, z.core.$strict>>;
86
+ skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
87
+ enabled: z.ZodOptional<z.ZodBoolean>;
88
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
89
+ systemPrompt: z.ZodOptional<z.ZodString>;
90
+ groupSessionScope: z.ZodOptional<z.ZodEnum<{
91
+ group: "group";
92
+ group_sender: "group_sender";
93
+ group_topic: "group_topic";
94
+ group_topic_sender: "group_topic_sender";
95
+ }>>;
96
+ topicSessionMode: z.ZodOptional<z.ZodEnum<{
97
+ enabled: "enabled";
98
+ disabled: "disabled";
99
+ }>>;
100
+ replyInThread: z.ZodOptional<z.ZodEnum<{
101
+ enabled: "enabled";
102
+ disabled: "disabled";
103
+ }>>;
104
+ }, z.core.$strict>>>>;
105
+ historyLimit: z.ZodOptional<z.ZodNumber>;
106
+ dmHistoryLimit: z.ZodOptional<z.ZodNumber>;
107
+ dms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
108
+ enabled: z.ZodOptional<z.ZodBoolean>;
109
+ systemPrompt: z.ZodOptional<z.ZodString>;
110
+ }, z.core.$strict>>>>;
111
+ textChunkLimit: z.ZodOptional<z.ZodNumber>;
112
+ chunkMode: z.ZodOptional<z.ZodEnum<{
113
+ length: "length";
114
+ newline: "newline";
115
+ }>>;
116
+ blockStreamingCoalesce: z.ZodOptional<z.ZodObject<{
117
+ enabled: z.ZodOptional<z.ZodBoolean>;
118
+ minDelayMs: z.ZodOptional<z.ZodNumber>;
119
+ maxDelayMs: z.ZodOptional<z.ZodNumber>;
120
+ }, z.core.$strict>>;
121
+ mediaMaxMb: z.ZodOptional<z.ZodNumber>;
122
+ httpTimeoutMs: z.ZodOptional<z.ZodNumber>;
123
+ heartbeat: z.ZodOptional<z.ZodObject<{
124
+ visibility: z.ZodOptional<z.ZodEnum<{
125
+ visible: "visible";
126
+ hidden: "hidden";
127
+ }>>;
128
+ intervalMs: z.ZodOptional<z.ZodNumber>;
129
+ }, z.core.$strict>>;
130
+ renderMode: z.ZodOptional<z.ZodEnum<{
131
+ auto: "auto";
132
+ raw: "raw";
133
+ card: "card";
134
+ }>>;
135
+ streaming: z.ZodOptional<z.ZodBoolean>;
136
+ tools: z.ZodOptional<z.ZodObject<{
137
+ doc: z.ZodOptional<z.ZodBoolean>;
138
+ chat: z.ZodOptional<z.ZodBoolean>;
139
+ wiki: z.ZodOptional<z.ZodBoolean>;
140
+ drive: z.ZodOptional<z.ZodBoolean>;
141
+ perm: z.ZodOptional<z.ZodBoolean>;
142
+ scopes: z.ZodOptional<z.ZodBoolean>;
143
+ calendar: z.ZodOptional<z.ZodBoolean>;
144
+ task: z.ZodOptional<z.ZodBoolean>;
145
+ sheets: z.ZodOptional<z.ZodBoolean>;
146
+ oauth: z.ZodOptional<z.ZodBoolean>;
147
+ identity: z.ZodOptional<z.ZodBoolean>;
148
+ }, z.core.$strict>>;
149
+ replyInThread: z.ZodOptional<z.ZodEnum<{
150
+ enabled: "enabled";
151
+ disabled: "disabled";
152
+ }>>;
153
+ reactionNotifications: z.ZodOptional<z.ZodEnum<{
154
+ off: "off";
155
+ own: "own";
156
+ all: "all";
157
+ }>>;
158
+ typingIndicator: z.ZodOptional<z.ZodBoolean>;
159
+ resolveSenderNames: z.ZodOptional<z.ZodBoolean>;
160
+ enabled: z.ZodOptional<z.ZodBoolean>;
161
+ name: z.ZodOptional<z.ZodString>;
162
+ appId: z.ZodOptional<z.ZodString>;
163
+ appSecret: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
164
+ source: z.ZodLiteral<"env">;
165
+ provider: z.ZodString;
166
+ id: z.ZodString;
167
+ }, z.core.$strip>, z.ZodObject<{
168
+ source: z.ZodLiteral<"file">;
169
+ provider: z.ZodString;
170
+ id: z.ZodString;
171
+ }, z.core.$strip>, z.ZodObject<{
172
+ source: z.ZodLiteral<"exec">;
173
+ provider: z.ZodString;
174
+ id: z.ZodString;
175
+ }, z.core.$strip>], "source">]>>;
176
+ encryptKey: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
177
+ source: z.ZodLiteral<"env">;
178
+ provider: z.ZodString;
179
+ id: z.ZodString;
180
+ }, z.core.$strip>, z.ZodObject<{
181
+ source: z.ZodLiteral<"file">;
182
+ provider: z.ZodString;
183
+ id: z.ZodString;
184
+ }, z.core.$strip>, z.ZodObject<{
185
+ source: z.ZodLiteral<"exec">;
186
+ provider: z.ZodString;
187
+ id: z.ZodString;
188
+ }, z.core.$strip>], "source">]>>;
189
+ verificationToken: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
190
+ source: z.ZodLiteral<"env">;
191
+ provider: z.ZodString;
192
+ id: z.ZodString;
193
+ }, z.core.$strip>, z.ZodObject<{
194
+ source: z.ZodLiteral<"file">;
195
+ provider: z.ZodString;
196
+ id: z.ZodString;
197
+ }, z.core.$strip>, z.ZodObject<{
198
+ source: z.ZodLiteral<"exec">;
199
+ provider: z.ZodString;
200
+ id: z.ZodString;
201
+ }, z.core.$strip>], "source">]>>;
202
+ domain: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
203
+ feishu: "feishu";
204
+ lark: "lark";
205
+ }>, z.ZodString]>>;
206
+ connectionMode: z.ZodOptional<z.ZodEnum<{
207
+ websocket: "websocket";
208
+ webhook: "webhook";
209
+ }>>;
210
+ webhookPath: z.ZodOptional<z.ZodString>;
211
+ }, z.core.$strict>>>>;
212
+ webhookHost: z.ZodOptional<z.ZodString>;
213
+ webhookPort: z.ZodOptional<z.ZodNumber>;
214
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodString>>;
215
+ markdown: z.ZodOptional<z.ZodObject<{
216
+ mode: z.ZodOptional<z.ZodEnum<{
217
+ native: "native";
218
+ escape: "escape";
219
+ strip: "strip";
220
+ }>>;
221
+ tableMode: z.ZodOptional<z.ZodEnum<{
222
+ native: "native";
223
+ ascii: "ascii";
224
+ simple: "simple";
225
+ }>>;
226
+ }, z.core.$strict>>;
227
+ configWrites: z.ZodOptional<z.ZodBoolean>;
228
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
229
+ groupAllowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
230
+ groupSenderAllowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
231
+ groups: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
232
+ requireMention: z.ZodOptional<z.ZodBoolean>;
233
+ tools: z.ZodOptional<z.ZodObject<{
234
+ allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
235
+ deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
236
+ }, z.core.$strict>>;
237
+ skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
238
+ enabled: z.ZodOptional<z.ZodBoolean>;
239
+ allowFrom: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
240
+ systemPrompt: z.ZodOptional<z.ZodString>;
241
+ groupSessionScope: z.ZodOptional<z.ZodEnum<{
242
+ group: "group";
243
+ group_sender: "group_sender";
244
+ group_topic: "group_topic";
245
+ group_topic_sender: "group_topic_sender";
246
+ }>>;
247
+ topicSessionMode: z.ZodOptional<z.ZodEnum<{
248
+ enabled: "enabled";
249
+ disabled: "disabled";
250
+ }>>;
251
+ replyInThread: z.ZodOptional<z.ZodEnum<{
252
+ enabled: "enabled";
253
+ disabled: "disabled";
254
+ }>>;
255
+ }, z.core.$strict>>>>;
256
+ historyLimit: z.ZodOptional<z.ZodNumber>;
257
+ dmHistoryLimit: z.ZodOptional<z.ZodNumber>;
258
+ dms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
259
+ enabled: z.ZodOptional<z.ZodBoolean>;
260
+ systemPrompt: z.ZodOptional<z.ZodString>;
261
+ }, z.core.$strict>>>>;
262
+ textChunkLimit: z.ZodOptional<z.ZodNumber>;
263
+ chunkMode: z.ZodOptional<z.ZodEnum<{
264
+ length: "length";
265
+ newline: "newline";
266
+ }>>;
267
+ blockStreamingCoalesce: z.ZodOptional<z.ZodObject<{
268
+ enabled: z.ZodOptional<z.ZodBoolean>;
269
+ minDelayMs: z.ZodOptional<z.ZodNumber>;
270
+ maxDelayMs: z.ZodOptional<z.ZodNumber>;
271
+ }, z.core.$strict>>;
272
+ mediaMaxMb: z.ZodOptional<z.ZodNumber>;
273
+ httpTimeoutMs: z.ZodOptional<z.ZodNumber>;
274
+ heartbeat: z.ZodOptional<z.ZodObject<{
275
+ visibility: z.ZodOptional<z.ZodEnum<{
276
+ visible: "visible";
277
+ hidden: "hidden";
278
+ }>>;
279
+ intervalMs: z.ZodOptional<z.ZodNumber>;
280
+ }, z.core.$strict>>;
281
+ renderMode: z.ZodOptional<z.ZodEnum<{
282
+ auto: "auto";
283
+ raw: "raw";
284
+ card: "card";
285
+ }>>;
286
+ streaming: z.ZodOptional<z.ZodBoolean>;
287
+ tools: z.ZodOptional<z.ZodObject<{
288
+ doc: z.ZodOptional<z.ZodBoolean>;
289
+ chat: z.ZodOptional<z.ZodBoolean>;
290
+ wiki: z.ZodOptional<z.ZodBoolean>;
291
+ drive: z.ZodOptional<z.ZodBoolean>;
292
+ perm: z.ZodOptional<z.ZodBoolean>;
293
+ scopes: z.ZodOptional<z.ZodBoolean>;
294
+ calendar: z.ZodOptional<z.ZodBoolean>;
295
+ task: z.ZodOptional<z.ZodBoolean>;
296
+ sheets: z.ZodOptional<z.ZodBoolean>;
297
+ oauth: z.ZodOptional<z.ZodBoolean>;
298
+ identity: z.ZodOptional<z.ZodBoolean>;
299
+ }, z.core.$strict>>;
300
+ replyInThread: z.ZodOptional<z.ZodEnum<{
301
+ enabled: "enabled";
302
+ disabled: "disabled";
303
+ }>>;
304
+ enabled: z.ZodOptional<z.ZodBoolean>;
305
+ defaultAccount: z.ZodOptional<z.ZodString>;
306
+ appId: z.ZodOptional<z.ZodString>;
307
+ appSecret: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
308
+ source: z.ZodLiteral<"env">;
309
+ provider: z.ZodString;
310
+ id: z.ZodString;
311
+ }, z.core.$strip>, z.ZodObject<{
312
+ source: z.ZodLiteral<"file">;
313
+ provider: z.ZodString;
314
+ id: z.ZodString;
315
+ }, z.core.$strip>, z.ZodObject<{
316
+ source: z.ZodLiteral<"exec">;
317
+ provider: z.ZodString;
318
+ id: z.ZodString;
319
+ }, z.core.$strip>], "source">]>>;
320
+ encryptKey: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
321
+ source: z.ZodLiteral<"env">;
322
+ provider: z.ZodString;
323
+ id: z.ZodString;
324
+ }, z.core.$strip>, z.ZodObject<{
325
+ source: z.ZodLiteral<"file">;
326
+ provider: z.ZodString;
327
+ id: z.ZodString;
328
+ }, z.core.$strip>, z.ZodObject<{
329
+ source: z.ZodLiteral<"exec">;
330
+ provider: z.ZodString;
331
+ id: z.ZodString;
332
+ }, z.core.$strip>], "source">]>>;
333
+ verificationToken: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
334
+ source: z.ZodLiteral<"env">;
335
+ provider: z.ZodString;
336
+ id: z.ZodString;
337
+ }, z.core.$strip>, z.ZodObject<{
338
+ source: z.ZodLiteral<"file">;
339
+ provider: z.ZodString;
340
+ id: z.ZodString;
341
+ }, z.core.$strip>, z.ZodObject<{
342
+ source: z.ZodLiteral<"exec">;
343
+ provider: z.ZodString;
344
+ id: z.ZodString;
345
+ }, z.core.$strip>], "source">]>>;
346
+ domain: z.ZodDefault<z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
347
+ feishu: "feishu";
348
+ lark: "lark";
349
+ }>, z.ZodString]>>>;
350
+ connectionMode: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
351
+ websocket: "websocket";
352
+ webhook: "webhook";
353
+ }>>>;
354
+ webhookPath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
355
+ }, z.core.$strict>;
356
+ //#endregion
357
+ export { FeishuConfigSchema, z };
@@ -0,0 +1,126 @@
1
+ import { createDedupeCache, createPersistentDedupe, readJsonFileWithFallback } from "./nextclaw-sdk/dedupe.js";
2
+ import "./nextclaw-sdk/feishu.js";
3
+ import path from "node:path";
4
+ import os from "node:os";
5
+ //#region src/dedup.ts
6
+ const DEDUP_TTL_MS = 1440 * 60 * 1e3;
7
+ const MEMORY_MAX_SIZE = 1e3;
8
+ const FILE_MAX_ENTRIES = 1e4;
9
+ const EVENT_DEDUP_TTL_MS = 300 * 1e3;
10
+ const EVENT_MEMORY_MAX_SIZE = 2e3;
11
+ const memoryDedupe = createDedupeCache({
12
+ ttlMs: DEDUP_TTL_MS,
13
+ maxSize: MEMORY_MAX_SIZE
14
+ });
15
+ const processingClaims = createDedupeCache({
16
+ ttlMs: EVENT_DEDUP_TTL_MS,
17
+ maxSize: EVENT_MEMORY_MAX_SIZE
18
+ });
19
+ function resolveStateDirFromEnv(env = process.env) {
20
+ const stateOverride = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim();
21
+ if (stateOverride) return stateOverride;
22
+ if (env.VITEST || env.NODE_ENV === "test") return path.join(os.tmpdir(), ["openclaw-vitest", String(process.pid)].join("-"));
23
+ return path.join(os.homedir(), ".openclaw");
24
+ }
25
+ function resolveNamespaceFilePath(namespace) {
26
+ const safe = namespace.replace(/[^a-zA-Z0-9_-]/g, "_");
27
+ return path.join(resolveStateDirFromEnv(), "feishu", "dedup", `${safe}.json`);
28
+ }
29
+ const persistentDedupe = createPersistentDedupe({
30
+ ttlMs: DEDUP_TTL_MS,
31
+ memoryMaxSize: MEMORY_MAX_SIZE,
32
+ fileMaxEntries: FILE_MAX_ENTRIES,
33
+ resolveFilePath: resolveNamespaceFilePath
34
+ });
35
+ function resolveEventDedupeKey(namespace, messageId) {
36
+ const trimmed = messageId?.trim();
37
+ if (!trimmed) return null;
38
+ return `${namespace}:${trimmed}`;
39
+ }
40
+ function normalizeMessageId(messageId) {
41
+ const trimmed = messageId?.trim();
42
+ return trimmed ? trimmed : null;
43
+ }
44
+ function resolveMemoryDedupeKey(namespace, messageId) {
45
+ const trimmed = normalizeMessageId(messageId);
46
+ if (!trimmed) return null;
47
+ return `${namespace}:${trimmed}`;
48
+ }
49
+ function tryBeginFeishuMessageProcessing(messageId, namespace = "global") {
50
+ return !processingClaims.check(resolveEventDedupeKey(namespace, messageId));
51
+ }
52
+ function releaseFeishuMessageProcessing(messageId, namespace = "global") {
53
+ processingClaims.delete(resolveEventDedupeKey(namespace, messageId));
54
+ }
55
+ async function finalizeFeishuMessageProcessing(params) {
56
+ const { messageId, namespace = "global", log, claimHeld = false } = params;
57
+ const normalizedMessageId = normalizeMessageId(messageId);
58
+ const memoryKey = resolveMemoryDedupeKey(namespace, messageId);
59
+ if (!memoryKey || !normalizedMessageId) return false;
60
+ if (!claimHeld && !tryBeginFeishuMessageProcessing(normalizedMessageId, namespace)) return false;
61
+ if (!tryRecordMessage(memoryKey)) {
62
+ releaseFeishuMessageProcessing(normalizedMessageId, namespace);
63
+ return false;
64
+ }
65
+ if (!await tryRecordMessagePersistent(normalizedMessageId, namespace, log)) {
66
+ releaseFeishuMessageProcessing(normalizedMessageId, namespace);
67
+ return false;
68
+ }
69
+ return true;
70
+ }
71
+ async function recordProcessedFeishuMessage(messageId, namespace = "global", log) {
72
+ const normalizedMessageId = normalizeMessageId(messageId);
73
+ const memoryKey = resolveMemoryDedupeKey(namespace, messageId);
74
+ if (!memoryKey || !normalizedMessageId) return false;
75
+ tryRecordMessage(memoryKey);
76
+ return await tryRecordMessagePersistent(normalizedMessageId, namespace, log);
77
+ }
78
+ async function hasProcessedFeishuMessage(messageId, namespace = "global", log) {
79
+ const normalizedMessageId = normalizeMessageId(messageId);
80
+ const memoryKey = resolveMemoryDedupeKey(namespace, messageId);
81
+ if (!memoryKey || !normalizedMessageId) return false;
82
+ if (hasRecordedMessage(memoryKey)) return true;
83
+ return hasRecordedMessagePersistent(normalizedMessageId, namespace, log);
84
+ }
85
+ /**
86
+ * Synchronous dedup — memory only.
87
+ * Kept for backward compatibility; prefer {@link tryRecordMessagePersistent}.
88
+ */
89
+ function tryRecordMessage(messageId) {
90
+ return !memoryDedupe.check(messageId);
91
+ }
92
+ function hasRecordedMessage(messageId) {
93
+ const trimmed = messageId.trim();
94
+ if (!trimmed) return false;
95
+ return memoryDedupe.peek(trimmed);
96
+ }
97
+ async function tryRecordMessagePersistent(messageId, namespace = "global", log) {
98
+ return persistentDedupe.checkAndRecord(messageId, {
99
+ namespace,
100
+ onDiskError: (error) => {
101
+ log?.(`feishu-dedup: disk error, falling back to memory: ${String(error)}`);
102
+ }
103
+ });
104
+ }
105
+ async function hasRecordedMessagePersistent(messageId, namespace = "global", log) {
106
+ const trimmed = messageId.trim();
107
+ if (!trimmed) return false;
108
+ const now = Date.now();
109
+ const filePath = resolveNamespaceFilePath(namespace);
110
+ try {
111
+ const { value } = await readJsonFileWithFallback(filePath, {});
112
+ const seenAt = value[trimmed];
113
+ if (typeof seenAt !== "number" || !Number.isFinite(seenAt)) return false;
114
+ return DEDUP_TTL_MS <= 0 || now - seenAt < DEDUP_TTL_MS;
115
+ } catch (error) {
116
+ log?.(`feishu-dedup: persistent peek failed: ${String(error)}`);
117
+ return false;
118
+ }
119
+ }
120
+ async function warmupDedupFromDisk(namespace, log) {
121
+ return persistentDedupe.warmup(namespace, (error) => {
122
+ log?.(`feishu-dedup: warmup disk error: ${String(error)}`);
123
+ });
124
+ }
125
+ //#endregion
126
+ export { finalizeFeishuMessageProcessing, hasProcessedFeishuMessage, recordProcessedFeishuMessage, releaseFeishuMessageProcessing, tryBeginFeishuMessageProcessing, tryRecordMessagePersistent, warmupDedupFromDisk };
@@ -0,0 +1,109 @@
1
+ import { feishuFetch } from "./feishu-fetch.js";
2
+ //#region src/device-flow.ts
3
+ function resolveOAuthEndpoints(domain) {
4
+ if (!domain || domain === "feishu") return {
5
+ deviceAuthorization: "https://accounts.feishu.cn/oauth/v1/device_authorization",
6
+ token: "https://open.feishu.cn/open-apis/authen/v2/oauth/token"
7
+ };
8
+ if (domain === "lark") return {
9
+ deviceAuthorization: "https://accounts.larksuite.com/oauth/v1/device_authorization",
10
+ token: "https://open.larksuite.com/open-apis/authen/v2/oauth/token"
11
+ };
12
+ const base = domain.replace(/\/+$/, "");
13
+ let accountsBase = base;
14
+ try {
15
+ const parsed = new URL(base);
16
+ if (parsed.hostname.startsWith("open.")) accountsBase = `${parsed.protocol}//${parsed.hostname.replace(/^open\./, "accounts.")}`;
17
+ } catch {}
18
+ return {
19
+ deviceAuthorization: `${accountsBase}/oauth/v1/device_authorization`,
20
+ token: `${base}/open-apis/authen/v2/oauth/token`
21
+ };
22
+ }
23
+ async function requestDeviceAuthorization(params) {
24
+ const endpoints = resolveOAuthEndpoints(params.domain);
25
+ let scope = params.scope?.trim() ?? "";
26
+ if (!scope.includes("offline_access")) scope = scope ? `${scope} offline_access` : "offline_access";
27
+ const basicAuth = Buffer.from(`${params.appId}:${params.appSecret}`).toString("base64");
28
+ const body = new URLSearchParams();
29
+ body.set("client_id", params.appId);
30
+ body.set("scope", scope);
31
+ const response = await feishuFetch(endpoints.deviceAuthorization, {
32
+ method: "POST",
33
+ headers: {
34
+ "Content-Type": "application/x-www-form-urlencoded",
35
+ Authorization: `Basic ${basicAuth}`
36
+ },
37
+ body: body.toString()
38
+ });
39
+ const data = await response.json();
40
+ if (!response.ok || data.error) throw new Error(String(data.error_description ?? data.error ?? `HTTP ${response.status}`));
41
+ return {
42
+ deviceCode: String(data.device_code ?? ""),
43
+ userCode: String(data.user_code ?? ""),
44
+ verificationUri: String(data.verification_uri ?? ""),
45
+ verificationUriComplete: String(data.verification_uri_complete ?? data.verification_uri ?? ""),
46
+ expiresIn: Number(data.expires_in ?? 240),
47
+ interval: Number(data.interval ?? 5)
48
+ };
49
+ }
50
+ function sleep(ms, signal) {
51
+ return new Promise((resolve, reject) => {
52
+ const timer = setTimeout(resolve, ms);
53
+ signal?.addEventListener("abort", () => {
54
+ clearTimeout(timer);
55
+ reject(new DOMException("Aborted", "AbortError"));
56
+ }, { once: true });
57
+ });
58
+ }
59
+ async function pollDeviceToken(params) {
60
+ const endpoints = resolveOAuthEndpoints(params.domain);
61
+ const deadline = Date.now() + params.expiresIn * 1e3;
62
+ let interval = params.interval;
63
+ while (Date.now() < deadline) {
64
+ if (params.signal?.aborted) return {
65
+ ok: false,
66
+ error: "expired_token",
67
+ message: "Polling was cancelled"
68
+ };
69
+ await sleep(interval * 1e3, params.signal);
70
+ const data = await (await feishuFetch(endpoints.token, {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
73
+ body: new URLSearchParams({
74
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
75
+ device_code: params.deviceCode,
76
+ client_id: params.appId,
77
+ client_secret: params.appSecret
78
+ }).toString()
79
+ })).json();
80
+ const error = typeof data.error === "string" ? data.error : void 0;
81
+ if (!error && data.access_token) return {
82
+ ok: true,
83
+ token: {
84
+ accessToken: String(data.access_token),
85
+ refreshToken: String(data.refresh_token ?? ""),
86
+ expiresIn: Number(data.expires_in ?? 7200),
87
+ refreshExpiresIn: Number(data.refresh_token_expires_in ?? data.expires_in ?? 7200),
88
+ scope: String(data.scope ?? "")
89
+ }
90
+ };
91
+ if (error === "authorization_pending") continue;
92
+ if (error === "slow_down") {
93
+ interval = Math.min(interval + 5, 60);
94
+ continue;
95
+ }
96
+ if (error === "access_denied" || error === "expired_token") return {
97
+ ok: false,
98
+ error,
99
+ message: String(data.error_description ?? error)
100
+ };
101
+ }
102
+ return {
103
+ ok: false,
104
+ error: "expired_token",
105
+ message: "Device authorization expired before approval finished."
106
+ };
107
+ }
108
+ //#endregion
109
+ export { pollDeviceToken, requestDeviceAuthorization, resolveOAuthEndpoints };
@@ -0,0 +1,101 @@
1
+ import { listDirectoryGroupEntriesFromMapKeysAndAllowFrom, listDirectoryUserEntriesFromAllowFromAndMapKeys } from "./nextclaw-sdk/core-channel.js";
2
+ import { resolveFeishuAccount } from "./accounts.js";
3
+ import { createFeishuClient } from "./client.js";
4
+ import { normalizeFeishuTarget } from "./targets.js";
5
+ //#region src/directory.ts
6
+ function toFeishuDirectoryPeers(ids) {
7
+ return ids.map((id) => ({
8
+ kind: "user",
9
+ id
10
+ }));
11
+ }
12
+ function toFeishuDirectoryGroups(ids) {
13
+ return ids.map((id) => ({
14
+ kind: "group",
15
+ id
16
+ }));
17
+ }
18
+ async function listFeishuDirectoryPeers(params) {
19
+ const account = resolveFeishuAccount({
20
+ cfg: params.cfg,
21
+ accountId: params.accountId
22
+ });
23
+ return toFeishuDirectoryPeers(listDirectoryUserEntriesFromAllowFromAndMapKeys({
24
+ allowFrom: account.config.allowFrom,
25
+ map: account.config.dms,
26
+ query: params.query,
27
+ limit: params.limit,
28
+ normalizeAllowFromId: (entry) => normalizeFeishuTarget(entry) ?? entry,
29
+ normalizeMapKeyId: (entry) => normalizeFeishuTarget(entry) ?? entry
30
+ }).map((entry) => entry.id));
31
+ }
32
+ async function listFeishuDirectoryGroups(params) {
33
+ const account = resolveFeishuAccount({
34
+ cfg: params.cfg,
35
+ accountId: params.accountId
36
+ });
37
+ return toFeishuDirectoryGroups(listDirectoryGroupEntriesFromMapKeysAndAllowFrom({
38
+ groups: account.config.groups,
39
+ allowFrom: account.config.groupAllowFrom,
40
+ query: params.query,
41
+ limit: params.limit
42
+ }).map((entry) => entry.id));
43
+ }
44
+ async function listFeishuDirectoryPeersLive(params) {
45
+ const account = resolveFeishuAccount({
46
+ cfg: params.cfg,
47
+ accountId: params.accountId
48
+ });
49
+ if (!account.configured) return listFeishuDirectoryPeers(params);
50
+ try {
51
+ const client = createFeishuClient(account);
52
+ const peers = [];
53
+ const limit = params.limit ?? 50;
54
+ const response = await client.contact.user.list({ params: { page_size: Math.min(limit, 50) } });
55
+ if (response.code === 0 && response.data?.items) for (const user of response.data.items) {
56
+ if (user.open_id) {
57
+ const q = params.query?.trim().toLowerCase() || "";
58
+ const name = user.name || "";
59
+ if (!q || user.open_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) peers.push({
60
+ kind: "user",
61
+ id: user.open_id,
62
+ name: name || void 0
63
+ });
64
+ }
65
+ if (peers.length >= limit) break;
66
+ }
67
+ return peers;
68
+ } catch {
69
+ return listFeishuDirectoryPeers(params);
70
+ }
71
+ }
72
+ async function listFeishuDirectoryGroupsLive(params) {
73
+ const account = resolveFeishuAccount({
74
+ cfg: params.cfg,
75
+ accountId: params.accountId
76
+ });
77
+ if (!account.configured) return listFeishuDirectoryGroups(params);
78
+ try {
79
+ const client = createFeishuClient(account);
80
+ const groups = [];
81
+ const limit = params.limit ?? 50;
82
+ const response = await client.im.chat.list({ params: { page_size: Math.min(limit, 100) } });
83
+ if (response.code === 0 && response.data?.items) for (const chat of response.data.items) {
84
+ if (chat.chat_id) {
85
+ const q = params.query?.trim().toLowerCase() || "";
86
+ const name = chat.name || "";
87
+ if (!q || chat.chat_id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) groups.push({
88
+ kind: "group",
89
+ id: chat.chat_id,
90
+ name: name || void 0
91
+ });
92
+ }
93
+ if (groups.length >= limit) break;
94
+ }
95
+ return groups;
96
+ } catch {
97
+ return listFeishuDirectoryGroups(params);
98
+ }
99
+ }
100
+ //#endregion
101
+ export { listFeishuDirectoryGroups, listFeishuDirectoryGroupsLive, listFeishuDirectoryPeers, listFeishuDirectoryPeersLive };