@zhin.js/adapter-satori 1.1.25 → 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 CHANGED
@@ -1,5 +1,36 @@
1
1
  # @zhin.js/adapter-satori
2
2
 
3
+ ## 1.1.27
4
+
5
+ ### Patch Changes
6
+
7
+ - 11306b0: 对齐 Satori 出站元素和被动回复的 `referrer`。
8
+
9
+ **破坏性变更:** `at` / `mention` 不再编成 `@name`,图片、音频、视频和文件不再编成 `[image:src]` 这类纯文本,改为标准元素 `<at>`、`<img>`、`<audio>`、`<video>`、`<file>`,并支持 `<emoji>`。入站 `content` 仍是协议原文,这些元素会另外解成段。
10
+
11
+ 收到带 `referrer` 的事件时,同一次处理里的 `message.create` 会原样带回该对象;之后的主动发送不带。`guild-emoji-added` / `guild-emoji-updated` / `guild-emoji-deleted` 映射为 `notice.group.emoji_added` / `emoji_updated` / `emoji_deleted`。
12
+
13
+ `@imhelper/satori-v1` 还没有这些类型(上游 `feat/satori-1.3-alignment` 未发布)。适配器使用本地类型,上游发版后可以换成官方类型。
14
+
15
+ - 54b034f: 对齐 Satori 的 Friend、reaction 和群成员角色。
16
+
17
+ **破坏性变更:** `listGroupMembers` 返回的 `roles` 改为 `GuildRole[]`(`{ id, name? }`)。旧 SDK 若仍下发 `string[]`,适配器会收成 `{ id }`。
18
+
19
+ 新增 `friend.list` / `friend.delete` / `friend.approve`(管理端口的 `listFriends`、`deleteFriend`、`approveRequest`、`rejectRequest`)。`friend-request` 进入 `request.receive`,名称是 `request.friend.add`。表态改为 `reaction.create` / `reaction.delete`,参数名是 `emoji_id`。
20
+
21
+ `@imhelper/satori-v1` 1.0.10 仍把好友列表当成 User,reaction 参数仍叫 `emoji`。这些类型是本地声明。上游 `feat/satori-1.3-alignment` 发版后可以换成官方类型。
22
+
23
+ - 79395bb: 群成员列表改为请求 `POST /v1/guild.member.list`。原先资源名写成 `guild-member`,实际打到 `/v1/guild-member.list`,与 Satori 文档不一致。
24
+
25
+ ## 1.1.26
26
+
27
+ ### Patch Changes
28
+
29
+ - 0d76a7c: Overhaul Console interactive workbenches, platform-specific adapter account onboarding/login flows, DeclarativePageView visual/interactive capabilities, and official utility plugin Console pages.
30
+ - Updated dependencies [0d76a7c]
31
+ - @zhin.js/adapter@1.1.32
32
+ - @zhin.js/core@1.1.60
33
+
3
34
  ## 1.1.25
4
35
 
5
36
  ### Patch Changes
package/README.md CHANGED
@@ -29,7 +29,7 @@ pnpm add @zhin.js/adapter-satori
29
29
 
30
30
  入站:`endpoint[endpointSpec].events.emit('message.receive', { conversation, message, content, sender, metadata })`(`conversation` 为 ConversationRef:DIRECT 频道 → kind `private`,其余 → kind `group`、所属 guild 进 `parent`)
31
31
 
32
- 出站:`send({ conversation, payload })` → Satori `message.create`(`channel_id = conversation.id`;payload 已由 gateway/core 渲染;无 segment-mapper)
32
+ 出站:`send({ conversation, payload })` → Satori `message.create`(`channel_id = conversation.id`)。同一次入站处理结束前的被动回复会原样带回 `referrer`。段里的 mention 编成 `<at>`,媒体编成 `<img>` / `<audio>` / `<video>` / `<file>`,`emoji` 和规范 `face` 编成 `<emoji>`。
33
33
 
34
34
  入站 `metadata.mentioned`:消息 content 中 `<at id="…"/>` 元素的 id 等于登录 selfId(配置的 `userId`)时置 `true`。
