@zhin.js/adapter-lark 1.1.17 → 1.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +13 -2
- package/adapters/lark/index.js +3 -17
- package/adapters/lark/index.ts +2 -17
- package/commands/lark/endpoint/definition.js +0 -2
- package/commands/lark/endpoint/definition.ts +0 -2
- package/lib/adapter.d.ts +19 -0
- package/lib/adapter.js +29 -0
- package/lib/client.d.ts +95 -11
- package/lib/client.js +657 -2
- package/lib/console-spec.d.ts +12 -0
- package/lib/console-spec.js +13 -0
- package/lib/console.d.ts +8 -0
- package/lib/console.js +13 -0
- package/lib/endpoint.d.ts +11 -102
- package/lib/endpoint.js +26 -671
- package/lib/index.d.ts +4 -2
- package/lib/index.js +3 -2
- package/lib/long-connection.d.ts +1 -1
- package/lib/long-connection.js +1 -1
- package/lib/media-upload.d.ts +5 -1
- package/lib/media-upload.js +6 -6
- package/lib/protocol.d.ts +1 -1
- package/lib/protocol.js +1 -1
- package/lib/sdk-http.d.ts +4 -0
- package/lib/sdk-http.js +88 -0
- package/lib/webhook.d.ts +1 -1
- package/lib/webhook.js +1 -1
- package/package.json +26 -18
- package/pages/index/index.js +15 -0
- package/pages/index/index.ts +16 -0
- package/plugin.js +3 -4
- package/src/adapter.ts +30 -0
- package/src/client.ts +726 -10
- package/src/console-spec.ts +18 -0
- package/src/console.ts +18 -0
- package/src/endpoint.ts +29 -749
- package/src/index.ts +4 -3
- package/src/long-connection.ts +2 -2
- package/src/media-upload.ts +10 -5
- package/src/protocol.ts +2 -2
- package/src/sdk-http.ts +65 -0
- package/src/webhook.ts +2 -2
- package/lib/lark-runtime-state.d.ts +0 -1
- package/lib/lark-runtime-state.js +0 -6
- package/src/lark-runtime-state.ts +0 -7
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, type AccessToken, type LarkEndpointConfig, type LarkApiResponse, type LarkEventBody, type LarkMessage, type LarkSendBody, type LarkWireSegment, type ResolvedLarkConfig, } from './protocol.js';
|
|
2
|
-
export {
|
|
2
|
+
export { type LarkClientEventMap } from './client.js';
|
|
3
3
|
export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
|
|
4
|
-
export {
|
|
4
|
+
export { LarkEndpoint, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
|
|
5
5
|
export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, type MediaBinary, } from './media-upload.js';
|
|
6
6
|
export { registerLarkWebhookRoutes, handleLarkWebhookRequest, type LarkWebhookHandler, } from './webhook.js';
|
|
7
7
|
export { createLarkLongConnection, type LarkLongConnection, type LarkLongConnectionFactory, type LarkLongConnectionOptions, } from './long-connection.js';
|
|
8
|
+
export { LarkClient, type LarkClientApi } from './client.js';
|
|
9
|
+
export { LarkAdapter } from './adapter.js';
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, } from './protocol.js';
|
|
2
|
-
export { larkClient } from './client.js';
|
|
3
2
|
export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
|
|
4
|
-
export {
|
|
3
|
+
export { LarkEndpoint, } from './endpoint.js';
|
|
5
4
|
export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
6
5
|
export { registerLarkWebhookRoutes, handleLarkWebhookRequest, } from './webhook.js';
|
|
7
6
|
export { createLarkLongConnection, } from './long-connection.js';
|
|
7
|
+
export { LarkClient } from './client.js';
|
|
8
|
+
export { LarkAdapter } from './adapter.js';
|
package/lib/long-connection.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface LarkLongConnection {
|
|
|
7
7
|
}
|
|
8
8
|
export interface LarkLongConnectionOptions {
|
|
9
9
|
readonly config: ResolvedLarkConfig;
|
|
10
|
-
readonly receive: (message: LarkMessage) => void;
|
|
10
|
+
readonly receive: (message: LarkMessage, nativeEvent?: unknown) => void;
|
|
11
11
|
readonly cardAction?: (event: LarkCardAction) => void;
|
|
12
12
|
readonly disconnected: () => void;
|
|
13
13
|
}
|
package/lib/long-connection.js
CHANGED
|
@@ -42,7 +42,7 @@ export const createLarkLongConnection = ({ config, receive, cardAction, disconne
|
|
|
42
42
|
cardAction?.(event); return {}; },
|
|
43
43
|
'im.message.receive_v1': (event) => {
|
|
44
44
|
if (!cancelled)
|
|
45
|
-
receive({ ...event.message, sender: event.sender });
|
|
45
|
+
receive({ ...event.message, sender: event.sender }, event);
|
|
46
46
|
// No downstream send is awaited: SDK ACK remains within its 3-second window.
|
|
47
47
|
},
|
|
48
48
|
});
|
package/lib/media-upload.d.ts
CHANGED
|
@@ -5,7 +5,11 @@ export interface MediaBinary {
|
|
|
5
5
|
readonly fileName: string;
|
|
6
6
|
}
|
|
7
7
|
/** 从 canonical MediaRef 解析二进制:base64 解码 / 本地读盘 / URL 下载。 */
|
|
8
|
-
export
|
|
8
|
+
export interface MediaResolveOptions {
|
|
9
|
+
readonly download?: (url: string, signal?: AbortSignal) => Promise<Buffer>;
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
export declare function resolveMediaBinary(media: MediaRef, { download, signal }?: MediaResolveOptions): Promise<MediaBinary>;
|
|
9
13
|
/** /im/v1/images 的 multipart body(image_type=message 用于消息内图片)。 */
|
|
10
14
|
export declare function buildImageUploadForm(binary: MediaBinary): FormData;
|
|
11
15
|
/**
|
package/lib/media-upload.js
CHANGED
|
@@ -13,8 +13,8 @@ const MIME_EXT = {
|
|
|
13
13
|
'image/webp': 'webp',
|
|
14
14
|
'image/bmp': 'bmp',
|
|
15
15
|
};
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
export async function resolveMediaBinary(media, { download = defaultDownload, signal } = {}) {
|
|
17
|
+
signal?.throwIfAborted();
|
|
18
18
|
const mimeType = media.mime_type ?? 'image/png';
|
|
19
19
|
const ext = MIME_EXT[mimeType] ?? 'png';
|
|
20
20
|
if (media.kind === 'base64') {
|
|
@@ -25,12 +25,12 @@ export async function resolveMediaBinary(media, download = defaultDownload) {
|
|
|
25
25
|
}
|
|
26
26
|
if (media.kind === 'path') {
|
|
27
27
|
const path = media.value.startsWith('file://') ? media.value.slice('file://'.length) : media.value;
|
|
28
|
-
return { data: await readFile(path), mimeType, fileName: basename(path) };
|
|
28
|
+
return { data: await readFile(path, { signal }), mimeType, fileName: basename(path) };
|
|
29
29
|
}
|
|
30
|
-
return { data: await download(media.value), mimeType, fileName: `image.${ext}` };
|
|
30
|
+
return { data: await download(media.value, signal), mimeType, fileName: `image.${ext}` };
|
|
31
31
|
}
|
|
32
|
-
async function defaultDownload(url) {
|
|
33
|
-
const response = await fetch(url, { signal: AbortSignal.timeout(30_000) });
|
|
32
|
+
async function defaultDownload(url, signal) {
|
|
33
|
+
const response = await fetch(url, { signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(30_000)]) : AbortSignal.timeout(30_000) });
|
|
34
34
|
if (!response.ok)
|
|
35
35
|
throw new Error(`download failed: HTTP ${response.status}`);
|
|
36
36
|
return Buffer.from(await response.arrayBuffer());
|
package/lib/protocol.d.ts
CHANGED
|
@@ -103,7 +103,7 @@ export declare function resolveChatType(chatId?: string, chatType?: string): 'gr
|
|
|
103
103
|
* 不产生 `parent`。
|
|
104
104
|
*/
|
|
105
105
|
export declare function larkInboundConversation(endpointKey: string, msg: LarkMessage): ConversationRef;
|
|
106
|
-
export declare function resolveSender(msg: LarkMessage): string;
|
|
106
|
+
export declare function resolveSender(msg: LarkMessage): string | undefined;
|
|
107
107
|
export declare function generateMessageId(msg: LarkMessage): string;
|
|
108
108
|
/** Build inbound text for OutboundMessageService.receive. */
|
|
109
109
|
export declare function formatInboundContent(msg: LarkMessage): string;
|
package/lib/protocol.js
CHANGED
|
@@ -78,7 +78,7 @@ export function larkInboundConversation(endpointKey, msg) {
|
|
|
78
78
|
export function resolveSender(msg) {
|
|
79
79
|
return msg.sender?.sender_id?.open_id
|
|
80
80
|
|| msg.sender?.sender_id?.user_id
|
|
81
|
-
||
|
|
81
|
+
|| undefined;
|
|
82
82
|
}
|
|
83
83
|
export function generateMessageId(msg) {
|
|
84
84
|
return msg.message_id || `${msg.create_time ?? Date.now()}`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HttpInstance } from '@larksuiteoapi/node-sdk';
|
|
2
|
+
import type { LarkFetch } from './client.js';
|
|
3
|
+
/** The installed SDK's documented HttpInstance seam, using the same account-owned transport. */
|
|
4
|
+
export declare function createLarkSdkHttpInstance(fetch: LarkFetch): HttpInstance;
|
package/lib/sdk-http.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Readable, PassThrough } from 'node:stream';
|
|
2
|
+
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
3
|
+
/** The installed SDK's documented HttpInstance seam, using the same account-owned transport. */
|
|
4
|
+
export function createLarkSdkHttpInstance(fetch) {
|
|
5
|
+
const request = async (input) => {
|
|
6
|
+
if (!input.url)
|
|
7
|
+
throw new TypeError('Lark SDK request URL is required');
|
|
8
|
+
const url = new URL(input.url);
|
|
9
|
+
if (input.params) {
|
|
10
|
+
const serializer = typeof input.paramsSerializer === 'function' ? input.paramsSerializer
|
|
11
|
+
: input.paramsSerializer?.serialize;
|
|
12
|
+
if (serializer) {
|
|
13
|
+
const query = serializer(input.params);
|
|
14
|
+
if (query)
|
|
15
|
+
url.search = url.search ? `${url.search}&${query}` : query;
|
|
16
|
+
}
|
|
17
|
+
else
|
|
18
|
+
for (const [key, value] of Object.entries(input.params)) {
|
|
19
|
+
if (value === undefined || value === null)
|
|
20
|
+
continue;
|
|
21
|
+
for (const item of Array.isArray(value) ? value : [value])
|
|
22
|
+
url.searchParams.append(key, String(item));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const headers = Object.fromEntries(Object.entries(input.headers ?? {}).filter(([, value]) => value !== undefined).map(([key, value]) => [key, String(value)]));
|
|
26
|
+
let body;
|
|
27
|
+
let streaming = false;
|
|
28
|
+
if (input.data !== undefined) {
|
|
29
|
+
const native = input.data;
|
|
30
|
+
if (typeof input.data === 'string' || input.data instanceof FormData || input.data instanceof ArrayBuffer || ArrayBuffer.isView(input.data))
|
|
31
|
+
body = input.data;
|
|
32
|
+
else if (native && (typeof native.pipe === 'function' || typeof native[Symbol.asyncIterator] === 'function')) {
|
|
33
|
+
if (native.getHeaders)
|
|
34
|
+
Object.assign(headers, native.getHeaders());
|
|
35
|
+
if (typeof native.pipe === 'function') {
|
|
36
|
+
const stream = new PassThrough();
|
|
37
|
+
stream.once('close', () => native.destroy?.());
|
|
38
|
+
native.pipe(stream);
|
|
39
|
+
body = stream;
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
body = input.data;
|
|
43
|
+
streaming = true;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
body = JSON.stringify(input.data);
|
|
47
|
+
if (!Object.keys(headers).some(key => key.toLowerCase() === 'content-type'))
|
|
48
|
+
headers['Content-Type'] = 'application/json';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const response = await fetch(url.toString(), { method: input.method, headers, body, ...(streaming ? { duplex: 'half' } : {}),
|
|
52
|
+
...(input.timeout ? { signal: AbortSignal.timeout(input.timeout) } : {}) });
|
|
53
|
+
if (!response.ok)
|
|
54
|
+
throw new EndpointDeliveryError('http_error', `Lark HTTP ${response.status}`, response.status >= 400 && response.status < 500 && response.status !== 408 ? 'rejected' : 'unknown');
|
|
55
|
+
const native = response;
|
|
56
|
+
let data;
|
|
57
|
+
if (input.responseType === 'stream') {
|
|
58
|
+
if (!native.body)
|
|
59
|
+
throw new Error('Lark transport returned no response stream');
|
|
60
|
+
data = Readable.fromWeb(native.body);
|
|
61
|
+
}
|
|
62
|
+
else if (input.responseType === 'arraybuffer') {
|
|
63
|
+
if (!native.arrayBuffer)
|
|
64
|
+
throw new Error('Lark transport returned no binary reader');
|
|
65
|
+
data = Buffer.from(await native.arrayBuffer());
|
|
66
|
+
}
|
|
67
|
+
else if (input.responseType === 'blob') {
|
|
68
|
+
if (!native.blob)
|
|
69
|
+
throw new Error('Lark transport returned no blob reader');
|
|
70
|
+
data = await native.blob();
|
|
71
|
+
}
|
|
72
|
+
else if (input.responseType === 'text' || input.responseType === 'document')
|
|
73
|
+
data = await response.text();
|
|
74
|
+
else
|
|
75
|
+
data = await response.json();
|
|
76
|
+
return (input.$return_headers ? { data, headers: Object.fromEntries(native.headers?.entries() ?? []) } : data);
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
request,
|
|
80
|
+
get: (url, options) => request({ ...options, url, method: 'GET' }),
|
|
81
|
+
delete: (url, options) => request({ ...options, url, method: 'DELETE' }),
|
|
82
|
+
head: (url, options) => request({ ...options, url, method: 'HEAD' }),
|
|
83
|
+
options: (url, options) => request({ ...options, url, method: 'OPTIONS' }),
|
|
84
|
+
post: (url, data, options) => request({ ...options, url, data, method: 'POST' }),
|
|
85
|
+
put: (url, data, options) => request({ ...options, url, data, method: 'PUT' }),
|
|
86
|
+
patch: (url, data, options) => request({ ...options, url, data, method: 'PATCH' }),
|
|
87
|
+
};
|
|
88
|
+
}
|
package/lib/webhook.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface LarkWebhookHandler {
|
|
|
9
9
|
readonly config: ResolvedLarkConfig;
|
|
10
10
|
readonly isOpen: boolean;
|
|
11
11
|
admitPlatform(name: string, event: unknown): void;
|
|
12
|
-
admit(msg: LarkMessage): void;
|
|
12
|
+
admit(msg: LarkMessage, nativeEvent?: unknown): void;
|
|
13
13
|
admitCardAction?(event: LarkCardAction): void;
|
|
14
14
|
}
|
|
15
15
|
export declare function registerLarkWebhookRoutes(http: HttpHost, handler: LarkWebhookHandler): HttpRouteRegistration[];
|
package/lib/webhook.js
CHANGED
|
@@ -63,7 +63,7 @@ export async function handleLarkWebhookRequest(request, response, handler) {
|
|
|
63
63
|
...event.event.message,
|
|
64
64
|
sender: event.event.message.sender ?? event.event.sender,
|
|
65
65
|
};
|
|
66
|
-
handler.admit(message);
|
|
66
|
+
handler.admit(message, event);
|
|
67
67
|
}
|
|
68
68
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
69
69
|
response.end(JSON.stringify({ code: 0, msg: 'success' }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-lark",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.19",
|
|
4
4
|
"description": "Zhin.js Lark/Feishu adapter (HTTP webhook and WebSocket long connection)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -33,26 +33,29 @@
|
|
|
33
33
|
"directory": "plugins/adapters/lark"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"undici": "6.29.1",
|
|
37
36
|
"@larksuiteoapi/node-sdk": "^1.67.0",
|
|
38
|
-
"
|
|
39
|
-
"@zhin.js/
|
|
40
|
-
"@zhin.js/
|
|
41
|
-
"@zhin.js/
|
|
42
|
-
"@zhin.js/
|
|
43
|
-
"@zhin.js/
|
|
37
|
+
"undici": "6.29.1",
|
|
38
|
+
"@zhin.js/adapter": "1.1.26",
|
|
39
|
+
"@zhin.js/agent-feature": "1.1.11",
|
|
40
|
+
"@zhin.js/client": "1.1.22",
|
|
41
|
+
"@zhin.js/console-contract": "1.1.3",
|
|
42
|
+
"@zhin.js/core": "1.1.54",
|
|
43
|
+
"@zhin.js/feature-kit": "1.1.10",
|
|
44
|
+
"@zhin.js/host-http": "1.1.12",
|
|
45
|
+
"@zhin.js/im-contract": "1.1.9",
|
|
44
46
|
"@zhin.js/logger": "1.1.2",
|
|
45
|
-
"@zhin.js/
|
|
46
|
-
"@zhin.js/
|
|
47
|
+
"@zhin.js/page": "1.1.11",
|
|
48
|
+
"@zhin.js/skill": "1.1.11",
|
|
49
|
+
"@zhin.js/tool": "1.1.13"
|
|
47
50
|
},
|
|
48
51
|
"peerDependencies": {
|
|
49
52
|
"zod": "^4.0.0",
|
|
50
|
-
"@zhin.js/adapter": "^1.1.
|
|
51
|
-
"@zhin.js/command": "^1.1.
|
|
52
|
-
"@zhin.js/core": "^1.1.
|
|
53
|
-
"@zhin.js/
|
|
54
|
-
"@zhin.js/
|
|
55
|
-
"zhin.js": "^1.1.
|
|
53
|
+
"@zhin.js/adapter": "^1.1.26",
|
|
54
|
+
"@zhin.js/command": "^1.1.12",
|
|
55
|
+
"@zhin.js/core": "^1.1.54",
|
|
56
|
+
"@zhin.js/host-http": "^1.1.12",
|
|
57
|
+
"@zhin.js/permission": "^1.1.10",
|
|
58
|
+
"zhin.js": "^1.1.19"
|
|
56
59
|
},
|
|
57
60
|
"peerDependenciesMeta": {
|
|
58
61
|
"@zhin.js/command": {
|
|
@@ -70,11 +73,12 @@
|
|
|
70
73
|
"typescript": "^6.0.3",
|
|
71
74
|
"vitest": "^4.1.10",
|
|
72
75
|
"zod": "^4.4.3",
|
|
73
|
-
"zhin.js": "1.1.
|
|
76
|
+
"zhin.js": "1.1.19"
|
|
74
77
|
},
|
|
75
78
|
"files": [
|
|
76
79
|
"adapters",
|
|
77
80
|
"commands",
|
|
81
|
+
"pages",
|
|
78
82
|
"plugin.js",
|
|
79
83
|
"schema.json",
|
|
80
84
|
"src",
|
|
@@ -101,7 +105,7 @@
|
|
|
101
105
|
"features": [
|
|
102
106
|
{
|
|
103
107
|
"package": "@zhin.js/adapter",
|
|
104
|
-
"api": "^
|
|
108
|
+
"api": "^2.0.0"
|
|
105
109
|
},
|
|
106
110
|
{
|
|
107
111
|
"package": "@zhin.js/command",
|
|
@@ -118,6 +122,10 @@
|
|
|
118
122
|
{
|
|
119
123
|
"package": "@zhin.js/agent-feature",
|
|
120
124
|
"api": "^1.0.0"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"package": "@zhin.js/page",
|
|
128
|
+
"api": "^1.0.0"
|
|
121
129
|
}
|
|
122
130
|
],
|
|
123
131
|
"plugins": []
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { definePage } from '@zhin.js/console-contract';
|
|
3
|
+
import { createAdapterConsolePage } from '@zhin.js/client';
|
|
4
|
+
export const meta = definePage({
|
|
5
|
+
title: 'Lark',
|
|
6
|
+
titleI18n: { en: 'Lark' },
|
|
7
|
+
icon: 'Bird',
|
|
8
|
+
order: 66,
|
|
9
|
+
requiredPermissions: ['lark:read'],
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Convention page: `pages/index/index.ts` → `/lark`(插件路径)。
|
|
13
|
+
* 连接状态、连接测试、endpoint 增删;登录待办来自 LoginAssist(ICQQ 等)。
|
|
14
|
+
*/
|
|
15
|
+
export default createAdapterConsolePage('lark');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { definePage } from '@zhin.js/console-contract';
|
|
2
|
+
import { createAdapterConsolePage } from '@zhin.js/client';
|
|
3
|
+
|
|
4
|
+
export const meta = definePage({
|
|
5
|
+
title: 'Lark',
|
|
6
|
+
titleI18n: { en: 'Lark' },
|
|
7
|
+
icon: 'Bird',
|
|
8
|
+
order: 66,
|
|
9
|
+
requiredPermissions: ['lark:read'],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Convention page: `pages/index/index.ts` → `/lark`(插件路径)。
|
|
14
|
+
* 连接状态、连接测试、endpoint 增删;登录待办来自 LoginAssist(ICQQ 等)。
|
|
15
|
+
*/
|
|
16
|
+
export default createAdapterConsolePage('lark');
|
package/plugin.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
-
import {
|
|
3
|
-
import { definePlugin } from 'zhin.js';
|
|
2
|
+
import { definePlugin, pluginConsoleRpcToken } from 'zhin.js';
|
|
4
3
|
import { permissionHostToken } from '@zhin.js/permission';
|
|
5
4
|
import { checkLarkPlatformPermit } from "./lib/platform-permit.js";
|
|
6
|
-
import {
|
|
5
|
+
import { createLarkConsoleRpc } from "./lib/console.js";
|
|
7
6
|
export default definePlugin({
|
|
8
7
|
name: 'lark',
|
|
9
8
|
metadata: {
|
|
10
9
|
displayName: 'Lark/Feishu (飞书) Adapter',
|
|
11
10
|
},
|
|
12
11
|
setup(context) {
|
|
13
|
-
context.resources.provide(
|
|
12
|
+
context.resources.provide(pluginConsoleRpcToken, createLarkConsoleRpc(context.resources, () => context.config.get()));
|
|
14
13
|
if (context.resources.has(permissionHostToken)) {
|
|
15
14
|
const host = context.resources.use(permissionHostToken);
|
|
16
15
|
return host.registerPlatform('lark', checkLarkPlatformPermit);
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LarkClient, type LarkClientEventMap } from './client.js';
|
|
2
|
+
import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
|
|
3
|
+
import { LarkEndpoint } from './endpoint.js';
|
|
4
|
+
import { resolveLarkConfig, type LarkEndpointConfig } from './protocol.js';
|
|
5
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
6
|
+
|
|
7
|
+
export class LarkAdapter extends Adapter<LarkEndpoint, LarkEndpointConfig, LarkClientEventMap> {
|
|
8
|
+
readonly #context: AdapterContext<LarkEndpointConfig>;
|
|
9
|
+
constructor(context: AdapterContext<LarkEndpointConfig>) { super(); this.#context = context; }
|
|
10
|
+
override get configurationIdentityFields(): readonly string[] { return ['id', 'appId', 'isFeishu']; }
|
|
11
|
+
override get configurationUpdateFields(): readonly string[] { return ['appSecret', 'encryptKey', 'verificationToken', 'mode', 'webhookPath', 'apiBaseUrl', 'webApiProxy', 'streamProxy']; }
|
|
12
|
+
override get configurationIdentityProbeFields(): readonly string[] { return ['appSecret', 'apiBaseUrl']; }
|
|
13
|
+
protected override async identifyConfiguration(input: LarkEndpointConfig, signal: AbortSignal, _changed: readonly string[]): Promise<string | undefined> {
|
|
14
|
+
const config = resolveLarkConfig(input), client = new LarkClient({ id: this.descriptor.id, config, signal });
|
|
15
|
+
try {
|
|
16
|
+
const response = await client.request<{ code?: number; bot?: { open_id?: unknown } }>({ url: `${config.apiBaseUrl}/bot/v3/info`, method: 'GET' });
|
|
17
|
+
if (response.code !== 0 || typeof response.bot?.open_id !== 'string' || !response.bot.open_id) throw new Error('Lark identity verification returned no bot open_id');
|
|
18
|
+
return JSON.stringify(['lark', new URL(config.apiBaseUrl).origin, response.bot.open_id]);
|
|
19
|
+
} finally { await client[Symbol.asyncDispose](); }
|
|
20
|
+
}
|
|
21
|
+
protected override validateConfiguration(config: LarkEndpointConfig): void { resolveLarkConfig(config); }
|
|
22
|
+
protected createEndpoint(input: LarkEndpointConfig, execution: EndpointCreationContext): LarkEndpoint {
|
|
23
|
+
const config = resolveLarkConfig(input);
|
|
24
|
+
return new LarkEndpoint({ id: execution.canonicalId, config, ...(config.mode === 'websocket' ? {} : { http: this.#context.use(httpHostToken) }) });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare module '@zhin.js/feature-kit' {
|
|
29
|
+
interface AdapterRegistry { readonly 'lark': LarkAdapter; }
|
|
30
|
+
}
|