@zhin.js/adapter-satori 1.1.26 → 1.1.27
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 +22 -0
- package/README.md +1 -1
- package/adapters/satori/index.js +5 -0
- package/adapters/satori/index.ts +5 -0
- package/lib/endpoint.d.ts +2 -1
- package/lib/endpoint.js +191 -64
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +121 -9
- package/lib/protocol.js +561 -6
- package/package.json +2 -2
- package/src/endpoint.ts +218 -61
- package/src/index.ts +16 -0
- package/src/protocol.ts +671 -8
package/src/endpoint.ts
CHANGED
|
@@ -7,7 +7,15 @@ import {
|
|
|
7
7
|
createEndpointSpecification,
|
|
8
8
|
endpointSpec,
|
|
9
9
|
type Endpoint,
|
|
10
|
+
type EndpointApproveRequest,
|
|
11
|
+
type EndpointFriend,
|
|
12
|
+
type EndpointReactionRequest,
|
|
13
|
+
type EndpointRejectRequest,
|
|
14
|
+
type EndpointRemoveReactionRequest,
|
|
15
|
+
type EndpointEventSink,
|
|
16
|
+
type EndpointIdentity,
|
|
10
17
|
type EndpointSpecification,
|
|
18
|
+
type EndpointUserRequest,
|
|
11
19
|
createEndpointLifecycle,
|
|
12
20
|
type EndpointChannel,
|
|
13
21
|
type EndpointConnectHandle,
|
|
@@ -31,11 +39,20 @@ import {
|
|
|
31
39
|
formatInboundContent,
|
|
32
40
|
formatMessageId,
|
|
33
41
|
formatSatoriOutbound,
|
|
42
|
+
inboundSatoriSegments,
|
|
34
43
|
isMessageEvent,
|
|
44
|
+
mapSatoriFriendRequest,
|
|
45
|
+
readSatoriFriend,
|
|
46
|
+
satoriFriendApproveParams,
|
|
47
|
+
satoriReactionParams,
|
|
48
|
+
withSatoriGuildRoles,
|
|
35
49
|
isSelfMentioned,
|
|
50
|
+
mapGuildEmojiNotice,
|
|
36
51
|
parseMessageRef,
|
|
37
52
|
resolveInboundSender,
|
|
38
53
|
satoriInboundConversation,
|
|
54
|
+
satoriMessageCreateParams,
|
|
55
|
+
withSatoriReferrer,
|
|
39
56
|
type ResolvedSatoriWebhookConfig,
|
|
40
57
|
type ResolvedSatoriWsConfig,
|
|
41
58
|
type SatoriEventBody,
|
|
@@ -74,6 +91,8 @@ export class SatoriWsEndpoint extends SatoriClient implements Endpoint {
|
|
|
74
91
|
readonly #call: SatoriActionCaller;
|
|
75
92
|
readonly #control: EndpointControl = Object.freeze<EndpointControl>({
|
|
76
93
|
recall: request => this.#recall(request),
|
|
94
|
+
addReaction: request => this.#addReaction(request),
|
|
95
|
+
removeReaction: request => this.#removeReaction(request),
|
|
77
96
|
});
|
|
78
97
|
|
|
79
98
|
constructor(options: SatoriWsEndpointOptions) {
|
|
@@ -143,10 +162,7 @@ export class SatoriWsEndpoint extends SatoriClient implements Endpoint {
|
|
|
143
162
|
|
|
144
163
|
async #send({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
|
|
145
164
|
const content = formatSatoriOutbound(payload);
|
|
146
|
-
const result = await this.#call({ resource: 'message', method: 'create', signal, params:
|
|
147
|
-
channel_id: conversation.id,
|
|
148
|
-
content,
|
|
149
|
-
} });
|
|
165
|
+
const result = await this.#call({ resource: 'message', method: 'create', signal, params: satoriMessageCreateParams(conversation.id, content) });
|
|
150
166
|
const msgId = extractCreatedMessageId(result);
|
|
151
167
|
this.#logger.debug(formatCompact({
|
|
152
168
|
op: 'satori_send',
|
|
@@ -159,34 +175,33 @@ export class SatoriWsEndpoint extends SatoriClient implements Endpoint {
|
|
|
159
175
|
|
|
160
176
|
#admitRaw(body: SatoriEventBody): void {
|
|
161
177
|
if (!matchesSatoriLogin(this.#options.config, body.login)) return;
|
|
162
|
-
if (
|
|
163
|
-
const conversation = { ...satoriInboundConversation(String(this.#options.id), body), endpoint: this[endpointSpec].identity };
|
|
164
|
-
const content = formatInboundContent(body);
|
|
165
|
-
const sender = resolveInboundSender(body);
|
|
166
|
-
const selfId = this.#options.config.userId;
|
|
167
|
-
const mentioned = isSelfMentioned(body, selfId);
|
|
168
|
-
void this[endpointSpec].events.message({
|
|
169
|
-
event: body,
|
|
170
|
-
...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
|
|
171
|
-
conversation,
|
|
172
|
-
message: { conversation, id: body.message.id },
|
|
173
|
-
content,
|
|
174
|
-
sender,
|
|
178
|
+
if (emitSatoriFriendRequest(body, {
|
|
175
179
|
endpointId: this.#options.config.id,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
180
|
+
call: this.#call,
|
|
181
|
+
emit: request => {
|
|
182
|
+
void this[endpointSpec].events.emit('request.receive', request).catch(error => {
|
|
183
|
+
this.#warnPlatformEvent('request.receive', error);
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
})) return;
|
|
187
|
+
const deliver = () => deliverSatoriInbound(body, {
|
|
188
|
+
endpointId: this.#options.config.id,
|
|
189
|
+
endpointKey: String(this.#options.id),
|
|
190
|
+
identity: this[endpointSpec].identity,
|
|
191
|
+
selfId: this.#options.config.userId,
|
|
181
192
|
platform: this.#options.config.platform,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
events: this[endpointSpec].events,
|
|
194
|
+
warnReceive: (channel, error) => {
|
|
195
|
+
this.#logger.warn(formatCompact({
|
|
196
|
+
op: 'satori_gateway_receive_failed',
|
|
197
|
+
channel,
|
|
198
|
+
error: error instanceof Error ? error.message : String(error),
|
|
199
|
+
}));
|
|
200
|
+
},
|
|
201
|
+
warnEvent: (event, error) => this.#warnPlatformEvent(event, error),
|
|
189
202
|
});
|
|
203
|
+
if (body.referrer !== undefined) withSatoriReferrer(body.referrer, deliver);
|
|
204
|
+
else deliver();
|
|
190
205
|
}
|
|
191
206
|
|
|
192
207
|
async #recall({ message, signal }: EndpointRecallRequest): Promise<void> {
|
|
@@ -197,6 +212,14 @@ export class SatoriWsEndpoint extends SatoriClient implements Endpoint {
|
|
|
197
212
|
} });
|
|
198
213
|
}
|
|
199
214
|
|
|
215
|
+
#addReaction(request: EndpointReactionRequest): Promise<string | null> {
|
|
216
|
+
return addSatoriReaction(this.#call, request);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#removeReaction(request: EndpointRemoveReactionRequest): Promise<void> {
|
|
220
|
+
return removeSatoriReaction(this.#call, request);
|
|
221
|
+
}
|
|
222
|
+
|
|
200
223
|
#warnPlatformEvent(name: string, error: unknown): void {
|
|
201
224
|
this.#logger.warn(formatCompact({
|
|
202
225
|
op: 'satori_platform_event_failed',
|
|
@@ -359,6 +382,8 @@ export class SatoriWebhookEndpoint extends SatoriClient implements Endpoint {
|
|
|
359
382
|
readonly #call: SatoriActionCaller;
|
|
360
383
|
readonly #control: EndpointControl = Object.freeze<EndpointControl>({
|
|
361
384
|
recall: request => this.#recall(request),
|
|
385
|
+
addReaction: request => this.#addReaction(request),
|
|
386
|
+
removeReaction: request => this.#removeReaction(request),
|
|
362
387
|
});
|
|
363
388
|
|
|
364
389
|
constructor(options: SatoriWebhookEndpointOptions) {
|
|
@@ -428,10 +453,7 @@ export class SatoriWebhookEndpoint extends SatoriClient implements Endpoint {
|
|
|
428
453
|
|
|
429
454
|
async #send({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
|
|
430
455
|
const content = formatSatoriOutbound(payload);
|
|
431
|
-
const result = await this.#call({ resource: 'message', method: 'create', signal, params:
|
|
432
|
-
channel_id: conversation.id,
|
|
433
|
-
content,
|
|
434
|
-
} });
|
|
456
|
+
const result = await this.#call({ resource: 'message', method: 'create', signal, params: satoriMessageCreateParams(conversation.id, content) });
|
|
435
457
|
const msgId = extractCreatedMessageId(result);
|
|
436
458
|
this.#logger.debug(formatCompact({
|
|
437
459
|
op: 'satori_send',
|
|
@@ -444,34 +466,33 @@ export class SatoriWebhookEndpoint extends SatoriClient implements Endpoint {
|
|
|
444
466
|
|
|
445
467
|
#admitRaw(body: SatoriEventBody): void {
|
|
446
468
|
if (!matchesSatoriLogin(this.#options.config, body.login)) return;
|
|
447
|
-
if (
|
|
448
|
-
const conversation = { ...satoriInboundConversation(String(this.#options.id), body), endpoint: this[endpointSpec].identity };
|
|
449
|
-
const content = formatInboundContent(body);
|
|
450
|
-
const sender = resolveInboundSender(body);
|
|
451
|
-
const selfId = this.#options.config.userId;
|
|
452
|
-
const mentioned = isSelfMentioned(body, selfId);
|
|
453
|
-
void this[endpointSpec].events.message({
|
|
454
|
-
event: body,
|
|
455
|
-
...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
|
|
456
|
-
conversation,
|
|
457
|
-
message: { conversation, id: body.message.id },
|
|
458
|
-
content,
|
|
459
|
-
sender,
|
|
469
|
+
if (emitSatoriFriendRequest(body, {
|
|
460
470
|
endpointId: this.#options.config.id,
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
471
|
+
call: this.#call,
|
|
472
|
+
emit: request => {
|
|
473
|
+
void this[endpointSpec].events.emit('request.receive', request).catch(error => {
|
|
474
|
+
this.#warnPlatformEvent('request.receive', error);
|
|
475
|
+
});
|
|
476
|
+
},
|
|
477
|
+
})) return;
|
|
478
|
+
const deliver = () => deliverSatoriInbound(body, {
|
|
479
|
+
endpointId: this.#options.config.id,
|
|
480
|
+
endpointKey: String(this.#options.id),
|
|
481
|
+
identity: this[endpointSpec].identity,
|
|
482
|
+
selfId: this.#options.config.userId,
|
|
466
483
|
platform: this.#options.config.platform,
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
484
|
+
events: this[endpointSpec].events,
|
|
485
|
+
warnReceive: (channel, error) => {
|
|
486
|
+
this.#logger.warn(formatCompact({
|
|
487
|
+
op: 'satori_gateway_receive_failed',
|
|
488
|
+
channel,
|
|
489
|
+
error: error instanceof Error ? error.message : String(error),
|
|
490
|
+
}));
|
|
491
|
+
},
|
|
492
|
+
warnEvent: (event, error) => this.#warnPlatformEvent(event, error),
|
|
474
493
|
});
|
|
494
|
+
if (body.referrer !== undefined) withSatoriReferrer(body.referrer, deliver);
|
|
495
|
+
else deliver();
|
|
475
496
|
}
|
|
476
497
|
|
|
477
498
|
async #recall({ message, signal }: EndpointRecallRequest): Promise<void> {
|
|
@@ -482,6 +503,14 @@ export class SatoriWebhookEndpoint extends SatoriClient implements Endpoint {
|
|
|
482
503
|
} });
|
|
483
504
|
}
|
|
484
505
|
|
|
506
|
+
#addReaction(request: EndpointReactionRequest): Promise<string | null> {
|
|
507
|
+
return addSatoriReaction(this.#call, request);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
#removeReaction(request: EndpointRemoveReactionRequest): Promise<void> {
|
|
511
|
+
return removeSatoriReaction(this.#call, request);
|
|
512
|
+
}
|
|
513
|
+
|
|
485
514
|
#warnPlatformEvent(name: string, error: unknown): void {
|
|
486
515
|
this.#logger.warn(formatCompact({
|
|
487
516
|
op: 'satori_platform_event_failed',
|
|
@@ -498,6 +527,47 @@ export class SatoriWebhookEndpoint extends SatoriClient implements Endpoint {
|
|
|
498
527
|
|
|
499
528
|
}
|
|
500
529
|
|
|
530
|
+
function deliverSatoriInbound(body: SatoriEventBody, input: {
|
|
531
|
+
readonly endpointId: string;
|
|
532
|
+
readonly endpointKey: string;
|
|
533
|
+
readonly identity: EndpointIdentity;
|
|
534
|
+
readonly selfId: string;
|
|
535
|
+
readonly platform: string;
|
|
536
|
+
readonly events: EndpointEventSink;
|
|
537
|
+
readonly warnReceive: (channel: string, error: unknown) => void;
|
|
538
|
+
readonly warnEvent: (event: string, error: unknown) => void;
|
|
539
|
+
}): Promise<unknown> {
|
|
540
|
+
const notice = mapGuildEmojiNotice(body, input.endpointId);
|
|
541
|
+
if (notice) {
|
|
542
|
+
return input.events.emit('notice.receive', notice).catch(error => input.warnEvent('notice.receive', error));
|
|
543
|
+
}
|
|
544
|
+
if (!isMessageEvent(body)) return Promise.resolve();
|
|
545
|
+
const conversation = { ...satoriInboundConversation(input.endpointKey, body), endpoint: input.identity };
|
|
546
|
+
const content = formatInboundContent(body);
|
|
547
|
+
const segments = typeof body.message.content === 'string'
|
|
548
|
+
? inboundSatoriSegments(body.message.content)
|
|
549
|
+
: undefined;
|
|
550
|
+
const sender = resolveInboundSender(body);
|
|
551
|
+
const mentioned = isSelfMentioned(body, input.selfId);
|
|
552
|
+
return input.events.message({
|
|
553
|
+
event: body,
|
|
554
|
+
...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
|
|
555
|
+
conversation,
|
|
556
|
+
message: { conversation, id: body.message.id },
|
|
557
|
+
content,
|
|
558
|
+
...(segments ? { segments } : {}),
|
|
559
|
+
sender,
|
|
560
|
+
endpointId: input.endpointId,
|
|
561
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
562
|
+
metadata: Object.freeze({
|
|
563
|
+
type: body.type,
|
|
564
|
+
channelType: isPrivateChannelType(body) ? 'private' : 'group',
|
|
565
|
+
sn: body.sn,
|
|
566
|
+
platform: input.platform,
|
|
567
|
+
}),
|
|
568
|
+
}).catch(error => input.warnReceive(conversation.id, error));
|
|
569
|
+
}
|
|
570
|
+
|
|
501
571
|
function isPrivateChannelType(body: SatoriEventBody): boolean {
|
|
502
572
|
const channel = body.channel ?? body.message?.channel;
|
|
503
573
|
return channel?.type === 1;
|
|
@@ -545,7 +615,8 @@ function asRecord(value: unknown): Record<string, unknown> {
|
|
|
545
615
|
|
|
546
616
|
/**
|
|
547
617
|
* Satori endpoint 的 EndpointManagement 语义端口(ws / webhook 共用),
|
|
548
|
-
* 数据走协议 API:guild.list / channel.list / guild
|
|
618
|
+
* 数据走协议 API:guild.list / channel.list / guild.member.list。
|
|
619
|
+
* @see https://satori.chat/zh-CN/resources/member.html
|
|
549
620
|
*/
|
|
550
621
|
export function createSatoriEndpointManagement(api: SatoriManagementApi): EndpointManagement {
|
|
551
622
|
return Object.freeze<EndpointManagement>({
|
|
@@ -583,14 +654,100 @@ export function createSatoriEndpointManagement(api: SatoriManagementApi): Endpoi
|
|
|
583
654
|
return channels;
|
|
584
655
|
},
|
|
585
656
|
async listGroupMembers({ groupId, signal }: EndpointGroupRequest): Promise<readonly unknown[]> {
|
|
586
|
-
// 平台形状(GuildMember[]
|
|
587
|
-
|
|
657
|
+
// 平台形状(GuildMember[])原样返回,再规范化 1.3 的 GuildRole 角色
|
|
658
|
+
const members = await listSatoriPages(api, { resource: 'guild.member', params: { guild_id: groupId }, signal });
|
|
659
|
+
return members.map(member => withSatoriGuildRoles(member));
|
|
660
|
+
},
|
|
661
|
+
async listFriends(request: EndpointManagementRequest = {}): Promise<readonly EndpointFriend[]> {
|
|
662
|
+
const friends: EndpointFriend[] = [];
|
|
663
|
+
for (const value of await listSatoriPages(api, { resource: 'friend', signal: request.signal })) {
|
|
664
|
+
const friend = readSatoriFriend(value);
|
|
665
|
+
if (!friend?.user?.id) continue;
|
|
666
|
+
const nick = friend.nick ?? '';
|
|
667
|
+
const name = friend.user.name ?? '';
|
|
668
|
+
friends.push({
|
|
669
|
+
user_id: friend.user.id,
|
|
670
|
+
nickname: name || nick || friend.user.id,
|
|
671
|
+
remark: nick,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
return friends;
|
|
675
|
+
},
|
|
676
|
+
async deleteFriend({ userId, signal }: EndpointUserRequest): Promise<void> {
|
|
677
|
+
await api({ resource: 'friend', method: 'delete', params: { user_id: userId }, signal });
|
|
678
|
+
},
|
|
679
|
+
async approveRequest({ requestId, remark, signal }: EndpointApproveRequest): Promise<void> {
|
|
680
|
+
await api({
|
|
681
|
+
resource: 'friend',
|
|
682
|
+
method: 'approve',
|
|
683
|
+
signal,
|
|
684
|
+
params: satoriFriendApproveParams(requestId, true, remark),
|
|
685
|
+
});
|
|
686
|
+
},
|
|
687
|
+
async rejectRequest({ requestId, reason, signal }: EndpointRejectRequest): Promise<void> {
|
|
688
|
+
await api({
|
|
689
|
+
resource: 'friend',
|
|
690
|
+
method: 'approve',
|
|
691
|
+
signal,
|
|
692
|
+
params: satoriFriendApproveParams(requestId, false, reason),
|
|
693
|
+
});
|
|
588
694
|
},
|
|
589
695
|
});
|
|
590
696
|
}
|
|
591
697
|
|
|
592
698
|
export type { CreateSatoriWebSocket, SatoriWsSocket } from './ws.js';
|
|
593
699
|
|
|
700
|
+
function emitSatoriFriendRequest(body: SatoriEventBody, input: {
|
|
701
|
+
readonly endpointId: string;
|
|
702
|
+
readonly call: SatoriActionCaller;
|
|
703
|
+
readonly emit: (request: ReturnType<typeof mapSatoriFriendRequest>) => void;
|
|
704
|
+
}): boolean {
|
|
705
|
+
if (body.type !== 'friend-request') return false;
|
|
706
|
+
const request = mapSatoriFriendRequest(body, input.endpointId, {
|
|
707
|
+
approve: (messageId, comment) => input.call({
|
|
708
|
+
resource: 'friend',
|
|
709
|
+
method: 'approve',
|
|
710
|
+
params: satoriFriendApproveParams(messageId, true, comment),
|
|
711
|
+
}).then(() => undefined),
|
|
712
|
+
reject: (messageId, reason) => input.call({
|
|
713
|
+
resource: 'friend',
|
|
714
|
+
method: 'approve',
|
|
715
|
+
params: satoriFriendApproveParams(messageId, false, reason),
|
|
716
|
+
}).then(() => undefined),
|
|
717
|
+
});
|
|
718
|
+
if (request) input.emit(request);
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
async function addSatoriReaction(call: SatoriActionCaller, request: EndpointReactionRequest): Promise<string | null> {
|
|
723
|
+
const { channelId, messageId } = parseMessageRef(request.message.id);
|
|
724
|
+
await call({
|
|
725
|
+
resource: 'reaction',
|
|
726
|
+
method: 'create',
|
|
727
|
+
signal: request.signal,
|
|
728
|
+
params: satoriReactionParams('create', {
|
|
729
|
+
channelId: channelId || request.message.conversation.id,
|
|
730
|
+
messageId,
|
|
731
|
+
emojiId: request.emoji,
|
|
732
|
+
}),
|
|
733
|
+
});
|
|
734
|
+
return request.emoji;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
async function removeSatoriReaction(call: SatoriActionCaller, request: EndpointRemoveReactionRequest): Promise<void> {
|
|
738
|
+
const { channelId, messageId } = parseMessageRef(request.message.id);
|
|
739
|
+
await call({
|
|
740
|
+
resource: 'reaction',
|
|
741
|
+
method: 'delete',
|
|
742
|
+
signal: request.signal,
|
|
743
|
+
params: satoriReactionParams('delete', {
|
|
744
|
+
channelId: channelId || request.message.conversation.id,
|
|
745
|
+
messageId,
|
|
746
|
+
emojiId: request.reactionId,
|
|
747
|
+
}),
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
594
751
|
/** A transport connection may multiplex logins; this Endpoint admits only its selected account. */
|
|
595
752
|
function matchesSatoriLogin(config: { readonly platform: string; readonly userId: string }, login: SatoriLogin | undefined): boolean {
|
|
596
753
|
return login?.platform === config.platform && login.user?.id === config.userId;
|
package/src/index.ts
CHANGED
|
@@ -3,9 +3,19 @@ export {
|
|
|
3
3
|
buildWsUrl,
|
|
4
4
|
callSatoriApi,
|
|
5
5
|
extractCreatedMessageId,
|
|
6
|
+
decodeSatoriContent,
|
|
6
7
|
formatInboundContent,
|
|
7
8
|
formatSatoriOutbound,
|
|
9
|
+
inboundSatoriSegments,
|
|
8
10
|
isMessageEvent,
|
|
11
|
+
mapSatoriFriendRequest,
|
|
12
|
+
normalizeSatoriGuildRoles,
|
|
13
|
+
readSatoriFriend,
|
|
14
|
+
satoriFriendApproveParams,
|
|
15
|
+
satoriReactionParams,
|
|
16
|
+
mapGuildEmojiNotice,
|
|
17
|
+
satoriMessageCreateParams,
|
|
18
|
+
withSatoriReferrer,
|
|
9
19
|
isPrivateChannel,
|
|
10
20
|
resolveInboundSender,
|
|
11
21
|
resolveSatoriConfig,
|
|
@@ -16,7 +26,13 @@ export {
|
|
|
16
26
|
type SatoriApiOptions,
|
|
17
27
|
type SatoriApiRequest,
|
|
18
28
|
type SatoriChannel,
|
|
29
|
+
type SatoriEmoji,
|
|
19
30
|
type SatoriEventBody,
|
|
31
|
+
type SatoriFriend,
|
|
32
|
+
type SatoriFriendRequestActions,
|
|
33
|
+
type SatoriGuildMember,
|
|
34
|
+
type SatoriGuildRole,
|
|
35
|
+
type SatoriReactionMethod,
|
|
20
36
|
type SatoriLogin,
|
|
21
37
|
type SatoriMessage,
|
|
22
38
|
type SatoriSignal,
|