35
35
 
@@ -17,9 +17,14 @@ export default defineAdapter({
17
17
  interactive: 'text',
18
18
  },
19
19
  recall: {},
20
+ reaction: {},
20
21
  },
21
22
  actions: {
22
23
  recall: { scopes: ['private', 'group', 'channel'] },
24
+ reaction: {
25
+ scopes: ['private', 'group', 'channel'],
26
+ params: { cancellable: true },
27
+ },
23
28
  },
24
29
  delivery: { send: true, spool: true },
25
30
  },
@@ -27,9 +27,14 @@ export default defineAdapter<SatoriEndpointConfig>({
27
27
  interactive: 'text',
28
28
  },
29
29
  recall: {},
30
+ reaction: {},
30
31
  },
31
32
  actions: {
32
33
  recall: { scopes: ['private', 'group', 'channel'] },
34
+ reaction: {
35
+ scopes: ['private', 'group', 'channel'],
36
+ params: { cancellable: true },
37
+ },
33
38
  },
34
39
  delivery: { send: true, spool: true },
35
40
  },
@@ -2,11 +2,61 @@ export const satoriConsoleSpec = {
2
2
  adapterKey: 'satori',
3
3
  adapterDisplayName: 'Satori',
4
4
  fields: [
5
- { key: 'platform', required: true, description: 'Selected Satori login platform' },
6
- { key: 'userId', required: true, description: 'Selected Satori login user ID' },
7
- { key: 'baseUrl', required: true, description: 'Satori 服务 base URL', descriptionI18n: { en: 'Satori service base URL' } },
8
- { key: 'path', description: 'webhook 路径(connection: webhook)', descriptionI18n: { en: 'Webhook path (connection: webhook)' } },
9
- { key: 'token', env: true, description: 'Satori access token' },
5
+ {
6
+ key: 'platform',
7
+ required: true,
8
+ label: '登录平台 (Platform)',
9
+ labelI18n: { en: 'Platform' },
10
+ group: '连接模式',
11
+ groupI18n: { en: 'Connection Mode' },
12
+ placeholder: 'chronocat / qq / onebot',
13
+ description: 'Satori 登录所属平台标识',
14
+ descriptionI18n: { en: 'Selected Satori login platform' },
15
+ },
16
+ {
17
+ key: 'userId',
18
+ required: true,
19
+ label: '机器人账号 ID (User ID)',
20
+ labelI18n: { en: 'Bot User ID' },
21
+ group: '连接模式',
22
+ groupI18n: { en: 'Connection Mode' },
23
+ placeholder: '123456789',
24
+ description: 'Satori 登录对应的机器人用户 ID',
25
+ descriptionI18n: { en: 'Selected Satori login user ID' },
26
+ },
27
+ {
28
+ key: 'baseUrl',
29
+ required: true,
30
+ label: 'Satori 服务地址',
31
+ labelI18n: { en: 'Satori Base URL' },
32
+ group: '连接模式',
33
+ groupI18n: { en: 'Connection Mode' },
34
+ placeholder: 'http://127.0.0.1:5500/v1',
35
+ description: 'Satori 服务 base URL',
36
+ descriptionI18n: { en: 'Satori service base URL' },
37
+ },
38
+ {
39
+ key: 'path',
40
+ label: 'Webhook 回调路径',
41
+ labelI18n: { en: 'Webhook Path' },
42
+ group: '连接模式',
43
+ groupI18n: { en: 'Connection Mode' },
44
+ placeholder: '/satori/webhook',
45
+ description: 'webhook 路径(connection: webhook)',
46
+ descriptionI18n: { en: 'Webhook path (connection: webhook)' },
47
+ },
48
+ {
49
+ key: 'token',
50
+ env: true,
51
+ label: 'Satori Token (鉴权令牌)',
52
+ labelI18n: { en: 'Satori Token' },
53
+ group: '安全认证',
54
+ groupI18n: { en: 'Authentication' },
55
+ placeholder: 'Satori 服务端配置的 Token',
56
+ placeholderI18n: { en: 'Token configured on Satori server' },
57
+ description: 'Satori 接口鉴权令牌',
58
+ descriptionI18n: { en: 'Satori access token' },
59
+ },
10
60
  ],
11
61
  docsUrl: 'https://zhin.js.org/adapters/satori',
12
62
  readPermission: 'satori:read',
package/lib/endpoint.d.ts CHANGED
@@ -41,7 +41,8 @@ export declare class SatoriWebhookEndpoint extends SatoriClient implements Endpo
41
41
  export type SatoriManagementApi = SatoriActionCaller;
42
42
  /**
43
43
  * Satori endpoint 的 EndpointManagement 语义端口(ws / webhook 共用),
44
- * 数据走协议 API:guild.list / channel.list / guild-member.list。
44
+ * 数据走协议 API:guild.list / channel.list / guild.member.list。
45
+ * @see https://satori.chat/zh-CN/resources/member.html
45
46
  */
46
47
  export declare function createSatoriEndpointManagement(api: SatoriManagementApi): EndpointManagement;
47
48
  export type { CreateSatoriWebSocket, SatoriWsSocket } from './ws.js';
package/lib/endpoint.js CHANGED
@@ -5,7 +5,7 @@ import { acceptHttpIngress } from 'imhelper';
5
5
  */
6
6
  import { createEndpointSpecification, endpointSpec, createEndpointLifecycle, } from 'zhin.js/adapter';
7
7
  import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
8
- import { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatMessageId, formatSatoriOutbound, isMessageEvent, isSelfMentioned, parseMessageRef, resolveInboundSender, satoriInboundConversation, } from './protocol.js';
8
+ import { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatMessageId, formatSatoriOutbound, inboundSatoriSegments, isMessageEvent, mapSatoriFriendRequest, readSatoriFriend, satoriFriendApproveParams, satoriReactionParams, withSatoriGuildRoles, isSelfMentioned, mapGuildEmojiNotice, parseMessageRef, resolveInboundSender, satoriInboundConversation, satoriMessageCreateParams, withSatoriReferrer, } from './protocol.js';
9
9
  import { registerSatoriWebhookRoutes } from './webhook.js';
10
10
  import { satoriClientOptions, createSatoriActionCaller, forwardSatoriClientEvents, SatoriClient } from './client.js';
11
11
  import { WS_OPEN, defaultCreateWebSocket, } from './ws.js';
@@ -21,6 +21,8 @@ export class SatoriWsEndpoint extends SatoriClient {
21
21
  #call;
22
22
  #control = Object.freeze({
23
23
  recall: request => this.#recall(request),
24
+ addReaction: request => this.#addReaction(request),
25
+ removeReaction: request => this.#removeReaction(request),
24
26
  });
