@zhin.js/adapter-milky 6.0.14 → 7.0.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.
- package/CHANGELOG.md +37 -0
- package/README.md +24 -3
- package/adapters/milky.js +1 -11
- package/adapters/milky.ts +1 -11
- package/lib/client.d.ts +21 -0
- package/lib/client.js +33 -0
- package/lib/endpoint.d.ts +1 -1
- package/lib/endpoint.js +1 -1
- package/lib/index.d.ts +5 -2
- package/lib/index.js +3 -2
- package/lib/milky-auth.d.ts +0 -1
- package/lib/milky-auth.js +0 -14
- package/lib/milky-endpoint-commands.d.ts +1 -1
- package/lib/protocol.d.ts +3 -3
- package/lib/protocol.js +2 -5
- package/lib/sse-endpoint.d.ts +6 -23
- package/lib/sse-endpoint.js +25 -87
- package/lib/webhook-endpoint.d.ts +6 -23
- package/lib/webhook-endpoint.js +29 -96
- package/lib/ws-endpoint.d.ts +6 -24
- package/lib/ws-endpoint.js +36 -116
- package/lib/wss-endpoint.d.ts +9 -23
- package/lib/wss-endpoint.js +65 -148
- package/package.json +16 -13
- package/src/client.ts +80 -0
- package/src/endpoint.ts +1 -1
- package/src/index.ts +17 -7
- package/src/milky-auth.ts +0 -15
- package/src/protocol.ts +4 -7
- package/src/sse-endpoint.ts +30 -102
- package/src/webhook-endpoint.ts +37 -113
- package/src/ws-endpoint.ts +46 -128
- package/src/wss-endpoint.ts +73 -161
- package/lib/milky-agent-deps.d.ts +0 -24
- package/lib/milky-agent-deps.js +0 -30
- package/src/milky-agent-deps.ts +0 -53
package/src/sse-endpoint.ts
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
* Milky SSE client endpoint — GET text/event-stream on /event.
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
+
ClientEndpoint,
|
|
6
|
+
createRecallEndpointControl,
|
|
5
7
|
createEndpointLifecycle,
|
|
6
8
|
type EndpointConnectHandle,
|
|
7
|
-
type
|
|
9
|
+
type EndpointControl,
|
|
8
10
|
type EndpointLifecycle,
|
|
9
11
|
type EndpointManagement,
|
|
10
12
|
type EndpointSendRequest,
|
|
11
13
|
} from 'zhin.js/adapter';
|
|
12
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
13
14
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
14
15
|
import type { CapabilityId } from 'zhin.js';
|
|
15
16
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
16
|
-
import {
|
|
17
|
+
import { callMilkyClient, createMilkyEndpointClient, forwardMilkyClientEvents, type MilkyClient } from './client.js';
|
|
17
18
|
import {
|
|
18
19
|
buildSendAction,
|
|
19
20
|
buildSseConnectOptions,
|
|
@@ -45,28 +46,38 @@ export type CreateMilkySseStream = (options: {
|
|
|
45
46
|
|
|
46
47
|
export interface MilkySseEndpointOptions {
|
|
47
48
|
readonly id: CapabilityId;
|
|
48
|
-
readonly gateway: MessageGateway;
|
|
49
|
-
readonly sideEvents?: SideEventGateway;
|
|
50
49
|
readonly config: MilkySseConfig;
|
|
51
50
|
readonly createSseStream?: CreateMilkySseStream;
|
|
52
51
|
readonly callApi?: typeof callApi;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
export class MilkySseEndpoint
|
|
54
|
+
export class MilkySseEndpoint extends ClientEndpoint<MilkyClient> {
|
|
55
|
+
readonly client: MilkyClient;
|
|
56
56
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
57
57
|
|
|
58
58
|
readonly #options: MilkySseEndpointOptions;
|
|
59
59
|
readonly #callApi: typeof callApi;
|
|
60
|
-
readonly management: EndpointManagement
|
|
60
|
+
readonly management: EndpointManagement;
|
|
61
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
61
62
|
readonly #lifecycle: EndpointLifecycle;
|
|
62
63
|
#stream?: SseClientHandle;
|
|
63
|
-
#open = false;
|
|
64
|
-
#unregisterAgent?: () => void;
|
|
65
64
|
|
|
66
65
|
constructor(options: MilkySseEndpointOptions) {
|
|
66
|
+
super();
|
|
67
67
|
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
68
68
|
this.#options = options;
|
|
69
69
|
this.#callApi = options.callApi ?? callApi;
|
|
70
|
+
this.client = createMilkyEndpointClient(options.config, this.#callApi);
|
|
71
|
+
this.management = createMilkyEndpointManagement({
|
|
72
|
+
callApi: (action, params) => callMilkyClient(this.client, action, params),
|
|
73
|
+
});
|
|
74
|
+
this.bindClientEvents(
|
|
75
|
+
(receive) => forwardMilkyClientEvents(this.client, receive),
|
|
76
|
+
(name, payload) => {
|
|
77
|
+
if (name === 'event') this.#admitRaw(payload as MilkyEvent);
|
|
78
|
+
},
|
|
79
|
+
(_name, error) => this.#warnPlatformEvent(error),
|
|
80
|
+
);
|
|
70
81
|
this.#lifecycle = createEndpointLifecycle({
|
|
71
82
|
name: options.config.id,
|
|
72
83
|
// reconnect_interval 旧语义为固定间隔:multiplier 1 + 无 jitter + 不封顶
|
|
@@ -81,30 +92,17 @@ export class MilkySseEndpoint implements EndpointInstance {
|
|
|
81
92
|
|
|
82
93
|
async start(): Promise<void> {
|
|
83
94
|
if (this.#lifecycle.started) return;
|
|
84
|
-
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
|
|
85
95
|
try {
|
|
86
96
|
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
87
97
|
} catch (err) {
|
|
88
98
|
// 与 WS 对齐:start 失败复位由基座保证;agent 反注册留在适配器侧,允许重试
|
|
89
|
-
this.#unregisterAgent?.();
|
|
90
|
-
this.#unregisterAgent = undefined;
|
|
91
99
|
throw err;
|
|
92
100
|
}
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
open(): void {
|
|
96
|
-
this.#open = true;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
close(): void {
|
|
100
|
-
this.#open = false;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
103
|
async stop(): Promise<void> {
|
|
104
|
-
this
|
|
104
|
+
this.close();
|
|
105
105
|
await this.#lifecycle.stop();
|
|
106
|
-
this.#unregisterAgent?.();
|
|
107
|
-
this.#unregisterAgent = undefined;
|
|
108
106
|
this.#stream?.close();
|
|
109
107
|
this.#stream = undefined;
|
|
110
108
|
}
|
|
@@ -112,7 +110,7 @@ export class MilkySseEndpoint implements EndpointInstance {
|
|
|
112
110
|
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
113
111
|
const message = formatOutboundSegments(payload);
|
|
114
112
|
const { action, params } = buildSendAction(conversation, message);
|
|
115
|
-
const data = await
|
|
113
|
+
const data = await callMilkyClient<{ message_seq?: number }>(this.client, action, params);
|
|
116
114
|
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
117
115
|
this.#logger.debug(formatCompact({
|
|
118
116
|
op: 'milky_send',
|
|
@@ -124,100 +122,30 @@ export class MilkySseEndpoint implements EndpointInstance {
|
|
|
124
122
|
return messageId;
|
|
125
123
|
}
|
|
126
124
|
|
|
127
|
-
callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
128
|
-
return this.#callApi(this.apiOptions(), action, params);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
125
|
async recallMessage(id: string): Promise<void> {
|
|
132
126
|
const parsed = parseMilkyMessageId(id);
|
|
133
127
|
if (!parsed) throw new Error(`Invalid message id: ${id}`);
|
|
134
128
|
if (parsed.message_scene === 'group') {
|
|
135
|
-
await this.
|
|
129
|
+
await callMilkyClient(this.client, 'recall_group_message', {
|
|
136
130
|
group_id: parsed.peer_id,
|
|
137
131
|
message_seq: parsed.message_seq,
|
|
138
132
|
});
|
|
139
133
|
} else {
|
|
140
|
-
await this.
|
|
134
|
+
await callMilkyClient(this.client, 'recall_private_message', {
|
|
141
135
|
user_id: parsed.peer_id,
|
|
142
136
|
message_seq: parsed.message_seq,
|
|
143
137
|
});
|
|
144
138
|
}
|
|
145
139
|
}
|
|
146
140
|
|
|
147
|
-
|
|
148
|
-
await this.callApi('kick_group_member', {
|
|
149
|
-
group_id: groupId,
|
|
150
|
-
user_id: userId,
|
|
151
|
-
reject_add_request: rejectAddRequest,
|
|
152
|
-
});
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async muteMember(groupId: number, userId: number, duration = 600): Promise<boolean> {
|
|
157
|
-
await this.callApi('set_group_member_mute', {
|
|
158
|
-
group_id: groupId,
|
|
159
|
-
user_id: userId,
|
|
160
|
-
duration,
|
|
161
|
-
});
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async muteAll(groupId: number, enable = true): Promise<boolean> {
|
|
166
|
-
await this.callApi('set_group_whole_mute', { group_id: groupId, is_mute: enable });
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async setAdmin(groupId: number, userId: number, enable = true): Promise<boolean> {
|
|
171
|
-
await this.callApi('set_group_member_admin', {
|
|
172
|
-
group_id: groupId,
|
|
173
|
-
user_id: userId,
|
|
174
|
-
is_set: enable,
|
|
175
|
-
});
|
|
176
|
-
return true;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async setCard(groupId: number, userId: number, card: string): Promise<boolean> {
|
|
180
|
-
await this.callApi('set_group_member_card', {
|
|
181
|
-
group_id: groupId,
|
|
182
|
-
user_id: userId,
|
|
183
|
-
card,
|
|
184
|
-
});
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async setTitle(groupId: number, userId: number, title: string): Promise<boolean> {
|
|
189
|
-
await this.callApi('set_group_member_special_title', {
|
|
190
|
-
group_id: groupId,
|
|
191
|
-
user_id: userId,
|
|
192
|
-
special_title: title,
|
|
193
|
-
});
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async setGroupName(groupId: number, name: string): Promise<boolean> {
|
|
198
|
-
await this.callApi('set_group_name', { group_id: groupId, new_group_name: name });
|
|
199
|
-
return true;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async getMemberList(groupId: number): Promise<unknown[]> {
|
|
203
|
-
return this.callApi('get_group_member_list', { group_id: groupId }) as Promise<unknown[]>;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async getGroupInfo(groupId: number): Promise<unknown> {
|
|
207
|
-
return this.callApi('get_group_info', { group_id: groupId });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
admit(event: MilkyEvent): void {
|
|
141
|
+
#admitRaw(event: MilkyEvent): void {
|
|
211
142
|
const data = parseMessageReceiveData(event);
|
|
212
|
-
if (!
|
|
143
|
+
if (!data) return;
|
|
213
144
|
this.#admitMessage(data, event);
|
|
214
145
|
}
|
|
215
146
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
baseUrl: this.#options.config.baseUrl,
|
|
219
|
-
access_token: this.#options.config.access_token,
|
|
220
|
-
};
|
|
147
|
+
#warnPlatformEvent(error: unknown): void {
|
|
148
|
+
this.#logger.warn(formatCompact({ op: 'milky_platform_event_failed', error: error instanceof Error ? error.message : String(error) }));
|
|
221
149
|
}
|
|
222
150
|
|
|
223
151
|
#admitMessage(data: MilkyIncomingMessage, event: MilkyEvent): void {
|
|
@@ -228,7 +156,7 @@ export class MilkySseEndpoint implements EndpointInstance {
|
|
|
228
156
|
const audioUrl = extractInboundAudioUrl(data);
|
|
229
157
|
const nickname = senderNickname(data);
|
|
230
158
|
const mentioned = isMentioned(data, event.self_id);
|
|
231
|
-
void this
|
|
159
|
+
void this.emit('message.receive', {
|
|
232
160
|
conversation,
|
|
233
161
|
message: { conversation, id: formatInboundMessageId(data) },
|
|
234
162
|
content,
|
|
@@ -317,7 +245,7 @@ export class MilkySseEndpoint implements EndpointInstance {
|
|
|
317
245
|
#onMessage(data: string): void {
|
|
318
246
|
try {
|
|
319
247
|
const event = JSON.parse(data) as MilkyEvent;
|
|
320
|
-
this.
|
|
248
|
+
this.client.ingest(event as Parameters<MilkyClient['ingest']>[0]);
|
|
321
249
|
} catch (error) {
|
|
322
250
|
this.#logger.warn(formatCompact({
|
|
323
251
|
op: 'milky_parse_failed',
|
package/src/webhook-endpoint.ts
CHANGED
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
* Milky webhook endpoint — httpHostToken POST inbound + baseUrl HTTP API outbound.
|
|
3
3
|
*/
|
|
4
4
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
import {
|
|
6
|
+
ClientEndpoint,
|
|
7
|
+
createRecallEndpointControl,
|
|
8
|
+
type EndpointControl,
|
|
9
|
+
type EndpointManagement,
|
|
10
|
+
type EndpointSendRequest,
|
|
9
11
|
} from 'zhin.js/adapter';
|
|
10
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
11
12
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
12
13
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
13
14
|
import type { CapabilityId } from 'zhin.js';
|
|
14
|
-
import {
|
|
15
|
+
import { verifyMilkyAccessToken } from './milky-auth.js';
|
|
15
16
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
16
|
-
import {
|
|
17
|
+
import { callMilkyClient, createMilkyEndpointClient, forwardMilkyClientEvents, type MilkyClient } from './client.js';
|
|
17
18
|
import {
|
|
18
19
|
buildSendAction,
|
|
19
20
|
callApi,
|
|
@@ -35,34 +36,43 @@ import {
|
|
|
35
36
|
|
|
36
37
|
export interface MilkyWebhookEndpointOptions {
|
|
37
38
|
readonly id: CapabilityId;
|
|
38
|
-
readonly gateway: MessageGateway;
|
|
39
|
-
readonly sideEvents?: SideEventGateway;
|
|
40
39
|
readonly http: HttpHost;
|
|
41
40
|
readonly config: MilkyWebhookConfig;
|
|
42
41
|
readonly callApi?: typeof callApi;
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
export class MilkyWebhookEndpoint
|
|
44
|
+
export class MilkyWebhookEndpoint extends ClientEndpoint<MilkyClient> {
|
|
45
|
+
readonly client: MilkyClient;
|
|
46
46
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
47
47
|
|
|
48
48
|
readonly #options: MilkyWebhookEndpointOptions;
|
|
49
49
|
readonly #callApi: typeof callApi;
|
|
50
|
-
readonly management: EndpointManagement
|
|
50
|
+
readonly management: EndpointManagement;
|
|
51
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
51
52
|
#routeReleases: HttpRouteRegistration[] = [];
|
|
52
|
-
#open = false;
|
|
53
53
|
#started = false;
|
|
54
|
-
#unregisterAgent?: () => void;
|
|
55
54
|
|
|
56
55
|
constructor(options: MilkyWebhookEndpointOptions) {
|
|
56
|
+
super();
|
|
57
57
|
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
58
58
|
this.#options = options;
|
|
59
59
|
this.#callApi = options.callApi ?? callApi;
|
|
60
|
+
this.client = createMilkyEndpointClient(options.config, this.#callApi);
|
|
61
|
+
this.management = createMilkyEndpointManagement({
|
|
62
|
+
callApi: (action, params) => callMilkyClient(this.client, action, params),
|
|
63
|
+
});
|
|
64
|
+
this.bindClientEvents(
|
|
65
|
+
(receive) => forwardMilkyClientEvents(this.client, receive),
|
|
66
|
+
(name, payload) => {
|
|
67
|
+
if (name === 'event') this.#admitRaw(payload as MilkyEvent);
|
|
68
|
+
},
|
|
69
|
+
(_name, error) => this.#warnPlatformEvent(error),
|
|
70
|
+
);
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
async start(): Promise<void> {
|
|
63
74
|
if (this.#started) return;
|
|
64
75
|
this.#started = true;
|
|
65
|
-
this.#unregisterAgent = registerMilkyAgentEndpoint(this.#options.config.id, this);
|
|
66
76
|
this.#setupRoutes();
|
|
67
77
|
this.#logger.info(formatCompact({
|
|
68
78
|
op: 'listen',
|
|
@@ -72,19 +82,9 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
|
|
|
72
82
|
}));
|
|
73
83
|
}
|
|
74
84
|
|
|
75
|
-
open(): void {
|
|
76
|
-
this.#open = true;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
close(): void {
|
|
80
|
-
this.#open = false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
85
|
async stop(): Promise<void> {
|
|
84
|
-
this
|
|
86
|
+
this.close();
|
|
85
87
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
86
|
-
this.#unregisterAgent?.();
|
|
87
|
-
this.#unregisterAgent = undefined;
|
|
88
88
|
this.#started = false;
|
|
89
89
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
90
90
|
}
|
|
@@ -92,7 +92,7 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
|
|
|
92
92
|
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
93
93
|
const message = formatOutboundSegments(payload);
|
|
94
94
|
const { action, params } = buildSendAction(conversation, message);
|
|
95
|
-
const data = await
|
|
95
|
+
const data = await callMilkyClient<{ message_seq?: number }>(this.client, action, params);
|
|
96
96
|
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
97
97
|
this.#logger.debug(formatCompact({
|
|
98
98
|
op: 'milky_send',
|
|
@@ -103,100 +103,30 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
|
|
|
103
103
|
return messageId;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
107
|
-
return this.#callApi(this.apiOptions(), action, params);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
106
|
async recallMessage(id: string): Promise<void> {
|
|
111
107
|
const parsed = parseMilkyMessageId(id);
|
|
112
108
|
if (!parsed) throw new Error(`Invalid message id: ${id}`);
|
|
113
109
|
if (parsed.message_scene === 'group') {
|
|
114
|
-
await this.
|
|
110
|
+
await callMilkyClient(this.client, 'recall_group_message', {
|
|
115
111
|
group_id: parsed.peer_id,
|
|
116
112
|
message_seq: parsed.message_seq,
|
|
117
113
|
});
|
|
118
114
|
} else {
|
|
119
|
-
await this.
|
|
115
|
+
await callMilkyClient(this.client, 'recall_private_message', {
|
|
120
116
|
user_id: parsed.peer_id,
|
|
121
117
|
message_seq: parsed.message_seq,
|
|
122
118
|
});
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
await this.callApi('kick_group_member', {
|
|
128
|
-
group_id: groupId,
|
|
129
|
-
user_id: userId,
|
|
130
|
-
reject_add_request: rejectAddRequest,
|
|
131
|
-
});
|
|
132
|
-
return true;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async muteMember(groupId: number, userId: number, duration = 600): Promise<boolean> {
|
|
136
|
-
await this.callApi('set_group_member_mute', {
|
|
137
|
-
group_id: groupId,
|
|
138
|
-
user_id: userId,
|
|
139
|
-
duration,
|
|
140
|
-
});
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async muteAll(groupId: number, enable = true): Promise<boolean> {
|
|
145
|
-
await this.callApi('set_group_whole_mute', { group_id: groupId, is_mute: enable });
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async setAdmin(groupId: number, userId: number, enable = true): Promise<boolean> {
|
|
150
|
-
await this.callApi('set_group_member_admin', {
|
|
151
|
-
group_id: groupId,
|
|
152
|
-
user_id: userId,
|
|
153
|
-
is_set: enable,
|
|
154
|
-
});
|
|
155
|
-
return true;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async setCard(groupId: number, userId: number, card: string): Promise<boolean> {
|
|
159
|
-
await this.callApi('set_group_member_card', {
|
|
160
|
-
group_id: groupId,
|
|
161
|
-
user_id: userId,
|
|
162
|
-
card,
|
|
163
|
-
});
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async setTitle(groupId: number, userId: number, title: string): Promise<boolean> {
|
|
168
|
-
await this.callApi('set_group_member_special_title', {
|
|
169
|
-
group_id: groupId,
|
|
170
|
-
user_id: userId,
|
|
171
|
-
special_title: title,
|
|
172
|
-
});
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async setGroupName(groupId: number, name: string): Promise<boolean> {
|
|
177
|
-
await this.callApi('set_group_name', { group_id: groupId, new_group_name: name });
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async getMemberList(groupId: number): Promise<unknown[]> {
|
|
182
|
-
return this.callApi('get_group_member_list', { group_id: groupId }) as Promise<unknown[]>;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async getGroupInfo(groupId: number): Promise<unknown> {
|
|
186
|
-
return this.callApi('get_group_info', { group_id: groupId });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
admit(event: MilkyEvent): void {
|
|
122
|
+
#admitRaw(event: MilkyEvent): void {
|
|
190
123
|
const data = parseMessageReceiveData(event);
|
|
191
|
-
if (!
|
|
124
|
+
if (!data) return;
|
|
192
125
|
this.#admitMessage(data, event);
|
|
193
126
|
}
|
|
194
127
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
baseUrl: this.#options.config.baseUrl,
|
|
198
|
-
access_token: this.#options.config.access_token,
|
|
199
|
-
};
|
|
128
|
+
#warnPlatformEvent(error: unknown): void {
|
|
129
|
+
this.#logger.warn(formatCompact({ op: 'milky_platform_event_failed', error: error instanceof Error ? error.message : String(error) }));
|
|
200
130
|
}
|
|
201
131
|
|
|
202
132
|
#admitMessage(data: MilkyIncomingMessage, event: MilkyEvent): void {
|
|
@@ -207,7 +137,7 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
|
|
|
207
137
|
const audioUrl = extractInboundAudioUrl(data);
|
|
208
138
|
const nickname = senderNickname(data);
|
|
209
139
|
const mentioned = isMentioned(data, event.self_id);
|
|
210
|
-
void this
|
|
140
|
+
void this.emit('message.receive', {
|
|
211
141
|
conversation,
|
|
212
142
|
message: { conversation, id: formatInboundMessageId(data) },
|
|
213
143
|
content,
|
|
@@ -249,18 +179,12 @@ export class MilkyWebhookEndpoint implements EndpointInstance {
|
|
|
249
179
|
response.end(JSON.stringify({ message: 'Unauthorized' }));
|
|
250
180
|
return;
|
|
251
181
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
event = JSON.parse(raw) as MilkyEvent;
|
|
256
|
-
} catch {
|
|
257
|
-
response.writeHead(400, { 'Content-Type': 'application/json' });
|
|
258
|
-
response.end(JSON.stringify({ message: 'Invalid JSON' }));
|
|
182
|
+
if (!this.clientEventsOpen) {
|
|
183
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
184
|
+
response.end(JSON.stringify({ status: 'ok' }));
|
|
259
185
|
return;
|
|
260
186
|
}
|
|
261
|
-
|
|
262
|
-
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
263
|
-
response.end(JSON.stringify({ status: 'ok' }));
|
|
187
|
+
await this.client.acceptHttp(request, response);
|
|
264
188
|
} catch (error) {
|
|
265
189
|
this.#logger.error('Milky webhook error:', error);
|
|
266
190
|
if (!response.headersSent) {
|