cc-wechat 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/.claude-plugin/plugin.json +6 -0
- package/.mcp.json +8 -0
- package/.pace/stop-block-count +1 -0
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/auth.d.ts +18 -0
- package/dist/auth.js +351 -0
- package/dist/auth.js.map +1 -0
- package/dist/cdn.d.ts +39 -0
- package/dist/cdn.js +228 -0
- package/dist/cdn.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +127 -0
- package/dist/cli.js.map +1 -0
- package/dist/ilink-api.d.ts +33 -0
- package/dist/ilink-api.js +206 -0
- package/dist/ilink-api.js.map +1 -0
- package/dist/patch.d.ts +7 -0
- package/dist/patch.js +165 -0
- package/dist/patch.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +406 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +24 -0
- package/dist/store.js +57 -0
- package/dist/store.js.map +1 -0
- package/dist/text-utils.d.ts +7 -0
- package/dist/text-utils.js +56 -0
- package/dist/text-utils.js.map +1 -0
- package/dist/types.d.ts +98 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/package.json +24 -0
- package/packages/cc-channel-patch/README.md +36 -0
- package/packages/cc-channel-patch/index.mjs +228 -0
- package/packages/cc-channel-patch/package.json +11 -0
- package/skills/configure/SKILL.md +32 -0
- package/src/auth.ts +400 -0
- package/src/cdn.ts +261 -0
- package/src/cli.ts +121 -0
- package/src/ilink-api.ts +279 -0
- package/src/patch.ts +182 -0
- package/src/qrcode-terminal.d.ts +10 -0
- package/src/server.ts +445 -0
- package/src/store.ts +62 -0
- package/src/text-utils.ts +56 -0
- package/src/types.ts +94 -0
- package/tsconfig.json +17 -0
package/dist/cdn.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc-wechat CDN 媒体操作 — AES-128-ECB 加解密 + 上传/下载
|
|
3
|
+
*/
|
|
4
|
+
import * as crypto from 'node:crypto';
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as os from 'node:os';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { apiFetch, buildHeaders, getUploadUrl, buildBaseInfo } from './ilink-api.js';
|
|
9
|
+
const CDN_BASE_URL = 'https://novac2c.cdn.weixin.qq.com/c2c';
|
|
10
|
+
// ─── AES-128-ECB 加解密 ──────────────────────────────
|
|
11
|
+
/** AES-128-ECB 加密(PKCS7 padding 由 Node.js 自动处理) */
|
|
12
|
+
export function encryptAesEcb(plaintext, key) {
|
|
13
|
+
const cipher = crypto.createCipheriv('aes-128-ecb', key, null);
|
|
14
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
15
|
+
}
|
|
16
|
+
/** AES-128-ECB 解密 */
|
|
17
|
+
export function decryptAesEcb(ciphertext, key) {
|
|
18
|
+
const decipher = crypto.createDecipheriv('aes-128-ecb', key, null);
|
|
19
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
20
|
+
}
|
|
21
|
+
/** 计算 AES-ECB PKCS7 padding 后的密文大小 */
|
|
22
|
+
export function aesEcbPaddedSize(plaintextSize) {
|
|
23
|
+
return Math.ceil((plaintextSize + 1) / 16) * 16;
|
|
24
|
+
}
|
|
25
|
+
// ─── 文件类型检测 ─────────────────────────────────────
|
|
26
|
+
/** 通过文件头 magic bytes 检测扩展名 */
|
|
27
|
+
function detectExtByMagic(buf) {
|
|
28
|
+
if (buf.length < 4)
|
|
29
|
+
return '';
|
|
30
|
+
// JPEG: FF D8 FF
|
|
31
|
+
if (buf[0] === 0xFF && buf[1] === 0xD8 && buf[2] === 0xFF)
|
|
32
|
+
return '.jpg';
|
|
33
|
+
// PNG: 89 50 4E 47
|
|
34
|
+
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47)
|
|
35
|
+
return '.png';
|
|
36
|
+
// GIF: 47 49 46 38
|
|
37
|
+
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38)
|
|
38
|
+
return '.gif';
|
|
39
|
+
// BMP: 42 4D
|
|
40
|
+
if (buf[0] === 0x42 && buf[1] === 0x4D)
|
|
41
|
+
return '.bmp';
|
|
42
|
+
// WEBP: 52 49 46 46 ... 57 45 42 50
|
|
43
|
+
if (buf.length >= 12 && buf[0] === 0x52 && buf[1] === 0x49 && buf[8] === 0x57 && buf[9] === 0x45)
|
|
44
|
+
return '.webp';
|
|
45
|
+
// MP4: ... 66 74 79 70 (ftyp at offset 4)
|
|
46
|
+
if (buf.length >= 8 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70)
|
|
47
|
+
return '.mp4';
|
|
48
|
+
// PDF: 25 50 44 46
|
|
49
|
+
if (buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46)
|
|
50
|
+
return '.pdf';
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
/** 根据扩展名检测媒体类型:IMAGE=1, VIDEO=2, FILE=3 */
|
|
54
|
+
function detectMediaType(filePath) {
|
|
55
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
56
|
+
if (['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'].includes(ext))
|
|
57
|
+
return 1;
|
|
58
|
+
if (['.mp4', '.mov', '.avi', '.mkv'].includes(ext))
|
|
59
|
+
return 2;
|
|
60
|
+
return 3;
|
|
61
|
+
}
|
|
62
|
+
// ─── 上传媒体 ─────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* 上传媒体文件到微信 CDN 并发送消息
|
|
65
|
+
* @param params.token - Bot 认证 token
|
|
66
|
+
* @param params.toUser - 目标用户 ID
|
|
67
|
+
* @param params.contextToken - 会话上下文 token
|
|
68
|
+
* @param params.filePath - 本地文件路径
|
|
69
|
+
* @param params.baseUrl - iLink API 基址(可选)
|
|
70
|
+
* @param params.cdnBaseUrl - CDN 基址(可选)
|
|
71
|
+
*/
|
|
72
|
+
export async function uploadMedia(params) {
|
|
73
|
+
const { token, toUser, contextToken, filePath, baseUrl, cdnBaseUrl } = params;
|
|
74
|
+
// 1. 读取文件
|
|
75
|
+
const fileData = fs.readFileSync(filePath);
|
|
76
|
+
const rawsize = fileData.length;
|
|
77
|
+
const rawfilemd5 = crypto.createHash('md5').update(fileData).digest('hex');
|
|
78
|
+
// 2. 生成 AES key 并检测媒体类型
|
|
79
|
+
const aesKey = crypto.randomBytes(16);
|
|
80
|
+
const mediaType = detectMediaType(filePath);
|
|
81
|
+
// 3. 加密文件
|
|
82
|
+
const ciphertext = encryptAesEcb(fileData, aesKey);
|
|
83
|
+
// 4. 构造 filekey
|
|
84
|
+
const extname = path.extname(filePath);
|
|
85
|
+
const rand = crypto.randomBytes(3).toString('hex');
|
|
86
|
+
const filekey = `cc-wechat-${Date.now()}-${rand}${extname}`;
|
|
87
|
+
// 5. 获取上传地址
|
|
88
|
+
const uploadResp = await getUploadUrl(token, {
|
|
89
|
+
filekey,
|
|
90
|
+
media_type: mediaType,
|
|
91
|
+
to_user_id: toUser,
|
|
92
|
+
rawsize,
|
|
93
|
+
rawfilemd5,
|
|
94
|
+
filesize: ciphertext.length,
|
|
95
|
+
no_need_thumb: true,
|
|
96
|
+
aeskey: aesKey.toString('hex'),
|
|
97
|
+
base_info: buildBaseInfo(),
|
|
98
|
+
}, baseUrl);
|
|
99
|
+
const uploadParam = uploadResp.upload_param ?? '';
|
|
100
|
+
const serverFilekey = uploadResp.filekey ?? filekey;
|
|
101
|
+
// 6. 上传到 CDN
|
|
102
|
+
const cdnUrl = `${cdnBaseUrl ?? CDN_BASE_URL}/upload` +
|
|
103
|
+
`?encrypted_query_param=${encodeURIComponent(uploadParam)}` +
|
|
104
|
+
`&filekey=${encodeURIComponent(serverFilekey)}`;
|
|
105
|
+
const authHeaders = buildHeaders(token);
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const timer = setTimeout(() => controller.abort(), 60_000);
|
|
108
|
+
let downloadParam;
|
|
109
|
+
try {
|
|
110
|
+
const cdnResp = await fetch(cdnUrl, {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers: {
|
|
113
|
+
...authHeaders,
|
|
114
|
+
'Content-Type': 'application/octet-stream',
|
|
115
|
+
},
|
|
116
|
+
body: new Uint8Array(ciphertext),
|
|
117
|
+
signal: controller.signal,
|
|
118
|
+
});
|
|
119
|
+
if (!cdnResp.ok) {
|
|
120
|
+
const errText = await cdnResp.text();
|
|
121
|
+
throw new Error(`[uploadMedia] CDN HTTP ${cdnResp.status}: ${errText}`);
|
|
122
|
+
}
|
|
123
|
+
downloadParam = cdnResp.headers.get('x-encrypted-param') ?? '';
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
}
|
|
128
|
+
// 7. 构造媒体信息
|
|
129
|
+
const aesKeyBase64 = Buffer.from(aesKey.toString('hex')).toString('base64');
|
|
130
|
+
const mediaInfo = {
|
|
131
|
+
encrypt_query_param: downloadParam,
|
|
132
|
+
aes_key: aesKeyBase64,
|
|
133
|
+
encrypt_type: 1,
|
|
134
|
+
};
|
|
135
|
+
// 8. 根据媒体类型构造 MessageItem
|
|
136
|
+
let mediaItem;
|
|
137
|
+
if (mediaType === 1) {
|
|
138
|
+
// 图片
|
|
139
|
+
mediaItem = { type: 2, image_item: { media: mediaInfo, mid_size: ciphertext.length } };
|
|
140
|
+
}
|
|
141
|
+
else if (mediaType === 2) {
|
|
142
|
+
// 视频
|
|
143
|
+
mediaItem = { type: 5, video_item: { media: mediaInfo, video_size: ciphertext.length } };
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// 文件
|
|
147
|
+
mediaItem = {
|
|
148
|
+
type: 4,
|
|
149
|
+
file_item: {
|
|
150
|
+
media: mediaInfo,
|
|
151
|
+
file_name: path.basename(filePath),
|
|
152
|
+
len: String(rawsize),
|
|
153
|
+
md5: rawfilemd5,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// 9. 发送消息
|
|
158
|
+
const clientId = `cc-wechat-${crypto.randomBytes(4).toString('hex')}`;
|
|
159
|
+
const body = JSON.stringify({
|
|
160
|
+
msg: {
|
|
161
|
+
from_user_id: '',
|
|
162
|
+
to_user_id: toUser,
|
|
163
|
+
client_id: clientId,
|
|
164
|
+
message_type: 2,
|
|
165
|
+
message_state: 2,
|
|
166
|
+
item_list: [mediaItem],
|
|
167
|
+
context_token: contextToken,
|
|
168
|
+
},
|
|
169
|
+
base_info: buildBaseInfo(),
|
|
170
|
+
});
|
|
171
|
+
await apiFetch({
|
|
172
|
+
baseUrl,
|
|
173
|
+
endpoint: 'ilink/bot/sendmessage',
|
|
174
|
+
body,
|
|
175
|
+
token,
|
|
176
|
+
timeoutMs: 10_000,
|
|
177
|
+
label: 'uploadMedia',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// ─── 下载媒体 ─────────────────────────────────────────
|
|
181
|
+
/**
|
|
182
|
+
* 从微信 CDN 下载并解密媒体文件
|
|
183
|
+
* @param params.encryptQueryParam - CDN 加密查询参数
|
|
184
|
+
* @param params.aesKeyBase64 - Base64 编码的 AES key
|
|
185
|
+
* @param params.cdnBaseUrl - CDN 基址(可选)
|
|
186
|
+
* @param params.outDir - 输出目录(可选,默认临时目录)
|
|
187
|
+
* @param params.fileName - 输出文件名(可选)
|
|
188
|
+
* @returns 文件绝对路径
|
|
189
|
+
*/
|
|
190
|
+
export async function downloadMedia(params) {
|
|
191
|
+
const { encryptQueryParam, aesKeyBase64, cdnBaseUrl, outDir, fileName } = params;
|
|
192
|
+
// 1. 构造下载 URL
|
|
193
|
+
const downloadUrl = `${cdnBaseUrl ?? CDN_BASE_URL}/download` +
|
|
194
|
+
`?encrypted_query_param=${encodeURIComponent(encryptQueryParam)}`;
|
|
195
|
+
// 2. 下载密文
|
|
196
|
+
const controller = new AbortController();
|
|
197
|
+
const timer = setTimeout(() => controller.abort(), 60_000);
|
|
198
|
+
let ciphertext;
|
|
199
|
+
try {
|
|
200
|
+
const resp = await fetch(downloadUrl, { signal: controller.signal });
|
|
201
|
+
if (!resp.ok) {
|
|
202
|
+
const errText = await resp.text();
|
|
203
|
+
throw new Error(`[downloadMedia] CDN HTTP ${resp.status}: ${errText}`);
|
|
204
|
+
}
|
|
205
|
+
ciphertext = Buffer.from(await resp.arrayBuffer());
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
clearTimeout(timer);
|
|
209
|
+
}
|
|
210
|
+
// 3. 解码 AES key(base64 → hex string → 16 字节 key)
|
|
211
|
+
const hexStr = Buffer.from(aesKeyBase64, 'base64').toString('utf-8');
|
|
212
|
+
const aesKey = Buffer.from(hexStr, 'hex');
|
|
213
|
+
// 4. 解密
|
|
214
|
+
const plaintext = decryptAesEcb(ciphertext, aesKey);
|
|
215
|
+
// 5. 通过文件头检测类型并加后缀
|
|
216
|
+
const ext = detectExtByMagic(plaintext);
|
|
217
|
+
const targetDir = outDir ?? path.join(os.tmpdir(), 'cc-wechat', 'media');
|
|
218
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
219
|
+
let targetName = fileName ?? `media-${Date.now()}`;
|
|
220
|
+
// 如果文件名没有后缀,根据 magic bytes 补上
|
|
221
|
+
if (!path.extname(targetName) && ext) {
|
|
222
|
+
targetName += ext;
|
|
223
|
+
}
|
|
224
|
+
const targetPath = path.join(targetDir, targetName);
|
|
225
|
+
fs.writeFileSync(targetPath, plaintext);
|
|
226
|
+
return path.resolve(targetPath);
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=cdn.js.map
|
package/dist/cdn.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* cc-wechat CLI 入口 — install/login/status/help 命令
|
|
4
|
+
*/
|
|
5
|
+
import { execSync } from 'node:child_process';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { loginTerminal } from './auth.js';
|
|
9
|
+
import { saveAccount, getActiveAccount } from './store.js';
|
|
10
|
+
// ─── help ────────────────────────────────────────────
|
|
11
|
+
/** 打印帮助信息 */
|
|
12
|
+
function help() {
|
|
13
|
+
console.log(`
|
|
14
|
+
cc-wechat — 微信 Claude Code Channel 插件
|
|
15
|
+
|
|
16
|
+
用法: npx cc-wechat <命令>
|
|
17
|
+
|
|
18
|
+
命令:
|
|
19
|
+
install 注册 MCP server + 扫码登录
|
|
20
|
+
patch 修补 Claude Code 以启用 Channels 功能
|
|
21
|
+
unpatch 恢复原始 Claude Code
|
|
22
|
+
login 重新扫码登录
|
|
23
|
+
status 查看连接状态
|
|
24
|
+
help 显示帮助
|
|
25
|
+
`);
|
|
26
|
+
}
|
|
27
|
+
// ─── install ─────────────────────────────────────────
|
|
28
|
+
/** 注册 MCP server + 扫码登录 */
|
|
29
|
+
async function install() {
|
|
30
|
+
console.log('\n🔧 cc-wechat 安装向导\n');
|
|
31
|
+
// [1/3] 注册 MCP server
|
|
32
|
+
console.log('[1/3] 注册 MCP server...');
|
|
33
|
+
const serverPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'server.js');
|
|
34
|
+
try {
|
|
35
|
+
execSync('claude mcp add -s user wechat-channel node ' + serverPath, { stdio: 'pipe' });
|
|
36
|
+
console.log(' ✅ MCP server 已注册');
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
try {
|
|
40
|
+
execSync('claude mcp remove wechat-channel', { stdio: 'pipe' });
|
|
41
|
+
execSync('claude mcp add -s user wechat-channel node ' + serverPath, { stdio: 'pipe' });
|
|
42
|
+
console.log(' ✅ MCP server 已重新注册');
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
console.error(' ❌ MCP server 注册失败:', e.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// [2/3] 微信扫码登录
|
|
49
|
+
console.log('\n[2/3] 微信扫码登录...');
|
|
50
|
+
const existing = getActiveAccount();
|
|
51
|
+
if (existing) {
|
|
52
|
+
console.log(' ⏭️ 已有登录账号,跳过扫码。如需重新登录请运行: npx cc-wechat login');
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const { token, accountId, baseUrl } = await loginTerminal();
|
|
56
|
+
saveAccount({
|
|
57
|
+
token,
|
|
58
|
+
baseUrl: baseUrl ?? '',
|
|
59
|
+
botId: accountId.replace(/@/g, '-').replace(/\./g, '-'),
|
|
60
|
+
savedAt: new Date().toISOString(),
|
|
61
|
+
});
|
|
62
|
+
console.log(' ✅ 登录成功');
|
|
63
|
+
}
|
|
64
|
+
// [3/3] 完成
|
|
65
|
+
console.log('\n[3/3] 安装完成!');
|
|
66
|
+
console.log('\n启动 Claude Code 时使用:');
|
|
67
|
+
console.log(' claude --dangerously-load-development-channels server:wechat-channel\n');
|
|
68
|
+
}
|
|
69
|
+
// ─── login ───────────────────────────────────────────
|
|
70
|
+
/** 重新扫码登录 */
|
|
71
|
+
async function login() {
|
|
72
|
+
console.log('\n🔑 微信扫码登录\n');
|
|
73
|
+
const { token, accountId, baseUrl } = await loginTerminal();
|
|
74
|
+
saveAccount({
|
|
75
|
+
token,
|
|
76
|
+
baseUrl: baseUrl ?? '',
|
|
77
|
+
botId: accountId.replace(/@/g, '-').replace(/\./g, '-'),
|
|
78
|
+
savedAt: new Date().toISOString(),
|
|
79
|
+
});
|
|
80
|
+
console.log('\n✅ 登录成功!账号已保存。\n');
|
|
81
|
+
}
|
|
82
|
+
// ─── status ──────────────────────────────────────────
|
|
83
|
+
/** 查看连接状态 */
|
|
84
|
+
function status() {
|
|
85
|
+
const account = getActiveAccount();
|
|
86
|
+
if (account) {
|
|
87
|
+
console.log('\n📋 当前账号状态:\n');
|
|
88
|
+
console.log(` botId: ${account.botId.substring(0, 12)}...`);
|
|
89
|
+
console.log(` baseUrl: ${account.baseUrl}`);
|
|
90
|
+
console.log(` savedAt: ${account.savedAt}\n`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.log('\n❌ 尚未登录。请运行: npx cc-wechat install\n');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ─── main ────────────────────────────────────────────
|
|
97
|
+
const command = process.argv[2];
|
|
98
|
+
switch (command) {
|
|
99
|
+
case 'install':
|
|
100
|
+
case 'setup':
|
|
101
|
+
install();
|
|
102
|
+
break;
|
|
103
|
+
case 'login':
|
|
104
|
+
login();
|
|
105
|
+
break;
|
|
106
|
+
case 'patch':
|
|
107
|
+
case 'unpatch': {
|
|
108
|
+
// 动态导入 patch 模块,传递命令
|
|
109
|
+
process.argv[2] = command;
|
|
110
|
+
await import('./patch.js');
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'status':
|
|
114
|
+
status();
|
|
115
|
+
break;
|
|
116
|
+
case 'help':
|
|
117
|
+
case '--help':
|
|
118
|
+
case '-h':
|
|
119
|
+
case undefined:
|
|
120
|
+
help();
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
console.error(`未知命令: ${command}`);
|
|
124
|
+
help();
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { BaseInfo, QRCodeResponse, QRStatusResponse, GetUpdatesResp, GetConfigResp, GetUploadUrlResp } from './types.js';
|
|
2
|
+
export declare const DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
3
|
+
/** 构造 base_info 通用字段 */
|
|
4
|
+
export declare function buildBaseInfo(): BaseInfo;
|
|
5
|
+
/** 生成随机 wechat uin(4 字节随机数 → 十进制 → base64) */
|
|
6
|
+
export declare function randomWechatUin(): string;
|
|
7
|
+
/** 构造请求头 */
|
|
8
|
+
export declare function buildHeaders(token?: string, body?: string): Record<string, string>;
|
|
9
|
+
/** 通用 HTTP 请求 */
|
|
10
|
+
export declare function apiFetch(params: {
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
endpoint: string;
|
|
13
|
+
body?: string;
|
|
14
|
+
token?: string;
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
label: string;
|
|
17
|
+
method?: string;
|
|
18
|
+
extraHeaders?: Record<string, string>;
|
|
19
|
+
}): Promise<string>;
|
|
20
|
+
/** 获取登录二维码 */
|
|
21
|
+
export declare function getQRCode(baseUrl?: string): Promise<QRCodeResponse>;
|
|
22
|
+
/** 轮询二维码扫描状态(长轮询,35s 超时) */
|
|
23
|
+
export declare function pollQRStatus(qrcode: string, baseUrl?: string): Promise<QRStatusResponse>;
|
|
24
|
+
/** 长轮询获取新消息 */
|
|
25
|
+
export declare function getUpdates(token: string, buf: string, baseUrl?: string, timeoutMs?: number): Promise<GetUpdatesResp>;
|
|
26
|
+
/** 发送文本消息,返回 client_id */
|
|
27
|
+
export declare function sendMessage(token: string, to: string, text: string, contextToken: string, baseUrl?: string): Promise<string>;
|
|
28
|
+
/** 发送输入状态指示 */
|
|
29
|
+
export declare function sendTyping(token: string, userId: string, ticket: string, status: number, baseUrl?: string): Promise<void>;
|
|
30
|
+
/** 获取配置(typing ticket 等) */
|
|
31
|
+
export declare function getConfig(token: string, userId: string, contextToken?: string, baseUrl?: string): Promise<GetConfigResp>;
|
|
32
|
+
/** 获取文件上传地址 */
|
|
33
|
+
export declare function getUploadUrl(token: string, params: Record<string, unknown>, baseUrl?: string): Promise<GetUploadUrlResp>;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cc-wechat iLink Bot API 封装 — 7 个 HTTP API
|
|
3
|
+
*/
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
5
|
+
// 默认 iLink 服务地址
|
|
6
|
+
export const DEFAULT_BASE_URL = 'https://ilinkai.weixin.qq.com';
|
|
7
|
+
const DEFAULT_BOT_TYPE = '3';
|
|
8
|
+
const LONG_POLL_TIMEOUT_MS = 35_000;
|
|
9
|
+
/** 构造 base_info 通用字段 */
|
|
10
|
+
export function buildBaseInfo() {
|
|
11
|
+
return { channel_version: '0.1.0' };
|
|
12
|
+
}
|
|
13
|
+
/** 生成随机 wechat uin(4 字节随机数 → 十进制 → base64) */
|
|
14
|
+
export function randomWechatUin() {
|
|
15
|
+
const num = randomBytes(4).readUInt32BE(0);
|
|
16
|
+
const str = num.toString(10);
|
|
17
|
+
return Buffer.from(str, 'utf-8').toString('base64');
|
|
18
|
+
}
|
|
19
|
+
/** 构造请求头 */
|
|
20
|
+
export function buildHeaders(token, body) {
|
|
21
|
+
const headers = {
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
'AuthorizationType': 'ilink_bot_token',
|
|
24
|
+
'X-WECHAT-UIN': randomWechatUin(),
|
|
25
|
+
};
|
|
26
|
+
if (token) {
|
|
27
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
28
|
+
}
|
|
29
|
+
if (body) {
|
|
30
|
+
headers['Content-Length'] = String(Buffer.byteLength(body, 'utf-8'));
|
|
31
|
+
}
|
|
32
|
+
return headers;
|
|
33
|
+
}
|
|
34
|
+
/** 通用 HTTP 请求 */
|
|
35
|
+
export async function apiFetch(params) {
|
|
36
|
+
const { endpoint, body, token, timeoutMs, label, method = 'POST', } = params;
|
|
37
|
+
// 确保 base URL 末尾有 /
|
|
38
|
+
let base = params.baseUrl ?? DEFAULT_BASE_URL;
|
|
39
|
+
if (!base.endsWith('/'))
|
|
40
|
+
base += '/';
|
|
41
|
+
const url = `${base}${endpoint}`;
|
|
42
|
+
const isGet = method === 'GET';
|
|
43
|
+
// GET 请求不传 body 和 Content-Type/Content-Length
|
|
44
|
+
const headers = isGet
|
|
45
|
+
? {
|
|
46
|
+
'AuthorizationType': 'ilink_bot_token',
|
|
47
|
+
'X-WECHAT-UIN': randomWechatUin(),
|
|
48
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
49
|
+
}
|
|
50
|
+
: buildHeaders(token, body);
|
|
51
|
+
// 合并额外请求头
|
|
52
|
+
if (params.extraHeaders) {
|
|
53
|
+
Object.assign(headers, params.extraHeaders);
|
|
54
|
+
}
|
|
55
|
+
const controller = new AbortController();
|
|
56
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
57
|
+
try {
|
|
58
|
+
const resp = await fetch(url, {
|
|
59
|
+
method,
|
|
60
|
+
headers,
|
|
61
|
+
...(isGet ? {} : { body }),
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
});
|
|
64
|
+
const text = await resp.text();
|
|
65
|
+
if (!resp.ok) {
|
|
66
|
+
throw new Error(`[${label}] HTTP ${resp.status}: ${text}`);
|
|
67
|
+
}
|
|
68
|
+
return text;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ─── QR 登录 API(GET 请求) ─────────────────────────
|
|
75
|
+
/** 获取登录二维码 */
|
|
76
|
+
export async function getQRCode(baseUrl) {
|
|
77
|
+
const text = await apiFetch({
|
|
78
|
+
baseUrl,
|
|
79
|
+
endpoint: `ilink/bot/get_bot_qrcode?bot_type=${DEFAULT_BOT_TYPE}`,
|
|
80
|
+
timeoutMs: 10_000,
|
|
81
|
+
label: 'getQRCode',
|
|
82
|
+
method: 'GET',
|
|
83
|
+
});
|
|
84
|
+
return JSON.parse(text);
|
|
85
|
+
}
|
|
86
|
+
/** 轮询二维码扫描状态(长轮询,35s 超时) */
|
|
87
|
+
export async function pollQRStatus(qrcode, baseUrl) {
|
|
88
|
+
try {
|
|
89
|
+
const text = await apiFetch({
|
|
90
|
+
baseUrl,
|
|
91
|
+
endpoint: `ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`,
|
|
92
|
+
timeoutMs: LONG_POLL_TIMEOUT_MS,
|
|
93
|
+
label: 'pollQRStatus',
|
|
94
|
+
method: 'GET',
|
|
95
|
+
extraHeaders: { 'iLink-App-ClientVersion': '1' },
|
|
96
|
+
});
|
|
97
|
+
return JSON.parse(text);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
101
|
+
return { status: 'wait' };
|
|
102
|
+
}
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// ─── 消息 API(POST 请求) ───────────────────────────
|
|
107
|
+
/** 长轮询获取新消息 */
|
|
108
|
+
export async function getUpdates(token, buf, baseUrl, timeoutMs) {
|
|
109
|
+
const body = JSON.stringify({
|
|
110
|
+
get_updates_buf: buf,
|
|
111
|
+
base_info: buildBaseInfo(),
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
const text = await apiFetch({
|
|
115
|
+
baseUrl,
|
|
116
|
+
endpoint: 'ilink/bot/getupdates',
|
|
117
|
+
body,
|
|
118
|
+
token,
|
|
119
|
+
timeoutMs: timeoutMs ?? LONG_POLL_TIMEOUT_MS,
|
|
120
|
+
label: 'getUpdates',
|
|
121
|
+
});
|
|
122
|
+
return JSON.parse(text);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
126
|
+
return { ret: 0, msgs: [], get_updates_buf: buf };
|
|
127
|
+
}
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** 发送文本消息,返回 client_id */
|
|
132
|
+
export async function sendMessage(token, to, text, contextToken, baseUrl) {
|
|
133
|
+
const clientId = `cc-wechat-${randomBytes(4).toString('hex')}`;
|
|
134
|
+
const body = JSON.stringify({
|
|
135
|
+
msg: {
|
|
136
|
+
from_user_id: '',
|
|
137
|
+
to_user_id: to,
|
|
138
|
+
client_id: clientId,
|
|
139
|
+
message_type: 2,
|
|
140
|
+
message_state: 2,
|
|
141
|
+
item_list: [{ type: 1, text_item: { text } }],
|
|
142
|
+
context_token: contextToken,
|
|
143
|
+
},
|
|
144
|
+
base_info: buildBaseInfo(),
|
|
145
|
+
});
|
|
146
|
+
await apiFetch({
|
|
147
|
+
baseUrl,
|
|
148
|
+
endpoint: 'ilink/bot/sendmessage',
|
|
149
|
+
body,
|
|
150
|
+
token,
|
|
151
|
+
timeoutMs: 10_000,
|
|
152
|
+
label: 'sendMessage',
|
|
153
|
+
});
|
|
154
|
+
return clientId;
|
|
155
|
+
}
|
|
156
|
+
/** 发送输入状态指示 */
|
|
157
|
+
export async function sendTyping(token, userId, ticket, status, baseUrl) {
|
|
158
|
+
const body = JSON.stringify({
|
|
159
|
+
user_id: userId,
|
|
160
|
+
typing_ticket: ticket,
|
|
161
|
+
typing_status: status,
|
|
162
|
+
base_info: buildBaseInfo(),
|
|
163
|
+
});
|
|
164
|
+
await apiFetch({
|
|
165
|
+
baseUrl,
|
|
166
|
+
endpoint: 'ilink/bot/sendtyping',
|
|
167
|
+
body,
|
|
168
|
+
token,
|
|
169
|
+
timeoutMs: 5_000,
|
|
170
|
+
label: 'sendTyping',
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/** 获取配置(typing ticket 等) */
|
|
174
|
+
export async function getConfig(token, userId, contextToken, baseUrl) {
|
|
175
|
+
const body = JSON.stringify({
|
|
176
|
+
user_id: userId,
|
|
177
|
+
...(contextToken ? { context_token: contextToken } : {}),
|
|
178
|
+
base_info: buildBaseInfo(),
|
|
179
|
+
});
|
|
180
|
+
const text = await apiFetch({
|
|
181
|
+
baseUrl,
|
|
182
|
+
endpoint: 'ilink/bot/getconfig',
|
|
183
|
+
body,
|
|
184
|
+
token,
|
|
185
|
+
timeoutMs: 10_000,
|
|
186
|
+
label: 'getConfig',
|
|
187
|
+
});
|
|
188
|
+
return JSON.parse(text);
|
|
189
|
+
}
|
|
190
|
+
/** 获取文件上传地址 */
|
|
191
|
+
export async function getUploadUrl(token, params, baseUrl) {
|
|
192
|
+
const body = JSON.stringify({
|
|
193
|
+
...params,
|
|
194
|
+
base_info: buildBaseInfo(),
|
|
195
|
+
});
|
|
196
|
+
const text = await apiFetch({
|
|
197
|
+
baseUrl,
|
|
198
|
+
endpoint: 'ilink/bot/getuploadurl',
|
|
199
|
+
body,
|
|
200
|
+
token,
|
|
201
|
+
timeoutMs: 10_000,
|
|
202
|
+
label: 'getUploadUrl',
|
|
203
|
+
});
|
|
204
|
+
return JSON.parse(text);
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=ilink-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ilink-api.js","sourceRoot":"","sources":["../src/ilink-api.ts"],"names":[],"mappings":"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"}
|