@clowder-ai/connector-feishu 0.0.0-stage → 0.1.0-alpha.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.
Files changed (78) hide show
  1. package/README.en.md +54 -0
  2. package/README.md +25 -2
  3. package/assets/icon.svg +3 -0
  4. package/dist/FeishuAdapter.d.ts +250 -0
  5. package/dist/FeishuAdapter.d.ts.map +1 -0
  6. package/dist/FeishuAdapter.js +845 -0
  7. package/dist/FeishuAdapter.js.map +1 -0
  8. package/dist/FeishuQrBindClient.d.ts +23 -0
  9. package/dist/FeishuQrBindClient.d.ts.map +1 -0
  10. package/dist/FeishuQrBindClient.js +97 -0
  11. package/dist/FeishuQrBindClient.js.map +1 -0
  12. package/dist/FeishuTokenManager.d.ts +15 -0
  13. package/dist/FeishuTokenManager.d.ts.map +1 -0
  14. package/dist/FeishuTokenManager.js +35 -0
  15. package/dist/FeishuTokenManager.js.map +1 -0
  16. package/dist/command-ingress.d.ts +10 -0
  17. package/dist/command-ingress.d.ts.map +1 -0
  18. package/dist/command-ingress.js +15 -0
  19. package/dist/command-ingress.js.map +1 -0
  20. package/dist/execution-status.d.ts +27 -0
  21. package/dist/execution-status.d.ts.map +1 -0
  22. package/dist/execution-status.js +48 -0
  23. package/dist/execution-status.js.map +1 -0
  24. package/dist/feishu-card-formatter.d.ts +18 -0
  25. package/dist/feishu-card-formatter.d.ts.map +1 -0
  26. package/dist/feishu-card-formatter.js +58 -0
  27. package/dist/feishu-card-formatter.js.map +1 -0
  28. package/dist/inbound-download.d.ts +13 -0
  29. package/dist/inbound-download.d.ts.map +1 -0
  30. package/dist/inbound-download.js +70 -0
  31. package/dist/inbound-download.js.map +1 -0
  32. package/dist/inbound-media-source.d.ts +25 -0
  33. package/dist/inbound-media-source.d.ts.map +1 -0
  34. package/dist/inbound-media-source.js +111 -0
  35. package/dist/inbound-media-source.js.map +1 -0
  36. package/dist/index.d.ts +9 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +5 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/lifecycle-action.d.ts +30 -0
  41. package/dist/lifecycle-action.d.ts.map +1 -0
  42. package/dist/lifecycle-action.js +457 -0
  43. package/dist/lifecycle-action.js.map +1 -0
  44. package/dist/materialize-media.d.ts +7 -0
  45. package/dist/materialize-media.d.ts.map +1 -0
  46. package/dist/materialize-media.js +35 -0
  47. package/dist/materialize-media.js.map +1 -0
  48. package/dist/media-notice.d.ts +6 -0
  49. package/dist/media-notice.d.ts.map +1 -0
  50. package/dist/media-notice.js +50 -0
  51. package/dist/media-notice.js.map +1 -0
  52. package/dist/plugin-entrypoint.d.ts +9 -0
  53. package/dist/plugin-entrypoint.d.ts.map +1 -0
  54. package/dist/plugin-entrypoint.js +347 -0
  55. package/dist/plugin-entrypoint.js.map +1 -0
  56. package/dist/reply-sender-map.d.ts +10 -0
  57. package/dist/reply-sender-map.d.ts.map +1 -0
  58. package/dist/reply-sender-map.js +123 -0
  59. package/dist/reply-sender-map.js.map +1 -0
  60. package/dist/runtime.d.ts +190 -0
  61. package/dist/runtime.d.ts.map +1 -0
  62. package/dist/runtime.js +580 -0
  63. package/dist/runtime.js.map +1 -0
  64. package/dist/settings.d.ts +20 -0
  65. package/dist/settings.d.ts.map +1 -0
  66. package/dist/settings.js +35 -0
  67. package/dist/settings.js.map +1 -0
  68. package/dist/thread-mappings.d.ts +46 -0
  69. package/dist/thread-mappings.d.ts.map +1 -0
  70. package/dist/thread-mappings.js +62 -0
  71. package/dist/thread-mappings.js.map +1 -0
  72. package/dist/types.d.ts +54 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/dist/types.js +7 -0
  75. package/dist/types.js.map +1 -0
  76. package/npm-shrinkwrap.json +979 -0
  77. package/package.json +58 -4
  78. package/plugin.yaml +118 -0
