@fragno-dev/telegram-fragment 0.0.1 → 0.0.3
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/dist/browser/client/react.d.ts +129 -3
- package/dist/browser/client/react.d.ts.map +1 -1
- package/dist/browser/client/react.js +32 -22
- package/dist/browser/client/react.js.map +1 -1
- package/dist/browser/client/solid.d.ts +129 -3
- package/dist/browser/client/solid.d.ts.map +1 -1
- package/dist/browser/client/solid.js +2 -2
- package/dist/browser/client/solid.js.map +1 -1
- package/dist/browser/client/svelte.d.ts +129 -3
- package/dist/browser/client/svelte.d.ts.map +1 -1
- package/dist/browser/client/svelte.js +1 -1
- package/dist/browser/client/vanilla.d.ts +129 -3
- package/dist/browser/client/vanilla.d.ts.map +1 -1
- package/dist/browser/client/vanilla.js +1 -1
- package/dist/browser/client/vue.d.ts +129 -3
- package/dist/browser/client/vue.d.ts.map +1 -1
- package/dist/browser/client/vue.js +1 -1
- package/dist/browser/{client-Bk-J98pf.d.ts → client-BumUy6cu.d.ts} +87 -83
- package/dist/browser/client-BumUy6cu.d.ts.map +1 -0
- package/dist/browser/index.d.ts +697 -48
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/{schema-QDMf15Vn.js → schema-IrJsGm4M.js} +264 -41
- package/dist/browser/schema-IrJsGm4M.js.map +1 -0
- package/dist/node/definition.d.ts.map +1 -1
- package/dist/node/index.d.ts +260 -13
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2 -2
- package/dist/node/index.js.map +1 -1
- package/dist/node/routes.d.ts +130 -9
- package/dist/node/routes.d.ts.map +1 -1
- package/dist/node/routes.js +25 -15
- package/dist/node/routes.js.map +1 -1
- package/dist/node/services.js +56 -53
- package/dist/node/services.js.map +1 -1
- package/dist/node/telegram-api.js +80 -16
- package/dist/node/telegram-api.js.map +1 -1
- package/dist/node/telegram-utils.js +284 -9
- package/dist/node/telegram-utils.js.map +1 -1
- package/dist/node/types.d.ts +308 -27
- package/dist/node/types.d.ts.map +1 -1
- package/dist/node/types.js +232 -27
- package/dist/node/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -8
- package/dist/browser/client-Bk-J98pf.d.ts.map +0 -1
- package/dist/browser/schema-QDMf15Vn.js.map +0 -1
package/dist/node/routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","names":[],"sources":["../../src/routes.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\nimport { decodeCursor } from \"@fragno-dev/db\";\nimport { ExponentialBackoffRetryPolicy } from \"@fragno-dev/db\";\n\nimport { telegramFragmentDefinition } from \"./definition\";\nimport { telegramSchema } from \"./schema\";\nimport { createTelegramApi } from \"./telegram-api\";\nimport { DEFAULT_COMMAND_SCOPES, parseCommandBindings } from \"./telegram-utils\";\nimport {\n telegramChatTypeSchema,\n telegramCommandBindingsSchema,\n telegramUpdateSchema,\n} from \"./types\";\nimport type { TelegramCommandScope, TelegramHooksMap } from \"./types\";\n\nconst chatSummarySchema = z.object({\n id: z.string(),\n type: telegramChatTypeSchema,\n title: z.string().nullable(),\n username: z.string().nullable(),\n isForum: z.boolean(),\n commandBindings: telegramCommandBindingsSchema.nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst userSummarySchema = z.object({\n id: z.string(),\n username: z.string().nullable(),\n firstName: z.string(),\n lastName: z.string().nullable(),\n isBot: z.boolean(),\n languageCode: z.string().nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst chatMemberSummarySchema = z.object({\n id: z.string(),\n chatId: z.string(),\n userId: z.string(),\n status: z.string(),\n joinedAt: z.date().nullable(),\n leftAt: z.date().nullable(),\n user: userSummarySchema.nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst messageSummarySchema = z.object({\n id: z.string(),\n chatId: z.string(),\n fromUserId: z.string().nullable(),\n senderChatId: z.string().nullable(),\n replyToMessageId: z.string().nullable(),\n messageType: z.enum([\"message\", \"edited_message\", \"channel_post\"]),\n text: z.string().nullable(),\n payload: z.unknown().nullable(),\n sentAt: z.date(),\n editedAt: z.date().nullable(),\n commandName: z.string().nullable(),\n fromUser: userSummarySchema.nullable(),\n});\n\nconst commandBindingInputSchema = z.object({\n chatId: z.string(),\n commandName: z.string(),\n enabled: z.boolean().optional().default(true),\n scopes: z.array(telegramChatTypeSchema).optional(),\n});\n\nconst commandBindingOutputSchema = z.object({\n chatId: z.string(),\n commandName: z.string(),\n enabled: z.boolean(),\n scopes: z.array(telegramChatTypeSchema).optional(),\n});\n\nconst commandOutputSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n scopes: z.array(telegramChatTypeSchema),\n enabled: z.boolean().optional(),\n effectiveScopes: z.array(telegramChatTypeSchema).optional(),\n binding: z\n .object({\n enabled: z.boolean().optional(),\n scopes: z.array(telegramChatTypeSchema).optional(),\n })\n .nullable()\n .optional(),\n});\n\nconst actionSchema = z.enum([\n \"typing\",\n \"upload_photo\",\n \"record_video\",\n \"upload_video\",\n \"record_voice\",\n \"upload_voice\",\n \"upload_document\",\n \"choose_sticker\",\n \"find_location\",\n \"record_video_note\",\n \"upload_video_note\",\n]);\n\nconst positiveIntSchema = z.coerce.number().int().positive();\n\nconst sendMessageSchema = z.object({\n text: z.string().min(1),\n parseMode: z.enum([\"MarkdownV2\", \"Markdown\", \"HTML\"]).optional(),\n disableWebPagePreview: z.boolean().optional(),\n replyToMessageId: positiveIntSchema.optional(),\n});\n\nconst editMessageSchema = z.object({\n text: z.string().min(1),\n parseMode: z.enum([\"MarkdownV2\", \"Markdown\", \"HTML\"]).optional(),\n disableWebPagePreview: z.boolean().optional(),\n});\n\nconst queuedMessageSchema = z.object({\n ok: z.boolean(),\n queued: z.boolean(),\n});\n\nconst webhookOutputSchema = z.object({\n ok: z.boolean(),\n duplicate: z.boolean().optional(),\n});\n\nconst isDuplicateHookError = (error: unknown): boolean => {\n if (!error || typeof error !== \"object\") {\n return false;\n }\n const code = \"code\" in error ? String(error.code) : \"\";\n const message = \"message\" in error ? String(error.message) : \"\";\n if (code === \"SQLITE_CONSTRAINT\" || code === \"23505\") {\n return message.includes(\"fragno_hooks\") || message.includes(\"hook\");\n }\n return message.toLowerCase().includes(\"duplicate\") || message.toLowerCase().includes(\"unique\");\n};\n\nconst filterUndefined = (payload: Record<string, unknown>) =>\n Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));\n\nexport const telegramRoutesFactory = defineRoutes(telegramFragmentDefinition).create(\n ({ defineRoute, services, config }) => {\n const api = createTelegramApi(config);\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/telegram/webhook\",\n inputSchema: telegramUpdateSchema,\n outputSchema: webhookOutputSchema,\n errorCodes: [\"UNAUTHORIZED\"] as const,\n handler: async function ({ headers, input }, { json, error }) {\n const secret = headers.get(\"x-telegram-bot-api-secret-token\");\n if (!secret || secret !== config.webhookSecretToken) {\n return error({ message: \"Unauthorized\", code: \"UNAUTHORIZED\" }, 401);\n }\n\n const update = await input.valid();\n\n try {\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\n \"internalProcessUpdate\",\n { update },\n { id: String(update.update_id) },\n );\n })\n .execute();\n\n return json({ ok: true });\n } catch (err) {\n console.error(\"telegram webhook hook insert error\", err);\n if (isDuplicateHookError(err)) {\n return json({ ok: true, duplicate: true });\n }\n throw err;\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/commands/bind\",\n inputSchema: commandBindingInputSchema,\n outputSchema: commandBindingOutputSchema,\n errorCodes: [\"chat_not_found\", \"command_not_found\", \"invalid_scopes\"] as const,\n handler: async function ({ input }, { json, error }) {\n const payload = await input.valid();\n const command = (config.commands ?? {})[payload.commandName];\n\n if (!command) {\n return error({ message: \"Command not found\", code: \"command_not_found\" }, 404);\n }\n\n const allowedScopes = command.scopes ?? DEFAULT_COMMAND_SCOPES;\n if (\n payload.scopes &&\n !payload.scopes.every((scope: TelegramCommandScope) => allowedScopes.includes(scope))\n ) {\n return error({ message: \"Invalid scopes\", code: \"invalid_scopes\" }, 400);\n }\n\n const result = await this.handlerTx({\n retryPolicy: new ExponentialBackoffRetryPolicy({\n maxRetries: 5,\n initialDelayMs: 10,\n maxDelayMs: 250,\n }),\n })\n .withServiceCalls(\n () =>\n [\n services.bindCommand({\n chatId: payload.chatId,\n commandName: payload.commandName,\n enabled: payload.enabled,\n scopes: payload.scopes,\n }),\n ] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n return json(result.binding);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/commands\",\n queryParameters: [\"chatId\"],\n outputSchema: z.object({\n commands: z.array(commandOutputSchema),\n }),\n errorCodes: [\"chat_not_found\"] as const,\n handler: async function ({ query }, { json, error }) {\n const chatId = query.get(\"chatId\") ?? undefined;\n const commandDefinitions = Object.values(config.commands ?? {});\n\n if (!chatId) {\n return json({\n commands: commandDefinitions.map((command) => ({\n name: command.name,\n description: command.description,\n scopes: command.scopes ?? DEFAULT_COMMAND_SCOPES,\n })),\n });\n }\n\n const chat = await this.handlerTx()\n .withServiceCalls(() => [services.getChat(chatId)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!chat) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n const bindings = parseCommandBindings(chat.commandBindings);\n\n return json({\n commands: commandDefinitions.map((command) => {\n const binding = bindings[command.name] ?? null;\n const enabled = binding ? binding.enabled !== false : true;\n const defaultScopes = command.scopes ?? DEFAULT_COMMAND_SCOPES;\n const effectiveScopes = binding?.scopes ?? defaultScopes;\n\n return {\n name: command.name,\n description: command.description,\n scopes: defaultScopes,\n enabled,\n effectiveScopes,\n binding,\n };\n }),\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats\",\n queryParameters: [\"type\"],\n outputSchema: z.array(chatSummarySchema),\n handler: async function ({ query }, { json }) {\n const parsed = z\n .object({ type: telegramChatTypeSchema.optional() })\n .parse({ type: query.get(\"type\") ?? undefined });\n\n const chats = await this.handlerTx()\n .withServiceCalls(() => [services.listChats(parsed.type)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(chats);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats/:chatId\",\n outputSchema: z.object({\n chat: chatSummarySchema,\n members: z.array(chatMemberSummarySchema),\n }),\n errorCodes: [\"chat_not_found\"] as const,\n handler: async function ({ pathParams }, { json, error }) {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.getChatWithMembers(pathParams.chatId)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!result.chat) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n return json({\n chat: result.chat,\n members: result.members,\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats/:chatId/messages\",\n queryParameters: [\"cursor\", \"pageSize\", \"order\"],\n outputSchema: z.object({\n messages: z.array(messageSummarySchema),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n }),\n handler: async function ({ pathParams, query }, { json }) {\n const parsed = z\n .object({\n cursor: z.string().optional(),\n pageSize: z.coerce.number().min(1).max(100).catch(50),\n order: z.enum([\"asc\", \"desc\"]).catch(\"desc\"),\n })\n .parse({\n cursor: query.get(\"cursor\") ?? undefined,\n pageSize: query.get(\"pageSize\"),\n order: query.get(\"order\"),\n });\n\n const cursor = parsed.cursor\n ? (() => {\n try {\n return decodeCursor(parsed.cursor!);\n } catch {\n return undefined;\n }\n })()\n : undefined;\n\n const result = await this.handlerTx()\n .withServiceCalls(\n () =>\n [\n services.listMessages({\n chatId: pathParams.chatId,\n pageSize: parsed.pageSize,\n order: parsed.order,\n cursor,\n }),\n ] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json({\n messages: result.messages,\n cursor: result.cursor?.encode(),\n hasNextPage: result.hasNextPage,\n });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/actions\",\n inputSchema: z.object({ action: actionSchema }),\n outputSchema: z.object({ ok: z.boolean() }),\n errorCodes: [\"TELEGRAM_API_ERROR\"] as const,\n handler: async function ({ pathParams, input }, { json, error }) {\n const { action } = await input.valid();\n const result = await api.sendChatAction({\n chat_id: pathParams.chatId,\n action,\n });\n\n if (!result.ok) {\n return error(\n { message: result.description ?? \"Telegram API error\", code: \"TELEGRAM_API_ERROR\" },\n 502,\n );\n }\n\n return json({ ok: true });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/send\",\n inputSchema: sendMessageSchema,\n outputSchema: queuedMessageSchema,\n handler: async function ({ pathParams, input }, { json }) {\n const payload = await input.valid();\n\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\"internalOutgoingMessage\", {\n action: \"sendMessage\",\n payload: filterUndefined({\n chat_id: pathParams.chatId,\n text: payload.text,\n parse_mode: payload.parseMode,\n disable_web_page_preview: payload.disableWebPagePreview,\n reply_to_message_id: payload.replyToMessageId,\n }),\n });\n })\n .execute();\n\n return json({ ok: true, queued: true });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/messages/:messageId/edit\",\n inputSchema: editMessageSchema,\n outputSchema: queuedMessageSchema,\n errorCodes: [\"INVALID_MESSAGE_ID\"] as const,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const messageIdResult = positiveIntSchema.safeParse(pathParams.messageId);\n if (!messageIdResult.success) {\n return error({ message: \"Invalid message id\", code: \"INVALID_MESSAGE_ID\" }, 400);\n }\n const messageId = messageIdResult.data;\n\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\"internalOutgoingMessage\", {\n action: \"editMessageText\",\n payload: filterUndefined({\n chat_id: pathParams.chatId,\n message_id: messageId,\n text: payload.text,\n parse_mode: payload.parseMode,\n disable_web_page_preview: payload.disableWebPagePreview,\n }),\n });\n })\n .execute();\n\n return json({ ok: true, queued: true });\n },\n }),\n ];\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"routes.js","names":[],"sources":["../../src/routes.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { defineRoutes } from \"@fragno-dev/core\";\nimport { decodeCursor } from \"@fragno-dev/db\";\nimport { ExponentialBackoffRetryPolicy } from \"@fragno-dev/db\";\n\nimport { telegramFragmentDefinition } from \"./definition\";\nimport { telegramSchema } from \"./schema\";\nimport { createTelegramApi } from \"./telegram-api\";\nimport {\n DEFAULT_COMMAND_SCOPES,\n normalizeTelegramUpdate,\n parseCommandBindings,\n} from \"./telegram-utils\";\nimport {\n telegramAttachmentSchema,\n telegramChatTypeSchema,\n telegramCommandBindingsSchema,\n} from \"./types\";\nimport type { TelegramCommandScope, TelegramHooksMap } from \"./types\";\n\nconst chatSummarySchema = z.object({\n id: z.string(),\n type: telegramChatTypeSchema,\n title: z.string().nullable(),\n username: z.string().nullable(),\n isForum: z.boolean(),\n commandBindings: telegramCommandBindingsSchema.nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst userSummarySchema = z.object({\n id: z.string(),\n username: z.string().nullable(),\n firstName: z.string(),\n lastName: z.string().nullable(),\n isBot: z.boolean(),\n languageCode: z.string().nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst chatMemberSummarySchema = z.object({\n id: z.string(),\n chatId: z.string(),\n userId: z.string(),\n status: z.string(),\n joinedAt: z.date().nullable(),\n leftAt: z.date().nullable(),\n user: userSummarySchema.nullable(),\n createdAt: z.date(),\n updatedAt: z.date(),\n});\n\nconst messageSummarySchema = z.object({\n id: z.string(),\n chatId: z.string(),\n fromUserId: z.string().nullable(),\n senderChatId: z.string().nullable(),\n replyToMessageId: z.string().nullable(),\n messageType: z.enum([\"message\", \"edited_message\", \"channel_post\"]),\n text: z.string().nullable(),\n attachments: z.array(telegramAttachmentSchema),\n payload: z.unknown().nullable(),\n sentAt: z.date(),\n editedAt: z.date().nullable(),\n commandName: z.string().nullable(),\n fromUser: userSummarySchema.nullable(),\n});\n\nconst commandBindingInputSchema = z.object({\n chatId: z.string(),\n commandName: z.string(),\n enabled: z.boolean().optional().default(true),\n scopes: z.array(telegramChatTypeSchema).optional(),\n});\n\nconst commandBindingOutputSchema = z.object({\n chatId: z.string(),\n commandName: z.string(),\n enabled: z.boolean(),\n scopes: z.array(telegramChatTypeSchema).optional(),\n});\n\nconst commandOutputSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n scopes: z.array(telegramChatTypeSchema),\n enabled: z.boolean().optional(),\n effectiveScopes: z.array(telegramChatTypeSchema).optional(),\n binding: z\n .object({\n enabled: z.boolean().optional(),\n scopes: z.array(telegramChatTypeSchema).optional(),\n })\n .nullable()\n .optional(),\n});\n\nconst actionSchema = z.enum([\n \"typing\",\n \"upload_photo\",\n \"record_video\",\n \"upload_video\",\n \"record_voice\",\n \"upload_voice\",\n \"upload_document\",\n \"choose_sticker\",\n \"find_location\",\n \"record_video_note\",\n \"upload_video_note\",\n]);\n\nconst positiveIntSchema = z.coerce.number().int().positive();\n\nconst sendMessageSchema = z.object({\n text: z.string().min(1),\n parseMode: z.enum([\"MarkdownV2\", \"Markdown\", \"HTML\"]).optional(),\n disableWebPagePreview: z.boolean().optional(),\n replyToMessageId: positiveIntSchema.optional(),\n});\n\nconst editMessageSchema = z.object({\n text: z.string().min(1),\n parseMode: z.enum([\"MarkdownV2\", \"Markdown\", \"HTML\"]).optional(),\n disableWebPagePreview: z.boolean().optional(),\n});\n\nconst queuedMessageSchema = z.object({\n ok: z.boolean(),\n queued: z.boolean(),\n});\n\nconst webhookOutputSchema = z.object({\n ok: z.boolean(),\n duplicate: z.boolean().optional(),\n});\n\nconst isDuplicateHookError = (error: unknown): boolean => {\n if (!error || typeof error !== \"object\") {\n return false;\n }\n const code = \"code\" in error ? String(error.code) : \"\";\n const message = \"message\" in error ? String(error.message) : \"\";\n if (code === \"SQLITE_CONSTRAINT\" || code === \"23505\") {\n return message.includes(\"fragno_hooks\") || message.includes(\"hook\");\n }\n return message.toLowerCase().includes(\"duplicate\") || message.toLowerCase().includes(\"unique\");\n};\n\nconst filterUndefined = (payload: Record<string, unknown>) =>\n Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));\n\nexport const telegramRoutesFactory = defineRoutes(telegramFragmentDefinition).create(\n ({ defineRoute, services, config }) => {\n const api = createTelegramApi(config);\n\n return [\n defineRoute({\n method: \"POST\",\n path: \"/telegram/webhook\",\n inputSchema: z.unknown(),\n outputSchema: webhookOutputSchema,\n errorCodes: [\"UNAUTHORIZED\", \"INVALID_UPDATE\"] as const,\n handler: async function ({ headers, input }, { json, error }) {\n const secret = headers.get(\"x-telegram-bot-api-secret-token\");\n if (!secret || secret !== config.webhookSecretToken) {\n return error({ message: \"Unauthorized\", code: \"UNAUTHORIZED\" }, 401);\n }\n\n const rawUpdate = await input.valid();\n let update;\n try {\n update = normalizeTelegramUpdate(rawUpdate);\n } catch {\n return error({ message: \"Invalid Telegram update\", code: \"INVALID_UPDATE\" }, 400);\n }\n\n try {\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\n \"internalProcessUpdate\",\n { update },\n { id: String(update.updateId) },\n );\n })\n .execute();\n\n return json({ ok: true });\n } catch (err) {\n console.error(\"telegram webhook hook insert error\", err);\n if (isDuplicateHookError(err)) {\n return json({ ok: true, duplicate: true });\n }\n throw err;\n }\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/commands/bind\",\n inputSchema: commandBindingInputSchema,\n outputSchema: commandBindingOutputSchema,\n errorCodes: [\"chat_not_found\", \"command_not_found\", \"invalid_scopes\"] as const,\n handler: async function ({ input }, { json, error }) {\n const payload = await input.valid();\n const command = (config.commands ?? {})[payload.commandName];\n\n if (!command) {\n return error({ message: \"Command not found\", code: \"command_not_found\" }, 404);\n }\n\n const allowedScopes = command.scopes ?? DEFAULT_COMMAND_SCOPES;\n if (\n payload.scopes &&\n !payload.scopes.every((scope: TelegramCommandScope) => allowedScopes.includes(scope))\n ) {\n return error({ message: \"Invalid scopes\", code: \"invalid_scopes\" }, 400);\n }\n\n const result = await this.handlerTx({\n retryPolicy: new ExponentialBackoffRetryPolicy({\n maxRetries: 5,\n initialDelayMs: 10,\n maxDelayMs: 250,\n }),\n })\n .withServiceCalls(\n () =>\n [\n services.bindCommand({\n chatId: payload.chatId,\n commandName: payload.commandName,\n enabled: payload.enabled,\n scopes: payload.scopes,\n }),\n ] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n return json(result.binding);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/commands\",\n queryParameters: [\"chatId\"],\n outputSchema: z.object({\n commands: z.array(commandOutputSchema),\n }),\n errorCodes: [\"chat_not_found\"] as const,\n handler: async function ({ query }, { json, error }) {\n const chatId = query.get(\"chatId\") ?? undefined;\n const commandDefinitions = Object.values(config.commands ?? {});\n\n if (!chatId) {\n return json({\n commands: commandDefinitions.map((command) => ({\n name: command.name,\n description: command.description,\n scopes: command.scopes ?? DEFAULT_COMMAND_SCOPES,\n })),\n });\n }\n\n const chat = await this.handlerTx()\n .withServiceCalls(() => [services.getChat(chatId)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!chat) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n const bindings = parseCommandBindings(chat.commandBindings);\n\n return json({\n commands: commandDefinitions.map((command) => {\n const binding = bindings[command.name] ?? null;\n const enabled = binding ? binding.enabled !== false : true;\n const defaultScopes = command.scopes ?? DEFAULT_COMMAND_SCOPES;\n const effectiveScopes = binding?.scopes ?? defaultScopes;\n\n return {\n name: command.name,\n description: command.description,\n scopes: defaultScopes,\n enabled,\n effectiveScopes,\n binding,\n };\n }),\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats\",\n queryParameters: [\"type\"],\n outputSchema: z.array(chatSummarySchema),\n handler: async function ({ query }, { json }) {\n const parsed = z\n .object({ type: telegramChatTypeSchema.optional() })\n .parse({ type: query.get(\"type\") ?? undefined });\n\n const chats = await this.handlerTx()\n .withServiceCalls(() => [services.listChats(parsed.type)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json(chats);\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats/:chatId\",\n outputSchema: z.object({\n chat: chatSummarySchema,\n members: z.array(chatMemberSummarySchema),\n }),\n errorCodes: [\"chat_not_found\"] as const,\n handler: async function ({ pathParams }, { json, error }) {\n const result = await this.handlerTx()\n .withServiceCalls(() => [services.getChatWithMembers(pathParams.chatId)] as const)\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n if (!result.chat) {\n return error({ message: \"Chat not found\", code: \"chat_not_found\" }, 404);\n }\n\n return json({\n chat: result.chat,\n members: result.members,\n });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/chats/:chatId/messages\",\n queryParameters: [\"cursor\", \"pageSize\", \"order\"],\n outputSchema: z.object({\n messages: z.array(messageSummarySchema),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n }),\n handler: async function ({ pathParams, query }, { json }) {\n const parsed = z\n .object({\n cursor: z.string().optional(),\n pageSize: z.coerce.number().min(1).max(100).catch(50),\n order: z.enum([\"asc\", \"desc\"]).catch(\"desc\"),\n })\n .parse({\n cursor: query.get(\"cursor\") ?? undefined,\n pageSize: query.get(\"pageSize\"),\n order: query.get(\"order\"),\n });\n\n const cursor = parsed.cursor\n ? (() => {\n try {\n return decodeCursor(parsed.cursor!);\n } catch {\n return undefined;\n }\n })()\n : undefined;\n\n const result = await this.handlerTx()\n .withServiceCalls(\n () =>\n [\n services.listMessages({\n chatId: pathParams.chatId,\n pageSize: parsed.pageSize,\n order: parsed.order,\n cursor,\n }),\n ] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n return json({\n messages: result.messages,\n cursor: result.cursor?.encode(),\n hasNextPage: result.hasNextPage,\n });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/actions\",\n inputSchema: z.object({ action: actionSchema }),\n outputSchema: z.object({ ok: z.boolean() }),\n errorCodes: [\"TELEGRAM_API_ERROR\"] as const,\n handler: async function ({ pathParams, input }, { json, error }) {\n const { action } = await input.valid();\n const result = await api.sendChatAction({\n chatId: pathParams.chatId,\n action,\n });\n\n if (!result.ok) {\n return error(\n { message: result.description ?? \"Telegram API error\", code: \"TELEGRAM_API_ERROR\" },\n 502,\n );\n }\n\n return json({ ok: true });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/send\",\n inputSchema: sendMessageSchema,\n outputSchema: queuedMessageSchema,\n handler: async function ({ pathParams, input }, { json }) {\n const payload = await input.valid();\n\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\"internalOutgoingMessage\", {\n action: \"sendMessage\",\n payload: filterUndefined({\n chatId: pathParams.chatId,\n text: payload.text,\n parseMode: payload.parseMode,\n disableWebPagePreview: payload.disableWebPagePreview,\n replyToMessageId: payload.replyToMessageId,\n }),\n });\n })\n .execute();\n\n return json({ ok: true, queued: true });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/chats/:chatId/messages/:messageId/edit\",\n inputSchema: editMessageSchema,\n outputSchema: queuedMessageSchema,\n errorCodes: [\"INVALID_MESSAGE_ID\"] as const,\n handler: async function ({ pathParams, input }, { json, error }) {\n const payload = await input.valid();\n const messageIdResult = positiveIntSchema.safeParse(pathParams.messageId);\n if (!messageIdResult.success) {\n return error({ message: \"Invalid message id\", code: \"INVALID_MESSAGE_ID\" }, 400);\n }\n const messageId = messageIdResult.data;\n\n await this.handlerTx()\n .mutate(({ forSchema }) => {\n const uow = forSchema(telegramSchema, {} as TelegramHooksMap);\n uow.triggerHook(\"internalOutgoingMessage\", {\n action: \"editMessageText\",\n payload: filterUndefined({\n chatId: pathParams.chatId,\n messageId,\n text: payload.text,\n parseMode: payload.parseMode,\n disableWebPagePreview: payload.disableWebPagePreview,\n }),\n });\n })\n .execute();\n\n return json({ ok: true, queued: true });\n },\n }),\n ];\n },\n);\n"],"mappings":";;;;;;;;;;AAqBA,MAAM,oBAAoB,EAAE,OAAO;CACjC,IAAI,EAAE,QAAQ;CACd,MAAM;CACN,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,SAAS,EAAE,SAAS;CACpB,iBAAiB,8BAA8B,UAAU;CACzD,WAAW,EAAE,MAAM;CACnB,WAAW,EAAE,MAAM;CACpB,CAAC;AAEF,MAAM,oBAAoB,EAAE,OAAO;CACjC,IAAI,EAAE,QAAQ;CACd,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,WAAW,EAAE,QAAQ;CACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,OAAO,EAAE,SAAS;CAClB,cAAc,EAAE,QAAQ,CAAC,UAAU;CACnC,WAAW,EAAE,MAAM;CACnB,WAAW,EAAE,MAAM;CACpB,CAAC;AAEF,MAAM,0BAA0B,EAAE,OAAO;CACvC,IAAI,EAAE,QAAQ;CACd,QAAQ,EAAE,QAAQ;CAClB,QAAQ,EAAE,QAAQ;CAClB,QAAQ,EAAE,QAAQ;CAClB,UAAU,EAAE,MAAM,CAAC,UAAU;CAC7B,QAAQ,EAAE,MAAM,CAAC,UAAU;CAC3B,MAAM,kBAAkB,UAAU;CAClC,WAAW,EAAE,MAAM;CACnB,WAAW,EAAE,MAAM;CACpB,CAAC;AAEF,MAAM,uBAAuB,EAAE,OAAO;CACpC,IAAI,EAAE,QAAQ;CACd,QAAQ,EAAE,QAAQ;CAClB,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,cAAc,EAAE,QAAQ,CAAC,UAAU;CACnC,kBAAkB,EAAE,QAAQ,CAAC,UAAU;CACvC,aAAa,EAAE,KAAK;EAAC;EAAW;EAAkB;EAAe,CAAC;CAClE,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,aAAa,EAAE,MAAM,yBAAyB;CAC9C,SAAS,EAAE,SAAS,CAAC,UAAU;CAC/B,QAAQ,EAAE,MAAM;CAChB,UAAU,EAAE,MAAM,CAAC,UAAU;CAC7B,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,UAAU,kBAAkB,UAAU;CACvC,CAAC;AAEF,MAAM,4BAA4B,EAAE,OAAO;CACzC,QAAQ,EAAE,QAAQ;CAClB,aAAa,EAAE,QAAQ;CACvB,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,KAAK;CAC7C,QAAQ,EAAE,MAAM,uBAAuB,CAAC,UAAU;CACnD,CAAC;AAEF,MAAM,6BAA6B,EAAE,OAAO;CAC1C,QAAQ,EAAE,QAAQ;CAClB,aAAa,EAAE,QAAQ;CACvB,SAAS,EAAE,SAAS;CACpB,QAAQ,EAAE,MAAM,uBAAuB,CAAC,UAAU;CACnD,CAAC;AAEF,MAAM,sBAAsB,EAAE,OAAO;CACnC,MAAM,EAAE,QAAQ;CAChB,aAAa,EAAE,QAAQ,CAAC,UAAU;CAClC,QAAQ,EAAE,MAAM,uBAAuB;CACvC,SAAS,EAAE,SAAS,CAAC,UAAU;CAC/B,iBAAiB,EAAE,MAAM,uBAAuB,CAAC,UAAU;CAC3D,SAAS,EACN,OAAO;EACN,SAAS,EAAE,SAAS,CAAC,UAAU;EAC/B,QAAQ,EAAE,MAAM,uBAAuB,CAAC,UAAU;EACnD,CAAC,CACD,UAAU,CACV,UAAU;CACd,CAAC;AAEF,MAAM,eAAe,EAAE,KAAK;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,oBAAoB,EAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,UAAU;AAE5D,MAAM,oBAAoB,EAAE,OAAO;CACjC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvB,WAAW,EAAE,KAAK;EAAC;EAAc;EAAY;EAAO,CAAC,CAAC,UAAU;CAChE,uBAAuB,EAAE,SAAS,CAAC,UAAU;CAC7C,kBAAkB,kBAAkB,UAAU;CAC/C,CAAC;AAEF,MAAM,oBAAoB,EAAE,OAAO;CACjC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE;CACvB,WAAW,EAAE,KAAK;EAAC;EAAc;EAAY;EAAO,CAAC,CAAC,UAAU;CAChE,uBAAuB,EAAE,SAAS,CAAC,UAAU;CAC9C,CAAC;AAEF,MAAM,sBAAsB,EAAE,OAAO;CACnC,IAAI,EAAE,SAAS;CACf,QAAQ,EAAE,SAAS;CACpB,CAAC;AAEF,MAAM,sBAAsB,EAAE,OAAO;CACnC,IAAI,EAAE,SAAS;CACf,WAAW,EAAE,SAAS,CAAC,UAAU;CAClC,CAAC;AAEF,MAAM,wBAAwB,UAA4B;AACxD,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;CAET,MAAM,OAAO,UAAU,QAAQ,OAAO,MAAM,KAAK,GAAG;CACpD,MAAM,UAAU,aAAa,QAAQ,OAAO,MAAM,QAAQ,GAAG;AAC7D,KAAI,SAAS,uBAAuB,SAAS,QAC3C,QAAO,QAAQ,SAAS,eAAe,IAAI,QAAQ,SAAS,OAAO;AAErE,QAAO,QAAQ,aAAa,CAAC,SAAS,YAAY,IAAI,QAAQ,aAAa,CAAC,SAAS,SAAS;;AAGhG,MAAM,mBAAmB,YACvB,OAAO,YAAY,OAAO,QAAQ,QAAQ,CAAC,QAAQ,GAAG,WAAW,UAAU,OAAU,CAAC;AAExF,MAAa,wBAAwB,aAAa,2BAA2B,CAAC,QAC3E,EAAE,aAAa,UAAU,aAAa;CACrC,MAAM,MAAM,kBAAkB,OAAO;AAErC,QAAO;EACL,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa,EAAE,SAAS;GACxB,cAAc;GACd,YAAY,CAAC,gBAAgB,iBAAiB;GAC9C,SAAS,eAAgB,EAAE,SAAS,SAAS,EAAE,MAAM,SAAS;IAC5D,MAAM,SAAS,QAAQ,IAAI,kCAAkC;AAC7D,QAAI,CAAC,UAAU,WAAW,OAAO,mBAC/B,QAAO,MAAM;KAAE,SAAS;KAAgB,MAAM;KAAgB,EAAE,IAAI;IAGtE,MAAM,YAAY,MAAM,MAAM,OAAO;IACrC,IAAI;AACJ,QAAI;AACF,cAAS,wBAAwB,UAAU;YACrC;AACN,YAAO,MAAM;MAAE,SAAS;MAA2B,MAAM;MAAkB,EAAE,IAAI;;AAGnF,QAAI;AACF,WAAM,KAAK,WAAW,CACnB,QAAQ,EAAE,gBAAgB;AAEzB,MADY,UAAU,gBAAgB,EAAE,CAAqB,CACzD,YACF,yBACA,EAAE,QAAQ,EACV,EAAE,IAAI,OAAO,OAAO,SAAS,EAAE,CAChC;OACD,CACD,SAAS;AAEZ,YAAO,KAAK,EAAE,IAAI,MAAM,CAAC;aAClB,KAAK;AACZ,aAAQ,MAAM,sCAAsC,IAAI;AACxD,SAAI,qBAAqB,IAAI,CAC3B,QAAO,KAAK;MAAE,IAAI;MAAM,WAAW;MAAM,CAAC;AAE5C,WAAM;;;GAGX,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY;IAAC;IAAkB;IAAqB;IAAiB;GACrE,SAAS,eAAgB,EAAE,SAAS,EAAE,MAAM,SAAS;IACnD,MAAM,UAAU,MAAM,MAAM,OAAO;IACnC,MAAM,WAAW,OAAO,YAAY,EAAE,EAAE,QAAQ;AAEhD,QAAI,CAAC,QACH,QAAO,MAAM;KAAE,SAAS;KAAqB,MAAM;KAAqB,EAAE,IAAI;IAGhF,MAAM,gBAAgB,QAAQ,UAAU;AACxC,QACE,QAAQ,UACR,CAAC,QAAQ,OAAO,OAAO,UAAgC,cAAc,SAAS,MAAM,CAAC,CAErF,QAAO,MAAM;KAAE,SAAS;KAAkB,MAAM;KAAkB,EAAE,IAAI;IAG1E,MAAM,SAAS,MAAM,KAAK,UAAU,EAClC,aAAa,IAAI,8BAA8B;KAC7C,YAAY;KACZ,gBAAgB;KAChB,YAAY;KACb,CAAC,EACH,CAAC,CACC,uBAEG,CACE,SAAS,YAAY;KACnB,QAAQ,QAAQ;KAChB,aAAa,QAAQ;KACrB,SAAS,QAAQ;KACjB,QAAQ,QAAQ;KACjB,CAAC,CACH,CACJ,CACA,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,QAAI,CAAC,OAAO,GACV,QAAO,MAAM;KAAE,SAAS;KAAkB,MAAM;KAAkB,EAAE,IAAI;AAG1E,WAAO,KAAK,OAAO,QAAQ;;GAE9B,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,iBAAiB,CAAC,SAAS;GAC3B,cAAc,EAAE,OAAO,EACrB,UAAU,EAAE,MAAM,oBAAoB,EACvC,CAAC;GACF,YAAY,CAAC,iBAAiB;GAC9B,SAAS,eAAgB,EAAE,SAAS,EAAE,MAAM,SAAS;IACnD,MAAM,SAAS,MAAM,IAAI,SAAS,IAAI;IACtC,MAAM,qBAAqB,OAAO,OAAO,OAAO,YAAY,EAAE,CAAC;AAE/D,QAAI,CAAC,OACH,QAAO,KAAK,EACV,UAAU,mBAAmB,KAAK,aAAa;KAC7C,MAAM,QAAQ;KACd,aAAa,QAAQ;KACrB,QAAQ,QAAQ,UAAU;KAC3B,EAAE,EACJ,CAAC;IAGJ,MAAM,OAAO,MAAM,KAAK,WAAW,CAChC,uBAAuB,CAAC,SAAS,QAAQ,OAAO,CAAC,CAAU,CAC3D,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,QAAI,CAAC,KACH,QAAO,MAAM;KAAE,SAAS;KAAkB,MAAM;KAAkB,EAAE,IAAI;IAG1E,MAAM,WAAW,qBAAqB,KAAK,gBAAgB;AAE3D,WAAO,KAAK,EACV,UAAU,mBAAmB,KAAK,YAAY;KAC5C,MAAM,UAAU,SAAS,QAAQ,SAAS;KAC1C,MAAM,UAAU,UAAU,QAAQ,YAAY,QAAQ;KACtD,MAAM,gBAAgB,QAAQ,UAAU;KACxC,MAAM,kBAAkB,SAAS,UAAU;AAE3C,YAAO;MACL,MAAM,QAAQ;MACd,aAAa,QAAQ;MACrB,QAAQ;MACR;MACA;MACA;MACD;MACD,EACH,CAAC;;GAEL,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,iBAAiB,CAAC,OAAO;GACzB,cAAc,EAAE,MAAM,kBAAkB;GACxC,SAAS,eAAgB,EAAE,SAAS,EAAE,QAAQ;IAC5C,MAAM,SAAS,EACZ,OAAO,EAAE,MAAM,uBAAuB,UAAU,EAAE,CAAC,CACnD,MAAM,EAAE,MAAM,MAAM,IAAI,OAAO,IAAI,QAAW,CAAC;AAOlD,WAAO,KALO,MAAM,KAAK,WAAW,CACjC,uBAAuB,CAAC,SAAS,UAAU,OAAO,KAAK,CAAC,CAAU,CAClE,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS,CAEM;;GAErB,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,cAAc,EAAE,OAAO;IACrB,MAAM;IACN,SAAS,EAAE,MAAM,wBAAwB;IAC1C,CAAC;GACF,YAAY,CAAC,iBAAiB;GAC9B,SAAS,eAAgB,EAAE,cAAc,EAAE,MAAM,SAAS;IACxD,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAAuB,CAAC,SAAS,mBAAmB,WAAW,OAAO,CAAC,CAAU,CACjF,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,QAAI,CAAC,OAAO,KACV,QAAO,MAAM;KAAE,SAAS;KAAkB,MAAM;KAAkB,EAAE,IAAI;AAG1E,WAAO,KAAK;KACV,MAAM,OAAO;KACb,SAAS,OAAO;KACjB,CAAC;;GAEL,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,iBAAiB;IAAC;IAAU;IAAY;IAAQ;GAChD,cAAc,EAAE,OAAO;IACrB,UAAU,EAAE,MAAM,qBAAqB;IACvC,QAAQ,EAAE,QAAQ,CAAC,UAAU;IAC7B,aAAa,EAAE,SAAS;IACzB,CAAC;GACF,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,QAAQ;IACxD,MAAM,SAAS,EACZ,OAAO;KACN,QAAQ,EAAE,QAAQ,CAAC,UAAU;KAC7B,UAAU,EAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG;KACrD,OAAO,EAAE,KAAK,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO;KAC7C,CAAC,CACD,MAAM;KACL,QAAQ,MAAM,IAAI,SAAS,IAAI;KAC/B,UAAU,MAAM,IAAI,WAAW;KAC/B,OAAO,MAAM,IAAI,QAAQ;KAC1B,CAAC;IAEJ,MAAM,SAAS,OAAO,gBACX;AACL,SAAI;AACF,aAAO,aAAa,OAAO,OAAQ;aAC7B;AACN;;QAEA,GACJ;IAEJ,MAAM,SAAS,MAAM,KAAK,WAAW,CAClC,uBAEG,CACE,SAAS,aAAa;KACpB,QAAQ,WAAW;KACnB,UAAU,OAAO;KACjB,OAAO,OAAO;KACd;KACD,CAAC,CACH,CACJ,CACA,WAAW,EAAE,eAAe,CAAC,cAAc,OAAO,CAClD,SAAS;AAEZ,WAAO,KAAK;KACV,UAAU,OAAO;KACjB,QAAQ,OAAO,QAAQ,QAAQ;KAC/B,aAAa,OAAO;KACrB,CAAC;;GAEL,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa,EAAE,OAAO,EAAE,QAAQ,cAAc,CAAC;GAC/C,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;GAC3C,YAAY,CAAC,qBAAqB;GAClC,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,EAAE,WAAW,MAAM,MAAM,OAAO;IACtC,MAAM,SAAS,MAAM,IAAI,eAAe;KACtC,QAAQ,WAAW;KACnB;KACD,CAAC;AAEF,QAAI,CAAC,OAAO,GACV,QAAO,MACL;KAAE,SAAS,OAAO,eAAe;KAAsB,MAAM;KAAsB,EACnF,IACD;AAGH,WAAO,KAAK,EAAE,IAAI,MAAM,CAAC;;GAE5B,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,QAAQ;IACxD,MAAM,UAAU,MAAM,MAAM,OAAO;AAEnC,UAAM,KAAK,WAAW,CACnB,QAAQ,EAAE,gBAAgB;AAEzB,KADY,UAAU,gBAAgB,EAAE,CAAqB,CACzD,YAAY,2BAA2B;MACzC,QAAQ;MACR,SAAS,gBAAgB;OACvB,QAAQ,WAAW;OACnB,MAAM,QAAQ;OACd,WAAW,QAAQ;OACnB,uBAAuB,QAAQ;OAC/B,kBAAkB,QAAQ;OAC3B,CAAC;MACH,CAAC;MACF,CACD,SAAS;AAEZ,WAAO,KAAK;KAAE,IAAI;KAAM,QAAQ;KAAM,CAAC;;GAE1C,CAAC;EAEF,YAAY;GACV,QAAQ;GACR,MAAM;GACN,aAAa;GACb,cAAc;GACd,YAAY,CAAC,qBAAqB;GAClC,SAAS,eAAgB,EAAE,YAAY,SAAS,EAAE,MAAM,SAAS;IAC/D,MAAM,UAAU,MAAM,MAAM,OAAO;IACnC,MAAM,kBAAkB,kBAAkB,UAAU,WAAW,UAAU;AACzE,QAAI,CAAC,gBAAgB,QACnB,QAAO,MAAM;KAAE,SAAS;KAAsB,MAAM;KAAsB,EAAE,IAAI;IAElF,MAAM,YAAY,gBAAgB;AAElC,UAAM,KAAK,WAAW,CACnB,QAAQ,EAAE,gBAAgB;AAEzB,KADY,UAAU,gBAAgB,EAAE,CAAqB,CACzD,YAAY,2BAA2B;MACzC,QAAQ;MACR,SAAS,gBAAgB;OACvB,QAAQ,WAAW;OACnB;OACA,MAAM,QAAQ;OACd,WAAW,QAAQ;OACnB,uBAAuB,QAAQ;OAChC,CAAC;MACH,CAAC;MACF,CACD,SAAS;AAEZ,WAAO,KAAK;KAAE,IAAI;KAAM,QAAQ;KAAM,CAAC;;GAE1C,CAAC;EACH;EAEJ"}
|
package/dist/node/services.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { telegramSchema } from "./schema.js";
|
|
2
|
-
import
|
|
3
|
-
import { DEFAULT_COMMAND_SCOPES, buildChatMemberId, buildMessageId, parseCommand, parseCommandBindings, parseTelegramUpdate } from "./telegram-utils.js";
|
|
2
|
+
import "./types.js";
|
|
3
|
+
import { DEFAULT_COMMAND_SCOPES, buildChatMemberId, buildMessageId, extractTelegramAttachments, parseCommand, parseCommandBindings, parseTelegramUpdate, safeNormalizeTelegramMessage } from "./telegram-utils.js";
|
|
4
4
|
import "@fragno-dev/db";
|
|
5
5
|
import "@fragno-dev/db/schema";
|
|
6
6
|
|
|
@@ -28,10 +28,7 @@ const parseMessageCompositeId = (value) => {
|
|
|
28
28
|
messageId: second ?? ""
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
|
-
const parseTelegramMessagePayload = (payload) =>
|
|
32
|
-
const result = telegramMessageSchema.safeParse(payload);
|
|
33
|
-
return result.success ? result.data : null;
|
|
34
|
-
};
|
|
31
|
+
const parseTelegramMessagePayload = (payload) => safeNormalizeTelegramMessage(payload);
|
|
35
32
|
const toUserSummary = (user) => ({
|
|
36
33
|
id: String(user.id.valueOf()),
|
|
37
34
|
username: user.username,
|
|
@@ -72,8 +69,9 @@ const toMessageSummary = (message) => {
|
|
|
72
69
|
const payload = parseTelegramMessagePayload(message.payload);
|
|
73
70
|
const chatId = payload?.chat ? String(payload.chat.id) : composite.chatId;
|
|
74
71
|
const fromUserId = payload?.from ? String(payload.from.id) : message.messageAuthor ? String(message.messageAuthor.id.valueOf()) : null;
|
|
75
|
-
const senderChatId = payload?.
|
|
76
|
-
const replyToMessageId = payload?.
|
|
72
|
+
const senderChatId = payload?.senderChat ? String(payload.senderChat.id) : null;
|
|
73
|
+
const replyToMessageId = payload?.replyToMessage ? buildMessageId(chatId, payload.replyToMessage.messageId) : null;
|
|
74
|
+
const attachments = payload ? extractTelegramAttachments(payload) : [];
|
|
77
75
|
return {
|
|
78
76
|
id: String(message.id.valueOf()),
|
|
79
77
|
chatId,
|
|
@@ -82,6 +80,7 @@ const toMessageSummary = (message) => {
|
|
|
82
80
|
replyToMessageId,
|
|
83
81
|
messageType: message.messageType,
|
|
84
82
|
text: message.text,
|
|
83
|
+
attachments,
|
|
85
84
|
payload: message.payload,
|
|
86
85
|
sentAt: message.sentAt,
|
|
87
86
|
editedAt: message.editedAt,
|
|
@@ -105,29 +104,30 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
105
104
|
const parsed = parseTelegramUpdate(update);
|
|
106
105
|
if (!parsed) return {
|
|
107
106
|
kind: "ignored",
|
|
108
|
-
updateId: update.
|
|
107
|
+
updateId: update.updateId
|
|
109
108
|
};
|
|
110
109
|
const { message, type, updateId } = parsed;
|
|
111
110
|
const chatId = String(message.chat.id);
|
|
112
|
-
const messageId = buildMessageId(chatId, message.
|
|
111
|
+
const messageId = buildMessageId(chatId, message.messageId);
|
|
113
112
|
const sentAt = /* @__PURE__ */ new Date(message.date * 1e3);
|
|
114
|
-
const editedAt = message.
|
|
113
|
+
const editedAt = message.editDate ? /* @__PURE__ */ new Date(message.editDate * 1e3) : null;
|
|
115
114
|
const fromUser = message.from ?? null;
|
|
116
115
|
const fromUserId = fromUser ? String(fromUser.id) : null;
|
|
117
|
-
const senderChat = message.
|
|
116
|
+
const senderChat = message.senderChat ?? null;
|
|
118
117
|
const senderChatId = senderChat ? String(senderChat.id) : null;
|
|
119
|
-
const replyToMessageId = message.
|
|
118
|
+
const replyToMessageId = message.replyToMessage ? buildMessageId(chatId, message.replyToMessage.messageId) : null;
|
|
120
119
|
const commandMatch = parseCommand(message, botUsername);
|
|
121
120
|
const commandName = commandMatch?.name ?? null;
|
|
121
|
+
const attachments = extractTelegramAttachments(message);
|
|
122
122
|
const membershipMap = /* @__PURE__ */ new Map();
|
|
123
|
-
const newMembers = message.
|
|
123
|
+
const newMembers = message.newChatMembers ?? [];
|
|
124
124
|
for (const member of newMembers) membershipMap.set(String(member.id), {
|
|
125
125
|
status: "member",
|
|
126
126
|
joinedAt: sentAt,
|
|
127
127
|
leftAt: null,
|
|
128
128
|
notify: true
|
|
129
129
|
});
|
|
130
|
-
if (message.
|
|
130
|
+
if (message.leftChatMember) membershipMap.set(String(message.leftChatMember.id), {
|
|
131
131
|
status: "left",
|
|
132
132
|
joinedAt: null,
|
|
133
133
|
leftAt: sentAt,
|
|
@@ -143,7 +143,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
143
143
|
const userIds = Array.from(new Set([
|
|
144
144
|
fromUserId,
|
|
145
145
|
...newMembers.map((member) => String(member.id)),
|
|
146
|
-
message.
|
|
146
|
+
message.leftChatMember ? String(message.leftChatMember.id) : null
|
|
147
147
|
].filter(Boolean)));
|
|
148
148
|
const memberIds = Array.from(new Set(Array.from(membershipMap.keys()).map((userId) => buildChatMemberId(chatId, userId))));
|
|
149
149
|
const chatsForUpsert = [];
|
|
@@ -160,7 +160,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
160
160
|
for (const user of [
|
|
161
161
|
fromUser,
|
|
162
162
|
...newMembers,
|
|
163
|
-
message.
|
|
163
|
+
message.leftChatMember
|
|
164
164
|
]) {
|
|
165
165
|
if (!user) continue;
|
|
166
166
|
const id = String(user.id);
|
|
@@ -187,7 +187,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
187
187
|
type: chat.type,
|
|
188
188
|
title: chat.title ?? null,
|
|
189
189
|
username: chat.username ?? null,
|
|
190
|
-
isForum: chat.
|
|
190
|
+
isForum: chat.isForum ?? false,
|
|
191
191
|
commandBindings: null,
|
|
192
192
|
createdAt: now,
|
|
193
193
|
updatedAt: now
|
|
@@ -197,7 +197,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
197
197
|
type: chat.type,
|
|
198
198
|
title: chat.title ?? null,
|
|
199
199
|
username: chat.username ?? null,
|
|
200
|
-
isForum: chat.
|
|
200
|
+
isForum: chat.isForum ?? false,
|
|
201
201
|
commandBindings: null,
|
|
202
202
|
createdAt: now,
|
|
203
203
|
updatedAt: now
|
|
@@ -207,7 +207,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
207
207
|
type: chat.type,
|
|
208
208
|
title: chat.title ?? null,
|
|
209
209
|
username: chat.username ?? null,
|
|
210
|
-
isForum: chat.
|
|
210
|
+
isForum: chat.isForum ?? false,
|
|
211
211
|
updatedAt: now
|
|
212
212
|
}).check());
|
|
213
213
|
chatSummaries.set(id, {
|
|
@@ -215,7 +215,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
215
215
|
type: chat.type,
|
|
216
216
|
title: chat.title ?? null,
|
|
217
217
|
username: chat.username ?? null,
|
|
218
|
-
isForum: chat.
|
|
218
|
+
isForum: chat.isForum ?? false,
|
|
219
219
|
updatedAt: now
|
|
220
220
|
});
|
|
221
221
|
}
|
|
@@ -228,39 +228,39 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
228
228
|
uow.create("user", {
|
|
229
229
|
id,
|
|
230
230
|
username: user.username ?? null,
|
|
231
|
-
firstName: user.
|
|
232
|
-
lastName: user.
|
|
233
|
-
isBot: user.
|
|
234
|
-
languageCode: user.
|
|
231
|
+
firstName: user.firstName,
|
|
232
|
+
lastName: user.lastName ?? null,
|
|
233
|
+
isBot: user.isBot ?? false,
|
|
234
|
+
languageCode: user.languageCode ?? null,
|
|
235
235
|
createdAt: now,
|
|
236
236
|
updatedAt: now
|
|
237
237
|
});
|
|
238
238
|
userSummaries.set(id, {
|
|
239
239
|
id,
|
|
240
240
|
username: user.username ?? null,
|
|
241
|
-
firstName: user.
|
|
242
|
-
lastName: user.
|
|
243
|
-
isBot: user.
|
|
244
|
-
languageCode: user.
|
|
241
|
+
firstName: user.firstName,
|
|
242
|
+
lastName: user.lastName ?? null,
|
|
243
|
+
isBot: user.isBot ?? false,
|
|
244
|
+
languageCode: user.languageCode ?? null,
|
|
245
245
|
createdAt: now,
|
|
246
246
|
updatedAt: now
|
|
247
247
|
});
|
|
248
248
|
} else {
|
|
249
249
|
uow.update("user", existing.id, (b) => b.set({
|
|
250
250
|
username: user.username ?? null,
|
|
251
|
-
firstName: user.
|
|
252
|
-
lastName: user.
|
|
253
|
-
isBot: user.
|
|
254
|
-
languageCode: user.
|
|
251
|
+
firstName: user.firstName,
|
|
252
|
+
lastName: user.lastName ?? null,
|
|
253
|
+
isBot: user.isBot ?? false,
|
|
254
|
+
languageCode: user.languageCode ?? null,
|
|
255
255
|
updatedAt: now
|
|
256
256
|
}).check());
|
|
257
257
|
userSummaries.set(id, {
|
|
258
258
|
...toUserSummary(existing),
|
|
259
259
|
username: user.username ?? null,
|
|
260
|
-
firstName: user.
|
|
261
|
-
lastName: user.
|
|
262
|
-
isBot: user.
|
|
263
|
-
languageCode: user.
|
|
260
|
+
firstName: user.firstName,
|
|
261
|
+
lastName: user.lastName ?? null,
|
|
262
|
+
isBot: user.isBot ?? false,
|
|
263
|
+
languageCode: user.languageCode ?? null,
|
|
264
264
|
updatedAt: now
|
|
265
265
|
});
|
|
266
266
|
}
|
|
@@ -334,6 +334,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
334
334
|
replyToMessageId,
|
|
335
335
|
messageType: type,
|
|
336
336
|
text: message.text ?? null,
|
|
337
|
+
attachments,
|
|
337
338
|
payload: message,
|
|
338
339
|
sentAt,
|
|
339
340
|
editedAt,
|
|
@@ -361,6 +362,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
361
362
|
replyToMessageId: existingMessage.replyToMessageId ? String(existingMessage.replyToMessageId.valueOf()) : null,
|
|
362
363
|
messageType: type,
|
|
363
364
|
text: message.text ?? existingMessage.text,
|
|
365
|
+
attachments,
|
|
364
366
|
payload: message,
|
|
365
367
|
sentAt: existingMessage.sentAt,
|
|
366
368
|
editedAt: editedAt ?? existingMessage.editedAt,
|
|
@@ -373,7 +375,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
373
375
|
type: message.chat.type,
|
|
374
376
|
title: message.chat.title ?? null,
|
|
375
377
|
username: message.chat.username ?? null,
|
|
376
|
-
isForum: message.chat.
|
|
378
|
+
isForum: message.chat.isForum ?? false,
|
|
377
379
|
commandBindings: null,
|
|
378
380
|
createdAt: now,
|
|
379
381
|
updatedAt: now
|
|
@@ -409,6 +411,7 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
409
411
|
chatId,
|
|
410
412
|
fromUserId,
|
|
411
413
|
text: message.text ?? null,
|
|
414
|
+
attachments,
|
|
412
415
|
commandName,
|
|
413
416
|
sentAt: messageSummary.sentAt,
|
|
414
417
|
editedAt: messageSummary.editedAt
|
|
@@ -432,13 +435,13 @@ const createProcessIncomingUpdateOps = (config) => {
|
|
|
432
435
|
const createUpsertOutgoingMessageOps = (input) => {
|
|
433
436
|
const { message, messageType } = input;
|
|
434
437
|
const chatId = String(message.chat.id);
|
|
435
|
-
const senderChatId = message.
|
|
438
|
+
const senderChatId = message.senderChat ? String(message.senderChat.id) : null;
|
|
436
439
|
const fromUser = message.from ?? null;
|
|
437
440
|
const fromUserId = fromUser ? String(fromUser.id) : null;
|
|
438
|
-
const messageId = buildMessageId(chatId, message.
|
|
439
|
-
const replyToMessageId = message.
|
|
441
|
+
const messageId = buildMessageId(chatId, message.messageId);
|
|
442
|
+
const replyToMessageId = message.replyToMessage ? buildMessageId(chatId, message.replyToMessage.messageId) : null;
|
|
440
443
|
const sentAt = /* @__PURE__ */ new Date(message.date * 1e3);
|
|
441
|
-
const editedAt = message.
|
|
444
|
+
const editedAt = message.editDate ? /* @__PURE__ */ new Date(message.editDate * 1e3) : null;
|
|
442
445
|
const chatIds = Array.from(new Set([chatId, senderChatId].filter(Boolean)));
|
|
443
446
|
return {
|
|
444
447
|
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))),
|
|
@@ -446,7 +449,7 @@ const createUpsertOutgoingMessageOps = (input) => {
|
|
|
446
449
|
const now = /* @__PURE__ */ new Date();
|
|
447
450
|
const chatById = new Map(existingChats.map((chat) => [chat.id.valueOf(), chat]));
|
|
448
451
|
const userById = new Map(existingUsers.map((user) => [user.id.valueOf(), user]));
|
|
449
|
-
const chatsForUpsert = [message.chat, message.
|
|
452
|
+
const chatsForUpsert = [message.chat, message.senderChat].filter(Boolean);
|
|
450
453
|
for (const chat of chatsForUpsert) {
|
|
451
454
|
const id = String(chat.id);
|
|
452
455
|
const existing = chatById.get(id);
|
|
@@ -455,7 +458,7 @@ const createUpsertOutgoingMessageOps = (input) => {
|
|
|
455
458
|
type: chat.type,
|
|
456
459
|
title: chat.title ?? null,
|
|
457
460
|
username: chat.username ?? null,
|
|
458
|
-
isForum: chat.
|
|
461
|
+
isForum: chat.isForum ?? false,
|
|
459
462
|
commandBindings: null,
|
|
460
463
|
createdAt: now,
|
|
461
464
|
updatedAt: now
|
|
@@ -464,7 +467,7 @@ const createUpsertOutgoingMessageOps = (input) => {
|
|
|
464
467
|
type: chat.type,
|
|
465
468
|
title: chat.title ?? null,
|
|
466
469
|
username: chat.username ?? null,
|
|
467
|
-
isForum: chat.
|
|
470
|
+
isForum: chat.isForum ?? false,
|
|
468
471
|
updatedAt: now
|
|
469
472
|
}).check());
|
|
470
473
|
}
|
|
@@ -474,19 +477,19 @@ const createUpsertOutgoingMessageOps = (input) => {
|
|
|
474
477
|
if (!existing) uow.create("user", {
|
|
475
478
|
id,
|
|
476
479
|
username: fromUser.username ?? null,
|
|
477
|
-
firstName: fromUser.
|
|
478
|
-
lastName: fromUser.
|
|
479
|
-
isBot: fromUser.
|
|
480
|
-
languageCode: fromUser.
|
|
480
|
+
firstName: fromUser.firstName,
|
|
481
|
+
lastName: fromUser.lastName ?? null,
|
|
482
|
+
isBot: fromUser.isBot ?? false,
|
|
483
|
+
languageCode: fromUser.languageCode ?? null,
|
|
481
484
|
createdAt: now,
|
|
482
485
|
updatedAt: now
|
|
483
486
|
});
|
|
484
487
|
else uow.update("user", existing.id, (b) => b.set({
|
|
485
488
|
username: fromUser.username ?? null,
|
|
486
|
-
firstName: fromUser.
|
|
487
|
-
lastName: fromUser.
|
|
488
|
-
isBot: fromUser.
|
|
489
|
-
languageCode: fromUser.
|
|
489
|
+
firstName: fromUser.firstName,
|
|
490
|
+
lastName: fromUser.lastName ?? null,
|
|
491
|
+
isBot: fromUser.isBot ?? false,
|
|
492
|
+
languageCode: fromUser.languageCode ?? null,
|
|
490
493
|
updatedAt: now
|
|
491
494
|
}).check());
|
|
492
495
|
}
|