@tencent-connect/dsh-qqbot 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/CHANGELOG_EN.md +11 -0
  3. package/README.md +12 -1
  4. package/dist/commands/help.d.ts +1 -1
  5. package/dist/commands/help.js +1 -1
  6. package/dist/config.d.ts +2 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +10 -8
  9. package/dist/config.js.map +1 -1
  10. package/dist/gateway/bootstrap.d.ts.map +1 -1
  11. package/dist/gateway/bootstrap.js +10 -0
  12. package/dist/gateway/bootstrap.js.map +1 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +41 -22
  16. package/dist/index.js.map +1 -1
  17. package/dist/setup/bind-routes.d.ts +78 -0
  18. package/dist/setup/bind-routes.d.ts.map +1 -0
  19. package/dist/setup/bind-routes.js +311 -0
  20. package/dist/setup/bind-routes.js.map +1 -0
  21. package/dist/setup/binding-service.d.ts +86 -0
  22. package/dist/setup/binding-service.d.ts.map +1 -0
  23. package/dist/setup/binding-service.js +175 -0
  24. package/dist/setup/binding-service.js.map +1 -0
  25. package/dist/setup/index.d.ts +50 -0
  26. package/dist/setup/index.d.ts.map +1 -0
  27. package/dist/setup/index.js +98 -0
  28. package/dist/setup/index.js.map +1 -0
  29. package/dist/setup/persist.d.ts +41 -0
  30. package/dist/setup/persist.d.ts.map +1 -0
  31. package/dist/setup/persist.js +201 -0
  32. package/dist/setup/persist.js.map +1 -0
  33. package/dist/setup/presenters.d.ts +40 -0
  34. package/dist/setup/presenters.d.ts.map +1 -0
  35. package/dist/setup/presenters.js +84 -0
  36. package/dist/setup/presenters.js.map +1 -0
  37. package/dist/setup/qr-svg.d.ts +8 -0
  38. package/dist/setup/qr-svg.d.ts.map +1 -0
  39. package/dist/setup/qr-svg.js +20 -0
  40. package/dist/setup/qr-svg.js.map +1 -0
  41. package/dist/shared/bind-protocol.d.ts +42 -0
  42. package/dist/shared/bind-protocol.d.ts.map +1 -0
  43. package/dist/shared/bind-protocol.js +19 -0
  44. package/dist/shared/bind-protocol.js.map +1 -0
  45. package/dist/shared/utils.d.ts +8 -3
  46. package/dist/shared/utils.d.ts.map +1 -1
  47. package/dist/shared/utils.js +45 -4
  48. package/dist/shared/utils.js.map +1 -1
  49. package/dist/transport/reply-limiter.d.ts +1 -1
  50. package/dist/transport/reply-limiter.js +1 -1
  51. package/lib/client.js +996 -0
  52. package/lib/client.js.map +1 -0
  53. package/package.json +25 -5
  54. package/pnpm-workspace.yaml +1 -0
  55. package/tsconfig.client.json +19 -0
  56. package/tsdown.client.config.ts +58 -0
  57. package/dist/setup.d.ts +0 -24
  58. package/dist/setup.d.ts.map +0 -1
  59. package/dist/setup.js +0 -170
  60. package/dist/setup.js.map +0 -1