25
27
  constructor(options) {
26
28
  const call = createSatoriActionCaller({ config: options.config, request: options.callApi ?? callSatoriApi, signal: options.signal });
@@ -90,10 +92,7 @@ export class SatoriWsEndpoint extends SatoriClient {
90
92
  }
91
93
  async #send({ conversation, payload, signal }) {
92
94
  const content = formatSatoriOutbound(payload);
93
- const result = await this.#call({ resource: 'message', method: 'create', signal, params: {
94
- channel_id: conversation.id,
95
- content,
96
- } });
95
+ const result = await this.#call({ resource: 'message', method: 'create', signal, params: satoriMessageCreateParams(conversation.id, content) });
97
96
  const msgId = extractCreatedMessageId(result);
98
97
  this.#logger.debug(formatCompact({
99
98
  op: 'satori_send',
@@ -106,35 +105,36 @@ export class SatoriWsEndpoint extends SatoriClient {
106
105
  #admitRaw(body) {
107
106
  if (!matchesSatoriLogin(this.#options.config, body.login))
108
107
  return;
109
- if (!isMessageEvent(body))
108
+ if (emitSatoriFriendRequest(body, {
109
+ endpointId: this.#options.config.id,
110
+ call: this.#call,
111
+ emit: request => {
112
+ void this[endpointSpec].events.emit('request.receive', request).catch(error => {
113
+ this.#warnPlatformEvent('request.receive', error);
114
+ });
115
+ },
116
+ }))
110
117
  return;
111
- const conversation = { ...satoriInboundConversation(String(this.#options.id), body), endpoint: this[endpointSpec].identity };
112
- const content = formatInboundContent(body);
113
- const sender = resolveInboundSender(body);
114
- const selfId = this.#options.config.userId;
115
- const mentioned = isSelfMentioned(body, selfId);
116
- void this[endpointSpec].events.message({
117
- event: body,
118
- ...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
119
- conversation,
120
- message: { conversation, id: body.message.id },
121
- content,
122
- sender,
118
+ const deliver = () => deliverSatoriInbound(body, {
123
119
  endpointId: this.#options.config.id,
124
- ...(mentioned ? { mentioned: true } : {}),
125
- metadata: Object.freeze({
126
- type: body.type,
127
- channelType: isPrivateChannelType(body) ? 'private' : 'group',
128
- sn: body.sn,
129
- platform: this.#options.config.platform,
130
- }),
131
- }).catch((err) => {
132
- this.#logger.warn(formatCompact({
133
- op: 'satori_gateway_receive_failed',
134
- channel: conversation.id,
135
- error: err instanceof Error ? err.message : String(err),
136
- }));
120
+ endpointKey: String(this.#options.id),
121
+ identity: this[endpointSpec].identity,
122
+ selfId: this.#options.config.userId,
123
+ platform: this.#options.config.platform,
124
+ events: this[endpointSpec].events,
125
+ warnReceive: (channel, error) => {
126
+ this.#logger.warn(formatCompact({
127
+ op: 'satori_gateway_receive_failed',
128
+ channel,
129
+ error: error instanceof Error ? error.message : String(error),
130
+ }));
131
+ },
132
+ warnEvent: (event, error) => this.#warnPlatformEvent(event, error),
137
133
  });
134
+ if (body.referrer !== undefined)
135
+ withSatoriReferrer(body.referrer, deliver);
136
+ else
137
+ deliver();
138
138
  }
139
139
  async #recall({ message, signal }) {
140
140
  const { channelId, messageId } = parseMessageRef(message.id);
@@ -143,6 +143,12 @@ export class SatoriWsEndpoint extends SatoriClient {
143
143
  message_id: messageId,
144
144
  } });