@@ -0,0 +1,580 @@
1
+ import * as lark from '@larksuiteoapi/node-sdk';
2
+ import { FeishuAdapter, } from './FeishuAdapter.js';
3
+ import { FeishuTokenManager } from './FeishuTokenManager.js';
4
+ const WS_START_TIMEOUT_MS = 30_000;
5
+ const WS_CONNECT_POLL_MS = 250;
6
+ /** WebSocket.OPEN — the lark SDK's own liveness truth (es/index.js isOpen). */
7
+ const WS_READY_STATE_OPEN = 1;
8
+ function terminateWsInstance(ws) {
9
+ if (ws === null || ws === undefined || typeof ws !== 'object')
10
+ return;
11
+ const socket = ws;
12
+ socket.removeAllListeners?.();
13
+ socket.terminate?.();
14
+ }
15
+ /**
16
+ * F2/F3: the lark WSClient cannot cancel a connection that is still
17
+ * handshaking — `close()` only touches the socket registered after 'open',
18
+ * so a stop() landing pre-open would leave an authenticated socket that
19
+ * starts pingLoop and self-reconnects forever (an orphan nobody can kill).
20
+ *
21
+ * This facade makes teardown deterministic:
22
+ * - `close()` terminates the current socket AND installs a birth guard that
23
+ * terminates any socket the SDK opens afterwards, plus a pingLoop no-op so
24
+ * a late 'open' cannot restart the ping timer.
25
+ * - `start()` does not settle until the SDK has registered an open socket
26
+ * (lark `WSClient.start()` resolves in the same tick it kicks off
27
+ * `reConnect(true)`, so without this the runtime would report `running`
28
+ * before anything is connected), or aborts on stop/timeout/SDK give-up.
29
+ * - after `start()` settles, the open socket's 'close' event drives the
30
+ * optional `onClose` hook (suppressed when `close()` initiated it), so the
31
+ * runtime can drop out of 'running' and schedule a reconnect instead of
32
+ * reporting a dead connection as live.
33
+ *
34
+ * `autoReconnect: false` is deliberate: SDK-owned reconnection was the F2
35
+ * revival mechanism. Reconnect supervision belongs to the Host lifecycle.
36
+ */
37
+ export class PausableLarkWsClient {
38
+ inner;
39
+ hooks;
40
+ stopped = false;
41
+ constructor(appId, appSecret, inner, hooks = {}) {
42
+ this.inner = inner ?? new lark.WSClient({
43
+ appId,
44
+ appSecret,
45
+ loggerLevel: lark.LoggerLevel.info,
46
+ autoReconnect: false,
47
+ });
48
+ this.hooks = hooks;
49
+ }
50
+ async start(options) {
51
+ await this.inner.start(options);
52
+ const deadline = Date.now() + WS_START_TIMEOUT_MS;
53
+ for (;;) {
54
+ if (this.stopped)
55
+ throw new Error('Feishu WSClient stopped during connect');
56
+ const socket = this.inner.wsConfig.getWSInstance();
57
+ if (socket !== null) {
58
+ // H1: registration is not liveness. The lark SDK's own isOpen checks
59
+ // use readyState === OPEN (es/index.js ~85475); with autoReconnect off
60
+ // a closed socket stays registered (the close handler returns before
61
+ // setWSInstance(null)), so a bare `!== null` accepts a corpse and
62
+ // reports 'running' over a dead socket with no recovery. Refusing here
63
+ // routes the failure into the runtime's supervised reconnect instead.
64
+ if (socket.readyState === WS_READY_STATE_OPEN) {
65
+ this.watchSocketClose(socket);
66
+ return;
67
+ }
68
+ throw new Error(`Feishu WSClient registered a socket that is not OPEN (readyState=${String(socket.readyState)}); refusing to treat a dead socket as connected`);
69
+ }
70
+ // Fail fast when the SDK has already given up: with autoReconnect off a
71
+ // failed handshake logs 'connect failed' and returns in about a second,
72
+ // clearing isConnecting long before the 30s deadline. Without this the
73
+ // start loop would spin the full timeout on every bad-credential boot.
74
+ if (this.inner.isConnecting === false) {
75
+ throw new Error('Feishu WSClient aborted the connection attempt before a socket opened');
76
+ }
77
+ if (Date.now() >= deadline) {
78
+ throw new Error(`Feishu WSClient start timed out after ${WS_START_TIMEOUT_MS}ms`);
79
+ }
80
+ await new Promise((resolve) => setTimeout(resolve, WS_CONNECT_POLL_MS));
81
+ }
82
+ }
83
+ watchSocketClose(socket) {
84
+ // The socket was readyState === OPEN when accepted in start()'s poll loop
85
+ // (same tick, no I/O in between), so only the asynchronous 'close' path
86
+ // matters here; a synchronous CLOSING/CLOSED check at attach time can no
87
+ // longer trigger and would fire while the runtime is still 'starting',
88
+ // where the hook's signal gets dropped (H1).
89
+ const emitter = socket;
90
+ if (typeof emitter !== 'object' || emitter === null || typeof emitter.on !== 'function')
91
+ return;
92
+ emitter.on('close', () => {
93
+ if (this.stopped)
94
+ return; // close() terminates the socket itself
95
+ this.hooks.onClose?.();
96
+ });
97
+ }
98
+ close() {
99
+ if (this.stopped)
100
+ return;
101
+ this.stopped = true;
102
+ const wsConfig = this.inner.wsConfig;
103
+ const originalSet = wsConfig.setWSInstance.bind(wsConfig);
104
+ wsConfig.setWSInstance = (ws) => {
105
+ if (ws === null || ws === undefined) {
106
+ originalSet(ws);
107
+ return;
108
+ }
109
+ // Socket born after stop: kill before the SDK registers/uses it.
110
+ terminateWsInstance(ws);
111
+ };
112
+ // A late 'open' would otherwise start the ping timer again.
113
+ this.inner.pingLoop = () => undefined;
114
+ terminateWsInstance(wsConfig.getWSInstance());
115
+ this.inner.close({ force: true });
116
+ }
117
+ }
118
+ function trimValue(value) {
119
+ return value.trim();
120
+ }
121
+ function hasCredentials(config) {
122
+ return config.appId.length > 0 && config.appSecret.length > 0;
123
+ }
124
+ function parseMentions(value) {
125
+ if (value === undefined || value.trim() === '')
126
+ return undefined;
127
+ let candidate;
128
+ try {
129
+ candidate = JSON.parse(value);
130
+ }
131
+ catch {
132
+ throw new TypeError('groupBotMentionsJson must be valid JSON');
133
+ }
134
+ if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)) {
135
+ throw new TypeError('groupBotMentionsJson must be an object');
136
+ }
137
+ const result = {};
138
+ for (const [rawAlias, rawTarget] of Object.entries(candidate)) {
139
+ const alias = rawAlias.trim();
140
+ if (alias.length === 0 || rawTarget === null || typeof rawTarget !== 'object' || Array.isArray(rawTarget)) {
141
+ throw new TypeError('groupBotMentionsJson entries must contain an alias and target object');
142
+ }
143
+ const target = rawTarget;
144
+ if (typeof target.openId !== 'string' || target.openId.trim() === '') {
145
+ throw new TypeError(`groupBotMentionsJson.${alias}.openId must be non-empty`);
146
+ }
147
+ result[alias] = {
148
+ openId: target.openId.trim(),
149
+ ...(typeof target.displayName === 'string' && target.displayName.trim() !== ''
150
+ ? { displayName: target.displayName.trim() } : {}),
151
+ };
152
+ }
153
+ return result;
154
+ }
155
+ export function requireFeishuWebhookInput(candidate) {
156
+ if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)) {
157
+ throw new TypeError('feishu webhook input must be an object');
158
+ }
159
+ return { body: candidate.body };
160
+ }
161
+ async function providerMessage(adapter, message) {
162
+ let senderName = message.senderName;
163
+ let chatName = message.chatName;
164
+ if (message.chatType === 'group') {
165
+ senderName ??= await adapter.resolveSenderName(message.senderId).catch(() => undefined);
166
+ senderName ??= await adapter.resolveSenderNameFromChat(message.senderId, message.chatId).catch(() => undefined);
167
+ chatName ??= await adapter.resolveChatName(message.chatId).catch(() => undefined);
168
+ }
169
+ const attachments = message.attachments?.map(attachment => ({
170
+ type: attachment.type,
171
+ platformKey: attachment.feishuKey,
172
+ ...(attachment.fileName === undefined ? {} : { fileName: attachment.fileName }),
173
+ ...(attachment.duration === undefined ? {} : { duration: attachment.duration }),
174
+ }));
175
+ const sender = message.chatType === 'group' && message.senderId !== 'unknown'
176
+ ? { id: message.senderId, ...(senderName === undefined ? {} : { name: senderName }) }
177
+ : undefined;
178
+ return {
179
+ externalConversationId: message.chatId,
180
+ providerMessageId: message.messageId,
181
+ ...(message.senderId === 'unknown' || message.senderId.trim() === '' ? {} : { externalSenderId: message.senderId }),
182
+ text: message.text,
183
+ ...(attachments === undefined ? {} : { attachments }),
184
+ ...(sender === undefined ? {} : { sender }),
185
+ conversation: {
186
+ type: message.chatType === 'group' ? 'group' : 'direct',
187
+ ...(chatName === undefined ? {} : { title: chatName }),
188
+ },
189
+ };
190
+ }
191
+ async function cardMessage(adapter, action) {
192
+ const value = action.actionValue;
193
+ const command = typeof value.cmd === 'string' && value.cmd.startsWith('/')
194
+ ? `${value.cmd}${typeof value.args === 'string' && value.args ? ` ${value.args}` : ''}`
195
+ : action.option?.startsWith('/') ? action.option : undefined;
196
+ const chatType = action.chatType ?? await adapter.resolveChatType(action.chatId);
197
+ if (chatType === undefined)
198
+ return null;
199
+ return {
200
+ externalConversationId: action.chatId,
201
+ providerMessageId: action.eventId,
202
+ ...(action.senderId === 'unknown' || action.senderId.trim() === '' ? {} : { externalSenderId: action.senderId }),
203
+ text: command ?? JSON.stringify(action.actionValue),
204
+ ...(command === undefined || action.senderId === '' ? {} : { sender: { id: action.senderId } }),
205
+ conversation: { type: chatType === 'group' ? 'group' : 'direct' },
206
+ };
207
+ }
208
+ export function createFeishuConnectorRuntime(options) {
209
+ // Credentials may arrive only later via the feishu_qr_login operation — empty
210
+ // values mean the runtime starts healthy and idle (no ingress) until connect().
211
+ let current = {
212
+ appId: trimValue(options.config.appId),
213
+ appSecret: trimValue(options.config.appSecret),
214
+ connectionMode: options.config.connectionMode,
215
+ ...(options.config.verificationToken === undefined ? {} : { verificationToken: options.config.verificationToken }),
216
+ ...(options.config.groupBotMentionsJson === undefined ? {} : { groupBotMentionsJson: options.config.groupBotMentionsJson }),
217
+ };
218
+ const createAdapter = options.createAdapter ?? ((id, secret, logger, value) => new FeishuAdapter(id, secret, logger, value));
219
+ const buildAdapterOptions = () => {
220
+ const groupBotMentions = parseMentions(current.groupBotMentionsJson);
221
+ return {
222
+ ...(current.verificationToken === undefined ? {} : { verificationToken: current.verificationToken }),
223
+ ...(groupBotMentions === undefined ? {} : { groupBotMentions }),
224
+ };
225
+ };
226
+ let outbound = hasCredentials(current)
227
+ ? createAdapter(current.appId, current.appSecret, options.logger, buildAdapterOptions())
228
+ : undefined;
229
+ let tokenManager;
230
+ const buildTokenManager = () => (new FeishuTokenManager({ appId: current.appId, appSecret: current.appSecret, ...(options.fetchFn === undefined ? {} : { fetchFn: options.fetchFn }) }));
231
+ if (outbound !== undefined) {
232
+ tokenManager = buildTokenManager();
233
+ outbound._injectTokenManager?.(tokenManager);
234
+ }
235
+ const requireOutbound = () => {
236
+ if (outbound === undefined) {
237
+ throw new Error('Feishu connector is not configured — complete QR authorization (feishu_qr_login) first');
238
+ }
239
+ return outbound;
240
+ };
241
+ let state = 'idle';
242
+ let ingressEpoch = 0;
243
+ const isCurrent = (epoch) => epoch === ingressEpoch && state !== 'stopped';
244
+ let armed = false;
245
+ let startPromise;
246
+ let stopPromise;
247
+ let wsClient;
248
+ let identityAbort;
249
+ const identityTasks = new Set();
250
+ let reconnectTimer;
251
+ const reconnectBaseDelayMs = options.reconnectDelayMs ?? 5_000;
252
+ const reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? 60_000;
253
+ // Backoff, not a fixed interval: each consecutive failed supervise attempt
254
+ // doubles the delay (capped), so a persistently dead endpoint is retried
255
+ // ~70x/hour instead of ~700x, and each retry no longer hammers a fresh
256
+ // tenant_access_token at a constant cadence. Reset on every transition into
257
+ // 'running'.
258
+ let reconnectAttempts = 0;
259
+ const nextBackoffMs = () => {
260
+ const exponential = Math.min(reconnectBaseDelayMs * 2 ** reconnectAttempts, reconnectMaxDelayMs);
261
+ reconnectAttempts += 1;
262
+ // ±20% jitter keeps simultaneous connectors from lock-stepping the Host.
263
+ return Math.round(exponential * (0.8 + Math.random() * 0.4));
264
+ };
265
+ // Both return the real delivery outcome so callers can derive their
266
+ // reported state from it instead of asserting success independently (G3):
267
+ // a message dropped by the state recheck must never be reported 'processed'.
268
+ const routeEvent = async (message, webhookEventId) => {
269
+ if (state !== 'running')
270
+ return false;
271
+ const hostMessage = await providerMessage(requireOutbound(), message);
272
+ // Group chats await name-resolution round-trips above; stop() landing in
273
+ // that window must not still deliver (TOCTOU recheck after the await).
274
+ if (state !== 'running')
275
+ return false;
276
+ // The webhook transport has a provider delivery ID distinct from the IM
277
+ // message ID. Replays of that delivery must carry the same Host source key.
278
+ await options.host.deliver(webhookEventId === undefined
279
+ ? hostMessage : { ...hostMessage, providerMessageId: webhookEventId });
280
+ return true;
281
+ };
282
+ const routeCard = async (action) => {
283
+ if (state !== 'running')
284
+ return 'not_running';
285
+ const message = await cardMessage(requireOutbound(), action);
286
+ if (message === null)
287
+ return 'chat_type_unknown';
288
+ if (state !== 'running')
289
+ return 'not_running';
290
+ await options.host.deliver(message);
291
+ return 'delivered';
292
+ };
293
+ const startIngress = async () => {
294
+ const adapter = requireOutbound();
295
+ const manager = tokenManager ?? buildTokenManager();
296
+ tokenManager = manager;
297
+ // Identity discovery is optional, but its I/O still belongs to this
298
+ // ingress generation. Retiring it must not access a revoked Host logger
299
+ // or publish an old identity into an adapter after disconnect/reconfigure.
300
+ identityAbort?.abort();
301
+ const cancellation = new AbortController();
302
+ identityAbort = cancellation;
303
+ const signal = AbortSignal.any([cancellation.signal, AbortSignal.timeout(30_000)]);
304
+ const identityTask = manager.getTenantAccessToken(signal).then(async (token) => {
305
+ signal.throwIfAborted();
306
+ const response = await (options.fetchFn ?? globalThis.fetch)('https://open.feishu.cn/open-apis/bot/v3/info', {
307
+ headers: { Authorization: `Bearer ${token}` },
308
+ signal,
309
+ });
310
+ signal.throwIfAborted();
311
+ if (!response.ok)
312
+ return;
313
+ const data = await response.json();
314
+ signal.throwIfAborted();
315
+ if (data.bot?.open_id)
316
+ adapter.setBotOpenId(data.bot.open_id);
317
+ }).catch(error => {
318
+ if (!cancellation.signal.aborted) {
319
+ options.logger.warn({ error }, '[FeishuRuntime] Bot identity resolution failed');
320
+ }
321
+ }).finally(() => { identityTasks.delete(identityTask); });
322
+ identityTasks.add(identityTask);
323
+ if (current.connectionMode !== 'websocket')
324
+ return;
325
+ const dispatcher = new lark.EventDispatcher({}).register({
326
+ 'im.message.receive_v1': async (data) => {
327
+ const parsed = adapter.parseEvent({ header: { event_type: 'im.message.receive_v1' }, event: data });
328
+ if (parsed !== null)
329
+ await routeEvent(parsed);
330
+ },
331
+ 'card.action.trigger': async (data) => {
332
+ const parsed = adapter.parseCardAction({
333
+ header: { event_type: 'card.action.trigger', event_id: data.event_id }, event: data,
334
+ });
335
+ if (parsed !== null)
336
+ await routeCard(parsed);
337
+ },
338
+ });
339
+ const createWs = options.createWsClient ?? ((value) => (new PausableLarkWsClient(value.appId, value.appSecret, undefined, { onClose: value.onClose })));
340
+ const client = createWs({ appId: current.appId, appSecret: current.appSecret, onClose: () => handleUnexpectedClose(client) });
341
+ wsClient = client;
342
+ // PausableLarkWsClient.start() settles only once the socket is really
343
+ // open (or stop/timeout/SDK give-up aborts it), so no outer timer needed.
344
+ // On rejection the client must be torn down here: an un-closed client
345
+ // keeps its registered socket, ping loop and close hook alive — the F2
346
+ // orphan the facade exists to prevent, now on the routine failure path
347
+ // (H1 made start() throw for dead sockets instead of accepting them).
348
+ try {
349
+ await client.start({ eventDispatcher: dispatcher });
350
+ }
351
+ catch (error) {
352
+ client.close({ force: true });
353
+ if (wsClient === client)
354
+ wsClient = undefined;
355
+ throw error;
356
+ }
357
+ };
358
+ // G1: the only trustworthy signal of a dead ingress is the socket's own
359
+ // 'close' event (the lark SDK leaves a dead socket registered when
360
+ // autoReconnect is off, so polling its registry would report 'alive').
361
+ // B3: the callback carries its originating client and only the CURRENT
362
+ // client may tear the connection down — a leaked/orphaned client's late
363
+ // close must not kill a healthy successor.
364
+ const handleUnexpectedClose = (caller) => {
365
+ if (wsClient !== caller)
366
+ return; // orphan close: not our connection
367
+ // PausableLarkWsClient suppresses the callback for stop-initiated closes
368
+ // via its stopped guard, so reaching here means an unexpected drop.
369
+ if (state !== 'running')
370
+ return;
371
+ identityAbort?.abort();
372
+ const dead = wsClient;
373
+ wsClient = undefined;
374
+ state = 'idle'; // no live inbound during reconnect; webhooks derive skipped
375
+ startPromise = undefined;
376
+ dead?.close({ force: true });
377
+ scheduleReconnect('ingress socket closed unexpectedly');
378
+ };
379
+ const scheduleReconnect = (reason) => {
380
+ if (state === 'stopped' || reconnectTimer !== undefined)
381
+ return;
382
+ const delayMs = nextBackoffMs();
383
+ options.logger.error(`[FeishuRuntime] ${reason}; reconnecting in ${delayMs}ms`);
384
+ reconnectTimer = setTimeout(() => {
385
+ reconnectTimer = undefined;
386
+ if (state !== 'idle')
387
+ return; // stop() or a fresh start() superseded it
388
+ state = 'starting';
389
+ const epoch = ingressEpoch;
390
+ startPromise = startIngress()
391
+ .then(() => {
392
+ if (isCurrent(epoch)) {
393
+ reconnectAttempts = 0;
394
+ state = 'running';
395
+ options.logger.info('[FeishuRuntime] Provider ingress started');
396
+ }
397
+ })
398
+ .catch((error) => {
399
+ // Timer-context rejection: never rethrow (unhandled rejection);
400
+ // log and reschedule the backoff instead.
401
+ if (!isCurrent(epoch))
402
+ return;
403
+ state = 'idle';
404
+ startPromise = undefined;
405
+ options.logger.error({ error }, '[FeishuRuntime] Reconnect attempt failed');
406
+ scheduleReconnect('reconnect attempt failed');
407
+ });
408
+ }, delayMs);
409
+ };
410
+ const stopIngress = () => {
411
+ ingressEpoch += 1;
412
+ identityAbort?.abort();
413
+ if (reconnectTimer !== undefined) {
414
+ clearTimeout(reconnectTimer);
415
+ reconnectTimer = undefined;
416
+ }
417
+ wsClient?.close({ force: true });
418
+ wsClient = undefined;
419
+ // Join even providers that settle cancellation asynchronously. The Host
420
+ // may revoke the context as soon as stop() resolves.
421
+ return Promise.all([...identityTasks]).then(() => undefined);
422
+ };
423
+ return {
424
+ get outbound() {
425
+ return requireOutbound();
426
+ },
427
+ start() {
428
+ if (state === 'stopped')
429
+ return Promise.reject(new Error('Feishu connector runtime has been stopped'));
430
+ if (startPromise !== undefined)
431
+ return startPromise;
432
+ armed = true;
433
+ if (outbound === undefined) {
434
+ // Armed but idle: no ingress until connect() supplies credentials.
435
+ startPromise = Promise.resolve();
436
+ return startPromise;
437
+ }
438
+ state = 'starting';
439
+ const epoch = ingressEpoch;
440
+ startPromise = startIngress()
441
+ .then(() => {
442
+ if (isCurrent(epoch)) {
443
+ reconnectAttempts = 0;
444
+ state = 'running';
445
+ options.logger.info('[FeishuRuntime] Provider ingress started');
446
+ }
447
+ })
448
+ .catch((error) => {
449
+ // stop() aborts the in-flight start on purpose — that is not a start
450
+ // failure and must not surface as an unhandled rejection.
451
+ if (!isCurrent(epoch))
452
+ return;
453
+ state = 'idle';
454
+ startPromise = undefined;
455
+ throw error;
456
+ });
457
+ return startPromise;
458
+ },
459
+ async connect(next) {
460
+ const appId = trimValue(next.appId);
461
+ const appSecret = trimValue(next.appSecret);
462
+ if (appId.length === 0 || appSecret.length === 0) {
463
+ throw new TypeError('appId and appSecret must be non-empty values');
464
+ }
465
+ if (state === 'stopped')
466
+ throw new Error('Feishu connector runtime has been stopped');
467
+ // Tear down the previous ingress before rebuilding: a live socket or a
468
+ // pending reconnect timer from the old credentials must not survive.
469
+ state = 'idle';
470
+ const draining = stopIngress();
471
+ const epoch = ingressEpoch;
472
+ await draining;
473
+ if (!isCurrent(epoch))
474
+ return;
475
+ current = { ...current, appId, appSecret, connectionMode: next.connectionMode };
476
+ outbound = createAdapter(appId, appSecret, options.logger, buildAdapterOptions());
477
+ tokenManager = buildTokenManager();
478
+ outbound._injectTokenManager?.(tokenManager);
479
+ state = 'idle';
480
+ startPromise = undefined;
481
+ if (!armed)
482
+ return;
483
+ state = 'starting';
484
+ startPromise = startIngress()
485
+ .then(() => {
486
+ if (isCurrent(epoch)) {
487
+ reconnectAttempts = 0;
488
+ state = 'running';
489
+ options.logger.info('[FeishuRuntime] Provider ingress started');
490
+ }
491
+ })
492
+ .catch((error) => {
493
+ if (!isCurrent(epoch))
494
+ return;
495
+ state = 'idle';
496
+ startPromise = undefined;
497
+ throw error;
498
+ });
499
+ return startPromise;
500
+ },
501
+ async disconnect() {
502
+ if (state === 'stopped')
503
+ return;
504
+ // Close the in-process ingress AND drop the configured adapter/token
505
+ // manager: the operation targetValues clear appId/appSecret, so any
506
+ // retained outbound would keep sending with credentials the owner just
507
+ // disconnected (the Host write-back does not restart the plugin).
508
+ state = 'idle';
509
+ const draining = stopIngress();
510
+ const epoch = ingressEpoch;
511
+ await draining;
512
+ if (!isCurrent(epoch))
513
+ return;
514
+ outbound = undefined;
515
+ tokenManager = undefined;
516
+ state = 'idle';
517
+ startPromise = undefined;
518
+ },
519
+ isConnected() {
520
+ return state === 'running';
521
+ },
522
+ status() {
523
+ const verificationToken = current.verificationToken;
524
+ return {
525
+ connectionMode: current.connectionMode,
526
+ hasVerificationToken: typeof verificationToken === 'string' && verificationToken.trim() !== '',
527
+ connected: state === 'running',
528
+ };
529
+ },
530
+ stop() {
531
+ if (stopPromise !== undefined)
532
+ return stopPromise;
533
+ armed = false;
534
+ state = 'stopped';
535
+ stopPromise = stopIngress();
536
+ return stopPromise;
537
+ },
538
+ async handleWebhook(candidate) {
539
+ if (state === 'stopped')
540
+ throw new Error('Feishu connector runtime has been stopped');
541
+ if (current.connectionMode === 'websocket')
542
+ return { kind: 'skipped', reason: 'websocket_mode' };
543
+ if (outbound === undefined)
544
+ return { kind: 'error', status: 503, message: 'feishu connector is not configured' };
545
+ const adapter = outbound;
546
+ const { body } = requireFeishuWebhookInput(candidate);
547
+ const challenge = adapter.isVerificationChallenge(body);
548
+ if (challenge !== null)
549
+ return { kind: 'challenge', response: challenge };
550
+ if (!adapter.verifyEventToken(body))
551
+ return { kind: 'error', status: 403, message: 'Invalid verification token' };
552
+ // Events arriving before start() completed (state idle/starting) are not
553
+ // delivered; report them honestly instead of dropping silently and
554
+ // claiming they were processed.
555
+ if (state !== 'running')
556
+ return { kind: 'skipped', reason: 'not_running' };
557
+ const action = adapter.parseCardAction(body);
558
+ if (action !== null) {
559
+ const routed = await routeCard(action);
560
+ if (routed === 'delivered')
561
+ return { kind: 'processed', messageId: 'card-action' };
562
+ // 'not_running' covers the guard killing the route mid-flight; only a
563
+ // completed route with an unresolvable chat type is chat_type_unknown.
564
+ return { kind: 'skipped', reason: routed === 'not_running' ? 'not_running' : 'chat_type_unknown' };
565
+ }
566
+ const parsed = adapter.parseEvent(body);
567
+ if (parsed === null)
568
+ return { kind: 'skipped', reason: 'unsupported_event' };
569
+ const header = body !== null && typeof body === 'object' && !Array.isArray(body)
570
+ ? body.header : undefined;
571
+ const eventId = header !== null && typeof header === 'object' && !Array.isArray(header)
572
+ ? header.event_id : undefined;
573
+ const stableEventId = typeof eventId === 'string' && eventId.length > 0 ? eventId : undefined;
574
+ return await routeEvent(parsed, stableEventId)
575
+ ? { kind: 'processed', messageId: stableEventId ?? parsed.messageId }
576
+ : { kind: 'skipped', reason: 'not_running' };
577
+ },
578
+ };
579
+ }
580
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { definePluginModule } from '@clowder-ai/plugin-sdk';
2
+ import type { ModulePluginHostShape } from '@clowder-ai/plugin-sdk';
3
+ import type { FeishuQrBindClient } from './FeishuQrBindClient.js';
4
+ export type SettingsHost = Pick<ModulePluginHostShape, 'config' | 'secrets' | 'storage' | 'log'>;
5
+ interface SettingsCall {
6
+ readonly signal?: AbortSignal;
7
+ assertCurrent(): void | Promise<void>;
8
+ }
9
+ export interface SettingsDefinition {
10
+ readonly actions: Readonly<Record<string, (params: unknown, action?: unknown, call?: SettingsCall) => Promise<unknown>>>;
11
+ dispose?(): void | Promise<void>;
12
+ }
13
+ export interface SettingsEntrypoint {
14
+ create(manifest: unknown): ReturnType<ReturnType<typeof definePluginModule>['create']> & {
15
+ settings(host: SettingsHost): SettingsDefinition;
16
+ };
17
+ }
18
+ export declare function createFeishuSettings(host: SettingsHost, client: FeishuQrBindClient): SettingsDefinition;
19
+ export {};
20
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC;AACjG,UAAU,YAAY;IAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,aAAa,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAAE;AAEhG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzH,OAAO,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AACD,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,kBAAkB,CAAA;KAAE,CAAC;CAC/I;AAID,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,kBAAkB,GAAG,kBAAkB,CA0BvG"}