@@ -0,0 +1,311 @@
1
+ import { persistCredentialsToProfile, removeCredentialsFromProfile, updateProfileConfig, } from "./persist.js";
2
+ import { getProfileDir } from "../shared/index.js";
3
+ import { AccessControlSchema } from "../config.js";
4
+ import { BIND_CONFIG_PATH, BIND_MANUAL_PATH, BIND_REFRESH_PATH, BIND_STATE_PATH, BIND_UNBIND_PATH, } from "../shared/bind-protocol.js";
5
+ // 协议单一来源:shared/bind-protocol.ts(类型 + 路径常量,客户端共用)
6
+ export { BIND_CONFIG_PATH, BIND_MANUAL_PATH, BIND_REFRESH_PATH, BIND_STATE_PATH, BIND_UNBIND_PATH };
7
+ /** 可经 UI 编辑的配置键(白名单:只收用户必要的字段,其余走 patch/env) */
8
+ const EDITABLE_CONFIG_KEYS = new Set([
9
+ 'requireMention', 'streaming', 'showToolResults', 'debug',
10
+ 'provider', 'model', 'preset',
11
+ 'groupPrompt', 'directPrompt',
12
+ 'access',
13
+ ]);
14
+ /** 白名单键的子 Schema(服务端校验:客户端校验仅为体验,安全边界在宿主) */
15
+ const EDITABLE_CONFIG_SCHEMAS = {
16
+ requireMention: (v) => booleanSchema(v, 'requireMention'),
17
+ streaming: (v) => booleanSchema(v, 'streaming'),
18
+ showToolResults: (v) => booleanSchema(v, 'showToolResults'),
19
+ debug: (v) => booleanSchema(v, 'debug'),
20
+ provider: stringSchema('provider'),
21
+ model: stringSchema('model'),
22
+ preset: stringSchema('preset'),
23
+ groupPrompt: stringSchema('groupPrompt'),
24
+ directPrompt: stringSchema('directPrompt'),
25
+ access: (v) => AccessControlSchema(v),
26
+ };
27
+ function booleanSchema(value, name) {
28
+ if (typeof value !== 'boolean')
29
+ throw new TypeError(`${name} 必须是布尔值`);
30
+ return value;
31
+ }
32
+ function stringSchema(name) {
33
+ return (value) => {
34
+ if (typeof value !== 'string')
35
+ throw new TypeError(`${name} 必须是字符串`);
36
+ if (value.length > 20000)
37
+ throw new TypeError(`${name} 过长`);
38
+ return value;
39
+ };
40
+ }
41
+ /** manual 请求体大小上限(appId + appSecret 远小于此值) */
42
+ const MAX_MANUAL_BODY_BYTES = 4096;
43
+ /**
44
+ * 注册绑定路由(状态查询 / 刷新二维码 / 手动凭据)。
45
+ *
46
+ * @param webServer - ctx.webServer
47
+ * @param service - 绑定状态机;已绑定 fiber 传 null(无扫码流程)
48
+ * @param logger - 日志
49
+ * @param options - 行为注入(bound 态回显、manual 处理)
50
+ * @returns 注销函数(与插件 fiber 生命周期绑定)
51
+ */
52
+ export function registerBindRoutes(webServer, service, logger, options = {}) {
53
+ const defaultManual = (credentials) => {
54
+ const persisted = persistCredentialsToProfile(credentials, getProfileDir() ?? undefined, logger);
55
+ return persisted ? { persisted: true } : { persisted: false, error: '无法定位 profile 目录或写入失败,请改用环境变量配置' };
56
+ };
57
+ const handleManualSubmit = options.onManualCredentials ?? defaultManual;
58
+ const disposers = [
59
+ webServer.register({
60
+ kind: 'exact',
61
+ path: BIND_STATE_PATH,
62
+ handler: (req, res) => { handleState(req, res, service, options); },
63
+ }),
64
+ webServer.register({
65
+ kind: 'exact',
66
+ path: BIND_REFRESH_PATH,
67
+ handler: (req, res) => { handleRefresh(req, res, service); },
68
+ }),
69
+ webServer.register({
70
+ kind: 'exact',
71
+ path: BIND_MANUAL_PATH,
72
+ handler: (req, res) => handleManual(req, res, handleManualSubmit),
73
+ }),
74
+ webServer.register({
75
+ kind: 'exact',
76
+ path: BIND_UNBIND_PATH,
77
+ handler: (req, res) => handleUnbind(req, res, options),
78
+ }),
79
+ webServer.register({
80
+ kind: 'exact',
81
+ path: BIND_CONFIG_PATH,
82
+ handler: (req, res) => handleConfig(req, res, options),
83
+ }),
84
+ ];
85
+ logger.info(`im-qqbot: 端内绑定页已就绪: ${BIND_STATE_PATH}`);
86
+ return () => { for (const dispose of disposers)
87
+ dispose(); };
88
+ }
89
+ /**
90
+ * 请求来源校验(最小 CSRF 防护)。
91
+ *
92
+ * 带 Origin 的请求必须与 Host 同源;同源 fetch 与 Desktop IPC 桥
93
+ * (后者会删除 origin 头)均放行。本路由数据不敏感且动作无害,
94
+ * 该级别的防护足够。
95
+ */
96
+ function trusted(req) {
97
+ const origin = req.headers.origin;
98
+ if (origin === undefined)
99
+ return true;
100
+ try {
101
+ return new URL(origin).host === req.headers.host;
102
+ }
103
+ catch {
104
+ return false;
105
+ }
106
+ }
107
+ function sendJson(res, status, body) {
108
+ const payload = JSON.stringify(body);
109
+ res.writeHead(status, {
110
+ 'content-type': 'application/json; charset=utf-8',
111
+ 'cache-control': 'no-store',
112
+ });
113
+ res.end(payload);
114
+ }
115
+ function handleState(req, res, service, options) {
116
+ if (!trusted(req)) {
117
+ sendJson(res, 403, { error: 'forbidden' });
118
+ return;
119
+ }
120
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
121
+ sendJson(res, 405, { error: 'method not allowed' });
122
+ return;
123
+ }
124
+ // 已绑定优先(appSecret 不回传,appId 非机密可回显)
125
+ const boundAppId = options.boundAppId?.() ?? null;
126
+ if (boundAppId !== null) {
127
+ sendJson(res, 200, { phase: 'bound', appId: boundAppId });
128
+ return;
129
+ }
130
+ sendJson(res, 200, service === null ? { phase: 'starting' } : service.wireState());
131
+ }
132
+ function handleRefresh(req, res, service) {
133
+ if (!trusted(req)) {
134
+ sendJson(res, 403, { error: 'forbidden' });
135
+ return;
136
+ }
137
+ if (req.method !== 'POST') {
138
+ sendJson(res, 405, { error: 'method not allowed' });
139
+ return;
140
+ }
141
+ // 丢弃可能的请求体(refresh 无参数)
142
+ req.resume();
143
+ service?.refresh();
144
+ // 新二维码异步生成,统一由状态轮询收敛
145
+ sendJson(res, 200, { phase: 'starting' });
146
+ }
147
+ /** 读取并解析 JSON 请求体(带大小上限) */
148
+ async function readJsonBody(req) {
149
+ const chunks = [];
150
+ let size = 0;
151
+ for await (const chunk of req) {
152
+ const buffer = chunk;
153
+ size += buffer.length;
154
+ if (size > MAX_MANUAL_BODY_BYTES)
155
+ throw new Error('request body too large');
156
+ chunks.push(buffer);
157
+ }
158
+ if (size === 0)
159
+ throw new Error('empty request body');
160
+ return JSON.parse(Buffer.concat(chunks).toString('utf8'));
161
+ }
162
+ /** 校验手动提交的凭据形态(不打印内容) */
163
+ function parseCredentials(body) {
164
+ if (typeof body !== 'object' || body === null)
165
+ return null;
166
+ const record = body;
167
+ const appId = typeof record.appId === 'string' ? record.appId.trim() : '';
168
+ const appSecret = typeof record.appSecret === 'string' ? record.appSecret.trim() : '';
169
+ if (appId.length === 0 || appSecret.length === 0)
170
+ return null;
171
+ if (appId.length > 128 || appSecret.length > 256)
172
+ return null;
173
+ return { appId, appSecret };
174
+ }
175
+ async function handleManual(req, res, submit) {
176
+ if (!trusted(req)) {
177
+ sendJson(res, 403, { error: 'forbidden' });
178
+ return;
179
+ }
180
+ if (req.method !== 'POST') {
181
+ sendJson(res, 405, { error: 'method not allowed' });
182
+ return;
183
+ }
184
+ let body;
185
+ try {
186
+ body = await readJsonBody(req);
187
+ }
188
+ catch (err) {
189
+ sendJson(res, 400, { ok: false, error: `invalid request body: ${err instanceof Error ? err.message : String(err)}` });
190
+ return;
191
+ }
192
+ const credentials = parseCredentials(body);
193
+ if (credentials === null) {
194
+ sendJson(res, 400, { ok: false, error: 'appId 与 appSecret 不能为空' });
195
+ return;
196
+ }
197
+ const result = submit(credentials);
198
+ if (!result.persisted) {
199
+ sendJson(res, 500, { ok: false, error: result.error ?? '保存失败' });
200
+ return;
201
+ }
202
+ // 写入 profile patch 触发 HMR 重载,新 fiber 以新凭据启动网关
203
+ sendJson(res, 200, { ok: true, message: '凭据已保存,插件将自动重载' });
204
+ }
205
+ /** 解绑:仅已绑定态可执行;移除 profile patch 中的凭据并触发 HMR 重载 */
206
+ function handleUnbind(req, res, options) {
207
+ if (!trusted(req)) {
208
+ sendJson(res, 403, { error: 'forbidden' });
209
+ return;
210
+ }
211
+ if (req.method !== 'POST') {
212
+ sendJson(res, 405, { error: 'method not allowed' });
213
+ return;
214
+ }
215
+ req.resume();
216
+ if ((options.boundAppId?.() ?? null) === null) {
217
+ sendJson(res, 409, { ok: false, error: '当前未绑定' });
218
+ return;
219
+ }
220
+ const result = options.onUnbind === undefined
221
+ ? (() => {
222
+ const removed = removeCredentialsFromProfile(getProfileDir() ?? undefined, undefined);
223
+ if (removed) {
224
+ // 清除进程内凭据:扫码绑定成功时会写入 env(供热更新后的下次
225
+ // apply 兜底读取);不清则 HMR 重载后新 fiber 仍从 env 读到
226
+ // 凭据,解绑不生效(状态一直停留在 bound)
227
+ delete process.env.QQBOT_APPID;
228
+ delete process.env.QQBOT_SECRET;
229
+ }
230
+ return removed
231
+ ? { persisted: true }
232
+ : { persisted: false, error: '无法定位 profile 目录或写入失败,请手动编辑 cordis.patch.yml' };
233
+ })()
234
+ : options.onUnbind();
235
+ if (!result.persisted) {
236
+ sendJson(res, 500, { ok: false, error: result.error ?? '解绑失败' });
237
+ return;
238
+ }
239
+ // 移除后写入触发 HMR 重载,插件回到未绑定态(绑定流程重新可用)
240
+ sendJson(res, 200, { ok: true, message: '已解绑,插件将重载并重新进入绑定流程' });
241
+ }
242
+ /**
243
+ * 配置读写:
244
+ * - GET:回显当前生效配置(appSecret 剔除,cwd 等只读字段正常返回)
245
+ * - POST:白名单 + 子 Schema 校验 → 最小写入 profile patch → HMR 重载
246
+ */
247
+ async function handleConfig(req, res, options) {
248
+ if (!trusted(req)) {
249
+ sendJson(res, 403, { error: 'forbidden' });
250
+ return;
251
+ }
252
+ if (req.method !== 'GET' && req.method !== 'POST') {
253
+ sendJson(res, 405, { error: 'method not allowed' });
254
+ return;
255
+ }
256
+ if (req.method === 'GET') {
257
+ const current = options.currentConfig?.() ?? {};
258
+ // appSecret 永不回传;其余(含只读 cwd)原样回显
259
+ const { appSecret: _s, ...safe } = current;
260
+ sendJson(res, 200, { config: safe });
261
+ return;
262
+ }
263
+ let body;
264
+ try {
265
+ body = await readJsonBody(req);
266
+ }
267
+ catch (err) {
268
+ sendJson(res, 400, { ok: false, error: `invalid request body: ${err instanceof Error ? err.message : String(err)}` });
269
+ return;
270
+ }
271
+ if (typeof body !== 'object' || body === null) {
272
+ sendJson(res, 400, { ok: false, error: '请求体必须是 JSON 对象' });
273
+ return;
274
+ }
275
+ const submitted = body;
276
+ // 白名单与凭据/只读字段拦截
277
+ for (const key of Object.keys(submitted)) {
278
+ if (!EDITABLE_CONFIG_KEYS.has(key)) {
279
+ const reason = key === 'appId' || key === 'appSecret'
280
+ ? '凭据请使用绑定/更换/解绑功能'
281
+ : key === 'cwd'
282
+ ? 'cwd 为只读字段'
283
+ : '不支持的字段';
284
+ sendJson(res, 400, { ok: false, error: `${reason}: ${key}` });
285
+ return;
286
+ }
287
+ }
288
+ // 逐键 Schema 校验(非法值拒绝,返回首个错误)
289
+ let validated = {};
290
+ try {
291
+ validated = Object.fromEntries(Object.entries(submitted).map(([key, value]) => {
292
+ const check = EDITABLE_CONFIG_SCHEMAS[key];
293
+ if (check === undefined)
294
+ throw new TypeError(`不支持的字段: ${key}`);
295
+ return [key, check(value)];
296
+ }));
297
+ }
298
+ catch (err) {
299
+ sendJson(res, 400, { ok: false, error: err instanceof TypeError ? err.message : String(err) });
300
+ return;
301
+ }
302
+ const persisted = options.onUpdateConfig === undefined
303
+ ? updateProfileConfig(validated, getProfileDir() ?? undefined, undefined)
304
+ : options.onUpdateConfig(validated);
305
+ if (!persisted) {
306
+ sendJson(res, 500, { ok: false, error: '无法定位 profile 目录或写入失败' });
307
+ return;
308
+ }
309
+ sendJson(res, 200, { ok: true, message: '配置已保存,插件将自动重载(进行中的机器人会话将重置)' });
310
+ }
311
+ //# sourceMappingURL=bind-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind-routes.js","sourceRoot":"","sources":["../../src/setup/bind-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import type { QrConnectCallbacks, QrConnectOptions } from '@tencent-connect/qqbot-connector';
2
+ import type { Logger } from '../types.ts';
3
+ import type { QrPresenter } from './presenters.ts';
4
+ import { renderQrSvgDataUrl } from './qr-svg.ts';
5
+ import type { SetupCredentials } from './persist.ts';
6
+ /** connector 连接函数签名(可注入便于测试) */
7
+ export type ConnectFn = (callbacks: QrConnectCallbacks, options?: QrConnectOptions) => () => void;
8
+ /** 绑定状态机相位 */
9
+ export type BindPhase = {
10
+ kind: 'idle';
11
+ } | {
12
+ kind: 'waiting';
13
+ url: string;
14
+ qrSvg?: string;
15
+ issuedAt: number;
16
+ } | {
17
+ kind: 'saving';
18
+ } | {
19
+ kind: 'failed';
20
+ reason: string;
21
+ };
22
+ /** HTTP 路由序列化形态(线上协议,供端内绑定页消费) */
23
+ export type BindStateWire = {
24
+ phase: 'starting';
25
+ } | {
26
+ phase: 'waiting';
27
+ url: string;
28
+ qrSvg?: string;
29
+ issuedAt: number;
30
+ } | {
31
+ phase: 'saving';
32
+ } | {
33
+ phase: 'failed';
34
+ reason: string;
35
+ };
36
+ /** 构造参数 */
37
+ export interface BindingServiceOptions {
38
+ /** 调用来源标识,拼入二维码 URL */
39
+ source: string;
40
+ logger: Logger;
41
+ /** connector 注入点(默认真实实现) */
42
+ connect?: ConnectFn;
43
+ /** 二维码渲染注入点(默认真实实现) */
44
+ renderQr?: typeof renderQrSvgDataUrl;
45
+ }
46
+ /**
47
+ * 单个绑定会话的状态机。
48
+ *
49
+ * start() 幂等;refresh() 通过 abort 当前 connectOnce 使 run 循环
50
+ * 重建绑定任务(新二维码);dispose() 终止一切轮询。
51
+ */
52
+ export declare class BindingService {
53
+ private phase;
54
+ private readonly listeners;
55
+ private readonly presenters;
56
+ private readonly connectFn;
57
+ private readonly renderQrFn;
58
+ private readonly source;
59
+ private readonly logger;
60
+ private readonly lifetime;
61
+ private refreshCtl;
62
+ private runId;
63
+ private startPromise;
64
+ private disposed;
65
+ constructor(options: BindingServiceOptions);
66
+ /** 当前相位(路由轮询读取) */
67
+ get currentPhase(): BindPhase;
68
+ /** 状态订阅(预留给 SSE 推送等增强) */
69
+ subscribe(listener: () => void): () => void;
70
+ /** 挂载呈现策略(须在 start() 前调用) */
71
+ attach(presenter: QrPresenter): void;
72
+ /** 序列化为线上协议 */
73
+ wireState(): BindStateWire;
74
+ /** 启动绑定流程(幂等) */
75
+ start(): Promise<SetupCredentials | null>;
76
+ /** 用户请求刷新:废弃当前二维码任务,run 循环会重建 */
77
+ refresh(): void;
78
+ /** 终止绑定(插件卸载 / HMR 接管 / 替换) */
79
+ dispose(): void;
80
+ private run;
81
+ private connectOnce;
82
+ private handleQrDisplayed;
83
+ private handleQrExpired;
84
+ private setPhase;
85
+ }
86
+ //# sourceMappingURL=binding-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-service.d.ts","sourceRoot":"","sources":["../../src/setup/binding-service.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAwB,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACnH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,gCAAgC;AAChC,MAAM,MAAM,SAAS,GAAG,CAAC,SAAS,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,IAAI,CAAC;AAElG,cAAc;AACd,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,kCAAkC;AAClC,MAAM,MAAM,aAAa,GACrB;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,GACrB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,WAAW;AACX,MAAM,WAAW,qBAAqB;IACpC,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACtC;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,YAAY,CAAiD;IACrE,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,qBAAqB;IAO1C,mBAAmB;IACnB,IAAI,YAAY,IAAI,SAAS,CAE5B;IAED,0BAA0B;IAC1B,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAK3C,6BAA6B;IAC7B,MAAM,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI;IAIpC,eAAe;IACf,SAAS,IAAI,aAAa;IAa1B,iBAAiB;IACjB,KAAK,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IASzC,iCAAiC;IACjC,OAAO,IAAI,IAAI;IAMf,+BAA+B;IAC/B,OAAO,IAAI,IAAI;YASD,GAAG;IAwBjB,OAAO,CAAC,WAAW;YAqCL,iBAAiB;IAgB/B,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;CAIjB"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * QQ Bot 绑定服务 — 扫码状态机(宿主内唯一事实源)
3
+ *
4
+ * - 协议轮询只在宿主执行(appSecret 解密后绝不出宿主进程)
5
+ * - 端内绑定页(bind-routes)只读投影本服务状态
6
+ * - 生命周期可取消(HMR / 插件卸载时 abort 轮询,不留孤儿任务)
7
+ * - refresh() 仅废弃当前二维码任务并重建(用户点击「刷新二维码」)
8
+ */
9
+ import { startQrConnect } from '@tencent-connect/qqbot-connector';
10
+ import { renderQrSvgDataUrl } from "./qr-svg.js";
11
+ /**
12
+ * 单个绑定会话的状态机。
13
+ *
14
+ * start() 幂等;refresh() 通过 abort 当前 connectOnce 使 run 循环
15
+ * 重建绑定任务(新二维码);dispose() 终止一切轮询。
16
+ */
17
+ export class BindingService {
18
+ phase = { kind: 'idle' };
19
+ listeners = new Set();
20
+ presenters = [];
21
+ connectFn;
22
+ renderQrFn;
23
+ source;
24
+ logger;
25
+ lifetime = new AbortController();
26
+ refreshCtl = null;
27
+ runId = 0;
28
+ startPromise = null;
29
+ disposed = false;
30
+ constructor(options) {
31
+ this.source = options.source;
32
+ this.logger = options.logger;
33
+ this.connectFn = options.connect ?? startQrConnect;
34
+ this.renderQrFn = options.renderQr ?? renderQrSvgDataUrl;
35
+ }
36
+ /** 当前相位(路由轮询读取) */
37
+ get currentPhase() {
38
+ return this.phase;
39
+ }
40
+ /** 状态订阅(预留给 SSE 推送等增强) */
41
+ subscribe(listener) {
42
+ this.listeners.add(listener);
43
+ return () => { this.listeners.delete(listener); };
44
+ }
45
+ /** 挂载呈现策略(须在 start() 前调用) */
46
+ attach(presenter) {
47
+ this.presenters.push(presenter);
48
+ }
49
+ /** 序列化为线上协议 */
50
+ wireState() {
51
+ switch (this.phase.kind) {
52
+ case 'idle':
53
+ return { phase: 'starting' };
54
+ case 'waiting':
55
+ return { phase: 'waiting', url: this.phase.url, qrSvg: this.phase.qrSvg, issuedAt: this.phase.issuedAt };
56
+ case 'saving':
57
+ return { phase: 'saving' };
58
+ case 'failed':
59
+ return { phase: 'failed', reason: this.phase.reason };
60
+ }
61
+ }
62
+ /** 启动绑定流程(幂等) */
63
+ start() {
64
+ if (this.startPromise === null) {
65
+ this.startPromise = this.run().finally(() => {
66
+ this.refreshCtl = null;
67
+ });
68
+ }
69
+ return this.startPromise;
70
+ }
71
+ /** 用户请求刷新:废弃当前二维码任务,run 循环会重建 */
72
+ refresh() {
73
+ if (this.disposed || this.startPromise === null)
74
+ return;
75
+ console.log('正在刷新二维码…\n');
76
+ this.refreshCtl?.abort();
77
+ }
78
+ /** 终止绑定(插件卸载 / HMR 接管 / 替换) */
79
+ dispose() {
80
+ if (this.disposed)
81
+ return;
82
+ this.disposed = true;
83
+ this.refreshCtl?.abort();
84
+ this.lifetime.abort();
85
+ this.presenters.length = 0;
86
+ this.listeners.clear();
87
+ }
88
+ async run() {
89
+ while (!this.disposed) {
90
+ const generation = ++this.runId;
91
+ let credentials;
92
+ try {
93
+ credentials = await this.connectOnce(generation);
94
+ }
95
+ catch (err) {
96
+ if (this.disposed)
97
+ return null;
98
+ const reason = err instanceof Error ? err.message : String(err);
99
+ this.setPhase({ kind: 'failed', reason });
100
+ console.error(`[im-qqbot] 扫码绑定失败: ${reason}`);
101
+ return null;
102
+ }
103
+ if (this.disposed)
104
+ return null;
105
+ if (credentials !== null) {
106
+ console.log(`\n✔ 扫码绑定成功! AppID: ${credentials.appId}\n`);
107
+ this.setPhase({ kind: 'saving' });
108
+ return credentials;
109
+ }
110
+ // null = refresh 触发的重启或空凭据软失败,循环重建新二维码任务
111
+ }
112
+ return null;
113
+ }
114
+ connectOnce(generation) {
115
+ return new Promise((resolve, reject) => {
116
+ const refreshCtl = new AbortController();
117
+ this.refreshCtl = refreshCtl;
118
+ const signal = AbortSignal.any([this.lifetime.signal, refreshCtl.signal]);
119
+ this.connectFn({
120
+ onSuccess: (credentials) => {
121
+ const cred = credentials[0];
122
+ if (!cred) {
123
+ // 软失败:以 failed 终结(不进入 refresh 循环,避免无限重试)
124
+ reject(new Error('扫码未返回有效凭据'));
125
+ return;
126
+ }
127
+ resolve({ appId: cred.appId, appSecret: cred.appSecret });
128
+ },
129
+ onFailure: (error) => {
130
+ // refresh / dispose 触发的取消按「重启」或「静默退出」处理
131
+ if (this.lifetime.signal.aborted || refreshCtl.signal.aborted) {
132
+ resolve(null);
133
+ return;
134
+ }
135
+ reject(error);
136
+ },
137
+ onQrDisplayed: (url) => { void this.handleQrDisplayed(generation, url); },
138
+ onQrExpired: () => { this.handleQrExpired(generation); },
139
+ }, {
140
+ displayQrCodeToConsole: this.presenters.some((p) => p.printQrToConsole),
141
+ signal,
142
+ source: this.source,
143
+ });
144
+ });
145
+ }
146
+ async handleQrDisplayed(generation, url) {
147
+ // 终端链接指引先于 SVG 渲染:指引是二维码渲染错位时的自救通道,
148
+ // 必须与 connector 的二维码打印同步衔接,不隔任何异步间隙
149
+ for (const presenter of this.presenters)
150
+ presenter.onQrDisplayed(url);
151
+ let qrSvg;
152
+ try {
153
+ qrSvg = await this.renderQrFn(url);
154
+ }
155
+ catch (err) {
156
+ this.logger.warn(`im-qqbot: 二维码 SVG 渲染失败(页面将降级为链接): ${err instanceof Error ? err.message : String(err)}`);
157
+ }
158
+ // 渲染期间可能已被 refresh/dispose 淘汰
159
+ if (generation !== this.runId || this.disposed)
160
+ return;
161
+ this.setPhase({ kind: 'waiting', url, qrSvg, issuedAt: Date.now() });
162
+ }
163
+ handleQrExpired(generation) {
164
+ if (generation !== this.runId)
165
+ return;
166
+ for (const presenter of this.presenters)
167
+ presenter.onQrExpired?.();
168
+ }
169
+ setPhase(phase) {
170
+ this.phase = phase;
171
+ for (const listener of this.listeners)
172
+ listener();
173
+ }
174
+ }
175
+ //# sourceMappingURL=binding-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-service.js","sourceRoot":"","sources":["../../src/setup/binding-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 凭据绑定编排 — setup/ 模块入口
3
+ *
4
+ * apply() 检测到凭据缺失时调用 ensureCredentials:
5
+ * 1. 创建 BindingService(单例接管,HMR 双 fiber 安全)
6
+ * 2. Web 宿主(dsh web / Desktop)注册端内绑定页路由
7
+ * —— 经 ctx.inject(['webServer'], ...) 可选注入:服务未就绪时插件
8
+ * 照常加载(CLI profile),就绪/替换时自动(重)注册路由
9
+ * 3. 按宿主形态挂呈现策略(终端 / 浏览器降级)
10
+ * 4. 生命周期与 ctx fiber 绑定(dispose 时 abort 轮询、注销路由)
11
+ *
12
+ * 凭据已配置的 fiber 调用 registerBoundCredentialRoutes 注册常驻路由
13
+ * (bound 状态回显 + 手动编辑),与扫码流程共用持久化路径。
14
+ */
15
+ import type { Context } from '@deepseek-ai/cordis';
16
+ import type { Logger } from '../types.ts';
17
+ import { type SetupCredentials } from './persist.ts';
18
+ export type { SetupCredentials } from './persist.ts';
19
+ export { persistCredentialsToProfile } from './persist.ts';
20
+ export { isDesktopHost } from './presenters.ts';
21
+ /** ensureCredentials 参数 */
22
+ export interface EnsureCredentialsOptions {
23
+ logger: Logger;
24
+ /** 二维码 URL 的 source 标识 */
25
+ source?: string;
26
+ /** 当前生效配置(apply 时 loader 合并值;config 路由 GET 回显用) */
27
+ config: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * 执行扫码绑定编排,返回凭据就绪的 Promise;失败/取消 resolve null。
31
+ *
32
+ * 【同步契约】函数体必须保持无 await——绑定编排(服务接管、路由注册、
33
+ * 呈现策略、ctx 生命周期挂载)在调用后的同步阶段全部完成,随后返回
34
+ * `service.start()` 的挂起 Promise。调用方(插件 apply)因此可以不等待
35
+ * 扫码结果直接完成加载:boot 的 `loader.await()` 会等所有插件 fiber
36
+ * settle,若 apply 无限期等待用户扫码,Host ready 会被阻塞
37
+ * (Desktop 界面无法进入、Web URL 延迟输出)。
38
+ *
39
+ * 凭据持久化由调用方在 Promise 的 then 链中执行——成功写入
40
+ * cordis.patch.yml 会触发 HMR 热重载,新 fiber 以凭据启动网关。
41
+ */
42
+ export declare function ensureCredentials(ctx: Context, options: EnsureCredentialsOptions): Promise<SetupCredentials | null>;
43
+ /**
44
+ * 凭据已配置的 fiber 注册常驻路由(状态回显 + 手动编辑/更换)。
45
+ *
46
+ * 在 apply 的 bootstrapGateway 之前调用;写入经同一 persist 路径,
47
+ * 保存后触发 HMR 重载、新 fiber 以新凭据重启网关。
48
+ */
49
+ export declare function registerBoundCredentialRoutes(ctx: Context, logger: Logger, appId: string, config: Record<string, unknown>): void;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/setup/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGlF,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD,2BAA2B;AAC3B,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAmDlC;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAehI"}