@zhin.js/adapter-milky 1.0.0 → 1.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/CHANGELOG.md +962 -0
- package/README.md +58 -117
- package/adapters/milky.js +51 -0
- package/adapters/milky.ts +74 -0
- package/agent/PERMITS.md +14 -0
- package/{skills/milky/SKILL.md → agent/skills/milky.md} +1 -1
- package/commands/endpoint/add/[id].js +3 -0
- package/commands/endpoint/add/[id].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +21 -0
- package/lib/client.js +33 -0
- package/lib/endpoint-management.d.ts +17 -0
- package/lib/endpoint-management.js +47 -0
- package/lib/endpoint.d.ts +7 -0
- package/lib/endpoint.js +6 -0
- package/lib/index.d.ts +6 -20
- package/lib/index.js +4 -33
- package/lib/milky-auth.d.ts +2 -0
- package/lib/milky-auth.js +16 -0
- package/lib/milky-endpoint-commands.d.ts +1 -0
- package/lib/milky-endpoint-commands.js +18 -0
- package/lib/milky-runtime-state.d.ts +1 -0
- package/lib/milky-runtime-state.js +6 -0
- package/lib/protocol.d.ts +174 -0
- package/lib/protocol.js +494 -0
- package/lib/sse-client.d.ts +20 -0
- package/lib/sse-client.js +85 -0
- package/lib/sse-endpoint.d.ts +32 -0
- package/lib/sse-endpoint.js +207 -0
- package/lib/webhook-endpoint.d.ts +22 -0
- package/lib/webhook-endpoint.js +149 -0
- package/lib/ws-endpoint.d.ts +23 -0
- package/lib/ws-endpoint.js +233 -0
- package/lib/ws-types.d.ts +11 -0
- package/lib/ws-types.js +1 -0
- package/lib/wss-endpoint.d.ts +25 -0
- package/lib/wss-endpoint.js +184 -0
- package/package.json +73 -19
- package/plugin.js +14 -0
- package/schema.json +100 -0
- package/src/client.ts +80 -0
- package/src/endpoint-management.ts +74 -0
- package/src/endpoint.ts +26 -0
- package/src/index.ts +63 -45
- package/src/milky-auth.ts +14 -0
- package/src/milky-endpoint-commands.ts +19 -0
- package/src/milky-runtime-state.ts +7 -0
- package/src/protocol.ts +647 -0
- package/src/sse-client.ts +106 -0
- package/src/sse-endpoint.ts +258 -0
- package/src/webhook-endpoint.ts +196 -0
- package/src/ws-endpoint.ts +291 -0
- package/src/ws-types.ts +12 -0
- package/src/wss-endpoint.ts +228 -0
- package/lib/adapter.d.ts +0 -28
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -90
- package/lib/adapter.js.map +0 -1
- package/lib/api.d.ts +0 -10
- package/lib/api.d.ts.map +0 -1
- package/lib/api.js +0 -48
- package/lib/api.js.map +0 -1
- package/lib/bot-sse.d.ts +0 -31
- package/lib/bot-sse.d.ts.map +0 -1
- package/lib/bot-sse.js +0 -195
- package/lib/bot-sse.js.map +0 -1
- package/lib/bot-webhook.d.ts +0 -34
- package/lib/bot-webhook.d.ts.map +0 -1
- package/lib/bot-webhook.js +0 -187
- package/lib/bot-webhook.js.map +0 -1
- package/lib/bot-ws.d.ts +0 -35
- package/lib/bot-ws.d.ts.map +0 -1
- package/lib/bot-ws.js +0 -262
- package/lib/bot-ws.js.map +0 -1
- package/lib/bot-wss.d.ts +0 -34
- package/lib/bot-wss.d.ts.map +0 -1
- package/lib/bot-wss.js +0 -225
- package/lib/bot-wss.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts +0 -75
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -5
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts +0 -35
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js +0 -157
- package/lib/utils.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -101
- package/src/api.ts +0 -63
- package/src/bot-sse.ts +0 -228
- package/src/bot-webhook.ts +0 -221
- package/src/bot-ws.ts +0 -296
- package/src/bot-wss.ts +0 -268
- package/src/types.ts +0 -73
- package/src/utils.ts +0 -174
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milky WS client endpoint — outbound connect to Milky protocol server.
|
|
3
|
+
*/
|
|
4
|
+
import WebSocket from 'ws';
|
|
5
|
+
import {
|
|
6
|
+
ClientEndpoint,
|
|
7
|
+
createRecallEndpointControl,
|
|
8
|
+
createEndpointLifecycle,
|
|
9
|
+
type EndpointConnectHandle,
|
|
10
|
+
type EndpointControl,
|
|
11
|
+
type EndpointLifecycle,
|
|
12
|
+
type EndpointManagement,
|
|
13
|
+
type EndpointSendRequest,
|
|
14
|
+
} from 'zhin.js/adapter';
|
|
15
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
16
|
+
import type { CapabilityId } from 'zhin.js';
|
|
17
|
+
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
18
|
+
import {
|
|
19
|
+
callMilkyClient,
|
|
20
|
+
createMilkyEndpointClient,
|
|
21
|
+
forwardMilkyClientEvents,
|
|
22
|
+
type MilkyClient,
|
|
23
|
+
} from './client.js';
|
|
24
|
+
import {
|
|
25
|
+
buildSendAction,
|
|
26
|
+
buildWsConnectOptions,
|
|
27
|
+
callApi,
|
|
28
|
+
extractInboundAudioUrl,
|
|
29
|
+
formatInboundContent,
|
|
30
|
+
formatInboundMessageId,
|
|
31
|
+
formatInboundSegments,
|
|
32
|
+
formatOutboundMessageId,
|
|
33
|
+
formatOutboundSegments,
|
|
34
|
+
isMentioned,
|
|
35
|
+
milkyInboundConversation,
|
|
36
|
+
parseMessageReceiveData,
|
|
37
|
+
parseMilkyMessageId,
|
|
38
|
+
senderNickname,
|
|
39
|
+
type MilkyEvent,
|
|
40
|
+
type MilkyIncomingMessage,
|
|
41
|
+
type MilkyWsConfig,
|
|
42
|
+
} from './protocol.js';
|
|
43
|
+
import type { MilkyWsCreateOptions, MilkyWsSocket } from './ws-types.js';
|
|
44
|
+
|
|
45
|
+
const WS_OPEN = 1;
|
|
46
|
+
|
|
47
|
+
export interface MilkyWsEndpointOptions {
|
|
48
|
+
readonly id: CapabilityId;
|
|
49
|
+
readonly config: MilkyWsConfig;
|
|
50
|
+
readonly createWebSocket?: (
|
|
51
|
+
url: string,
|
|
52
|
+
options: MilkyWsCreateOptions,
|
|
53
|
+
) => MilkyWsSocket;
|
|
54
|
+
readonly callApi?: typeof callApi;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class MilkyWsEndpoint extends ClientEndpoint<MilkyClient> {
|
|
58
|
+
readonly client: MilkyClient;
|
|
59
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
60
|
+
|
|
61
|
+
readonly #options: MilkyWsEndpointOptions;
|
|
62
|
+
readonly #callApi: typeof callApi;
|
|
63
|
+
readonly management: EndpointManagement;
|
|
64
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
65
|
+
readonly #lifecycle: EndpointLifecycle;
|
|
66
|
+
#ws?: MilkyWsSocket;
|
|
67
|
+
#clientSocketRelease?: () => void;
|
|
68
|
+
|
|
69
|
+
constructor(options: MilkyWsEndpointOptions) {
|
|
70
|
+
super();
|
|
71
|
+
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
72
|
+
this.#options = options;
|
|
73
|
+
this.#callApi = options.callApi ?? callApi;
|
|
74
|
+
this.client = createMilkyEndpointClient(options.config, this.#callApi);
|
|
75
|
+
this.management = createMilkyEndpointManagement({
|
|
76
|
+
callApi: (action, params) => callMilkyClient(this.client, action, params),
|
|
77
|
+
});
|
|
78
|
+
this.bindClientEvents(
|
|
79
|
+
(receive) => forwardMilkyClientEvents(this.client, receive),
|
|
80
|
+
(name, payload) => {
|
|
81
|
+
if (name === 'event') this.#admitRaw(payload as MilkyEvent);
|
|
82
|
+
},
|
|
83
|
+
(_name, error) => this.#warnPlatformEvent(error),
|
|
84
|
+
);
|
|
85
|
+
this.#lifecycle = createEndpointLifecycle({
|
|
86
|
+
name: options.config.id,
|
|
87
|
+
// reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
|
|
88
|
+
reconnect: {
|
|
89
|
+
initialIntervalMs: options.config.reconnect_interval,
|
|
90
|
+
multiplier: 1,
|
|
91
|
+
maxIntervalMs: Number.MAX_SAFE_INTEGER,
|
|
92
|
+
jitterMs: 0,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async start(): Promise<void> {
|
|
98
|
+
if (this.#lifecycle.started) return;
|
|
99
|
+
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
close(): void {
|
|
103
|
+
super.close();
|
|
104
|
+
this.#clientSocketRelease?.();
|
|
105
|
+
this.#clientSocketRelease = undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async stop(): Promise<void> {
|
|
109
|
+
this.close();
|
|
110
|
+
await this.#lifecycle.stop();
|
|
111
|
+
if (this.#ws) {
|
|
112
|
+
try {
|
|
113
|
+
this.#ws.close();
|
|
114
|
+
} catch {
|
|
115
|
+
/* ignore */
|
|
116
|
+
}
|
|
117
|
+
this.#ws = undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
122
|
+
const message = formatOutboundSegments(payload);
|
|
123
|
+
const { action, params } = buildSendAction(conversation, message);
|
|
124
|
+
const data = await callMilkyClient<{ message_seq?: number }>(this.client, action, params);
|
|
125
|
+
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
126
|
+
this.#logger.debug(formatCompact({
|
|
127
|
+
op: 'milky_send',
|
|
128
|
+
endpoint: this.#options.config.id,
|
|
129
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
130
|
+
messageId,
|
|
131
|
+
}));
|
|
132
|
+
return messageId;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async recallMessage(id: string): Promise<void> {
|
|
136
|
+
const parsed = parseMilkyMessageId(id);
|
|
137
|
+
if (!parsed) throw new Error(`Invalid message id: ${id}`);
|
|
138
|
+
if (parsed.message_scene === 'group') {
|
|
139
|
+
await callMilkyClient(this.client, 'recall_group_message', {
|
|
140
|
+
group_id: parsed.peer_id,
|
|
141
|
+
message_seq: parsed.message_seq,
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
await callMilkyClient(this.client, 'recall_private_message', {
|
|
145
|
+
user_id: parsed.peer_id,
|
|
146
|
+
message_seq: parsed.message_seq,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
#admitRaw(event: MilkyEvent): void {
|
|
152
|
+
const data = parseMessageReceiveData(event);
|
|
153
|
+
if (!data) return;
|
|
154
|
+
this.#admitMessage(data, event);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#warnPlatformEvent(error: unknown): void {
|
|
158
|
+
this.#logger.warn(formatCompact({
|
|
159
|
+
op: 'milky_platform_event_failed',
|
|
160
|
+
error: error instanceof Error ? error.message : String(error),
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#admitMessage(data: MilkyIncomingMessage, event: MilkyEvent): void {
|
|
165
|
+
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
166
|
+
const target = `${conversation.kind}:${conversation.id}`;
|
|
167
|
+
const content = formatInboundContent(data);
|
|
168
|
+
const segments = formatInboundSegments(data);
|
|
169
|
+
const audioUrl = extractInboundAudioUrl(data);
|
|
170
|
+
const nickname = senderNickname(data);
|
|
171
|
+
const mentioned = isMentioned(data, event.self_id);
|
|
172
|
+
void this.emit('message.receive', {
|
|
173
|
+
conversation,
|
|
174
|
+
message: { conversation, id: formatInboundMessageId(data) },
|
|
175
|
+
content,
|
|
176
|
+
segments,
|
|
177
|
+
sender: { id: String(data.sender_id), name: nickname },
|
|
178
|
+
endpointId: this.#options.config.id,
|
|
179
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
180
|
+
metadata: Object.freeze({
|
|
181
|
+
message_scene: data.message_scene,
|
|
182
|
+
peer_id: String(data.peer_id),
|
|
183
|
+
sender_id: String(data.sender_id),
|
|
184
|
+
message_seq: data.message_seq,
|
|
185
|
+
time: data.time ?? event.time,
|
|
186
|
+
self_id: event.self_id != null ? String(event.self_id) : undefined,
|
|
187
|
+
...(nickname ? { nickname } : {}),
|
|
188
|
+
}),
|
|
189
|
+
}).catch((err) => {
|
|
190
|
+
this.#logger.warn(formatCompact({
|
|
191
|
+
op: 'milky_gateway_receive_failed',
|
|
192
|
+
target,
|
|
193
|
+
error: err instanceof Error ? err.message : String(err),
|
|
194
|
+
}));
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async #connect(handle: EndpointConnectHandle): Promise<void> {
|
|
199
|
+
const { url, headers, safeUrl } = buildWsConnectOptions(this.#options.config);
|
|
200
|
+
const create = this.#options.createWebSocket
|
|
201
|
+
?? ((connectUrl: string, options: MilkyWsCreateOptions) =>
|
|
202
|
+
new WebSocket(connectUrl, { headers: options.headers }) as unknown as MilkyWsSocket);
|
|
203
|
+
|
|
204
|
+
await new Promise<void>((resolve, reject) => {
|
|
205
|
+
let settled = false;
|
|
206
|
+
const ws = create(url, { headers });
|
|
207
|
+
this.#ws = ws;
|
|
208
|
+
handle.onForceClose(() => {
|
|
209
|
+
try {
|
|
210
|
+
ws.close();
|
|
211
|
+
} catch {
|
|
212
|
+
/* ignore */
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
ws.on('open', () => {
|
|
217
|
+
if (settled) return;
|
|
218
|
+
settled = true;
|
|
219
|
+
if (!this.#options.config.access_token) {
|
|
220
|
+
this.#logger.warn(formatCompact({
|
|
221
|
+
endpoint: this.#options.config.id,
|
|
222
|
+
ok: false,
|
|
223
|
+
error: 'missing access_token',
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
this.#logger.debug(formatCompact({
|
|
227
|
+
endpoint: this.#options.config.id,
|
|
228
|
+
mode: 'ws',
|
|
229
|
+
url: safeUrl,
|
|
230
|
+
}));
|
|
231
|
+
// stop-during-connect 竞态:已停止则不再武装心跳(基座 stop 已清理定时器)
|
|
232
|
+
if (this.#lifecycle.started) {
|
|
233
|
+
this.#lifecycle.startHeartbeat(() => {
|
|
234
|
+
try {
|
|
235
|
+
if (ws.readyState === WS_OPEN) ws.ping?.();
|
|
236
|
+
} catch {
|
|
237
|
+
/* ignore */
|
|
238
|
+
}
|
|
239
|
+
}, this.#options.config.heartbeat_interval);
|
|
240
|
+
}
|
|
241
|
+
resolve();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
this.#clientSocketRelease?.();
|
|
245
|
+
this.#clientSocketRelease = this.client.acceptWebSocket(ws);
|
|
246
|
+
|
|
247
|
+
ws.on('close', (code, reason) => {
|
|
248
|
+
this.#clientSocketRelease?.();
|
|
249
|
+
this.#clientSocketRelease = undefined;
|
|
250
|
+
const reasonStr = typeof reason === 'string'
|
|
251
|
+
? reason
|
|
252
|
+
: Buffer.isBuffer(reason)
|
|
253
|
+
? reason.toString()
|
|
254
|
+
: String(reason ?? '');
|
|
255
|
+
const codeNum = typeof code === 'number' ? code : Number(code ?? 0);
|
|
256
|
+
const codeHint = codeNum === 1005
|
|
257
|
+
? ' [无状态,多为服务端/代理未发 close 帧即断开]'
|
|
258
|
+
: codeNum === 1006
|
|
259
|
+
? ' [异常关闭]'
|
|
260
|
+
: '';
|
|
261
|
+
this.#logger.warn(formatCompact({
|
|
262
|
+
op: 'disconnect',
|
|
263
|
+
code: codeNum,
|
|
264
|
+
error: `${reasonStr || 'closed'}${codeHint}`,
|
|
265
|
+
reconnect_ms: this.#options.config.reconnect_interval,
|
|
266
|
+
}));
|
|
267
|
+
// 基座语义:仅曾 open 的连接才武装重连;初始连接失败由 start() 的 catch 复位
|
|
268
|
+
handle.notifyClosed(new Error(`Milky WS 关闭: ${codeNum} ${reasonStr}`));
|
|
269
|
+
if (!settled) {
|
|
270
|
+
settled = true;
|
|
271
|
+
reject(new Error(`Milky WS 关闭: ${codeNum} ${reasonStr}`));
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
ws.on('error', (err) => {
|
|
276
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
277
|
+
this.#logger.warn(formatCompact({
|
|
278
|
+
op: 'ws_error',
|
|
279
|
+
endpoint: this.#options.config.id,
|
|
280
|
+
ok: false,
|
|
281
|
+
error: error.message,
|
|
282
|
+
}));
|
|
283
|
+
if (!settled) {
|
|
284
|
+
settled = true;
|
|
285
|
+
reject(error);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
}
|
package/src/ws-types.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Minimal WS surface used by the endpoint (real `ws` or test mock). */
|
|
2
|
+
export interface MilkyWsSocket {
|
|
3
|
+
readonly readyState: number;
|
|
4
|
+
send?(data: string): void;
|
|
5
|
+
close(code?: number, reason?: string): void;
|
|
6
|
+
ping?(): void;
|
|
7
|
+
on(event: 'open' | 'message' | 'close' | 'error', listener: (...args: unknown[]) => void): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MilkyWsCreateOptions {
|
|
11
|
+
readonly headers?: Record<string, string>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milky reverse WSS endpoint — httpHostToken WS upgrade inbound + baseUrl HTTP API outbound.
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
ClientEndpoint,
|
|
6
|
+
createEndpointLifecycle,
|
|
7
|
+
createRecallEndpointControl,
|
|
8
|
+
type EndpointLifecycle,
|
|
9
|
+
type EndpointControl,
|
|
10
|
+
type EndpointManagement,
|
|
11
|
+
type EndpointSendRequest,
|
|
12
|
+
} from 'zhin.js/adapter';
|
|
13
|
+
import type { HttpHost, WsConnection } from '@zhin.js/host-http';
|
|
14
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
15
|
+
import type { CapabilityId } from 'zhin.js';
|
|
16
|
+
import { verifyMilkyAccessToken } from './milky-auth.js';
|
|
17
|
+
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
18
|
+
import { callMilkyClient, createMilkyEndpointClient, forwardMilkyClientEvents, type MilkyClient } from './client.js';
|
|
19
|
+
import {
|
|
20
|
+
buildSendAction,
|
|
21
|
+
callApi,
|
|
22
|
+
extractInboundAudioUrl,
|
|
23
|
+
formatInboundContent,
|
|
24
|
+
formatInboundMessageId,
|
|
25
|
+
formatInboundSegments,
|
|
26
|
+
formatOutboundMessageId,
|
|
27
|
+
formatOutboundSegments,
|
|
28
|
+
isMentioned,
|
|
29
|
+
milkyInboundConversation,
|
|
30
|
+
parseMessageReceiveData,
|
|
31
|
+
parseMilkyMessageId,
|
|
32
|
+
senderNickname,
|
|
33
|
+
type MilkyEvent,
|
|
34
|
+
type MilkyIncomingMessage,
|
|
35
|
+
type MilkyWssConfig,
|
|
36
|
+
} from './protocol.js';
|
|
37
|
+
import type { MilkyWsSocket } from './ws-types.js';
|
|
38
|
+
|
|
39
|
+
const WS_OPEN = 1;
|
|
40
|
+
|
|
41
|
+
export interface MilkyWssEndpointOptions {
|
|
42
|
+
readonly id: CapabilityId;
|
|
43
|
+
readonly http: HttpHost;
|
|
44
|
+
readonly config: MilkyWssConfig;
|
|
45
|
+
readonly callApi?: typeof callApi;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
49
|
+
readonly client: MilkyClient;
|
|
50
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
51
|
+
|
|
52
|
+
readonly #options: MilkyWssEndpointOptions;
|
|
53
|
+
readonly #callApi: typeof callApi;
|
|
54
|
+
readonly management: EndpointManagement;
|
|
55
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
56
|
+
#ws?: MilkyWsSocket;
|
|
57
|
+
#wsRelease?: () => void;
|
|
58
|
+
#clientSocketRelease?: () => void;
|
|
59
|
+
readonly #lifecycle: EndpointLifecycle;
|
|
60
|
+
|
|
61
|
+
constructor(options: MilkyWssEndpointOptions) {
|
|
62
|
+
super();
|
|
63
|
+
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
64
|
+
this.#options = options;
|
|
65
|
+
this.#callApi = options.callApi ?? callApi;
|
|
66
|
+
this.#lifecycle = createEndpointLifecycle({
|
|
67
|
+
name: options.config.id,
|
|
68
|
+
reconnect: false,
|
|
69
|
+
heartbeat: { intervalMs: options.config.heartbeat_interval },
|
|
70
|
+
});
|
|
71
|
+
this.client = createMilkyEndpointClient(options.config, this.#callApi);
|
|
72
|
+
this.management = createMilkyEndpointManagement({
|
|
73
|
+
callApi: (action, params) => callMilkyClient(this.client, action, params),
|
|
74
|
+
});
|
|
75
|
+
this.bindClientEvents(
|
|
76
|
+
(receive) => forwardMilkyClientEvents(this.client, receive),
|
|
77
|
+
(name, payload) => {
|
|
78
|
+
if (name === 'event') this.#admitRaw(payload as MilkyEvent);
|
|
79
|
+
},
|
|
80
|
+
(_name, error) => this.#warnPlatformEvent(error),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async start(): Promise<void> {
|
|
85
|
+
await this.#lifecycle.start(async (lifecycleHandle) => {
|
|
86
|
+
const handle = this.#options.http.ws(this.#options.config.path);
|
|
87
|
+
this.#wsRelease = handle.onConnection((connection) => {
|
|
88
|
+
this.#acceptConnection(connection);
|
|
89
|
+
});
|
|
90
|
+
lifecycleHandle.onForceClose(() => {
|
|
91
|
+
this.#wsRelease?.();
|
|
92
|
+
this.#wsRelease = undefined;
|
|
93
|
+
this.#clientSocketRelease?.();
|
|
94
|
+
this.#clientSocketRelease = undefined;
|
|
95
|
+
try {
|
|
96
|
+
this.#ws?.close();
|
|
97
|
+
} catch {
|
|
98
|
+
/* ignore */
|
|
99
|
+
}
|
|
100
|
+
this.#ws = undefined;
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
this.#logger.info(formatCompact({
|
|
104
|
+
op: 'listen',
|
|
105
|
+
endpoint: this.#options.config.id,
|
|
106
|
+
mode: 'wss',
|
|
107
|
+
path: this.#options.config.path,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async stop(): Promise<void> {
|
|
112
|
+
this.close();
|
|
113
|
+
await this.#lifecycle.stop();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
117
|
+
const message = formatOutboundSegments(payload);
|
|
118
|
+
const { action, params } = buildSendAction(conversation, message);
|
|
119
|
+
const data = await callMilkyClient<{ message_seq?: number }>(this.client, action, params);
|
|
120
|
+
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
121
|
+
this.#logger.debug(formatCompact({
|
|
122
|
+
op: 'milky_send',
|
|
123
|
+
endpoint: this.#options.config.id,
|
|
124
|
+
target: `${conversation.kind}:${conversation.id}`,
|
|
125
|
+
messageId,
|
|
126
|
+
}));
|
|
127
|
+
return messageId;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async recallMessage(id: string): Promise<void> {
|
|
131
|
+
const parsed = parseMilkyMessageId(id);
|
|
132
|
+
if (!parsed) throw new Error(`Invalid message id: ${id}`);
|
|
133
|
+
if (parsed.message_scene === 'group') {
|
|
134
|
+
await callMilkyClient(this.client, 'recall_group_message', {
|
|
135
|
+
group_id: parsed.peer_id,
|
|
136
|
+
message_seq: parsed.message_seq,
|
|
137
|
+
});
|
|
138
|
+
} else {
|
|
139
|
+
await callMilkyClient(this.client, 'recall_private_message', {
|
|
140
|
+
user_id: parsed.peer_id,
|
|
141
|
+
message_seq: parsed.message_seq,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#admitRaw(event: MilkyEvent): void {
|
|
147
|
+
const data = parseMessageReceiveData(event);
|
|
148
|
+
if (!data) return;
|
|
149
|
+
this.#admitMessage(data, event);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#warnPlatformEvent(error: unknown): void {
|
|
153
|
+
this.#logger.warn(formatCompact({ op: 'milky_platform_event_failed', error: error instanceof Error ? error.message : String(error) }));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#admitMessage(data: MilkyIncomingMessage, event: MilkyEvent): void {
|
|
157
|
+
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
158
|
+
const target = `${conversation.kind}:${conversation.id}`;
|
|
159
|
+
const content = formatInboundContent(data);
|
|
160
|
+
const segments = formatInboundSegments(data);
|
|
161
|
+
const audioUrl = extractInboundAudioUrl(data);
|
|
162
|
+
const nickname = senderNickname(data);
|
|
163
|
+
const mentioned = isMentioned(data, event.self_id);
|
|
164
|
+
void this.emit('message.receive', {
|
|
165
|
+
conversation,
|
|
166
|
+
message: { conversation, id: formatInboundMessageId(data) },
|
|
167
|
+
content,
|
|
168
|
+
segments,
|
|
169
|
+
sender: { id: String(data.sender_id) },
|
|
170
|
+
endpointId: this.#options.config.id,
|
|
171
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
172
|
+
metadata: Object.freeze({
|
|
173
|
+
message_scene: data.message_scene,
|
|
174
|
+
peer_id: String(data.peer_id),
|
|
175
|
+
sender_id: String(data.sender_id),
|
|
176
|
+
message_seq: data.message_seq,
|
|
177
|
+
time: data.time ?? event.time,
|
|
178
|
+
self_id: event.self_id != null ? String(event.self_id) : undefined,
|
|
179
|
+
...(nickname ? { nickname } : {}),
|
|
180
|
+
}),
|
|
181
|
+
}).catch((err) => {
|
|
182
|
+
this.#logger.warn(formatCompact({
|
|
183
|
+
op: 'milky_gateway_receive_failed',
|
|
184
|
+
target,
|
|
185
|
+
error: err instanceof Error ? err.message : String(err),
|
|
186
|
+
}));
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#acceptConnection(connection: WsConnection): void {
|
|
191
|
+
if (!verifyMilkyAccessToken(this.#options.config.access_token, connection.request)) {
|
|
192
|
+
connection.socket.close(4003, 'Unauthorized');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const socket = connection.socket as unknown as MilkyWsSocket;
|
|
196
|
+
if (this.#ws) {
|
|
197
|
+
try {
|
|
198
|
+
this.#ws.close();
|
|
199
|
+
} catch {
|
|
200
|
+
/* ignore */
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
this.#ws = socket;
|
|
204
|
+
this.#lifecycle.startHeartbeat(() => {
|
|
205
|
+
try {
|
|
206
|
+
if (this.#ws?.readyState === WS_OPEN) this.#ws.ping?.();
|
|
207
|
+
} catch {
|
|
208
|
+
/* ignore */
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
this.#clientSocketRelease?.();
|
|
212
|
+
this.#clientSocketRelease = this.client.acceptWebSocket(socket);
|
|
213
|
+
socket.on('close', () => {
|
|
214
|
+
this.#clientSocketRelease?.();
|
|
215
|
+
this.#clientSocketRelease = undefined;
|
|
216
|
+
if (this.#ws === socket) {
|
|
217
|
+
this.#ws = undefined;
|
|
218
|
+
this.#lifecycle.stopHeartbeat();
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
this.#logger.debug(formatCompact({
|
|
222
|
+
endpoint: this.#options.config.id,
|
|
223
|
+
mode: 'wss',
|
|
224
|
+
peer: connection.request.socket.remoteAddress,
|
|
225
|
+
}));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
}
|
package/lib/adapter.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Milky 适配器:单一适配器支持 WS 正向 / SSE / Webhook / 反向 WS,由 config.connection 区分
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, Plugin } from 'zhin.js';
|
|
5
|
-
import { MilkyWsClient } from './bot-ws.js';
|
|
6
|
-
import { MilkySseClient } from './bot-sse.js';
|
|
7
|
-
import { MilkyWebhookBot } from './bot-webhook.js';
|
|
8
|
-
import { MilkyWssServer } from './bot-wss.js';
|
|
9
|
-
import type { MilkyBotConfig } from './types.js';
|
|
10
|
-
export type MilkyBot = MilkyWsClient | MilkySseClient | MilkyWebhookBot | MilkyWssServer;
|
|
11
|
-
export declare class MilkyAdapter extends Adapter<MilkyBot> {
|
|
12
|
-
#private;
|
|
13
|
-
constructor(plugin: Plugin);
|
|
14
|
-
createBot(config: MilkyBotConfig): MilkyBot;
|
|
15
|
-
kickMember(botId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
16
|
-
muteMember(botId: string, sceneId: string, userId: string, duration?: number): Promise<boolean>;
|
|
17
|
-
muteAll(botId: string, sceneId: string, enable?: boolean): Promise<boolean>;
|
|
18
|
-
setAdmin(botId: string, sceneId: string, userId: string, enable?: boolean): Promise<boolean>;
|
|
19
|
-
setMemberNickname(botId: string, sceneId: string, userId: string, nickname: string): Promise<boolean>;
|
|
20
|
-
setGroupName(botId: string, sceneId: string, name: string): Promise<boolean>;
|
|
21
|
-
listMembers(botId: string, sceneId: string): Promise<{
|
|
22
|
-
members: unknown[];
|
|
23
|
-
count: number;
|
|
24
|
-
}>;
|
|
25
|
-
getGroupInfo(botId: string, sceneId: string): Promise<unknown>;
|
|
26
|
-
start(): Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=adapter.d.ts.map
|
package/lib/adapter.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAiB,OAAO,EAAE,MAAM,EAAyB,MAAM,SAAS,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EACV,cAAc,EAKf,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,cAAc,GAAG,eAAe,GAAG,cAAc,CAAC;AAEzF,qBAAa,YAAa,SAAQ,OAAO,CAAC,QAAQ,CAAC;;gBAGrC,MAAM,EAAE,MAAM;IAI1B,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,QAAQ;IAiBrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMzD,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAM;IAMzE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAO;IAMrD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAO;IAMtE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAMlF,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMzD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;IAO1C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAM3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
|
package/lib/adapter.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Milky 适配器:单一适配器支持 WS 正向 / SSE / Webhook / 反向 WS,由 config.connection 区分
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter } from 'zhin.js';
|
|
5
|
-
import { MilkyWsClient } from './bot-ws.js';
|
|
6
|
-
import { MilkySseClient } from './bot-sse.js';
|
|
7
|
-
import { MilkyWebhookBot } from './bot-webhook.js';
|
|
8
|
-
import { MilkyWssServer } from './bot-wss.js';
|
|
9
|
-
export class MilkyAdapter extends Adapter {
|
|
10
|
-
#router;
|
|
11
|
-
constructor(plugin) {
|
|
12
|
-
super(plugin, 'milky', []);
|
|
13
|
-
}
|
|
14
|
-
createBot(config) {
|
|
15
|
-
switch (config.connection) {
|
|
16
|
-
case 'ws':
|
|
17
|
-
return new MilkyWsClient(this, config);
|
|
18
|
-
case 'sse':
|
|
19
|
-
return new MilkySseClient(this, config);
|
|
20
|
-
case 'webhook':
|
|
21
|
-
if (!this.#router)
|
|
22
|
-
throw new Error('Milky connection: webhook 需要 router,请安装并在配置中启用 @zhin.js/host-router');
|
|
23
|
-
return new MilkyWebhookBot(this, this.#router, config);
|
|
24
|
-
case 'wss':
|
|
25
|
-
if (!this.#router)
|
|
26
|
-
throw new Error('Milky connection: wss 需要 router,请安装并在配置中启用 @zhin.js/host-router');
|
|
27
|
-
return new MilkyWssServer(this, this.#router, config);
|
|
28
|
-
default:
|
|
29
|
-
throw new Error(`Unknown Milky connection: ${config.connection}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async kickMember(botId, sceneId, userId) {
|
|
33
|
-
const bot = this.bots.get(botId);
|
|
34
|
-
if (!bot)
|
|
35
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
36
|
-
return bot.kickMember(Number(sceneId), Number(userId), false);
|
|
37
|
-
}
|
|
38
|
-
async muteMember(botId, sceneId, userId, duration = 600) {
|
|
39
|
-
const bot = this.bots.get(botId);
|
|
40
|
-
if (!bot)
|
|
41
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
42
|
-
return bot.muteMember(Number(sceneId), Number(userId), duration);
|
|
43
|
-
}
|
|
44
|
-
async muteAll(botId, sceneId, enable = true) {
|
|
45
|
-
const bot = this.bots.get(botId);
|
|
46
|
-
if (!bot)
|
|
47
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
48
|
-
return bot.muteAll(Number(sceneId), enable);
|
|
49
|
-
}
|
|
50
|
-
async setAdmin(botId, sceneId, userId, enable = true) {
|
|
51
|
-
const bot = this.bots.get(botId);
|
|
52
|
-
if (!bot)
|
|
53
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
54
|
-
return bot.setAdmin(Number(sceneId), Number(userId), enable);
|
|
55
|
-
}
|
|
56
|
-
async setMemberNickname(botId, sceneId, userId, nickname) {
|
|
57
|
-
const bot = this.bots.get(botId);
|
|
58
|
-
if (!bot)
|
|
59
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
60
|
-
return bot.setCard(Number(sceneId), Number(userId), nickname);
|
|
61
|
-
}
|
|
62
|
-
async setGroupName(botId, sceneId, name) {
|
|
63
|
-
const bot = this.bots.get(botId);
|
|
64
|
-
if (!bot)
|
|
65
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
66
|
-
return bot.setGroupName(Number(sceneId), name);
|
|
67
|
-
}
|
|
68
|
-
async listMembers(botId, sceneId) {
|
|
69
|
-
const bot = this.bots.get(botId);
|
|
70
|
-
if (!bot)
|
|
71
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
72
|
-
const members = await bot.getMemberList(Number(sceneId));
|
|
73
|
-
return { members: Array.isArray(members) ? members : [], count: Array.isArray(members) ? members.length : 0 };
|
|
74
|
-
}
|
|
75
|
-
async getGroupInfo(botId, sceneId) {
|
|
76
|
-
const bot = this.bots.get(botId);
|
|
77
|
-
if (!bot)
|
|
78
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
79
|
-
return bot.getGroupInfo(Number(sceneId));
|
|
80
|
-
}
|
|
81
|
-
async start() {
|
|
82
|
-
// 同步获取已就绪的 router,或通过 useContext 在 router 挂载后赋值
|
|
83
|
-
this.#router = this.plugin.inject('router');
|
|
84
|
-
this.plugin.useContext('router', (router) => {
|
|
85
|
-
this.#router = router;
|
|
86
|
-
});
|
|
87
|
-
await super.start();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
//# sourceMappingURL=adapter.js.map
|
package/lib/adapter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/lib/api.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export interface MilkyApiClientOptions {
|
|
2
|
-
baseUrl: string;
|
|
3
|
-
access_token?: string;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* 调用协议端 API:POST {baseUrl}/api/{apiName},Body JSON,鉴权。
|
|
7
|
-
* 非 200 或 retcode !== 0 时抛错。
|
|
8
|
-
*/
|
|
9
|
-
export declare function callApi<T = unknown>(options: MilkyApiClientOptions, apiName: string, params?: Record<string, unknown>): Promise<T>;
|
|
10
|
-
//# sourceMappingURL=api.d.ts.map
|
package/lib/api.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD;;;GAGG;AACH,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EACvC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
|