145
145
  }
146
+ #addReaction(request) {
147
+ return addSatoriReaction(this.#call, request);
148
+ }
149
+ #removeReaction(request) {
150
+ return removeSatoriReaction(this.#call, request);
151
+ }
146
152
  #warnPlatformEvent(name, error) {
147
153
  this.#logger.warn(formatCompact({
148
154
  op: 'satori_platform_event_failed',
@@ -294,6 +300,8 @@ export class SatoriWebhookEndpoint extends SatoriClient {
294
300
  #call;
295
301
  #control = Object.freeze({
296
302
  recall: request => this.#recall(request),
303
+ addReaction: request => this.#addReaction(request),
304
+ removeReaction: request => this.#removeReaction(request),
297
305
  });
298
306
  constructor(options) {
299
307
  const call = createSatoriActionCaller({ config: options.config, request: options.callApi ?? callSatoriApi, signal: options.signal });
@@ -363,10 +371,7 @@ export class SatoriWebhookEndpoint extends SatoriClient {
363
371
  }
364
372
  async #send({ conversation, payload, signal }) {
365
373
  const content = formatSatoriOutbound(payload);
366
- const result = await this.#call({ resource: 'message', method: 'create', signal, params: {
367
- channel_id: conversation.id,
368
- content,
369
- } });
374
+ const result = await this.#call({ resource: 'message', method: 'create', signal, params: satoriMessageCreateParams(conversation.id, content) });
370
375
  const msgId = extractCreatedMessageId(result);
371
376
  this.#logger.debug(formatCompact({
372
377
  op: 'satori_send',
