@zhin.js/adapter-kook 2.0.10 → 2.0.12
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 +16 -0
- package/README.md +99 -7
- package/lib/bot.d.ts +33 -2
- package/lib/bot.d.ts.map +1 -1
- package/lib/bot.js +157 -20
- package/lib/bot.js.map +1 -1
- package/lib/kook-asset-upload.d.ts +12 -0
- package/lib/kook-asset-upload.d.ts.map +1 -0
- package/lib/kook-asset-upload.js +46 -0
- package/lib/kook-asset-upload.js.map +1 -0
- package/lib/kook-inbound.d.ts +6 -0
- package/lib/kook-inbound.d.ts.map +1 -0
- package/lib/kook-inbound.js +22 -0
- package/lib/kook-inbound.js.map +1 -0
- package/lib/kook-msg-route.d.ts +34 -0
- package/lib/kook-msg-route.d.ts.map +1 -0
- package/lib/kook-msg-route.js +106 -0
- package/lib/kook-msg-route.js.map +1 -0
- package/lib/kook-side-events.d.ts +43 -0
- package/lib/kook-side-events.d.ts.map +1 -0
- package/lib/kook-side-events.js +147 -0
- package/lib/kook-side-events.js.map +1 -0
- package/lib/outbound-media.d.ts +10 -0
- package/lib/outbound-media.d.ts.map +1 -0
- package/lib/outbound-media.js +86 -0
- package/lib/outbound-media.js.map +1 -0
- package/lib/outbound-sendable.d.ts +11 -0
- package/lib/outbound-sendable.d.ts.map +1 -0
- package/lib/outbound-sendable.js +55 -0
- package/lib/outbound-sendable.js.map +1 -0
- package/lib/types.d.ts +19 -0
- package/lib/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/bot.ts +233 -20
- package/src/kook-asset-upload.ts +55 -0
- package/src/kook-inbound.ts +22 -0
- package/src/kook-msg-route.ts +122 -0
- package/src/kook-side-events.ts +202 -0
- package/src/outbound-media.ts +111 -0
- package/src/outbound-sendable.ts +61 -0
- package/src/types.ts +20 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-asset-upload.d.ts","sourceRoot":"","sources":["../src/kook-asset-upload.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CACF,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,EACd,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAC5C,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAuBD,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,EACzB,IAAI,EAAE,MAAM,GAAG,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK /v3/asset/create 上传(formdata-node 要求 Blob,不能直传 Node Buffer)。
|
|
3
|
+
*/
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
function guessFilename(data) {
|
|
6
|
+
if (Buffer.isBuffer(data))
|
|
7
|
+
return "upload.png";
|
|
8
|
+
if (/^data:image\/png/i.test(data))
|
|
9
|
+
return "upload.png";
|
|
10
|
+
if (/^data:image\/jpe?g/i.test(data))
|
|
11
|
+
return "upload.jpg";
|
|
12
|
+
if (/^data:image\/gif/i.test(data))
|
|
13
|
+
return "upload.gif";
|
|
14
|
+
if (/^data:image\/webp/i.test(data))
|
|
15
|
+
return "upload.webp";
|
|
16
|
+
const base = data.replace(/^file:\/\//, "").split("/").pop();
|
|
17
|
+
return base?.includes(".") ? base : "upload.png";
|
|
18
|
+
}
|
|
19
|
+
async function toBuffer(data) {
|
|
20
|
+
if (Buffer.isBuffer(data))
|
|
21
|
+
return data;
|
|
22
|
+
if (data.startsWith("base64://")) {
|
|
23
|
+
return Buffer.from(data.slice(9), "base64");
|
|
24
|
+
}
|
|
25
|
+
if (/^data:[^/]+\/[^;]+;base64,/i.test(data)) {
|
|
26
|
+
return Buffer.from(data.replace(/^data:[^/]+\/[^;]+;base64,/, ""), "base64");
|
|
27
|
+
}
|
|
28
|
+
return readFile(data.replace(/^file:\/\//, ""));
|
|
29
|
+
}
|
|
30
|
+
export async function uploadKookAsset(request, data) {
|
|
31
|
+
if (typeof data === "string" && /^https?:\/\//i.test(data)) {
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
const buffer = await toBuffer(data);
|
|
35
|
+
const form = new globalThis.FormData();
|
|
36
|
+
form.append("file", new globalThis.Blob([new Uint8Array(buffer)]), guessFilename(data));
|
|
37
|
+
const response = await request.post("/v3/asset/create", form, {
|
|
38
|
+
headers: { Accept: "application/json" },
|
|
39
|
+
});
|
|
40
|
+
const url = response.data?.url;
|
|
41
|
+
if (!url) {
|
|
42
|
+
throw new Error(`KOOK asset upload failed: ${response.message ?? "missing url"}`);
|
|
43
|
+
}
|
|
44
|
+
return url;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=kook-asset-upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-asset-upload.js","sourceRoot":"","sources":["../src/kook-asset-upload.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAU5C,SAAS,aAAa,CAAC,IAAqB;IAC1C,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IAC/C,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IACxD,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IAC1D,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,YAAY,CAAC;IACxD,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC;IAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IAC7D,OAAO,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAqB;IAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAyB,EACzB,IAAqB;IAErB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAExF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAE;QAC5D,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-inbound.d.ts","sourceRoot":"","sources":["../src/kook-inbound.ts"],"names":[],"mappings":"AAKA,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAElD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUnC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK 入站侧事件去重(gateway notice / 系统消息)
|
|
3
|
+
*/
|
|
4
|
+
const DEDUPE_TTL_MS = 120_000;
|
|
5
|
+
export class InboundMessageDeduper {
|
|
6
|
+
seen = new Map();
|
|
7
|
+
shouldProcess(key) {
|
|
8
|
+
const now = Date.now();
|
|
9
|
+
for (const [id, t] of this.seen) {
|
|
10
|
+
if (now - t > DEDUPE_TTL_MS)
|
|
11
|
+
this.seen.delete(id);
|
|
12
|
+
}
|
|
13
|
+
if (this.seen.has(key))
|
|
14
|
+
return false;
|
|
15
|
+
this.seen.set(key, now);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.seen.clear();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=kook-inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-inbound.js","sourceRoot":"","sources":["../src/kook-inbound.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B,MAAM,OAAO,qBAAqB;IACf,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAElD,aAAa,CAAC,GAAW;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,IAAI,GAAG,GAAG,CAAC,GAAG,aAAa;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK msg_id 路由:频道 / 私聊 API 路径不同,出站编码路由、入站/删除按路由命中。
|
|
3
|
+
*/
|
|
4
|
+
export type KookMsgRoute = 'channel' | 'direct';
|
|
5
|
+
export declare function routeFromSceneType(sceneType?: 'private' | 'group' | 'channel'): KookMsgRoute | undefined;
|
|
6
|
+
export declare function routeFromSendType(type: 'private' | 'group' | 'channel'): KookMsgRoute;
|
|
7
|
+
/** 出站 send 返回值,供 recall / typing 删除时走路由 */
|
|
8
|
+
export declare function encodeKookMsgRef(route: KookMsgRoute, msgId: string): string;
|
|
9
|
+
export declare function parseKookMsgRef(ref: string): {
|
|
10
|
+
route?: KookMsgRoute;
|
|
11
|
+
msgId: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function plainKookMsgId(ref: string): string;
|
|
14
|
+
export declare function resolveKookRoutes(action: 'add' | 'delete', routeHint?: KookMsgRoute): KookMsgRoute[];
|
|
15
|
+
export declare function isKookMsgGoneError(err: unknown): boolean;
|
|
16
|
+
/** KOOK 标准成功:code=0;少数接口 HTTP 200 省略 code */
|
|
17
|
+
export declare function isKookApiSuccess(result: unknown): boolean;
|
|
18
|
+
/** 明确的业务失败(可尝试另一路由) */
|
|
19
|
+
export declare function isKookExplicitError(result: unknown): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* delete 请求已返回且未抛错:是否停止(不再打第二条路由)。
|
|
22
|
+
* 仅当双路由且响应为明确错误码时,才继续尝试下一路由。
|
|
23
|
+
*/
|
|
24
|
+
export declare function shouldStopDeleteAfterResponse(result: unknown, routeCount: number): boolean;
|
|
25
|
+
/** KOOK 有时用 HTTP 200 + 非 0 code 表示目标已不存在 */
|
|
26
|
+
export declare function isKookApiGoneResult(result: unknown): boolean;
|
|
27
|
+
export declare function kookDeleteApiPath(route: KookMsgRoute): string;
|
|
28
|
+
export declare function kookReactionApiPath(route: KookMsgRoute, action: 'add' | 'delete'): string;
|
|
29
|
+
export declare function encodeKookReactionId(route: KookMsgRoute, msgId: string, emoji: string): string;
|
|
30
|
+
export declare function parseKookReactionId(reactionId: string): {
|
|
31
|
+
route?: KookMsgRoute;
|
|
32
|
+
emoji: string;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=kook-msg-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-msg-route.d.ts","sourceRoot":"","sources":["../src/kook-msg-route.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEhD,wBAAgB,kBAAkB,CAChC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAC1C,YAAY,GAAG,SAAS,CAI1B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAErF;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMpF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,KAAK,GAAG,QAAQ,EACxB,SAAS,CAAC,EAAE,YAAY,GACvB,YAAY,EAAE,CAIhB;AASD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAExD;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAMzD;AAED,uBAAuB;AACvB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAI5D;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAIT;AAED,4CAA4C;AAC5C,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAK5D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE7D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAIzF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG;IACvD,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAYA"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK msg_id 路由:频道 / 私聊 API 路径不同,出站编码路由、入站/删除按路由命中。
|
|
3
|
+
*/
|
|
4
|
+
export function routeFromSceneType(sceneType) {
|
|
5
|
+
if (sceneType === 'private')
|
|
6
|
+
return 'direct';
|
|
7
|
+
if (sceneType === 'group' || sceneType === 'channel')
|
|
8
|
+
return 'channel';
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
export function routeFromSendType(type) {
|
|
12
|
+
return type === 'private' ? 'direct' : 'channel';
|
|
13
|
+
}
|
|
14
|
+
/** 出站 send 返回值,供 recall / typing 删除时走路由 */
|
|
15
|
+
export function encodeKookMsgRef(route, msgId) {
|
|
16
|
+
return `kook:${route}:${msgId}`;
|
|
17
|
+
}
|
|
18
|
+
export function parseKookMsgRef(ref) {
|
|
19
|
+
const parts = ref.split(':');
|
|
20
|
+
if (parts[0] === 'kook' && (parts[1] === 'channel' || parts[1] === 'direct') && parts.length >= 3) {
|
|
21
|
+
return { route: parts[1], msgId: parts.slice(2).join(':') };
|
|
22
|
+
}
|
|
23
|
+
return { msgId: ref };
|
|
24
|
+
}
|
|
25
|
+
export function plainKookMsgId(ref) {
|
|
26
|
+
return parseKookMsgRef(ref).msgId;
|
|
27
|
+
}
|
|
28
|
+
export function resolveKookRoutes(action, routeHint) {
|
|
29
|
+
if (action === 'delete' && routeHint)
|
|
30
|
+
return [routeHint];
|
|
31
|
+
if (routeHint)
|
|
32
|
+
return [routeHint, routeHint === 'channel' ? 'direct' : 'channel'];
|
|
33
|
+
return ['channel', 'direct'];
|
|
34
|
+
}
|
|
35
|
+
function isKookGoneText(text) {
|
|
36
|
+
return text.includes('404')
|
|
37
|
+
|| text.includes('该数据不存在')
|
|
38
|
+
|| text.includes('没有权限操作')
|
|
39
|
+
|| text.toLowerCase().includes('not found');
|
|
40
|
+
}
|
|
41
|
+
export function isKookMsgGoneError(err) {
|
|
42
|
+
return isKookGoneText(err instanceof Error ? err.message : String(err));
|
|
43
|
+
}
|
|
44
|
+
/** KOOK 标准成功:code=0;少数接口 HTTP 200 省略 code */
|
|
45
|
+
export function isKookApiSuccess(result) {
|
|
46
|
+
if (result == null || typeof result !== 'object')
|
|
47
|
+
return false;
|
|
48
|
+
const { code } = result;
|
|
49
|
+
if (code === 0)
|
|
50
|
+
return true;
|
|
51
|
+
if (code === undefined)
|
|
52
|
+
return true;
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
/** 明确的业务失败(可尝试另一路由) */
|
|
56
|
+
export function isKookExplicitError(result) {
|
|
57
|
+
if (result == null || typeof result !== 'object')
|
|
58
|
+
return false;
|
|
59
|
+
const { code } = result;
|
|
60
|
+
return typeof code === 'number' && code !== 0;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* delete 请求已返回且未抛错:是否停止(不再打第二条路由)。
|
|
64
|
+
* 仅当双路由且响应为明确错误码时,才继续尝试下一路由。
|
|
65
|
+
*/
|
|
66
|
+
export function shouldStopDeleteAfterResponse(result, routeCount) {
|
|
67
|
+
if (isKookApiSuccess(result) || isKookApiGoneResult(result))
|
|
68
|
+
return true;
|
|
69
|
+
if (routeCount === 1)
|
|
70
|
+
return true;
|
|
71
|
+
return !isKookExplicitError(result);
|
|
72
|
+
}
|
|
73
|
+
/** KOOK 有时用 HTTP 200 + 非 0 code 表示目标已不存在 */
|
|
74
|
+
export function isKookApiGoneResult(result) {
|
|
75
|
+
if (!result || typeof result !== 'object')
|
|
76
|
+
return false;
|
|
77
|
+
const { code, message } = result;
|
|
78
|
+
if (code === 404)
|
|
79
|
+
return true;
|
|
80
|
+
return isKookGoneText(message ?? '');
|
|
81
|
+
}
|
|
82
|
+
export function kookDeleteApiPath(route) {
|
|
83
|
+
return route === 'channel' ? '/v3/message/delete' : '/v3/direct-message/delete';
|
|
84
|
+
}
|
|
85
|
+
export function kookReactionApiPath(route, action) {
|
|
86
|
+
const prefix = route === 'channel' ? '/v3/message' : '/v3/direct-message';
|
|
87
|
+
const suffix = action === 'add' ? 'add-reaction' : 'delete-reaction';
|
|
88
|
+
return `${prefix}/${suffix}`;
|
|
89
|
+
}
|
|
90
|
+
export function encodeKookReactionId(route, msgId, emoji) {
|
|
91
|
+
return `reaction:${route}:${msgId}:${emoji}`;
|
|
92
|
+
}
|
|
93
|
+
export function parseKookReactionId(reactionId) {
|
|
94
|
+
const parts = reactionId.split(':');
|
|
95
|
+
if (parts[0] === 'reaction' && (parts[1] === 'channel' || parts[1] === 'direct')) {
|
|
96
|
+
return {
|
|
97
|
+
route: parts[1],
|
|
98
|
+
emoji: parts.slice(3).join(':') || '⏳',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (parts[0] === 'reaction' && parts.length >= 3) {
|
|
102
|
+
return { emoji: parts.slice(2).join(':') || '⏳' };
|
|
103
|
+
}
|
|
104
|
+
return { emoji: parts[parts.length - 1] ?? '⏳' };
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=kook-msg-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-msg-route.js","sourceRoot":"","sources":["../src/kook-msg-route.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK Gateway 非聊天入站:系统消息 (type=255) / BROADCAST → Notice
|
|
3
|
+
* @see https://developer.kookapp.cn/doc/event/event-introduction
|
|
4
|
+
*/
|
|
5
|
+
import { Notice } from "zhin.js";
|
|
6
|
+
/** KOOK WebSocket s=0 时 d 字段(kook-client Receiver 入参) */
|
|
7
|
+
export interface KookGatewayEvent {
|
|
8
|
+
channel_type?: string;
|
|
9
|
+
type?: number;
|
|
10
|
+
target_id?: string;
|
|
11
|
+
author_id?: string;
|
|
12
|
+
content?: string;
|
|
13
|
+
msg_id?: string;
|
|
14
|
+
msg_timestamp?: number;
|
|
15
|
+
nonce?: string;
|
|
16
|
+
extra?: KookGatewayExtra;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
export interface KookGatewayExtra {
|
|
20
|
+
type?: string;
|
|
21
|
+
body?: Record<string, unknown>;
|
|
22
|
+
guild_id?: string;
|
|
23
|
+
channel_id?: string;
|
|
24
|
+
channel_name?: string;
|
|
25
|
+
author?: {
|
|
26
|
+
id?: string;
|
|
27
|
+
username?: string;
|
|
28
|
+
nickname?: string;
|
|
29
|
+
};
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** 是否应由适配器作为 notice 处理(kook-client 对 notice 的 transform 为空实现) */
|
|
33
|
+
export declare function isKookNoticeGatewayEvent(data: unknown): data is KookGatewayEvent;
|
|
34
|
+
export declare function resolveKookSideEventDedupeKey(event: KookGatewayEvent, kind: "notice" | "gateway"): string;
|
|
35
|
+
/** 解析 notice 发生的频道 / 群 / 私聊 */
|
|
36
|
+
export declare function resolveKookNoticeChannel(event: KookGatewayEvent): {
|
|
37
|
+
id: string;
|
|
38
|
+
type: "group" | "private" | "channel";
|
|
39
|
+
};
|
|
40
|
+
export declare function enrichKookGatewayForPlugins(event: KookGatewayEvent): KookGatewayEvent;
|
|
41
|
+
export declare function formatKookNotice(event: KookGatewayEvent, botName: string): ReturnType<typeof Notice.from<KookGatewayEvent>>;
|
|
42
|
+
export declare function formatKookNoticeLog(notice: ReturnType<typeof formatKookNotice>): string;
|
|
43
|
+
//# sourceMappingURL=kook-side-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-side-events.d.ts","sourceRoot":"","sources":["../src/kook-side-events.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAkC,MAAM,SAAS,CAAC;AAEjE,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAID,iEAAiE;AACjE,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,gBAAgB,CAKhF;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,QAAQ,GAAG,SAAS,GACzB,MAAM,CAOR;AA6BD,+BAA+B;AAC/B,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,gBAAgB,GACtB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;CAAE,CA+DvD;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAWrF;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,GACd,UAAU,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CA6BlD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,MAAM,CAOvF"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK Gateway 非聊天入站:系统消息 (type=255) / BROADCAST → Notice
|
|
3
|
+
* @see https://developer.kookapp.cn/doc/event/event-introduction
|
|
4
|
+
*/
|
|
5
|
+
import { Notice, formatCompact } from "zhin.js";
|
|
6
|
+
const SYSTEM_MESSAGE_TYPE = 255;
|
|
7
|
+
/** 是否应由适配器作为 notice 处理(kook-client 对 notice 的 transform 为空实现) */
|
|
8
|
+
export function isKookNoticeGatewayEvent(data) {
|
|
9
|
+
if (!data || typeof data !== "object")
|
|
10
|
+
return false;
|
|
11
|
+
const ev = data;
|
|
12
|
+
if (ev.type === SYSTEM_MESSAGE_TYPE)
|
|
13
|
+
return true;
|
|
14
|
+
return ev.channel_type === "BROADCAST";
|
|
15
|
+
}
|
|
16
|
+
export function resolveKookSideEventDedupeKey(event, kind) {
|
|
17
|
+
if (event.msg_id)
|
|
18
|
+
return `${kind}:${event.msg_id}`;
|
|
19
|
+
const extra = event.extra ?? {};
|
|
20
|
+
const noticeType = extra.type ?? String(event.type ?? "");
|
|
21
|
+
const scope = event.target_id ?? "";
|
|
22
|
+
const ts = event.msg_timestamp ?? 0;
|
|
23
|
+
return `${kind}:${ts}_${noticeType}_${scope}`;
|
|
24
|
+
}
|
|
25
|
+
const NOTICE_TYPE_MAP = {
|
|
26
|
+
joined_guild: "group_member_increase",
|
|
27
|
+
exited_guild: "group_member_decrease",
|
|
28
|
+
deleted_message: "group_recall",
|
|
29
|
+
deleted_private_message: "friend_recall",
|
|
30
|
+
added_reaction: "group_emoji_reaction",
|
|
31
|
+
deleted_reaction: "group_emoji_reaction",
|
|
32
|
+
private_added_reaction: "group_emoji_reaction",
|
|
33
|
+
private_deleted_reaction: "group_emoji_reaction",
|
|
34
|
+
};
|
|
35
|
+
function resolveNoticeZhinType(rawType) {
|
|
36
|
+
return NOTICE_TYPE_MAP[rawType] ?? rawType;
|
|
37
|
+
}
|
|
38
|
+
function senderFromId(id, name) {
|
|
39
|
+
if (id == null || id === "")
|
|
40
|
+
return undefined;
|
|
41
|
+
const s = String(id);
|
|
42
|
+
return { id: s, name: name ?? s };
|
|
43
|
+
}
|
|
44
|
+
function readString(obj, key) {
|
|
45
|
+
const v = obj?.[key];
|
|
46
|
+
if (v == null || v === "")
|
|
47
|
+
return undefined;
|
|
48
|
+
return String(v);
|
|
49
|
+
}
|
|
50
|
+
/** 解析 notice 发生的频道 / 群 / 私聊 */
|
|
51
|
+
export function resolveKookNoticeChannel(event) {
|
|
52
|
+
const extra = event.extra ?? {};
|
|
53
|
+
const body = extra.body ?? {};
|
|
54
|
+
const rawType = String(extra.type ?? "");
|
|
55
|
+
if (event.channel_type === "BROADCAST") {
|
|
56
|
+
const guildId = readString(body, "guild_id")
|
|
57
|
+
?? extra.guild_id
|
|
58
|
+
?? event.target_id
|
|
59
|
+
?? "";
|
|
60
|
+
return { id: guildId, type: "group" };
|
|
61
|
+
}
|
|
62
|
+
if (event.type === SYSTEM_MESSAGE_TYPE && event.channel_type === "GROUP") {
|
|
63
|
+
const guildId = readString(body, "guild_id")
|
|
64
|
+
?? extra.guild_id
|
|
65
|
+
?? event.target_id
|
|
66
|
+
?? "";
|
|
67
|
+
if (rawType === "joined_guild"
|
|
68
|
+
|| rawType === "exited_guild"
|
|
69
|
+
|| rawType === "updated_guild"
|
|
70
|
+
|| rawType === "deleted_guild"
|
|
71
|
+
|| rawType.startsWith("added_role")
|
|
72
|
+
|| rawType.startsWith("deleted_role")
|
|
73
|
+
|| rawType.startsWith("updated_role")
|
|
74
|
+
|| rawType.startsWith("added_block")
|
|
75
|
+
|| rawType.startsWith("deleted_block")
|
|
76
|
+
|| rawType === "self_joined_guild"
|
|
77
|
+
|| rawType === "self_exited_guild") {
|
|
78
|
+
return { id: guildId, type: "group" };
|
|
79
|
+
}
|
|
80
|
+
const channelId = readString(body, "channel_id")
|
|
81
|
+
?? extra.channel_id
|
|
82
|
+
?? event.target_id
|
|
83
|
+
?? "";
|
|
84
|
+
return { id: channelId, type: "channel" };
|
|
85
|
+
}
|
|
86
|
+
if (rawType.startsWith("private_")
|
|
87
|
+
|| rawType.includes("private_message")
|
|
88
|
+
|| event.channel_type === "PERSON") {
|
|
89
|
+
const userId = readString(body, "user_id")
|
|
90
|
+
?? readString(body, "target_id")
|
|
91
|
+
?? event.target_id
|
|
92
|
+
?? event.author_id
|
|
93
|
+
?? "";
|
|
94
|
+
return { id: userId, type: "private" };
|
|
95
|
+
}
|
|
96
|
+
const channelId = readString(body, "channel_id")
|
|
97
|
+
?? extra.channel_id
|
|
98
|
+
?? event.target_id
|
|
99
|
+
?? "";
|
|
100
|
+
return { id: channelId, type: "channel" };
|
|
101
|
+
}
|
|
102
|
+
export function enrichKookGatewayForPlugins(event) {
|
|
103
|
+
const extra = event.extra ?? {};
|
|
104
|
+
const noticeType = extra.type;
|
|
105
|
+
if (!isKookNoticeGatewayEvent(event)) {
|
|
106
|
+
return { ...event, post_type: "message" };
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
...event,
|
|
110
|
+
post_type: "notice",
|
|
111
|
+
notice_type: noticeType ?? "system",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function formatKookNotice(event, botName) {
|
|
115
|
+
const extra = event.extra ?? {};
|
|
116
|
+
const body = extra.body ?? {};
|
|
117
|
+
const rawType = String(extra.type ?? "unknown");
|
|
118
|
+
const $type = resolveNoticeZhinType(rawType);
|
|
119
|
+
const channel = resolveKookNoticeChannel(event);
|
|
120
|
+
const ts = event.msg_timestamp ?? Date.now();
|
|
121
|
+
const targetId = readString(body, "user_id")
|
|
122
|
+
?? readString(body, "msg_id")
|
|
123
|
+
?? readString(body, "target_id");
|
|
124
|
+
const operatorId = readString(body, "operator_id")
|
|
125
|
+
?? (event.author_id !== "1" ? event.author_id : undefined);
|
|
126
|
+
const mapped = NOTICE_TYPE_MAP[rawType] != null;
|
|
127
|
+
return Notice.from(event, {
|
|
128
|
+
$id: resolveKookSideEventDedupeKey(event, "notice"),
|
|
129
|
+
$adapter: "kook",
|
|
130
|
+
$bot: botName,
|
|
131
|
+
$type,
|
|
132
|
+
$subType: mapped ? rawType : undefined,
|
|
133
|
+
$channel: channel,
|
|
134
|
+
$operator: senderFromId(operatorId),
|
|
135
|
+
$target: senderFromId(targetId),
|
|
136
|
+
$timestamp: ts,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
export function formatKookNoticeLog(notice) {
|
|
140
|
+
return formatCompact({
|
|
141
|
+
notice: notice.$type,
|
|
142
|
+
kook_type: notice.$subType,
|
|
143
|
+
channel: `${notice.$channel.type}(${notice.$channel.id})`,
|
|
144
|
+
bot: notice.$bot,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=kook-side-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kook-side-events.js","sourceRoot":"","sources":["../src/kook-side-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KOOK 出站媒体:base64 / 本地文件须先走 /v3/asset/create 上传,再嵌入 KMarkdown。
|
|
3
|
+
*/
|
|
4
|
+
import type { MessageElement, SendContent } from "zhin.js";
|
|
5
|
+
export interface KookMediaUploader {
|
|
6
|
+
uploadMedia(data: string | Buffer): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
/** 将 base64 / 本地媒体上传为 KOOK 可访问 URL */
|
|
9
|
+
export declare function materializeOutboundMedia(uploader: KookMediaUploader, content: SendContent): Promise<MessageElement[]>;
|
|
10
|
+
//# sourceMappingURL=outbound-media.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-media.d.ts","sourceRoot":"","sources":["../src/outbound-media.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAkB,WAAW,EAAE,MAAM,SAAS,CAAC;AAI3E,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD;AA2FD,sCAAsC;AACtC,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CAM3B"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const MEDIA_TYPES = new Set(["image", "audio", "video", "file"]);
|
|
2
|
+
function isMessageSegment(seg) {
|
|
3
|
+
return typeof seg.type === "string";
|
|
4
|
+
}
|
|
5
|
+
function isRemoteUrl(value) {
|
|
6
|
+
return /^https?:\/\//i.test(value);
|
|
7
|
+
}
|
|
8
|
+
function asSegments(content) {
|
|
9
|
+
if (typeof content === "string") {
|
|
10
|
+
return [{ type: "text", data: { text: content } }];
|
|
11
|
+
}
|
|
12
|
+
if (!Array.isArray(content)) {
|
|
13
|
+
return [content];
|
|
14
|
+
}
|
|
15
|
+
return content.map((item) => typeof item === "string" ? { type: "text", data: { text: item } } : item);
|
|
16
|
+
}
|
|
17
|
+
function extractBase64Buffer(data) {
|
|
18
|
+
const url = typeof data.url === "string" ? data.url : undefined;
|
|
19
|
+
const file = typeof data.file === "string" ? data.file : undefined;
|
|
20
|
+
const base64 = typeof data.base64 === "string" ? data.base64 : undefined;
|
|
21
|
+
if (url?.startsWith("base64://")) {
|
|
22
|
+
return Buffer.from(url.slice(9), "base64");
|
|
23
|
+
}
|
|
24
|
+
if (url && /^data:[^/]+\/[^;]+;base64,/i.test(url)) {
|
|
25
|
+
return Buffer.from(url.replace(/^data:[^/]+\/[^;]+;base64,/, ""), "base64");
|
|
26
|
+
}
|
|
27
|
+
if (file?.startsWith("base64://")) {
|
|
28
|
+
return Buffer.from(file.slice(9), "base64");
|
|
29
|
+
}
|
|
30
|
+
if (base64) {
|
|
31
|
+
const raw = base64.startsWith("base64://") ? base64.slice(9) : base64;
|
|
32
|
+
return Buffer.from(raw, "base64");
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function resolveLocalFile(data) {
|
|
37
|
+
const url = typeof data.url === "string" ? data.url : undefined;
|
|
38
|
+
const file = typeof data.file === "string" ? data.file : undefined;
|
|
39
|
+
const candidate = file ?? url;
|
|
40
|
+
if (!candidate || isRemoteUrl(candidate))
|
|
41
|
+
return undefined;
|
|
42
|
+
if (candidate.startsWith("base64://") || /^data:/.test(candidate))
|
|
43
|
+
return undefined;
|
|
44
|
+
if (candidate.startsWith("file://") || candidate.startsWith("/") || !candidate.includes("://")) {
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
function withUploadedUrl(seg, uploadedUrl) {
|
|
50
|
+
const data = { ...seg.data };
|
|
51
|
+
data.url = uploadedUrl;
|
|
52
|
+
data.file = uploadedUrl;
|
|
53
|
+
delete data.base64;
|
|
54
|
+
return { type: seg.type, data };
|
|
55
|
+
}
|
|
56
|
+
async function resolveMediaSegment(uploader, seg) {
|
|
57
|
+
if (!MEDIA_TYPES.has(seg.type))
|
|
58
|
+
return seg;
|
|
59
|
+
const data = seg.data;
|
|
60
|
+
const url = typeof data.url === "string" ? data.url : undefined;
|
|
61
|
+
const file = typeof data.file === "string" ? data.file : undefined;
|
|
62
|
+
if ((url && isRemoteUrl(url)) || (file && isRemoteUrl(file))) {
|
|
63
|
+
return seg;
|
|
64
|
+
}
|
|
65
|
+
const buffer = extractBase64Buffer(data);
|
|
66
|
+
if (buffer) {
|
|
67
|
+
const uploaded = await uploader.uploadMedia(buffer);
|
|
68
|
+
return withUploadedUrl(seg, uploaded);
|
|
69
|
+
}
|
|
70
|
+
const local = resolveLocalFile(data);
|
|
71
|
+
if (local) {
|
|
72
|
+
const uploaded = await uploader.uploadMedia(local);
|
|
73
|
+
return withUploadedUrl(seg, uploaded);
|
|
74
|
+
}
|
|
75
|
+
return seg;
|
|
76
|
+
}
|
|
77
|
+
/** 将 base64 / 本地媒体上传为 KOOK 可访问 URL */
|
|
78
|
+
export async function materializeOutboundMedia(uploader, content) {
|
|
79
|
+
const segments = asSegments(content);
|
|
80
|
+
return Promise.all(segments.map(async (item) => {
|
|
81
|
+
if (!isMessageSegment(item))
|
|
82
|
+
return item;
|
|
83
|
+
return resolveMediaSegment(uploader, item);
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=outbound-media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-media.js","sourceRoot":"","sources":["../src/outbound-media.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAMjE,SAAS,gBAAgB,CAAC,GAAmB;IAC3C,OAAO,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC;AACtC,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,OAAoB;IACtC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC1B,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACzE,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,IAA6B;IACxD,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAEzE,IAAI,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,GAAG,IAAI,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACtE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gBAAgB,CAAC,IAA6B;IACrD,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,MAAM,SAAS,GAAG,IAAI,IAAI,GAAG,CAAC;IAC9B,IAAI,CAAC,SAAS,IAAI,WAAW,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,IAAI,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IACpF,IAAI,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/F,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,GAAmB,EAAE,WAAmB;IAC/D,MAAM,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,EAA6B,CAAC;IACxD,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC;IACvB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IACxB,OAAO,IAAI,CAAC,MAAM,CAAC;IACnB,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAoB,CAAC;AACpD,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,QAA2B,EAC3B,GAAmB;IAEnB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAE3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;IACjD,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACnE,IAAI,CAAC,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC7D,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpD,OAAO,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACnD,OAAO,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sCAAsC;AACtC,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,QAA2B,EAC3B,OAAoB;IAEpB,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zhin 消息段 → kook-client Sendable。
|
|
3
|
+
* 图片/音视频须用 segment 发送对应 msg_type,不能写成 Markdown 。
|
|
4
|
+
*/
|
|
5
|
+
import { type MessageSegment as KookMessageSegment } from "kook-client";
|
|
6
|
+
import type { MessageElement } from "zhin.js";
|
|
7
|
+
/**
|
|
8
|
+
* 单张图片(可带 reply)→ kook image 消息段(type=2)
|
|
9
|
+
*/
|
|
10
|
+
export declare function convertToKookSendable(elements: MessageElement[], formatText: (content: MessageElement[]) => string): string | KookMessageSegment[];
|
|
11
|
+
//# sourceMappingURL=outbound-sendable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound-sendable.d.ts","sourceRoot":"","sources":["../src/outbound-sendable.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAW,KAAK,cAAc,IAAI,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAM9C;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,cAAc,EAAE,EAC1B,UAAU,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,MAAM,GAChD,MAAM,GAAG,kBAAkB,EAAE,CA2C/B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zhin 消息段 → kook-client Sendable。
|
|
3
|
+
* 图片/音视频须用 segment 发送对应 msg_type,不能写成 Markdown 。
|
|
4
|
+
*/
|
|
5
|
+
import { segment } from "kook-client";
|
|
6
|
+
function mediaUrl(data) {
|
|
7
|
+
return String(data.url ?? data.file ?? "");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 单张图片(可带 reply)→ kook image 消息段(type=2)
|
|
11
|
+
*/
|
|
12
|
+
export function convertToKookSendable(elements, formatText) {
|
|
13
|
+
const replies = [];
|
|
14
|
+
const images = [];
|
|
15
|
+
const videos = [];
|
|
16
|
+
const audios = [];
|
|
17
|
+
const rest = [];
|
|
18
|
+
for (const el of elements) {
|
|
19
|
+
if (el.type === "reply" && el.data.id) {
|
|
20
|
+
replies.push(String(el.data.id));
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (el.type === "image") {
|
|
24
|
+
const url = mediaUrl(el.data);
|
|
25
|
+
if (url)
|
|
26
|
+
images.push(url);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (el.type === "video") {
|
|
30
|
+
const url = mediaUrl(el.data);
|
|
31
|
+
if (url)
|
|
32
|
+
videos.push(url);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (el.type === "audio") {
|
|
36
|
+
const url = mediaUrl(el.data);
|
|
37
|
+
if (url)
|
|
38
|
+
audios.push(url);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
rest.push(el);
|
|
42
|
+
}
|
|
43
|
+
const replySegs = replies.map((id) => segment.reply(id));
|
|
44
|
+
if (images.length === 1 && videos.length === 0 && audios.length === 0 && rest.length === 0) {
|
|
45
|
+
return [...replySegs, segment.image(images[0])];
|
|
46
|
+
}
|
|
47
|
+
if (videos.length === 1 && images.length === 0 && audios.length === 0 && rest.length === 0) {
|
|
48
|
+
return [...replySegs, segment.video(videos[0])];
|
|
49
|
+
}
|
|
50
|
+
if (audios.length === 1 && images.length === 0 && videos.length === 0 && rest.length === 0) {
|
|
51
|
+
return [...replySegs, segment.audio(audios[0])];
|
|
52
|
+
}
|
|
53
|
+
return formatText(elements);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=outbound-sendable.js.map
|