@fragno-dev/telegram-fragment 0.0.1

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 (60) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +87 -0
  3. package/dist/browser/client/react.d.ts +226 -0
  4. package/dist/browser/client/react.d.ts.map +1 -0
  5. package/dist/browser/client/react.js +166 -0
  6. package/dist/browser/client/react.js.map +1 -0
  7. package/dist/browser/client/solid.d.ts +228 -0
  8. package/dist/browser/client/solid.d.ts.map +1 -0
  9. package/dist/browser/client/solid.js +136 -0
  10. package/dist/browser/client/solid.js.map +1 -0
  11. package/dist/browser/client/svelte.d.ts +223 -0
  12. package/dist/browser/client/svelte.d.ts.map +1 -0
  13. package/dist/browser/client/svelte.js +134 -0
  14. package/dist/browser/client/svelte.js.map +1 -0
  15. package/dist/browser/client/vanilla.d.ts +252 -0
  16. package/dist/browser/client/vanilla.d.ts.map +1 -0
  17. package/dist/browser/client/vanilla.js +160 -0
  18. package/dist/browser/client/vanilla.js.map +1 -0
  19. package/dist/browser/client/vue.d.ts +226 -0
  20. package/dist/browser/client/vue.d.ts.map +1 -0
  21. package/dist/browser/client/vue.js +133 -0
  22. package/dist/browser/client/vue.js.map +1 -0
  23. package/dist/browser/client-Bk-J98pf.d.ts +679 -0
  24. package/dist/browser/client-Bk-J98pf.d.ts.map +1 -0
  25. package/dist/browser/index.d.ts +1392 -0
  26. package/dist/browser/index.d.ts.map +1 -0
  27. package/dist/browser/index.js +24 -0
  28. package/dist/browser/index.js.map +1 -0
  29. package/dist/browser/schema-QDMf15Vn.js +2343 -0
  30. package/dist/browser/schema-QDMf15Vn.js.map +1 -0
  31. package/dist/node/command-handler-api.js +42 -0
  32. package/dist/node/command-handler-api.js.map +1 -0
  33. package/dist/node/definition.d.ts +194 -0
  34. package/dist/node/definition.d.ts.map +1 -0
  35. package/dist/node/definition.js +90 -0
  36. package/dist/node/definition.js.map +1 -0
  37. package/dist/node/index.d.ts +587 -0
  38. package/dist/node/index.d.ts.map +1 -0
  39. package/dist/node/index.js +29 -0
  40. package/dist/node/index.js.map +1 -0
  41. package/dist/node/routes.d.ts +385 -0
  42. package/dist/node/routes.d.ts.map +1 -0
  43. package/dist/node/routes.js +392 -0
  44. package/dist/node/routes.js.map +1 -0
  45. package/dist/node/schema.d.ts +13 -0
  46. package/dist/node/schema.d.ts.map +1 -0
  47. package/dist/node/schema.js +78 -0
  48. package/dist/node/schema.js.map +1 -0
  49. package/dist/node/services.js +589 -0
  50. package/dist/node/services.js.map +1 -0
  51. package/dist/node/telegram-api.js +41 -0
  52. package/dist/node/telegram-api.js.map +1 -0
  53. package/dist/node/telegram-utils.js +61 -0
  54. package/dist/node/telegram-utils.js.map +1 -0
  55. package/dist/node/types.d.ts +245 -0
  56. package/dist/node/types.d.ts.map +1 -0
  57. package/dist/node/types.js +92 -0
  58. package/dist/node/types.js.map +1 -0
  59. package/dist/tsconfig.tsbuildinfo +1 -0
  60. package/package.json +96 -0
