@inline-openclaw/inline 0.0.4 → 0.0.6

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.
@@ -1,18 +1,43 @@
1
- import { jsonResult, readReactionParams, readNumberParam, readStringParam, } from "openclaw/plugin-sdk";
2
- import { InlineSdkClient, Method } from "@inline-chat/realtime-sdk";
1
+ import { createActionGate, jsonResult, readReactionParams, readNumberParam, readStringParam, } from "openclaw/plugin-sdk";
2
+ import { InlineSdkClient, Method, Member_Role, } from "@inline-chat/realtime-sdk";
3
3
  import { resolveInlineAccount, resolveInlineToken } from "./accounts.js";
4
4
  import { normalizeInlineTarget } from "./normalize.js";
5
- const ACTIONS = [
6
- "react",
7
- "reactions",
8
- "read",
9
- "search",
10
- "edit",
11
- "channel-info",
12
- "channel-edit",
13
- "addParticipant",
14
- "member-info",
5
+ const ACTION_GROUPS = [
6
+ { key: "reply", defaultEnabled: true, actions: ["reply", "thread-reply"] },
7
+ { key: "reactions", defaultEnabled: true, actions: ["react", "reactions"] },
8
+ { key: "read", defaultEnabled: true, actions: ["read"] },
9
+ { key: "search", defaultEnabled: true, actions: ["search"] },
10
+ { key: "edit", defaultEnabled: true, actions: ["edit"] },
11
+ {
12
+ key: "channels",
13
+ defaultEnabled: true,
14
+ actions: [
15
+ "channel-info",
16
+ "channel-edit",
17
+ "channel-list",
18
+ "channel-create",
19
+ "channel-delete",
20
+ "channel-move",
21
+ "thread-list",
22
+ "thread-create",
23
+ ],
24
+ },
25
+ {
26
+ key: "participants",
27
+ defaultEnabled: true,
28
+ actions: ["addParticipant", "removeParticipant", "leaveGroup", "member-info"],
29
+ },
30
+ { key: "delete", defaultEnabled: true, actions: ["delete", "unsend"] },
31
+ { key: "pins", defaultEnabled: true, actions: ["pin", "unpin", "list-pins"] },
32
+ { key: "permissions", defaultEnabled: true, actions: ["permissions"] },
15
33
  ];
34
+ const ACTION_TO_GATE_KEY = new Map();
35
+ for (const group of ACTION_GROUPS) {
36
+ for (const action of group.actions) {
37
+ ACTION_TO_GATE_KEY.set(action, group.key);
38
+ }
39
+ }
40
+ const SUPPORTED_ACTIONS = Array.from(ACTION_TO_GATE_KEY.keys());
16
41
  function normalizeChatId(raw) {
17
42
  const normalized = normalizeInlineTarget(raw) ?? raw.trim();
18
43
  if (!/^[0-9]+$/.test(normalized)) {
@@ -35,11 +60,28 @@ function readFlexibleId(params, key) {
35
60
  }
36
61
  return undefined;
37
62
  }
63
+ function readBooleanParam(params, key) {
64
+ const value = params[key];
65
+ if (typeof value === "boolean")
66
+ return value;
67
+ if (typeof value === "string") {
68
+ const trimmed = value.trim().toLowerCase();
69
+ if (trimmed === "true")
70
+ return true;
71
+ if (trimmed === "false")
72
+ return false;
73
+ }
74
+ return undefined;
75
+ }
38
76
  function parseInlineId(raw, label) {
39
- if (typeof raw === "bigint")
77
+ if (typeof raw === "bigint") {
78
+ if (raw < 0n) {
79
+ throw new Error(`inline action: invalid ${label} "${raw.toString()}"`);
80
+ }
40
81
  return raw;
82
+ }
41
83
  if (typeof raw === "number") {
42
- if (!Number.isFinite(raw) || !Number.isInteger(raw)) {
84
+ if (!Number.isFinite(raw) || !Number.isInteger(raw) || raw < 0) {
43
85
  throw new Error(`inline action: invalid ${label} "${String(raw)}"`);
44
86
  }
45
87
  return BigInt(raw);
@@ -61,6 +103,34 @@ function parseOptionalInlineId(raw, label) {
61
103
  return undefined;
62
104
  return parseInlineId(raw, label);
63
105
  }
106
+ function parseInlineIdList(raw, label) {
107
+ if (raw == null)
108
+ return [];
109
+ if (Array.isArray(raw)) {
110
+ return raw.map((item) => parseInlineId(item, label));
111
+ }
112
+ if (typeof raw === "string") {
113
+ const trimmed = raw.trim();
114
+ if (!trimmed)
115
+ return [];
116
+ const chunks = trimmed
117
+ .split(",")
118
+ .map((item) => item.trim())
119
+ .filter(Boolean);
120
+ if (chunks.length <= 1) {
121
+ return [parseInlineId(trimmed, label)];
122
+ }
123
+ return chunks.map((item) => parseInlineId(item, label));
124
+ }
125
+ return [parseInlineId(raw, label)];
126
+ }
127
+ function parseInlineIdListFromParams(params, key) {
128
+ const direct = params[key];
129
+ if (direct != null) {
130
+ return parseInlineIdList(direct, key);
131
+ }
132
+ return [];
133
+ }
64
134
  function resolveChatIdFromParams(params) {
65
135
  const raw = readFlexibleId(params, "chatId") ??
66
136
  readFlexibleId(params, "channelId") ??
@@ -79,6 +149,15 @@ function buildChatPeer(chatId) {
79
149
  },
80
150
  };
81
151
  }
152
+ function buildInlineUserDisplayName(user) {
153
+ const explicit = [user.firstName?.trim(), user.lastName?.trim()].filter(Boolean).join(" ");
154
+ if (explicit)
155
+ return explicit;
156
+ const username = user.username?.trim();
157
+ if (username)
158
+ return `@${username}`;
159
+ return "Unknown";
160
+ }
82
161
  function mapMessage(message) {
83
162
  const reactions = (message.reactions?.reactions ?? []).map((reaction) => ({
84
163
  emoji: reaction.emoji ?? "",
@@ -97,19 +176,52 @@ function mapMessage(message) {
97
176
  reactions,
98
177
  };
99
178
  }
179
+ function mapChatEntry(params) {
180
+ const dialog = params.dialogByChatId.get(String(params.chat.id));
181
+ const peer = params.chat.peerId?.type;
182
+ let peerUser = null;
183
+ if (peer?.oneofKind === "user") {
184
+ peerUser = params.usersById.get(String(peer.user.userId)) ?? null;
185
+ }
186
+ return {
187
+ id: String(params.chat.id),
188
+ title: params.chat.title,
189
+ spaceId: params.chat.spaceId != null ? String(params.chat.spaceId) : null,
190
+ isPublic: params.chat.isPublic ?? false,
191
+ createdBy: params.chat.createdBy != null ? String(params.chat.createdBy) : null,
192
+ date: params.chat.date != null ? Number(params.chat.date) * 1000 : null,
193
+ unreadCount: dialog?.unreadCount ?? 0,
194
+ archived: Boolean(dialog?.archived),
195
+ pinned: Boolean(dialog?.pinned),
196
+ peer: peer?.oneofKind === "user"
197
+ ? {
198
+ kind: "user",
199
+ id: String(peer.user.userId),
200
+ username: peerUser?.username ?? null,
201
+ name: peerUser ? buildInlineUserDisplayName(peerUser) : null,
202
+ }
203
+ : peer?.oneofKind === "chat"
204
+ ? { kind: "chat", id: String(peer.chat.chatId) }
205
+ : null,
206
+ };
207
+ }
208
+ function mapSpaceMemberRole(role) {
209
+ if (role == null)
210
+ return null;
211
+ if (role === Member_Role.OWNER)
212
+ return "owner";
213
+ if (role === Member_Role.ADMIN)
214
+ return "admin";
215
+ if (role === Member_Role.MEMBER)
216
+ return "member";
217
+ return null;
218
+ }
100
219
  async function loadMessageReactions(params) {
101
- const result = await params.client.invokeRaw(Method.GET_CHAT_HISTORY, {
102
- oneofKind: "getChatHistory",
103
- getChatHistory: {
104
- peerId: buildChatPeer(params.chatId),
105
- offsetId: params.messageId + 1n,
106
- limit: 8,
107
- },
220
+ const target = await findMessageById({
221
+ client: params.client,
222
+ chatId: params.chatId,
223
+ messageId: params.messageId,
108
224
  });
109
- if (result.oneofKind !== "getChatHistory") {
110
- throw new Error(`inline action: expected getChatHistory result, got ${String(result.oneofKind)}`);
111
- }
112
- const target = (result.getChatHistory.messages ?? []).find((message) => message.id === params.messageId) ?? null;
113
225
  if (!target) {
114
226
  return [];
115
227
  }
@@ -132,6 +244,32 @@ async function loadMessageReactions(params) {
132
244
  }
133
245
  return Array.from(byEmoji.values());
134
246
  }
247
+ async function findMessageById(params) {
248
+ const directResult = await params.client
249
+ .invokeRaw(Method.GET_MESSAGES, {
250
+ oneofKind: "getMessages",
251
+ getMessages: {
252
+ peerId: buildChatPeer(params.chatId),
253
+ messageIds: [params.messageId],
254
+ },
255
+ })
256
+ .catch(() => null);
257
+ if (directResult?.oneofKind === "getMessages") {
258
+ return (directResult.getMessages.messages ?? []).find((message) => message.id === params.messageId) ?? null;
259
+ }
260
+ const result = await params.client.invokeRaw(Method.GET_CHAT_HISTORY, {
261
+ oneofKind: "getChatHistory",
262
+ getChatHistory: {
263
+ peerId: buildChatPeer(params.chatId),
264
+ offsetId: params.messageId + 1n,
265
+ limit: 8,
266
+ },
267
+ });
268
+ if (result.oneofKind !== "getChatHistory") {
269
+ throw new Error(`inline action: expected getChatHistory result, got ${String(result.oneofKind)}`);
270
+ }
271
+ return (result.getChatHistory.messages ?? []).find((message) => message.id === params.messageId) ?? null;
272
+ }
135
273
  async function withInlineClient(params) {
136
274
  const account = resolveInlineAccount({ cfg: params.cfg, accountId: params.accountId ?? null });
137
275
  if (!account.configured || !account.baseUrl) {
@@ -164,14 +302,68 @@ function toJsonSafe(value) {
164
302
  }
165
303
  return value;
166
304
  }
305
+ function buildDialogMap(dialogs) {
306
+ const map = new Map();
307
+ for (const dialog of dialogs) {
308
+ const chatId = dialog.chatId;
309
+ if (chatId != null) {
310
+ map.set(String(chatId), dialog);
311
+ continue;
312
+ }
313
+ const peer = dialog.peer?.type;
314
+ if (peer?.oneofKind === "chat") {
315
+ map.set(String(peer.chat.chatId), dialog);
316
+ }
317
+ }
318
+ return map;
319
+ }
320
+ function buildUserMap(users) {
321
+ const map = new Map();
322
+ for (const user of users) {
323
+ map.set(String(user.id), user);
324
+ }
325
+ return map;
326
+ }
327
+ function listAllActions() {
328
+ const out = new Set();
329
+ for (const group of ACTION_GROUPS) {
330
+ for (const action of group.actions) {
331
+ out.add(action);
332
+ }
333
+ }
334
+ return Array.from(out);
335
+ }
336
+ function isActionEnabled(params) {
337
+ const key = ACTION_TO_GATE_KEY.get(params.action);
338
+ if (!key)
339
+ return false;
340
+ const group = ACTION_GROUPS.find((item) => item.key === key);
341
+ if (!group)
342
+ return false;
343
+ const account = resolveInlineAccount({
344
+ cfg: params.cfg,
345
+ accountId: params.accountId ?? null,
346
+ });
347
+ const gate = createActionGate((account.config.actions ?? {}));
348
+ return gate(key, group.defaultEnabled);
349
+ }
167
350
  export const inlineMessageActions = {
168
351
  listActions: ({ cfg }) => {
169
352
  const account = resolveInlineAccount({ cfg, accountId: null });
170
353
  if (!account.enabled || !account.configured)
171
354
  return [];
172
- return [...ACTIONS];
355
+ const gate = createActionGate((account.config.actions ?? {}));
356
+ const actions = new Set();
357
+ for (const group of ACTION_GROUPS) {
358
+ if (!gate(group.key, group.defaultEnabled))
359
+ continue;
360
+ for (const action of group.actions) {
361
+ actions.add(action);
362
+ }
363
+ }
364
+ return Array.from(actions);
173
365
  },
174
- supportsAction: ({ action }) => ACTIONS.includes(action),
366
+ supportsAction: ({ action }) => SUPPORTED_ACTIONS.includes(action),
175
367
  extractToolSend: ({ args }) => {
176
368
  const action = typeof args.action === "string" ? args.action.trim() : "";
177
369
  if (action !== "sendMessage")
@@ -185,13 +377,51 @@ export const inlineMessageActions = {
185
377
  return { to: normalized };
186
378
  },
187
379
  handleAction: async ({ action, params, cfg, accountId }) => {
188
- if (action === "react") {
380
+ if (!SUPPORTED_ACTIONS.includes(action)) {
381
+ throw new Error(`Action ${action} is not supported for provider inline.`);
382
+ }
383
+ if (!isActionEnabled({ cfg, accountId: accountId ?? null, action })) {
384
+ throw new Error(`inline action: ${action} is disabled by channels.inline.actions`);
385
+ }
386
+ const normalizedAction = action === "thread-reply" ? "reply" : action;
387
+ if (normalizedAction === "reply") {
388
+ const parseMarkdown = resolveInlineAccount({ cfg, accountId: accountId ?? null }).config.parseMarkdown ?? true;
189
389
  return await withInlineClient({
190
390
  cfg,
191
391
  accountId,
192
392
  fn: async (client) => {
193
393
  const chatId = resolveChatIdFromParams(params);
194
- const messageId = parseInlineId(readFlexibleId(params, "messageId") ?? readStringParam(params, "messageId", { required: true }), "messageId");
394
+ const replyToMsgId = parseInlineId(readFlexibleId(params, "messageId") ??
395
+ readFlexibleId(params, "replyTo") ??
396
+ readFlexibleId(params, "replyToId") ??
397
+ readStringParam(params, "messageId") ??
398
+ readStringParam(params, "replyTo") ??
399
+ readStringParam(params, "replyToId", { required: true }), "messageId");
400
+ const text = readStringParam(params, "message") ??
401
+ readStringParam(params, "text", { required: true, allowEmpty: true });
402
+ const sent = await client.sendMessage({
403
+ chatId,
404
+ text,
405
+ replyToMsgId,
406
+ parseMarkdown,
407
+ });
408
+ return jsonResult({
409
+ ok: true,
410
+ chatId: String(chatId),
411
+ messageId: sent.messageId != null ? String(sent.messageId) : null,
412
+ replyToId: String(replyToMsgId),
413
+ });
414
+ },
415
+ });
416
+ }
417
+ if (normalizedAction === "react") {
418
+ return await withInlineClient({
419
+ cfg,
420
+ accountId,
421
+ fn: async (client) => {
422
+ const chatId = resolveChatIdFromParams(params);
423
+ const messageId = parseInlineId(readFlexibleId(params, "messageId") ??
424
+ readStringParam(params, "messageId", { required: true }), "messageId");
195
425
  const { emoji, remove, isEmpty } = readReactionParams(params, {
196
426
  removeErrorMessage: "Emoji is required to remove an Inline reaction.",
197
427
  });
@@ -234,13 +464,14 @@ export const inlineMessageActions = {
234
464
  },
235
465
  });
236
466
  }
237
- if (action === "reactions") {
467
+ if (normalizedAction === "reactions") {
238
468
  return await withInlineClient({
239
469
  cfg,
240
470
  accountId,
241
471
  fn: async (client) => {
242
472
  const chatId = resolveChatIdFromParams(params);
243
- const messageId = parseInlineId(readFlexibleId(params, "messageId") ?? readStringParam(params, "messageId", { required: true }), "messageId");
473
+ const messageId = parseInlineId(readFlexibleId(params, "messageId") ??
474
+ readStringParam(params, "messageId", { required: true }), "messageId");
244
475
  const reactions = await loadMessageReactions({
245
476
  client,
246
477
  chatId,
@@ -255,7 +486,7 @@ export const inlineMessageActions = {
255
486
  },
256
487
  });
257
488
  }
258
- if (action === "read") {
489
+ if (normalizedAction === "read") {
259
490
  return await withInlineClient({
260
491
  cfg,
261
492
  accountId,
@@ -282,7 +513,7 @@ export const inlineMessageActions = {
282
513
  },
283
514
  });
284
515
  }
285
- if (action === "search") {
516
+ if (normalizedAction === "search") {
286
517
  return await withInlineClient({
287
518
  cfg,
288
519
  accountId,
@@ -314,13 +545,14 @@ export const inlineMessageActions = {
314
545
  },
315
546
  });
316
547
  }
317
- if (action === "edit") {
548
+ if (normalizedAction === "edit") {
318
549
  return await withInlineClient({
319
550
  cfg,
320
551
  accountId,
321
552
  fn: async (client) => {
322
553
  const chatId = resolveChatIdFromParams(params);
323
- const messageId = parseInlineId(readFlexibleId(params, "messageId") ?? readStringParam(params, "messageId", { required: true }), "messageId");
554
+ const messageId = parseInlineId(readFlexibleId(params, "messageId") ??
555
+ readStringParam(params, "messageId", { required: true }), "messageId");
324
556
  const text = readStringParam(params, "message", { required: true, allowEmpty: true });
325
557
  const result = await client.invokeRaw(Method.EDIT_MESSAGE, {
326
558
  oneofKind: "editMessage",
@@ -337,7 +569,7 @@ export const inlineMessageActions = {
337
569
  },
338
570
  });
339
571
  }
340
- if (action === "channel-info") {
572
+ if (normalizedAction === "channel-info") {
341
573
  return await withInlineClient({
342
574
  cfg,
343
575
  accountId,
@@ -360,7 +592,7 @@ export const inlineMessageActions = {
360
592
  },
361
593
  });
362
594
  }
363
- if (action === "channel-edit") {
595
+ if (normalizedAction === "channel-edit") {
364
596
  return await withInlineClient({
365
597
  cfg,
366
598
  accountId,
@@ -388,7 +620,150 @@ export const inlineMessageActions = {
388
620
  },
389
621
  });
390
622
  }
391
- if (action === "addParticipant") {
623
+ if (normalizedAction === "channel-list" || normalizedAction === "thread-list") {
624
+ return await withInlineClient({
625
+ cfg,
626
+ accountId,
627
+ fn: async (client) => {
628
+ const query = readStringParam(params, "query") ??
629
+ readStringParam(params, "q") ??
630
+ undefined;
631
+ const limit = Math.max(1, Math.min(200, readNumberParam(params, "limit", { integer: true }) ?? 50));
632
+ const result = await client.invokeRaw(Method.GET_CHATS, {
633
+ oneofKind: "getChats",
634
+ getChats: {},
635
+ });
636
+ if (result.oneofKind !== "getChats") {
637
+ throw new Error(`inline action: expected getChats result, got ${String(result.oneofKind)}`);
638
+ }
639
+ const dialogByChatId = buildDialogMap(result.getChats.dialogs ?? []);
640
+ const usersById = buildUserMap(result.getChats.users ?? []);
641
+ const entries = (result.getChats.chats ?? []).map((chat) => mapChatEntry({ chat, dialogByChatId, usersById }));
642
+ const normalizedQuery = query?.trim().toLowerCase() ?? "";
643
+ const filtered = normalizedQuery
644
+ ? entries.filter((entry) => {
645
+ const haystack = [
646
+ entry.id,
647
+ entry.title,
648
+ entry.peer?.kind === "user" ? entry.peer.username ?? "" : "",
649
+ entry.peer?.kind === "user" ? entry.peer.name ?? "" : "",
650
+ ]
651
+ .join("\n")
652
+ .toLowerCase();
653
+ return haystack.includes(normalizedQuery);
654
+ })
655
+ : entries;
656
+ return jsonResult(toJsonSafe({
657
+ ok: true,
658
+ query: query ?? null,
659
+ count: filtered.length,
660
+ chats: filtered.slice(0, limit),
661
+ }));
662
+ },
663
+ });
664
+ }
665
+ if (normalizedAction === "channel-create" || normalizedAction === "thread-create") {
666
+ return await withInlineClient({
667
+ cfg,
668
+ accountId,
669
+ fn: async (client) => {
670
+ const title = readStringParam(params, "title") ??
671
+ readStringParam(params, "name") ??
672
+ readStringParam(params, "message", { required: true });
673
+ const description = readStringParam(params, "description");
674
+ const emoji = readStringParam(params, "emoji");
675
+ const spaceId = parseOptionalInlineId(readFlexibleId(params, "spaceId") ?? readFlexibleId(params, "space"), "spaceId");
676
+ const isPublic = readBooleanParam(params, "isPublic") ?? false;
677
+ const participantIds = [
678
+ ...parseInlineIdListFromParams(params, "participants"),
679
+ ...parseInlineIdListFromParams(params, "participantIds"),
680
+ ...parseInlineIdListFromParams(params, "userIds"),
681
+ ...parseInlineIdListFromParams(params, "userId"),
682
+ ];
683
+ const dedupedParticipants = Array.from(new Set(participantIds.map((id) => id.toString()))).map((id) => BigInt(id));
684
+ const result = await client.invokeRaw(Method.CREATE_CHAT, {
685
+ oneofKind: "createChat",
686
+ createChat: {
687
+ title,
688
+ ...(spaceId != null ? { spaceId } : {}),
689
+ ...(description ? { description } : {}),
690
+ ...(emoji ? { emoji } : {}),
691
+ isPublic,
692
+ participants: isPublic ? [] : dedupedParticipants.map((userId) => ({ userId })),
693
+ },
694
+ });
695
+ if (result.oneofKind !== "createChat") {
696
+ throw new Error(`inline action: expected createChat result, got ${String(result.oneofKind)}`);
697
+ }
698
+ return jsonResult(toJsonSafe({
699
+ ok: true,
700
+ title,
701
+ spaceId: spaceId != null ? String(spaceId) : null,
702
+ isPublic,
703
+ participants: dedupedParticipants.map((id) => String(id)),
704
+ chat: result.createChat.chat ?? null,
705
+ dialog: result.createChat.dialog ?? null,
706
+ }));
707
+ },
708
+ });
709
+ }
710
+ if (normalizedAction === "channel-delete") {
711
+ return await withInlineClient({
712
+ cfg,
713
+ accountId,
714
+ fn: async (client) => {
715
+ const chatId = resolveChatIdFromParams(params);
716
+ const result = await client.invokeRaw(Method.DELETE_CHAT, {
717
+ oneofKind: "deleteChat",
718
+ deleteChat: {
719
+ peerId: buildChatPeer(chatId),
720
+ },
721
+ });
722
+ if (result.oneofKind !== "deleteChat") {
723
+ throw new Error(`inline action: expected deleteChat result, got ${String(result.oneofKind)}`);
724
+ }
725
+ return jsonResult({
726
+ ok: true,
727
+ chatId: String(chatId),
728
+ });
729
+ },
730
+ });
731
+ }
732
+ if (normalizedAction === "channel-move") {
733
+ return await withInlineClient({
734
+ cfg,
735
+ accountId,
736
+ fn: async (client) => {
737
+ const chatId = resolveChatIdFromParams(params);
738
+ const rawSpace = readStringParam(params, "spaceId") ?? readStringParam(params, "toSpaceId");
739
+ const normalizedSpace = rawSpace?.trim().toLowerCase();
740
+ const moveToHome = normalizedSpace === "" ||
741
+ normalizedSpace === "home" ||
742
+ normalizedSpace === "none" ||
743
+ normalizedSpace === "null";
744
+ const parsedSpace = moveToHome
745
+ ? undefined
746
+ : parseOptionalInlineId(readFlexibleId(params, "spaceId") ?? readFlexibleId(params, "toSpaceId"), "spaceId");
747
+ const result = await client.invokeRaw(Method.MOVE_THREAD, {
748
+ oneofKind: "moveThread",
749
+ moveThread: {
750
+ chatId,
751
+ ...(parsedSpace != null ? { spaceId: parsedSpace } : {}),
752
+ },
753
+ });
754
+ if (result.oneofKind !== "moveThread") {
755
+ throw new Error(`inline action: expected moveThread result, got ${String(result.oneofKind)}`);
756
+ }
757
+ return jsonResult(toJsonSafe({
758
+ ok: true,
759
+ chatId: String(chatId),
760
+ spaceId: parsedSpace != null ? String(parsedSpace) : null,
761
+ chat: result.moveThread.chat ?? null,
762
+ }));
763
+ },
764
+ });
765
+ }
766
+ if (normalizedAction === "addParticipant") {
392
767
  return await withInlineClient({
393
768
  cfg,
394
769
  accountId,
@@ -417,13 +792,69 @@ export const inlineMessageActions = {
417
792
  },
418
793
  });
419
794
  }
420
- if (action === "member-info") {
795
+ if (normalizedAction === "removeParticipant") {
796
+ return await withInlineClient({
797
+ cfg,
798
+ accountId,
799
+ fn: async (client) => {
800
+ const chatId = resolveChatIdFromParams(params);
801
+ const userId = parseInlineId(readFlexibleId(params, "userId") ??
802
+ readFlexibleId(params, "participant") ??
803
+ readFlexibleId(params, "memberId") ??
804
+ readStringParam(params, "userId", { required: true }), "userId");
805
+ const result = await client.invokeRaw(Method.REMOVE_CHAT_PARTICIPANT, {
806
+ oneofKind: "removeChatParticipant",
807
+ removeChatParticipant: {
808
+ chatId,
809
+ userId,
810
+ },
811
+ });
812
+ if (result.oneofKind !== "removeChatParticipant") {
813
+ throw new Error(`inline action: expected removeChatParticipant result, got ${String(result.oneofKind)}`);
814
+ }
815
+ return jsonResult({
816
+ ok: true,
817
+ chatId: String(chatId),
818
+ userId: String(userId),
819
+ });
820
+ },
821
+ });
822
+ }
823
+ if (normalizedAction === "leaveGroup") {
421
824
  return await withInlineClient({
422
825
  cfg,
423
826
  accountId,
424
827
  fn: async (client) => {
425
828
  const chatId = resolveChatIdFromParams(params);
426
- const userId = parseInlineId(readFlexibleId(params, "userId") ?? readStringParam(params, "userId", { required: true }), "userId");
829
+ const me = await client.getMe();
830
+ const userId = me.userId;
831
+ const result = await client.invokeRaw(Method.REMOVE_CHAT_PARTICIPANT, {
832
+ oneofKind: "removeChatParticipant",
833
+ removeChatParticipant: {
834
+ chatId,
835
+ userId,
836
+ },
837
+ });
838
+ if (result.oneofKind !== "removeChatParticipant") {
839
+ throw new Error(`inline action: expected removeChatParticipant result, got ${String(result.oneofKind)}`);
840
+ }
841
+ return jsonResult({
842
+ ok: true,
843
+ chatId: String(chatId),
844
+ userId: String(userId),
845
+ left: true,
846
+ });
847
+ },
848
+ });
849
+ }
850
+ if (normalizedAction === "member-info") {
851
+ return await withInlineClient({
852
+ cfg,
853
+ accountId,
854
+ fn: async (client) => {
855
+ const chatId = resolveChatIdFromParams(params);
856
+ const userId = parseInlineId(readFlexibleId(params, "userId") ??
857
+ readStringParam(params, "userId", { required: true }), "userId");
427
858
  const result = await client.invokeRaw(Method.GET_CHAT_PARTICIPANTS, {
428
859
  oneofKind: "getChatParticipants",
429
860
  getChatParticipants: { chatId },
@@ -443,7 +874,180 @@ export const inlineMessageActions = {
443
874
  },
444
875
  });
445
876
  }
877
+ if (normalizedAction === "delete" || normalizedAction === "unsend") {
878
+ return await withInlineClient({
879
+ cfg,
880
+ accountId,
881
+ fn: async (client) => {
882
+ const chatId = resolveChatIdFromParams(params);
883
+ const messageIds = [
884
+ ...parseInlineIdListFromParams(params, "messageIds"),
885
+ ...parseInlineIdListFromParams(params, "messages"),
886
+ ...parseInlineIdListFromParams(params, "ids"),
887
+ ];
888
+ if (messageIds.length === 0) {
889
+ messageIds.push(parseInlineId(readFlexibleId(params, "messageId") ??
890
+ readStringParam(params, "messageId", { required: true }), "messageId"));
891
+ }
892
+ const deduped = Array.from(new Set(messageIds.map((id) => id.toString()))).map((id) => BigInt(id));
893
+ const result = await client.invokeRaw(Method.DELETE_MESSAGES, {
894
+ oneofKind: "deleteMessages",
895
+ deleteMessages: {
896
+ peerId: buildChatPeer(chatId),
897
+ messageIds: deduped,
898
+ },
899
+ });
900
+ if (result.oneofKind !== "deleteMessages") {
901
+ throw new Error(`inline action: expected deleteMessages result, got ${String(result.oneofKind)}`);
902
+ }
903
+ return jsonResult({
904
+ ok: true,
905
+ chatId: String(chatId),
906
+ messageIds: deduped.map((id) => String(id)),
907
+ });
908
+ },
909
+ });
910
+ }
911
+ if (normalizedAction === "pin" || normalizedAction === "unpin") {
912
+ return await withInlineClient({
913
+ cfg,
914
+ accountId,
915
+ fn: async (client) => {
916
+ const chatId = resolveChatIdFromParams(params);
917
+ const messageId = parseInlineId(readFlexibleId(params, "messageId") ??
918
+ readStringParam(params, "messageId", { required: true }), "messageId");
919
+ const unpin = normalizedAction === "unpin" || readBooleanParam(params, "unpin") === true;
920
+ const result = await client.invokeRaw(Method.PIN_MESSAGE, {
921
+ oneofKind: "pinMessage",
922
+ pinMessage: {
923
+ peerId: buildChatPeer(chatId),
924
+ messageId,
925
+ unpin,
926
+ },
927
+ });
928
+ if (result.oneofKind !== "pinMessage") {
929
+ throw new Error(`inline action: expected pinMessage result, got ${String(result.oneofKind)}`);
930
+ }
931
+ return jsonResult({
932
+ ok: true,
933
+ chatId: String(chatId),
934
+ messageId: String(messageId),
935
+ unpin,
936
+ });
937
+ },
938
+ });
939
+ }
940
+ if (normalizedAction === "list-pins") {
941
+ return await withInlineClient({
942
+ cfg,
943
+ accountId,
944
+ fn: async (client) => {
945
+ const chatId = resolveChatIdFromParams(params);
946
+ const result = await client.invokeRaw(Method.GET_CHAT, {
947
+ oneofKind: "getChat",
948
+ getChat: { peerId: buildChatPeer(chatId) },
949
+ });
950
+ if (result.oneofKind !== "getChat") {
951
+ throw new Error(`inline action: expected getChat result, got ${String(result.oneofKind)}`);
952
+ }
953
+ const pinnedMessageIds = (result.getChat.pinnedMessageIds ?? []).map((id) => String(id));
954
+ return jsonResult({
955
+ ok: true,
956
+ chatId: String(chatId),
957
+ pinnedMessageIds,
958
+ });
959
+ },
960
+ });
961
+ }
962
+ if (normalizedAction === "permissions") {
963
+ return await withInlineClient({
964
+ cfg,
965
+ accountId,
966
+ fn: async (client) => {
967
+ const chatId = resolveChatIdFromParams(params);
968
+ const chatResult = await client.invokeRaw(Method.GET_CHAT, {
969
+ oneofKind: "getChat",
970
+ getChat: { peerId: buildChatPeer(chatId) },
971
+ });
972
+ if (chatResult.oneofKind !== "getChat") {
973
+ throw new Error(`inline action: expected getChat result, got ${String(chatResult.oneofKind)}`);
974
+ }
975
+ const spaceId = chatResult.getChat.chat?.spaceId ?? chatResult.getChat.dialog?.spaceId;
976
+ if (spaceId == null) {
977
+ throw new Error("inline action: permissions requires a chat that belongs to a space");
978
+ }
979
+ const userIdRaw = readFlexibleId(params, "userId") ??
980
+ readFlexibleId(params, "memberId") ??
981
+ readStringParam(params, "userId");
982
+ const userId = userIdRaw ? parseInlineId(userIdRaw, "userId") : undefined;
983
+ const roleValue = readStringParam(params, "role")?.trim().toLowerCase();
984
+ const canAccessPublicChats = readBooleanParam(params, "canAccessPublicChats");
985
+ if (userId != null && roleValue) {
986
+ const role = roleValue === "admin"
987
+ ? { role: { oneofKind: "admin", admin: {} } }
988
+ : roleValue === "member"
989
+ ? {
990
+ role: {
991
+ oneofKind: "member",
992
+ member: {
993
+ canAccessPublicChats: canAccessPublicChats ?? true,
994
+ },
995
+ },
996
+ }
997
+ : null;
998
+ if (!role) {
999
+ throw new Error("inline action: role must be \"admin\" or \"member\"");
1000
+ }
1001
+ const updateResult = await client.invokeRaw(Method.UPDATE_MEMBER_ACCESS, {
1002
+ oneofKind: "updateMemberAccess",
1003
+ updateMemberAccess: {
1004
+ spaceId,
1005
+ userId,
1006
+ role,
1007
+ },
1008
+ });
1009
+ if (updateResult.oneofKind !== "updateMemberAccess") {
1010
+ throw new Error(`inline action: expected updateMemberAccess result, got ${String(updateResult.oneofKind)}`);
1011
+ }
1012
+ }
1013
+ const membersResult = await client.invokeRaw(Method.GET_SPACE_MEMBERS, {
1014
+ oneofKind: "getSpaceMembers",
1015
+ getSpaceMembers: {
1016
+ spaceId,
1017
+ },
1018
+ });
1019
+ if (membersResult.oneofKind !== "getSpaceMembers") {
1020
+ throw new Error(`inline action: expected getSpaceMembers result, got ${String(membersResult.oneofKind)}`);
1021
+ }
1022
+ const usersById = buildUserMap(membersResult.getSpaceMembers.users ?? []);
1023
+ const members = (membersResult.getSpaceMembers.members ?? []).map((member) => {
1024
+ const linkedUser = usersById.get(String(member.userId));
1025
+ return {
1026
+ userId: String(member.userId),
1027
+ role: mapSpaceMemberRole(member.role),
1028
+ canAccessPublicChats: member.canAccessPublicChats,
1029
+ date: Number(member.date) * 1000,
1030
+ user: linkedUser
1031
+ ? {
1032
+ id: String(linkedUser.id),
1033
+ name: buildInlineUserDisplayName(linkedUser),
1034
+ username: linkedUser.username ?? null,
1035
+ }
1036
+ : null,
1037
+ };
1038
+ });
1039
+ const filteredMembers = userId != null ? members.filter((member) => member.userId === String(userId)) : members;
1040
+ return jsonResult(toJsonSafe({
1041
+ ok: true,
1042
+ chatId: String(chatId),
1043
+ spaceId: String(spaceId),
1044
+ members: filteredMembers,
1045
+ }));
1046
+ },
1047
+ });
1048
+ }
446
1049
  throw new Error(`Action ${action} is not supported for provider inline.`);
447
1050
  },
448
1051
  };
1052
+ export const inlineSupportedActions = listAllActions();
449
1053
  //# sourceMappingURL=actions.js.map