@overpod/mcp-telegram 1.25.0 → 1.26.0

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +35 -5
  3. package/dist/__tests__/approve-join-request.test.d.ts +1 -0
  4. package/dist/__tests__/approve-join-request.test.js +107 -0
  5. package/dist/__tests__/boosts.test.d.ts +1 -0
  6. package/dist/__tests__/boosts.test.js +310 -0
  7. package/dist/__tests__/broadcast-stats.test.d.ts +1 -0
  8. package/dist/__tests__/broadcast-stats.test.js +172 -0
  9. package/dist/__tests__/business-chat-links.test.d.ts +1 -0
  10. package/dist/__tests__/business-chat-links.test.js +102 -0
  11. package/dist/__tests__/get-message-buttons.test.d.ts +1 -0
  12. package/dist/__tests__/get-message-buttons.test.js +122 -0
  13. package/dist/__tests__/group-calls.test.d.ts +1 -0
  14. package/dist/__tests__/group-calls.test.js +503 -0
  15. package/dist/__tests__/inline-query-send.test.d.ts +1 -0
  16. package/dist/__tests__/inline-query-send.test.js +94 -0
  17. package/dist/__tests__/inline-query.test.d.ts +1 -0
  18. package/dist/__tests__/inline-query.test.js +115 -0
  19. package/dist/__tests__/megagroup-stats.test.d.ts +1 -0
  20. package/dist/__tests__/megagroup-stats.test.js +166 -0
  21. package/dist/__tests__/press-button.test.d.ts +1 -0
  22. package/dist/__tests__/press-button.test.js +123 -0
  23. package/dist/__tests__/quick-replies.test.d.ts +1 -0
  24. package/dist/__tests__/quick-replies.test.js +245 -0
  25. package/dist/__tests__/set-chat-reactions.test.d.ts +1 -0
  26. package/dist/__tests__/set-chat-reactions.test.js +129 -0
  27. package/dist/__tests__/stars-status.test.d.ts +1 -0
  28. package/dist/__tests__/stars-status.test.js +205 -0
  29. package/dist/__tests__/stars-transactions.test.d.ts +1 -0
  30. package/dist/__tests__/stars-transactions.test.js +82 -0
  31. package/dist/__tests__/stories.test.d.ts +1 -0
  32. package/dist/__tests__/stories.test.js +361 -0
  33. package/dist/__tests__/toggle-anti-spam.test.d.ts +1 -0
  34. package/dist/__tests__/toggle-anti-spam.test.js +80 -0
  35. package/dist/__tests__/toggle-channel-signatures.test.d.ts +1 -0
  36. package/dist/__tests__/toggle-channel-signatures.test.js +80 -0
  37. package/dist/__tests__/toggle-forum-mode.test.d.ts +1 -0
  38. package/dist/__tests__/toggle-forum-mode.test.js +80 -0
  39. package/dist/__tests__/toggle-prehistory-hidden.test.d.ts +1 -0
  40. package/dist/__tests__/toggle-prehistory-hidden.test.js +80 -0
  41. package/dist/__tests__/updates.test.d.ts +1 -0
  42. package/dist/__tests__/updates.test.js +221 -0
  43. package/dist/rate-limiter.d.ts +8 -2
  44. package/dist/rate-limiter.js +15 -8
  45. package/dist/telegram-client.d.ts +580 -0
  46. package/dist/telegram-client.js +1322 -0
  47. package/dist/tools/account.js +16 -0
  48. package/dist/tools/boosts.d.ts +3 -0
  49. package/dist/tools/boosts.js +65 -0
  50. package/dist/tools/chats.js +150 -0
  51. package/dist/tools/group-calls.d.ts +4 -0
  52. package/dist/tools/group-calls.js +77 -0
  53. package/dist/tools/index.js +10 -0
  54. package/dist/tools/messages.js +192 -0
  55. package/dist/tools/quick-replies.d.ts +4 -0
  56. package/dist/tools/quick-replies.js +58 -0
  57. package/dist/tools/reactions.js +43 -0
  58. package/dist/tools/stars.d.ts +4 -0
  59. package/dist/tools/stars.js +71 -0
  60. package/dist/tools/stories.d.ts +3 -0
  61. package/dist/tools/stories.js +107 -0
  62. package/package.json +1 -1