@@ -379,35 +384,36 @@ export class SatoriWebhookEndpoint extends SatoriClient {
379
384
  #admitRaw(body) {
380
385
  if (!matchesSatoriLogin(this.#options.config, body.login))
381
386
  return;
382
- if (!isMessageEvent(body))
387
+ if (emitSatoriFriendRequest(body, {
388
+ endpointId: this.#options.config.id,
389
+ call: this.#call,
390
+ emit: request => {
391
+ void this[endpointSpec].events.emit('request.receive', request).catch(error => {
392
+ this.#warnPlatformEvent('request.receive', error);
393
+ });
394
+ },
395
+ }))
383
396
  return;
384
- const conversation = { ...satoriInboundConversation(String(this.#options.id), body), endpoint: this[endpointSpec].identity };
385
- const content = formatInboundContent(body);
386
- const sender = resolveInboundSender(body);
387
- const selfId = this.#options.config.userId;
388
- const mentioned = isSelfMentioned(body, selfId);
389
- void this[endpointSpec].events.message({
390
- event: body,
391
- ...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
392
- conversation,
393
- message: { conversation, id: body.message.id },
394
- content,
395
- sender,
397
+ const deliver = () => deliverSatoriInbound(body, {
396
398
  endpointId: this.#options.config.id,
397
- ...(mentioned ? { mentioned: true } : {}),
398
- metadata: Object.freeze({
399
- type: body.type,
400
- channelType: isPrivateChannelType(body) ? 'private' : 'group',
401
- sn: body.sn,
402
- platform: this.#options.config.platform,
403
- }),
404
- }).catch((err) => {
405
- this.#logger.warn(formatCompact({
406
- op: 'satori_gateway_receive_failed',
407
- channel: conversation.id,
408
- error: err instanceof Error ? err.message : String(err),
409
- }));
399
+ endpointKey: String(this.#options.id),
400
+ identity: this[endpointSpec].identity,
401
+ selfId: this.#options.config.userId,
402
+ platform: this.#options.config.platform,
403
+ events: this[endpointSpec].events,
404
+ warnReceive: (channel, error) => {
405
+ this.#logger.warn(formatCompact({
406
+ op: 'satori_gateway_receive_failed',
407
+ channel,
408
+ error: error instanceof Error ? error.message : String(error),
409
+ }));
410
+ },
411
+ warnEvent: (event, error) => this.#warnPlatformEvent(event, error),
410
412
  });
413
+ if (body.referrer !== undefined)
414
+ withSatoriReferrer(body.referrer, deliver);
415
+ else
416
+ deliver();
411
417
  }
412
418
  async #recall({ message, signal }) {
413
419
  const { channelId, messageId } = parseMessageRef(message.id);
@@ -416,6 +422,12 @@ export class SatoriWebhookEndpoint extends SatoriClient {
416
422
  message_id: messageId,
417
423
  } });
418
424
  }
425
+ #addReaction(request) {
426
+ return addSatoriReaction(this.#call, request);
427
+ }
428
+ #removeReaction(request) {
429
+ return removeSatoriReaction(this.#call, request);
430
+ }
419
431
  #warnPlatformEvent(name, error) {
420
432
  this.#logger.warn(formatCompact({
421
433
  op: 'satori_platform_event_failed',
@@ -430,6 +442,38 @@ export class SatoriWebhookEndpoint extends SatoriClient {
430
442
  this.ingest(body);
431
443
  }
432
444
  }
