@onlyne/im-qq 3.1.0 → 3.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,303 @@
1
+ /**
2
+ * The QQ official Bot OpenAPI v2 connector. Inbound events arrive either on the platform's
3
+ * WebSocket gateway (the default, owned by `gateway.ts`) or on the signed HTTP callback the host
4
+ * hands to `handleWebhook`; every outbound platform call goes through the injected port either way.
5
+ */
6
+ import { readFile as nodeReadFile } from 'node:fs/promises';
7
+ import { OnlyneError } from '@onlyne/lib';
8
+ import { resolveCredential } from '@onlyne/im-core';
9
+ import { createQqPort, messagePath } from './port.js';
10
+ import { normalizeEvent } from './normalize.js';
11
+ import { createSendState, outcomeOf, parseConversation, sendMessage } from './send.js';
12
+ import { challenge, verifyHex } from './webhook.js';
13
+ import { createQqGateway } from './gateway.js';
14
+ export { createQqPort, messagePath, QqPortError, } from './port.js';
15
+ export { normalizeEvent } from './normalize.js';
16
+ export { challenge, deriveEd25519, signHex, verifyHex } from './webhook.js';
17
+ export { createSendState, parseConversation, sendMessage } from './send.js';
18
+ export { createQqGateway, QQ_INTENTS, } from './gateway.js';
19
+ export const QQ_CREDENTIAL_VARIABLES = ['QQ_BOT_APP_ID', 'QQ_BOT_APP_SECRET'];
20
+ /** Platform operations the connector implements beyond `send`; a resource lists them. */
21
+ export const QQ_OPERATIONS = ['recall', 'typing'];
22
+ /** QQ signs every dispatch over its timestamp; a callback older than this is a replay. */
23
+ const SIGNATURE_WINDOW_MS = 5 * 60 * 1000;
24
+ /** What QQ's `input_notify` shows the user; the platform caps the hint at 60 seconds. */
25
+ const TYPING_SECONDS = 60;
26
+ function recordOf(value) {
27
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
28
+ ? value
29
+ : undefined;
30
+ }
31
+ export function createQqConnector(options = {}) {
32
+ const now = options.now ?? Date.now;
33
+ const log = options.log ?? (() => { });
34
+ const transport = options.transport ?? 'websocket';
35
+ const listeners = [];
36
+ /** One chain per conversation: the endpoint's `receive` calls land in arrival order. */
37
+ const queues = new Map();
38
+ const sendState = createSendState();
39
+ let port;
40
+ let gateway;
41
+ let lifecycle = 'onboarding';
42
+ let onboarding;
43
+ let failure;
44
+ let lastEventAt;
45
+ let appId;
46
+ let appSecret;
47
+ /** The credential resolved and the token was proven: outbound calls can go. */
48
+ let ready = false;
49
+ function emit(event) {
50
+ const previous = queues.get(event.conversation) ?? Promise.resolve();
51
+ const run = previous.then(async () => {
52
+ for (const listener of listeners)
53
+ await listener(event);
54
+ });
55
+ // The chain survives a failing listener so the next event in this conversation still runs;
56
+ // the caller keeps the rejection and answers the platform with a retryable status.
57
+ const settled = run.catch(() => { });
58
+ queues.set(event.conversation, settled);
59
+ void settled.then(() => {
60
+ if (queues.get(event.conversation) === settled)
61
+ queues.delete(event.conversation);
62
+ });
63
+ return run;
64
+ }
65
+ function refuse(code, message, status) {
66
+ return Response.json({ error: { code, message } }, { status });
67
+ }
68
+ function credentialFields(problem) {
69
+ const env = options.env ?? process.env;
70
+ // A configured file that could not be read: the resolve problem is the real fix, not the pair.
71
+ if (options.credentialFile !== undefined)
72
+ return [problem ?? `Provide ${QQ_CREDENTIAL_VARIABLES.join(' + ')}.`];
73
+ const missing = QQ_CREDENTIAL_VARIABLES.filter(name => (env[name] ?? '').length === 0);
74
+ return missing.length > 0 ? missing : [problem ?? `Provide ${QQ_CREDENTIAL_VARIABLES.join(' + ')}.`];
75
+ }
76
+ return {
77
+ platform: 'qq',
78
+ operations: QQ_OPERATIONS,
79
+ async start() {
80
+ lifecycle = 'connecting';
81
+ const credential = await resolveCredential({ value: options.credential, file: options.credentialFile, variables: [...QQ_CREDENTIAL_VARIABLES] }, options.readFile ?? (path => nodeReadFile(path, 'utf8')), options.env ?? process.env);
82
+ if (credential.value === undefined) {
83
+ // A missing credential is a state, not a failure: the host renders the fields to provide.
84
+ lifecycle = 'onboarding';
85
+ onboarding = credentialFields(credential.problem);
86
+ failure = undefined;
87
+ log('qq connector is onboarding', { onboarding });
88
+ return;
89
+ }
90
+ const separator = credential.value.indexOf(':');
91
+ if (separator <= 0 || separator === credential.value.length - 1) {
92
+ lifecycle = 'error';
93
+ failure = 'The QQ credential is appId:appSecret.';
94
+ onboarding = [...QQ_CREDENTIAL_VARIABLES];
95
+ log('qq connector rejected the credential shape', { error: failure });
96
+ return;
97
+ }
98
+ appId = credential.value.slice(0, separator);
99
+ appSecret = credential.value.slice(separator + 1);
100
+ port = options.port ?? createQqPort({
101
+ appId,
102
+ appSecret,
103
+ ...(options.now === undefined ? {} : { now: options.now }),
104
+ });
105
+ try {
106
+ await port.start();
107
+ // Fetching the token proves the pair: QQ answers a bad secret here and nowhere earlier.
108
+ await port.token();
109
+ ready = true;
110
+ onboarding = undefined;
111
+ failure = undefined;
112
+ if (transport === 'webhook') {
113
+ lifecycle = 'connected';
114
+ log('qq connector is connected', {
115
+ app_id: appId,
116
+ transport,
117
+ webhook_path: options.webhookPath ?? 'unset',
118
+ });
119
+ return;
120
+ }
121
+ gateway = createQqGateway({
122
+ port,
123
+ log,
124
+ now,
125
+ ...(options.onState === undefined ? {} : { onState: options.onState }),
126
+ ...(options.gateway ?? {}),
127
+ });
128
+ // Not awaited to a socket: a gateway that cannot reach QQ stays a retrying state, and
129
+ // the host's status panel shows it, instead of a failed start.
130
+ await gateway.start({
131
+ dispatch: async (payload) => {
132
+ const event = normalizeEvent(payload, now);
133
+ if (event === undefined)
134
+ return;
135
+ // A rejection leaves the sequence number where it was: the platform replays the event.
136
+ await emit(event);
137
+ log('qq.dispatch', {
138
+ conversation: event.conversation, source_id: event.source_id, kind: event.kind,
139
+ ...(typeof payload.t === 'string' ? { type: payload.t } : {}),
140
+ ...(typeof payload.s === 'number' ? { seq: payload.s } : {}),
141
+ });
142
+ lastEventAt = event.at;
143
+ },
144
+ });
145
+ lifecycle = 'connecting';
146
+ log('qq connector is dialing the gateway', { app_id: appId, transport });
147
+ }
148
+ catch (error) {
149
+ ready = false;
150
+ lifecycle = 'error';
151
+ failure = error instanceof Error ? error.message : String(error);
152
+ log('qq connector could not authenticate', { error: failure });
153
+ }
154
+ },
155
+ onEvent(listener) {
156
+ listeners.push(listener);
157
+ },
158
+ async send(request) {
159
+ if (port === undefined || !ready) {
160
+ const hint = onboarding === undefined ? '' : `; provide ${onboarding.join(', ')}`;
161
+ return { state: 'unknown', error: `The QQ connector is not connected${hint}.` };
162
+ }
163
+ return sendMessage(port, request, sendState);
164
+ },
165
+ validate(operation, data) {
166
+ if (!QQ_OPERATIONS.includes(operation)) {
167
+ throw new OnlyneError('invalid_request', `The QQ connector does not implement ${operation}.`);
168
+ }
169
+ const raw = recordOf(data) ?? {};
170
+ if (operation === 'recall' && (typeof raw.message_id !== 'string' || raw.message_id.length === 0)) {
171
+ throw new OnlyneError('invalid_request', 'recall names message_id.');
172
+ }
173
+ if (typeof raw.conversation !== 'string' || raw.conversation.length === 0) {
174
+ throw new OnlyneError('invalid_request', `${operation} names conversation.`);
175
+ }
176
+ },
177
+ async operate(operation, data) {
178
+ if (port === undefined || !ready) {
179
+ return { state: 'unknown', error: 'The QQ connector is not connected.' };
180
+ }
181
+ const raw = recordOf(data) ?? {};
182
+ const conversation = typeof raw.conversation === 'string' ? raw.conversation : '';
183
+ const target = parseConversation(conversation);
184
+ if (target === undefined) {
185
+ return {
186
+ state: 'unknown',
187
+ error: `The QQ connector addresses c2c:<openid> or group:<openid>, not ${conversation}.`,
188
+ };
189
+ }
190
+ try {
191
+ if (operation === 'recall') {
192
+ await port.request('DELETE', messagePath(target, String(raw.message_id)));
193
+ return { state: 'committed' };
194
+ }
195
+ if (operation === 'typing') {
196
+ if (target.kind === 'group')
197
+ return { state: 'unknown', error: 'QQ typing is c2c only.' };
198
+ const body = { msg_type: 6, input_notify: { input_type: 1, input_second: TYPING_SECONDS } };
199
+ await port.send(target, body);
200
+ return { state: 'committed' };
201
+ }
202
+ return { state: 'unknown', error: `The QQ connector does not implement ${operation}.` };
203
+ }
204
+ catch (error) {
205
+ return outcomeOf(error, 'operation');
206
+ }
207
+ },
208
+ async handleWebhook(request) {
209
+ if (request.method !== 'POST') {
210
+ return refuse('method_not_allowed', 'The QQ webhook accepts POST only.', 405);
211
+ }
212
+ const rawBody = await request.text();
213
+ let payload;
214
+ try {
215
+ payload = JSON.parse(rawBody);
216
+ }
217
+ catch {
218
+ return refuse('invalid_request', 'The QQ webhook body is not JSON.', 400);
219
+ }
220
+ const envelope = recordOf(payload);
221
+ if (envelope === undefined) {
222
+ return refuse('invalid_request', 'The QQ webhook body is not an object.', 400);
223
+ }
224
+ if (appSecret === undefined) {
225
+ return refuse('unavailable', 'The QQ connector has no credential, so a callback cannot be validated.', 503);
226
+ }
227
+ if (envelope.op === 13) {
228
+ const claimed = request.headers.get('x-bot-appid');
229
+ if (claimed !== null && appId !== undefined && claimed !== appId) {
230
+ return refuse('unauthenticated', 'X-Bot-Appid does not match the configured app id.', 401);
231
+ }
232
+ const answer = challenge(appSecret, rawBody);
233
+ if (answer === undefined) {
234
+ return refuse('invalid_request', 'The validation callback names plain_token and event_ts.', 400);
235
+ }
236
+ return Response.json(answer);
237
+ }
238
+ if (envelope.op === 0) {
239
+ const timestamp = request.headers.get('x-signature-timestamp');
240
+ const signature = request.headers.get('x-signature-ed25519');
241
+ if (timestamp === null || signature === null) {
242
+ return refuse('unauthenticated', 'The QQ dispatch carries no signature headers.', 401);
243
+ }
244
+ const stamp = Number(timestamp);
245
+ if (!Number.isFinite(stamp) || Math.abs(now() - stamp * 1000) > SIGNATURE_WINDOW_MS) {
246
+ return refuse('unauthenticated', 'The QQ dispatch timestamp is outside the five-minute window.', 401);
247
+ }
248
+ if (!verifyHex(appSecret, `${timestamp}${rawBody}`, signature)) {
249
+ return refuse('unauthenticated', 'The QQ dispatch signature does not verify.', 401);
250
+ }
251
+ const event = normalizeEvent(payload, now);
252
+ if (event !== undefined) {
253
+ try {
254
+ await emit(event);
255
+ }
256
+ catch (error) {
257
+ const detail = error instanceof Error ? error.message : String(error);
258
+ // Never ack a batch whose durable receive failed: QQ retries a non-2xx answer.
259
+ log('qq inbound listener failed', { source_id: event.source_id, error: detail });
260
+ return refuse('unavailable', `The inbound event was not stored: ${detail}`, 500);
261
+ }
262
+ log('qq.dispatch', {
263
+ conversation: event.conversation, source_id: event.source_id, kind: event.kind,
264
+ ...(typeof envelope.t === 'string' ? { type: envelope.t } : {}),
265
+ });
266
+ lastEventAt = event.at;
267
+ }
268
+ return Response.json({ op: 12 });
269
+ }
270
+ // Heartbeats and anything newer than this connector knows: acknowledged, not translated.
271
+ return Response.json({ op: 12 });
272
+ },
273
+ status() {
274
+ const observed = gateway?.status();
275
+ return {
276
+ state: observed?.state ?? lifecycle,
277
+ connected: observed === undefined ? lifecycle === 'connected' : observed.state === 'online',
278
+ reconnects: observed?.reconnects ?? 0,
279
+ rate_limits: port?.status().rate_limits ?? 0,
280
+ transport,
281
+ ...(lastEventAt === undefined ? {} : { last_event_at: lastEventAt }),
282
+ ...(onboarding === undefined || onboarding.length === 0 ? {} : { onboarding }),
283
+ ...(failure === undefined ? {} : { error: failure }),
284
+ ...(observed === undefined ? {} : {
285
+ heartbeat_timeouts: observed.heartbeat_timeouts,
286
+ resumes: observed.resumes,
287
+ resume_failures: observed.resume_failures,
288
+ shards: observed.shards,
289
+ }),
290
+ };
291
+ },
292
+ async stop() {
293
+ listeners.length = 0;
294
+ queues.clear();
295
+ await gateway?.stop();
296
+ gateway = undefined;
297
+ await port?.stop();
298
+ ready = false;
299
+ lifecycle = 'stopped';
300
+ },
301
+ };
302
+ }
303
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The QQ event envelope, translated into one `ImEvent`. Pure: no clock beyond the injected one,
3
+ * no network, no state — the same payload always normalizes the same way.
4
+ *
5
+ * Envelope: `{id, op, d, s, t}`. `op 0` is a dispatch and `t` names the event; anything else
6
+ * (heartbeat, callback validation) is not an inbound event.
7
+ */
8
+ import type { ImEvent } from '@onlyne/im-core';
9
+ /** One `op 0` dispatch; `undefined` for an event this connector does not translate. */
10
+ export declare function normalizeEvent(payload: unknown, now?: () => number): ImEvent | undefined;
11
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAgB,OAAO,EAAW,MAAM,iBAAiB,CAAC;AA2LtE,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,OAAO,GAAG,SAAS,CAUlG"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The QQ event envelope, translated into one `ImEvent`. Pure: no clock beyond the injected one,
3
+ * no network, no state — the same payload always normalizes the same way.
4
+ *
5
+ * Envelope: `{id, op, d, s, t}`. `op 0` is a dispatch and `t` names the event; anything else
6
+ * (heartbeat, callback validation) is not an inbound event.
7
+ */
8
+ const PLATFORM = 'qq';
9
+ const MESSAGE_EVENTS = {
10
+ C2C_MESSAGE_CREATE: true,
11
+ GROUP_AT_MESSAGE_CREATE: true,
12
+ };
13
+ const LIFECYCLE_EVENTS = {
14
+ GROUP_ADD_ROBOT: true,
15
+ GROUP_DEL_ROBOT: true,
16
+ FRIEND_ADD: true,
17
+ FRIEND_DEL: true,
18
+ C2C_MSG_RECEIVE: true,
19
+ C2C_MSG_REJECT: true,
20
+ GROUP_MSG_RECEIVE: true,
21
+ GROUP_MSG_REJECT: true,
22
+ };
23
+ function recordOf(value) {
24
+ return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
25
+ }
26
+ function textOf(value) {
27
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
28
+ }
29
+ function senderOf(d) {
30
+ const author = recordOf(d.author);
31
+ return textOf(author?.user_openid) ?? textOf(author?.id)
32
+ ?? textOf(d.openid) ?? textOf(d.op_member_openid) ?? textOf(d.user_openid);
33
+ }
34
+ /**
35
+ * `group:<group_openid>` when the event names a group, else `c2c:<openid>`. A c2c message keeps
36
+ * its openid under `author`, not at the top level.
37
+ */
38
+ function conversationOf(d) {
39
+ const group = textOf(d.group_openid);
40
+ if (group !== undefined)
41
+ return `group:${group}`;
42
+ const user = senderOf(d);
43
+ return user === undefined ? undefined : `c2c:${user}`;
44
+ }
45
+ /** `message_scene.ext` carries `msg_idx=REFIDX_…` for this message and `ref_msg_idx=…` for the quote. */
46
+ function sceneIndexes(d) {
47
+ const ext = recordOf(d.message_scene)?.ext;
48
+ const indexes = {};
49
+ if (!Array.isArray(ext))
50
+ return indexes;
51
+ for (const entry of ext) {
52
+ if (typeof entry !== 'string')
53
+ continue;
54
+ const separator = entry.indexOf('=');
55
+ if (separator <= 0)
56
+ continue;
57
+ const name = entry.slice(0, separator);
58
+ const value = entry.slice(separator + 1);
59
+ if (value.length === 0)
60
+ continue;
61
+ if (name === 'msg_idx')
62
+ indexes.self = value;
63
+ else if (name === 'ref_msg_idx')
64
+ indexes.quoted = value;
65
+ }
66
+ return indexes;
67
+ }
68
+ function attachmentsOf(d) {
69
+ if (!Array.isArray(d.attachments))
70
+ return [];
71
+ const attachments = [];
72
+ for (const entry of d.attachments) {
73
+ const item = recordOf(entry);
74
+ if (item === undefined)
75
+ continue;
76
+ const contentType = (textOf(item.content_type) ?? '').toLowerCase();
77
+ const kind = contentType.startsWith('image/')
78
+ ? 'image'
79
+ : contentType === 'voice' || contentType.startsWith('audio/')
80
+ ? 'audio'
81
+ : contentType.startsWith('video/')
82
+ ? 'video'
83
+ : 'file';
84
+ const url = textOf(item.url);
85
+ // A voice attachment arrives as SILK; the WAV url is the one a player can open.
86
+ const handle = kind === 'audio' ? textOf(item.voice_wav_url) ?? url : url ?? textOf(item.voice_wav_url);
87
+ if (handle === undefined)
88
+ continue;
89
+ const filename = textOf(item.filename);
90
+ attachments.push({ kind, platform_handle: handle, ...(filename === undefined ? {} : { alt: filename }) });
91
+ }
92
+ return attachments;
93
+ }
94
+ /** The first voice attachment's server-side transcript, when the platform produced one. */
95
+ function transcriptOf(d) {
96
+ if (!Array.isArray(d.attachments))
97
+ return undefined;
98
+ for (const entry of d.attachments) {
99
+ const item = recordOf(entry);
100
+ if (item === undefined)
101
+ continue;
102
+ const contentType = (textOf(item.content_type) ?? '').toLowerCase();
103
+ if (contentType !== 'voice' && !contentType.startsWith('audio/'))
104
+ continue;
105
+ const transcript = textOf(item.asr_refer_text);
106
+ if (transcript !== undefined)
107
+ return transcript;
108
+ }
109
+ return undefined;
110
+ }
111
+ /** `msg_elements[0].content` of a quote reply: the platform inlines the quoted body there. */
112
+ function quotedTextOf(d) {
113
+ if (!Array.isArray(d.msg_elements))
114
+ return undefined;
115
+ const first = recordOf(d.msg_elements[0]);
116
+ return textOf(first?.content);
117
+ }
118
+ function messageEvent(d, envelope, now) {
119
+ const conversation = conversationOf(d);
120
+ const messageId = textOf(d.id);
121
+ if (conversation === undefined || messageId === undefined)
122
+ return undefined;
123
+ const messageType = typeof d.message_type === 'number' ? d.message_type : undefined;
124
+ const indexes = sceneIndexes(d);
125
+ const quotedText = messageType === 103 ? quotedTextOf(d) : undefined;
126
+ const attachments = attachmentsOf(d);
127
+ const content = textOf(d.content);
128
+ const arkPrompt = textOf(recordOf(d.ark_data)?.prompt);
129
+ const text = content
130
+ ?? (quotedText ?? arkPrompt)
131
+ ?? transcriptOf(d)
132
+ ?? '';
133
+ const replyParts = {};
134
+ if (indexes.quoted !== undefined)
135
+ replyParts.parent = indexes.quoted;
136
+ if (quotedText !== undefined)
137
+ replyParts.quoted_text = quotedText;
138
+ const sender = senderOf(d);
139
+ return {
140
+ platform: PLATFORM,
141
+ source_id: messageId,
142
+ conversation,
143
+ kind: 'message',
144
+ ...(sender === undefined ? {} : { from: sender }),
145
+ text,
146
+ attachments,
147
+ ...(Object.keys(replyParts).length === 0 ? {} : { reply: replyParts }),
148
+ message_handle: messageId,
149
+ // The passive reply id and the quote index are two ids for one message; the bridge hands the
150
+ // composite back as `reply_to` and `send` splits it again.
151
+ ref_handle: indexes.self === undefined ? messageId : `${messageId}|${indexes.self}`,
152
+ at: textOf(d.timestamp) ?? new Date(now()).toISOString(),
153
+ raw: envelope,
154
+ };
155
+ }
156
+ function interactionEvent(d, envelope, now) {
157
+ const id = textOf(d.id);
158
+ const conversation = conversationOf(d);
159
+ if (id === undefined || conversation === undefined)
160
+ return undefined;
161
+ const sender = senderOf(d);
162
+ return {
163
+ platform: PLATFORM,
164
+ source_id: id,
165
+ conversation,
166
+ kind: 'action',
167
+ ...(sender === undefined ? {} : { from: sender }),
168
+ text: '',
169
+ attachments: [],
170
+ action: { id, ...(d.data === undefined ? {} : { value: d.data }) },
171
+ at: textOf(d.timestamp) ?? new Date(now()).toISOString(),
172
+ raw: envelope,
173
+ };
174
+ }
175
+ function lifecycleEvent(type, d, envelope, now) {
176
+ const sourceId = textOf(envelope.id) ?? textOf(d.id);
177
+ const conversation = conversationOf(d);
178
+ if (sourceId === undefined || conversation === undefined)
179
+ return undefined;
180
+ const sender = senderOf(d);
181
+ return {
182
+ platform: PLATFORM,
183
+ source_id: sourceId,
184
+ conversation,
185
+ kind: 'event',
186
+ ...(sender === undefined ? {} : { from: sender }),
187
+ text: '',
188
+ attachments: [],
189
+ event: { type },
190
+ at: textOf(d.timestamp) ?? new Date(now()).toISOString(),
191
+ raw: envelope,
192
+ };
193
+ }
194
+ /** One `op 0` dispatch; `undefined` for an event this connector does not translate. */
195
+ export function normalizeEvent(payload, now = Date.now) {
196
+ const envelope = recordOf(payload);
197
+ if (envelope === undefined || envelope.op !== 0)
198
+ return undefined;
199
+ const type = textOf(envelope.t);
200
+ const d = recordOf(envelope.d);
201
+ if (type === undefined || d === undefined)
202
+ return undefined;
203
+ if (MESSAGE_EVENTS[type] === true)
204
+ return messageEvent(d, envelope, now);
205
+ if (type === 'INTERACTION_CREATE')
206
+ return interactionEvent(d, envelope, now);
207
+ if (LIFECYCLE_EVENTS[type] === true)
208
+ return lifecycleEvent(type, d, envelope, now);
209
+ return undefined;
210
+ }
211
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
package/dist/port.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * The HTTP boundary: every platform call the connector makes goes through this port, so the
3
+ * translation logic runs against a fake in tests and the real QQ OpenAPI in production. The only
4
+ * injected seams are `fetch` and `now`.
5
+ */
6
+ export declare const QQ_API_BASE = "https://api.bot.qq.com";
7
+ export interface QqHttpRequest {
8
+ method: string;
9
+ headers: Record<string, string>;
10
+ body?: string;
11
+ }
12
+ export interface QqHttpResponse {
13
+ readonly status: number;
14
+ text(): Promise<string>;
15
+ }
16
+ export type QqFetch = (url: string, init: QqHttpRequest) => Promise<QqHttpResponse>;
17
+ export interface QqPortErrorInit {
18
+ /** The HTTP status; `0` when the request never reached the platform. */
19
+ status: number;
20
+ /** The platform's own error code, when its body carried one. */
21
+ code?: string | number;
22
+ /** The platform's own error text, verbatim. */
23
+ detail?: string;
24
+ }
25
+ /** A platform refusal or a transport failure, with what the platform said kept apart from the summary. */
26
+ export declare class QqPortError extends Error {
27
+ readonly status: number;
28
+ readonly code?: string | number;
29
+ readonly detail?: string;
30
+ constructor(message: string, init: QqPortErrorInit);
31
+ }
32
+ /** A QQ conversation coordinate as the platform addresses it. */
33
+ export interface QqSendTarget {
34
+ kind: 'c2c' | 'group';
35
+ openid: string;
36
+ }
37
+ /** The message body QQ v2 accepts; the connector fills only what it sends. */
38
+ export interface QqMessageBody {
39
+ msg_type: number;
40
+ content?: string;
41
+ markdown?: {
42
+ content: string;
43
+ };
44
+ /** The passive reply id from the inbound event. */
45
+ msg_id?: string;
46
+ msg_seq?: number;
47
+ message_reference?: {
48
+ message_id: string;
49
+ };
50
+ input_notify?: {
51
+ input_type: 1;
52
+ input_second: number;
53
+ };
54
+ }
55
+ export interface QqSendResult {
56
+ id?: string;
57
+ timestamp?: string;
58
+ ext_info?: {
59
+ ref_idx?: string;
60
+ };
61
+ }
62
+ export interface QqPortStatus {
63
+ state: string;
64
+ connected: boolean;
65
+ rate_limits: number;
66
+ }
67
+ export interface QqPort {
68
+ start(): Promise<void>;
69
+ stop(): Promise<void>;
70
+ /** The access token, fetched on demand and cached until shortly before it expires. */
71
+ token(): Promise<string>;
72
+ request<T>(method: string, path: string, body?: unknown): Promise<T>;
73
+ send(target: QqSendTarget, body: QqMessageBody): Promise<QqSendResult>;
74
+ status(): QqPortStatus;
75
+ }
76
+ export interface QqPortOptions {
77
+ appId: string;
78
+ appSecret: string;
79
+ baseUrl?: string;
80
+ fetch?: QqFetch;
81
+ now?: () => number;
82
+ }
83
+ /** The message endpoint for one conversation; `messageId` narrows it to that message (retract). */
84
+ export declare function messagePath(target: QqSendTarget, messageId?: string): string;
85
+ export declare function createQqPort(options: QqPortOptions): QqPort;
86
+ //# sourceMappingURL=port.d.ts.map