@prajwalshete/telegram-plugin 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +21 -0
  3. package/README.md +109 -2
  4. package/dist/adapters/clock.d.ts +3 -0
  5. package/dist/adapters/clock.js +4 -0
  6. package/dist/adapters/console-log.d.ts +13 -0
  7. package/dist/adapters/console-log.js +41 -0
  8. package/dist/adapters/d1-db.d.ts +5 -0
  9. package/dist/adapters/d1-db.js +37 -0
  10. package/dist/adapters/ids.d.ts +5 -0
  11. package/dist/adapters/ids.js +25 -0
  12. package/dist/adapters/index.d.ts +7 -0
  13. package/dist/adapters/keyring.d.ts +50 -0
  14. package/dist/adapters/keyring.js +174 -0
  15. package/dist/adapters/metrics.d.ts +28 -0
  16. package/dist/adapters/metrics.js +48 -0
  17. package/dist/adapters/r2-files.d.ts +20 -0
  18. package/dist/adapters/r2-files.js +53 -0
  19. package/dist/bin/cli.d.ts +1 -0
  20. package/dist/bin/cli.js +45 -0
  21. package/dist/client/broadcasts.d.ts +35 -0
  22. package/dist/client/commands.d.ts +23 -0
  23. package/dist/client/endpoint.d.ts +34 -0
  24. package/dist/client/events.d.ts +33 -0
  25. package/dist/client/index.d.ts +11 -0
  26. package/dist/client/index.js +3 -0
  27. package/dist/client/schedules.d.ts +42 -0
  28. package/dist/client/schema.d.ts +181 -0
  29. package/dist/client/send.d.ts +15 -0
  30. package/dist/client/templates.d.ts +47 -0
  31. package/dist/contracts/bots.d.ts +129 -0
  32. package/dist/contracts/bots.js +70 -0
  33. package/dist/contracts/broadcasts.d.ts +116 -0
  34. package/dist/contracts/broadcasts.js +63 -0
  35. package/dist/contracts/chats.d.ts +97 -0
  36. package/dist/contracts/chats.js +66 -0
  37. package/dist/contracts/commands.d.ts +52 -0
  38. package/dist/contracts/commands.js +53 -0
  39. package/dist/contracts/common.d.ts +38 -0
  40. package/dist/contracts/common.js +41 -0
  41. package/dist/contracts/deliveries.d.ts +103 -0
  42. package/dist/contracts/deliveries.js +74 -0
  43. package/dist/contracts/destinations.d.ts +24 -0
  44. package/dist/contracts/destinations.js +28 -0
  45. package/dist/contracts/events.d.ts +165 -0
  46. package/dist/contracts/events.js +98 -0
  47. package/dist/contracts/features.d.ts +20 -0
  48. package/dist/contracts/features.js +21 -0
  49. package/dist/contracts/health.d.ts +55 -0
  50. package/dist/contracts/health.js +58 -0
  51. package/dist/contracts/index.d.ts +22 -0
  52. package/dist/contracts/index.js +22 -0
  53. package/dist/contracts/labels.d.ts +38 -0
  54. package/dist/contracts/labels.js +52 -0
  55. package/dist/contracts/links.d.ts +51 -0
  56. package/dist/contracts/links.js +50 -0
  57. package/dist/contracts/meta.d.ts +132 -0
  58. package/dist/contracts/meta.js +85 -0
  59. package/dist/contracts/permissions.d.ts +24 -0
  60. package/dist/contracts/permissions.js +27 -0
  61. package/dist/contracts/problems.d.ts +106 -0
  62. package/dist/contracts/problems.js +101 -0
  63. package/dist/contracts/recipients.d.ts +36 -0
  64. package/dist/contracts/recipients.js +22 -0
  65. package/dist/contracts/schedules.d.ts +276 -0
  66. package/dist/contracts/schedules.js +143 -0
  67. package/dist/contracts/send.d.ts +126 -0
  68. package/dist/contracts/send.js +69 -0
  69. package/dist/contracts/subscriptions.d.ts +38 -0
  70. package/dist/contracts/subscriptions.js +31 -0
  71. package/dist/contracts/templates.d.ts +358 -0
  72. package/dist/contracts/templates.js +174 -0
  73. package/dist/contracts/users.d.ts +15 -0
  74. package/dist/contracts/users.js +19 -0
  75. package/dist/core/guards.d.ts +22 -0
  76. package/dist/core/guards.js +47 -0
  77. package/dist/core/html/escape.d.ts +2 -0
  78. package/dist/core/html/escape.js +36 -0
  79. package/dist/core/html/tokenize.js +65 -0
  80. package/dist/core/index.d.ts +18 -0
  81. package/dist/core/pacing.d.ts +1 -0
  82. package/dist/core/pacing.js +86 -0
  83. package/dist/core/random.d.ts +2 -0
  84. package/dist/core/random.js +38 -0
  85. package/dist/core/recipients.d.ts +1 -0
  86. package/dist/core/recipients.js +86 -0
  87. package/dist/core/schedule/describe.d.ts +3 -0
  88. package/dist/core/schedule/describe.js +74 -0
  89. package/dist/core/schedule/index.d.ts +4 -0
  90. package/dist/core/schedule/policy.d.ts +1 -0
  91. package/dist/core/schedule/policy.js +37 -0
  92. package/dist/core/schedule/rule.d.ts +25 -0
  93. package/dist/core/schedule/rule.js +142 -0
  94. package/dist/core/schedule/tz.d.ts +2 -0
  95. package/dist/core/schedule/tz.js +59 -0
  96. package/dist/core/split/plain.d.ts +2 -0
  97. package/dist/core/split/plain.js +23 -0
  98. package/dist/core/split/split.d.ts +15 -0
  99. package/dist/core/split/split.js +158 -0
  100. package/dist/core/template/ast.d.ts +58 -0
  101. package/dist/core/template/ast.js +5 -0
  102. package/dist/core/template/expr.js +108 -0
  103. package/dist/core/template/filters.d.ts +20 -0
  104. package/dist/core/template/filters.js +127 -0
  105. package/dist/core/template/format.d.ts +17 -0
  106. package/dist/core/template/format.js +88 -0
  107. package/dist/core/template/index.d.ts +20 -0
  108. package/dist/core/template/index.js +29 -0
  109. package/dist/core/template/parse.d.ts +8 -0
  110. package/dist/core/template/parse.js +369 -0
  111. package/dist/core/template/render.d.ts +17 -0
  112. package/dist/core/template/render.js +118 -0
  113. package/dist/core/template/shape.d.ts +28 -0
  114. package/dist/core/template/shape.js +151 -0
  115. package/dist/core/template/tags.js +105 -0
  116. package/dist/core/template/validate.d.ts +10 -0
  117. package/dist/core/template/validate.js +144 -0
  118. package/dist/core/template/variables.d.ts +15 -0
  119. package/dist/core/template/variables.js +41 -0
  120. package/dist/do/index.d.ts +3 -0
  121. package/dist/do/index.js +3 -0
  122. package/dist/do/telegram-bot-do.d.ts +45 -0
  123. package/dist/do/telegram-bot-do.js +219 -0
  124. package/dist/engine/actions/callback.js +256 -0
  125. package/dist/engine/actions/tokens.d.ts +2 -0
  126. package/dist/engine/actions/tokens.js +51 -0
  127. package/dist/engine/bot-api.js +20 -0
  128. package/dist/engine/bot-features.js +39 -0
  129. package/dist/engine/chat-state.js +66 -0
  130. package/dist/engine/content/audience.js +54 -0
  131. package/dist/engine/content/buttons.d.ts +1 -0
  132. package/dist/engine/content/buttons.js +113 -0
  133. package/dist/engine/content/fanout.js +284 -0
  134. package/dist/engine/content/intersect.d.ts +6 -0
  135. package/dist/engine/content/intersect.js +26 -0
  136. package/dist/engine/content/providers.d.ts +6 -0
  137. package/dist/engine/content/providers.js +142 -0
  138. package/dist/engine/content/recipients.js +128 -0
  139. package/dist/engine/content/render.js +138 -0
  140. package/dist/engine/content/reply.js +156 -0
  141. package/dist/engine/content/report-files.js +78 -0
  142. package/dist/engine/content/template-rows.js +74 -0
  143. package/dist/engine/dialogs/dialog.d.ts +2 -0
  144. package/dist/engine/dialogs/dialog.js +375 -0
  145. package/dist/engine/dispatch/builtins.js +198 -0
  146. package/dist/engine/dispatch/commands.js +194 -0
  147. package/dist/engine/dispatch/context.d.ts +2 -0
  148. package/dist/engine/dispatch/context.js +194 -0
  149. package/dist/engine/dispatch/dispatcher.js +66 -0
  150. package/dist/engine/dispatch/handlers.d.ts +1 -0
  151. package/dist/engine/dispatch/handlers.js +103 -0
  152. package/dist/engine/dispatch/lifecycle.js +85 -0
  153. package/dist/engine/dispatch/link-chat.js +31 -0
  154. package/dist/engine/dispatch/linking.js +273 -0
  155. package/dist/engine/errors.d.ts +60 -0
  156. package/dist/engine/errors.js +72 -0
  157. package/dist/engine/events/filters.d.ts +5 -0
  158. package/dist/engine/events/filters.js +82 -0
  159. package/dist/engine/events/kick.js +30 -0
  160. package/dist/engine/events/payload.d.ts +3 -0
  161. package/dist/engine/events/payload.js +16 -0
  162. package/dist/engine/events/tick.js +208 -0
  163. package/dist/engine/i18n.d.ts +12 -0
  164. package/dist/engine/i18n.js +55 -0
  165. package/dist/engine/inbound/files.js +121 -0
  166. package/dist/engine/inbound/handler.js +46 -0
  167. package/dist/engine/jobs.d.ts +32 -0
  168. package/dist/engine/jobs.js +85 -0
  169. package/dist/engine/link-codes.js +46 -0
  170. package/dist/engine/metrics.js +12 -0
  171. package/dist/engine/options.d.ts +369 -0
  172. package/dist/engine/options.js +81 -0
  173. package/dist/engine/outbox/dead-letter.js +78 -0
  174. package/dist/engine/outbox/do-registry.d.ts +10 -0
  175. package/dist/engine/outbox/do-registry.js +10 -0
  176. package/dist/engine/outbox/do-transport.d.ts +33 -0
  177. package/dist/engine/outbox/do-transport.js +73 -0
  178. package/dist/engine/outbox/drain.d.ts +13 -0
  179. package/dist/engine/outbox/drain.js +381 -0
  180. package/dist/engine/outbox/enqueue.d.ts +1 -0
  181. package/dist/engine/outbox/enqueue.js +63 -0
  182. package/dist/engine/outbox/select.js +24 -0
  183. package/dist/engine/outbox/send.js +362 -0
  184. package/dist/engine/outbox/transport.d.ts +35 -0
  185. package/dist/engine/outbox/transport.js +175 -0
  186. package/dist/engine/outbox/wake.js +28 -0
  187. package/dist/engine/registry.d.ts +502 -0
  188. package/dist/engine/registry.js +258 -0
  189. package/dist/engine/rows.d.ts +25 -0
  190. package/dist/engine/rows.js +131 -0
  191. package/dist/engine/runtime.d.ts +95 -0
  192. package/dist/engine/runtime.js +149 -0
  193. package/dist/engine/schedules/fire.js +208 -0
  194. package/dist/engine/schedules/resume.js +75 -0
  195. package/dist/engine/schedules/rows.js +69 -0
  196. package/dist/engine/schedules/tick.js +30 -0
  197. package/dist/engine/schedules/wake.js +50 -0
  198. package/dist/engine/state.d.ts +11 -0
  199. package/dist/engine/state.js +78 -0
  200. package/dist/locales/en.js +339 -0
  201. package/dist/locales/en.json +341 -0
  202. package/dist/locales/mr.js +339 -0
  203. package/dist/locales/mr.json +341 -0
  204. package/dist/ports/db.d.ts +22 -0
  205. package/dist/ports/index.d.ts +4 -0
  206. package/dist/ports/ports.d.ts +257 -0
  207. package/dist/ports/sql.d.ts +39 -0
  208. package/dist/ports/sql.js +76 -0
  209. package/dist/renderers/csv.d.ts +14 -0
  210. package/dist/renderers/csv.js +51 -0
  211. package/dist/renderers/html.d.ts +44 -0
  212. package/dist/renderers/html.js +81 -0
  213. package/dist/renderers/index.d.ts +5 -0
  214. package/dist/renderers/index.js +4 -0
  215. package/dist/renderers/table.d.ts +30 -0
  216. package/dist/renderers/table.js +114 -0
  217. package/dist/routes/admin.js +146 -0
  218. package/dist/routes/app.d.ts +3111 -0
  219. package/dist/routes/app.js +9 -0
  220. package/dist/routes/broadcasts.js +37 -0
  221. package/dist/routes/commands.js +35 -0
  222. package/dist/routes/content.js +12 -0
  223. package/dist/routes/events.js +36 -0
  224. package/dist/routes/http.d.ts +30 -0
  225. package/dist/routes/http.js +223 -0
  226. package/dist/routes/me.js +59 -0
  227. package/dist/routes/schedules.js +62 -0
  228. package/dist/routes/send.js +24 -0
  229. package/dist/routes/templates.js +70 -0
  230. package/dist/routes/webhook.js +147 -0
  231. package/dist/schema/columns.js +307 -0
  232. package/dist/schema/ddl.d.ts +7 -0
  233. package/dist/schema/ddl.js +45 -0
  234. package/dist/schema/index.d.ts +4255 -0
  235. package/dist/schema/index.js +44 -0
  236. package/dist/schema/reference.sql +359 -0
  237. package/dist/schema/tables.d.ts +4243 -0
  238. package/dist/schema/tables.js +327 -0
  239. package/dist/schema/version.d.ts +5 -0
  240. package/dist/schema/version.js +7 -0
  241. package/dist/server/index.d.ts +55 -0
  242. package/dist/server/index.js +46 -0
  243. package/dist/server/plugin.d.ts +81 -0
  244. package/dist/server/plugin.js +247 -0
  245. package/dist/server/version.d.ts +2 -0
  246. package/dist/server/version.js +4 -0
  247. package/dist/services/ai-tool.d.ts +26 -0
  248. package/dist/services/ai-tool.js +148 -0
  249. package/dist/services/bots.js +300 -0
  250. package/dist/services/broadcasts.js +390 -0
  251. package/dist/services/chats.js +83 -0
  252. package/dist/services/cleanup.js +83 -0
  253. package/dist/services/commands.js +140 -0
  254. package/dist/services/deliveries.js +53 -0
  255. package/dist/services/destinations.js +91 -0
  256. package/dist/services/event-rules.js +229 -0
  257. package/dist/services/events.js +20 -0
  258. package/dist/services/idempotency.js +64 -0
  259. package/dist/services/links.js +200 -0
  260. package/dist/services/menu.js +95 -0
  261. package/dist/services/ops.js +90 -0
  262. package/dist/services/rekey.js +63 -0
  263. package/dist/services/reports.js +87 -0
  264. package/dist/services/schedules.js +214 -0
  265. package/dist/services/send.d.ts +14 -0
  266. package/dist/services/send.js +421 -0
  267. package/dist/services/subscriptions.js +28 -0
  268. package/dist/services/templates.js +259 -0
  269. package/dist/telegram/classify.d.ts +30 -0
  270. package/dist/telegram/classify.js +164 -0
  271. package/dist/telegram/client.d.ts +73 -0
  272. package/dist/telegram/client.js +135 -0
  273. package/dist/telegram/errors.d.ts +37 -0
  274. package/dist/telegram/errors.js +62 -0
  275. package/dist/telegram/inbound.d.ts +40 -0
  276. package/dist/telegram/inbound.js +72 -0
  277. package/dist/telegram/index.d.ts +8 -0
  278. package/dist/telegram/multipart.d.ts +5 -0
  279. package/dist/telegram/multipart.js +47 -0
  280. package/dist/telegram/types.d.ts +271 -0
  281. package/dist/telegram/update.d.ts +833 -0
  282. package/dist/telegram/update.js +129 -0
  283. package/dist/testing/fake-html.d.ts +9 -0
  284. package/dist/testing/fake-html.js +83 -0
  285. package/dist/testing/fake-telegram.d.ts +206 -0
  286. package/dist/testing/fake-telegram.js +856 -0
  287. package/dist/testing/index.d.ts +7 -0
  288. package/dist/testing/index.js +7 -0
  289. package/dist/testing/reference-sql.d.ts +4 -0
  290. package/dist/testing/reference-sql.js +8 -0
  291. package/dist/testing/test-plugin.d.ts +126 -0
  292. package/dist/testing/test-plugin.js +182 -0
  293. package/dist/testing/updates.d.ts +100 -0
  294. package/dist/testing/updates.js +212 -0
  295. package/package.json +113 -3
