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