@krischoichoi/channel-lark 0.6.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.
Files changed (62) hide show
  1. package/README.md +114 -0
  2. package/lib/adapter.d.ts +128 -0
  3. package/lib/adapter.d.ts.map +1 -0
  4. package/lib/adapter.js +347 -0
  5. package/lib/adapter.js.map +1 -0
  6. package/lib/auth/device-authorization.d.ts +12 -0
  7. package/lib/auth/device-authorization.d.ts.map +1 -0
  8. package/lib/auth/device-authorization.js +169 -0
  9. package/lib/auth/device-authorization.js.map +1 -0
  10. package/lib/card.d.ts +124 -0
  11. package/lib/card.d.ts.map +1 -0
  12. package/lib/card.js +347 -0
  13. package/lib/card.js.map +1 -0
  14. package/lib/config.d.ts +103 -0
  15. package/lib/config.d.ts.map +1 -0
  16. package/lib/config.js +60 -0
  17. package/lib/config.js.map +1 -0
  18. package/lib/definition.d.ts +74 -0
  19. package/lib/definition.d.ts.map +1 -0
  20. package/lib/definition.js +190 -0
  21. package/lib/definition.js.map +1 -0
  22. package/lib/inbound.d.ts +41 -0
  23. package/lib/inbound.d.ts.map +1 -0
  24. package/lib/inbound.js +102 -0
  25. package/lib/inbound.js.map +1 -0
  26. package/lib/index.d.ts +58 -0
  27. package/lib/index.d.ts.map +1 -0
  28. package/lib/index.js +104 -0
  29. package/lib/index.js.map +1 -0
  30. package/lib/lark-sdk-upstream.d.ts +128 -0
  31. package/lib/lark-sdk-upstream.d.ts.map +1 -0
  32. package/lib/lark-sdk-upstream.js +339 -0
  33. package/lib/lark-sdk-upstream.js.map +1 -0
  34. package/lib/manifest.d.ts +23 -0
  35. package/lib/manifest.d.ts.map +1 -0
  36. package/lib/manifest.js +36 -0
  37. package/lib/manifest.js.map +1 -0
  38. package/lib/mapper.d.ts +47 -0
  39. package/lib/mapper.d.ts.map +1 -0
  40. package/lib/mapper.js +223 -0
  41. package/lib/mapper.js.map +1 -0
  42. package/lib/media-hydrator.d.ts +55 -0
  43. package/lib/media-hydrator.d.ts.map +1 -0
  44. package/lib/media-hydrator.js +172 -0
  45. package/lib/media-hydrator.js.map +1 -0
  46. package/lib/openapi-outbound.d.ts +216 -0
  47. package/lib/openapi-outbound.d.ts.map +1 -0
  48. package/lib/openapi-outbound.js +384 -0
  49. package/lib/openapi-outbound.js.map +1 -0
  50. package/lib/outbound.d.ts +21 -0
  51. package/lib/outbound.d.ts.map +1 -0
  52. package/lib/outbound.js +93 -0
  53. package/lib/outbound.js.map +1 -0
  54. package/lib/upstream/media-port.d.ts +154 -0
  55. package/lib/upstream/media-port.d.ts.map +1 -0
  56. package/lib/upstream/media-port.js +168 -0
  57. package/lib/upstream/media-port.js.map +1 -0
  58. package/lib/upstream.d.ts +119 -0
  59. package/lib/upstream.d.ts.map +1 -0
  60. package/lib/upstream.js +2 -0
  61. package/lib/upstream.js.map +1 -0
  62. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # @krischoichoi/channel-lark