@@ -0,0 +1,327 @@
1
+ import { SCHEMA_VERSION } from "./version.js";
2
+ import { sql } from "drizzle-orm";
3
+ import { index, integer, primaryKey, sqliteTable, text, uniqueIndex } from "drizzle-orm/sqlite-core";
4
+ // src/schema/tables.ts
5
+ /**
6
+ * Drizzle (sqlite-core) definitions of every plugin table (docs/03). The host re-exports them in its schema and
7
+ * generates + commits the migration. Changes are add-only. Flags are INTEGER 0/1, times are epoch ms, JSON is TEXT.
8
+ * Table and index names are fixed (`tg_*`): the runtime's SQL uses these names, so they cannot be renamed.
9
+ */
10
+ function telegramTables() {
11
+ const n = (name) => `tg_${name}`;
12
+ const tenant = () => text("tenant").notNull().default("");
13
+ return {
14
+ tgBot: sqliteTable(n("bot"), {
15
+ id: text("id").primaryKey().notNull(),
16
+ tenant: tenant(),
17
+ name: text("name").notNull(),
18
+ tgBotId: text("tg_bot_id").notNull(),
19
+ username: text("username").notNull(),
20
+ tokenEnc: text("token_enc").notNull(),
21
+ webhookSecretEnc: text("webhook_secret_enc"),
22
+ mode: text("mode").notNull().default("webhook"),
23
+ status: text("status").notNull().default("active"),
24
+ statusDetail: text("status_detail"),
25
+ checkedAt: integer("checked_at"),
26
+ defaultLocale: text("default_locale").notNull().default("en"),
27
+ featuresJson: text("features_json"),
28
+ ratePerSec: integer("rate_per_sec").notNull().default(25),
29
+ pausedUntil: integer("paused_until"),
30
+ drainLeaseUntil: integer("drain_lease_until"),
31
+ drainToken: text("drain_token"),
32
+ commandsSyncedHash: text("commands_synced_hash"),
33
+ createdBy: text("created_by"),
34
+ createdAt: integer("created_at").notNull(),
35
+ updatedAt: integer("updated_at").notNull(),
36
+ deletedAt: integer("deleted_at")
37
+ }, (t) => [index(n("bot_tenant_status_idx")).on(t.tenant, t.status), uniqueIndex(n("bot_tg_bot_uq")).on(t.tenant, t.tgBotId).where(sql`deleted_at IS NULL`)]),
38
+ tgChat: sqliteTable(n("chat"), {
39
+ id: text("id").primaryKey().notNull(),
40
+ tenant: tenant(),
41
+ botId: text("bot_id").notNull(),
42
+ chatId: text("chat_id").notNull(),
43
+ kind: text("kind").notNull(),
44
+ title: text("title"),
45
+ username: text("username"),
46
+ userId: text("user_id"),
47
+ audienceJson: text("audience_json"),
48
+ status: text("status").notNull().default("pending"),
49
+ locale: text("locale"),
50
+ timezone: text("timezone"),
51
+ topicsJson: text("topics_json"),
52
+ nextAllowedAt: integer("next_allowed_at"),
53
+ minuteWindowStart: integer("minute_window_start"),
54
+ minuteCount: integer("minute_count").notNull().default(0),
55
+ linkedBy: text("linked_by"),
56
+ linkedAt: integer("linked_at"),
57
+ createdAt: integer("created_at").notNull(),
58
+ updatedAt: integer("updated_at").notNull()
59
+ }, (t) => [
60
+ uniqueIndex(n("chat_bot_chat_uq")).on(t.tenant, t.botId, t.chatId),
61
+ index(n("chat_user_idx")).on(t.userId),
62
+ index(n("chat_bot_status_idx")).on(t.botId, t.status)
63
+ ]),
64
+ tgLinkCode: sqliteTable(n("link_code"), {
65
+ codeHash: text("code_hash").primaryKey().notNull(),
66
+ tenant: tenant(),
67
+ botId: text("bot_id").notNull(),
68
+ purpose: text("purpose").notNull(),
69
+ userId: text("user_id"),
70
+ audienceJson: text("audience_json"),
71
+ expiresAt: integer("expires_at").notNull(),
72
+ usedAt: integer("used_at"),
73
+ usedByChat: text("used_by_chat"),
74
+ createdBy: text("created_by"),
75
+ createdAt: integer("created_at").notNull()
76
+ }, (t) => [index(n("link_code_expires_idx")).on(t.expiresAt)]),
77
+ tgDestination: sqliteTable(n("destination"), {
78
+ id: text("id").primaryKey().notNull(),
79
+ tenant: tenant(),
80
+ name: text("name").notNull(),
81
+ slug: text("slug").notNull(),
82
+ botId: text("bot_id").notNull(),
83
+ chatRef: text("chat_ref").notNull(),
84
+ messageThreadId: integer("message_thread_id"),
85
+ aiAllowed: integer("ai_allowed").notNull().default(0),
86
+ createdBy: text("created_by"),
87
+ createdAt: integer("created_at").notNull(),
88
+ updatedAt: integer("updated_at").notNull(),
89
+ deletedAt: integer("deleted_at")
90
+ }, (t) => [uniqueIndex(n("destination_slug_uq")).on(t.tenant, t.slug)]),
91
+ tgCommand: sqliteTable(n("command"), {
92
+ tenant: tenant(),
93
+ botId: text("bot_id").notNull(),
94
+ command: text("command").notNull(),
95
+ enabled: integer("enabled").notNull().default(1),
96
+ rolesJson: text("roles_json"),
97
+ aliasesJson: text("aliases_json"),
98
+ descriptionJson: text("description_json"),
99
+ showInMenu: integer("show_in_menu").notNull().default(1),
100
+ sort: integer("sort").notNull().default(0),
101
+ updatedBy: text("updated_by"),
102
+ updatedAt: integer("updated_at").notNull()
103
+ }, (t) => [primaryKey({ columns: [
104
+ t.tenant,
105
+ t.botId,
106
+ t.command
107
+ ] })]),
108
+ tgTemplate: sqliteTable(n("template"), {
109
+ id: text("id").primaryKey().notNull(),
110
+ tenant: tenant(),
111
+ key: text("key").notNull(),
112
+ name: text("name").notNull(),
113
+ kind: text("kind").notNull().default("message"),
114
+ provider: text("provider"),
115
+ providerParamsJson: text("provider_params_json"),
116
+ bodyJson: text("body_json").notNull(),
117
+ format: text("format").notNull().default("html"),
118
+ reportJson: text("report_json"),
119
+ buttonsJson: text("buttons_json"),
120
+ optionsJson: text("options_json"),
121
+ version: integer("version").notNull().default(1),
122
+ createdBy: text("created_by"),
123
+ createdAt: integer("created_at").notNull(),
124
+ updatedBy: text("updated_by"),
125
+ updatedAt: integer("updated_at").notNull(),
126
+ deletedAt: integer("deleted_at")
127
+ }, (t) => [uniqueIndex(n("template_key_uq")).on(t.tenant, t.key)]),
128
+ tgTemplateVersion: sqliteTable(n("template_version"), {
129
+ tenant: tenant(),
130
+ templateId: text("template_id").notNull(),
131
+ version: integer("version").notNull(),
132
+ bodyJson: text("body_json").notNull(),
133
+ reportJson: text("report_json"),
134
+ buttonsJson: text("buttons_json"),
135
+ savedBy: text("saved_by"),
136
+ savedAt: integer("saved_at").notNull()
137
+ }, (t) => [primaryKey({ columns: [t.templateId, t.version] })]),
138
+ tgSubscription: sqliteTable(n("subscription"), {
139
+ tenant: tenant(),
140
+ chatRef: text("chat_ref").notNull(),
141
+ topic: text("topic").notNull(),
142
+ muted: integer("muted").notNull().default(0),
143
+ quietJson: text("quiet_json"),
144
+ updatedAt: integer("updated_at").notNull()
145
+ }, (t) => [primaryKey({ columns: [
146
+ t.tenant,
147
+ t.chatRef,
148
+ t.topic
149
+ ] })]),
150
+ tgSchedule: sqliteTable(n("schedule"), {
151
+ id: text("id").primaryKey().notNull(),
152
+ tenant: tenant(),
153
+ name: text("name").notNull(),
154
+ ruleJson: text("rule_json").notNull(),
155
+ timezone: text("timezone").notNull(),
156
+ templateId: text("template_id").notNull(),
157
+ paramsJson: text("params_json"),
158
+ recipientsJson: text("recipients_json").notNull(),
159
+ personalize: integer("personalize").notNull().default(1),
160
+ missedPolicy: text("missed_policy").notNull().default("run_once"),
161
+ missedGraceMin: integer("missed_grace_min").notNull().default(30),
162
+ enabled: integer("enabled").notNull().default(1),
163
+ pausedUntil: integer("paused_until"),
164
+ nextRunAt: integer("next_run_at"),
165
+ claimUntil: integer("claim_until"),
166
+ claimToken: text("claim_token"),
167
+ lastRunAt: integer("last_run_at"),
168
+ lastStatus: text("last_status"),
169
+ createdBy: text("created_by"),
170
+ createdAt: integer("created_at").notNull(),
171
+ updatedAt: integer("updated_at").notNull(),
172
+ deletedAt: integer("deleted_at")
173
+ }, (t) => [index(n("schedule_due_idx")).on(t.enabled, t.nextRunAt)]),
174
+ tgScheduleRun: sqliteTable(n("schedule_run"), {
175
+ id: text("id").primaryKey().notNull(),
176
+ tenant: tenant(),
177
+ scheduleId: text("schedule_id").notNull(),
178
+ slotAt: integer("slot_at").notNull(),
179
+ trigger: text("trigger").notNull().default("schedule"),
180
+ startedAt: integer("started_at").notNull(),
181
+ finishedAt: integer("finished_at"),
182
+ status: text("status").notNull().default("running"),
183
+ deliveries: integer("deliveries").notNull().default(0),
184
+ error: text("error"),
185
+ templateVersion: integer("template_version")
186
+ }, (t) => [uniqueIndex(n("schedule_run_slot_uq")).on(t.scheduleId, t.slotAt)]),
187
+ tgEventRule: sqliteTable(n("event_rule"), {
188
+ id: text("id").primaryKey().notNull(),
189
+ tenant: tenant(),
190
+ event: text("event").notNull(),
191
+ name: text("name").notNull(),
192
+ filterJson: text("filter_json"),
193
+ templateId: text("template_id").notNull(),
194
+ recipientsJson: text("recipients_json").notNull(),
195
+ throttleJson: text("throttle_json"),
196
+ enabled: integer("enabled").notNull().default(1),
197
+ createdBy: text("created_by"),
198
+ createdAt: integer("created_at").notNull(),
199
+ updatedAt: integer("updated_at").notNull(),
200
+ deletedAt: integer("deleted_at")
201
+ }, (t) => [index(n("event_rule_event_idx")).on(t.tenant, t.event, t.enabled)]),
202
+ tgEvent: sqliteTable(n("event"), {
203
+ id: text("id").primaryKey().notNull(),
204
+ tenant: tenant(),
205
+ event: text("event").notNull(),
206
+ payloadJson: text("payload_json").notNull(),
207
+ dedupeKey: text("dedupe_key").notNull(),
208
+ occurredAt: integer("occurred_at").notNull(),
209
+ status: text("status").notNull().default("pending"),
210
+ attempts: integer("attempts").notNull().default(0),
211
+ claimUntil: integer("claim_until"),
212
+ claimToken: text("claim_token"),
213
+ processedAt: integer("processed_at"),
214
+ error: text("error")
215
+ }, (t) => [uniqueIndex(n("event_dedupe_uq")).on(t.tenant, t.dedupeKey), index(n("event_status_idx")).on(t.status, t.occurredAt)]),
216
+ tgBroadcast: sqliteTable(n("broadcast"), {
217
+ id: text("id").primaryKey().notNull(),
218
+ tenant: tenant(),
219
+ title: text("title").notNull(),
220
+ templateId: text("template_id"),
221
+ bodyJson: text("body_json"),
222
+ paramsJson: text("params_json"),
223
+ fileRef: text("file_ref"),
224
+ recipientsJson: text("recipients_json").notNull(),
225
+ status: text("status").notNull().default("draft"),
226
+ statsJson: text("stats_json"),
227
+ createdBy: text("created_by"),
228
+ createdAt: integer("created_at").notNull(),
229
+ updatedAt: integer("updated_at").notNull(),
230
+ sentAt: integer("sent_at"),
231
+ deletedAt: integer("deleted_at")
232
+ }),
233
+ tgDelivery: sqliteTable(n("delivery"), {
234
+ id: text("id").primaryKey().notNull(),
235
+ tenant: tenant(),
236
+ botId: text("bot_id").notNull(),
237
+ chatRef: text("chat_ref").notNull(),
238
+ messageThreadId: integer("message_thread_id"),
239
+ source: text("source").notNull(),
240
+ sourceId: text("source_id"),
241
+ kind: text("kind").notNull().default("text"),
242
+ bodyHtml: text("body_html"),
243
+ part: integer("part").notNull().default(0),
244
+ parts: integer("parts").notNull().default(1),
245
+ fileRef: text("file_ref"),
246
+ fileName: text("file_name"),
247
+ fileMime: text("file_mime"),
248
+ replyMarkupJson: text("reply_markup_json"),
249
+ optionsJson: text("options_json"),
250
+ /** What to render when `body_html` is still null (template, params, audience, locale). */
251
+ renderJson: text("render_json"),
252
+ /** Target message for `edit` / `delete`. */
253
+ targetMessageId: integer("target_message_id"),
254
+ dedupeKey: text("dedupe_key").notNull(),
255
+ status: text("status").notNull().default("queued"),
256
+ attempts: integer("attempts").notNull().default(0),
257
+ nextAttemptAt: integer("next_attempt_at").notNull(),
258
+ leaseUntil: integer("lease_until"),
259
+ leaseToken: text("lease_token"),
260
+ tgMessageId: integer("tg_message_id"),
261
+ errorCode: text("error_code"),
262
+ errorDetail: text("error_detail"),
263
+ createdAt: integer("created_at").notNull(),
264
+ updatedAt: integer("updated_at").notNull(),
265
+ sentAt: integer("sent_at")
266
+ }, (t) => [
267
+ uniqueIndex(n("delivery_dedupe_uq")).on(t.tenant, t.dedupeKey),
268
+ index(n("delivery_due_idx")).on(t.botId, t.status, t.nextAttemptAt),
269
+ index(n("delivery_source_idx")).on(t.source, t.sourceId)
270
+ ]),
271
+ tgUpdate: sqliteTable(n("update"), {
272
+ tenant: tenant(),
273
+ botId: text("bot_id").notNull(),
274
+ updateId: integer("update_id").notNull(),
275
+ kind: text("kind"),
276
+ chatId: text("chat_id"),
277
+ status: text("status").notNull().default("received"),
278
+ attempts: integer("attempts").notNull().default(0),
279
+ receivedAt: integer("received_at").notNull(),
280
+ processedAt: integer("processed_at"),
281
+ error: text("error")
282
+ }, (t) => [primaryKey({ columns: [t.botId, t.updateId] }), index(n("update_status_idx")).on(t.status, t.receivedAt)]),
283
+ tgActionToken: sqliteTable(n("action_token"), {
284
+ id: text("id").primaryKey().notNull(),
285
+ tenant: tenant(),
286
+ botId: text("bot_id").notNull(),
287
+ action: text("action").notNull(),
288
+ paramsJson: text("params_json"),
289
+ chatRef: text("chat_ref"),
290
+ userId: text("user_id"),
291
+ singleUse: integer("single_use").notNull().default(1),
292
+ confirmedAt: integer("confirmed_at"),
293
+ expiresAt: integer("expires_at").notNull(),
294
+ usedAt: integer("used_at"),
295
+ result: text("result"),
296
+ createdAt: integer("created_at").notNull()
297
+ }, (t) => [index(n("action_token_expires_idx")).on(t.expiresAt)]),
298
+ tgDialog: sqliteTable(n("dialog"), {
299
+ tenant: tenant(),
300
+ chatRef: text("chat_ref").notNull(),
301
+ dialog: text("dialog").notNull(),
302
+ userId: text("user_id"),
303
+ step: text("step").notNull(),
304
+ stateJson: text("state_json").notNull().default("{}"),
305
+ expiresAt: integer("expires_at").notNull(),
306
+ startedAt: integer("started_at").notNull(),
307
+ updatedAt: integer("updated_at").notNull()
308
+ }, (t) => [primaryKey({ columns: [t.tenant, t.chatRef] }), index(n("dialog_expires_idx")).on(t.expiresAt)]),
309
+ tgState: sqliteTable(n("state"), {
310
+ tenant: tenant(),
311
+ key: text("key").notNull(),
312
+ value: text("value").notNull(),
313
+ updatedAt: integer("updated_at").notNull()
314
+ }, (t) => [primaryKey({ columns: [t.tenant, t.key] })]),
315
+ tgAudit: sqliteTable(n("audit"), {
316
+ id: text("id").primaryKey().notNull(),
317
+ tenant: tenant(),
318
+ actor: text("actor"),
319
+ entity: text("entity").notNull(),
320
+ entityId: text("entity_id"),
321
+ action: text("action").notNull(),
322
+ diffJson: text("diff_json"),
323
+ at: integer("at").notNull()
324
+ }, (t) => [index(n("audit_entity_idx")).on(t.entity, t.entityId)])
325
+ };
326
+ }
327
+ export { SCHEMA_VERSION, telegramTables };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Bump when a table or column is added (add-only). `GET /admin/meta` reports it, and the plugin refuses to run on a
3
+ * DB that is behind. Kept free of drizzle-orm so `server` can import it without the optional peer.
4
+ */
5
+ export declare const SCHEMA_VERSION = 2;
@@ -0,0 +1,7 @@
1
+ // src/schema/version.ts
2
+ /**
3
+ * Bump when a table or column is added (add-only). `GET /admin/meta` reports it, and the plugin refuses to run on a
4
+ * DB that is behind. Kept free of drizzle-orm so `server` can import it without the optional peer.
5
+ */
6
+ const SCHEMA_VERSION = 2;
7
+ export { SCHEMA_VERSION };
@@ -0,0 +1,55 @@
1
+ import { CoreTemplateError, TemplateAst } from "../core/template/ast.js";
2
+ import { BUILTIN_FILTERS, FilterDef, FilterFn, FilterRegistry, defineFilter } from "../core/template/filters.js";
3
+ import { SqlFragment, SqlInput, SqlValue, isSqlFragment, sql } from "../ports/sql.js";
4
+ import { DbPort, RunResult } from "../ports/db.js";
5
+ import { TelegramConfigError, TelegramPluginError, TelegramProblemExtensions, featureDisabled, isTelegramPluginError, toPluginError } from "../engine/errors.js";
6
+ import { ActorInfo, ActorPort, AuditEntry, AuditPort, AuthorizePort, ClockPort, ErrorsPort, FilesPort, I18nPort, IdsPort, KeyringPort, LogFields, LogPort, MetricsPort, OpenedFile, PortOrFactory, RenderInput, RenderedFile, RendererPort, SchedulerPort, SettingsPort, StoredFile, TransportPort, UserInfo, UsersPort } from "../ports/ports.js";
7
+ import { ParsedUpdate, TgCallbackQuery, TgChat, TgChatMember, TgChatMemberUpdated, TgDocument, TgForumTopicCreated, TgMessage, TgMessageEntity, TgPhotoSize, TgUpdate, TgUser, parseUpdate } from "../telegram/update.js";
8
+ import { AnswerCallbackQueryParams, BotCommand, BotCommandScope, BotUser, ButtonStyle, ChatAction, ChatFullInfo, ChatId, CommandScopeParams, DeleteMessageParams, DeleteWebhookParams, EditMessageReplyMarkupParams, EditMessageTextParams, ForceReply, GetUpdatesParams, InlineKeyboardButton, InlineKeyboardMarkup, InputFile, InputFileUpload, KeyboardButton, LinkPreviewOptions, MethodName, MethodResults, ParseMode, ReplyKeyboardMarkup, ReplyKeyboardRemove, ReplyMarkup, ReplyParameters, SendChatActionParams, SendDocumentParams, SendMessageParams, SendOptions, SendPhotoParams, SetMyCommandsParams, SetWebhookParams, TgFile, UpdateType, WebhookInfo } from "../telegram/types.js";
9
+ import { BotApi, CallOptions, DEFAULT_TELEGRAM_BASE_URL, DEFAULT_TELEGRAM_TIMEOUT_MS, FetchLike, TelegramClient, TelegramClientOptions, TokenGetter, fetchTelegram } from "../telegram/client.js";
10
+ import { ANY_ROLE, ActionContext, ActionDef, ActionResult, AudienceDef, CommandContext, CommandDef, DialogChoice, DialogDef, DialogFinishContext, DialogStepDef, EventDef, FileSourceContext, FileSourceDef, ProviderContext, ProviderDef, RESERVED_COMMANDS, Registry, ReplyApi, ReplyOptions, defineAction, defineAudience, defineCommand, defineDialog, defineEvent, defineFileSource, defineProvider, definitions } from "../engine/registry.js";
11
+ import { DEFAULT_LIMITS, DEFAULT_RETENTION, FeatureFlags, FreeTextContext, InboundContext, InboundFile, TelegramAiOptions, TelegramCrons, TelegramEnv, TelegramFeaturesInput, TelegramGroupOptions, TelegramHooks, TelegramInboundOptions, TelegramLimits, TelegramLogLevel, TelegramPluginOptions, TelegramPorts, TelegramRetention, TransportChoice } from "../engine/options.js";
12
+ import { Runtime } from "../engine/runtime.js";
13
+ import { BotDoHost, registerTelegramPlugin } from "../engine/outbox/do-registry.js";
14
+ import { DoTransport, botStub, doTransport, isDoTransport } from "../engine/outbox/do-transport.js";
15
+ import { SCHEMA_VERSION } from "../schema/version.js";
16
+ import { systemClock } from "../adapters/clock.js";
17
+ import { consoleLog, redactSecrets, silentLog } from "../adapters/console-log.js";
18
+ import { D1_MAX_PARAMS, d1Db } from "../adapters/d1-db.js";
19
+ import { uuidv7, uuidv7Ids } from "../adapters/ids.js";
20
+ import { AnalyticsEngineLike, AnalyticsEngineMetricsOptions, analyticsEngineMetrics, noopMetrics } from "../adapters/metrics.js";
21
+ import { R2FilesOptions, r2Files } from "../adapters/r2-files.js";
22
+ import { KeyringError, KeyringSecret, WebCryptoKeyring, base64ToBytes, bytesToBase64Url, generateKeyringSecret, kidOfCiphertext, parseKeyringSecret, randomBase64Url, timingSafeEqualStrings, webCryptoKeyring } from "../adapters/keyring.js";
23
+ import { checkAiText } from "../core/guards.js";
24
+ import { escapeHtml } from "../core/html/escape.js";
25
+ import { describeRule } from "../core/schedule/describe.js";
26
+ import { nextRuns, validateRule } from "../core/schedule/rule.js";
27
+ import { isValidTimeZone } from "../core/schedule/tz.js";
28
+ import { toPlainText } from "../core/split/plain.js";
29
+ import { CAPTION_LIMIT, TEXT_LIMIT, splitMessage, visibleLength } from "../core/split/split.js";
30
+ import { validateTemplate } from "../core/template/validate.js";
31
+ import { parseTemplate } from "../core/template/parse.js";
32
+ import { RenderContext, renderTemplate } from "../core/template/render.js";
33
+ import { Shape, shapeVariables, zodToShape } from "../core/template/shape.js";
34
+ import { VariableRef, listVariables } from "../core/template/variables.js";
35
+ import { CompileResult, compileTemplate } from "../core/template/index.js";
36
+ import { ACTION_PREFIX } from "../engine/actions/tokens.js";
37
+ import { ProviderTimeout } from "../engine/content/providers.js";
38
+ import { ParsedCommand, UpdateClass, classifyUpdate, isLifecycleMessage, isValidStartPayload, parseCommand, parseStartPayload, updateChat, updateFrom, updateMessage, updateType } from "../telegram/inbound.js";
39
+ import { untrustedWrap } from "../engine/dispatch/context.js";
40
+ import { DIALOG_PREFIX } from "../engine/dialogs/dialog.js";
41
+ import { matchFilter, matchFilters } from "../engine/events/filters.js";
42
+ import { stripSensitive } from "../engine/events/payload.js";
43
+ import { TelegramJob, TelegramJobContext, TelegramJobResult } from "../engine/jobs.js";
44
+ import { PluginQueueMessage, cronTransport, isPluginMessage, queueTransport } from "../engine/outbox/transport.js";
45
+ import { SchemaState } from "../engine/state.js";
46
+ import { TelegramRoutesApp } from "../routes/app.js";
47
+ import { AiSendKind, AiToolDestination, AiToolSpec } from "../services/ai-tool.js";
48
+ import { intersectData } from "../engine/content/intersect.js";
49
+ import { EnqueueOptions, recordProviderKey } from "../services/send.js";
50
+ import { TelegramOutcome, TelegramOutcomeKind, TelegramOutcomeReason, classifyTelegramError, settle } from "../telegram/classify.js";
51
+ import { TelegramApiError, TelegramNetworkError, isTelegramApiError } from "../telegram/errors.js";
52
+ import { inputFile, isInputFileUpload } from "../telegram/multipart.js";
53
+ import { ExecLike, TelegramPlugin, createTelegramPlugin } from "./plugin.js";
54
+ import { PLUGIN_VERSION } from "./version.js";
55
+ export { ACTION_PREFIX, ANY_ROLE, type ActionContext, type ActionDef, type ActionResult, type ActorInfo, type ActorPort, type AiSendKind, type AiToolDestination, type AiToolSpec, type AnalyticsEngineLike, type AnalyticsEngineMetricsOptions, type AnswerCallbackQueryParams, type AudienceDef, type AuditEntry, type AuditPort, type AuthorizePort, BUILTIN_FILTERS, BotApi, type BotCommand, type BotCommandScope, type BotDoHost, type BotUser, type ButtonStyle, CAPTION_LIMIT, CallOptions, type ChatAction, type ChatFullInfo, type ChatId, type ClockPort, type CommandContext, type CommandDef, type CommandScopeParams, type CompileResult, type CoreTemplateError, D1_MAX_PARAMS, DEFAULT_LIMITS, DEFAULT_RETENTION, DEFAULT_TELEGRAM_BASE_URL, DEFAULT_TELEGRAM_TIMEOUT_MS, DIALOG_PREFIX, type DbPort, type DeleteMessageParams, type DeleteWebhookParams, type DialogChoice, type DialogDef, type DialogFinishContext, type DialogStepDef, type DoTransport, type EditMessageReplyMarkupParams, type EditMessageTextParams, type EnqueueOptions, type ErrorsPort, type EventDef, type ExecLike, type FeatureFlags, FetchLike, type FileSourceContext, type FileSourceDef, type FilesPort, type FilterDef, type FilterFn, type FilterRegistry, type ForceReply, type FreeTextContext, type GetUpdatesParams, type I18nPort, type IdsPort, type InboundContext, type InboundFile, type InlineKeyboardButton, type InlineKeyboardMarkup, type InputFile, type InputFileUpload, type KeyboardButton, KeyringError, type KeyringPort, KeyringSecret, type LinkPreviewOptions, type LogFields, type LogPort, type MethodName, type MethodResults, type MetricsPort, type OpenedFile, PLUGIN_VERSION, type ParseMode, ParsedCommand, ParsedUpdate, type PluginQueueMessage, type PortOrFactory, type ProviderContext, type ProviderDef, ProviderTimeout, type R2FilesOptions, RESERVED_COMMANDS, type Registry, type RenderContext, type RenderInput, type RenderedFile, type RendererPort, type ReplyApi, type ReplyKeyboardMarkup, type ReplyKeyboardRemove, type ReplyMarkup, type ReplyOptions, type ReplyParameters, type RunResult, type Runtime, SCHEMA_VERSION, type SchedulerPort, type SchemaState, type SendChatActionParams, type SendDocumentParams, type SendMessageParams, type SendOptions, type SendPhotoParams, type SetMyCommandsParams, type SetWebhookParams, type SettingsPort, type Shape, type SqlFragment, type SqlInput, type SqlValue, type StoredFile, TEXT_LIMIT, type TelegramAiOptions, TelegramApiError, TelegramClient, TelegramClientOptions, TelegramConfigError, type TelegramCrons, type TelegramEnv, type TelegramFeaturesInput, type TelegramGroupOptions, type TelegramHooks, type TelegramInboundOptions, type TelegramJob, type TelegramJobContext, type TelegramJobResult, type TelegramLimits, type TelegramLogLevel, TelegramNetworkError, TelegramOutcome, TelegramOutcomeKind, TelegramOutcomeReason, type TelegramPlugin, TelegramPluginError, type TelegramPluginOptions, type TelegramPorts, type TelegramProblemExtensions, type TelegramRetention, type TelegramRoutesApp, type TemplateAst, TgCallbackQuery, TgChat, TgChatMember, TgChatMemberUpdated, TgDocument, type TgFile, TgForumTopicCreated, TgMessage, TgMessageEntity, TgPhotoSize, TgUpdate, TgUser, TokenGetter, type TransportChoice, type TransportPort, UpdateClass, type UpdateType, type UserInfo, type UsersPort, type VariableRef, WebCryptoKeyring, type WebhookInfo, analyticsEngineMetrics, base64ToBytes, botStub, bytesToBase64Url, checkAiText, classifyTelegramError, classifyUpdate, compileTemplate, consoleLog, createTelegramPlugin, cronTransport, d1Db, defineAction, defineAudience, defineCommand, defineDialog, defineEvent, defineFileSource, defineFilter, defineProvider, definitions, describeRule, doTransport, escapeHtml, featureDisabled, fetchTelegram, generateKeyringSecret, inputFile, intersectData, isDoTransport, isInputFileUpload, isLifecycleMessage, isPluginMessage, isSqlFragment, isTelegramApiError, isTelegramPluginError, isValidStartPayload, isValidTimeZone, kidOfCiphertext, listVariables, matchFilter, matchFilters, nextRuns, noopMetrics, parseCommand, parseKeyringSecret, parseStartPayload, parseTemplate, parseUpdate, queueTransport, r2Files, randomBase64Url, recordProviderKey, redactSecrets, registerTelegramPlugin, renderTemplate, settle, shapeVariables, silentLog, splitMessage, sql, stripSensitive, systemClock, timingSafeEqualStrings, toPlainText, toPluginError, untrustedWrap, updateChat, updateFrom, updateMessage, updateType, uuidv7, uuidv7Ids, validateRule, validateTemplate, visibleLength, webCryptoKeyring, zodToShape };
@@ -0,0 +1,46 @@
1
+ import { SCHEMA_VERSION } from "../schema/version.js";
2
+ import { systemClock } from "../adapters/clock.js";
3
+ import { consoleLog, redactSecrets, silentLog } from "../adapters/console-log.js";
4
+ import { D1_MAX_PARAMS, d1Db } from "../adapters/d1-db.js";
5
+ import { uuidv7, uuidv7Ids } from "../adapters/ids.js";
6
+ import { analyticsEngineMetrics, noopMetrics } from "../adapters/metrics.js";
7
+ import { r2Files } from "../adapters/r2-files.js";
8
+ import { KeyringError, base64ToBytes, bytesToBase64Url, generateKeyringSecret, kidOfCiphertext, parseKeyringSecret, randomBase64Url, timingSafeEqualStrings, webCryptoKeyring } from "../adapters/keyring.js";
9
+ import { checkAiText } from "../core/guards.js";
10
+ import { escapeHtml } from "../core/html/escape.js";
11
+ import { isValidTimeZone } from "../core/schedule/tz.js";
12
+ import { describeRule } from "../core/schedule/describe.js";
13
+ import { nextRuns, validateRule } from "../core/schedule/rule.js";
14
+ import { toPlainText } from "../core/split/plain.js";
15
+ import { CAPTION_LIMIT, TEXT_LIMIT, splitMessage, visibleLength } from "../core/split/split.js";
16
+ import { parseTemplate } from "../core/template/parse.js";
17
+ import { BUILTIN_FILTERS, defineFilter } from "../core/template/filters.js";
18
+ import { shapeVariables, zodToShape } from "../core/template/shape.js";
19
+ import { validateTemplate } from "../core/template/validate.js";
20
+ import { renderTemplate } from "../core/template/render.js";
21
+ import { listVariables } from "../core/template/variables.js";
22
+ import { compileTemplate } from "../core/template/index.js";
23
+ import { isSqlFragment, sql } from "../ports/sql.js";
24
+ import { TelegramConfigError, TelegramPluginError, featureDisabled, isTelegramPluginError, toPluginError } from "../engine/errors.js";
25
+ import { ACTION_PREFIX } from "../engine/actions/tokens.js";
26
+ import { ProviderTimeout } from "../engine/content/providers.js";
27
+ import { TelegramApiError, TelegramNetworkError, isTelegramApiError } from "../telegram/errors.js";
28
+ import { classifyTelegramError, settle } from "../telegram/classify.js";
29
+ import { DIALOG_PREFIX } from "../engine/dialogs/dialog.js";
30
+ import { classifyUpdate, isLifecycleMessage, isValidStartPayload, parseCommand, parseStartPayload, updateChat, updateFrom, updateMessage, updateType } from "../telegram/inbound.js";
31
+ import { intersectData } from "../engine/content/intersect.js";
32
+ import { ANY_ROLE, RESERVED_COMMANDS, defineAction, defineAudience, defineCommand, defineDialog, defineEvent, defineFileSource, defineProvider, definitions } from "../engine/registry.js";
33
+ import { recordProviderKey } from "../services/send.js";
34
+ import { untrustedWrap } from "../engine/dispatch/context.js";
35
+ import { matchFilter, matchFilters } from "../engine/events/filters.js";
36
+ import { stripSensitive } from "../engine/events/payload.js";
37
+ import { DEFAULT_LIMITS, DEFAULT_RETENTION } from "../engine/options.js";
38
+ import { registerTelegramPlugin } from "../engine/outbox/do-registry.js";
39
+ import { inputFile, isInputFileUpload } from "../telegram/multipart.js";
40
+ import { botStub, doTransport, isDoTransport } from "../engine/outbox/do-transport.js";
41
+ import { TgCallbackQuery, TgChat, TgChatMember, TgChatMemberUpdated, TgDocument, TgForumTopicCreated, TgMessage, TgMessageEntity, TgPhotoSize, TgUpdate, TgUser, parseUpdate } from "../telegram/update.js";
42
+ import { cronTransport, isPluginMessage, queueTransport } from "../engine/outbox/transport.js";
43
+ import { DEFAULT_TELEGRAM_BASE_URL, DEFAULT_TELEGRAM_TIMEOUT_MS, fetchTelegram } from "../telegram/client.js";
44
+ import { PLUGIN_VERSION } from "./version.js";
45
+ import { createTelegramPlugin } from "./plugin.js";
46
+ export { ACTION_PREFIX, ANY_ROLE, BUILTIN_FILTERS, CAPTION_LIMIT, D1_MAX_PARAMS, DEFAULT_LIMITS, DEFAULT_RETENTION, DEFAULT_TELEGRAM_BASE_URL, DEFAULT_TELEGRAM_TIMEOUT_MS, DIALOG_PREFIX, KeyringError, PLUGIN_VERSION, ProviderTimeout, RESERVED_COMMANDS, SCHEMA_VERSION, TEXT_LIMIT, TelegramApiError, TelegramConfigError, TelegramNetworkError, TelegramPluginError, TgCallbackQuery, TgChat, TgChatMember, TgChatMemberUpdated, TgDocument, TgForumTopicCreated, TgMessage, TgMessageEntity, TgPhotoSize, TgUpdate, TgUser, analyticsEngineMetrics, base64ToBytes, botStub, bytesToBase64Url, checkAiText, classifyTelegramError, classifyUpdate, compileTemplate, consoleLog, createTelegramPlugin, cronTransport, d1Db, defineAction, defineAudience, defineCommand, defineDialog, defineEvent, defineFileSource, defineFilter, defineProvider, definitions, describeRule, doTransport, escapeHtml, featureDisabled, fetchTelegram, generateKeyringSecret, inputFile, intersectData, isDoTransport, isInputFileUpload, isLifecycleMessage, isPluginMessage, isSqlFragment, isTelegramApiError, isTelegramPluginError, isValidStartPayload, isValidTimeZone, kidOfCiphertext, listVariables, matchFilter, matchFilters, nextRuns, noopMetrics, parseCommand, parseKeyringSecret, parseStartPayload, parseTemplate, parseUpdate, queueTransport, r2Files, randomBase64Url, recordProviderKey, redactSecrets, registerTelegramPlugin, renderTemplate, settle, shapeVariables, silentLog, splitMessage, sql, stripSensitive, systemClock, timingSafeEqualStrings, toPlainText, toPluginError, untrustedWrap, updateChat, updateFrom, updateMessage, updateType, uuidv7, uuidv7Ids, validateRule, validateTemplate, visibleLength, webCryptoKeyring, zodToShape };
@@ -0,0 +1,81 @@
1
+ import { PluginMeta } from "../contracts/meta.js";
2
+ import { SendIntent, SendPreview } from "../contracts/send.js";
3
+ import { SqlFragment } from "../ports/sql.js";
4
+ import { TelegramPluginOptions } from "../engine/options.js";
5
+ import { Runtime } from "../engine/runtime.js";
6
+ import { TelegramJob } from "../engine/jobs.js";
7
+ import { SchemaState } from "../engine/state.js";
8
+ import { TgEnv } from "../routes/http.js";
9
+ import { buildRoutes } from "../routes/app.js";
10
+ import { AiToolSpec } from "../services/ai-tool.js";
11
+ import { EnqueueOptions } from "../services/send.js";
12
+ import { Hono } from "hono";
13
+ /** The part of a Workers `ExecutionContext` the plugin uses (background work after the response). */
14
+ export type ExecLike = {
15
+ /** Keeps the invocation alive until `p` settles. */
16
+ waitUntil(p: Promise<unknown>): void;
17
+ };
18
+ /**
19
+ * What `createTelegramPlugin()` returns: the routes to mount, the jobs to schedule, the queue consumer and the
20
+ * programmatic API. Every method that takes `env` builds a fresh per-invocation runtime from it. Methods of the
21
+ * programmatic API (`emit`, `preview`, `enqueue`, `kick`, `aiToolSpec`) throw only `TelegramPluginError`.
22
+ */
23
+ export interface TelegramPlugin<E, A> {
24
+ /** The Hono sub-app (webhook, admin API, self-service). Mount it: `app.route("/api/telegram", telegram.routes)`. */
25
+ readonly routes: ReturnType<typeof buildRoutes> & Hono<TgEnv>;
26
+ /** `telegram:tick` (every minute), `telegram:cleanup` and `telegram:rekey` (daily); run them from `scheduled`. */
27
+ readonly jobs: readonly TelegramJob<E>[];
28
+ /**
29
+ * Queue consumer: `if (await telegram.queue(batch, env, ctx)) return;`. Handles (acks / retries one by one) the
30
+ * plugin's messages in any batch and resolves `true` only when EVERY message was the plugin's. On `false`, handle
31
+ * only the messages with `!isPluginMessage(m.body)` and ack them one by one (never `ackAll()` / `retryAll()`).
32
+ * A dedicated queue for the plugin is simpler.
33
+ */
34
+ queue(batch: MessageBatch<unknown>, env: E, ctx?: ExecLike): Promise<boolean>;
35
+ /**
36
+ * SQL for the host's batch: a `tg_event` row (features.events), so the event commits with the host's write.
37
+ * The payload is validated against the event's schema (`validation_failed`). Fan-out runs on the tick, or at
38
+ * once after `kick` under the queue / DO transports. `dedupeKey` makes a repeated emit a no-op.
39
+ */
40
+ emit(event: string, payload: unknown, opts?: {
41
+ dedupeKey?: string;
42
+ }): SqlFragment[];
43
+ /**
44
+ * Validates and previews a send intent as `actor` (destination, rendered parts, file, confirm sentence) without
45
+ * writing anything. Use it for confirm cards (AI propose); `enqueue` does the actual send. Throws
46
+ * `TelegramPluginError` (`destination_not_allowed`, `forbidden`, `send_text_rejected` with `reasons`, …).
47
+ */
48
+ preview(env: E, intent: SendIntent, actor: A, opts?: Omit<EnqueueOptions, "dedupeKey">): Promise<SendPreview>;
49
+ /**
50
+ * SQL for the host's batch: the outbox rows of a send intent, re-checked as the live `actor`. `opts.dedupeKey`
51
+ * (required) makes a retried commit send once. Call `kick` after the batch commits.
52
+ */
53
+ enqueue(env: E, intent: SendIntent, actor: A, opts: EnqueueOptions): Promise<SqlFragment[]>;
54
+ /**
55
+ * features.ai: JSON-schema description of a generic `send_to_telegram` tool for this actor (its `ai_allowed`
56
+ * destinations, `me`, enabled kinds). The tool proposes; wire it as propose (`preview` with `source: "ai"`) →
57
+ * the host's confirm card (`preview.consequence`) → commit (`enqueue` with `dedupeKey: "ai:" + nonce` in the host
58
+ * batch, then `kick`). See `services/ai-tool.ts`.
59
+ */
60
+ aiToolSpec(env: E, actor: A): Promise<AiToolSpec>;
61
+ /** Starts a drain (and event fan-out) now; use it in `waitUntil` after a commit. `botIds` limits the drain. */
62
+ kick(env: E, opts?: {
63
+ botIds?: string[];
64
+ ctx?: ExecLike;
65
+ }): Promise<void>;
66
+ /** Features, versions and registered keys (permissions are empty here; `GET /admin/meta` adds the caller's). */
67
+ meta(): PluginMeta;
68
+ /** Records `SCHEMA_VERSION` in `tg_state` when the tables are current; reports what is missing otherwise. */
69
+ ensureState(env: E): Promise<SchemaState>;
70
+ /**
71
+ * @internal The resolved runtime for one invocation (tests and plugin internals). It gives raw access to the
72
+ * database and ports and performs NO permission checks; its shape may change in any release. Use `routes`,
73
+ * `preview`, `enqueue`, `emit` and `kick` in host code.
74
+ */
75
+ runtime(env: E, ctx?: ExecLike): Runtime<A>;
76
+ }
77
+ /**
78
+ * Builds the plugin: validates `options` once (throws `TelegramConfigError`), indexes the host definitions and
79
+ * registers the instance for TelegramBotDO under its tenant. No I/O happens until a route, job or method runs.
80
+ */
81
+ export declare function createTelegramPlugin<E, A>(options: TelegramPluginOptions<E, A>): TelegramPlugin<E, A>;