@zhin.js/adapter-onebot11 1.1.19 → 1.1.21
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 +38 -0
- package/lib/protocol.d.ts +2 -1
- package/lib/self-profile.d.ts +12 -0
- package/lib/self-profile.js +56 -0
- package/lib/ws-endpoint.js +7 -3
- package/lib/wss-endpoint.js +7 -3
- package/package.json +20 -20
- package/schema.json +106 -1
- package/src/protocol.ts +2 -1
- package/src/self-profile.ts +67 -0
- package/src/ws-endpoint.ts +7 -3
- package/src/wss-endpoint.ts +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot11
|
|
2
2
|
|
|
3
|
+
## 1.1.21
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b88e988: Preserve account-profile write acknowledgements already observed before cancellation, distinguish native Discord REST rejection from unknown outcomes, and retain the last valid profile when a newer concurrent read fails. Keep scene-scoped SOUL presence consistent with the actual prompt and allow discovered URLs to pass through the existing network authorization policy.
|
|
8
|
+
- af8f803: Use the current Endpoint's platform profile for Agent account identity, with per-field configured fallbacks and scoped, identity-approved profile tools. Keep SOUL first-person and independent of account names. Profile ports preserve the source Client, cancellation, truthful update outcomes and private image authority.
|
|
9
|
+
|
|
10
|
+
Adapter Feature API 2.1 and Tool Feature API 1.1 describe the additive profile requirements; new Core, official adapters and generated plugins declare the corresponding floors. Existing compatible API-2.0/API-1.0 plugins remain accepted by the newer providers. npm releases remain patch.
|
|
11
|
+
|
|
12
|
+
Private IM assets now bind to the full canonical conversation and principal. Existing IM asset records that contain only the earlier lossy hash remain on disk until their original expiry, but cannot be safely rebound; recapture them. No automatic file deletion, platform profile mutation or workspace SOUL rewrite occurs during upgrade.
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [b88e988]
|
|
15
|
+
- Updated dependencies [f78eb84]
|
|
16
|
+
- Updated dependencies [c15cef9]
|
|
17
|
+
- Updated dependencies [b0c02a2]
|
|
18
|
+
- Updated dependencies [af8f803]
|
|
19
|
+
- Updated dependencies [26fda97]
|
|
20
|
+
- Updated dependencies [976886c]
|
|
21
|
+
- Updated dependencies [032dc96]
|
|
22
|
+
- @zhin.js/adapter@1.1.27
|
|
23
|
+
- @zhin.js/client@1.1.23
|
|
24
|
+
- @zhin.js/im-contract@1.1.10
|
|
25
|
+
- @zhin.js/core@1.1.55
|
|
26
|
+
- @zhin.js/tool@1.1.14
|
|
27
|
+
- @zhin.js/page@1.1.13
|
|
28
|
+
- @zhin.js/host-http@1.1.13
|
|
29
|
+
- @zhin.js/agent-feature@1.1.12
|
|
30
|
+
- @zhin.js/feature-kit@1.1.11
|
|
31
|
+
- @zhin.js/permission@1.1.11
|
|
32
|
+
- @zhin.js/skill@1.1.12
|
|
33
|
+
|
|
34
|
+
## 1.1.20
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- Updated dependencies [5e878ba]
|
|
39
|
+
- @zhin.js/page@1.1.12
|
|
40
|
+
|
|
3
41
|
## 1.1.19
|
|
4
42
|
|
|
5
43
|
### Patch Changes
|
package/lib/protocol.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EndpointProfileConfiguration } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* OneBot 11 protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
|
|
3
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
@@ -5,7 +6,7 @@
|
|
|
5
6
|
*/
|
|
6
7
|
import { type MediaRef, type ConversationRef } from '@zhin.js/im-contract';
|
|
7
8
|
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
8
|
-
export interface OneBot11EndpointConfig {
|
|
9
|
+
export interface OneBot11EndpointConfig extends EndpointProfileConfiguration {
|
|
9
10
|
readonly connection?: 'ws' | 'wss';
|
|
10
11
|
readonly id: string;
|
|
11
12
|
readonly access_token?: string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EndpointProfile, PendingRpcRequest } from 'zhin.js/adapter';
|
|
2
|
+
interface Onebot11SelfProfileOptions {
|
|
3
|
+
readonly call: (request: PendingRpcRequest) => Promise<unknown>;
|
|
4
|
+
readonly reportAccount: (id: string | undefined) => void;
|
|
5
|
+
}
|
|
6
|
+
interface Onebot11SelfProfile extends EndpointProfile {
|
|
7
|
+
/** The same verified account observations used by transport ingress and shutdown. */
|
|
8
|
+
reportAccount(id: string | undefined): void;
|
|
9
|
+
}
|
|
10
|
+
/** OneBot11's standard self-information action has no standard profile mutation counterpart. */
|
|
11
|
+
export declare function createOnebot11SelfProfile({ call, reportAccount }: Onebot11SelfProfileOptions): Onebot11SelfProfile;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** OneBot11's standard self-information action has no standard profile mutation counterpart. */
|
|
2
|
+
export function createOnebot11SelfProfile({ call, reportAccount }) {
|
|
3
|
+
let nickname;
|
|
4
|
+
let accountId;
|
|
5
|
+
let accountRevision = 0;
|
|
6
|
+
let readSequence = 0;
|
|
7
|
+
let publishedSequence = 0;
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
writableFields: Object.freeze([]),
|
|
10
|
+
get current() { return nickname === undefined ? {} : { nickname }; },
|
|
11
|
+
reportAccount(id) {
|
|
12
|
+
if (id !== accountId || id === undefined) {
|
|
13
|
+
accountId = id;
|
|
14
|
+
nickname = undefined;
|
|
15
|
+
accountRevision++;
|
|
16
|
+
readSequence++;
|
|
17
|
+
publishedSequence = readSequence;
|
|
18
|
+
}
|
|
19
|
+
reportAccount(id);
|
|
20
|
+
},
|
|
21
|
+
async read({ signal }) {
|
|
22
|
+
const revision = accountRevision;
|
|
23
|
+
const sequence = ++readSequence;
|
|
24
|
+
const assertAccount = () => {
|
|
25
|
+
signal.throwIfAborted();
|
|
26
|
+
if (revision !== accountRevision)
|
|
27
|
+
throw new Error('OneBot11 account changed while reading self profile');
|
|
28
|
+
};
|
|
29
|
+
const self = await call({ action: 'get_login_info', signal });
|
|
30
|
+
assertAccount();
|
|
31
|
+
if (!self?.user_id || typeof self.nickname !== 'string')
|
|
32
|
+
throw new Error('OneBot11 returned an incomplete self profile');
|
|
33
|
+
if (sequence > publishedSequence) {
|
|
34
|
+
publishedSequence = sequence;
|
|
35
|
+
accountId = String(self.user_id);
|
|
36
|
+
nickname = self.nickname;
|
|
37
|
+
reportAccount(accountId);
|
|
38
|
+
}
|
|
39
|
+
// Keep confirmed login facts in current, while lookup errors remain lookup errors.
|
|
40
|
+
const details = await call({ action: 'get_stranger_info', params: { user_id: self.user_id, no_cache: true }, signal });
|
|
41
|
+
assertAccount();
|
|
42
|
+
if (!details || String(details.user_id) !== String(self.user_id))
|
|
43
|
+
throw new Error('OneBot11 returned another account profile');
|
|
44
|
+
const observedNickname = typeof details.nickname === 'string' ? details.nickname : self.nickname;
|
|
45
|
+
if (sequence >= publishedSequence) {
|
|
46
|
+
publishedSequence = sequence;
|
|
47
|
+
nickname = observedNickname;
|
|
48
|
+
}
|
|
49
|
+
const profile = { nickname: observedNickname,
|
|
50
|
+
...(details.sex === 'male' || details.sex === 'female' || details.sex === 'unknown' ? { gender: details.sex } : {}),
|
|
51
|
+
...(typeof details.age === 'number' && Number.isFinite(details.age) ? { age: details.age } : {}),
|
|
52
|
+
};
|
|
53
|
+
return profile;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createOnebot11SelfProfile } from './self-profile.js';
|
|
1
2
|
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot11 WS client endpoint — outbound connect to OneBot implementation.
|
|
@@ -25,6 +26,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
25
26
|
#ws;
|
|
26
27
|
#stopped = false;
|
|
27
28
|
#rpc;
|
|
29
|
+
#profile;
|
|
28
30
|
constructor(options) {
|
|
29
31
|
const rpc = createOneBot11Rpc({ endpointId: options.config.id, signal: options.signal,
|
|
30
32
|
socket: () => this.#lifecycle.state === 'open' ? this.#ws : undefined,
|
|
@@ -36,6 +38,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
36
38
|
const callApi = (request) => this.#rpc.call(request).then(readOnebot11Response);
|
|
37
39
|
this.#management = createOneBot11EndpointManagement({ callApi });
|
|
38
40
|
this.#content = createOneBot11ContentPort(callApi);
|
|
41
|
+
this.#profile = createOnebot11SelfProfile({ call: callApi, reportAccount: id => this[endpointSpec].reportSelfUserId(id) });
|
|
39
42
|
const readTransportState = () => this.#lifecycle.state;
|
|
40
43
|
this[endpointSpec] = createEndpointSpecification(this, {
|
|
41
44
|
name: options.config.id,
|
|
@@ -44,6 +47,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
44
47
|
send: request => this.#send(request),
|
|
45
48
|
get transportState() { return readTransportState(); },
|
|
46
49
|
management: this.#management, control: this.#control, content: this.#content,
|
|
50
|
+
profile: this.#profile,
|
|
47
51
|
});
|
|
48
52
|
this.#releaseClientEvents = forwardOnebot11ClientEvents(this, (name, payload) => {
|
|
49
53
|
void this[endpointSpec].events.run(() => {
|
|
@@ -106,7 +110,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
106
110
|
this.#rpc.dispose();
|
|
107
111
|
this.#releaseClientEvents();
|
|
108
112
|
this.#ws = undefined;
|
|
109
|
-
this
|
|
113
|
+
this.#profile.reportAccount(undefined);
|
|
110
114
|
}
|
|
111
115
|
}
|
|
112
116
|
async #send({ conversation, payload, signal }) {
|
|
@@ -134,7 +138,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
134
138
|
#admitRaw(ev) {
|
|
135
139
|
const selfId = resolveOnebot11SelfId(ev.self_id);
|
|
136
140
|
if (!this.#stopped && selfId)
|
|
137
|
-
this
|
|
141
|
+
this.#profile.reportAccount(selfId);
|
|
138
142
|
if (!isMessageEvent(ev)) {
|
|
139
143
|
receiveOneBot11SideEvent(ev, {
|
|
140
144
|
emit: (name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
@@ -181,7 +185,7 @@ export class OneBot11WsEndpoint extends Onebot11Client {
|
|
|
181
185
|
if (this.#stopped || this.#transportState !== 'open')
|
|
182
186
|
return;
|
|
183
187
|
if (selfId)
|
|
184
|
-
this
|
|
188
|
+
this.#profile.reportAccount(selfId);
|
|
185
189
|
}
|
|
186
190
|
#warnPlatformEvent(error) {
|
|
187
191
|
this.#logger.warn(formatCompact({
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createOnebot11SelfProfile } from './self-profile.js';
|
|
1
2
|
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot11 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
@@ -26,6 +27,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
26
27
|
#connectionLifecycle;
|
|
27
28
|
#connectionTask = Promise.resolve();
|
|
28
29
|
#rpc;
|
|
30
|
+
#profile;
|
|
29
31
|
#started = false;
|
|
30
32
|
#stopped = false;
|
|
31
33
|
constructor(options) {
|
|
@@ -44,6 +46,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
44
46
|
const callApi = (request) => this.#rpc.call(request).then(readOnebot11Response);
|
|
45
47
|
this.#management = createOneBot11EndpointManagement({ callApi });
|
|
46
48
|
this.#content = createOneBot11ContentPort(callApi);
|
|
49
|
+
this.#profile = createOnebot11SelfProfile({ call: callApi, reportAccount: id => this[endpointSpec].reportSelfUserId(id) });
|
|
47
50
|
const readTransportState = () => this.#transportState;
|
|
48
51
|
this[endpointSpec] = createEndpointSpecification(this, {
|
|
49
52
|
name: options.config.id,
|
|
@@ -52,6 +55,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
52
55
|
send: request => this.#send(request),
|
|
53
56
|
get transportState() { return readTransportState(); },
|
|
54
57
|
management: this.#management, control: this.#control, content: this.#content,
|
|
58
|
+
profile: this.#profile,
|
|
55
59
|
});
|
|
56
60
|
this.#releaseClientEvents = forwardOnebot11ClientEvents(this, (name, payload) => {
|
|
57
61
|
void this[endpointSpec].events.run(() => {
|
|
@@ -121,7 +125,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
121
125
|
this.#releaseClientEvents();
|
|
122
126
|
this.#ws = undefined;
|
|
123
127
|
this.#started = false;
|
|
124
|
-
this
|
|
128
|
+
this.#profile.reportAccount(undefined);
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
async #send({ conversation, payload, signal }) {
|
|
@@ -142,7 +146,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
142
146
|
#admitRaw(ev) {
|
|
143
147
|
const selfId = resolveOnebot11SelfId(ev.self_id);
|
|
144
148
|
if (!this.#stopped && selfId)
|
|
145
|
-
this
|
|
149
|
+
this.#profile.reportAccount(selfId);
|
|
146
150
|
if (!isMessageEvent(ev)) {
|
|
147
151
|
receiveOneBot11SideEvent(ev, {
|
|
148
152
|
emit: (name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
@@ -188,7 +192,7 @@ export class OneBot11WssEndpoint extends Onebot11Client {
|
|
|
188
192
|
if (this.#stopped || this.#transportState !== 'open')
|
|
189
193
|
return;
|
|
190
194
|
if (selfId)
|
|
191
|
-
this
|
|
195
|
+
this.#profile.reportAccount(selfId);
|
|
192
196
|
}
|
|
193
197
|
#warnPlatformEvent(error) {
|
|
194
198
|
this.#logger.warn(formatCompact({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-onebot11",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.21",
|
|
4
4
|
"description": "Zhin.js OneBot 11 adapter for Plugin Runtime (WebSocket client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -45,19 +45,19 @@
|
|
|
45
45
|
"@imhelper/onebot-v11": "1.0.7",
|
|
46
46
|
"imhelper": "1.0.7",
|
|
47
47
|
"ws": "^8.21.1",
|
|
48
|
-
"@zhin.js/adapter": "1.1.
|
|
49
|
-
"@zhin.js/
|
|
50
|
-
"@zhin.js/
|
|
48
|
+
"@zhin.js/adapter": "1.1.27",
|
|
49
|
+
"@zhin.js/client": "1.1.23",
|
|
50
|
+
"@zhin.js/agent-feature": "1.1.12",
|
|
51
51
|
"@zhin.js/console-contract": "1.1.3",
|
|
52
|
-
"@zhin.js/core": "1.1.
|
|
53
|
-
"@zhin.js/feature-kit": "1.1.
|
|
54
|
-
"@zhin.js/host-http": "1.1.
|
|
55
|
-
"@zhin.js/im-contract": "1.1.
|
|
52
|
+
"@zhin.js/core": "1.1.55",
|
|
53
|
+
"@zhin.js/feature-kit": "1.1.11",
|
|
54
|
+
"@zhin.js/host-http": "1.1.13",
|
|
55
|
+
"@zhin.js/im-contract": "1.1.10",
|
|
56
56
|
"@zhin.js/logger": "1.1.2",
|
|
57
|
-
"@zhin.js/
|
|
58
|
-
"@zhin.js/
|
|
59
|
-
"@zhin.js/skill": "1.1.
|
|
60
|
-
"@zhin.js/tool": "1.1.
|
|
57
|
+
"@zhin.js/permission": "1.1.11",
|
|
58
|
+
"@zhin.js/page": "1.1.13",
|
|
59
|
+
"@zhin.js/skill": "1.1.12",
|
|
60
|
+
"@zhin.js/tool": "1.1.14"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/node": "^26.1.2",
|
|
@@ -65,15 +65,15 @@
|
|
|
65
65
|
"typescript": "^6.0.3",
|
|
66
66
|
"vitest": "^4.1.10",
|
|
67
67
|
"zod": "^4.4.3",
|
|
68
|
-
"@zhin.js/host-http": "1.1.
|
|
69
|
-
"zhin.js": "1.1.
|
|
68
|
+
"@zhin.js/host-http": "1.1.13",
|
|
69
|
+
"zhin.js": "1.1.20"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"zod": "^4.0.0",
|
|
73
|
-
"@zhin.js/adapter": "^1.1.
|
|
74
|
-
"@zhin.js/command": "^1.1.
|
|
75
|
-
"@zhin.js/core": "^1.1.
|
|
76
|
-
"zhin.js": "^1.1.
|
|
73
|
+
"@zhin.js/adapter": "^1.1.27",
|
|
74
|
+
"@zhin.js/command": "^1.1.13",
|
|
75
|
+
"@zhin.js/core": "^1.1.55",
|
|
76
|
+
"zhin.js": "^1.1.20"
|
|
77
77
|
},
|
|
78
78
|
"peerDependenciesMeta": {
|
|
79
79
|
"@zhin.js/command": {
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"features": [
|
|
108
108
|
{
|
|
109
109
|
"package": "@zhin.js/adapter",
|
|
110
|
-
"api": "^2.
|
|
110
|
+
"api": "^2.1.0"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"package": "@zhin.js/command",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"package": "@zhin.js/tool",
|
|
118
|
-
"api": "^1.
|
|
118
|
+
"api": "^1.1.0"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"package": "@zhin.js/skill",
|
package/schema.json
CHANGED
|
@@ -115,6 +115,27 @@
|
|
|
115
115
|
"id": {
|
|
116
116
|
"type": "string",
|
|
117
117
|
"description": "OneBot11 bot name"
|
|
118
|
+
},
|
|
119
|
+
"nickname": {
|
|
120
|
+
"type": [
|
|
121
|
+
"string",
|
|
122
|
+
"null"
|
|
123
|
+
],
|
|
124
|
+
"description": "账号昵称兜底",
|
|
125
|
+
"x-i18n": {
|
|
126
|
+
"en": {
|
|
127
|
+
"description": "Fallback account nickname"
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"profile": {
|
|
132
|
+
"$ref": "#/$defs/selfProfileFallback",
|
|
133
|
+
"description": "账号资料兜底",
|
|
134
|
+
"x-i18n": {
|
|
135
|
+
"en": {
|
|
136
|
+
"description": "Fallback account profile"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
118
139
|
}
|
|
119
140
|
},
|
|
120
141
|
"required": [
|
|
@@ -136,9 +157,93 @@
|
|
|
136
157
|
"description": "Command prefix. The default empty string allows unprefixed commands; '/' requires a leading slash. Each endpoints[i] can override it."
|
|
137
158
|
}
|
|
138
159
|
}
|
|
160
|
+
},
|
|
161
|
+
"nickname": {
|
|
162
|
+
"type": [
|
|
163
|
+
"string",
|
|
164
|
+
"null"
|
|
165
|
+
],
|
|
166
|
+
"description": "账号昵称兜底",
|
|
167
|
+
"x-i18n": {
|
|
168
|
+
"en": {
|
|
169
|
+
"description": "Fallback account nickname"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"profile": {
|
|
174
|
+
"$ref": "#/$defs/selfProfileFallback",
|
|
175
|
+
"description": "账号资料兜底",
|
|
176
|
+
"x-i18n": {
|
|
177
|
+
"en": {
|
|
178
|
+
"description": "Fallback account profile"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
139
181
|
}
|
|
140
182
|
},
|
|
141
183
|
"required": [
|
|
142
184
|
"endpoints"
|
|
143
|
-
]
|
|
185
|
+
],
|
|
186
|
+
"$defs": {
|
|
187
|
+
"selfProfileFallback": {
|
|
188
|
+
"type": "object",
|
|
189
|
+
"additionalProperties": false,
|
|
190
|
+
"properties": {
|
|
191
|
+
"gender": {
|
|
192
|
+
"type": [
|
|
193
|
+
"string",
|
|
194
|
+
"null"
|
|
195
|
+
],
|
|
196
|
+
"enum": [
|
|
197
|
+
"male",
|
|
198
|
+
"female",
|
|
199
|
+
"other",
|
|
200
|
+
"unknown",
|
|
201
|
+
null
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
"age": {
|
|
205
|
+
"type": [
|
|
206
|
+
"integer",
|
|
207
|
+
"null"
|
|
208
|
+
],
|
|
209
|
+
"minimum": 0
|
|
210
|
+
},
|
|
211
|
+
"birthday": {
|
|
212
|
+
"type": [
|
|
213
|
+
"string",
|
|
214
|
+
"null"
|
|
215
|
+
],
|
|
216
|
+
"pattern": "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$"
|
|
217
|
+
},
|
|
218
|
+
"signature": {
|
|
219
|
+
"type": [
|
|
220
|
+
"string",
|
|
221
|
+
"null"
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
"avatar": {
|
|
225
|
+
"type": [
|
|
226
|
+
"string",
|
|
227
|
+
"null"
|
|
228
|
+
],
|
|
229
|
+
"pattern": "^(https?://[^\\s/?#]+(?:[/?#].*)?|)$"
|
|
230
|
+
},
|
|
231
|
+
"interests": {
|
|
232
|
+
"type": [
|
|
233
|
+
"array",
|
|
234
|
+
"null"
|
|
235
|
+
],
|
|
236
|
+
"items": {
|
|
237
|
+
"type": "string"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"bio": {
|
|
241
|
+
"type": [
|
|
242
|
+
"string",
|
|
243
|
+
"null"
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
144
249
|
}
|
package/src/protocol.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { EndpointProfileConfiguration } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* OneBot 11 protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
|
|
3
4
|
* Canonicalization is owned by gateway/core before endpoint.send.
|
|
@@ -9,7 +10,7 @@ import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
|
9
10
|
const logger = getLogger('onebot11');
|
|
10
11
|
|
|
11
12
|
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
12
|
-
export interface OneBot11EndpointConfig {
|
|
13
|
+
export interface OneBot11EndpointConfig extends EndpointProfileConfiguration {
|
|
13
14
|
readonly connection?: 'ws' | 'wss';
|
|
14
15
|
readonly id: string;
|
|
15
16
|
readonly access_token?: string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { EndpointProfile, PendingRpcRequest } from 'zhin.js/adapter';
|
|
2
|
+
import type { SelfProfile } from '@zhin.js/im-contract';
|
|
3
|
+
|
|
4
|
+
interface Onebot11SelfProfileOptions {
|
|
5
|
+
readonly call: (request: PendingRpcRequest) => Promise<unknown>;
|
|
6
|
+
readonly reportAccount: (id: string | undefined) => void;
|
|
7
|
+
}
|
|
8
|
+
interface Onebot11SelfProfile extends EndpointProfile {
|
|
9
|
+
/** The same verified account observations used by transport ingress and shutdown. */
|
|
10
|
+
reportAccount(id: string | undefined): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** OneBot11's standard self-information action has no standard profile mutation counterpart. */
|
|
14
|
+
export function createOnebot11SelfProfile({ call, reportAccount }: Onebot11SelfProfileOptions): Onebot11SelfProfile {
|
|
15
|
+
let nickname: string | undefined;
|
|
16
|
+
let accountId: string | undefined;
|
|
17
|
+
let accountRevision = 0;
|
|
18
|
+
let readSequence = 0;
|
|
19
|
+
let publishedSequence = 0;
|
|
20
|
+
return Object.freeze<Onebot11SelfProfile>({
|
|
21
|
+
writableFields: Object.freeze([]),
|
|
22
|
+
get current() { return nickname === undefined ? {} : { nickname }; },
|
|
23
|
+
reportAccount(id) {
|
|
24
|
+
if (id !== accountId || id === undefined) {
|
|
25
|
+
accountId = id;
|
|
26
|
+
nickname = undefined;
|
|
27
|
+
accountRevision++;
|
|
28
|
+
readSequence++;
|
|
29
|
+
publishedSequence = readSequence;
|
|
30
|
+
}
|
|
31
|
+
reportAccount(id);
|
|
32
|
+
},
|
|
33
|
+
async read({ signal }) {
|
|
34
|
+
const revision = accountRevision;
|
|
35
|
+
const sequence = ++readSequence;
|
|
36
|
+
const assertAccount = () => {
|
|
37
|
+
signal.throwIfAborted();
|
|
38
|
+
if (revision !== accountRevision) throw new Error('OneBot11 account changed while reading self profile');
|
|
39
|
+
};
|
|
40
|
+
const self = await call({ action: 'get_login_info', signal }) as { user_id?: number | string; nickname?: string } | undefined;
|
|
41
|
+
assertAccount();
|
|
42
|
+
if (!self?.user_id || typeof self.nickname !== 'string') throw new Error('OneBot11 returned an incomplete self profile');
|
|
43
|
+
if (sequence > publishedSequence) {
|
|
44
|
+
publishedSequence = sequence;
|
|
45
|
+
accountId = String(self.user_id);
|
|
46
|
+
nickname = self.nickname;
|
|
47
|
+
reportAccount(accountId);
|
|
48
|
+
}
|
|
49
|
+
// Keep confirmed login facts in current, while lookup errors remain lookup errors.
|
|
50
|
+
const details = await call({ action: 'get_stranger_info', params: { user_id: self.user_id, no_cache: true }, signal }) as {
|
|
51
|
+
user_id?: number | string; nickname?: string; sex?: string; age?: number;
|
|
52
|
+
} | undefined;
|
|
53
|
+
assertAccount();
|
|
54
|
+
if (!details || String(details.user_id) !== String(self.user_id)) throw new Error('OneBot11 returned another account profile');
|
|
55
|
+
const observedNickname = typeof details.nickname === 'string' ? details.nickname : self.nickname;
|
|
56
|
+
if (sequence >= publishedSequence) {
|
|
57
|
+
publishedSequence = sequence;
|
|
58
|
+
nickname = observedNickname;
|
|
59
|
+
}
|
|
60
|
+
const profile: SelfProfile = { nickname: observedNickname,
|
|
61
|
+
...(details.sex === 'male' || details.sex === 'female' || details.sex === 'unknown' ? { gender: details.sex } : {}),
|
|
62
|
+
...(typeof details.age === 'number' && Number.isFinite(details.age) ? { age: details.age } : {}),
|
|
63
|
+
};
|
|
64
|
+
return profile;
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
package/src/ws-endpoint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createOnebot11SelfProfile } from './self-profile.js';
|
|
1
2
|
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot11 WS client endpoint — outbound connect to OneBot implementation.
|
|
@@ -68,6 +69,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
68
69
|
#ws?: OneBot11WsSocket;
|
|
69
70
|
#stopped = false;
|
|
70
71
|
readonly #rpc: OneBot11Rpc;
|
|
72
|
+
readonly #profile: ReturnType<typeof createOnebot11SelfProfile>;
|
|
71
73
|
|
|
72
74
|
constructor(options: OneBot11WsEndpointOptions) {
|
|
73
75
|
const rpc = createOneBot11Rpc({ endpointId: options.config.id, signal: options.signal,
|
|
@@ -80,6 +82,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
80
82
|
const callApi = (request: PendingRpcRequest) => this.#rpc.call(request).then(readOnebot11Response);
|
|
81
83
|
this.#management = createOneBot11EndpointManagement({ callApi });
|
|
82
84
|
this.#content = createOneBot11ContentPort(callApi);
|
|
85
|
+
this.#profile = createOnebot11SelfProfile({ call: callApi, reportAccount: id => this[endpointSpec].reportSelfUserId(id) });
|
|
83
86
|
const readTransportState = () => this.#lifecycle.state;
|
|
84
87
|
this[endpointSpec] = createEndpointSpecification(this, {
|
|
85
88
|
name: options.config.id,
|
|
@@ -88,6 +91,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
88
91
|
send: request => this.#send(request),
|
|
89
92
|
get transportState() { return readTransportState(); },
|
|
90
93
|
management: this.#management, control: this.#control, content: this.#content,
|
|
94
|
+
profile: this.#profile,
|
|
91
95
|
});
|
|
92
96
|
this.#releaseClientEvents = forwardOnebot11ClientEvents(this, (name, payload) => {
|
|
93
97
|
void this[endpointSpec].events.run(() => {
|
|
@@ -145,7 +149,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
145
149
|
this.#rpc.dispose();
|
|
146
150
|
this.#releaseClientEvents();
|
|
147
151
|
this.#ws = undefined;
|
|
148
|
-
this
|
|
152
|
+
this.#profile.reportAccount(undefined);
|
|
149
153
|
}
|
|
150
154
|
}
|
|
151
155
|
|
|
@@ -175,7 +179,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
175
179
|
|
|
176
180
|
#admitRaw(ev: OneBot11Event): void {
|
|
177
181
|
const selfId = resolveOnebot11SelfId(ev.self_id);
|
|
178
|
-
if (!this.#stopped && selfId) this
|
|
182
|
+
if (!this.#stopped && selfId) this.#profile.reportAccount(selfId);
|
|
179
183
|
if (!isMessageEvent(ev)) {
|
|
180
184
|
receiveOneBot11SideEvent(ev, {
|
|
181
185
|
emit: (name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
@@ -221,7 +225,7 @@ export class OneBot11WsEndpoint extends Onebot11Client implements Endpoint {
|
|
|
221
225
|
}));
|
|
222
226
|
});
|
|
223
227
|
if (this.#stopped || this.#transportState !== 'open') return;
|
|
224
|
-
if (selfId) this
|
|
228
|
+
if (selfId) this.#profile.reportAccount(selfId);
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
#warnPlatformEvent(error: unknown): void {
|
package/src/wss-endpoint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createOnebot11SelfProfile } from './self-profile.js';
|
|
1
2
|
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
2
3
|
/**
|
|
3
4
|
* OneBot11 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
@@ -64,6 +65,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
64
65
|
readonly #connectionLifecycle: EndpointLifecycle;
|
|
65
66
|
#connectionTask = Promise.resolve();
|
|
66
67
|
readonly #rpc: OneBot11Rpc;
|
|
68
|
+
readonly #profile: ReturnType<typeof createOnebot11SelfProfile>;
|
|
67
69
|
#started = false;
|
|
68
70
|
#stopped = false;
|
|
69
71
|
|
|
@@ -83,6 +85,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
83
85
|
const callApi = (request: PendingRpcRequest) => this.#rpc.call(request).then(readOnebot11Response);
|
|
84
86
|
this.#management = createOneBot11EndpointManagement({ callApi });
|
|
85
87
|
this.#content = createOneBot11ContentPort(callApi);
|
|
88
|
+
this.#profile = createOnebot11SelfProfile({ call: callApi, reportAccount: id => this[endpointSpec].reportSelfUserId(id) });
|
|
86
89
|
const readTransportState = () => this.#transportState;
|
|
87
90
|
this[endpointSpec] = createEndpointSpecification(this, {
|
|
88
91
|
name: options.config.id,
|
|
@@ -91,6 +94,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
91
94
|
send: request => this.#send(request),
|
|
92
95
|
get transportState() { return readTransportState(); },
|
|
93
96
|
management: this.#management, control: this.#control, content: this.#content,
|
|
97
|
+
profile: this.#profile,
|
|
94
98
|
});
|
|
95
99
|
this.#releaseClientEvents = forwardOnebot11ClientEvents(this, (name, payload) => {
|
|
96
100
|
void this[endpointSpec].events.run(() => {
|
|
@@ -155,7 +159,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
155
159
|
this.#releaseClientEvents();
|
|
156
160
|
this.#ws = undefined;
|
|
157
161
|
this.#started = false;
|
|
158
|
-
this
|
|
162
|
+
this.#profile.reportAccount(undefined);
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
|
|
@@ -178,7 +182,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
178
182
|
|
|
179
183
|
#admitRaw(ev: OneBot11Event): void {
|
|
180
184
|
const selfId = resolveOnebot11SelfId(ev.self_id);
|
|
181
|
-
if (!this.#stopped && selfId) this
|
|
185
|
+
if (!this.#stopped && selfId) this.#profile.reportAccount(selfId);
|
|
182
186
|
if (!isMessageEvent(ev)) {
|
|
183
187
|
receiveOneBot11SideEvent(ev, {
|
|
184
188
|
emit: (name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
@@ -223,7 +227,7 @@ export class OneBot11WssEndpoint extends Onebot11Client implements Endpoint {
|
|
|
223
227
|
}));
|
|
224
228
|
});
|
|
225
229
|
if (this.#stopped || this.#transportState !== 'open') return;
|
|
226
|
-
if (selfId) this
|
|
230
|
+
if (selfId) this.#profile.reportAccount(selfId);
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
#warnPlatformEvent(error: unknown): void {
|