445
+ function deliverSatoriInbound(body, input) {
446
+ const notice = mapGuildEmojiNotice(body, input.endpointId);
447
+ if (notice) {
448
+ return input.events.emit('notice.receive', notice).catch(error => input.warnEvent('notice.receive', error));
449
+ }
450
+ if (!isMessageEvent(body))
451
+ return Promise.resolve();
452
+ const conversation = { ...satoriInboundConversation(input.endpointKey, body), endpoint: input.identity };
453
+ const content = formatInboundContent(body);
454
+ const segments = typeof body.message.content === 'string'
455
+ ? inboundSatoriSegments(body.message.content)
456
+ : undefined;
457
+ const sender = resolveInboundSender(body);
458
+ const mentioned = isSelfMentioned(body, input.selfId);
459
+ return input.events.message({
460
+ event: body,
461
+ ...(typeof body.timestamp === 'number' ? { platformSentAt: body.timestamp } : {}),
462
+ conversation,
463
+ message: { conversation, id: body.message.id },
464
+ content,
465
+ ...(segments ? { segments } : {}),
466
+ sender,
467
+ endpointId: input.endpointId,
468
+ ...(mentioned ? { mentioned: true } : {}),
469
+ metadata: Object.freeze({
470
+ type: body.type,
471
+ channelType: isPrivateChannelType(body) ? 'private' : 'group',
472
+ sn: body.sn,
473
+ platform: input.platform,
474
+ }),
475
+ }).catch(error => input.warnReceive(conversation.id, error));
476
+ }
433
477
  function isPrivateChannelType(body) {
434
478
  const channel = body.channel ?? body.message?.channel;
435
479
  return channel?.type === 1;
@@ -458,7 +502,8 @@ function asRecord(value) {
458
502
  }
459
503
  /**
460
504
  * Satori endpoint 的 EndpointManagement 语义端口(ws / webhook 共用),
461
- * 数据走协议 API:guild.list / channel.list / guild-member.list。
505
+ * 数据走协议 API:guild.list / channel.list / guild.member.list。
506
+ * @see https://satori.chat/zh-CN/resources/member.html
462
507
  */
463
508
  export function createSatoriEndpointManagement(api) {
464
509
  return Object.freeze({
@@ -500,9 +545,91 @@ export function createSatoriEndpointManagement(api) {
500
545
  return channels;
501
546
  },
502
547
  async listGroupMembers({ groupId, signal }) {
503
- // 平台形状(GuildMember[])原样返回
504
- return listSatoriPages(api, { resource: 'guild-member', params: { guild_id: groupId }, signal });
548
+ // 平台形状(GuildMember[])原样返回,再规范化 1.3 的 GuildRole 角色
549
+ const members = await listSatoriPages(api, { resource: 'guild.member', params: { guild_id: groupId }, signal });
550
+ return members.map(member => withSatoriGuildRoles(member));
551
+ },
552
+ async listFriends(request = {}) {
553
+ const friends = [];
554
+ for (const value of await listSatoriPages(api, { resource: 'friend', signal: request.signal })) {
555
+ const friend = readSatoriFriend(value);
556
+ if (!friend?.user?.id)
557
+ continue;
558
+ const nick = friend.nick ?? '';
559
+ const name = friend.user.name ?? '';
560
+ friends.push({
561
+ user_id: friend.user.id,
562
+ nickname: name || nick || friend.user.id,
563
+ remark: nick,
564
+ });
565
+ }
566
+ return friends;
567
+ },
568
+ async deleteFriend({ userId, signal }) {
569
+ await api({ resource: 'friend', method: 'delete', params: { user_id: userId }, signal });
505
570
  },
571
+ async approveRequest({ requestId, remark, signal }) {
572
+ await api({
573
+ resource: 'friend',
574
+ method: 'approve',
575
+ signal,
576
+ params: satoriFriendApproveParams(requestId, true, remark),
577
+ });
578
+ },
579
+ async rejectRequest({ requestId, reason, signal }) {
580
+ await api({
581
+ resource: 'friend',
582
+ method: 'approve',
583
+ signal,
584
+ params: satoriFriendApproveParams(requestId, false, reason),
585
+ });
586
+ },
587
+ });
588
+ }
589
+ function emitSatoriFriendRequest(body, input) {
590
+ if (body.type !== 'friend-request')
591
+ return false;
592
+ const request = mapSatoriFriendRequest(body, input.endpointId, {
593
+ approve: (messageId, comment) => input.call({
594
+ resource: 'friend',
595
+ method: 'approve',
596
+ params: satoriFriendApproveParams(messageId, true, comment),
597
+ }).then(() => undefined),
598
+ reject: (messageId, reason) => input.call({
599
+ resource: 'friend',
600
+ method: 'approve',
601
+ params: satoriFriendApproveParams(messageId, false, reason),
602
+ }).then(() => undefined),
603
+ });
604
+ if (request)
605
+ input.emit(request);
606
+ return true;
607
+ }
608
+ async function addSatoriReaction(call, request) {
609
+ const { channelId, messageId } = parseMessageRef(request.message.id);
610
+ await call({
611
+ resource: 'reaction',
612
+ method: 'create',
613
+ signal: request.signal,
614
+ params: satoriReactionParams('create', {
615
+ channelId: channelId || request.message.conversation.id,
616
+ messageId,
617
+ emojiId: request.emoji,
618
+ }),
619
+ });
620
+ return request.emoji;
621
+ }
622
+ async function removeSatoriReaction(call, request) {
623
+ const { channelId, messageId } = parseMessageRef(request.message.id);
624
+ await call({
625
+ resource: 'reaction',
626
+ method: 'delete',
627
+ signal: request.signal,
628
+ params: satoriReactionParams('delete', {
629
+ channelId: channelId || request.message.conversation.id,
630
+ messageId,
631
+ emojiId: request.reactionId,
632
+ }),
506
633
  });
507
634
  }
508
635
  /** A transport connection may multiplex logins; this Endpoint admits only its selected account. */
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatSatoriOutbound, isMessageEvent, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, type ResolvedSatoriWebhookConfig, type ResolvedSatoriWsConfig, type SatoriEndpointConfig, type SatoriApiOptions, type SatoriApiRequest, type SatoriChannel, type SatoriEventBody, type SatoriLogin, type SatoriMessage, type SatoriSignal, type SatoriUser, type SatoriWireSegment, } from './protocol.js';
1
+ export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, decodeSatoriContent, formatInboundContent, formatSatoriOutbound, inboundSatoriSegments, isMessageEvent, mapSatoriFriendRequest, normalizeSatoriGuildRoles, readSatoriFriend, satoriFriendApproveParams, satoriReactionParams, mapGuildEmojiNotice, satoriMessageCreateParams, withSatoriReferrer, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, type ResolvedSatoriWebhookConfig, type ResolvedSatoriWsConfig, type SatoriEndpointConfig, type SatoriApiOptions, type SatoriApiRequest, type SatoriChannel, type SatoriEmoji, type SatoriEventBody, type SatoriFriend, type SatoriFriendRequestActions, type SatoriGuildMember, type SatoriGuildRole, type SatoriReactionMethod, type SatoriLogin, type SatoriMessage, type SatoriSignal, type SatoriUser, type SatoriWireSegment, } from './protocol.js';
2
2
  export { SatoriWebhookEndpoint, SatoriWsEndpoint, type CreateSatoriWebSocket, type SatoriApiCaller, type SatoriWebhookEndpointOptions, type SatoriWsEndpointOptions, type SatoriWsSocket, } from './endpoint.js';