@@ -0,0 +1,589 @@
1
+ import { telegramSchema } from "./schema.js";
2
+ import { telegramMessageSchema } from "./types.js";
3
+ import { DEFAULT_COMMAND_SCOPES, buildChatMemberId, buildMessageId, parseCommand, parseCommandBindings, parseTelegramUpdate } from "./telegram-utils.js";
4
+ import "@fragno-dev/db";
5
+ import "@fragno-dev/db/schema";
6
+
7
+ //#region src/services.ts
8
+ const missingId = "__missing__";
9
+ const parseCompositeId = (value) => {
10
+ const raw = String(value.valueOf());
11
+ const [first, second] = raw.split(":");
12
+ return {
13
+ first: first ?? raw,
14
+ second: second ?? null
15
+ };
16
+ };
17
+ const parseChatMemberCompositeId = (value) => {
18
+ const { first, second } = parseCompositeId(value);
19
+ return {
20
+ chatId: first,
21
+ userId: second ?? ""
22
+ };
23
+ };
24
+ const parseMessageCompositeId = (value) => {
25
+ const { first, second } = parseCompositeId(value);
26
+ return {
27
+ chatId: first,
28
+ messageId: second ?? ""
29
+ };
30
+ };
31
+ const parseTelegramMessagePayload = (payload) => {
32
+ const result = telegramMessageSchema.safeParse(payload);
33
+ return result.success ? result.data : null;
34
+ };
35
+ const toUserSummary = (user) => ({
36
+ id: String(user.id.valueOf()),
37
+ username: user.username,
38
+ firstName: user.firstName,
39
+ lastName: user.lastName,
40
+ isBot: user.isBot,
41
+ languageCode: user.languageCode,
42
+ createdAt: user.createdAt,
43
+ updatedAt: user.updatedAt
44
+ });
45
+ const toChatSummary = (chat) => ({
46
+ id: String(chat.id.valueOf()),
47
+ type: chat.type,
48
+ title: chat.title,
49
+ username: chat.username,
50
+ isForum: chat.isForum,
51
+ commandBindings: chat.commandBindings ? parseCommandBindings(chat.commandBindings) : null,
52
+ createdAt: chat.createdAt,
53
+ updatedAt: chat.updatedAt
54
+ });
55
+ const toChatMemberSummary = (member) => {
56
+ const composite = parseChatMemberCompositeId(member.id);
57
+ const userId = member.chatMemberUser ? String(member.chatMemberUser.id.valueOf()) : composite.userId;
58
+ return {
59
+ id: String(member.id.valueOf()),
60
+ chatId: composite.chatId,
61
+ userId,
62
+ status: member.status,
63
+ joinedAt: member.joinedAt,
64
+ leftAt: member.leftAt,
65
+ user: member.chatMemberUser ? toUserSummary(member.chatMemberUser) : null,
66
+ createdAt: member.createdAt,
67
+ updatedAt: member.updatedAt
68
+ };
69
+ };
70
+ const toMessageSummary = (message) => {
71
+ const composite = parseMessageCompositeId(message.id);
72
+ const payload = parseTelegramMessagePayload(message.payload);
73
+ const chatId = payload?.chat ? String(payload.chat.id) : composite.chatId;
74
+ const fromUserId = payload?.from ? String(payload.from.id) : message.messageAuthor ? String(message.messageAuthor.id.valueOf()) : null;
75
+ const senderChatId = payload?.sender_chat ? String(payload.sender_chat.id) : null;
76
+ const replyToMessageId = payload?.reply_to_message ? buildMessageId(chatId, payload.reply_to_message.message_id) : null;
77
+ return {
78
+ id: String(message.id.valueOf()),
79
+ chatId,
80
+ fromUserId,
81
+ senderChatId,
82
+ replyToMessageId,
83
+ messageType: message.messageType,
84
+ text: message.text,
85
+ payload: message.payload,
86
+ sentAt: message.sentAt,
87
+ editedAt: message.editedAt,
88
+ commandName: message.commandName,
89
+ fromUser: message.messageAuthor ? toUserSummary(message.messageAuthor) : null
90
+ };
91
+ };
92
+ const createProcessIncomingUpdateOps = (config) => {
93
+ const commands = config.commands ?? {};
94
+ const botUsername = config.botUsername;
95
+ const resolveCommandScopes = (commandName, chatType, bindings) => {
96
+ const definition = commands[commandName];
97
+ if (!definition) return null;
98
+ const binding = bindings[commandName];
99
+ const enabled = binding ? binding.enabled !== false : true;
100
+ const scopes = binding?.scopes ?? definition.scopes ?? DEFAULT_COMMAND_SCOPES;
101
+ if (!enabled || !scopes.includes(chatType)) return null;
102
+ return { scopes };
103
+ };
104
+ return (update) => {
105
+ const parsed = parseTelegramUpdate(update);
106
+ if (!parsed) return {
107
+ kind: "ignored",
108
+ updateId: update.update_id
109
+ };
110
+ const { message, type, updateId } = parsed;
111
+ const chatId = String(message.chat.id);
112
+ const messageId = buildMessageId(chatId, message.message_id);
113
+ const sentAt = /* @__PURE__ */ new Date(message.date * 1e3);
114
+ const editedAt = message.edit_date ? /* @__PURE__ */ new Date(message.edit_date * 1e3) : null;
115
+ const fromUser = message.from ?? null;
116
+ const fromUserId = fromUser ? String(fromUser.id) : null;
117
+ const senderChat = message.sender_chat ?? null;
118
+ const senderChatId = senderChat ? String(senderChat.id) : null;
119
+ const replyToMessageId = message.reply_to_message ? buildMessageId(chatId, message.reply_to_message.message_id) : null;
120
+ const commandMatch = parseCommand(message, botUsername);
121
+ const commandName = commandMatch?.name ?? null;
122
+ const membershipMap = /* @__PURE__ */ new Map();
123
+ const newMembers = message.new_chat_members ?? [];
124
+ for (const member of newMembers) membershipMap.set(String(member.id), {
125
+ status: "member",
126
+ joinedAt: sentAt,
127
+ leftAt: null,
128
+ notify: true
129
+ });
130
+ if (message.left_chat_member) membershipMap.set(String(message.left_chat_member.id), {
131
+ status: "left",
132
+ joinedAt: null,
133
+ leftAt: sentAt,
134
+ notify: true
135
+ });
136
+ if (fromUserId && message.chat.type !== "channel" && !membershipMap.has(fromUserId)) membershipMap.set(fromUserId, {
137
+ status: "member",
138
+ joinedAt: sentAt,
139
+ leftAt: null,
140
+ notify: false
141
+ });
142
+ const chatIds = Array.from(new Set([chatId, senderChatId ? String(senderChatId) : null].filter(Boolean)));
143
+ const userIds = Array.from(new Set([
144
+ fromUserId,
145
+ ...newMembers.map((member) => String(member.id)),
146
+ message.left_chat_member ? String(message.left_chat_member.id) : null
147
+ ].filter(Boolean)));
148
+ const memberIds = Array.from(new Set(Array.from(membershipMap.keys()).map((userId) => buildChatMemberId(chatId, userId))));
149
+ const chatsForUpsert = [];
150
+ const seenChatIds = /* @__PURE__ */ new Set();
151
+ for (const chat of [message.chat, senderChat]) {
152
+ if (!chat) continue;
153
+ const id = String(chat.id);
154
+ if (seenChatIds.has(id)) continue;
155
+ seenChatIds.add(id);
156
+ chatsForUpsert.push(chat);
157
+ }
158
+ const usersForUpsert = [];
159
+ const seenUserIds = /* @__PURE__ */ new Set();
160
+ for (const user of [
161
+ fromUser,
162
+ ...newMembers,
163
+ message.left_chat_member
164
+ ]) {
165
+ if (!user) continue;
166
+ const id = String(user.id);
167
+ if (seenUserIds.has(id)) continue;
168
+ seenUserIds.add(id);
169
+ usersForUpsert.push(user);
170
+ }
171
+ return {
172
+ kind: "message",
173
+ updateId,
174
+ retrieve: (uow) => uow.find("chat", (b) => b.whereIndex("primary", (eb) => eb("id", "in", chatIds.length ? chatIds : [missingId]))).find("user", (b) => b.whereIndex("primary", (eb) => eb("id", "in", userIds.length ? userIds : [missingId]))).find("chatMember", (b) => b.whereIndex("primary", (eb) => eb("id", "in", memberIds.length ? memberIds : [missingId]))).findFirst("message", (b) => b.whereIndex("primary", (eb) => eb("id", "=", messageId))),
175
+ mutate: ({ uow, retrieveResult: [existingChats, existingUsers, existingMembers, existingMessage] }) => {
176
+ const now = /* @__PURE__ */ new Date();
177
+ const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat]));
178
+ const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user]));
179
+ const memberById = new Map(existingMembers.map((member) => [member.id.valueOf(), member]));
180
+ const chatSummaries = /* @__PURE__ */ new Map();
181
+ for (const chat of chatsForUpsert) {
182
+ const id = String(chat.id);
183
+ const existing = chatById.get(id);
184
+ if (!existing) {
185
+ uow.create("chat", {
186
+ id,
187
+ type: chat.type,
188
+ title: chat.title ?? null,
189
+ username: chat.username ?? null,
190
+ isForum: chat.is_forum ?? false,
191
+ commandBindings: null,
192
+ createdAt: now,
193
+ updatedAt: now
194
+ });
195
+ chatSummaries.set(id, {
196
+ id,
197
+ type: chat.type,
198
+ title: chat.title ?? null,
199
+ username: chat.username ?? null,
200
+ isForum: chat.is_forum ?? false,
201
+ commandBindings: null,
202
+ createdAt: now,
203
+ updatedAt: now
204
+ });
205
+ } else {
206
+ uow.update("chat", existing.id, (b) => b.set({
207
+ type: chat.type,
208
+ title: chat.title ?? null,
209
+ username: chat.username ?? null,
210
+ isForum: chat.is_forum ?? false,
211
+ updatedAt: now
212
+ }).check());
213
+ chatSummaries.set(id, {
214
+ ...toChatSummary(existing),
215
+ type: chat.type,
216
+ title: chat.title ?? null,
217
+ username: chat.username ?? null,
218
+ isForum: chat.is_forum ?? false,
219
+ updatedAt: now
220
+ });
221
+ }
222
+ }
223
+ const userSummaries = /* @__PURE__ */ new Map();
224
+ for (const user of usersForUpsert) {
225
+ const id = String(user.id);
226
+ const existing = userById.get(id);
227
+ if (!existing) {
228
+ uow.create("user", {
229
+ id,
230
+ username: user.username ?? null,
231
+ firstName: user.first_name,
232
+ lastName: user.last_name ?? null,
233
+ isBot: user.is_bot ?? false,
234
+ languageCode: user.language_code ?? null,
235
+ createdAt: now,
236
+ updatedAt: now
237
+ });
238
+ userSummaries.set(id, {
239
+ id,
240
+ username: user.username ?? null,
241
+ firstName: user.first_name,
242
+ lastName: user.last_name ?? null,
243
+ isBot: user.is_bot ?? false,
244
+ languageCode: user.language_code ?? null,
245
+ createdAt: now,
246
+ updatedAt: now
247
+ });
248
+ } else {
249
+ uow.update("user", existing.id, (b) => b.set({
250
+ username: user.username ?? null,
251
+ firstName: user.first_name,
252
+ lastName: user.last_name ?? null,
253
+ isBot: user.is_bot ?? false,
254
+ languageCode: user.language_code ?? null,
255
+ updatedAt: now
256
+ }).check());
257
+ userSummaries.set(id, {
258
+ ...toUserSummary(existing),
259
+ username: user.username ?? null,
260
+ firstName: user.first_name,
261
+ lastName: user.last_name ?? null,
262
+ isBot: user.is_bot ?? false,
263
+ languageCode: user.language_code ?? null,
264
+ updatedAt: now
265
+ });
266
+ }
267
+ }
268
+ const memberPayloads = [];
269
+ for (const [userId, membership] of membershipMap.entries()) {
270
+ const memberId = buildChatMemberId(chatId, userId);
271
+ const existing = memberById.get(memberId);
272
+ if (!existing) {
273
+ uow.create("chatMember", {
274
+ id: memberId,
275
+ chatId,
276
+ userId,
277
+ status: membership.status,
278
+ joinedAt: membership.joinedAt,
279
+ leftAt: membership.leftAt,
280
+ createdAt: now,
281
+ updatedAt: now
282
+ });
283
+ if (membership.notify) memberPayloads.push({
284
+ updateId,
285
+ chatId,
286
+ userId,
287
+ status: membership.status,
288
+ joinedAt: membership.joinedAt,
289
+ leftAt: membership.leftAt
290
+ });
291
+ continue;
292
+ }
293
+ const nextJoinedAt = membership.status === "member" && membership.joinedAt !== null && membership.notify ? membership.joinedAt : existing.joinedAt;
294
+ const nextLeftAt = membership.status === "left" ? membership.leftAt ?? existing.leftAt ?? now : membership.status === "member" ? null : existing.leftAt;
295
+ if (existing.status !== membership.status || existing.joinedAt?.getTime() !== nextJoinedAt?.getTime() || existing.leftAt?.getTime() !== nextLeftAt?.getTime()) {
296
+ uow.update("chatMember", existing.id, (b) => b.set({
297
+ status: membership.status,
298
+ joinedAt: nextJoinedAt,
299
+ leftAt: nextLeftAt,
300
+ updatedAt: now
301
+ }).check());
302
+ if (membership.notify) memberPayloads.push({
303
+ updateId,
304
+ chatId,
305
+ userId,
306
+ status: membership.status,
307
+ joinedAt: nextJoinedAt,
308
+ leftAt: nextLeftAt
309
+ });
310
+ }
311
+ }
312
+ let shouldTriggerMessage = false;
313
+ let messageSummary;
314
+ if (!existingMessage) {
315
+ uow.create("message", {
316
+ id: messageId,
317
+ chatId,
318
+ fromUserId,
319
+ senderChatId,
320
+ replyToMessageId,
321
+ messageType: type,
322
+ text: message.text ?? null,
323
+ payload: message,
324
+ sentAt,
325
+ editedAt,
326
+ commandName
327
+ });
328
+ shouldTriggerMessage = true;
329
+ messageSummary = {
330
+ id: messageId,
331
+ chatId,
332
+ fromUserId,
333
+ senderChatId,
334
+ replyToMessageId,
335
+ messageType: type,
336
+ text: message.text ?? null,
337
+ payload: message,
338
+ sentAt,
339
+ editedAt,
340
+ commandName,
341
+ fromUser: fromUserId ? userSummaries.get(fromUserId) ?? null : null
342
+ };
343
+ } else {
344
+ const isEdit = type === "edited_message";
345
+ const duplicateEdit = isEdit && existingMessage.editedAt?.getTime() === editedAt?.getTime() && existingMessage.text === (message.text ?? null);
346
+ if (isEdit && !duplicateEdit) {
347
+ uow.update("message", existingMessage.id, (b) => b.set({
348
+ messageType: type,
349
+ text: message.text ?? null,
350
+ payload: message,
351
+ editedAt,
352
+ commandName
353
+ }).check());
354
+ shouldTriggerMessage = true;
355
+ }
356
+ messageSummary = {
357
+ id: String(existingMessage.id.valueOf()),
358
+ chatId: String(existingMessage.chatId.valueOf()),
359
+ fromUserId: existingMessage.fromUserId ? String(existingMessage.fromUserId.valueOf()) : null,
360
+ senderChatId: existingMessage.senderChatId ? String(existingMessage.senderChatId.valueOf()) : null,
361
+ replyToMessageId: existingMessage.replyToMessageId ? String(existingMessage.replyToMessageId.valueOf()) : null,
362
+ messageType: type,
363
+ text: message.text ?? existingMessage.text,
364
+ payload: message,
365
+ sentAt: existingMessage.sentAt,
366
+ editedAt: editedAt ?? existingMessage.editedAt,
367
+ commandName,
368
+ fromUser: fromUserId ? userSummaries.get(fromUserId) ?? null : null
369
+ };
370
+ }
371
+ const chatSummary = chatSummaries.get(chatId) ?? (chatById.get(chatId) ? toChatSummary(chatById.get(chatId)) : {
372
+ id: chatId,
373
+ type: message.chat.type,
374
+ title: message.chat.title ?? null,
375
+ username: message.chat.username ?? null,
376
+ isForum: message.chat.is_forum ?? false,
377
+ commandBindings: null,
378
+ createdAt: now,
379
+ updatedAt: now
380
+ });
381
+ const commandBindings = chatSummary.commandBindings ?? {};
382
+ let commandResult = null;
383
+ if (commandMatch && type !== "edited_message") {
384
+ const resolved = resolveCommandScopes(commandMatch.name, chatSummary.type, commandBindings);
385
+ if (resolved) {
386
+ commandResult = {
387
+ name: commandMatch.name,
388
+ args: commandMatch.args,
389
+ raw: commandMatch.raw,
390
+ scopes: resolved.scopes
391
+ };
392
+ if (shouldTriggerMessage) uow.triggerHook("onCommandMatched", {
393
+ updateId,
394
+ messageId: messageSummary.id,
395
+ chatId,
396
+ fromUserId,
397
+ commandName: commandMatch.name,
398
+ args: commandMatch.args,
399
+ raw: commandMatch.raw,
400
+ sentAt
401
+ });
402
+ }
403
+ }
404
+ if (shouldTriggerMessage) {
405
+ const payload = {
406
+ updateId,
407
+ updateType: type,
408
+ messageId: messageSummary.id,
409
+ chatId,
410
+ fromUserId,
411
+ text: message.text ?? null,
412
+ commandName,
413
+ sentAt: messageSummary.sentAt,
414
+ editedAt: messageSummary.editedAt
415
+ };
416
+ uow.triggerHook("onMessageReceived", payload);
417
+ }
418
+ for (const payload of memberPayloads) uow.triggerHook("onChatMemberUpdated", payload);
419
+ return {
420
+ kind: "message",
421
+ updateId,
422
+ updateType: type,
423
+ chat: chatSummary,
424
+ message: messageSummary,
425
+ fromUser: fromUserId ? userSummaries.get(fromUserId) ?? null : null,
426
+ command: commandResult
427
+ };
428
+ }
429
+ };
430
+ };
431
+ };
432
+ const createUpsertOutgoingMessageOps = (input) => {
433
+ const { message, messageType } = input;
434
+ const chatId = String(message.chat.id);
435
+ const senderChatId = message.sender_chat ? String(message.sender_chat.id) : null;
436
+ const fromUser = message.from ?? null;
437
+ const fromUserId = fromUser ? String(fromUser.id) : null;
438
+ const messageId = buildMessageId(chatId, message.message_id);
439
+ const replyToMessageId = message.reply_to_message ? buildMessageId(chatId, message.reply_to_message.message_id) : null;
440
+ const sentAt = /* @__PURE__ */ new Date(message.date * 1e3);
441
+ const editedAt = message.edit_date ? /* @__PURE__ */ new Date(message.edit_date * 1e3) : null;
442
+ const chatIds = Array.from(new Set([chatId, senderChatId].filter(Boolean)));
443
+ return {
444
+ retrieve: (uow) => uow.find("chat", (b) => b.whereIndex("primary", (eb) => eb("id", "in", chatIds.length ? chatIds : [missingId]))).find("user", (b) => b.whereIndex("primary", (eb) => eb("id", "in", fromUserId ? [fromUserId] : [missingId]))).findFirst("message", (b) => b.whereIndex("primary", (eb) => eb("id", "=", messageId))),
445
+ mutate: ({ uow, retrieveResult: [existingChats, existingUsers, existingMessage] }) => {
446
+ const now = /* @__PURE__ */ new Date();
447
+ const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat]));
448
+ const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user]));
449
+ const chatsForUpsert = [message.chat, message.sender_chat].filter(Boolean);
450
+ for (const chat of chatsForUpsert) {
451
+ const id = String(chat.id);
452
+ const existing = chatById.get(id);
453
+ if (!existing) uow.create("chat", {
454
+ id,
455
+ type: chat.type,
456
+ title: chat.title ?? null,
457
+ username: chat.username ?? null,
458
+ isForum: chat.is_forum ?? false,
459
+ commandBindings: null,
460
+ createdAt: now,
461
+ updatedAt: now
462
+ });
463
+ else uow.update("chat", existing.id, (b) => b.set({
464
+ type: chat.type,
465
+ title: chat.title ?? null,
466
+ username: chat.username ?? null,
467
+ isForum: chat.is_forum ?? false,
468
+ updatedAt: now
469
+ }).check());
470
+ }
471
+ if (fromUser) {
472
+ const id = String(fromUser.id);
473
+ const existing = userById.get(id);
474
+ if (!existing) uow.create("user", {
475
+ id,
476
+ username: fromUser.username ?? null,
477
+ firstName: fromUser.first_name,
478
+ lastName: fromUser.last_name ?? null,
479
+ isBot: fromUser.is_bot ?? false,
480
+ languageCode: fromUser.language_code ?? null,
481
+ createdAt: now,
482
+ updatedAt: now
483
+ });
484
+ else uow.update("user", existing.id, (b) => b.set({
485
+ username: fromUser.username ?? null,
486
+ firstName: fromUser.first_name,
487
+ lastName: fromUser.last_name ?? null,
488
+ isBot: fromUser.is_bot ?? false,
489
+ languageCode: fromUser.language_code ?? null,
490
+ updatedAt: now
491
+ }).check());
492
+ }
493
+ const messagePayload = {
494
+ chatId,
495
+ fromUserId,
496
+ senderChatId,
497
+ replyToMessageId,
498
+ messageType,
499
+ text: message.text ?? null,
500
+ payload: message,
501
+ sentAt,
502
+ editedAt,
503
+ commandName: null
504
+ };
505
+ if (!existingMessage) uow.create("message", {
506
+ id: messageId,
507
+ ...messagePayload
508
+ });
509
+ else uow.update("message", existingMessage.id, (b) => b.set(messagePayload).check());
510
+ }
511
+ };
512
+ };
513
+ const createTelegramServices = (config) => {
514
+ const buildProcessIncomingUpdateOps = createProcessIncomingUpdateOps(config);
515
+ return {
516
+ processIncomingUpdate: function(update) {
517
+ const ops = buildProcessIncomingUpdateOps(update);
518
+ if (ops.kind === "ignored") return this.serviceTx(telegramSchema).mutate(() => ops).build();
519
+ return this.serviceTx(telegramSchema).retrieve(ops.retrieve).mutate(({ uow, retrieveResult }) => ops.mutate({
520
+ uow,
521
+ retrieveResult
522
+ })).build();
523
+ },
524
+ bindCommand: function(input) {
525
+ return this.serviceTx(telegramSchema).retrieve((uow) => uow.findFirst("chat", (b) => b.whereIndex("primary", (eb) => eb("id", "=", input.chatId)))).mutate(({ uow, retrieveResult: [chat] }) => {
526
+ if (!chat) return {
527
+ ok: false,
528
+ reason: "chat_not_found"
529
+ };
530
+ const nextBindings = {
531
+ ...parseCommandBindings(chat.commandBindings),
532
+ [input.commandName]: {
533
+ enabled: input.enabled,
534
+ scopes: input.scopes
535
+ }
536
+ };
537
+ uow.update("chat", chat.id, (b) => b.set({
538
+ commandBindings: nextBindings,
539
+ updatedAt: /* @__PURE__ */ new Date()
540
+ }).check());
541
+ return {
542
+ ok: true,
543
+ binding: {
544
+ chatId: input.chatId,
545
+ commandName: input.commandName,
546
+ enabled: input.enabled,
547
+ scopes: input.scopes
548
+ }
549
+ };
550
+ }).build();
551
+ },
552
+ listChats: function(type) {
553
+ return this.serviceTx(telegramSchema).retrieve((uow) => {
554
+ if (type) return uow.find("chat", (b) => b.whereIndex("idx_chat_type", (eb) => eb("type", "=", type)));
555
+ return uow.find("chat", (b) => b.whereIndex("primary"));
556
+ }).transformRetrieve(([chats]) => chats.map(toChatSummary)).build();
557
+ },
558
+ getChat: function(chatId) {
559
+ return this.serviceTx(telegramSchema).retrieve((uow) => uow.findFirst("chat", (b) => b.whereIndex("primary", (eb) => eb("id", "=", chatId)))).transformRetrieve(([chat]) => chat ? toChatSummary(chat) : null).build();
560
+ },
561
+ getChatWithMembers: function(chatId) {
562
+ return this.serviceTx(telegramSchema).retrieve((uow) => uow.findFirst("chat", (b) => b.whereIndex("primary", (eb) => eb("id", "=", chatId))).find("chatMember", (b) => b.whereIndex("idx_chat_member_chat", (eb) => eb("chatId", "=", chatId)).join((j) => j.chatMemberUser()))).transformRetrieve(([chat, members]) => ({
563
+ chat: chat ? toChatSummary(chat) : null,
564
+ members: members.map(toChatMemberSummary)
565
+ })).build();
566
+ },
567
+ listMessages: function(input) {
568
+ return this.serviceTx(telegramSchema).retrieve((uow) => uow.findWithCursor("message", (b) => {
569
+ const query = b.whereIndex("idx_message_chat_sent", (eb) => eb("chatId", "=", input.chatId)).orderByIndex("idx_message_chat_sent", input.order).pageSize(input.pageSize).join((j) => j.messageAuthor());
570
+ return input.cursor ? query.after(input.cursor) : query;
571
+ })).transformRetrieve(([messages]) => ({
572
+ messages: messages.items.map(toMessageSummary),
573
+ cursor: messages.cursor,
574
+ hasNextPage: messages.hasNextPage
575
+ })).build();
576
+ },
577
+ upsertOutgoingMessage: function(input) {
578
+ const ops = createUpsertOutgoingMessageOps(input);
579
+ return this.serviceTx(telegramSchema).retrieve(ops.retrieve).mutate(({ uow, retrieveResult }) => ops.mutate({
580
+ uow,
581
+ retrieveResult
582
+ })).build();
583
+ }
584
+ };
585
+ };
586
+
587
+ //#endregion
588
+ export { createProcessIncomingUpdateOps, createTelegramServices, createUpsertOutgoingMessageOps };
589
+ //# sourceMappingURL=services.js.map