happy2 0.0.5

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 (373) hide show
  1. package/README.md +82 -0
  2. package/package.json +74 -0
  3. package/packages/happy2-server/Dockerfile +18 -0
  4. package/packages/happy2-server/README.md +418 -0
  5. package/packages/happy2-server/bin/happy2.js +3 -0
  6. package/packages/happy2-server/dist/cli.d.ts +3 -0
  7. package/packages/happy2-server/dist/cli.d.ts.map +1 -0
  8. package/packages/happy2-server/dist/cli.js +44 -0
  9. package/packages/happy2-server/dist/cli.js.map +1 -0
  10. package/packages/happy2-server/dist/index.d.ts +24 -0
  11. package/packages/happy2-server/dist/index.d.ts.map +1 -0
  12. package/packages/happy2-server/dist/index.js +22 -0
  13. package/packages/happy2-server/dist/index.js.map +1 -0
  14. package/packages/happy2-server/dist/modules/agents/builtin-images.d.ts +8 -0
  15. package/packages/happy2-server/dist/modules/agents/builtin-images.d.ts.map +1 -0
  16. package/packages/happy2-server/dist/modules/agents/builtin-images.js +283 -0
  17. package/packages/happy2-server/dist/modules/agents/builtin-images.js.map +1 -0
  18. package/packages/happy2-server/dist/modules/agents/command.d.ts +3 -0
  19. package/packages/happy2-server/dist/modules/agents/command.d.ts.map +1 -0
  20. package/packages/happy2-server/dist/modules/agents/command.js +7 -0
  21. package/packages/happy2-server/dist/modules/agents/command.js.map +1 -0
  22. package/packages/happy2-server/dist/modules/agents/daemon.d.ts +106 -0
  23. package/packages/happy2-server/dist/modules/agents/daemon.d.ts.map +1 -0
  24. package/packages/happy2-server/dist/modules/agents/daemon.js +522 -0
  25. package/packages/happy2-server/dist/modules/agents/daemon.js.map +1 -0
  26. package/packages/happy2-server/dist/modules/agents/docker.d.ts +51 -0
  27. package/packages/happy2-server/dist/modules/agents/docker.d.ts.map +1 -0
  28. package/packages/happy2-server/dist/modules/agents/docker.js +256 -0
  29. package/packages/happy2-server/dist/modules/agents/docker.js.map +1 -0
  30. package/packages/happy2-server/dist/modules/agents/docker.test.d.ts +2 -0
  31. package/packages/happy2-server/dist/modules/agents/docker.test.d.ts.map +1 -0
  32. package/packages/happy2-server/dist/modules/agents/docker.test.js +155 -0
  33. package/packages/happy2-server/dist/modules/agents/docker.test.js.map +1 -0
  34. package/packages/happy2-server/dist/modules/agents/index.d.ts +5 -0
  35. package/packages/happy2-server/dist/modules/agents/index.d.ts.map +1 -0
  36. package/packages/happy2-server/dist/modules/agents/index.js +4 -0
  37. package/packages/happy2-server/dist/modules/agents/index.js.map +1 -0
  38. package/packages/happy2-server/dist/modules/agents/service.d.ts +140 -0
  39. package/packages/happy2-server/dist/modules/agents/service.d.ts.map +1 -0
  40. package/packages/happy2-server/dist/modules/agents/service.js +1283 -0
  41. package/packages/happy2-server/dist/modules/agents/service.js.map +1 -0
  42. package/packages/happy2-server/dist/modules/auth/cloudflare-access.d.ts +15 -0
  43. package/packages/happy2-server/dist/modules/auth/cloudflare-access.d.ts.map +1 -0
  44. package/packages/happy2-server/dist/modules/auth/cloudflare-access.js +49 -0
  45. package/packages/happy2-server/dist/modules/auth/cloudflare-access.js.map +1 -0
  46. package/packages/happy2-server/dist/modules/auth/crypto.d.ts +4 -0
  47. package/packages/happy2-server/dist/modules/auth/crypto.d.ts.map +1 -0
  48. package/packages/happy2-server/dist/modules/auth/crypto.js +31 -0
  49. package/packages/happy2-server/dist/modules/auth/crypto.js.map +1 -0
  50. package/packages/happy2-server/dist/modules/auth/crypto.test.d.ts +2 -0
  51. package/packages/happy2-server/dist/modules/auth/crypto.test.d.ts.map +1 -0
  52. package/packages/happy2-server/dist/modules/auth/crypto.test.js +11 -0
  53. package/packages/happy2-server/dist/modules/auth/crypto.test.js.map +1 -0
  54. package/packages/happy2-server/dist/modules/auth/email.d.ts +3 -0
  55. package/packages/happy2-server/dist/modules/auth/email.d.ts.map +1 -0
  56. package/packages/happy2-server/dist/modules/auth/email.js +22 -0
  57. package/packages/happy2-server/dist/modules/auth/email.js.map +1 -0
  58. package/packages/happy2-server/dist/modules/auth/metadata.d.ts +5 -0
  59. package/packages/happy2-server/dist/modules/auth/metadata.d.ts.map +1 -0
  60. package/packages/happy2-server/dist/modules/auth/metadata.js +28 -0
  61. package/packages/happy2-server/dist/modules/auth/metadata.js.map +1 -0
  62. package/packages/happy2-server/dist/modules/auth/metadata.test.d.ts +2 -0
  63. package/packages/happy2-server/dist/modules/auth/metadata.test.d.ts.map +1 -0
  64. package/packages/happy2-server/dist/modules/auth/metadata.test.js +10 -0
  65. package/packages/happy2-server/dist/modules/auth/metadata.test.js.map +1 -0
  66. package/packages/happy2-server/dist/modules/auth/methods.d.ts +10 -0
  67. package/packages/happy2-server/dist/modules/auth/methods.d.ts.map +1 -0
  68. package/packages/happy2-server/dist/modules/auth/methods.js +21 -0
  69. package/packages/happy2-server/dist/modules/auth/methods.js.map +1 -0
  70. package/packages/happy2-server/dist/modules/auth/methods.test.d.ts +2 -0
  71. package/packages/happy2-server/dist/modules/auth/methods.test.d.ts.map +1 -0
  72. package/packages/happy2-server/dist/modules/auth/methods.test.js +16 -0
  73. package/packages/happy2-server/dist/modules/auth/methods.test.js.map +1 -0
  74. package/packages/happy2-server/dist/modules/auth/oidc.d.ts +9 -0
  75. package/packages/happy2-server/dist/modules/auth/oidc.d.ts.map +1 -0
  76. package/packages/happy2-server/dist/modules/auth/oidc.js +68 -0
  77. package/packages/happy2-server/dist/modules/auth/oidc.js.map +1 -0
  78. package/packages/happy2-server/dist/modules/auth/service.d.ts +44 -0
  79. package/packages/happy2-server/dist/modules/auth/service.d.ts.map +1 -0
  80. package/packages/happy2-server/dist/modules/auth/service.js +208 -0
  81. package/packages/happy2-server/dist/modules/auth/service.js.map +1 -0
  82. package/packages/happy2-server/dist/modules/auth/tokens.d.ts +21 -0
  83. package/packages/happy2-server/dist/modules/auth/tokens.d.ts.map +1 -0
  84. package/packages/happy2-server/dist/modules/auth/tokens.js +79 -0
  85. package/packages/happy2-server/dist/modules/auth/tokens.js.map +1 -0
  86. package/packages/happy2-server/dist/modules/automation/repository.d.ts +127 -0
  87. package/packages/happy2-server/dist/modules/automation/repository.d.ts.map +1 -0
  88. package/packages/happy2-server/dist/modules/automation/repository.js +821 -0
  89. package/packages/happy2-server/dist/modules/automation/repository.js.map +1 -0
  90. package/packages/happy2-server/dist/modules/collaboration/repository.d.ts +839 -0
  91. package/packages/happy2-server/dist/modules/collaboration/repository.d.ts.map +1 -0
  92. package/packages/happy2-server/dist/modules/collaboration/repository.js +5795 -0
  93. package/packages/happy2-server/dist/modules/collaboration/repository.js.map +1 -0
  94. package/packages/happy2-server/dist/modules/collaboration/repository.test.d.ts +2 -0
  95. package/packages/happy2-server/dist/modules/collaboration/repository.test.d.ts.map +1 -0
  96. package/packages/happy2-server/dist/modules/collaboration/repository.test.js +620 -0
  97. package/packages/happy2-server/dist/modules/collaboration/repository.test.js.map +1 -0
  98. package/packages/happy2-server/dist/modules/collaboration/types.d.ts +243 -0
  99. package/packages/happy2-server/dist/modules/collaboration/types.d.ts.map +1 -0
  100. package/packages/happy2-server/dist/modules/collaboration/types.js +8 -0
  101. package/packages/happy2-server/dist/modules/collaboration/types.js.map +1 -0
  102. package/packages/happy2-server/dist/modules/config/defaults.d.ts +8 -0
  103. package/packages/happy2-server/dist/modules/config/defaults.d.ts.map +1 -0
  104. package/packages/happy2-server/dist/modules/config/defaults.js +70 -0
  105. package/packages/happy2-server/dist/modules/config/defaults.js.map +1 -0
  106. package/packages/happy2-server/dist/modules/config/defaults.test.d.ts +2 -0
  107. package/packages/happy2-server/dist/modules/config/defaults.test.d.ts.map +1 -0
  108. package/packages/happy2-server/dist/modules/config/defaults.test.js +27 -0
  109. package/packages/happy2-server/dist/modules/config/defaults.test.js.map +1 -0
  110. package/packages/happy2-server/dist/modules/config/environment.d.ts +4 -0
  111. package/packages/happy2-server/dist/modules/config/environment.d.ts.map +1 -0
  112. package/packages/happy2-server/dist/modules/config/environment.js +92 -0
  113. package/packages/happy2-server/dist/modules/config/environment.js.map +1 -0
  114. package/packages/happy2-server/dist/modules/config/loader.d.ts +5 -0
  115. package/packages/happy2-server/dist/modules/config/loader.d.ts.map +1 -0
  116. package/packages/happy2-server/dist/modules/config/loader.js +251 -0
  117. package/packages/happy2-server/dist/modules/config/loader.js.map +1 -0
  118. package/packages/happy2-server/dist/modules/config/loader.test.d.ts +2 -0
  119. package/packages/happy2-server/dist/modules/config/loader.test.d.ts.map +1 -0
  120. package/packages/happy2-server/dist/modules/config/loader.test.js +108 -0
  121. package/packages/happy2-server/dist/modules/config/loader.test.js.map +1 -0
  122. package/packages/happy2-server/dist/modules/config/paths.d.ts +7 -0
  123. package/packages/happy2-server/dist/modules/config/paths.d.ts.map +1 -0
  124. package/packages/happy2-server/dist/modules/config/paths.js +15 -0
  125. package/packages/happy2-server/dist/modules/config/paths.js.map +1 -0
  126. package/packages/happy2-server/dist/modules/config/paths.test.d.ts +2 -0
  127. package/packages/happy2-server/dist/modules/config/paths.test.d.ts.map +1 -0
  128. package/packages/happy2-server/dist/modules/config/paths.test.js +22 -0
  129. package/packages/happy2-server/dist/modules/config/paths.test.js.map +1 -0
  130. package/packages/happy2-server/dist/modules/config/runtime.d.ts +6 -0
  131. package/packages/happy2-server/dist/modules/config/runtime.d.ts.map +1 -0
  132. package/packages/happy2-server/dist/modules/config/runtime.js +14 -0
  133. package/packages/happy2-server/dist/modules/config/runtime.js.map +1 -0
  134. package/packages/happy2-server/dist/modules/config/type.d.ts +88 -0
  135. package/packages/happy2-server/dist/modules/config/type.d.ts.map +1 -0
  136. package/packages/happy2-server/dist/modules/config/type.js +2 -0
  137. package/packages/happy2-server/dist/modules/config/type.js.map +1 -0
  138. package/packages/happy2-server/dist/modules/database.d.ts +105 -0
  139. package/packages/happy2-server/dist/modules/database.d.ts.map +1 -0
  140. package/packages/happy2-server/dist/modules/database.js +583 -0
  141. package/packages/happy2-server/dist/modules/database.js.map +1 -0
  142. package/packages/happy2-server/dist/modules/drizzle.d.ts +11 -0
  143. package/packages/happy2-server/dist/modules/drizzle.d.ts.map +1 -0
  144. package/packages/happy2-server/dist/modules/drizzle.js +31 -0
  145. package/packages/happy2-server/dist/modules/drizzle.js.map +1 -0
  146. package/packages/happy2-server/dist/modules/files/lock.d.ts +3 -0
  147. package/packages/happy2-server/dist/modules/files/lock.d.ts.map +1 -0
  148. package/packages/happy2-server/dist/modules/files/lock.js +83 -0
  149. package/packages/happy2-server/dist/modules/files/lock.js.map +1 -0
  150. package/packages/happy2-server/dist/modules/files/media.d.ts +18 -0
  151. package/packages/happy2-server/dist/modules/files/media.d.ts.map +1 -0
  152. package/packages/happy2-server/dist/modules/files/media.js +352 -0
  153. package/packages/happy2-server/dist/modules/files/media.js.map +1 -0
  154. package/packages/happy2-server/dist/modules/files/provider.d.ts +130 -0
  155. package/packages/happy2-server/dist/modules/files/provider.d.ts.map +1 -0
  156. package/packages/happy2-server/dist/modules/files/provider.js +448 -0
  157. package/packages/happy2-server/dist/modules/files/provider.js.map +1 -0
  158. package/packages/happy2-server/dist/modules/files/quota.d.ts +58 -0
  159. package/packages/happy2-server/dist/modules/files/quota.d.ts.map +1 -0
  160. package/packages/happy2-server/dist/modules/files/quota.js +180 -0
  161. package/packages/happy2-server/dist/modules/files/quota.js.map +1 -0
  162. package/packages/happy2-server/dist/modules/files/routes.test.d.ts +2 -0
  163. package/packages/happy2-server/dist/modules/files/routes.test.d.ts.map +1 -0
  164. package/packages/happy2-server/dist/modules/files/routes.test.js +163 -0
  165. package/packages/happy2-server/dist/modules/files/routes.test.js.map +1 -0
  166. package/packages/happy2-server/dist/modules/files/scanner.d.ts +27 -0
  167. package/packages/happy2-server/dist/modules/files/scanner.d.ts.map +1 -0
  168. package/packages/happy2-server/dist/modules/files/scanner.js +66 -0
  169. package/packages/happy2-server/dist/modules/files/scanner.js.map +1 -0
  170. package/packages/happy2-server/dist/modules/files/storage.d.ts +95 -0
  171. package/packages/happy2-server/dist/modules/files/storage.d.ts.map +1 -0
  172. package/packages/happy2-server/dist/modules/files/storage.js +855 -0
  173. package/packages/happy2-server/dist/modules/files/storage.js.map +1 -0
  174. package/packages/happy2-server/dist/modules/files/storage.test.d.ts +2 -0
  175. package/packages/happy2-server/dist/modules/files/storage.test.d.ts.map +1 -0
  176. package/packages/happy2-server/dist/modules/files/storage.test.js +170 -0
  177. package/packages/happy2-server/dist/modules/files/storage.test.js.map +1 -0
  178. package/packages/happy2-server/dist/modules/integrations/index.d.ts +6 -0
  179. package/packages/happy2-server/dist/modules/integrations/index.d.ts.map +1 -0
  180. package/packages/happy2-server/dist/modules/integrations/index.js +6 -0
  181. package/packages/happy2-server/dist/modules/integrations/index.js.map +1 -0
  182. package/packages/happy2-server/dist/modules/integrations/repository.d.ts +136 -0
  183. package/packages/happy2-server/dist/modules/integrations/repository.d.ts.map +1 -0
  184. package/packages/happy2-server/dist/modules/integrations/repository.js +1229 -0
  185. package/packages/happy2-server/dist/modules/integrations/repository.js.map +1 -0
  186. package/packages/happy2-server/dist/modules/integrations/repository.test.d.ts +2 -0
  187. package/packages/happy2-server/dist/modules/integrations/repository.test.d.ts.map +1 -0
  188. package/packages/happy2-server/dist/modules/integrations/repository.test.js +345 -0
  189. package/packages/happy2-server/dist/modules/integrations/repository.test.js.map +1 -0
  190. package/packages/happy2-server/dist/modules/integrations/routes.test.d.ts +2 -0
  191. package/packages/happy2-server/dist/modules/integrations/routes.test.d.ts.map +1 -0
  192. package/packages/happy2-server/dist/modules/integrations/routes.test.js +161 -0
  193. package/packages/happy2-server/dist/modules/integrations/routes.test.js.map +1 -0
  194. package/packages/happy2-server/dist/modules/integrations/secrets.d.ts +19 -0
  195. package/packages/happy2-server/dist/modules/integrations/secrets.d.ts.map +1 -0
  196. package/packages/happy2-server/dist/modules/integrations/secrets.js +69 -0
  197. package/packages/happy2-server/dist/modules/integrations/secrets.js.map +1 -0
  198. package/packages/happy2-server/dist/modules/integrations/ssrf.d.ts +32 -0
  199. package/packages/happy2-server/dist/modules/integrations/ssrf.d.ts.map +1 -0
  200. package/packages/happy2-server/dist/modules/integrations/ssrf.js +185 -0
  201. package/packages/happy2-server/dist/modules/integrations/ssrf.js.map +1 -0
  202. package/packages/happy2-server/dist/modules/integrations/ssrf.test.d.ts +2 -0
  203. package/packages/happy2-server/dist/modules/integrations/ssrf.test.d.ts.map +1 -0
  204. package/packages/happy2-server/dist/modules/integrations/ssrf.test.js +56 -0
  205. package/packages/happy2-server/dist/modules/integrations/ssrf.test.js.map +1 -0
  206. package/packages/happy2-server/dist/modules/integrations/transport.d.ts +21 -0
  207. package/packages/happy2-server/dist/modules/integrations/transport.d.ts.map +1 -0
  208. package/packages/happy2-server/dist/modules/integrations/transport.js +108 -0
  209. package/packages/happy2-server/dist/modules/integrations/transport.js.map +1 -0
  210. package/packages/happy2-server/dist/modules/integrations/transport.test.d.ts +2 -0
  211. package/packages/happy2-server/dist/modules/integrations/transport.test.d.ts.map +1 -0
  212. package/packages/happy2-server/dist/modules/integrations/transport.test.js +66 -0
  213. package/packages/happy2-server/dist/modules/integrations/transport.test.js.map +1 -0
  214. package/packages/happy2-server/dist/modules/integrations/types.d.ts +155 -0
  215. package/packages/happy2-server/dist/modules/integrations/types.d.ts.map +1 -0
  216. package/packages/happy2-server/dist/modules/integrations/types.js +26 -0
  217. package/packages/happy2-server/dist/modules/integrations/types.js.map +1 -0
  218. package/packages/happy2-server/dist/modules/operations/export-worker.d.ts +16 -0
  219. package/packages/happy2-server/dist/modules/operations/export-worker.d.ts.map +1 -0
  220. package/packages/happy2-server/dist/modules/operations/export-worker.js +56 -0
  221. package/packages/happy2-server/dist/modules/operations/export-worker.js.map +1 -0
  222. package/packages/happy2-server/dist/modules/operations/repository.d.ts +215 -0
  223. package/packages/happy2-server/dist/modules/operations/repository.d.ts.map +1 -0
  224. package/packages/happy2-server/dist/modules/operations/repository.js +2011 -0
  225. package/packages/happy2-server/dist/modules/operations/repository.js.map +1 -0
  226. package/packages/happy2-server/dist/modules/operations/repository.test.d.ts +2 -0
  227. package/packages/happy2-server/dist/modules/operations/repository.test.d.ts.map +1 -0
  228. package/packages/happy2-server/dist/modules/operations/repository.test.js +610 -0
  229. package/packages/happy2-server/dist/modules/operations/repository.test.js.map +1 -0
  230. package/packages/happy2-server/dist/modules/operations/types.d.ts +144 -0
  231. package/packages/happy2-server/dist/modules/operations/types.d.ts.map +1 -0
  232. package/packages/happy2-server/dist/modules/operations/types.js +9 -0
  233. package/packages/happy2-server/dist/modules/operations/types.js.map +1 -0
  234. package/packages/happy2-server/dist/modules/realtime/events.d.ts +99 -0
  235. package/packages/happy2-server/dist/modules/realtime/events.d.ts.map +1 -0
  236. package/packages/happy2-server/dist/modules/realtime/events.js +173 -0
  237. package/packages/happy2-server/dist/modules/realtime/events.js.map +1 -0
  238. package/packages/happy2-server/dist/modules/realtime/index.d.ts +4 -0
  239. package/packages/happy2-server/dist/modules/realtime/index.d.ts.map +1 -0
  240. package/packages/happy2-server/dist/modules/realtime/index.js +4 -0
  241. package/packages/happy2-server/dist/modules/realtime/index.js.map +1 -0
  242. package/packages/happy2-server/dist/modules/realtime/local.d.ts +37 -0
  243. package/packages/happy2-server/dist/modules/realtime/local.d.ts.map +1 -0
  244. package/packages/happy2-server/dist/modules/realtime/local.js +181 -0
  245. package/packages/happy2-server/dist/modules/realtime/local.js.map +1 -0
  246. package/packages/happy2-server/dist/modules/realtime/local.test.d.ts +2 -0
  247. package/packages/happy2-server/dist/modules/realtime/local.test.d.ts.map +1 -0
  248. package/packages/happy2-server/dist/modules/realtime/local.test.js +186 -0
  249. package/packages/happy2-server/dist/modules/realtime/local.test.js.map +1 -0
  250. package/packages/happy2-server/dist/modules/realtime/pubsub.d.ts +26 -0
  251. package/packages/happy2-server/dist/modules/realtime/pubsub.d.ts.map +1 -0
  252. package/packages/happy2-server/dist/modules/realtime/pubsub.js +7 -0
  253. package/packages/happy2-server/dist/modules/realtime/pubsub.js.map +1 -0
  254. package/packages/happy2-server/dist/modules/request/database-idempotency.d.ts +15 -0
  255. package/packages/happy2-server/dist/modules/request/database-idempotency.d.ts.map +1 -0
  256. package/packages/happy2-server/dist/modules/request/database-idempotency.js +141 -0
  257. package/packages/happy2-server/dist/modules/request/database-idempotency.js.map +1 -0
  258. package/packages/happy2-server/dist/modules/request/idempotency-hook.d.ts +12 -0
  259. package/packages/happy2-server/dist/modules/request/idempotency-hook.d.ts.map +1 -0
  260. package/packages/happy2-server/dist/modules/request/idempotency-hook.js +98 -0
  261. package/packages/happy2-server/dist/modules/request/idempotency-hook.js.map +1 -0
  262. package/packages/happy2-server/dist/modules/request/idempotency.d.ts +146 -0
  263. package/packages/happy2-server/dist/modules/request/idempotency.d.ts.map +1 -0
  264. package/packages/happy2-server/dist/modules/request/idempotency.js +312 -0
  265. package/packages/happy2-server/dist/modules/request/idempotency.js.map +1 -0
  266. package/packages/happy2-server/dist/modules/request/idempotency.test.d.ts +2 -0
  267. package/packages/happy2-server/dist/modules/request/idempotency.test.d.ts.map +1 -0
  268. package/packages/happy2-server/dist/modules/request/idempotency.test.js +191 -0
  269. package/packages/happy2-server/dist/modules/request/idempotency.test.js.map +1 -0
  270. package/packages/happy2-server/dist/modules/request/index.d.ts +5 -0
  271. package/packages/happy2-server/dist/modules/request/index.d.ts.map +1 -0
  272. package/packages/happy2-server/dist/modules/request/index.js +5 -0
  273. package/packages/happy2-server/dist/modules/request/index.js.map +1 -0
  274. package/packages/happy2-server/dist/modules/request/rate-limit.d.ts +100 -0
  275. package/packages/happy2-server/dist/modules/request/rate-limit.d.ts.map +1 -0
  276. package/packages/happy2-server/dist/modules/request/rate-limit.js +239 -0
  277. package/packages/happy2-server/dist/modules/request/rate-limit.js.map +1 -0
  278. package/packages/happy2-server/dist/modules/request/rate-limit.test.d.ts +2 -0
  279. package/packages/happy2-server/dist/modules/request/rate-limit.test.d.ts.map +1 -0
  280. package/packages/happy2-server/dist/modules/request/rate-limit.test.js +123 -0
  281. package/packages/happy2-server/dist/modules/request/rate-limit.test.js.map +1 -0
  282. package/packages/happy2-server/dist/modules/schema.d.ts +31454 -0
  283. package/packages/happy2-server/dist/modules/schema.d.ts.map +1 -0
  284. package/packages/happy2-server/dist/modules/schema.js +1081 -0
  285. package/packages/happy2-server/dist/modules/schema.js.map +1 -0
  286. package/packages/happy2-server/dist/modules/workspace/index.d.ts +3 -0
  287. package/packages/happy2-server/dist/modules/workspace/index.d.ts.map +1 -0
  288. package/packages/happy2-server/dist/modules/workspace/index.js +3 -0
  289. package/packages/happy2-server/dist/modules/workspace/index.js.map +1 -0
  290. package/packages/happy2-server/dist/modules/workspace/service.d.ts +54 -0
  291. package/packages/happy2-server/dist/modules/workspace/service.d.ts.map +1 -0
  292. package/packages/happy2-server/dist/modules/workspace/service.js +997 -0
  293. package/packages/happy2-server/dist/modules/workspace/service.js.map +1 -0
  294. package/packages/happy2-server/dist/modules/workspace/types.d.ts +58 -0
  295. package/packages/happy2-server/dist/modules/workspace/types.d.ts.map +1 -0
  296. package/packages/happy2-server/dist/modules/workspace/types.js +11 -0
  297. package/packages/happy2-server/dist/modules/workspace/types.js.map +1 -0
  298. package/packages/happy2-server/dist/routes/agents.d.ts +5 -0
  299. package/packages/happy2-server/dist/routes/agents.d.ts.map +1 -0
  300. package/packages/happy2-server/dist/routes/agents.js +225 -0
  301. package/packages/happy2-server/dist/routes/agents.js.map +1 -0
  302. package/packages/happy2-server/dist/routes/auth.d.ts +5 -0
  303. package/packages/happy2-server/dist/routes/auth.d.ts.map +1 -0
  304. package/packages/happy2-server/dist/routes/auth.js +128 -0
  305. package/packages/happy2-server/dist/routes/auth.js.map +1 -0
  306. package/packages/happy2-server/dist/routes/automation.d.ts +6 -0
  307. package/packages/happy2-server/dist/routes/automation.d.ts.map +1 -0
  308. package/packages/happy2-server/dist/routes/automation.js +315 -0
  309. package/packages/happy2-server/dist/routes/automation.js.map +1 -0
  310. package/packages/happy2-server/dist/routes/basic.d.ts +3 -0
  311. package/packages/happy2-server/dist/routes/basic.d.ts.map +1 -0
  312. package/packages/happy2-server/dist/routes/basic.js +5 -0
  313. package/packages/happy2-server/dist/routes/basic.js.map +1 -0
  314. package/packages/happy2-server/dist/routes/collaboration.d.ts +7 -0
  315. package/packages/happy2-server/dist/routes/collaboration.d.ts.map +1 -0
  316. package/packages/happy2-server/dist/routes/collaboration.js +1285 -0
  317. package/packages/happy2-server/dist/routes/collaboration.js.map +1 -0
  318. package/packages/happy2-server/dist/routes/files.d.ts +9 -0
  319. package/packages/happy2-server/dist/routes/files.d.ts.map +1 -0
  320. package/packages/happy2-server/dist/routes/files.js +397 -0
  321. package/packages/happy2-server/dist/routes/files.js.map +1 -0
  322. package/packages/happy2-server/dist/routes/integrations.d.ts +6 -0
  323. package/packages/happy2-server/dist/routes/integrations.d.ts.map +1 -0
  324. package/packages/happy2-server/dist/routes/integrations.js +486 -0
  325. package/packages/happy2-server/dist/routes/integrations.js.map +1 -0
  326. package/packages/happy2-server/dist/routes/operations.d.ts +5 -0
  327. package/packages/happy2-server/dist/routes/operations.d.ts.map +1 -0
  328. package/packages/happy2-server/dist/routes/operations.js +588 -0
  329. package/packages/happy2-server/dist/routes/operations.js.map +1 -0
  330. package/packages/happy2-server/dist/routes/operations.test.d.ts +2 -0
  331. package/packages/happy2-server/dist/routes/operations.test.d.ts.map +1 -0
  332. package/packages/happy2-server/dist/routes/operations.test.js +106 -0
  333. package/packages/happy2-server/dist/routes/operations.test.js.map +1 -0
  334. package/packages/happy2-server/dist/routes/sync.d.ts +6 -0
  335. package/packages/happy2-server/dist/routes/sync.d.ts.map +1 -0
  336. package/packages/happy2-server/dist/routes/sync.js +549 -0
  337. package/packages/happy2-server/dist/routes/sync.js.map +1 -0
  338. package/packages/happy2-server/dist/routes/workspace.d.ts +5 -0
  339. package/packages/happy2-server/dist/routes/workspace.d.ts.map +1 -0
  340. package/packages/happy2-server/dist/routes/workspace.js +240 -0
  341. package/packages/happy2-server/dist/routes/workspace.js.map +1 -0
  342. package/packages/happy2-server/dist/runner.d.ts +3 -0
  343. package/packages/happy2-server/dist/runner.d.ts.map +1 -0
  344. package/packages/happy2-server/dist/runner.js +30 -0
  345. package/packages/happy2-server/dist/runner.js.map +1 -0
  346. package/packages/happy2-server/dist/server.d.ts +32 -0
  347. package/packages/happy2-server/dist/server.d.ts.map +1 -0
  348. package/packages/happy2-server/dist/server.js +284 -0
  349. package/packages/happy2-server/dist/server.js.map +1 -0
  350. package/packages/happy2-server/dist/standalone.d.ts +13 -0
  351. package/packages/happy2-server/dist/standalone.d.ts.map +1 -0
  352. package/packages/happy2-server/dist/standalone.js +99 -0
  353. package/packages/happy2-server/dist/standalone.js.map +1 -0
  354. package/packages/happy2-server/dist/web/assets/figtree-latin-wght-normal-D_ZTVpCC.woff2 +0 -0
  355. package/packages/happy2-server/dist/web/assets/happy-otter-Q2O_g-DT.png +0 -0
  356. package/packages/happy2-server/dist/web/assets/index-COvbX8JP.css +2 -0
  357. package/packages/happy2-server/dist/web/assets/index-DdpugxMO.js +57 -0
  358. package/packages/happy2-server/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  359. package/packages/happy2-server/dist/web/assets/onboarding-CRUpq9xl.png +0 -0
  360. package/packages/happy2-server/dist/web/index.html +13 -0
  361. package/packages/happy2-server/drizzle/0000_initial.sql +13 -0
  362. package/packages/happy2-server/drizzle/0001_accounts_profiles_files.sql +42 -0
  363. package/packages/happy2-server/drizzle/0002_file_visibility_and_uploader.sql +5 -0
  364. package/packages/happy2-server/drizzle/0003_collaboration.sql +565 -0
  365. package/packages/happy2-server/drizzle/0004_collaboration_expansion.sql +1099 -0
  366. package/packages/happy2-server/drizzle/0005_ai_agents.sql +85 -0
  367. package/packages/happy2-server/drizzle/0006_rig_global_event_queue.sql +10 -0
  368. package/packages/happy2-server/drizzle/0007_rename_server_identity.sql +3 -0
  369. package/packages/happy2-server/drizzle/0008_agent_message_streaming.sql +47 -0
  370. package/packages/happy2-server/drizzle/0009_chat_workspace_binding_lookup.sql +2 -0
  371. package/packages/happy2-server/drizzle/0010_rig_secret_assignments.sql +21 -0
  372. package/packages/happy2-server/drizzle/meta/_journal.json +83 -0
  373. package/packages/happy2-server/happy2.example.toml +104 -0