2
+
3
+ Lark / Feishu / 飞书 channel adapter for DeepSeek Harness.
4
+
5
+ Maps Lark to the stable Channel Contract through the official
6
+ `@larksuiteoapi/node-sdk` **only**:
7
+
8
+ - **Inbound** — `WSClient` + `EventDispatcher` (WebSocket long-connection):
9
+ `im.message.receive_v1` and `card.action.trigger`.
10
+ - **Outbound** — the official OpenAPI client: `im.v1.message.create` / `patch`,
11
+ image/file uploads, and CardKit 2.0 card entities with **native streaming**
12
+ (`cardkit.v1.card.create` → `cardElement.content` → `card.settings`).
13
+
14
+ There is no self-hosted gateway and no legacy transport. Interactive cards
15
+ use **Card JSON 2.0** only (buttons are direct `body.elements` with
16
+ `behaviors[].value`; no `tag: "action"` container and no `lark_md`).
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pnpm add @krischoichoi/channel-lark
22
+ ```
23
+
24
+ Or install the whole bundle:
25
+
26
+ ```bash
27
+ npx @deepseek-ai/dsh plugin --profile web add -w @krischoichoi/dsh-channels@latest
28
+ ```
29
+
30
+ ## Configuration
31
+
32
+ ```yaml
33
+ - id: channels-lark
34
+ name: '@krischoichoi/channel-lark'
35
+ inject: [channels, credentials, channelControl]
36
+ config:
37
+ enabled: true
38
+ accountId: main
39
+ upstream:
40
+ mode: sdk # fixed — the official SDK is the only upstream driver
41
+ appId: "cli_xxx" # AppId(非机密)
42
+ domain: feishu # feishu(国内)| lark(海外)
43
+ # appSecretRef 默认 DSH_CHANNEL_LARK_MAIN_APP_SECRET
44
+ # 真实 AppSecret 只存 ctx.credentials
45
+ card:
46
+ createOnFirstDelta: true
47
+ typingIndicator: true
48
+ ```
49
+
50
+ The AppSecret is resolved through `ctx.credentials` at startup and injected as
51
+ `deps.appSecret`; it is never written to profile config.
52
+
53
+ > **Config governance**: only `upstream.mode: sdk` and the credential reference
54
+ > `upstream.appSecretRef` are supported. Plaintext `upstream.appSecret` and the
55
+ > former gateway settings are not part of the configuration contract.
56
+
57
+ ## Streaming
58
+
59
+ Lark uses `edit` streaming over **CardKit 2.0 native streaming** (the official
60
+ "打字机" typewriter flow — never `im.v1.message.patch` pseudo-streaming):
61
+
62
+ 1. `cardkit.v1.card.create` creates a Card JSON 2.0 entity with
63
+ `streaming_mode: true` and a stable `element_id`;
64
+ 2. `im.v1.message.create` sends the card reference
65
+ (`{ type: "card", data: { card_id } }`);
66
+ 3. every streamed delta replaces the markdown element's full content via
67
+ `cardkit.v1.cardElement.content` with a monotonically increasing `sequence`
68
+ and a stable `uuid`;
69
+ 4. `finish()` / `fail()` close the stream by setting `streaming_mode: false`
70
+ (and the final summary) through `cardkit.v1.card.settings`.
71
+
72
+ When a single markdown element approaches the platform's ~30,000-char cap the
73
+ handle rolls over into a fresh card (`chunkIds` records every sent card).
74
+
75
+ ## Capabilities
76
+
77
+ | Capability | Value |
78
+ | --- | --- |
79
+ | text / image / file / audio | ✅ |
80
+ | markdown / cards / reactions / threads | ✅ |
81
+ | interactive buttons | ✅ (`card.action.trigger`, Card JSON 2.0) |
82
+ | video | ❌ |
83
+ | streaming | `edit` (CardKit 2.0 native streaming) |
84
+
85
+ ## Upstream
86
+
87
+ | Field | Value |
88
+ | --- | --- |
89
+ | SDK | `@larksuiteoapi/node-sdk` |
90
+ | Tested version | `1.73.1` |
91
+ | Status | `tested` (**offline-tested**: contract + fixture + SDK-mode suites) |
92
+
93
+ > Live gate status: **LIVE-REQUIRED**. `status: tested` reflects the offline
94
+ > Channel Contract + fixture + official-SDK offline suites only. Real-app
95
+ > permission / event subscription / message & card send behavior must still be
96
+ > verified live (see §8 of the alignment plan) before the adapter may be
97
+ > claimed live-tested.
98
+
99
+ ## Development
100
+
101
+ ```bash
102
+ pnpm --filter @krischoichoi/channel-lark build
103
+ pnpm --filter @krischoichoi/channel-lark typecheck
104
+ pnpm --filter @krischoichoi/channel-lark test
105
+ ```
106
+
107
+ ## Related
108
+
109
+ - [Repository root](../../README.md)
110
+ - [Adapter authoring guide](../../docs/adapter-authoring.md)
111
+
112
+ ## License
113
+
114
+ [MIT](../../LICENSE)
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Lark channel adapter.
3
+ *
4
+ * Maps the Lark/Feishu platform (through the OFFICIAL `@larksuiteoapi/node-sdk`
5
+ * driver stack) to the Channel Contract. All network/lifecycle resources live
6
+ * behind the upstream driver and are aborted via the adapter context signal.
7
+ * The adapter never touches Harness Agent APIs.
8
+ *
9
+ * The upstream is ALWAYS the official SDK:
10
+ * - inbound → `LarkSdkUpstream`: WSClient + EventDispatcher
11
+ * (`im.message.receive_v1` + `card.action.trigger`), outbound delegated to
12
+ * the official OpenAPI client (`LarkOpenApiOutbound`). The WS client comes
13
+ * from `deps.sdkClient` / `deps.sdkClientFactory`, the OpenAPI client from
14
+ * `deps.openApiClient` / `deps.openApiClientFactory`, each defaulting to a
15
+ * real client built from the RESOLVED `deps.appId` / `deps.appSecret`,
16
+ * resolved via ctx.credentials (the adapter never reads secrets from config).
17
+ * Missing credentials fail start loudly, not construction.
18
+ *
19
+ * There is no transport injection and no gateway: offline tests inject fake
20
+ * WS + OpenAPI clients instead.
21
+ *
22
+ * Auth is connection-state driven: the upstream driver owns the platform
23
+ * credentials, so the adapter derives its auth state from the connection
24
+ * (connected → authenticated).
25
+ */
26
+ import type { ChannelAdapter, ChannelAdapterContext, ChannelCapabilities, ChannelHealth, ChannelTarget, CreateReplyOptions, OutboundMessage, ReplyHandle, SendResult } from '@krischoichoi/channel-core';
27
+ import { Domain } from '@larksuiteoapi/node-sdk';
28
+ import type { LarkConfig } from './config.js';
29
+ import { type LarkSdkClient } from './lark-sdk-upstream.js';
30
+ import { type LarkOpenApiClient } from './openapi-outbound.js';
31
+ import { type LarkMediaPort } from './upstream/media-port.js';
32
+ import { type LarkManifest } from './manifest.js';
33
+ export interface LarkAdapterDeps {
34
+ /**
35
+ * Resolved Lark AppId (a plain config string resolved by the plugin and
36
+ * handed in for the default client builders; never a secret).
37
+ */
38
+ appId?: string;
39
+ /**
40
+ * Resolved Lark AppSecret (resolved via `ctx.credentials` by the plugin;
41
+ * never present in profile config / logs).
42
+ */
43
+ appSecret?: string;
44
+ /**
45
+ * Pre-built WS long-connection client (offline tests). Overrides
46
+ * `sdkClientFactory`; when neither is given a real `WSClient` is built from
47
+ * `appId`/`appSecret` at start time.
48
+ */
49
+ sdkClient?: LarkSdkClient;
50
+ /** Lazy WS client factory; overrides the default WSClient. */
51
+ sdkClientFactory?: (config: LarkConfig) => LarkSdkClient;
52
+ /**
53
+ * Pre-built official OpenAPI client (offline tests). Overrides
54
+ * `openApiClientFactory`; when neither is given a real `Client` is built
55
+ * from `appId`/`appSecret` at start time.
56
+ */
57
+ openApiClient?: LarkOpenApiClient;
58
+ /** Lazy OpenAPI client factory. */
59
+ openApiClientFactory?: (config: LarkConfig) => LarkOpenApiClient;
60
+ /**
61
+ * Injectable media port for inbound media hydration. When absent, the
62
+ * adapter builds a default LarkOpenApiMediaPort from the same resolved
63
+ * OpenAPI client used for outbound.
64
+ */
65
+ mediaPort?: LarkMediaPort;
66
+ /** Injectable clock (tests). */
67
+ now?: () => number;
68
+ }
69
+ export declare class LarkAdapter implements ChannelAdapter {
70
+ private readonly config;
71
+ readonly id = "lark";
72
+ /** Upstream compatibility manifest (read structurally by `channels doctor`). */
73
+ readonly manifest: LarkManifest;
74
+ readonly capabilities: ChannelCapabilities;
75
+ private ctx?;
76
+ /** Built in `start()` (driver selection needs the resolved deps/credentials). */
77
+ private upstream;
78
+ private readonly deps;
79
+ private inbound;
80
+ private outbound;
81
+ /** Media port used for inbound media hydration (built in start). */
82
+ private mediaPort?;
83
+ private started;
84
+ private stopped;
85
+ private receiveLoop?;
86
+ private connected;
87
+ /** Connection-state-driven auth; the upstream driver owns credentials. */
88
+ private authState;
89
+ private readonly now;
90
+ /** Internal stop signal merged with the context signal for prompt teardown. */
91
+ private stopController?;
92
+ private receiveSignal?;
93
+ constructor(config: LarkConfig, deps?: LarkAdapterDeps);
94
+ start(ctx: ChannelAdapterContext): Promise<void>;
95
+ stop(): Promise<void>;
96
+ send(target: ChannelTarget, message: OutboundMessage): Promise<SendResult>;
97
+ edit(target: ChannelTarget, messageId: string, message: OutboundMessage): Promise<SendResult>;
98
+ startTypingForTarget(target: ChannelTarget): Promise<void>;
99
+ stopTypingForTarget(target: ChannelTarget): Promise<void>;
100
+ createReply(target: ChannelTarget, _options?: CreateReplyOptions): Promise<ReplyHandle>;
101
+ getHealth(): Promise<ChannelHealth>;
102
+ /** WS long-connection receive loop with exponential backoff on failure. */
103
+ startReceiveLoop(): void;
104
+ /** Build the official-SDK upstream driver. */
105
+ private buildUpstream;
106
+ /** Select the official OpenAPI outbound driver. */
107
+ private resolveOpenApiOutbound;
108
+ /**
109
+ * Select the media port for inbound media hydration. An explicit dep wins;
110
+ * otherwise the adapter builds a default `LarkOpenApiMediaPort` from the
111
+ * same resolved OpenAPI client used for outbound.
112
+ */
113
+ private resolveMediaPort;
114
+ private resolveSdkClient;
115
+ private runReceiveLoop;
116
+ /** Flip connection/auth state once the upstream proves reachable. */
117
+ private markConnected;
118
+ private aborted;
119
+ private setAuth;
120
+ private emitAuth;
121
+ private emitConnection;
122
+ }
123
+ /**
124
+ * Resolve a config domain string to the SDK's `Domain` enum, preserving a
125
+ * custom base domain verbatim (the SDK accepts `Domain | string`).
126
+ */
127
+ export declare function resolveDomain(value: string): Domain | string;
128
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
package/lib/adapter.js ADDED
@@ -0,0 +1,347 @@
1
+ import { ChannelError } from '@krischoichoi/channel-core';
2
+ import { Client, Domain, WSClient } from '@larksuiteoapi/node-sdk';
3
+ import { LarkSdkUpstream, } from './lark-sdk-upstream.js';
4
+ import { LarkOpenApiOutbound } from './openapi-outbound.js';
5
+ import { LarkOpenApiMediaPort } from './upstream/media-port.js';
6
+ import { InboundProcessor } from './inbound.js';
7
+ import { OutboundSender } from './outbound.js';
8
+ import { LarkCardReply } from './card.js';
9
+ import { manifest as larkManifest } from './manifest.js';
10
+ export class LarkAdapter {
11
+ config;
12
+ id = 'lark';
13
+ /** Upstream compatibility manifest (read structurally by `channels doctor`). */
14
+ manifest = larkManifest;
15
+ capabilities = {
16
+ text: true,
17
+ image: true,
18
+ file: true,
19
+ audio: true,
20
+ video: false,
21
+ markdown: true,
22
+ cards: true,
23
+ interactiveActions: true,
24
+ reactions: true,
25
+ threads: true,
26
+ streaming: 'edit',
27
+ // Directional media precision. Inbound: image/file/audio/video are all
28
+ // hydrated to real bytes before emit — the official `message.resource`
29
+ // API documents audio/video downloads, so every binary kind the mapper
30
+ // produces routes its file_key through `messageResource.get` into
31
+ // localData. Outbound: image (`sendMedia` → im.image.create) and file
32
+ // (`sendFile` → im.file.create) upload real bytes; there is no audio/video
33
+ // send path — audio/video outbound parts fall back to `[audio]`/`[video]`
34
+ // text placeholders, so outbound audio/video are 'unsupported'.
35
+ media: {
36
+ inbound: {
37
+ image: 'bytes',
38
+ file: 'bytes',
39
+ audio: 'bytes',
40
+ video: 'bytes',
41
+ },
42
+ outbound: {
43
+ image: 'bytes',
44
+ file: 'bytes',
45
+ audio: 'unsupported',
46
+ video: 'unsupported',
47
+ },
48
+ },
49
+ };
50
+ ctx;
51
+ /** Built in `start()` (driver selection needs the resolved deps/credentials). */
52
+ upstream;
53
+ deps;
54
+ inbound;
55
+ outbound;
56
+ /** Media port used for inbound media hydration (built in start). */
57
+ mediaPort;
58
+ started = false;
59
+ stopped = false;
60
+ receiveLoop;
61
+ connected = false;
62
+ /** Connection-state-driven auth; the upstream driver owns credentials. */
63
+ authState = 'unknown';
64
+ now;
65
+ /** Internal stop signal merged with the context signal for prompt teardown. */
66
+ stopController;
67
+ receiveSignal;
68
+ constructor(config, deps = {}) {
69
+ this.config = config;
70
+ this.now = deps.now ?? Date.now;
71
+ this.deps = deps;
72
+ }
73
+ async start(ctx) {
74
+ if (this.started)
75
+ return;
76
+ this.ctx = ctx;
77
+ this.stopped = false;
78
+ this.buildUpstream();
79
+ this.stopController = new AbortController();
80
+ this.receiveSignal = AbortSignal.any([ctx.signal, this.stopController.signal]);
81
+ this.mediaPort = this.resolveMediaPort();
82
+ this.inbound = new InboundProcessor({
83
+ ctx,
84
+ meta: { channel: this.id, accountId: this.config.accountId },
85
+ dedupEnabled: this.config.dedup.enabled,
86
+ dedupWindowMs: this.config.dedup.windowMs,
87
+ now: this.now,
88
+ mediaPort: this.mediaPort,
89
+ });
90
+ this.outbound = new OutboundSender(this.upstream, ctx.logger);
91
+ this.connected = false;
92
+ this.authState = 'unknown';
93
+ this.emitAuth(this.authState);
94
+ this.emitConnection('connecting');
95
+ this.startReceiveLoop();
96
+ this.started = true;
97
+ }
98
+ async stop() {
99
+ if (!this.started || this.stopped)
100
+ return;
101
+ this.stopped = true;
102
+ this.started = false;
103
+ this.connected = false;
104
+ // The owning fiber aborts the context signal first; the loop also exits
105
+ // on our internal stop signal so stop() never depends on an external
106
+ // abort (contract tests stop without disposing the context).
107
+ this.stopController?.abort();
108
+ const loop = this.receiveLoop;
109
+ this.receiveLoop = undefined;
110
+ if (loop)
111
+ await loop.catch(() => undefined);
112
+ this.emitConnection('closed');
113
+ }
114
+ async send(target, message) {
115
+ if (!this.started || !this.outbound) {
116
+ throw new ChannelError('CHANNEL_NOT_STARTED', 'lark adapter is not started');
117
+ }
118
+ return this.outbound.send(target, message);
119
+ }
120
+ async edit(target, messageId, message) {
121
+ if (!this.started || !this.outbound) {
122
+ throw new ChannelError('CHANNEL_NOT_STARTED', 'lark adapter is not started');
123
+ }
124
+ return this.outbound.edit(target, messageId, message);
125
+ }
126
+ async startTypingForTarget(target) {
127
+ if (this.config.card.typingIndicator === false || !target.replyToMessageId)
128
+ return;
129
+ await this.upstream.startTyping?.(String(target.replyToMessageId));
130
+ }
131
+ async stopTypingForTarget(target) {
132
+ if (this.config.card.typingIndicator === false || !target.replyToMessageId)
133
+ return;
134
+ await this.upstream.stopTyping?.(String(target.replyToMessageId));
135
+ }
136
+ async createReply(target, _options) {
137
+ if (!this.started || !this.ctx) {
138
+ throw new ChannelError('CHANNEL_NOT_STARTED', 'lark adapter is not started');
139
+ }
140
+ return new LarkCardReply({
141
+ upstream: this.upstream,
142
+ target,
143
+ logger: this.ctx.logger,
144
+ createOnFirstDelta: this.config.card.createOnFirstDelta,
145
+ now: this.now,
146
+ });
147
+ }
148
+ async getHealth() {
149
+ if (!this.started) {
150
+ return { status: 'down', detail: 'lark adapter is not started', authenticated: false };
151
+ }
152
+ if (this.connected) {
153
+ return { status: 'ok', detail: 'connected', connection: 'connected', authenticated: true };
154
+ }
155
+ return {
156
+ status: 'degraded',
157
+ detail: 'receive loop down',
158
+ connection: 'disconnected',
159
+ authenticated: false,
160
+ };
161
+ }
162
+ /** WS long-connection receive loop with exponential backoff on failure. */
163
+ startReceiveLoop() {
164
+ if (this.receiveLoop)
165
+ return;
166
+ this.receiveLoop = this.runReceiveLoop();
167
+ }
168
+ /** Build the official-SDK upstream driver. */
169
+ buildUpstream() {
170
+ const outbound = this.resolveOpenApiOutbound();
171
+ const options = {
172
+ client: this.resolveSdkClient(),
173
+ outbound,
174
+ resolveChatType: (conversationId) => outbound.getChatType?.(conversationId) ?? Promise.resolve(undefined),
175
+ onConnected: () => this.markConnected(),
176
+ };
177
+ this.upstream = new LarkSdkUpstream(options);
178
+ }
179
+ /** Select the official OpenAPI outbound driver. */
180
+ resolveOpenApiOutbound() {
181
+ if (this.deps.openApiClient) {
182
+ return new LarkOpenApiOutbound({ client: this.deps.openApiClient });
183
+ }
184
+ if (this.deps.openApiClientFactory) {
185
+ return new LarkOpenApiOutbound({ client: this.deps.openApiClientFactory(this.config) });
186
+ }
187
+ return new LarkOpenApiOutbound({
188
+ client: createDefaultOpenApiClient(this.deps.appId, this.deps.appSecret, this.config),
189
+ });
190
+ }
191
+ /**
192
+ * Select the media port for inbound media hydration. An explicit dep wins;
193
+ * otherwise the adapter builds a default `LarkOpenApiMediaPort` from the
194
+ * same resolved OpenAPI client used for outbound.
195
+ */
196
+ resolveMediaPort() {
197
+ if (this.deps.mediaPort)
198
+ return this.deps.mediaPort;
199
+ // The resolved client is the real SDK `Client`, which structurally
200
+ // satisfies the wider `LarkMediaClient` surface (message resource + image
201
+ // + file). When a caller injects a fake typed only as `LarkOpenApiClient`,
202
+ // hydration still safely degrades: a missing messageResource surfaces as
203
+ // a runtime failure that the hydrator marks.
204
+ const client = this.deps.openApiClient
205
+ ?? (this.deps.openApiClientFactory && this.deps.openApiClientFactory(this.config))
206
+ ?? createDefaultOpenApiClient(this.deps.appId, this.deps.appSecret, this.config);
207
+ return new LarkOpenApiMediaPort({ client: client });
208
+ }
209
+ resolveSdkClient() {
210
+ if (this.deps.sdkClient)
211
+ return this.deps.sdkClient;
212
+ if (this.deps.sdkClientFactory)
213
+ return this.deps.sdkClientFactory(this.config);
214
+ return createDefaultWSClient(this.deps.appId, this.deps.appSecret, this.config);
215
+ }
216
+ async runReceiveLoop() {
217
+ let attempt = 0;
218
+ while (!this.stopped && !this.aborted()) {
219
+ try {
220
+ await this.upstream.receive(this.receiveSignal, (raw) => {
221
+ void this.inbound.handle(raw).catch((error) => {
222
+ this.ctx.logger.error('[channel-lark] inbound handling failed', error);
223
+ });
224
+ });
225
+ attempt = 0;
226
+ // A completed receive cycle proves the upstream is reachable; auth
227
+ // follows the connection state (the driver owns credentials). The WS
228
+ // driver reports connectivity via onConnected.
229
+ this.markConnected();
230
+ }
231
+ catch (error) {
232
+ if (this.stopped || this.aborted())
233
+ break;
234
+ attempt += 1;
235
+ this.connected = false;
236
+ this.emitConnection('reconnecting');
237
+ if (this.config.reconnect.enabled && attempt > this.config.reconnect.maxRetries) {
238
+ this.ctx.logger.warn('[channel-lark] reconnect budget exhausted');
239
+ this.setAuth('failed');
240
+ this.emitConnection('disconnected');
241
+ break;
242
+ }
243
+ const delay = Math.min(this.config.reconnect.baseDelayMs * 2 ** Math.min(attempt - 1, 8), this.config.reconnect.maxDelayMs);
244
+ this.ctx.logger.warn(`[channel-lark] receive loop error; retry in ${delay}ms`, error);
245
+ await sleep(delay, this.receiveSignal);
246
+ }
247
+ }
248
+ this.connected = false;
249
+ if (!this.stopped && !this.aborted()) {
250
+ this.emitConnection('disconnected');
251
+ }
252
+ }
253
+ /** Flip connection/auth state once the upstream proves reachable. */
254
+ markConnected() {
255
+ if (this.stopped)
256
+ return;
257
+ if (this.connected)
258
+ return;
259
+ this.connected = true;
260
+ this.setAuth('authenticated');
261
+ this.emitConnection('connected');
262
+ }
263
+ aborted() {
264
+ return this.receiveSignal?.aborted ?? true;
265
+ }
266
+ setAuth(state) {
267
+ if (this.authState === state)
268
+ return;
269
+ this.authState = state;
270
+ this.emitAuth(state);
271
+ }
272
+ emitAuth(state) {
273
+ if (!this.ctx)
274
+ return;
275
+ void this.ctx
276
+ .emit({
277
+ type: 'auth.changed',
278
+ channel: this.id,
279
+ accountId: this.config.accountId,
280
+ state,
281
+ })
282
+ .catch(() => undefined);
283
+ }
284
+ emitConnection(state) {
285
+ if (!this.ctx)
286
+ return;
287
+ void this.ctx
288
+ .emit({
289
+ type: 'connection.changed',
290
+ channel: this.id,
291
+ accountId: this.config.accountId,
292
+ state,
293
+ })
294
+ .catch(() => undefined);
295
+ }
296
+ }
297
+ /** Build the real SDK WS client from resolved credentials; never logs them. */
298
+ function createDefaultWSClient(appId, appSecret, config) {
299
+ if (!appId || !appSecret) {
300
+ throw new ChannelError('CHANNEL_ERROR', 'lark upstream requires resolved appId and appSecret credentials');
301
+ }
302
+ return new WSClient({
303
+ appId,
304
+ appSecret,
305
+ domain: resolveDomain(config.upstream.domain ?? 'feishu'),
306
+ });
307
+ }
308
+ /** Build the real SDK OpenAPI client from resolved credentials; never logs them. */
309
+ function createDefaultOpenApiClient(appId, appSecret, config) {
310
+ if (!appId || !appSecret) {
311
+ throw new ChannelError('CHANNEL_ERROR', 'lark upstream requires resolved appId and appSecret credentials');
312
+ }
313
+ return new Client({
314
+ appId,
315
+ appSecret,
316
+ domain: resolveDomain(config.upstream.domain ?? 'feishu'),
317
+ });
318
+ }
319
+ /**
320
+ * Resolve a config domain string to the SDK's `Domain` enum, preserving a
321
+ * custom base domain verbatim (the SDK accepts `Domain | string`).
322
+ */
323
+ export function resolveDomain(value) {
324
+ if (value === 'feishu')
325
+ return Domain.Feishu;
326
+ if (value === 'lark')
327
+ return Domain.Lark;
328
+ return value;
329
+ }
330
+ function sleep(ms, signal) {
331
+ return new Promise((resolve) => {
332
+ if (signal?.aborted) {
333
+ resolve();
334
+ return;
335
+ }
336
+ const timer = setTimeout(() => {
337
+ signal?.removeEventListener('abort', onAbort);
338
+ resolve();
339
+ }, ms);
340
+ const onAbort = () => {
341
+ clearTimeout(timer);
342
+ resolve();
343
+ };
344
+ signal?.addEventListener('abort', onAbort, { once: true });
345
+ });
346
+ }
347
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type AuthProviderSession, type PublicAuthStatus } from '@krischoichoi/channel-control';
2
+ export interface LarkDeviceAuthorizationOptions {
3
+ appId: string;
4
+ appSecret: string;
5
+ domain?: string;
6
+ fetcher?: typeof fetch;
7
+ }
8
+ /** Begin Feishu/Lark device authorization. Secrets remain in opaque host state. */
9
+ export declare function beginLarkDeviceAuthorization(options: LarkDeviceAuthorizationOptions): Promise<AuthProviderSession>;
10
+ /** Poll a device authorization session without exposing provider tokens. */
11
+ export declare function pollLarkDeviceAuthorization(session: AuthProviderSession, options?: Pick<LarkDeviceAuthorizationOptions, 'fetcher'>): Promise<PublicAuthStatus>;
12
+ //# sourceMappingURL=device-authorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-authorization.d.ts","sourceRoot":"","sources":["../../src/auth/device-authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,+BAA+B,CAAC;AAsCvC,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAsDD,mFAAmF;AACnF,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,mBAAmB,CAAC,CAoC9B;AAED,4EAA4E;AAC5E,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,IAAI,CAAC,8BAA8B,EAAE,SAAS,CAAM,GAC5D,OAAO,CAAC,gBAAgB,CAAC,CA+C3B"}