@zhin.js/adapter-napcat 1.1.18 → 1.1.20
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 +46 -0
- package/README.md +8 -5
- package/adapters/napcat/index.js +2 -29
- package/adapters/napcat/index.ts +3 -35
- package/agents/napcat/skills/napcat-account/tools/set_profile/index.js +1 -1
- package/agents/napcat/skills/napcat-account/tools/set_profile/index.ts +1 -1
- package/agents/napcat/skills/napcat-group-files-history/tools/upload_group_file/index.js +1 -1
- package/agents/napcat/skills/napcat-group-files-history/tools/upload_group_file/index.ts +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/set_title/index.js +1 -1
- package/agents/napcat/skills/napcat-group-settings/tools/set_title/index.ts +1 -1
- package/agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.js +1 -1
- package/agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.ts +1 -1
- package/commands/napcat/endpoint/definition.js +0 -2
- package/commands/napcat/endpoint/definition.ts +0 -2
- package/lib/adapter.d.ts +23 -0
- package/lib/adapter.js +42 -0
- package/lib/client.d.ts +53 -16
- package/lib/client.js +53 -10
- 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 +13 -13
- package/lib/http-endpoint.d.ts +5 -15
- package/lib/http-endpoint.js +44 -36
- package/lib/identity.d.ts +3 -0
- package/lib/identity.js +32 -0
- package/lib/index.d.ts +3 -2
- package/lib/index.js +2 -2
- package/lib/onebot-get-msg.d.ts +2 -2
- package/lib/onebot-get-msg.js +2 -2
- package/lib/protocol.d.ts +5 -0
- package/lib/protocol.js +23 -11
- package/lib/ws-endpoint.d.ts +6 -16
- package/lib/ws-endpoint.js +57 -48
- package/lib/ws-transport.d.ts +18 -12
- package/lib/ws-transport.js +28 -72
- package/lib/ws-types.d.ts +0 -5
- package/lib/wss-endpoint.d.ts +7 -15
- package/lib/wss-endpoint.js +56 -47
- package/package.json +18 -18
- package/plugin.js +0 -3
- package/src/adapter.ts +45 -0
- package/src/client.ts +91 -19
- package/src/console.ts +2 -5
- package/src/endpoint-management.ts +19 -15
- package/src/http-endpoint.ts +47 -45
- package/src/identity.ts +29 -0
- package/src/index.ts +9 -5
- package/src/onebot-get-msg.ts +4 -4
- package/src/protocol.ts +26 -14
- package/src/ws-endpoint.ts +61 -54
- package/src/ws-transport.ts +40 -101
- package/src/ws-types.ts +0 -6
- package/src/wss-endpoint.ts +60 -54
- package/lib/napcat-runtime-state.d.ts +0 -1
- package/lib/napcat-runtime-state.js +0 -6
- package/src/napcat-runtime-state.ts +0 -7
package/src/wss-endpoint.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
|
3
3
|
* NapCat reverse WSS endpoint — accepts inbound WebSocket from NapCat.
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
|
-
Endpoint,
|
|
6
|
+
createEndpointSpecification, endpointSpec, type Endpoint, type EndpointSpecification,
|
|
7
7
|
createEndpointLifecycle,
|
|
8
8
|
createRecallEndpointControl,
|
|
9
9
|
type EndpointLifecycle,
|
|
@@ -38,46 +38,51 @@ import { receiveNapCatSideEvent } from './side-event-dispatch.js';
|
|
|
38
38
|
import { createNapCatContentPort } from './onebot-get-msg.js';
|
|
39
39
|
import { NapcatClient } from './client.js';
|
|
40
40
|
import {
|
|
41
|
-
callNapCatWsAction,
|
|
42
|
-
handleNapCatWsMessage,
|
|
43
|
-
rejectAllPending,
|
|
44
|
-
} from './ws-transport.js';
|
|
45
|
-
import { NapCatWsEndpoint } from './ws-endpoint.js';
|
|
46
|
-
import {
|
|
47
|
-
type NapCatPendingAction,
|
|
48
41
|
type NapCatWsSocket,
|
|
49
42
|
} from './ws-types.js';
|
|
50
43
|
import { verifyNapCatAccessToken } from './wss-auth.js';
|
|
51
44
|
|
|
52
45
|
export interface NapCatWssEndpointOptions {
|
|
53
46
|
readonly id: CapabilityId;
|
|
47
|
+
readonly signal?: AbortSignal;
|
|
54
48
|
readonly http: HttpHost;
|
|
55
49
|
readonly config: NapCatWssConfig;
|
|
56
50
|
}
|
|
57
51
|
|
|
58
|
-
export class NapCatWssEndpoint extends
|
|
59
|
-
readonly
|
|
52
|
+
export class NapCatWssEndpoint extends NapcatClient implements Endpoint {
|
|
53
|
+
readonly [endpointSpec]: EndpointSpecification;
|
|
60
54
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
61
55
|
|
|
62
56
|
readonly #options: NapCatWssEndpointOptions;
|
|
63
57
|
readonly #inboundDeduper = new InboundMessageDeduper();
|
|
64
|
-
readonly management: EndpointManagement = createNapCatEndpointManagement(this
|
|
65
|
-
readonly control: EndpointControl = createRecallEndpointControl((id) => this
|
|
66
|
-
readonly content = createNapCatContentPort(
|
|
58
|
+
readonly #management: EndpointManagement = createNapCatEndpointManagement(this);
|
|
59
|
+
readonly #control: EndpointControl = createRecallEndpointControl((id, signal) => this.#recallMessage(id, signal));
|
|
60
|
+
readonly #content = createNapCatContentPort(request => this.requestApi(request));
|
|
67
61
|
readonly #connectionLifecycle: EndpointLifecycle;
|
|
68
|
-
#ws?: NapCatWsSocket;
|
|
69
62
|
#wsRelease?: () => void;
|
|
70
63
|
#connectionTask = Promise.resolve();
|
|
71
|
-
#requestId = { value: 0 };
|
|
72
|
-
#pending = new Map<string, NapCatPendingAction>();
|
|
73
64
|
#open = false;
|
|
74
65
|
#started = false;
|
|
75
66
|
#stopped = false;
|
|
76
67
|
|
|
77
68
|
constructor(options: NapCatWssEndpointOptions) {
|
|
78
|
-
super();
|
|
69
|
+
super({ config: options.config, signal: options.signal });
|
|
79
70
|
this.#logger = getAdapterLogger('napcat', options.config.id);
|
|
80
71
|
this.#options = options;
|
|
72
|
+
const readTransportState = () => this.#transportState;
|
|
73
|
+
this[endpointSpec] = createEndpointSpecification(this, {
|
|
74
|
+
name: options.config.id,
|
|
75
|
+
start: () => this.#start(), open: () => this.#openEndpoint(),
|
|
76
|
+
close: () => this.#close(), stop: () => this.#stop(),
|
|
77
|
+
send: request => this.#send(request),
|
|
78
|
+
management: this.#management, control: this.#control, content: this.#content,
|
|
79
|
+
get transportState() { return readTransportState(); },
|
|
80
|
+
});
|
|
81
|
+
this.on('event', event => {
|
|
82
|
+
void this[endpointSpec].events.run(() => this.#admit(event)).catch((error: unknown) => {
|
|
83
|
+
this.#logger.debug(formatCompact({ op: 'napcat_receive_failed', error: error instanceof Error ? error.message : String(error) }));
|
|
84
|
+
});
|
|
85
|
+
});
|
|
81
86
|
this.#connectionLifecycle = createEndpointLifecycle({
|
|
82
87
|
name: `${options.config.id}:inbound`,
|
|
83
88
|
reconnect: false,
|
|
@@ -85,15 +90,19 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
85
90
|
});
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
get transportState(): EndpointTransportState {
|
|
93
|
+
get #transportState(): EndpointTransportState {
|
|
89
94
|
if (this.#stopped) return 'stopped';
|
|
90
95
|
if (!this.#started) return 'idle';
|
|
91
96
|
if (this.#connectionLifecycle.state === 'closed') return 'closed';
|
|
92
|
-
if (this
|
|
97
|
+
if (this.transportSocket?.readyState === 1) return 'open';
|
|
93
98
|
return this.#connectionLifecycle.state === 'connecting' ? 'connecting' : 'idle';
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
protected override get actionSocket(): NapCatWsSocket | undefined {
|
|
102
|
+
return this.#connectionLifecycle.state === 'closed' ? undefined : this.transportSocket;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async #start(): Promise<void> {
|
|
97
106
|
if (this.#started) return;
|
|
98
107
|
this.#stopped = false;
|
|
99
108
|
this.#started = true;
|
|
@@ -117,31 +126,31 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
117
126
|
}));
|
|
118
127
|
}
|
|
119
128
|
|
|
120
|
-
|
|
129
|
+
#openEndpoint(): void {
|
|
121
130
|
this.#open = true;
|
|
122
131
|
}
|
|
123
132
|
|
|
124
|
-
close(): void {
|
|
133
|
+
#close(): void {
|
|
125
134
|
this.#open = false;
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
async stop(): Promise<void> {
|
|
137
|
+
async #stop(): Promise<void> {
|
|
129
138
|
this.#stopped = true;
|
|
130
139
|
this.#open = false;
|
|
131
140
|
this.#wsRelease?.();
|
|
132
141
|
this.#wsRelease = undefined;
|
|
133
142
|
await this.#connectionTask;
|
|
134
143
|
await this.#connectionLifecycle.stop();
|
|
135
|
-
|
|
144
|
+
this.rpc.disconnect();
|
|
136
145
|
this.#inboundDeduper.clear();
|
|
137
|
-
this
|
|
146
|
+
this.transportSocket = undefined;
|
|
138
147
|
this.#started = false;
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
150
|
+
async #send({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
|
|
142
151
|
const message = formatOutboundSegments(payload);
|
|
143
152
|
const { action, params } = buildSendAction(napcatOutboundTarget(conversation), message);
|
|
144
|
-
const data = await this.
|
|
153
|
+
const data = await this.requestApi({ action, params, signal }) as { message_id?: number | string } | undefined;
|
|
145
154
|
const rawId = data?.message_id;
|
|
146
155
|
if ((typeof rawId !== 'number' && typeof rawId !== 'string') || String(rawId).trim() === '' || (typeof rawId === 'number' && !Number.isFinite(rawId))) {
|
|
147
156
|
throw new EndpointDeliveryError('delivery_unconfirmed', 'Message delivery is unconfirmed: platform returned no message_id', 'unknown');
|
|
@@ -149,18 +158,17 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
149
158
|
return String(rawId);
|
|
150
159
|
}
|
|
151
160
|
|
|
152
|
-
async recallMessage(messageId: string): Promise<void> {
|
|
161
|
+
async #recallMessage(messageId: string, signal?: AbortSignal): Promise<void> {
|
|
153
162
|
if (!messageId) return;
|
|
154
|
-
await this.
|
|
163
|
+
await this.requestApi({ action: 'delete_msg', params: { message_id: Number(messageId) }, signal });
|
|
155
164
|
}
|
|
156
165
|
|
|
157
|
-
#callApi(action: string, params: Record<string, unknown> = {}): Promise<unknown> {
|
|
158
|
-
return callNapCatWsAction(this.#connectionLifecycle.state === 'closed' ? undefined : this.#ws, this.#pending, this.#requestId, action, params);
|
|
159
|
-
}
|
|
160
166
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
|
|
168
|
+
#admit(ev: NapCatEvent): void {
|
|
169
|
+
const nativeEvent = ev;
|
|
170
|
+
if (!this.#open && !this.#started) return;
|
|
171
|
+
void this[endpointSpec].events.platform(napCatPlatformEventName(ev), ev).catch((error) => {
|
|
164
172
|
this.#logger.warn(formatCompact({
|
|
165
173
|
op: 'napcat_platform_event_failed',
|
|
166
174
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -168,9 +176,9 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
168
176
|
});
|
|
169
177
|
if (!isMessageEvent(ev)) {
|
|
170
178
|
receiveNapCatSideEvent(
|
|
171
|
-
(name, payload) => this.emit(name, payload),
|
|
179
|
+
(name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
172
180
|
this.#options.config.id,
|
|
173
|
-
this
|
|
181
|
+
this,
|
|
174
182
|
ev,
|
|
175
183
|
this.#logger,
|
|
176
184
|
);
|
|
@@ -182,10 +190,12 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
182
190
|
if (Array.isArray(ev.message) || typeof ev.message === 'string') {
|
|
183
191
|
ev = { ...ev, message: normalizeMessage(ev.message) };
|
|
184
192
|
}
|
|
185
|
-
const conversation = napcatInboundConversation(String(this.#options.id), ev);
|
|
193
|
+
const conversation = { ...napcatInboundConversation(String(this.#options.id), ev), endpoint: this[endpointSpec].identity };
|
|
186
194
|
const nickname = senderNickname(ev);
|
|
187
195
|
const mentioned = isNapCatBotMentioned(ev);
|
|
188
|
-
void this.
|
|
196
|
+
void this[endpointSpec].events.message({
|
|
197
|
+
event: nativeEvent,
|
|
198
|
+
...(typeof nativeEvent.time === 'number' ? { platformSentAt: nativeEvent.time * 1000 } : {}),
|
|
189
199
|
conversation,
|
|
190
200
|
message: { conversation, id: msgId },
|
|
191
201
|
content: formatInboundContent(ev),
|
|
@@ -225,12 +235,12 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
225
235
|
}
|
|
226
236
|
const socket = connection.socket as unknown as NapCatWsSocket;
|
|
227
237
|
await this.#connectionLifecycle.stop();
|
|
228
|
-
|
|
238
|
+
this.rpc.disconnect('Connection replaced');
|
|
229
239
|
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
230
|
-
this
|
|
240
|
+
this.transportSocket = socket;
|
|
231
241
|
lifecycleHandle.onForceClose(() => {
|
|
232
|
-
if (this
|
|
233
|
-
|
|
242
|
+
if (this.transportSocket === socket) {
|
|
243
|
+
this.rpc.disconnect();
|
|
234
244
|
}
|
|
235
245
|
try {
|
|
236
246
|
socket.close();
|
|
@@ -246,25 +256,21 @@ export class NapCatWssEndpoint extends Endpoint<NapcatClient> {
|
|
|
246
256
|
}
|
|
247
257
|
}, this.#options.config.heartbeat_interval);
|
|
248
258
|
socket.on('pong', () => {
|
|
249
|
-
if (this
|
|
259
|
+
if (this.transportSocket === socket) this.#connectionLifecycle.notifyHeartbeatAck();
|
|
250
260
|
});
|
|
251
261
|
socket.on('message', (data) => {
|
|
252
|
-
if (this
|
|
262
|
+
if (this.transportSocket !== socket || this.#connectionLifecycle.state === 'closed') return;
|
|
253
263
|
this.#connectionLifecycle.notifyHeartbeatAck();
|
|
254
|
-
|
|
255
|
-
endpointId: this.#options.config.id,
|
|
256
|
-
pending: this.#pending,
|
|
257
|
-
admit: (event) => this.admit(event),
|
|
258
|
-
});
|
|
264
|
+
this.rpc.receive(data, event => this.ingest(event));
|
|
259
265
|
});
|
|
260
266
|
socket.on('error', (error) => {
|
|
261
|
-
if (this
|
|
267
|
+
if (this.transportSocket !== socket) return;
|
|
262
268
|
this.#logger.warn(formatCompact({ op: 'ws_error', error: String(error) }));
|
|
263
269
|
});
|
|
264
270
|
socket.on('close', () => {
|
|
265
|
-
if (this
|
|
266
|
-
this
|
|
267
|
-
|
|
271
|
+
if (this.transportSocket !== socket) return;
|
|
272
|
+
this.transportSocket = undefined;
|
|
273
|
+
this.rpc.disconnect();
|
|
268
274
|
lifecycleHandle.notifyClosed(new Error('NapCat reverse WebSocket closed'));
|
|
269
275
|
});
|
|
270
276
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const napcatRuntimeStateToken: import("zhin.js").Token<import("@zhin.js/adapter").EndpointRuntimeState>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NapCat 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `napcat endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
export const napcatRuntimeStateToken = defineEndpointRuntimeStateToken('napcat');
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NapCat 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `napcat endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
|
|
7
|
-
export const napcatRuntimeStateToken = defineEndpointRuntimeStateToken('napcat');
|