@@ -0,0 +1,821 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { createClient } from "@libsql/client";
3
+ import { createId } from "@paralleldrive/cuid2";
4
+ import { and, asc, desc, eq, gt, isNull, lte, or, sql } from "drizzle-orm";
5
+ import { CollaborationError } from "../collaboration/types.js";
6
+ import { createDatabase, retrySqliteBusy, } from "../drizzle.js";
7
+ import { accounts, auditLogEntries, automationRuns, automations, botIdentities, chats, messages, scheduledMessageAttachments, scheduledMessages, serverSyncState, syncEvents, users, webhookDeliveries, } from "../schema.js";
8
+ export class AutomationRepository {
9
+ collaboration;
10
+ options;
11
+ client;
12
+ db;
13
+ ownsClient;
14
+ constructor(source, collaboration, options = {}) {
15
+ this.collaboration = collaboration;
16
+ this.options = options;
17
+ this.ownsClient = typeof source === "string";
18
+ this.client =
19
+ typeof source === "string"
20
+ ? createClient({ url: source, authToken: options.authToken })
21
+ : source;
22
+ this.db = createDatabase(this.client);
23
+ }
24
+ close() {
25
+ if (this.ownsClient)
26
+ this.client.close();
27
+ }
28
+ async listAutomations(actorUserId) {
29
+ await this.requireAdmin(this.db, actorUserId);
30
+ return (await this.db
31
+ .select()
32
+ .from(automations)
33
+ .where(isNull(automations.deletedAt))
34
+ .orderBy(desc(automations.createdAt), desc(automations.id))).map(asAutomation);
35
+ }
36
+ async createAutomation(input) {
37
+ return this.write(async (tx) => {
38
+ await this.requireAdmin(tx, input.actorUserId);
39
+ if (input.chatId && !(await this.chatExists(tx, input.chatId)))
40
+ throw new CollaborationError("not_found", "Automation chat was not found");
41
+ if (input.botId && !(await this.botExists(tx, input.botId)))
42
+ throw new CollaborationError("not_found", "Automation bot was not found");
43
+ validateTrigger(input.triggerType, input.triggerConfig, input.nextRunAt);
44
+ validateAction(input.actionType, input.actionConfig, input.chatId);
45
+ const id = createId();
46
+ const webhookToken = input.triggerType === "webhook"
47
+ ? `happy2_auto_${randomBytes(32).toString("base64url")}`
48
+ : undefined;
49
+ const triggerConfig = webhookToken
50
+ ? { ...input.triggerConfig, tokenHash: secretHash(webhookToken) }
51
+ : input.triggerConfig;
52
+ await tx.insert(automations).values({
53
+ id,
54
+ name: input.name,
55
+ createdByUserId: input.actorUserId,
56
+ botId: input.botId ?? null,
57
+ chatId: input.chatId ?? null,
58
+ triggerType: input.triggerType,
59
+ triggerConfigJson: JSON.stringify(triggerConfig),
60
+ actionType: input.actionType,
61
+ actionConfigJson: JSON.stringify(input.actionConfig),
62
+ timezone: input.timezone ?? null,
63
+ nextRunAt: input.nextRunAt ?? null,
64
+ });
65
+ const sequence = await this.nextSequence(tx);
66
+ await tx
67
+ .update(automations)
68
+ .set({ createdSequence: sequence })
69
+ .where(eq(automations.id, id));
70
+ await this.insertSyncEvent(tx, {
71
+ sequence,
72
+ kind: "automation.created",
73
+ entityId: id,
74
+ actorUserId: input.actorUserId,
75
+ });
76
+ await this.appendAudit(tx, input.actorUserId, "automation.created", id);
77
+ const row = await getAutomation(tx, id);
78
+ if (!row)
79
+ throw new Error("Automation was not created");
80
+ return {
81
+ automation: asAutomation(row),
82
+ hint: areaHint(sequence, "automations"),
83
+ ...(webhookToken ? { webhookToken } : {}),
84
+ };
85
+ });
86
+ }
87
+ async updateAutomation(input) {
88
+ return this.write(async (tx) => {
89
+ await this.requireAdmin(tx, input.actorUserId);
90
+ const current = await getAutomation(tx, input.automationId);
91
+ if (!current)
92
+ throw new CollaborationError("not_found", "Automation was not found");
93
+ const currentTriggerConfig = jsonObject(current.triggerConfigJson);
94
+ const triggerConfig = input.triggerConfig
95
+ ? {
96
+ ...input.triggerConfig,
97
+ ...(typeof currentTriggerConfig.tokenHash === "string"
98
+ ? { tokenHash: currentTriggerConfig.tokenHash }
99
+ : {}),
100
+ }
101
+ : currentTriggerConfig;
102
+ const actionConfig = input.actionConfig ?? jsonObject(current.actionConfigJson);
103
+ validateTrigger(current.triggerType, triggerConfig, input.nextRunAt === null
104
+ ? undefined
105
+ : (input.nextRunAt ?? current.nextRunAt ?? undefined));
106
+ validateAction(current.actionType, actionConfig, current.chatId ?? undefined);
107
+ await tx
108
+ .update(automations)
109
+ .set({
110
+ ...(input.active === undefined ? {} : { active: input.active ? 1 : 0 }),
111
+ ...(input.name === undefined ? {} : { name: input.name }),
112
+ ...(input.triggerConfig === undefined
113
+ ? {}
114
+ : { triggerConfigJson: JSON.stringify(triggerConfig) }),
115
+ ...(input.actionConfig === undefined
116
+ ? {}
117
+ : { actionConfigJson: JSON.stringify(actionConfig) }),
118
+ ...(input.nextRunAt === undefined ? {} : { nextRunAt: input.nextRunAt }),
119
+ updatedAt: sql `CURRENT_TIMESTAMP`,
120
+ })
121
+ .where(and(eq(automations.id, input.automationId), isNull(automations.deletedAt)));
122
+ const sequence = await this.nextSequence(tx);
123
+ await this.insertSyncEvent(tx, {
124
+ sequence,
125
+ kind: "automation.updated",
126
+ entityId: input.automationId,
127
+ actorUserId: input.actorUserId,
128
+ });
129
+ await this.appendAudit(tx, input.actorUserId, "automation.updated", input.automationId);
130
+ const row = await getAutomation(tx, input.automationId);
131
+ if (!row)
132
+ throw new Error("Automation disappeared");
133
+ return { automation: asAutomation(row), hint: areaHint(sequence, "automations") };
134
+ });
135
+ }
136
+ async deleteAutomation(actorUserId, automationId) {
137
+ return this.write(async (tx) => {
138
+ await this.requireAdmin(tx, actorUserId);
139
+ const changed = await tx
140
+ .update(automations)
141
+ .set({
142
+ active: 0,
143
+ deletedAt: sql `CURRENT_TIMESTAMP`,
144
+ updatedAt: sql `CURRENT_TIMESTAMP`,
145
+ })
146
+ .where(and(eq(automations.id, automationId), isNull(automations.deletedAt)))
147
+ .returning({ id: automations.id });
148
+ if (changed.length === 0)
149
+ throw new CollaborationError("not_found", "Automation was not found");
150
+ const sequence = await this.nextSequence(tx);
151
+ await this.insertSyncEvent(tx, {
152
+ sequence,
153
+ kind: "automation.deleted",
154
+ entityId: automationId,
155
+ actorUserId,
156
+ });
157
+ await this.appendAudit(tx, actorUserId, "automation.deleted", automationId);
158
+ return areaHint(sequence, "automations");
159
+ });
160
+ }
161
+ async runAutomationNow(actorUserId, automationId, triggerEventId = `manual:${createId()}`) {
162
+ await this.requireAdmin(this.db, actorUserId);
163
+ return this.executeAutomation(automationId, triggerEventId, actorUserId);
164
+ }
165
+ async runWebhookAutomation(token, idempotencyKey) {
166
+ if (!token.startsWith("happy2_auto_") || token.length > 256)
167
+ throw new CollaborationError("not_found", "Automation webhook was not found");
168
+ if (idempotencyKey !== undefined &&
169
+ (idempotencyKey.length < 1 ||
170
+ idempotencyKey.length > 200 ||
171
+ !/^[\x21-\x7e]+$/.test(idempotencyKey)))
172
+ throw new CollaborationError("invalid", "Idempotency key is invalid");
173
+ const candidates = await this.db
174
+ .select()
175
+ .from(automations)
176
+ .where(and(eq(automations.active, 1), isNull(automations.deletedAt), eq(automations.triggerType, "webhook")))
177
+ .orderBy(asc(automations.id));
178
+ const digest = secretHash(token);
179
+ const row = candidates.find((candidate) => {
180
+ const stored = jsonObject(candidate.triggerConfigJson).tokenHash;
181
+ return typeof stored === "string" && hashesEqual(stored, digest);
182
+ });
183
+ if (!row?.createdByUserId)
184
+ throw new CollaborationError("not_found", "Automation webhook was not found");
185
+ const eventId = idempotencyKey
186
+ ? `webhook:${secretHash(`${row.id}:${idempotencyKey}`)}`
187
+ : `webhook:${createId()}`;
188
+ return this.executeAutomation(row.id, eventId, row.createdByUserId);
189
+ }
190
+ async runDueAutomations(limit = 25) {
191
+ const due = await this.db
192
+ .select({
193
+ id: automations.id,
194
+ createdByUserId: automations.createdByUserId,
195
+ nextRunAt: automations.nextRunAt,
196
+ })
197
+ .from(automations)
198
+ .where(and(eq(automations.active, 1), isNull(automations.deletedAt), eq(automations.triggerType, "schedule"), sql `${automations.nextRunAt} is not null`, lte(sql `datetime(${automations.nextRunAt})`, sql `CURRENT_TIMESTAMP`)))
199
+ .orderBy(asc(automations.nextRunAt), asc(automations.id))
200
+ .limit(limit);
201
+ const hints = [];
202
+ for (const row of due) {
203
+ if (!row.createdByUserId || !row.nextRunAt)
204
+ continue;
205
+ try {
206
+ const result = await this.executeAutomation(row.id, `schedule:${row.nextRunAt}`, row.createdByUserId);
207
+ if (result.hint)
208
+ hints.push(result.hint);
209
+ }
210
+ catch {
211
+ // The execution row and automation last_error retain durable failure details.
212
+ }
213
+ }
214
+ return hints;
215
+ }
216
+ /** Processes durable sync events after the event-automation cursor, including after restart. */
217
+ async runPendingEventAutomations(limit = 100) {
218
+ const [cursor] = await this.db
219
+ .select({ sequence: serverSyncState.automationEventSequence })
220
+ .from(serverSyncState)
221
+ .where(eq(serverSyncState.id, 1));
222
+ if (!cursor)
223
+ throw new Error("Sync state has not been initialized");
224
+ const sequences = await this.db
225
+ .selectDistinct({ sequence: syncEvents.sequence })
226
+ .from(syncEvents)
227
+ .where(gt(syncEvents.sequence, cursor.sequence))
228
+ .orderBy(asc(syncEvents.sequence))
229
+ .limit(limit);
230
+ const hints = [];
231
+ for (const row of sequences) {
232
+ hints.push(...(await this.runEventAutomations(row.sequence)));
233
+ await this.db
234
+ .update(serverSyncState)
235
+ .set({
236
+ automationEventSequence: sql `max(${serverSyncState.automationEventSequence}, ${row.sequence})`,
237
+ })
238
+ .where(eq(serverSyncState.id, 1));
239
+ }
240
+ return hints;
241
+ }
242
+ async runEventAutomations(sequence) {
243
+ if (!Number.isSafeInteger(sequence) || sequence < 1)
244
+ throw new TypeError("sequence must be a positive safe integer");
245
+ const [events, definitions] = await Promise.all([
246
+ this.db
247
+ .select({
248
+ id: syncEvents.id,
249
+ kind: syncEvents.kind,
250
+ chatId: syncEvents.chatId,
251
+ entityId: syncEvents.entityId,
252
+ })
253
+ .from(syncEvents)
254
+ .where(eq(syncEvents.sequence, sequence))
255
+ .orderBy(asc(syncEvents.id)),
256
+ this.db
257
+ .select()
258
+ .from(automations)
259
+ .where(and(eq(automations.active, 1), isNull(automations.deletedAt), eq(automations.triggerType, "event")))
260
+ .orderBy(asc(automations.id)),
261
+ ]);
262
+ const hints = [];
263
+ for (const event of events) {
264
+ const automated = event.entityId
265
+ ? Boolean((await this.db
266
+ .select({ id: messages.id })
267
+ .from(messages)
268
+ .where(and(eq(messages.id, event.entityId), or(eq(messages.kind, "automated"), sql `${messages.senderBotId} is not null`)))
269
+ .limit(1))[0])
270
+ : false;
271
+ for (const definition of definitions) {
272
+ if (definition.createdSequence >= sequence)
273
+ continue;
274
+ const automation = asAutomation(definition);
275
+ if (!matchesEvent(automation.triggerConfig, {
276
+ kind: event.kind,
277
+ chatId: event.chatId ?? undefined,
278
+ automated,
279
+ }))
280
+ continue;
281
+ if (!definition.createdByUserId)
282
+ continue;
283
+ try {
284
+ const result = await this.executeAutomation(automation.id, `sync:${event.id}`, definition.createdByUserId);
285
+ if (result.hint)
286
+ hints.push(result.hint);
287
+ }
288
+ catch {
289
+ // The automation run and last_error persist the failure for administrators.
290
+ }
291
+ }
292
+ }
293
+ return hints;
294
+ }
295
+ async scheduleMessage(input) {
296
+ if (!(await this.collaboration.canPostToChat(input.actorUserId, input.chatId)))
297
+ throw new CollaborationError("not_found", "Chat was not found");
298
+ for (const fileId of input.attachmentFileIds)
299
+ if (!(await this.collaboration.canAccessFile(input.actorUserId, fileId)))
300
+ throw new CollaborationError("not_found", "Attachment file was not found");
301
+ return this.write(async (tx) => {
302
+ const id = createId();
303
+ try {
304
+ await tx.insert(scheduledMessages).values({
305
+ id,
306
+ chatId: input.chatId,
307
+ createdByUserId: input.actorUserId,
308
+ text: input.text,
309
+ quotedMessageId: input.quotedMessageId ?? null,
310
+ threadRootMessageId: input.threadRootMessageId ?? null,
311
+ scheduledFor: input.scheduledFor,
312
+ timezone: input.timezone ?? null,
313
+ clientMutationId: input.clientMutationId ?? null,
314
+ });
315
+ }
316
+ catch (error) {
317
+ if (!input.clientMutationId)
318
+ throw error;
319
+ const [existing] = await tx
320
+ .select({ id: scheduledMessages.id })
321
+ .from(scheduledMessages)
322
+ .where(and(eq(scheduledMessages.createdByUserId, input.actorUserId), eq(scheduledMessages.clientMutationId, input.clientMutationId)));
323
+ if (!existing)
324
+ throw error;
325
+ return {
326
+ message: await this.getScheduledMessageWith(tx, input.actorUserId, existing.id),
327
+ };
328
+ }
329
+ if (input.attachmentFileIds.length > 0)
330
+ await tx.insert(scheduledMessageAttachments).values(input.attachmentFileIds.map((fileId, position) => ({
331
+ scheduledMessageId: id,
332
+ fileId,
333
+ position,
334
+ })));
335
+ const sequence = await this.nextSequence(tx);
336
+ await this.insertSyncEvent(tx, {
337
+ sequence,
338
+ kind: "scheduled.created",
339
+ entityId: id,
340
+ actorUserId: input.actorUserId,
341
+ targetUserId: input.actorUserId,
342
+ });
343
+ return {
344
+ message: await this.getScheduledMessageWith(tx, input.actorUserId, id),
345
+ hint: areaHint(sequence, "scheduled-messages"),
346
+ };
347
+ });
348
+ }
349
+ async listScheduledMessages(actorUserId) {
350
+ const rows = await this.db
351
+ .select({ id: scheduledMessages.id })
352
+ .from(scheduledMessages)
353
+ .where(eq(scheduledMessages.createdByUserId, actorUserId))
354
+ .orderBy(asc(scheduledMessages.scheduledFor), asc(scheduledMessages.id));
355
+ const messages = [];
356
+ for (const row of rows)
357
+ messages.push(await this.getScheduledMessageWith(this.db, actorUserId, row.id));
358
+ return messages;
359
+ }
360
+ async cancelScheduledMessage(actorUserId, scheduledMessageId) {
361
+ return this.write(async (tx) => {
362
+ const changed = await tx
363
+ .update(scheduledMessages)
364
+ .set({
365
+ status: "cancelled",
366
+ cancelledAt: sql `CURRENT_TIMESTAMP`,
367
+ updatedAt: sql `CURRENT_TIMESTAMP`,
368
+ })
369
+ .where(and(eq(scheduledMessages.id, scheduledMessageId), eq(scheduledMessages.createdByUserId, actorUserId), eq(scheduledMessages.status, "scheduled")))
370
+ .returning({ id: scheduledMessages.id });
371
+ if (changed.length === 0)
372
+ throw new CollaborationError("not_found", "Scheduled message was not found");
373
+ const sequence = await this.nextSequence(tx);
374
+ await this.insertSyncEvent(tx, {
375
+ sequence,
376
+ kind: "scheduled.cancelled",
377
+ entityId: scheduledMessageId,
378
+ actorUserId,
379
+ targetUserId: actorUserId,
380
+ });
381
+ return areaHint(sequence, "scheduled-messages");
382
+ });
383
+ }
384
+ async publishDueScheduledMessages(limit = 25) {
385
+ const due = await this.db
386
+ .select({ id: scheduledMessages.id, actorUserId: scheduledMessages.createdByUserId })
387
+ .from(scheduledMessages)
388
+ .where(or(and(eq(scheduledMessages.status, "scheduled"), lte(sql `datetime(${scheduledMessages.scheduledFor})`, sql `CURRENT_TIMESTAMP`)), and(eq(scheduledMessages.status, "publishing"), lte(sql `datetime(${scheduledMessages.updatedAt})`, sql `datetime('now', '-1 minute')`))))
389
+ .orderBy(asc(scheduledMessages.scheduledFor), asc(scheduledMessages.id))
390
+ .limit(limit);
391
+ const hints = [];
392
+ for (const row of due) {
393
+ if (!row.actorUserId)
394
+ continue;
395
+ const actorUserId = row.actorUserId;
396
+ const [claimed] = await this.db
397
+ .update(scheduledMessages)
398
+ .set({ status: "publishing", updatedAt: sql `CURRENT_TIMESTAMP` })
399
+ .where(and(eq(scheduledMessages.id, row.id), or(eq(scheduledMessages.status, "scheduled"), and(eq(scheduledMessages.status, "publishing"), lte(sql `datetime(${scheduledMessages.updatedAt})`, sql `datetime('now', '-1 minute')`)))))
400
+ .returning({ id: scheduledMessages.id });
401
+ if (!claimed)
402
+ continue;
403
+ let sent;
404
+ try {
405
+ const scheduled = await this.getScheduledMessageWith(this.db, actorUserId, row.id);
406
+ const [detail] = await this.db
407
+ .select({
408
+ quotedMessageId: scheduledMessages.quotedMessageId,
409
+ threadRootMessageId: scheduledMessages.threadRootMessageId,
410
+ })
411
+ .from(scheduledMessages)
412
+ .where(eq(scheduledMessages.id, row.id));
413
+ sent = await this.collaboration.sendMessage({
414
+ actorUserId,
415
+ chatId: scheduled.chatId,
416
+ text: scheduled.text,
417
+ attachmentFileIds: scheduled.attachmentFileIds,
418
+ quotedMessageId: detail?.quotedMessageId ?? undefined,
419
+ threadRootMessageId: detail?.threadRootMessageId ?? undefined,
420
+ clientMutationId: `scheduled:${row.id}`,
421
+ });
422
+ }
423
+ catch (error) {
424
+ hints.push(await this.write(async (tx) => {
425
+ await tx
426
+ .update(scheduledMessages)
427
+ .set({
428
+ status: "failed",
429
+ lastError: errorMessage(error),
430
+ updatedAt: sql `CURRENT_TIMESTAMP`,
431
+ })
432
+ .where(eq(scheduledMessages.id, row.id));
433
+ const sequence = await this.nextSequence(tx);
434
+ await this.insertSyncEvent(tx, {
435
+ sequence,
436
+ kind: "scheduled.failed",
437
+ entityId: row.id,
438
+ actorUserId,
439
+ targetUserId: actorUserId,
440
+ });
441
+ return areaHint(sequence, "scheduled-messages");
442
+ }));
443
+ continue;
444
+ }
445
+ const areaHintValue = await this.write(async (tx) => {
446
+ await tx
447
+ .update(scheduledMessages)
448
+ .set({
449
+ status: "published",
450
+ publishedMessageId: sent.message.id,
451
+ publishedAt: sql `CURRENT_TIMESTAMP`,
452
+ updatedAt: sql `CURRENT_TIMESTAMP`,
453
+ })
454
+ .where(eq(scheduledMessages.id, row.id));
455
+ const sequence = await this.nextSequence(tx);
456
+ await this.insertSyncEvent(tx, {
457
+ sequence,
458
+ kind: "scheduled.published",
459
+ entityId: row.id,
460
+ actorUserId,
461
+ targetUserId: actorUserId,
462
+ });
463
+ return areaHint(sequence, "scheduled-messages");
464
+ });
465
+ hints.push(sent.hint, areaHintValue);
466
+ }
467
+ return hints;
468
+ }
469
+ async executeAutomation(automationId, triggerEventId, actorUserId) {
470
+ const claimed = await this.write(async (tx) => {
471
+ const row = await getAutomation(tx, automationId);
472
+ if (!row || row.active !== 1)
473
+ throw new CollaborationError("not_found", "Automation was not found");
474
+ const [existing] = await tx
475
+ .select()
476
+ .from(automationRuns)
477
+ .where(and(eq(automationRuns.automationId, automationId), eq(automationRuns.triggerEventId, triggerEventId)));
478
+ if (existing?.status === "succeeded")
479
+ return {
480
+ automation: asAutomation(row),
481
+ runId: existing.id,
482
+ alreadyCompleted: true,
483
+ };
484
+ let runId;
485
+ if (existing) {
486
+ runId = existing.id;
487
+ const reclaimed = await tx
488
+ .update(automationRuns)
489
+ .set({
490
+ status: "running",
491
+ attempts: sql `${automationRuns.attempts} + 1`,
492
+ startedAt: sql `CURRENT_TIMESTAMP`,
493
+ completedAt: null,
494
+ lastError: null,
495
+ })
496
+ .where(and(eq(automationRuns.id, runId), or(sql `${automationRuns.status} in ('pending', 'failed')`, and(eq(automationRuns.status, "running"), lte(sql `datetime(${automationRuns.startedAt})`, sql `datetime('now', '-1 minute')`)))))
497
+ .returning({ id: automationRuns.id });
498
+ if (reclaimed.length === 0)
499
+ return { automation: asAutomation(row), runId, alreadyCompleted: true };
500
+ }
501
+ else {
502
+ runId = createId();
503
+ await tx.insert(automationRuns).values({
504
+ id: runId,
505
+ automationId,
506
+ triggerEventId,
507
+ scheduledFor: row.nextRunAt,
508
+ status: "running",
509
+ attempts: 1,
510
+ startedAt: sql `CURRENT_TIMESTAMP`,
511
+ });
512
+ }
513
+ await this.appendAudit(tx, actorUserId, "automation.run", automationId);
514
+ const intervalSeconds = positiveNumber(jsonObject(row.triggerConfigJson).intervalSeconds);
515
+ await tx
516
+ .update(automations)
517
+ .set({
518
+ nextRunAt: intervalSeconds
519
+ ? new Date(Date.now() + intervalSeconds * 1_000).toISOString()
520
+ : null,
521
+ ...(intervalSeconds || row.triggerType !== "schedule" ? {} : { active: 0 }),
522
+ lastRunAt: sql `CURRENT_TIMESTAMP`,
523
+ lastError: null,
524
+ updatedAt: sql `CURRENT_TIMESTAMP`,
525
+ })
526
+ .where(eq(automations.id, automationId));
527
+ return { automation: asAutomation(row), runId, alreadyCompleted: false };
528
+ });
529
+ if (claimed.alreadyCompleted)
530
+ return { runId: claimed.runId };
531
+ try {
532
+ let hint;
533
+ if (claimed.automation.actionType === "send_message") {
534
+ const config = claimed.automation.actionConfig;
535
+ const chatId = claimed.automation.chatId ?? requiredString(config.chatId, "chatId");
536
+ const sent = await this.collaboration.sendAutomatedMessage({
537
+ actorUserId,
538
+ chatId,
539
+ text: requiredString(config.text, "text"),
540
+ attachmentFileIds: stringArray(config.attachmentFileIds),
541
+ clientMutationId: `automation:${claimed.runId}`,
542
+ botId: claimed.automation.botId,
543
+ });
544
+ hint = sent.hint;
545
+ }
546
+ else if (claimed.automation.actionType === "call_webhook") {
547
+ const subscriptionId = requiredString(claimed.automation.actionConfig.subscriptionId, "subscriptionId");
548
+ await this.db
549
+ .insert(webhookDeliveries)
550
+ .values({
551
+ id: createId(),
552
+ subscriptionId,
553
+ eventId: claimed.runId,
554
+ eventType: "automation.triggered",
555
+ payloadJson: JSON.stringify(claimed.automation.actionConfig.payload ?? {}),
556
+ })
557
+ .onConflictDoNothing();
558
+ }
559
+ else {
560
+ if (!this.options.moderate)
561
+ throw new Error("Moderation automation handler is unavailable");
562
+ const config = claimed.automation.actionConfig;
563
+ const moderated = await this.options.moderate({
564
+ actorUserId,
565
+ reportId: requiredString(config.reportId, "reportId"),
566
+ action: moderationAction(config.action),
567
+ reason: optionalString(config.reason),
568
+ expiresAt: optionalString(config.expiresAt),
569
+ metadata: optionalObject(config.metadata),
570
+ automationRunId: claimed.runId,
571
+ });
572
+ hint = moderated.sync;
573
+ }
574
+ await this.db
575
+ .update(automationRuns)
576
+ .set({
577
+ status: "succeeded",
578
+ resultJson: JSON.stringify({ hint: hint ?? null }),
579
+ completedAt: sql `CURRENT_TIMESTAMP`,
580
+ })
581
+ .where(eq(automationRuns.id, claimed.runId));
582
+ return { hint, runId: claimed.runId };
583
+ }
584
+ catch (error) {
585
+ const message = errorMessage(error);
586
+ await this.write(async (tx) => {
587
+ await tx
588
+ .update(automationRuns)
589
+ .set({
590
+ status: "failed",
591
+ lastError: message,
592
+ completedAt: sql `CURRENT_TIMESTAMP`,
593
+ })
594
+ .where(eq(automationRuns.id, claimed.runId));
595
+ await tx
596
+ .update(automations)
597
+ .set({ lastError: message, updatedAt: sql `CURRENT_TIMESTAMP` })
598
+ .where(eq(automations.id, automationId));
599
+ });
600
+ throw error;
601
+ }
602
+ }
603
+ async getScheduledMessageWith(executor, actorUserId, id) {
604
+ const [row] = await executor
605
+ .select()
606
+ .from(scheduledMessages)
607
+ .where(and(eq(scheduledMessages.id, id), eq(scheduledMessages.createdByUserId, actorUserId)));
608
+ if (!row)
609
+ throw new CollaborationError("not_found", "Scheduled message was not found");
610
+ const attachments = await executor
611
+ .select({ fileId: scheduledMessageAttachments.fileId })
612
+ .from(scheduledMessageAttachments)
613
+ .where(eq(scheduledMessageAttachments.scheduledMessageId, id))
614
+ .orderBy(asc(scheduledMessageAttachments.position));
615
+ return {
616
+ id,
617
+ chatId: row.chatId,
618
+ text: row.text,
619
+ attachmentFileIds: attachments.map(({ fileId }) => fileId),
620
+ scheduledFor: row.scheduledFor,
621
+ timezone: row.timezone ?? undefined,
622
+ status: row.status,
623
+ publishedMessageId: row.publishedMessageId ?? undefined,
624
+ lastError: row.lastError ?? undefined,
625
+ createdAt: row.createdAt,
626
+ updatedAt: row.updatedAt,
627
+ };
628
+ }
629
+ async requireAdmin(executor, userId) {
630
+ const [row] = await executor
631
+ .select({ id: users.id })
632
+ .from(users)
633
+ .innerJoin(accounts, eq(accounts.id, users.accountId))
634
+ .where(and(eq(users.id, userId), eq(users.role, "admin"), isNull(users.deletedAt), eq(accounts.active, 1), isNull(accounts.bannedAt), isNull(accounts.deletedAt)));
635
+ if (!row)
636
+ throw new CollaborationError("forbidden", "Server admin permission is required");
637
+ }
638
+ async chatExists(executor, chatId) {
639
+ return Boolean((await executor
640
+ .select({ id: chats.id })
641
+ .from(chats)
642
+ .where(and(eq(chats.id, chatId), isNull(chats.deletedAt)))
643
+ .limit(1))[0]);
644
+ }
645
+ async botExists(executor, botId) {
646
+ return Boolean((await executor
647
+ .select({ id: botIdentities.id })
648
+ .from(botIdentities)
649
+ .where(and(eq(botIdentities.id, botId), eq(botIdentities.active, 1), isNull(botIdentities.deletedAt)))
650
+ .limit(1))[0]);
651
+ }
652
+ async nextSequence(tx) {
653
+ const [row] = await tx
654
+ .update(serverSyncState)
655
+ .set({ sequence: sql `${serverSyncState.sequence} + 1` })
656
+ .where(eq(serverSyncState.id, 1))
657
+ .returning({ sequence: serverSyncState.sequence });
658
+ if (!row)
659
+ throw new Error("Sync state has not been initialized");
660
+ return row.sequence;
661
+ }
662
+ async insertSyncEvent(tx, input) {
663
+ await tx.insert(syncEvents).values({
664
+ sequence: input.sequence,
665
+ kind: input.kind,
666
+ entityId: input.entityId,
667
+ actorUserId: input.actorUserId ?? null,
668
+ targetUserId: input.targetUserId ?? null,
669
+ });
670
+ }
671
+ async appendAudit(tx, actorUserId, action, targetId) {
672
+ await tx.insert(auditLogEntries).values({
673
+ id: createId(),
674
+ actorUserId,
675
+ action,
676
+ targetType: "automation",
677
+ targetId,
678
+ });
679
+ }
680
+ write(operation) {
681
+ return retrySqliteBusy(() => this.db.transaction(operation));
682
+ }
683
+ }
684
+ async function getAutomation(executor, id) {
685
+ const rows = await executor
686
+ .select()
687
+ .from(automations)
688
+ .where(and(eq(automations.id, id), isNull(automations.deletedAt)));
689
+ return rows[0];
690
+ }
691
+ function areaHint(sequence, area) {
692
+ return { sequence: String(sequence), chats: [], areas: [area] };
693
+ }
694
+ function asAutomation(row) {
695
+ const triggerConfig = jsonObject(row.triggerConfigJson);
696
+ delete triggerConfig.tokenHash;
697
+ return {
698
+ id: row.id,
699
+ name: row.name,
700
+ chatId: row.chatId ?? undefined,
701
+ botId: row.botId ?? undefined,
702
+ triggerType: row.triggerType,
703
+ triggerConfig,
704
+ actionType: row.actionType,
705
+ actionConfig: jsonObject(row.actionConfigJson),
706
+ timezone: row.timezone ?? undefined,
707
+ nextRunAt: row.nextRunAt ?? undefined,
708
+ active: row.active === 1,
709
+ lastRunAt: row.lastRunAt ?? undefined,
710
+ lastError: row.lastError ?? undefined,
711
+ createdAt: row.createdAt,
712
+ updatedAt: row.updatedAt,
713
+ };
714
+ }
715
+ function validateTrigger(type, config, nextRunAt) {
716
+ if (type === "schedule") {
717
+ if (!nextRunAt || !Number.isFinite(Date.parse(nextRunAt)))
718
+ throw new CollaborationError("invalid", "Scheduled automation requires nextRunAt");
719
+ const interval = config.intervalSeconds;
720
+ if (interval !== undefined &&
721
+ (!Number.isSafeInteger(interval) ||
722
+ interval < 60 ||
723
+ interval > 31_536_000))
724
+ throw new CollaborationError("invalid", "intervalSeconds must be between 60 and 31536000");
725
+ }
726
+ if (type === "event")
727
+ eventKinds(config);
728
+ }
729
+ function validateAction(type, config, chatId) {
730
+ if (type === "send_message") {
731
+ if (!chatId && typeof config.chatId !== "string")
732
+ throw new CollaborationError("invalid", "Send-message automation requires a chat");
733
+ requiredString(config.text, "actionConfig.text");
734
+ stringArray(config.attachmentFileIds);
735
+ }
736
+ if (type === "call_webhook")
737
+ requiredString(config.subscriptionId, "subscriptionId");
738
+ if (type === "moderate") {
739
+ requiredString(config.reportId, "reportId");
740
+ moderationAction(config.action);
741
+ }
742
+ }
743
+ function eventKinds(config) {
744
+ if (typeof config.event === "string" && config.event.trim())
745
+ return [config.event];
746
+ if (Array.isArray(config.eventTypes) &&
747
+ config.eventTypes.length > 0 &&
748
+ config.eventTypes.length <= 100 &&
749
+ config.eventTypes.every((value) => typeof value === "string" && value.length > 0 && value.length <= 128))
750
+ return [...new Set(config.eventTypes)];
751
+ throw new CollaborationError("invalid", "Event automation requires triggerConfig.event or triggerConfig.eventTypes");
752
+ }
753
+ function matchesEvent(config, event) {
754
+ const kinds = eventKinds(config);
755
+ if (!kinds.includes("*") && !kinds.includes(event.kind))
756
+ return false;
757
+ if (typeof config.chatId === "string" && config.chatId !== event.chatId)
758
+ return false;
759
+ return config.includeAutomated === true || !event.automated;
760
+ }
761
+ function moderationAction(value) {
762
+ const values = [
763
+ "warn",
764
+ "restrict",
765
+ "remove_message",
766
+ "remove_file",
767
+ "ban",
768
+ "unban",
769
+ "delete_user",
770
+ ];
771
+ if (typeof value !== "string" || !values.includes(value))
772
+ throw new CollaborationError("invalid", "actionConfig.action is invalid");
773
+ return value;
774
+ }
775
+ function optionalString(value) {
776
+ if (value === undefined)
777
+ return undefined;
778
+ if (typeof value !== "string")
779
+ throw new CollaborationError("invalid", "Automation action value must be a string");
780
+ return value;
781
+ }
782
+ function optionalObject(value) {
783
+ if (value === undefined)
784
+ return undefined;
785
+ if (!value || typeof value !== "object" || Array.isArray(value))
786
+ throw new CollaborationError("invalid", "Automation metadata must be an object");
787
+ return value;
788
+ }
789
+ function secretHash(value) {
790
+ return createHash("sha256").update(value, "utf8").digest("hex");
791
+ }
792
+ function hashesEqual(left, right) {
793
+ const a = Buffer.from(left, "hex");
794
+ const b = Buffer.from(right, "hex");
795
+ return a.length === b.length && a.length > 0 && timingSafeEqual(a, b);
796
+ }
797
+ function jsonObject(value) {
798
+ const parsed = JSON.parse(value);
799
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
800
+ throw new Error("Expected JSON object");
801
+ return parsed;
802
+ }
803
+ function requiredString(value, name) {
804
+ if (typeof value !== "string" || value.length === 0)
805
+ throw new CollaborationError("invalid", `${name} is required`);
806
+ return value;
807
+ }
808
+ function stringArray(value) {
809
+ if (value === undefined)
810
+ return [];
811
+ if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string"))
812
+ throw new CollaborationError("invalid", "attachmentFileIds must be an array of ids");
813
+ return [...new Set(value)];
814
+ }
815
+ function positiveNumber(value) {
816
+ return Number.isSafeInteger(value) && value > 0 ? value : undefined;
817
+ }
818
+ function errorMessage(error) {
819
+ return (error instanceof Error ? error.message : String(error)).slice(0, 2_000);
820
+ }
821
+ //# sourceMappingURL=repository.js.map