@zhin.js/adapter-line 0.1.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.
- package/README.md +76 -0
- package/lib/adapter.d.ts +15 -0
- package/lib/adapter.d.ts.map +1 -0
- package/lib/adapter.js +20 -0
- package/lib/adapter.js.map +1 -0
- package/lib/endpoint.d.ts +38 -0
- package/lib/endpoint.d.ts.map +1 -0
- package/lib/endpoint.js +532 -0
- package/lib/endpoint.js.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +83 -0
- package/lib/index.js.map +1 -0
- package/lib/types.d.ts +112 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +5 -0
- package/lib/types.js.map +1 -0
- package/package.json +74 -0
- package/plugin.yml +3 -0
- package/skills/line/PERMITS.md +17 -0
- package/skills/line/SKILL.md +39 -0
- package/src/adapter.ts +29 -0
- package/src/endpoint.ts +605 -0
- package/src/index.ts +100 -0
- package/src/types.ts +130 -0
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LINE Messaging API 类型定义
|
|
3
|
+
*/
|
|
4
|
+
export interface LineEndpointConfig {
|
|
5
|
+
context: 'line';
|
|
6
|
+
name: string;
|
|
7
|
+
channelSecret: string;
|
|
8
|
+
channelAccessToken: string;
|
|
9
|
+
webhookPath?: string;
|
|
10
|
+
apiBaseUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LineUser {
|
|
13
|
+
userId: string;
|
|
14
|
+
displayName?: string;
|
|
15
|
+
pictureUrl?: string;
|
|
16
|
+
statusMessage?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface LineMessageEvent {
|
|
19
|
+
type: 'message';
|
|
20
|
+
replyToken: string;
|
|
21
|
+
source: LineSource;
|
|
22
|
+
timestamp: number;
|
|
23
|
+
message: LineMessage;
|
|
24
|
+
}
|
|
25
|
+
export interface LineFollowEvent {
|
|
26
|
+
type: 'follow';
|
|
27
|
+
replyToken: string;
|
|
28
|
+
source: LineSource;
|
|
29
|
+
timestamp: number;
|
|
30
|
+
}
|
|
31
|
+
export interface LineUnfollowEvent {
|
|
32
|
+
type: 'unfollow';
|
|
33
|
+
source: LineSource;
|
|
34
|
+
timestamp: number;
|
|
35
|
+
}
|
|
36
|
+
export interface LineJoinEvent {
|
|
37
|
+
type: 'join';
|
|
38
|
+
replyToken: string;
|
|
39
|
+
source: LineSource;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
}
|
|
42
|
+
export interface LineLeaveEvent {
|
|
43
|
+
type: 'leave';
|
|
44
|
+
source: LineSource;
|
|
45
|
+
timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
export interface LinePostbackEvent {
|
|
48
|
+
type: 'postback';
|
|
49
|
+
replyToken: string;
|
|
50
|
+
source: LineSource;
|
|
51
|
+
timestamp: number;
|
|
52
|
+
postback: {
|
|
53
|
+
data: string;
|
|
54
|
+
params?: Record<string, string>;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export type LineEvent = LineMessageEvent | LineFollowEvent | LineUnfollowEvent | LineJoinEvent | LineLeaveEvent | LinePostbackEvent;
|
|
58
|
+
export interface LineSource {
|
|
59
|
+
type: 'user' | 'group' | 'room';
|
|
60
|
+
userId?: string;
|
|
61
|
+
groupId?: string;
|
|
62
|
+
roomId?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface LineMessage {
|
|
65
|
+
id: string;
|
|
66
|
+
type: 'text' | 'image' | 'video' | 'audio' | 'file' | 'location' | 'sticker';
|
|
67
|
+
text?: string;
|
|
68
|
+
fileName?: string;
|
|
69
|
+
fileSize?: number;
|
|
70
|
+
title?: string;
|
|
71
|
+
address?: string;
|
|
72
|
+
latitude?: number;
|
|
73
|
+
longitude?: number;
|
|
74
|
+
packageId?: string;
|
|
75
|
+
stickerId?: string;
|
|
76
|
+
stickerResourceType?: string;
|
|
77
|
+
duration?: number;
|
|
78
|
+
}
|
|
79
|
+
export interface LineWebhookBody {
|
|
80
|
+
destination: string;
|
|
81
|
+
events: LineEvent[];
|
|
82
|
+
}
|
|
83
|
+
export interface LineReplyMessage {
|
|
84
|
+
type: 'text' | 'image' | 'video' | 'audio' | 'location' | 'sticker' | 'flex';
|
|
85
|
+
text?: string;
|
|
86
|
+
originalContentUrl?: string;
|
|
87
|
+
previewImageUrl?: string;
|
|
88
|
+
packageId?: string;
|
|
89
|
+
stickerId?: string;
|
|
90
|
+
title?: string;
|
|
91
|
+
address?: string;
|
|
92
|
+
latitude?: number;
|
|
93
|
+
longitude?: number;
|
|
94
|
+
duration?: number;
|
|
95
|
+
altText?: string;
|
|
96
|
+
contents?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
export interface LineReplyRequest {
|
|
99
|
+
replyToken: string;
|
|
100
|
+
messages: LineReplyMessage[];
|
|
101
|
+
}
|
|
102
|
+
export interface LinePushRequest {
|
|
103
|
+
to: string;
|
|
104
|
+
messages: LineReplyMessage[];
|
|
105
|
+
}
|
|
106
|
+
export interface LineApiResponse {
|
|
107
|
+
sentMessages?: Array<{
|
|
108
|
+
id: string;
|
|
109
|
+
quoteToken?: string;
|
|
110
|
+
}>;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/lib/types.js
ADDED
package/lib/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zhin.js/adapter-line",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zhin.js adapter for LINE Messaging API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./lib/index.js",
|
|
7
|
+
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"development": "./src/index.ts",
|
|
12
|
+
"import": "./lib/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"zhin",
|
|
17
|
+
"zhin.js",
|
|
18
|
+
"bot",
|
|
19
|
+
"adapter",
|
|
20
|
+
"line",
|
|
21
|
+
"chatbot"
|
|
22
|
+
],
|
|
23
|
+
"author": {
|
|
24
|
+
"name": "lc-cn",
|
|
25
|
+
"email": "admin@liucl.cn",
|
|
26
|
+
"url": "https://github.com/lc-cn"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"url": "git+https://github.com/zhinjs/zhin.git",
|
|
31
|
+
"type": "git",
|
|
32
|
+
"directory": "plugins/adapters/line"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.9.2",
|
|
36
|
+
"typescript": "^6.0.3",
|
|
37
|
+
"@zhin.js/cli": "1.0.89",
|
|
38
|
+
"@zhin.js/host-api": "1.0.1",
|
|
39
|
+
"@zhin.js/host-router": "1.0.1",
|
|
40
|
+
"@zhin.js/logger": "0.1.71",
|
|
41
|
+
"zhin.js": "2.0.1"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@zhin.js/host-api": "1.0.1",
|
|
45
|
+
"@zhin.js/host-router": "1.0.1",
|
|
46
|
+
"@zhin.js/logger": "0.1.71",
|
|
47
|
+
"zhin.js": "2.0.1"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@zhin.js/host-router": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"@zhin.js/host-api": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"files": [
|
|
58
|
+
"src",
|
|
59
|
+
"lib",
|
|
60
|
+
"skills",
|
|
61
|
+
"plugin.yml",
|
|
62
|
+
"README.md",
|
|
63
|
+
"CHANGELOG.md"
|
|
64
|
+
],
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"access": "public",
|
|
67
|
+
"registry": "https://registry.npmjs.org"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "zhin build",
|
|
71
|
+
"clean": "rimraf lib dist",
|
|
72
|
+
"build:node": "tsc"
|
|
73
|
+
}
|
|
74
|
+
}
|
package/plugin.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# LINE 适配器权限说明
|
|
2
|
+
|
|
3
|
+
LINE Messaging API 适配器本身不涉及平台级权限检查(LINE 没有类似 Telegram 的 ChatMember 权限模型)。
|
|
4
|
+
|
|
5
|
+
## 平台权限
|
|
6
|
+
|
|
7
|
+
LINE 的权限模型通过 LINE Official Account Manager 管理,不在 bot 层面控制。
|
|
8
|
+
所有发消息权限由 Channel Access Token 的 scope 决定。
|
|
9
|
+
|
|
10
|
+
## 已知 scope
|
|
11
|
+
|
|
12
|
+
| scope | 说明 |
|
|
13
|
+
|-------|------|
|
|
14
|
+
| `message` | 发送消息(Reply + Push) |
|
|
15
|
+
| `profile` | 获取用户资料 |
|
|
16
|
+
|
|
17
|
+
如需额外权限,请在 LINE Developers Console 的 Messaging API 设置中启用。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: line
|
|
3
|
+
platforms:
|
|
4
|
+
- line
|
|
5
|
+
description: >-
|
|
6
|
+
LINE Messaging API 适配器技能。当用户在 LINE 私聊或群组中发送消息时,
|
|
7
|
+
框架通过 Webhook 接收并处理。支持文本、图片、视频、音频、文件、位置、贴纸
|
|
8
|
+
等消息类型。回复消息使用 Reply API(自动引用上下文),主动发送使用 Push API。
|
|
9
|
+
keywords:
|
|
10
|
+
- line
|
|
11
|
+
- adapter:line
|
|
12
|
+
- messaging-api
|
|
13
|
+
- webhook
|
|
14
|
+
tags:
|
|
15
|
+
- im
|
|
16
|
+
- adapter
|
|
17
|
+
---
|
|
18
|
+
# LINE Messaging API 技能
|
|
19
|
+
|
|
20
|
+
LINE 的 Messaging API 基于 Webhook 模式:平台将事件 POST 到指定 URL,适配器签名验证后处理。
|
|
21
|
+
|
|
22
|
+
## 消息接收
|
|
23
|
+
|
|
24
|
+
- 文本消息:直接转发为 text segment
|
|
25
|
+
- 媒体消息(image/video/audio/file):包含 message_id,可通过 Content API 获取
|
|
26
|
+
- 位置消息:包含经纬度和地址
|
|
27
|
+
- 贴纸消息:包含 packageId 和 stickerId
|
|
28
|
+
|
|
29
|
+
## 消息发送
|
|
30
|
+
|
|
31
|
+
- **Reply API**:有 replyToken 时自动使用,回复会关联原始消息
|
|
32
|
+
- **Push API**:无 replyToken 时使用,主动推送到 userId/groupId/roomId
|
|
33
|
+
- 单次最多 5 条消息,单条文本最多 5000 字符
|
|
34
|
+
|
|
35
|
+
## 限制
|
|
36
|
+
|
|
37
|
+
- 不支持消息撤回
|
|
38
|
+
- 不支持已读回执(read receipt)
|
|
39
|
+
- 媒体消息仅提供 message_id,需额外 API 调用获取内容
|
package/src/adapter.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LINE 适配器
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
Adapter,
|
|
6
|
+
Plugin,
|
|
7
|
+
} from "zhin.js";
|
|
8
|
+
import { LineEndpoint } from "./endpoint.js";
|
|
9
|
+
import type { LineEndpointConfig } from "./types.js";
|
|
10
|
+
import type { Router } from "@zhin.js/host-router/router";
|
|
11
|
+
|
|
12
|
+
export class LineAdapter extends Adapter<LineEndpoint> {
|
|
13
|
+
static override readonly capabilities = ['inbound', 'outbound'] as const;
|
|
14
|
+
|
|
15
|
+
#router: Router;
|
|
16
|
+
|
|
17
|
+
constructor(plugin: Plugin, router: Router) {
|
|
18
|
+
super(plugin, "line", []);
|
|
19
|
+
this.#router = router;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
createEndpoint(config: LineEndpointConfig): LineEndpoint {
|
|
23
|
+
return new LineEndpoint(this, this.#router, config);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async start(): Promise<void> {
|
|
27
|
+
await super.start();
|
|
28
|
+
}
|
|
29
|
+
}
|