@@ -0,0 +1,361 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import bigInt from "big-integer";
4
+ import { Api } from "telegram/tl/index.js";
5
+ import { summarizeAllStories, summarizePeerStories, summarizeStoriesById, summarizeStoryItem, summarizeStoryView, summarizeStoryViewsList, TelegramService, } from "../telegram-client.js";
6
+ function makeService(invocations, responder) {
7
+ const fakeClient = {
8
+ invoke: async (req) => {
9
+ invocations.push(req);
10
+ return responder(req);
11
+ },
12
+ };
13
+ const service = new TelegramService(1, "hash");
14
+ const internals = service;
15
+ internals.client = fakeClient;
16
+ internals.connected = true;
17
+ return service;
18
+ }
19
+ function makeActiveStory(id, opts = {}) {
20
+ return new Api.StoryItem({
21
+ id,
22
+ date: 1000 + id,
23
+ expireDate: 2000 + id,
24
+ caption: opts.caption,
25
+ media: new Api.MessageMediaEmpty(),
26
+ fromId: new Api.PeerUser({ userId: bigInt(42) }),
27
+ pinned: true,
28
+ public: true,
29
+ views: new Api.StoryViews({
30
+ viewsCount: opts.views ?? 0,
31
+ reactionsCount: opts.reactions,
32
+ }),
33
+ });
34
+ }
35
+ describe("summarizeStoryItem", () => {
36
+ it("summarizes active StoryItem with media className and views counters", () => {
37
+ const item = makeActiveStory(1, { caption: "hi", views: 7, reactions: 3 });
38
+ const out = summarizeStoryItem(item);
39
+ assert.strictEqual(out.id, 1);
40
+ assert.strictEqual(out.kind, "active");
41
+ assert.strictEqual(out.caption, "hi");
42
+ assert.strictEqual(out.mediaType, "MessageMediaEmpty");
43
+ assert.strictEqual(out.viewsCount, 7);
44
+ assert.strictEqual(out.reactionsCount, 3);
45
+ assert.deepStrictEqual(out.fromId, { kind: "user", id: "42" });
46
+ assert.strictEqual(out.pinned, true);
47
+ assert.strictEqual(out.public, true);
48
+ });
49
+ it("summarizes StoryItemDeleted as kind=deleted", () => {
50
+ const out = summarizeStoryItem(new Api.StoryItemDeleted({ id: 5 }));
51
+ assert.deepStrictEqual(out, { id: 5, kind: "deleted" });
52
+ });
53
+ it("summarizes StoryItemSkipped as kind=skipped", () => {
54
+ const out = summarizeStoryItem(new Api.StoryItemSkipped({ id: 9, date: 111, expireDate: 222, closeFriends: true }));
55
+ assert.strictEqual(out.kind, "skipped");
56
+ assert.strictEqual(out.id, 9);
57
+ assert.strictEqual(out.date, 111);
58
+ assert.strictEqual(out.expireDate, 222);
59
+ assert.strictEqual(out.closeFriends, true);
60
+ });
61
+ });
62
+ describe("summarizePeerStories", () => {
63
+ it("maps peer+stories and preserves maxReadId", () => {
64
+ const ps = new Api.PeerStories({
65
+ peer: new Api.PeerUser({ userId: bigInt(77) }),
66
+ maxReadId: 3,
67
+ stories: [makeActiveStory(1), new Api.StoryItemDeleted({ id: 2 })],
68
+ });
69
+ const out = summarizePeerStories(ps);
70
+ assert.ok(out);
71
+ assert.deepStrictEqual(out?.peer, { kind: "user", id: "77" });
72
+ assert.strictEqual(out?.maxReadId, 3);
73
+ assert.strictEqual(out?.stories.length, 2);
74
+ assert.strictEqual(out?.stories[0].kind, "active");
75
+ assert.strictEqual(out?.stories[1].kind, "deleted");
76
+ });
77
+ });
78
+ describe("summarizeAllStories", () => {
79
+ it("returns modified=false and empty peerStories for AllStoriesNotModified", () => {
80
+ const resp = new Api.stories.AllStoriesNotModified({
81
+ state: "abc",
82
+ stealthMode: new Api.StoriesStealthMode({ activeUntilDate: 123 }),
83
+ });
84
+ const out = summarizeAllStories(resp);
85
+ assert.strictEqual(out.modified, false);
86
+ assert.strictEqual(out.state, "abc");
87
+ assert.deepStrictEqual(out.peerStories, []);
88
+ assert.strictEqual(out.stealthMode?.activeUntilDate, 123);
89
+ });
90
+ it("returns modified=true with peer stories for AllStories", () => {
91
+ const ps = new Api.PeerStories({
92
+ peer: new Api.PeerChannel({ channelId: bigInt(500) }),
93
+ stories: [makeActiveStory(10, { caption: "ch-story" })],
94
+ });
95
+ const resp = new Api.stories.AllStories({
96
+ hasMore: true,
97
+ count: 1,
98
+ state: "next-token",
99
+ peerStories: [ps],
100
+ chats: [],
101
+ users: [],
102
+ stealthMode: new Api.StoriesStealthMode({}),
103
+ });
104
+ const out = summarizeAllStories(resp);
105
+ assert.strictEqual(out.modified, true);
106
+ assert.strictEqual(out.hasMore, true);
107
+ assert.strictEqual(out.count, 1);
108
+ assert.strictEqual(out.state, "next-token");
109
+ assert.strictEqual(out.peerStories.length, 1);
110
+ assert.deepStrictEqual(out.peerStories[0].peer, { kind: "channel", id: "500" });
111
+ assert.strictEqual(out.peerStories[0].stories[0].caption, "ch-story");
112
+ });
113
+ });
114
+ describe("TelegramService.getAllStories", () => {
115
+ it("invokes stories.GetAllStories with passed options", async () => {
116
+ const invocations = [];
117
+ const service = makeService(invocations, () => new Api.stories.AllStoriesNotModified({
118
+ state: "s1",
119
+ stealthMode: new Api.StoriesStealthMode({}),
120
+ }));
121
+ const out = await service.getAllStories({ next: true, hidden: false, state: "s0" });
122
+ const call = invocations.find((r) => r instanceof Api.stories.GetAllStories);
123
+ assert.ok(call);
124
+ assert.strictEqual(call.next, true);
125
+ assert.strictEqual(call.hidden, false);
126
+ assert.strictEqual(call.state, "s0");
127
+ assert.strictEqual(out.modified, false);
128
+ assert.strictEqual(out.state, "s1");
129
+ });
130
+ it("returns peerStories for AllStories response", async () => {
131
+ const invocations = [];
132
+ const ps = new Api.PeerStories({
133
+ peer: new Api.PeerUser({ userId: bigInt(1) }),
134
+ stories: [makeActiveStory(1)],
135
+ });
136
+ const service = makeService(invocations, () => new Api.stories.AllStories({
137
+ hasMore: false,
138
+ count: 1,
139
+ state: "final",
140
+ peerStories: [ps],
141
+ chats: [],
142
+ users: [],
143
+ stealthMode: new Api.StoriesStealthMode({}),
144
+ }));
145
+ const out = await service.getAllStories();
146
+ assert.strictEqual(out.modified, true);
147
+ assert.strictEqual(out.peerStories.length, 1);
148
+ assert.strictEqual(out.peerStories[0].stories[0].id, 1);
149
+ });
150
+ });
151
+ describe("TelegramService.getPeerStories", () => {
152
+ it("invokes stories.GetPeerStories with resolved numeric peer", async () => {
153
+ const invocations = [];
154
+ const inner = new Api.PeerStories({
155
+ peer: new Api.PeerUser({ userId: bigInt(42) }),
156
+ maxReadId: 5,
157
+ stories: [makeActiveStory(11, { caption: "hello" }), new Api.StoryItemDeleted({ id: 12 })],
158
+ });
159
+ const service = makeService(invocations, () => new Api.stories.PeerStories({
160
+ stories: inner,
161
+ chats: [],
162
+ users: [],
163
+ }));
164
+ const out = await service.getPeerStories("42");
165
+ const call = invocations.find((r) => r instanceof Api.stories.GetPeerStories);
166
+ assert.ok(call);
167
+ assert.strictEqual(call.peer, "42");
168
+ assert.ok(out);
169
+ assert.deepStrictEqual(out?.peer, { kind: "user", id: "42" });
170
+ assert.strictEqual(out?.maxReadId, 5);
171
+ assert.strictEqual(out?.stories.length, 2);
172
+ assert.strictEqual(out?.stories[0].caption, "hello");
173
+ assert.strictEqual(out?.stories[1].kind, "deleted");
174
+ });
175
+ it("passes @username peers through unchanged", async () => {
176
+ const invocations = [];
177
+ const service = makeService(invocations, () => new Api.stories.PeerStories({
178
+ stories: new Api.PeerStories({
179
+ peer: new Api.PeerChannel({ channelId: bigInt(777) }),
180
+ stories: [],
181
+ }),
182
+ chats: [],
183
+ users: [],
184
+ }));
185
+ await service.getPeerStories("@durov");
186
+ const call = invocations.find((r) => r instanceof Api.stories.GetPeerStories);
187
+ assert.ok(call);
188
+ assert.strictEqual(call.peer, "@durov");
189
+ });
190
+ });
191
+ describe("summarizeStoriesById", () => {
192
+ it("maps count, stories and pinnedToTop", () => {
193
+ const resp = new Api.stories.Stories({
194
+ count: 2,
195
+ stories: [makeActiveStory(10, { caption: "first" }), new Api.StoryItemDeleted({ id: 11 })],
196
+ pinnedToTop: [10],
197
+ chats: [],
198
+ users: [],
199
+ });
200
+ const out = summarizeStoriesById(resp);
201
+ assert.strictEqual(out.count, 2);
202
+ assert.strictEqual(out.stories.length, 2);
203
+ assert.strictEqual(out.stories[0].caption, "first");
204
+ assert.strictEqual(out.stories[1].kind, "deleted");
205
+ assert.deepStrictEqual(out.pinnedToTop, [10]);
206
+ });
207
+ });
208
+ describe("TelegramService.getStoriesById", () => {
209
+ it("invokes stories.GetStoriesByID with resolved peer and ids", async () => {
210
+ const invocations = [];
211
+ const service = makeService(invocations, () => new Api.stories.Stories({
212
+ count: 1,
213
+ stories: [makeActiveStory(7, { caption: "single" })],
214
+ chats: [],
215
+ users: [],
216
+ }));
217
+ const out = await service.getStoriesById("42", [7, 8]);
218
+ const call = invocations.find((r) => r instanceof Api.stories.GetStoriesByID);
219
+ assert.ok(call);
220
+ assert.strictEqual(call.peer, "42");
221
+ assert.deepStrictEqual(call.id, [7, 8]);
222
+ assert.strictEqual(out.count, 1);
223
+ assert.strictEqual(out.stories[0].id, 7);
224
+ assert.strictEqual(out.stories[0].caption, "single");
225
+ });
226
+ it("passes @username peers through unchanged", async () => {
227
+ const invocations = [];
228
+ const service = makeService(invocations, () => new Api.stories.Stories({
229
+ count: 0,
230
+ stories: [],
231
+ chats: [],
232
+ users: [],
233
+ }));
234
+ await service.getStoriesById("@durov", [1]);
235
+ const call = invocations.find((r) => r instanceof Api.stories.GetStoriesByID);
236
+ assert.ok(call);
237
+ assert.strictEqual(call.peer, "@durov");
238
+ });
239
+ });
240
+ describe("summarizeStoryView", () => {
241
+ it("maps StoryView (user) with reaction", () => {
242
+ const view = new Api.StoryView({
243
+ userId: bigInt(501),
244
+ date: 1710000000,
245
+ reaction: new Api.ReactionEmoji({ emoticon: "👍" }),
246
+ blocked: false,
247
+ });
248
+ const out = summarizeStoryView(view);
249
+ assert.strictEqual(out.kind, "user");
250
+ if (out.kind !== "user")
251
+ throw new Error("wrong kind");
252
+ assert.strictEqual(out.userId, "501");
253
+ assert.strictEqual(out.date, 1710000000);
254
+ assert.strictEqual(out.reaction, "👍");
255
+ assert.strictEqual(out.blocked, false);
256
+ });
257
+ it("maps StoryView without reaction to reaction:undefined", () => {
258
+ const view = new Api.StoryView({ userId: bigInt(7), date: 1, blockedMyStoriesFrom: true });
259
+ const out = summarizeStoryView(view);
260
+ assert.strictEqual(out.kind, "user");
261
+ if (out.kind !== "user")
262
+ throw new Error("wrong kind");
263
+ assert.strictEqual(out.userId, "7");
264
+ assert.strictEqual(out.reaction, undefined);
265
+ assert.strictEqual(out.blockedMyStoriesFrom, true);
266
+ });
267
+ it("maps StoryViewPublicRepost with peer and story id", () => {
268
+ const view = new Api.StoryViewPublicRepost({
269
+ peerId: new Api.PeerChannel({ channelId: bigInt(900) }),
270
+ story: new Api.StoryItemDeleted({ id: 44 }),
271
+ });
272
+ const out = summarizeStoryView(view);
273
+ assert.strictEqual(out.kind, "publicRepost");
274
+ if (out.kind !== "publicRepost")
275
+ throw new Error("wrong kind");
276
+ assert.deepStrictEqual(out.peer, { kind: "channel", id: "900" });
277
+ assert.strictEqual(out.storyId, 44);
278
+ });
279
+ });
280
+ describe("summarizeStoryViewsList", () => {
281
+ it("maps counts, views array and nextOffset", () => {
282
+ const list = new Api.stories.StoryViewsList({
283
+ count: 2,
284
+ viewsCount: 5,
285
+ forwardsCount: 1,
286
+ reactionsCount: 3,
287
+ views: [
288
+ new Api.StoryView({
289
+ userId: bigInt(10),
290
+ date: 100,
291
+ reaction: new Api.ReactionEmoji({ emoticon: "❤" }),
292
+ }),
293
+ new Api.StoryView({ userId: bigInt(11), date: 101 }),
294
+ ],
295
+ chats: [],
296
+ users: [],
297
+ nextOffset: "cursor-1",
298
+ });
299
+ const out = summarizeStoryViewsList(list);
300
+ assert.strictEqual(out.count, 2);
301
+ assert.strictEqual(out.viewsCount, 5);
302
+ assert.strictEqual(out.forwardsCount, 1);
303
+ assert.strictEqual(out.reactionsCount, 3);
304
+ assert.strictEqual(out.nextOffset, "cursor-1");
305
+ assert.strictEqual(out.views.length, 2);
306
+ assert.strictEqual(out.views[0].kind, "user");
307
+ if (out.views[0].kind !== "user")
308
+ throw new Error("wrong kind");
309
+ assert.strictEqual(out.views[0].userId, "10");
310
+ assert.strictEqual(out.views[0].reaction, "❤");
311
+ });
312
+ });
313
+ describe("TelegramService.getStoryViewsList", () => {
314
+ it("invokes stories.GetStoryViewsList with resolved peer and options", async () => {
315
+ const invocations = [];
316
+ const service = makeService(invocations, () => new Api.stories.StoryViewsList({
317
+ count: 0,
318
+ viewsCount: 0,
319
+ forwardsCount: 0,
320
+ reactionsCount: 0,
321
+ views: [],
322
+ chats: [],
323
+ users: [],
324
+ }));
325
+ const out = await service.getStoryViewsList("42", {
326
+ id: 99,
327
+ q: "alice",
328
+ justContacts: true,
329
+ reactionsFirst: true,
330
+ limit: 25,
331
+ });
332
+ const call = invocations.find((r) => r instanceof Api.stories.GetStoryViewsList);
333
+ assert.ok(call);
334
+ assert.strictEqual(call.peer, "42");
335
+ assert.strictEqual(call.id, 99);
336
+ assert.strictEqual(call.q, "alice");
337
+ assert.strictEqual(call.justContacts, true);
338
+ assert.strictEqual(call.reactionsFirst, true);
339
+ assert.strictEqual(call.limit, 25);
340
+ assert.strictEqual(call.offset, "");
341
+ assert.strictEqual(out.count, 0);
342
+ assert.strictEqual(out.views.length, 0);
343
+ });
344
+ it("passes offset cursor through", async () => {
345
+ const invocations = [];
346
+ const service = makeService(invocations, () => new Api.stories.StoryViewsList({
347
+ count: 0,
348
+ viewsCount: 0,
349
+ forwardsCount: 0,
350
+ reactionsCount: 0,
351
+ views: [],
352
+ chats: [],
353
+ users: [],
354
+ }));
355
+ await service.getStoryViewsList("@durov", { id: 1, offset: "prev-cursor" });
356
+ const call = invocations.find((r) => r instanceof Api.stories.GetStoryViewsList);
357
+ assert.ok(call);
358
+ assert.strictEqual(call.offset, "prev-cursor");
359
+ assert.strictEqual(call.limit, 50);
360
+ });
361
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import bigInt from "big-integer";
4
+ import { Api } from "telegram/tl/index.js";
5
+ import { TelegramService } from "../telegram-client.js";
6
+ function makeService(entity, invocations) {
7
+ const fakeClient = {
8
+ invoke: async (req) => {
9
+ invocations.push(req);
10
+ return undefined;
11
+ },
12
+ };
13
+ const service = new TelegramService(1, "hash");
14
+ const internals = service;
15
+ internals.client = fakeClient;
16
+ internals.connected = true;
17
+ internals.resolveChat = async () => entity;
18
+ return service;
19
+ }
20
+ describe("TelegramService.toggleAntiSpam", () => {
21
+ it("invokes channels.ToggleAntiSpam with enabled=true for supergroup", async () => {
22
+ const megagroup = new Api.Channel({
23
+ id: bigInt(12345),
24
+ title: "supergroup",
25
+ photo: new Api.ChatPhotoEmpty(),
26
+ date: 0,
27
+ accessHash: bigInt(1),
28
+ megagroup: true,
29
+ });
30
+ const invocations = [];
31
+ const service = makeService(megagroup, invocations);
32
+ await service.toggleAntiSpam("12345", true);
33
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleAntiSpam);
34
+ assert.ok(call, "ToggleAntiSpam was invoked");
35
+ assert.strictEqual(call.enabled, true);
36
+ });
37
+ it("invokes channels.ToggleAntiSpam with enabled=false", async () => {
38
+ const megagroup = new Api.Channel({
39
+ id: bigInt(22222),
40
+ title: "supergroup",
41
+ photo: new Api.ChatPhotoEmpty(),
42
+ date: 0,
43
+ accessHash: bigInt(1),
44
+ megagroup: true,
45
+ });
46
+ const invocations = [];
47
+ const service = makeService(megagroup, invocations);
48
+ await service.toggleAntiSpam("22222", false);
49
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleAntiSpam);
50
+ assert.ok(call);
51
+ assert.strictEqual(call.enabled, false);
52
+ });
53
+ it("rejects broadcast channels (not megagroup)", async () => {
54
+ const broadcast = new Api.Channel({
55
+ id: bigInt(33333),
56
+ title: "broadcast",
57
+ photo: new Api.ChatPhotoEmpty(),
58
+ date: 0,
59
+ accessHash: bigInt(1),
60
+ broadcast: true,
61
+ });
62
+ const invocations = [];
63
+ const service = makeService(broadcast, invocations);
64
+ await assert.rejects(service.toggleAntiSpam("33333", true), /supergroups, not broadcast channels/);
65
+ assert.strictEqual(invocations.find((r) => r instanceof Api.channels.ToggleAntiSpam), undefined, "no API call on invalid target");
66
+ });
67
+ it("rejects non-channel entities (basic group)", async () => {
68
+ const chat = new Api.Chat({
69
+ id: bigInt(44444),
70
+ title: "basic group",
71
+ photo: new Api.ChatPhotoEmpty(),
72
+ participantsCount: 5,
73
+ date: 0,
74
+ version: 0,
75
+ });
76
+ const invocations = [];
77
+ const service = makeService(chat, invocations);
78
+ await assert.rejects(service.toggleAntiSpam("44444", true), /supergroups/);
79
+ });
80
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import bigInt from "big-integer";
4
+ import { Api } from "telegram/tl/index.js";
5
+ import { TelegramService } from "../telegram-client.js";
6
+ function makeService(entity, invocations) {
7
+ const fakeClient = {
8
+ invoke: async (req) => {
9
+ invocations.push(req);
10
+ return undefined;
11
+ },
12
+ };
13
+ const service = new TelegramService(1, "hash");
14
+ const internals = service;
15
+ internals.client = fakeClient;
16
+ internals.connected = true;
17
+ internals.resolveChat = async () => entity;
18
+ return service;
19
+ }
20
+ describe("TelegramService.toggleChannelSignatures", () => {
21
+ it("invokes channels.ToggleSignatures with signaturesEnabled=true for broadcast channel", async () => {
22
+ const channel = new Api.Channel({
23
+ id: bigInt(12345),
24
+ title: "broadcast",
25
+ photo: new Api.ChatPhotoEmpty(),
26
+ date: 0,
27
+ accessHash: bigInt(1),
28
+ broadcast: true,
29
+ });
30
+ const invocations = [];
31
+ const service = makeService(channel, invocations);
32
+ await service.toggleChannelSignatures("12345", true);
33
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleSignatures);
34
+ assert.ok(call, "ToggleSignatures was invoked");
35
+ assert.strictEqual(call.signaturesEnabled, true);
36
+ });
37
+ it("invokes channels.ToggleSignatures with signaturesEnabled=false", async () => {
38
+ const channel = new Api.Channel({
39
+ id: bigInt(22222),
40
+ title: "broadcast",
41
+ photo: new Api.ChatPhotoEmpty(),
42
+ date: 0,
43
+ accessHash: bigInt(1),
44
+ broadcast: true,
45
+ });
46
+ const invocations = [];
47
+ const service = makeService(channel, invocations);
48
+ await service.toggleChannelSignatures("22222", false);
49
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleSignatures);
50
+ assert.ok(call);
51
+ assert.strictEqual(call.signaturesEnabled, false);
52
+ });
53
+ it("rejects supergroups (megagroup)", async () => {
54
+ const megagroup = new Api.Channel({
55
+ id: bigInt(33333),
56
+ title: "supergroup",
57
+ photo: new Api.ChatPhotoEmpty(),
58
+ date: 0,
59
+ accessHash: bigInt(1),
60
+ megagroup: true,
61
+ });
62
+ const invocations = [];
63
+ const service = makeService(megagroup, invocations);
64
+ await assert.rejects(service.toggleChannelSignatures("33333", true), /broadcast channels/);
65
+ assert.strictEqual(invocations.find((r) => r instanceof Api.channels.ToggleSignatures), undefined, "no API call on invalid target");
66
+ });
67
+ it("rejects non-channel entities", async () => {
68
+ const chat = new Api.Chat({
69
+ id: bigInt(44444),
70
+ title: "small group",
71
+ photo: new Api.ChatPhotoEmpty(),
72
+ participantsCount: 5,
73
+ date: 0,
74
+ version: 0,
75
+ });
76
+ const invocations = [];
77
+ const service = makeService(chat, invocations);
78
+ await assert.rejects(service.toggleChannelSignatures("44444", true), /broadcast channels/);
79
+ });
80
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import bigInt from "big-integer";
4
+ import { Api } from "telegram/tl/index.js";
5
+ import { TelegramService } from "../telegram-client.js";
6
+ function makeService(entity, invocations) {
7
+ const fakeClient = {
8
+ invoke: async (req) => {
9
+ invocations.push(req);
10
+ return undefined;
11
+ },
12
+ };
13
+ const service = new TelegramService(1, "hash");
14
+ const internals = service;
15
+ internals.client = fakeClient;
16
+ internals.connected = true;
17
+ internals.resolveChat = async () => entity;
18
+ return service;
19
+ }
20
+ describe("TelegramService.toggleForumMode", () => {
21
+ it("invokes channels.ToggleForum with enabled=true for supergroup", async () => {
22
+ const megagroup = new Api.Channel({
23
+ id: bigInt(12345),
24
+ title: "supergroup",
25
+ photo: new Api.ChatPhotoEmpty(),
26
+ date: 0,
27
+ accessHash: bigInt(1),
28
+ megagroup: true,
29
+ });
30
+ const invocations = [];
31
+ const service = makeService(megagroup, invocations);
32
+ await service.toggleForumMode("12345", true);
33
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleForum);
34
+ assert.ok(call, "ToggleForum was invoked");
35
+ assert.strictEqual(call.enabled, true);
36
+ });
37
+ it("invokes channels.ToggleForum with enabled=false", async () => {
38
+ const megagroup = new Api.Channel({
39
+ id: bigInt(22222),
40
+ title: "supergroup",
41
+ photo: new Api.ChatPhotoEmpty(),
42
+ date: 0,
43
+ accessHash: bigInt(1),
44
+ megagroup: true,
45
+ });
46
+ const invocations = [];
47
+ const service = makeService(megagroup, invocations);
48
+ await service.toggleForumMode("22222", false);
49
+ const call = invocations.find((r) => r instanceof Api.channels.ToggleForum);
50
+ assert.ok(call);
51
+ assert.strictEqual(call.enabled, false);
52
+ });
53
+ it("rejects broadcast channels (not megagroup)", async () => {
54
+ const broadcast = new Api.Channel({
55
+ id: bigInt(33333),
56
+ title: "broadcast",
57
+ photo: new Api.ChatPhotoEmpty(),
58
+ date: 0,
59
+ accessHash: bigInt(1),
60
+ broadcast: true,
61
+ });
62
+ const invocations = [];
63
+ const service = makeService(broadcast, invocations);
64
+ await assert.rejects(service.toggleForumMode("33333", true), /supergroups, not broadcast channels/);
65
+ assert.strictEqual(invocations.find((r) => r instanceof Api.channels.ToggleForum), undefined, "no API call on invalid target");
66
+ });
67
+ it("rejects non-channel entities (basic group)", async () => {
68
+ const chat = new Api.Chat({
69
+ id: bigInt(44444),
70
+ title: "basic group",
71
+ photo: new Api.ChatPhotoEmpty(),
72
+ participantsCount: 5,
73
+ date: 0,
74
+ version: 0,
75
+ });
76
+ const invocations = [];
77
+ const service = makeService(chat, invocations);
78
+ await assert.rejects(service.toggleForumMode("44444", true), /supergroups/);
79
+ });
80
+ });
@@ -0,0 +1 @@
1
+ export {};