3
3
  export { handleSatoriWebhookRequest, registerSatoriWebhookRoutes, resolveSatoriOpcode, verifySatoriToken, type SatoriWebhookHandler, } from './webhook.js';
4
4
  export { WS_OPEN, defaultCreateWebSocket, } from './ws.js';
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, formatInboundContent, formatSatoriOutbound, isMessageEvent, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, } from './protocol.js';
1
+ export { SatoriOpcode, buildWsUrl, callSatoriApi, extractCreatedMessageId, decodeSatoriContent, formatInboundContent, formatSatoriOutbound, inboundSatoriSegments, isMessageEvent, mapSatoriFriendRequest, normalizeSatoriGuildRoles, readSatoriFriend, satoriFriendApproveParams, satoriReactionParams, mapGuildEmojiNotice, satoriMessageCreateParams, withSatoriReferrer, isPrivateChannel, resolveInboundSender, resolveSatoriConfig, satoriInboundConversation, } from './protocol.js';
2
2
  export { SatoriWebhookEndpoint, SatoriWsEndpoint, } from './endpoint.js';
3
3
  export { handleSatoriWebhookRequest, registerSatoriWebhookRoutes, resolveSatoriOpcode, verifySatoriToken, } from './webhook.js';
4
4
  export { WS_OPEN, defaultCreateWebSocket, } from './ws.js';