@rubytech/create-realagent-code 0.1.582 → 0.1.584
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/package.json +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts +1 -1
- package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/routine-templates/dist/index.js +5 -1
- package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
- package/payload/platform/lib/routine-templates/src/index.ts +4 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts +269 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.js +351 -0
- package/payload/platform/lib/telegram-managed-bot/dist/index.js.map +1 -0
- package/payload/platform/lib/telegram-managed-bot/src/__tests__/managed-bot.test.ts +251 -0
- package/payload/platform/lib/telegram-managed-bot/src/index.ts +529 -0
- package/payload/platform/lib/telegram-managed-bot/tsconfig.json +9 -0
- package/payload/platform/lib/telegram-managed-bot/vitest.config.ts +9 -0
- package/payload/platform/lib/telegram-reach/dist/index.d.ts +86 -0
- package/payload/platform/lib/telegram-reach/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/telegram-reach/dist/index.js +246 -0
- package/payload/platform/lib/telegram-reach/dist/index.js.map +1 -0
- package/payload/platform/lib/telegram-reach/src/__tests__/telegram-reach.test.ts +268 -0
- package/payload/platform/lib/telegram-reach/src/index.ts +296 -0
- package/payload/platform/lib/telegram-reach/tsconfig.json +9 -0
- package/payload/platform/lib/telegram-reach/vitest.config.ts +9 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +9 -0
- package/payload/platform/plugins/admin/hooks/__tests__/preference-consult-directive.test.sh +26 -0
- package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +20 -3
- package/payload/platform/plugins/admin/hooks/preference-consult-directive.sh +50 -5
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +146 -8
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +16 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js +100 -0
- package/payload/platform/plugins/contacts/mcp/dist/__tests__/telegram-user-id.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js +11 -5
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +5 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +21 -4
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +5 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +29 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/vitest.config.ts +14 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +17 -3
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +15 -0
- package/payload/platform/plugins/docs/references/telegram-guide.md +113 -4
- package/payload/platform/plugins/filesystem/PLUGIN.md +2 -2
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js +108 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/__tests__/account-schema.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts +17 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js +162 -0
- package/payload/platform/plugins/filesystem/mcp/dist/lib/account-schema.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts +2 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.d.ts.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js +116 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/__tests__/schema-fence.test.js.map +1 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js +9 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-edit.js.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.d.ts.map +1 -1
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js +10 -0
- package/payload/platform/plugins/filesystem/mcp/dist/tools/file-write.js.map +1 -1
- package/payload/platform/plugins/scheduling/PLUGIN.md +8 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +7 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +53 -6
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +38 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +5 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +18 -3
- package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +30 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +112 -39
- package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +14 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +258 -8
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +206 -3
- package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +29 -21
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +94 -14
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +29 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +30 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +69 -6
- package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +12 -0
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +36 -5
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +103 -10
- package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +42 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +19 -5
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +5 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/instructions.js +13 -0
- package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.d.ts +13 -0
- package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/telegram-channel/dist/notification.js +13 -2
- package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +52 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +64 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +14 -2
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/templates/account-schema/SCHEMA.md +17 -10
- package/payload/platform/templates/agents/admin/IDENTITY.md +5 -0
- package/payload/platform/templates/specialists/agents/data-manager.md +2 -2
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-BFRB2U75.js → chunk-CV6AEMKH.js} +1 -0
- package/payload/server/{manager-CTVTF4YB.js → manager-FQSQSSJ3.js} +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/agents.html +5 -5
- package/payload/server/public/assets/{AdminLoginScreens-AnJZfgFz.js → AdminLoginScreens-BLsDYWVi.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BLsDYWVi.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-CEVqyQqg.js → AdminShell-BZS8jzFA.js} +1 -1
- package/payload/server/public/assets/AdminShell-BZS8jzFA.js.br +0 -0
- package/payload/server/public/assets/AdminShell-BZS8jzFA.js.gz +0 -0
- package/payload/server/public/assets/{activity-czUaUl8I.js → activity-DOjvoLdd.js} +1 -1
- package/payload/server/public/assets/activity-DOjvoLdd.js.br +0 -0
- package/payload/server/public/assets/activity-DOjvoLdd.js.gz +0 -0
- package/payload/server/public/assets/{admin-B0iRcfuk.js → admin-JrSNg29g.js} +1 -1
- package/payload/server/public/assets/admin-JrSNg29g.js.br +0 -0
- package/payload/server/public/assets/admin-JrSNg29g.js.gz +0 -0
- package/payload/server/public/assets/{agents-BocONCeQ.js → agents--9WMJVLC.js} +1 -1
- package/payload/server/public/assets/agents--9WMJVLC.js.br +0 -0
- package/payload/server/public/assets/agents--9WMJVLC.js.gz +0 -0
- package/payload/server/public/assets/{browser-Cy-rJm3t.js → browser-DiiMmTrM.js} +1 -1
- package/payload/server/public/assets/browser-DiiMmTrM.js.br +0 -0
- package/payload/server/public/assets/browser-DiiMmTrM.js.gz +0 -0
- package/payload/server/public/assets/{calendar-DUTKxWtd.js → calendar-CazmCzgO.js} +1 -1
- package/payload/server/public/assets/calendar-CazmCzgO.js.br +0 -0
- package/payload/server/public/assets/calendar-CazmCzgO.js.gz +0 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js +1 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js.br +0 -0
- package/payload/server/public/assets/chat-CB0TcyXX.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-0tVo23Dh.js +1 -0
- package/payload/server/public/assets/chevron-left-0tVo23Dh.js.br +0 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js +1 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js.br +0 -0
- package/payload/server/public/assets/clock-D2cZ0sge.js.gz +0 -0
- package/payload/server/public/assets/{copy-DE9qmAs5.js → copy-C87QIN_o.js} +1 -1
- package/payload/server/public/assets/copy-C87QIN_o.js.br +0 -0
- package/payload/server/public/assets/copy-C87QIN_o.js.gz +0 -0
- package/payload/server/public/assets/data-CK7AMxPt.js +1 -0
- package/payload/server/public/assets/data-CK7AMxPt.js.br +0 -0
- package/payload/server/public/assets/data-CK7AMxPt.js.gz +0 -0
- package/payload/server/public/assets/{field-DE2tEfTo.js → field-C3kQgGWE.js} +1 -1
- package/payload/server/public/assets/field-C3kQgGWE.js.br +0 -0
- package/payload/server/public/assets/field-C3kQgGWE.js.gz +0 -0
- package/payload/server/public/assets/{file-text-BHfL2gqo.js → file-text-rWowl9RN.js} +1 -1
- package/payload/server/public/assets/file-text-rWowl9RN.js.br +0 -0
- package/payload/server/public/assets/file-text-rWowl9RN.js.gz +0 -0
- package/payload/server/public/assets/{graph-08S_BofN.js → graph-CVJKz1Uo.js} +1 -1
- package/payload/server/public/assets/graph-CVJKz1Uo.js.br +0 -0
- package/payload/server/public/assets/graph-CVJKz1Uo.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-C640Er5R.js → graph-labels-kneGnsHB.js} +1 -1
- package/payload/server/public/assets/graph-labels-kneGnsHB.js.br +0 -0
- package/payload/server/public/assets/graph-labels-kneGnsHB.js.gz +0 -0
- package/payload/server/public/assets/{jsx-runtime-FxjwOUbA.css → jsx-runtime-rMaiYjNu.css} +1 -1
- package/payload/server/public/assets/jsx-runtime-rMaiYjNu.css.br +0 -0
- package/payload/server/public/assets/{jsx-runtime-FxjwOUbA.css.gz → jsx-runtime-rMaiYjNu.css.gz} +0 -0
- package/payload/server/public/assets/{operator-DH5Kw3fL.js → operator-BGvB4hu4.js} +1 -1
- package/payload/server/public/assets/operator-BGvB4hu4.js.br +0 -0
- package/payload/server/public/assets/operator-BGvB4hu4.js.gz +0 -0
- package/payload/server/public/assets/{page-BDpa4HWT.js → page-DBQLOasI.js} +1 -1
- package/payload/server/public/assets/page-DBQLOasI.js.br +0 -0
- package/payload/server/public/assets/page-DBQLOasI.js.gz +0 -0
- package/payload/server/public/assets/{page-yn7ivq8O.js → page-DyVAu7tm.js} +1 -1
- package/payload/server/public/assets/page-DyVAu7tm.js.br +0 -0
- package/payload/server/public/assets/page-DyVAu7tm.js.gz +0 -0
- package/payload/server/public/assets/play-DgP7vl0r.js +1 -0
- package/payload/server/public/assets/play-DgP7vl0r.js.br +0 -0
- package/payload/server/public/assets/play-DgP7vl0r.js.gz +0 -0
- package/payload/server/public/assets/{public-D_qjqet7.js → public-BvUQR3hd.js} +1 -1
- package/payload/server/public/assets/public-BvUQR3hd.js.br +0 -0
- package/payload/server/public/assets/public-BvUQR3hd.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-Ixkq1iUA.js → rotate-ccw-Dnn7gbPh.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-Dnn7gbPh.js.gz +0 -0
- package/payload/server/public/assets/{routines-Cxjlmcp7.js → routines-N8NmxPOZ.js} +1 -1
- package/payload/server/public/assets/routines-N8NmxPOZ.js.br +0 -0
- package/payload/server/public/assets/routines-N8NmxPOZ.js.gz +0 -0
- package/payload/server/public/assets/{skills-DEo9hSVX.js → skills-B2CRgO-U.js} +1 -1
- package/payload/server/public/assets/skills-B2CRgO-U.js.br +0 -0
- package/payload/server/public/assets/skills-B2CRgO-U.js.gz +0 -0
- package/payload/server/public/assets/{tasks-BxApOIXI.js → tasks-8QLGtlSj.js} +1 -1
- package/payload/server/public/assets/tasks-8QLGtlSj.js.br +0 -0
- package/payload/server/public/assets/tasks-8QLGtlSj.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-BYzMcXv8.js → triangle-alert-el772yUQ.js} +1 -1
- package/payload/server/public/assets/triangle-alert-el772yUQ.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-el772yUQ.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-Bk2HVcjy.js → useCopyFeedback-DfNAu8hQ.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DfNAu8hQ.js.gz +0 -0
- package/payload/server/public/assets/{useMediaQuery-DEti-vAx.js → useMediaQuery-B469O83-.js} +1 -1
- package/payload/server/public/assets/useMediaQuery-B469O83-.js.br +0 -0
- package/payload/server/public/assets/{useMediaQuery-DEti-vAx.js.gz → useMediaQuery-B469O83-.js.gz} +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-kQ92rL-f.js → useVoiceRecorder-Bb-51cJv.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-Bb-51cJv.js.gz +0 -0
- package/payload/server/public/assets/{wrench-BhLkHffv.js → wrench-Ck4phkdB.js} +1 -1
- package/payload/server/public/assets/wrench-Ck4phkdB.js.br +0 -0
- package/payload/server/public/assets/wrench-Ck4phkdB.js.gz +0 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +8 -8
- package/payload/server/public/chat.html +14 -14
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/field.html +3 -3
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +15 -15
- package/payload/server/public/public.html +14 -14
- package/payload/server/public/routines.html +8 -8
- package/payload/server/public/skills.html +6 -6
- package/payload/server/public/tasks.html +7 -7
- package/payload/server/server.js +3114 -1371
- package/payload/server/public/assets/AdminLoginScreens-AnJZfgFz.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-AnJZfgFz.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-CEVqyQqg.js.br +0 -0
- package/payload/server/public/assets/AdminShell-CEVqyQqg.js.gz +0 -0
- package/payload/server/public/assets/activity-czUaUl8I.js.br +0 -0
- package/payload/server/public/assets/activity-czUaUl8I.js.gz +0 -0
- package/payload/server/public/assets/admin-B0iRcfuk.js.br +0 -0
- package/payload/server/public/assets/admin-B0iRcfuk.js.gz +0 -0
- package/payload/server/public/assets/agents-BocONCeQ.js.br +0 -0
- package/payload/server/public/assets/agents-BocONCeQ.js.gz +0 -0
- package/payload/server/public/assets/browser-Cy-rJm3t.js.br +0 -0
- package/payload/server/public/assets/browser-Cy-rJm3t.js.gz +0 -0
- package/payload/server/public/assets/calendar-DUTKxWtd.js.br +0 -0
- package/payload/server/public/assets/calendar-DUTKxWtd.js.gz +0 -0
- package/payload/server/public/assets/chat-Cis7sHsZ.js +0 -1
- package/payload/server/public/assets/chat-Cis7sHsZ.js.br +0 -0
- package/payload/server/public/assets/chat-Cis7sHsZ.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-Bhhx8j2r.js +0 -1
- package/payload/server/public/assets/chevron-left-Bhhx8j2r.js.br +0 -0
- package/payload/server/public/assets/clock-Ca3nx7Cc.js +0 -1
- package/payload/server/public/assets/clock-Ca3nx7Cc.js.br +0 -0
- package/payload/server/public/assets/clock-Ca3nx7Cc.js.gz +0 -0
- package/payload/server/public/assets/copy-DE9qmAs5.js.br +0 -0
- package/payload/server/public/assets/copy-DE9qmAs5.js.gz +0 -0
- package/payload/server/public/assets/data-CkaAEeP1.js +0 -1
- package/payload/server/public/assets/data-CkaAEeP1.js.br +0 -0
- package/payload/server/public/assets/data-CkaAEeP1.js.gz +0 -0
- package/payload/server/public/assets/field-DE2tEfTo.js.br +0 -0
- package/payload/server/public/assets/field-DE2tEfTo.js.gz +0 -0
- package/payload/server/public/assets/file-text-BHfL2gqo.js.br +0 -0
- package/payload/server/public/assets/file-text-BHfL2gqo.js.gz +0 -0
- package/payload/server/public/assets/graph-08S_BofN.js.br +0 -0
- package/payload/server/public/assets/graph-08S_BofN.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-C640Er5R.js.br +0 -0
- package/payload/server/public/assets/graph-labels-C640Er5R.js.gz +0 -0
- package/payload/server/public/assets/jsx-runtime-FxjwOUbA.css.br +0 -0
- package/payload/server/public/assets/operator-DH5Kw3fL.js.br +0 -0
- package/payload/server/public/assets/operator-DH5Kw3fL.js.gz +0 -0
- package/payload/server/public/assets/page-BDpa4HWT.js.br +0 -0
- package/payload/server/public/assets/page-BDpa4HWT.js.gz +0 -0
- package/payload/server/public/assets/page-yn7ivq8O.js.br +0 -0
- package/payload/server/public/assets/page-yn7ivq8O.js.gz +0 -0
- package/payload/server/public/assets/play-CMN7ht-S.js +0 -1
- package/payload/server/public/assets/play-CMN7ht-S.js.br +0 -0
- package/payload/server/public/assets/play-CMN7ht-S.js.gz +0 -0
- package/payload/server/public/assets/public-D_qjqet7.js.br +0 -0
- package/payload/server/public/assets/public-D_qjqet7.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-Ixkq1iUA.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-Ixkq1iUA.js.gz +0 -0
- package/payload/server/public/assets/routines-Cxjlmcp7.js.br +0 -0
- package/payload/server/public/assets/routines-Cxjlmcp7.js.gz +0 -0
- package/payload/server/public/assets/skills-DEo9hSVX.js.br +0 -0
- package/payload/server/public/assets/skills-DEo9hSVX.js.gz +0 -0
- package/payload/server/public/assets/tasks-BxApOIXI.js.br +0 -0
- package/payload/server/public/assets/tasks-BxApOIXI.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-BYzMcXv8.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-BYzMcXv8.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-Bk2HVcjy.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-Bk2HVcjy.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DEti-vAx.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-kQ92rL-f.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-kQ92rL-f.js.gz +0 -0
- package/payload/server/public/assets/wrench-BhLkHffv.js.br +0 -0
- package/payload/server/public/assets/wrench-BhLkHffv.js.gz +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js → jsx-runtime-BmNepPEn.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js.br → jsx-runtime-BmNepPEn.js.br} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-BL3pljPe.js.gz → jsx-runtime-BmNepPEn.js.gz} +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Task 2618 — Telegram's managed-bot surface, and the webhook registration that
|
|
4
|
+
* a newly provisioned bot needs.
|
|
5
|
+
*
|
|
6
|
+
* This is a shared lib rather than plugin code because BOTH sides need it. The
|
|
7
|
+
* `managed_bot` update lands on the UI webhook route, which must fetch the new
|
|
8
|
+
* bot's token, persist it and register its webhook; the `telegram-bot-provision`
|
|
9
|
+
* MCP tool needs the same four Bot API calls for its own actions. UI production
|
|
10
|
+
* code does not import plugin source, so the alternative was a second copy of
|
|
11
|
+
* `TELEGRAM_ALLOWED_UPDATES` on the UI side — and two lists that must agree, of
|
|
12
|
+
* a set where naming any class replaces Telegram's default, is exactly the drift
|
|
13
|
+
* Task 2612 spent a task fixing.
|
|
14
|
+
*
|
|
15
|
+
* `TELEGRAM_ALLOWED_UPDATES` and `setTelegramWebhook` MOVED here from
|
|
16
|
+
* `plugins/telegram/mcp/src/lib/telegram.ts`, which now re-exports both so every
|
|
17
|
+
* existing plugin import keeps its path.
|
|
18
|
+
*
|
|
19
|
+
* Every name below is quoted from core.telegram.org/bots/api, read 2026-08-09.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.MANAGED_BOT_METHODS = exports.MAX_ADDED_USER_IDS = exports.MANAGED_BOT_REQUEST_ID_MAX = exports.TELEGRAM_ALLOWED_UPDATES = void 0;
|
|
23
|
+
exports.setTelegramWebhook = setTelegramWebhook;
|
|
24
|
+
exports.writeTelegramBotEntry = writeTelegramBotEntry;
|
|
25
|
+
exports.getTelegramWebhookInfo = getTelegramWebhookInfo;
|
|
26
|
+
exports.readTelegramBotEntry = readTelegramBotEntry;
|
|
27
|
+
exports.buildManagedBotRequestKeyboard = buildManagedBotRequestKeyboard;
|
|
28
|
+
exports.getManagedBotToken = getManagedBotToken;
|
|
29
|
+
exports.replaceManagedBotToken = replaceManagedBotToken;
|
|
30
|
+
exports.getManagedBotAccessSettings = getManagedBotAccessSettings;
|
|
31
|
+
exports.setManagedBotAccessSettings = setManagedBotAccessSettings;
|
|
32
|
+
exports.botCanManageBots = botCanManageBots;
|
|
33
|
+
const node_crypto_1 = require("node:crypto");
|
|
34
|
+
const node_fs_1 = require("node:fs");
|
|
35
|
+
const node_path_1 = require("node:path");
|
|
36
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
37
|
+
/**
|
|
38
|
+
* Task 2612 — the update classes this install asks Telegram for.
|
|
39
|
+
*
|
|
40
|
+
* The trap: naming ANY class replaces Telegram's default set, so a class that
|
|
41
|
+
* works today and is missing from this list stops arriving with no error
|
|
42
|
+
* anywhere. Telegram's default is every class except `chat_member`,
|
|
43
|
+
* `message_reaction` and `message_reaction_count`.
|
|
44
|
+
*
|
|
45
|
+
* Task 2618 — `managed_bot` is fifteenth. It IS in Telegram's default set, so it
|
|
46
|
+
* arrives on an install that names nothing; but this install names its list, so
|
|
47
|
+
* omitting it here is the difference between a tapped provisioning button that
|
|
48
|
+
* works and one that silently does nothing.
|
|
49
|
+
*
|
|
50
|
+
* The order is the one Task 2612 states, and the registration test asserts the
|
|
51
|
+
* whole array rather than membership — the failure guarded against is a name
|
|
52
|
+
* silently dropped, which a membership check cannot see.
|
|
53
|
+
*/
|
|
54
|
+
exports.TELEGRAM_ALLOWED_UPDATES = [
|
|
55
|
+
"message",
|
|
56
|
+
"edited_message",
|
|
57
|
+
"callback_query",
|
|
58
|
+
"poll_answer",
|
|
59
|
+
"poll",
|
|
60
|
+
"message_reaction",
|
|
61
|
+
"pre_checkout_query",
|
|
62
|
+
"shipping_query",
|
|
63
|
+
"subscription",
|
|
64
|
+
"my_chat_member",
|
|
65
|
+
"business_connection",
|
|
66
|
+
"business_message",
|
|
67
|
+
"edited_business_message",
|
|
68
|
+
"deleted_business_messages",
|
|
69
|
+
"managed_bot",
|
|
70
|
+
// Task 2616 — the group set. `chat_member` (another member's membership
|
|
71
|
+
// changed, as against `my_chat_member` for the bot's own) and
|
|
72
|
+
// `message_reaction_count` (the anonymous tally that pairs with
|
|
73
|
+
// `message_reaction`) are OUTSIDE Telegram's default, so neither arrives until
|
|
74
|
+
// a bot re-registers. `chat_join_request` and the two boost classes are inside
|
|
75
|
+
// it and are named so that making the list explicit is not itself a regression.
|
|
76
|
+
"chat_member",
|
|
77
|
+
"chat_join_request",
|
|
78
|
+
"message_reaction_count",
|
|
79
|
+
"chat_boost",
|
|
80
|
+
"removed_chat_boost",
|
|
81
|
+
// Task 2617 — the channel pair. Both are INSIDE Telegram's default set, so they
|
|
82
|
+
// would arrive on an install that names nothing; this install names its own
|
|
83
|
+
// list, so they are named here for the reason `chat_join_request` and the two
|
|
84
|
+
// boost classes are — making the list explicit must not itself be a regression.
|
|
85
|
+
//
|
|
86
|
+
// Without them a channel post never reaches the route at all, and the failure is
|
|
87
|
+
// silent: Telegram reports no error for a class it was not asked for.
|
|
88
|
+
"channel_post",
|
|
89
|
+
"edited_channel_post",
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Register a webhook URL with Telegram and generate a cryptographic secret.
|
|
93
|
+
*
|
|
94
|
+
* The secret is generated via crypto.randomBytes (64 hex chars), passed as
|
|
95
|
+
* `secret_token`, and written to disk ONLY after the API confirms success. That
|
|
96
|
+
* order prevents orphaned secret files when the call fails, and avoids
|
|
97
|
+
* overwriting a working secret during a failed re-registration.
|
|
98
|
+
*
|
|
99
|
+
* Telegram sends the secret in the X-Telegram-Bot-Api-Secret-Token header on
|
|
100
|
+
* every delivery; the webhook route validates it before processing.
|
|
101
|
+
*
|
|
102
|
+
* If secretFilePath is omitted, no secret is generated.
|
|
103
|
+
*/
|
|
104
|
+
async function setTelegramWebhook(botToken, webhookUrl, secretFilePath, fetchImpl = fetch) {
|
|
105
|
+
const secret = secretFilePath ? (0, node_crypto_1.randomBytes)(32).toString("hex") : undefined;
|
|
106
|
+
// Task 2612 — `allowed_updates` travels on every registration.
|
|
107
|
+
const body = {
|
|
108
|
+
url: webhookUrl,
|
|
109
|
+
allowed_updates: [...exports.TELEGRAM_ALLOWED_UPDATES],
|
|
110
|
+
};
|
|
111
|
+
if (secret) {
|
|
112
|
+
body.secret_token = secret;
|
|
113
|
+
}
|
|
114
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/setWebhook`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: { "Content-Type": "application/json" },
|
|
117
|
+
body: JSON.stringify(body),
|
|
118
|
+
});
|
|
119
|
+
const data = (await res.json());
|
|
120
|
+
if (!data.ok) {
|
|
121
|
+
return { ok: false, error: data.description ?? "Failed to set webhook" };
|
|
122
|
+
}
|
|
123
|
+
if (secret && secretFilePath) {
|
|
124
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(secretFilePath), { recursive: true });
|
|
125
|
+
(0, node_fs_1.writeFileSync)(secretFilePath, secret, { mode: 0o600 });
|
|
126
|
+
console.error(`[telegram] webhook secret written to ${secretFilePath} (${secret.length} chars)`);
|
|
127
|
+
}
|
|
128
|
+
return { ok: true, secret };
|
|
129
|
+
}
|
|
130
|
+
/** Merge one bot entry into an account's `telegram.bots[]`, replacing any entry
|
|
131
|
+
* with the same id and leaving every other entry and every other key
|
|
132
|
+
* byte-identical.
|
|
133
|
+
*
|
|
134
|
+
* THE single writer of that array. Two callers reach it: the plugin's
|
|
135
|
+
* `persistTelegramBot`, which adds the brand-containment assertion it needs
|
|
136
|
+
* because it resolves this directory from an untrusted `accountId`; and the UI
|
|
137
|
+
* webhook route, which already holds a directory that came from the platform's
|
|
138
|
+
* own account enumeration. A bot registry with two writers is one that
|
|
139
|
+
* eventually disagrees with itself about who is registered.
|
|
140
|
+
*
|
|
141
|
+
* Task 2368's invariant is carried unchanged: registering, re-pointing or
|
|
142
|
+
* rotating one bot cannot disturb another. */
|
|
143
|
+
function writeTelegramBotEntry(accountDir, entry) {
|
|
144
|
+
const configPath = (0, node_path_1.join)(accountDir, "account.json");
|
|
145
|
+
if (!(0, node_fs_1.existsSync)(configPath)) {
|
|
146
|
+
return { ok: false, error: `account.json not found at ${configPath}` };
|
|
147
|
+
}
|
|
148
|
+
let config;
|
|
149
|
+
try {
|
|
150
|
+
config = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
// Refuse rather than overwrite. A file that will not parse holds state this
|
|
154
|
+
// merge cannot preserve, and replacing it would drop every other bot.
|
|
155
|
+
return { ok: false, error: `account.json parse failed: ${e.message}` };
|
|
156
|
+
}
|
|
157
|
+
const telegram = config.telegram ?? {};
|
|
158
|
+
const bots = Array.isArray(telegram.bots) ? telegram.bots : [];
|
|
159
|
+
const at = bots.findIndex((b) => b && typeof b === "object" && b.id === entry.id);
|
|
160
|
+
if (at >= 0)
|
|
161
|
+
bots[at] = entry;
|
|
162
|
+
else
|
|
163
|
+
bots.push(entry);
|
|
164
|
+
telegram.bots = bots;
|
|
165
|
+
config.telegram = telegram;
|
|
166
|
+
(0, node_fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
167
|
+
return { ok: true };
|
|
168
|
+
}
|
|
169
|
+
/** What Telegram says it is currently delivering for this bot.
|
|
170
|
+
*
|
|
171
|
+
* Task 2618 — MOVED here from the plugin, which re-exports it. Three callers
|
|
172
|
+
* now: the plugin's registration probe, the tool's rotate action reading the URL
|
|
173
|
+
* to restore, and the UI's hourly managed-bot census. */
|
|
174
|
+
async function getTelegramWebhookInfo(botToken, fetchImpl = fetch) {
|
|
175
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/getWebhookInfo`);
|
|
176
|
+
const data = (await res.json());
|
|
177
|
+
return {
|
|
178
|
+
url: data.result.url,
|
|
179
|
+
pendingUpdateCount: data.result.pending_update_count,
|
|
180
|
+
lastErrorDate: data.result.last_error_date ?? 0,
|
|
181
|
+
allowedUpdates: data.result.allowed_updates ?? [],
|
|
182
|
+
...(data.result.last_error_message !== undefined
|
|
183
|
+
? { lastErrorMessage: data.result.last_error_message }
|
|
184
|
+
: {}),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/** One stored entry, whole, or null when the account holds no bot with that id.
|
|
188
|
+
*
|
|
189
|
+
* The point is "whole". `listRegisteredBots` returns `{ id, role, agent }` for
|
|
190
|
+
* the callers that only need to name a bot, and a rotation that spread THAT into
|
|
191
|
+
* the writer would silently drop `adminUsers`, `dmPolicy`, `allowFrom` and
|
|
192
|
+
* `managed` — replacing a token would quietly un-admit every admin on the bot.
|
|
193
|
+
* A rotation changes one field and must carry the rest through untouched. */
|
|
194
|
+
function readTelegramBotEntry(accountDir, botId) {
|
|
195
|
+
const configPath = (0, node_path_1.join)(accountDir, "account.json");
|
|
196
|
+
if (!(0, node_fs_1.existsSync)(configPath))
|
|
197
|
+
return null;
|
|
198
|
+
try {
|
|
199
|
+
const config = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
|
|
200
|
+
const bots = config.telegram?.bots;
|
|
201
|
+
if (!Array.isArray(bots))
|
|
202
|
+
return null;
|
|
203
|
+
return bots.find((b) => b && typeof b === "object" && b.id === botId) ?? null;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** The largest `request_id` Telegram accepts: it is a signed 32-bit integer. */
|
|
210
|
+
exports.MANAGED_BOT_REQUEST_ID_MAX = 2_147_483_647;
|
|
211
|
+
/** The one reply keyboard this install builds: a single button asking the user to
|
|
212
|
+
* create a bot for this bot to manage.
|
|
213
|
+
*
|
|
214
|
+
* Shared because both doors send it — the MCP tool's `offer` action and, if a
|
|
215
|
+
* later caller needs it, the UI's own outbound. One builder, because a button
|
|
216
|
+
* whose `request_id` is built two ways is a button whose answer cannot be
|
|
217
|
+
* correlated.
|
|
218
|
+
*
|
|
219
|
+
* One button in one row: `request_id` must be "unique within the message" and
|
|
220
|
+
* nothing here has a reason to send two at once. `one_time_keyboard` so it
|
|
221
|
+
* disappears once tapped rather than sitting in the operator's chat. */
|
|
222
|
+
function buildManagedBotRequestKeyboard(input) {
|
|
223
|
+
if (!Number.isInteger(input.requestId) ||
|
|
224
|
+
input.requestId < 1 ||
|
|
225
|
+
input.requestId > exports.MANAGED_BOT_REQUEST_ID_MAX) {
|
|
226
|
+
// Refused here, not by Telegram: Telegram rejects the send with a description
|
|
227
|
+
// that never names the field, so the operator would see a failed offer and no
|
|
228
|
+
// reason for it.
|
|
229
|
+
throw new Error(`request_id ${input.requestId} is not a positive signed 32-bit integer, which is what Telegram requires`);
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
keyboard: [
|
|
233
|
+
[
|
|
234
|
+
{
|
|
235
|
+
text: input.text,
|
|
236
|
+
request_managed_bot: {
|
|
237
|
+
request_id: input.requestId,
|
|
238
|
+
...(input.suggestedName !== undefined ? { suggested_name: input.suggestedName } : {}),
|
|
239
|
+
...(input.suggestedUsername !== undefined
|
|
240
|
+
? { suggested_username: input.suggestedUsername }
|
|
241
|
+
: {}),
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
],
|
|
246
|
+
one_time_keyboard: true,
|
|
247
|
+
resize_keyboard: true,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/** Telegram caps `added_user_ids` at ten. Refused locally so the cap is named,
|
|
251
|
+
* rather than surfacing as an opaque API error with no number in it. */
|
|
252
|
+
exports.MAX_ADDED_USER_IDS = 10;
|
|
253
|
+
/** The four Bot API methods this module owns, keyed by the action that uses each.
|
|
254
|
+
* Read by the plugin's `OWNED_METHODS` census and by its `api-guard` refusals,
|
|
255
|
+
* so neither can disagree with this module about what it covers. */
|
|
256
|
+
exports.MANAGED_BOT_METHODS = Object.freeze({
|
|
257
|
+
token: "getManagedBotToken",
|
|
258
|
+
rotate: "replaceManagedBotToken",
|
|
259
|
+
accessRead: "getManagedBotAccessSettings",
|
|
260
|
+
accessWrite: "setManagedBotAccessSettings",
|
|
261
|
+
});
|
|
262
|
+
async function call(botToken, method, body, fetchImpl) {
|
|
263
|
+
try {
|
|
264
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/${method}`, {
|
|
265
|
+
method: "POST",
|
|
266
|
+
headers: { "Content-Type": "application/json" },
|
|
267
|
+
body: JSON.stringify(body),
|
|
268
|
+
});
|
|
269
|
+
const data = (await res.json());
|
|
270
|
+
if (!data.ok)
|
|
271
|
+
return { ok: false, error: data.description ?? `${method} failed` };
|
|
272
|
+
return { ok: true, result: data.result };
|
|
273
|
+
}
|
|
274
|
+
catch (e) {
|
|
275
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** "Use this method to get the token of a managed bot. Returns the token as
|
|
279
|
+
* String on success." `userId` is the MANAGED bot's own user id, which is also
|
|
280
|
+
* the numeric prefix of the token this returns.
|
|
281
|
+
*
|
|
282
|
+
* The token is a credential. Every caller persists it and nothing logs it. */
|
|
283
|
+
async function getManagedBotToken(managingBotToken, userId, fetchImpl = fetch) {
|
|
284
|
+
const r = await call(managingBotToken, exports.MANAGED_BOT_METHODS.token, { user_id: userId }, fetchImpl);
|
|
285
|
+
if (!r.ok)
|
|
286
|
+
return r;
|
|
287
|
+
return typeof r.result === "string"
|
|
288
|
+
? { ok: true, token: r.result }
|
|
289
|
+
: { ok: false, error: "no-token-in-result" };
|
|
290
|
+
}
|
|
291
|
+
/** "Use this method to revoke the current token of a managed bot and generate a
|
|
292
|
+
* new one. Returns the new token as String on success."
|
|
293
|
+
*
|
|
294
|
+
* The bot's user id is unchanged by a rotation, so the new token has the same
|
|
295
|
+
* numeric prefix and the bot keys on nothing new. */
|
|
296
|
+
async function replaceManagedBotToken(managingBotToken, userId, fetchImpl = fetch) {
|
|
297
|
+
const r = await call(managingBotToken, exports.MANAGED_BOT_METHODS.rotate, { user_id: userId }, fetchImpl);
|
|
298
|
+
if (!r.ok)
|
|
299
|
+
return r;
|
|
300
|
+
return typeof r.result === "string"
|
|
301
|
+
? { ok: true, token: r.result }
|
|
302
|
+
: { ok: false, error: "no-token-in-result" };
|
|
303
|
+
}
|
|
304
|
+
/** "Returns a BotAccessSettings object on success." */
|
|
305
|
+
async function getManagedBotAccessSettings(managingBotToken, userId, fetchImpl = fetch) {
|
|
306
|
+
const r = await call(managingBotToken, exports.MANAGED_BOT_METHODS.accessRead, { user_id: userId }, fetchImpl);
|
|
307
|
+
if (!r.ok)
|
|
308
|
+
return r;
|
|
309
|
+
const s = r.result;
|
|
310
|
+
return {
|
|
311
|
+
ok: true,
|
|
312
|
+
isAccessRestricted: s?.is_access_restricted === true,
|
|
313
|
+
addedUserIds: (s?.added_users ?? [])
|
|
314
|
+
.map((u) => u?.id)
|
|
315
|
+
.filter((id) => typeof id === "number"),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/** "Use this method to change the access settings of a managed bot. Returns True
|
|
319
|
+
* on success." `addedUserIds` is "Ignored if is_access_restricted is False",
|
|
320
|
+
* which is Telegram's behaviour and is not re-implemented here. */
|
|
321
|
+
async function setManagedBotAccessSettings(managingBotToken, userId, isAccessRestricted, addedUserIds, fetchImpl = fetch) {
|
|
322
|
+
if (addedUserIds && addedUserIds.length > exports.MAX_ADDED_USER_IDS) {
|
|
323
|
+
return { ok: false, error: "too-many-added-user-ids" };
|
|
324
|
+
}
|
|
325
|
+
const r = await call(managingBotToken, exports.MANAGED_BOT_METHODS.accessWrite, {
|
|
326
|
+
user_id: userId,
|
|
327
|
+
is_access_restricted: isAccessRestricted,
|
|
328
|
+
...(addedUserIds ? { added_user_ids: addedUserIds } : {}),
|
|
329
|
+
}, fetchImpl);
|
|
330
|
+
return r.ok ? { ok: true } : { ok: false, error: r.error };
|
|
331
|
+
}
|
|
332
|
+
/** The managing bot's own `getMe`, for the one field that gates provisioning.
|
|
333
|
+
* A bot without `can_manage_bots` cannot offer the request button at all, and
|
|
334
|
+
* the switch lives in the @BotFather Mini App rather than behind any API call. */
|
|
335
|
+
async function botCanManageBots(botToken, fetchImpl = fetch) {
|
|
336
|
+
try {
|
|
337
|
+
const res = await fetchImpl(`${TELEGRAM_API}/bot${botToken}/getMe`);
|
|
338
|
+
const data = (await res.json());
|
|
339
|
+
if (!data.ok)
|
|
340
|
+
return { ok: false, error: data.description ?? "getMe failed" };
|
|
341
|
+
return {
|
|
342
|
+
ok: true,
|
|
343
|
+
canManageBots: data.result?.can_manage_bots === true,
|
|
344
|
+
username: data.result?.username ?? "unknown",
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import {
|
|
6
|
+
TELEGRAM_ALLOWED_UPDATES,
|
|
7
|
+
setTelegramWebhook,
|
|
8
|
+
getManagedBotToken,
|
|
9
|
+
replaceManagedBotToken,
|
|
10
|
+
getManagedBotAccessSettings,
|
|
11
|
+
setManagedBotAccessSettings,
|
|
12
|
+
MANAGED_BOT_METHODS,
|
|
13
|
+
MAX_ADDED_USER_IDS,
|
|
14
|
+
writeTelegramBotEntry,
|
|
15
|
+
} from "../index.js";
|
|
16
|
+
|
|
17
|
+
/** One captured request: the method name off the URL, and the parsed JSON body. */
|
|
18
|
+
interface Captured {
|
|
19
|
+
method: string;
|
|
20
|
+
body: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function stub(result: unknown, captured: Captured[] = [], ok = true) {
|
|
24
|
+
return (async (url: string | URL, init?: RequestInit) => {
|
|
25
|
+
const u = String(url);
|
|
26
|
+
captured.push({
|
|
27
|
+
method: u.slice(u.lastIndexOf("/") + 1),
|
|
28
|
+
body: init?.body ? JSON.parse(String(init.body)) : {},
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
json: async () => (ok ? { ok: true, result } : { ok: false, description: "nope" }),
|
|
32
|
+
} as Response;
|
|
33
|
+
}) as unknown as typeof fetch;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("TELEGRAM_ALLOWED_UPDATES", () => {
|
|
37
|
+
// Asserted as the WHOLE array, not membership. Naming any class replaces
|
|
38
|
+
// Telegram's default set, so a name silently dropped stops that class arriving
|
|
39
|
+
// with no error anywhere, and a membership check cannot see a deletion.
|
|
40
|
+
// This is the THIRD site asserting this one array, after the plugin's
|
|
41
|
+
// webhook-register test and the UI's provisioning-arm test. It went stale
|
|
42
|
+
// without anybody noticing: the group work took the list from fifteen names to
|
|
43
|
+
// twenty and left this expectation at fifteen, and nothing caught it because no
|
|
44
|
+
// gate runs this lib's suite. Whoever changes the constant next must change
|
|
45
|
+
// three expectations, and only two of them are reachable from a `npm test` in
|
|
46
|
+
// platform/ui.
|
|
47
|
+
it("is the twenty-two names, in order", () => {
|
|
48
|
+
expect([...TELEGRAM_ALLOWED_UPDATES]).toEqual([
|
|
49
|
+
"message",
|
|
50
|
+
"edited_message",
|
|
51
|
+
"callback_query",
|
|
52
|
+
"poll_answer",
|
|
53
|
+
"poll",
|
|
54
|
+
"message_reaction",
|
|
55
|
+
"pre_checkout_query",
|
|
56
|
+
"shipping_query",
|
|
57
|
+
"subscription",
|
|
58
|
+
"my_chat_member",
|
|
59
|
+
"business_connection",
|
|
60
|
+
"business_message",
|
|
61
|
+
"edited_business_message",
|
|
62
|
+
"deleted_business_messages",
|
|
63
|
+
"managed_bot",
|
|
64
|
+
// the group set
|
|
65
|
+
"chat_member",
|
|
66
|
+
"chat_join_request",
|
|
67
|
+
"message_reaction_count",
|
|
68
|
+
"chat_boost",
|
|
69
|
+
"removed_chat_boost",
|
|
70
|
+
// the channel pair
|
|
71
|
+
"channel_post",
|
|
72
|
+
"edited_channel_post",
|
|
73
|
+
]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("carries managed_bot, without which no provisioning update ever arrives", () => {
|
|
77
|
+
expect(TELEGRAM_ALLOWED_UPDATES).toContain("managed_bot");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("setTelegramWebhook", () => {
|
|
82
|
+
it("sends the whole allowed_updates array", async () => {
|
|
83
|
+
const cap: Captured[] = [];
|
|
84
|
+
const r = await setTelegramWebhook("111:AAA", "https://x/api/telegram/", undefined, stub(true, cap));
|
|
85
|
+
expect(r.ok).toBe(true);
|
|
86
|
+
expect(cap[0]?.method).toBe("setWebhook");
|
|
87
|
+
expect(cap[0]?.body.allowed_updates).toEqual([...TELEGRAM_ALLOWED_UPDATES]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("writes the secret only after Telegram confirms", async () => {
|
|
91
|
+
const dir = mkdtempSync(join(tmpdir(), "mb-"));
|
|
92
|
+
const path = join(dir, "111");
|
|
93
|
+
await setTelegramWebhook("111:AAA", "https://x/api/telegram/", path, stub(true));
|
|
94
|
+
expect(readFileSync(path, "utf-8")).toHaveLength(64);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("getManagedBotToken", () => {
|
|
99
|
+
it("asks for the named managed bot and returns its token", async () => {
|
|
100
|
+
const cap: Captured[] = [];
|
|
101
|
+
const r = await getManagedBotToken("111:AAA", 999, stub("999:NEWTOKEN", cap));
|
|
102
|
+
expect(cap[0]?.method).toBe("getManagedBotToken");
|
|
103
|
+
expect(cap[0]?.body).toEqual({ user_id: 999 });
|
|
104
|
+
expect(r).toEqual({ ok: true, token: "999:NEWTOKEN" });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("reports a Telegram refusal rather than throwing", async () => {
|
|
108
|
+
const r = await getManagedBotToken("111:AAA", 999, stub(null, [], false));
|
|
109
|
+
expect(r).toEqual({ ok: false, error: "nope" });
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("replaceManagedBotToken", () => {
|
|
114
|
+
it("revokes and returns the new token", async () => {
|
|
115
|
+
const cap: Captured[] = [];
|
|
116
|
+
const r = await replaceManagedBotToken("111:AAA", 999, stub("999:ROTATED", cap));
|
|
117
|
+
expect(cap[0]?.method).toBe("replaceManagedBotToken");
|
|
118
|
+
expect(cap[0]?.body).toEqual({ user_id: 999 });
|
|
119
|
+
expect(r).toEqual({ ok: true, token: "999:ROTATED" });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("getManagedBotAccessSettings", () => {
|
|
124
|
+
it("maps Telegram's snake_case into the settings shape", async () => {
|
|
125
|
+
const r = await getManagedBotAccessSettings(
|
|
126
|
+
"111:AAA",
|
|
127
|
+
999,
|
|
128
|
+
stub({ is_access_restricted: true, added_users: [{ id: 7 }, { id: 8 }] }),
|
|
129
|
+
);
|
|
130
|
+
expect(r).toEqual({ ok: true, isAccessRestricted: true, addedUserIds: [7, 8] });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("reads an absent added_users as nobody, not as unknown", async () => {
|
|
134
|
+
const r = await getManagedBotAccessSettings("111:AAA", 999, stub({ is_access_restricted: false }));
|
|
135
|
+
expect(r).toEqual({ ok: true, isAccessRestricted: false, addedUserIds: [] });
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe("setManagedBotAccessSettings", () => {
|
|
140
|
+
it("sends the restriction flag and the id list", async () => {
|
|
141
|
+
const cap: Captured[] = [];
|
|
142
|
+
const r = await setManagedBotAccessSettings("111:AAA", 999, true, [7, 8], stub(true, cap));
|
|
143
|
+
expect(r.ok).toBe(true);
|
|
144
|
+
expect(cap[0]?.method).toBe("setManagedBotAccessSettings");
|
|
145
|
+
expect(cap[0]?.body).toEqual({ user_id: 999, is_access_restricted: true, added_user_ids: [7, 8] });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("omits added_user_ids when none were given", async () => {
|
|
149
|
+
const cap: Captured[] = [];
|
|
150
|
+
await setManagedBotAccessSettings("111:AAA", 999, true, undefined, stub(true, cap));
|
|
151
|
+
expect(cap[0]?.body).toEqual({ user_id: 999, is_access_restricted: true });
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Telegram documents "up to 10". Refusing locally names the cap; letting
|
|
155
|
+
// Telegram refuse would surface as an opaque API error with no number in it.
|
|
156
|
+
it("refuses more than ten ids before calling Telegram", async () => {
|
|
157
|
+
const cap: Captured[] = [];
|
|
158
|
+
const r = await setManagedBotAccessSettings(
|
|
159
|
+
"111:AAA",
|
|
160
|
+
999,
|
|
161
|
+
true,
|
|
162
|
+
Array.from({ length: MAX_ADDED_USER_IDS + 1 }, (_, i) => i + 1),
|
|
163
|
+
stub(true, cap),
|
|
164
|
+
);
|
|
165
|
+
expect(r).toEqual({ ok: false, error: "too-many-added-user-ids" });
|
|
166
|
+
expect(cap).toHaveLength(0);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The single writer of `telegram.bots[]`.
|
|
172
|
+
*
|
|
173
|
+
* Both callers reach it: the plugin's `persistTelegramBot`, which adds the
|
|
174
|
+
* brand-containment assertion it needs because it resolves the directory from an
|
|
175
|
+
* untrusted accountId, and the UI webhook route, which already holds a directory
|
|
176
|
+
* that came from the platform's own account enumeration. One implementation of
|
|
177
|
+
* the array merge, because a bot registry with two writers is a bot registry that
|
|
178
|
+
* eventually disagrees with itself about who is registered.
|
|
179
|
+
*/
|
|
180
|
+
describe("writeTelegramBotEntry", () => {
|
|
181
|
+
function accountDir(existing?: unknown): string {
|
|
182
|
+
const dir = mkdtempSync(join(tmpdir(), "acct-"));
|
|
183
|
+
writeFileSync(
|
|
184
|
+
join(dir, "account.json"),
|
|
185
|
+
JSON.stringify(existing ?? { accountId: "a", telegram: {} }),
|
|
186
|
+
);
|
|
187
|
+
return dir;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const read = (dir: string) => JSON.parse(readFileSync(join(dir, "account.json"), "utf-8"));
|
|
191
|
+
|
|
192
|
+
it("appends an unbound entry to an account holding none", () => {
|
|
193
|
+
const dir = accountDir();
|
|
194
|
+
expect(writeTelegramBotEntry(dir, { id: "999", token: "999:C", role: "unbound" })).toEqual({
|
|
195
|
+
ok: true,
|
|
196
|
+
});
|
|
197
|
+
expect(read(dir).telegram.bots).toEqual([{ id: "999", token: "999:C", role: "unbound" }]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Task 2368's invariant, carried over: registering or re-pointing one bot
|
|
201
|
+
// cannot disturb another.
|
|
202
|
+
it("replaces only the entry with the same id, leaving every other byte-identical", () => {
|
|
203
|
+
const dir = accountDir({
|
|
204
|
+
accountId: "a",
|
|
205
|
+
telegram: {
|
|
206
|
+
bots: [
|
|
207
|
+
{ id: "111", token: "111:A", role: "admin", adminUsers: [42] },
|
|
208
|
+
{ id: "999", token: "999:OLD", role: "unbound" },
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
writeTelegramBotEntry(dir, { id: "999", token: "999:NEW", role: "unbound" });
|
|
213
|
+
expect(read(dir).telegram.bots).toEqual([
|
|
214
|
+
{ id: "111", token: "111:A", role: "admin", adminUsers: [42] },
|
|
215
|
+
{ id: "999", token: "999:NEW", role: "unbound" },
|
|
216
|
+
]);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("leaves every non-telegram key untouched", () => {
|
|
220
|
+
const dir = accountDir({ accountId: "a", name: "Acme", telegram: {} });
|
|
221
|
+
writeTelegramBotEntry(dir, { id: "999", token: "999:C", role: "unbound" });
|
|
222
|
+
expect(read(dir).name).toBe("Acme");
|
|
223
|
+
expect(read(dir).accountId).toBe("a");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("refuses when there is no account.json to merge into", () => {
|
|
227
|
+
const dir = mkdtempSync(join(tmpdir(), "acct-"));
|
|
228
|
+
expect(writeTelegramBotEntry(dir, { id: "999", token: "999:C", role: "unbound" })).toMatchObject(
|
|
229
|
+
{ ok: false },
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("refuses rather than overwriting when account.json will not parse", () => {
|
|
234
|
+
const dir = mkdtempSync(join(tmpdir(), "acct-"));
|
|
235
|
+
writeFileSync(join(dir, "account.json"), "{ not json");
|
|
236
|
+
const before = readFileSync(join(dir, "account.json"), "utf-8");
|
|
237
|
+
expect(writeTelegramBotEntry(dir, { id: "9", token: "9:C", role: "unbound" }).ok).toBe(false);
|
|
238
|
+
expect(readFileSync(join(dir, "account.json"), "utf-8")).toBe(before);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe("MANAGED_BOT_METHODS", () => {
|
|
243
|
+
it("names the four Bot API methods this module owns", () => {
|
|
244
|
+
expect(Object.values(MANAGED_BOT_METHODS).sort()).toEqual([
|
|
245
|
+
"getManagedBotAccessSettings",
|
|
246
|
+
"getManagedBotToken",
|
|
247
|
+
"replaceManagedBotToken",
|
|
248
|
+
"setManagedBotAccessSettings",
|
|
249
|
+
]);
|
|
250
|
+
});
|
|
251
|
+
});
|