@zhin.js/adapter-milky 1.1.18 → 1.1.19
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 +36 -0
- package/README.md +9 -6
- package/adapters/milky/index.js +3 -36
- package/adapters/milky/index.ts +2 -41
- package/commands/milky/endpoint/definition.js +0 -2
- package/commands/milky/endpoint/definition.ts +0 -2
- package/lib/adapter.d.ts +21 -0
- package/lib/adapter.js +36 -0
- package/lib/client.d.ts +20 -15
- package/lib/client.js +28 -21
- package/lib/console.d.ts +1 -1
- package/lib/console.js +2 -5
- package/lib/endpoint-management.d.ts +2 -2
- package/lib/endpoint-management.js +8 -8
- package/lib/index.d.ts +3 -2
- package/lib/index.js +2 -1
- package/lib/protocol.d.ts +6 -1
- package/lib/protocol.js +15 -14
- package/lib/sse-endpoint.d.ts +5 -10
- package/lib/sse-endpoint.js +52 -33
- package/lib/webhook-endpoint.d.ts +5 -10
- package/lib/webhook-endpoint.js +55 -34
- package/lib/ws-endpoint.d.ts +5 -11
- package/lib/ws-endpoint.js +54 -35
- package/lib/wss-endpoint.d.ts +5 -10
- package/lib/wss-endpoint.js +52 -33
- package/package.json +17 -17
- package/plugin.js +0 -4
- package/src/adapter.ts +39 -0
- package/src/client.ts +37 -43
- package/src/console.ts +2 -5
- package/src/endpoint-management.ts +15 -12
- package/src/index.ts +2 -1
- package/src/protocol.ts +18 -12
- package/src/sse-endpoint.ts +45 -31
- package/src/webhook-endpoint.ts +48 -32
- package/src/ws-endpoint.ts +49 -35
- package/src/wss-endpoint.ts +45 -31
- package/lib/milky-runtime-state.d.ts +0 -1
- package/lib/milky-runtime-state.js +0 -6
- package/src/milky-runtime-state.ts +0 -7
package/src/wss-endpoint.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Milky reverse WSS endpoint — httpHostToken WS upgrade inbound + baseUrl HTTP API outbound.
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
createEndpointSpecification, endpointSpec, type Endpoint, type EndpointSpecification,
|
|
6
6
|
createEndpointLifecycle,
|
|
7
7
|
createRecallEndpointControl,
|
|
8
8
|
type EndpointLifecycle,
|
|
@@ -15,7 +15,7 @@ import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
|
15
15
|
import type { CapabilityId } from 'zhin.js';
|
|
16
16
|
import { verifyMilkyAccessToken } from './milky-auth.js';
|
|
17
17
|
import { createMilkyEndpointManagement } from './endpoint-management.js';
|
|
18
|
-
import {
|
|
18
|
+
import { createMilkyActionCaller, readMilkyResponse, type MilkyActionCaller, milkyClientOptions, forwardMilkyClientEvents, MilkyClient } from './client.js';
|
|
19
19
|
import {
|
|
20
20
|
buildSendAction,
|
|
21
21
|
callApi,
|
|
@@ -40,19 +40,21 @@ const WS_OPEN = 1;
|
|
|
40
40
|
|
|
41
41
|
export interface MilkyWssEndpointOptions {
|
|
42
42
|
readonly id: CapabilityId;
|
|
43
|
+
readonly signal?: AbortSignal;
|
|
43
44
|
readonly http: HttpHost;
|
|
44
45
|
readonly config: MilkyWssConfig;
|
|
45
46
|
readonly callApi?: typeof callApi;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
export class MilkyWssEndpoint extends
|
|
49
|
-
readonly
|
|
49
|
+
export class MilkyWssEndpoint extends MilkyClient implements Endpoint {
|
|
50
|
+
readonly [endpointSpec]: EndpointSpecification;
|
|
51
|
+
#open = false;
|
|
50
52
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
51
53
|
|
|
52
54
|
readonly #options: MilkyWssEndpointOptions;
|
|
53
|
-
readonly #
|
|
54
|
-
readonly
|
|
55
|
-
readonly control: EndpointControl = createRecallEndpointControl((id) => this
|
|
55
|
+
readonly #management: EndpointManagement;
|
|
56
|
+
readonly #call: MilkyActionCaller;
|
|
57
|
+
readonly #control: EndpointControl = createRecallEndpointControl((id, signal) => this.#recallMessage({ id, signal }));
|
|
56
58
|
#ws?: MilkyWsSocket;
|
|
57
59
|
#wsRelease?: () => void;
|
|
58
60
|
#clientSocketRelease?: () => void;
|
|
@@ -61,28 +63,37 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
61
63
|
#started = false;
|
|
62
64
|
|
|
63
65
|
constructor(options: MilkyWssEndpointOptions) {
|
|
64
|
-
|
|
66
|
+
const call = createMilkyActionCaller({ config: options.config, request: options.callApi ?? callApi, signal: options.signal });
|
|
67
|
+
super(milkyClientOptions({ config: options.config, call }));
|
|
68
|
+
this.#call = call;
|
|
65
69
|
this.#logger = getAdapterLogger('milky', options.config.id);
|
|
66
70
|
this.#options = options;
|
|
67
|
-
this.#callApi = options.callApi ?? callApi;
|
|
68
71
|
this.#connectionLifecycle = createEndpointLifecycle({
|
|
69
72
|
name: `${options.config.id}:inbound`,
|
|
70
73
|
reconnect: false,
|
|
71
74
|
});
|
|
72
|
-
this
|
|
73
|
-
|
|
74
|
-
callApi: (action, params) => callMilkyClient(this.client, action, params),
|
|
75
|
+
this.#management = createMilkyEndpointManagement({
|
|
76
|
+
callApi: request => call(request).then(response => readMilkyResponse(response, request.action)),
|
|
75
77
|
});
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
const readTransportState = () => this.#connectionLifecycle.state;
|
|
79
|
+
this[endpointSpec] = createEndpointSpecification(this, {
|
|
80
|
+
name: options.config.id,
|
|
81
|
+
start: () => this.#start(), open: () => { this.#open = true; },
|
|
82
|
+
close: () => { this.#open = false; }, stop: () => this.#stop(),
|
|
83
|
+
send: request => this.#send(request),
|
|
84
|
+
management: this.#management, control: this.#control,
|
|
85
|
+
get transportState() { return readTransportState(); },
|
|
86
|
+
});
|
|
87
|
+
forwardMilkyClientEvents(this, (name, payload) => {
|
|
88
|
+
void this[endpointSpec].events.run(() => {
|
|
89
|
+
if (!this.#open && !this.#started) return;
|
|
90
|
+
void this[endpointSpec].events.platform(name, payload).catch(error => this.#warnPlatformEvent(error));
|
|
79
91
|
if (name === 'event') this.#admitRaw(payload as MilkyEvent);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
);
|
|
92
|
+
}).catch(error => this.#warnPlatformEvent(error));
|
|
93
|
+
});
|
|
83
94
|
}
|
|
84
95
|
|
|
85
|
-
async start(): Promise<void> {
|
|
96
|
+
async #start(): Promise<void> {
|
|
86
97
|
if (this.#started) return;
|
|
87
98
|
this.#started = true;
|
|
88
99
|
const handle = this.#options.http.ws(this.#options.config.path);
|
|
@@ -105,8 +116,8 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
105
116
|
}));
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
async stop(): Promise<void> {
|
|
109
|
-
this
|
|
119
|
+
async #stop(): Promise<void> {
|
|
120
|
+
this.#open = false;
|
|
110
121
|
this.#wsRelease?.();
|
|
111
122
|
this.#wsRelease = undefined;
|
|
112
123
|
await this.#connectionTask;
|
|
@@ -115,10 +126,10 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
115
126
|
this.#started = false;
|
|
116
127
|
}
|
|
117
128
|
|
|
118
|
-
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
129
|
+
async #send({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
|
|
119
130
|
const message = formatOutboundSegments(payload);
|
|
120
131
|
const { action, params } = buildSendAction(conversation, message);
|
|
121
|
-
const data =
|
|
132
|
+
const data = readMilkyResponse<{ message_seq?: number }>(await this.#call({ action, params, signal }), action);
|
|
122
133
|
const messageId = formatOutboundMessageId(conversation, data?.message_seq);
|
|
123
134
|
this.#logger.debug(formatCompact({
|
|
124
135
|
op: 'milky_send',
|
|
@@ -129,23 +140,24 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
129
140
|
return messageId;
|
|
130
141
|
}
|
|
131
142
|
|
|
132
|
-
async recallMessage(id: string): Promise<void> {
|
|
143
|
+
async #recallMessage({ id, signal }: { readonly id: string; readonly signal?: AbortSignal }): Promise<void> {
|
|
133
144
|
const parsed = parseMilkyMessageId(id);
|
|
134
145
|
if (!parsed) throw new Error(`Invalid message id: ${id}`);
|
|
135
146
|
if (parsed.message_scene === 'group') {
|
|
136
|
-
await
|
|
147
|
+
readMilkyResponse(await this.#call({ action: 'recall_group_message', signal, params: {
|
|
137
148
|
group_id: parsed.peer_id,
|
|
138
149
|
message_seq: parsed.message_seq,
|
|
139
|
-
});
|
|
150
|
+
} }), 'recall_group_message');
|
|
140
151
|
} else {
|
|
141
|
-
await
|
|
152
|
+
readMilkyResponse(await this.#call({ action: 'recall_private_message', signal, params: {
|
|
142
153
|
user_id: parsed.peer_id,
|
|
143
154
|
message_seq: parsed.message_seq,
|
|
144
|
-
});
|
|
155
|
+
} }), 'recall_private_message');
|
|
145
156
|
}
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
#admitRaw(event: MilkyEvent): void {
|
|
160
|
+
if (event.self_id != null) this[endpointSpec].reportSelfUserId(String(event.self_id));
|
|
149
161
|
const data = parseMessageReceiveData(event);
|
|
150
162
|
if (!data) return;
|
|
151
163
|
this.#admitMessage(data, event);
|
|
@@ -156,14 +168,16 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
#admitMessage(data: MilkyIncomingMessage, event: MilkyEvent): void {
|
|
159
|
-
const conversation = milkyInboundConversation(String(this.#options.id), data);
|
|
171
|
+
const conversation = { ...milkyInboundConversation(String(this.#options.id), data), endpoint: this[endpointSpec].identity };
|
|
160
172
|
const target = `${conversation.kind}:${conversation.id}`;
|
|
161
173
|
const content = formatInboundContent(data);
|
|
162
174
|
const segments = formatInboundSegments(data);
|
|
163
175
|
const audioUrl = extractInboundAudioUrl(data);
|
|
164
176
|
const nickname = senderNickname(data);
|
|
165
177
|
const mentioned = isMentioned(data, event.self_id);
|
|
166
|
-
void this.
|
|
178
|
+
void this[endpointSpec].events.message({
|
|
179
|
+
event,
|
|
180
|
+
...(typeof event.time === 'number' ? { platformSentAt: event.time * 1000 } : {}),
|
|
167
181
|
conversation,
|
|
168
182
|
message: { conversation, id: formatInboundMessageId(data) },
|
|
169
183
|
content,
|
|
@@ -198,7 +212,7 @@ export class MilkyWssEndpoint extends ClientEndpoint<MilkyClient> {
|
|
|
198
212
|
await this.#connectionLifecycle.stop();
|
|
199
213
|
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
200
214
|
this.#ws = socket;
|
|
201
|
-
const releaseClientSocket = this.
|
|
215
|
+
const releaseClientSocket = this.acceptWebSocket(socket);
|
|
202
216
|
this.#clientSocketRelease = releaseClientSocket;
|
|
203
217
|
lifecycleHandle.onForceClose(() => {
|
|
204
218
|
if (this.#clientSocketRelease === releaseClientSocket) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const milkyRuntimeStateToken: import("zhin.js").Token<import("@zhin.js/adapter").EndpointRuntimeState>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Milky 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `milky endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
export const milkyRuntimeStateToken = defineEndpointRuntimeStateToken('milky');
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Milky 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `milky endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
|
|
7
|
-
export const milkyRuntimeStateToken = defineEndpointRuntimeStateToken('milky');
|