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,106 @@
1
+ import Fastify, {} from "fastify";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { Database } from "../modules/database.js";
7
+ import { OperationsRepository } from "../modules/operations/repository.js";
8
+ import { registerOperationsRoutes } from "./operations.js";
9
+ describe("operations routes", () => {
10
+ let directory;
11
+ let database;
12
+ let repository;
13
+ let app;
14
+ let admin;
15
+ let member;
16
+ beforeEach(async () => {
17
+ directory = await mkdtemp(join(tmpdir(), "happy2-operations-routes-"));
18
+ const url = `file:${join(directory, "happy2.db")}`;
19
+ database = new Database(url);
20
+ await database.migrate();
21
+ repository = new OperationsRepository(url);
22
+ admin = await createUser(database, "admin@example.com", "admin", "Ada");
23
+ member = await createUser(database, "member@example.com", "member", "Grace");
24
+ app = Fastify({ trustProxy: false });
25
+ registerOperationsRoutes(app, fakeAuth(() => ({ admin, member })), repository);
26
+ });
27
+ afterEach(async () => {
28
+ await app.close();
29
+ repository.close();
30
+ database.close();
31
+ await rm(directory, { recursive: true, force: true });
32
+ });
33
+ it("maps authentication, role, and validation failures to stable HTTP errors", async () => {
34
+ const unauthorized = await app.inject({ method: "GET", url: "/v0/admin/auditLogs" });
35
+ expect(unauthorized.statusCode).toBe(401);
36
+ const forbidden = await app.inject({
37
+ method: "GET",
38
+ url: "/v0/admin/auditLogs",
39
+ headers: { authorization: "Bearer member" },
40
+ });
41
+ expect(forbidden.statusCode).toBe(403);
42
+ const invalid = await app.inject({
43
+ method: "POST",
44
+ url: `/v0/admin/users/${member.user.id}/applyBan`,
45
+ headers: { authorization: "Bearer admin" },
46
+ payload: { unexpected: true },
47
+ });
48
+ expect(invalid.statusCode).toBe(400);
49
+ expect(invalid.json()).toMatchObject({ error: "invalid_request" });
50
+ });
51
+ it("creates a member report and lets an administrator review it", async () => {
52
+ const created = await app.inject({
53
+ method: "POST",
54
+ url: "/v0/reports/createReport",
55
+ headers: {
56
+ authorization: "Bearer member",
57
+ "x-happy2-device": "Happy (2) Desktop",
58
+ },
59
+ payload: {
60
+ targetUserId: admin.user.id,
61
+ reason: "Profile needs review",
62
+ },
63
+ });
64
+ expect(created.statusCode).toBe(201);
65
+ expect(created.json().report).toMatchObject({
66
+ reportedByUserId: member.user.id,
67
+ status: "open",
68
+ });
69
+ const listed = await app.inject({
70
+ method: "GET",
71
+ url: "/v0/admin/reports?status=open&limit=10",
72
+ headers: { authorization: "Bearer admin" },
73
+ });
74
+ expect(listed.statusCode).toBe(200);
75
+ expect(listed.json().reports).toHaveLength(1);
76
+ });
77
+ });
78
+ function fakeAuth(identities) {
79
+ return {
80
+ async authenticate(request) {
81
+ const token = request.headers.authorization?.replace(/^Bearer /, "");
82
+ const selected = token === "admin"
83
+ ? identities().admin
84
+ : token === "member"
85
+ ? identities().member
86
+ : undefined;
87
+ if (!selected)
88
+ return undefined;
89
+ return {
90
+ session: {
91
+ id: `session-${token}`,
92
+ accountId: selected.account.id,
93
+ expiresAt: new Date(Date.now() + 60_000),
94
+ },
95
+ accountId: selected.account.id,
96
+ user: selected.user,
97
+ };
98
+ },
99
+ };
100
+ }
101
+ async function createUser(database, email, username, firstName) {
102
+ const account = await database.createPasswordAccount(email, "not-used-in-this-test");
103
+ const user = await database.createProfile(account.id, { firstName, username, email });
104
+ return { account, user };
105
+ }
106
+ //# sourceMappingURL=operations.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.test.js","sourceRoot":"","sources":["../../sources/routes/operations.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import type { AuthService } from "../modules/auth/service.js";
3
+ import { CollaborationRepository } from "../modules/collaboration/repository.js";
4
+ import { type PubSub } from "../modules/realtime/index.js";
5
+ export declare function registerSyncRoutes(app: FastifyInstance, auth: AuthService, repository: CollaborationRepository, pubsub: PubSub): void;
6
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../sources/routes/sync.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAEjF,OAAO,EAOH,KAAK,MAAM,EAKd,MAAM,8BAA8B,CAAC;AAatC,wBAAgB,kBAAkB,CAC9B,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,WAAW,EACjB,UAAU,EAAE,uBAAuB,EACnC,MAAM,EAAE,MAAM,GACf,IAAI,CA+KN"}
@@ -0,0 +1,549 @@
1
+ import { createId } from "@paralleldrive/cuid2";
2
+ import { CollaborationRepository } from "../modules/collaboration/repository.js";
3
+ import { CollaborationError } from "../modules/collaboration/types.js";
4
+ import { assertRealtimeEvent, assertRealtimeId, assertSequence, DEFAULT_REALTIME_LIMITS, realtimeTopics, } from "../modules/realtime/index.js";
5
+ const COMMON_DIFFERENCE_LIMIT = 500;
6
+ const MAX_COMMON_DIFFERENCE_LIMIT = 1_000;
7
+ const CHAT_DIFFERENCE_LIMIT = 100;
8
+ const MAX_CHAT_DIFFERENCE_LIMIT = 1_000;
9
+ const DEFAULT_TYPING_TTL_MS = 10_000;
10
+ const HEARTBEAT_MS = 15_000;
11
+ const MAX_INITIAL_EVENTS = 256;
12
+ const MAX_SSE_QUEUE_BYTES = 256 * 1024;
13
+ export function registerSyncRoutes(app, auth, repository, pubsub) {
14
+ // Presence connections are intentionally process-local, just like the current PubSub adapter.
15
+ // Keeping ownership here prevents one user from touching another user's connection by id.
16
+ const presenceOwners = new Map();
17
+ app.get("/v0/sync/state", async (request, reply) => {
18
+ const current = await auth.authenticate(request);
19
+ if (!current)
20
+ return unauthorized(reply);
21
+ return { state: await repository.getState(), serverTime: new Date().toISOString() };
22
+ });
23
+ app.post("/v0/sync/getDifference", async (request, reply) => {
24
+ const current = await auth.authenticate(request);
25
+ if (!current)
26
+ return unauthorized(reply);
27
+ try {
28
+ const body = object(request.body, "body");
29
+ const state = object(body.state, "state");
30
+ return await repository.getDifference({
31
+ userId: current.user.id,
32
+ generation: id(state.generation, "state.generation"),
33
+ fromSequence: sequence(state.sequence, "state.sequence"),
34
+ untilSequence: optionalSequence(body.untilSequence, "untilSequence"),
35
+ limit: limit(body.limit, COMMON_DIFFERENCE_LIMIT, MAX_COMMON_DIFFERENCE_LIMIT),
36
+ });
37
+ }
38
+ catch (error) {
39
+ return handledError(reply, error) ?? Promise.reject(error);
40
+ }
41
+ });
42
+ app.post("/v0/sync/acknowledge", async (request, reply) => {
43
+ const current = await auth.authenticate(request);
44
+ if (!current)
45
+ return unauthorized(reply);
46
+ try {
47
+ const body = object(request.body, "body");
48
+ const state = object(body.state, "state");
49
+ await repository.acknowledgeSyncConsumer({
50
+ userId: current.user.id,
51
+ deviceId: id(body.deviceId, "deviceId"),
52
+ generation: id(state.generation, "state.generation"),
53
+ sequence: sequence(state.sequence, "state.sequence"),
54
+ });
55
+ return reply.code(202).send({ accepted: true });
56
+ }
57
+ catch (error) {
58
+ return handledError(reply, error) ?? Promise.reject(error);
59
+ }
60
+ });
61
+ app.post("/v0/chats/:chatId/getDifference", async (request, reply) => {
62
+ const current = await auth.authenticate(request);
63
+ if (!current)
64
+ return unauthorized(reply);
65
+ try {
66
+ const chatId = routeId(request, "chatId");
67
+ const body = object(request.body, "body");
68
+ const state = object(body.state, "state");
69
+ return await repository.getChatDifference({
70
+ userId: current.user.id,
71
+ chatId,
72
+ membershipEpoch: id(state.membershipEpoch, "state.membershipEpoch"),
73
+ fromPts: sequence(state.pts, "state.pts"),
74
+ untilPts: optionalSequence(body.untilPts, "untilPts"),
75
+ limit: limit(body.limit, CHAT_DIFFERENCE_LIMIT, MAX_CHAT_DIFFERENCE_LIMIT),
76
+ });
77
+ }
78
+ catch (error) {
79
+ return handledError(reply, error) ?? Promise.reject(error);
80
+ }
81
+ });
82
+ app.get("/v0/sync/events", async (request, reply) => {
83
+ const current = await auth.authenticate(request);
84
+ if (!current)
85
+ return unauthorized(reply);
86
+ return openEventStream(request, reply, current.user.id, auth, repository, pubsub, presenceOwners);
87
+ });
88
+ app.post("/v0/chats/:chatId/setTyping", async (request, reply) => {
89
+ const current = await auth.authenticate(request);
90
+ if (!current)
91
+ return unauthorized(reply);
92
+ try {
93
+ const chatId = routeId(request, "chatId");
94
+ const body = object(request.body, "body");
95
+ if (typeof body.active !== "boolean")
96
+ throw new RequestValidationError("active must be a boolean");
97
+ const ttlMs = typingTtl(body.ttlMs);
98
+ if (!(await repository.canPostToChat(current.user.id, chatId))) {
99
+ return (await repository.canAccessChat(current.user.id, chatId))
100
+ ? reply.code(403).send({ error: "forbidden" })
101
+ : reply.code(404).send({ error: "not_found" });
102
+ }
103
+ const occurredAt = Date.now();
104
+ const event = body.active
105
+ ? {
106
+ type: "typing",
107
+ chatId,
108
+ userId: current.user.id,
109
+ active: true,
110
+ occurredAt,
111
+ expiresAt: occurredAt + ttlMs,
112
+ }
113
+ : {
114
+ type: "typing",
115
+ chatId,
116
+ userId: current.user.id,
117
+ active: false,
118
+ occurredAt,
119
+ };
120
+ assertRealtimeEvent(event);
121
+ await pubsub.publish(realtimeTopics.chat(chatId), event);
122
+ return reply.code(202).send({ accepted: true });
123
+ }
124
+ catch (error) {
125
+ return handledError(reply, error) ?? Promise.reject(error);
126
+ }
127
+ });
128
+ app.post("/v0/me/updatePresence", async (request, reply) => {
129
+ const current = await auth.authenticate(request);
130
+ if (!current)
131
+ return unauthorized(reply);
132
+ try {
133
+ const body = object(request.body, "body");
134
+ const connectionId = id(body.connectionId, "connectionId");
135
+ if (presenceOwners.get(connectionId) !== current.user.id)
136
+ return reply.code(404).send({ error: "presence_connection_not_found" });
137
+ const presence = await pubsub.recordPresenceActivity(connectionId);
138
+ return presence
139
+ ? { presence }
140
+ : reply.code(404).send({ error: "presence_connection_not_found" });
141
+ }
142
+ catch (error) {
143
+ return handledError(reply, error) ?? Promise.reject(error);
144
+ }
145
+ });
146
+ app.post("/v0/calls/:callId/sendSignal", async (request, reply) => {
147
+ const current = await auth.authenticate(request);
148
+ if (!current)
149
+ return unauthorized(reply);
150
+ try {
151
+ const callId = routeId(request, "callId");
152
+ const body = object(request.body, "body");
153
+ const chatId = id(body.chatId, "chatId");
154
+ const recipientUserId = id(body.recipientUserId, "recipientUserId");
155
+ if (recipientUserId === current.user.id)
156
+ throw new RequestValidationError("recipientUserId must identify another user");
157
+ if (!(await repository.canSignalCall({
158
+ userId: current.user.id,
159
+ callId,
160
+ chatId,
161
+ recipientUserId,
162
+ })))
163
+ return reply.code(404).send({ error: "call_or_recipient_not_found" });
164
+ const event = {
165
+ type: "call.signal",
166
+ callId,
167
+ chatId,
168
+ senderUserId: current.user.id,
169
+ recipientUserId,
170
+ signal: webRtcSignal(body.signal),
171
+ occurredAt: Date.now(),
172
+ };
173
+ assertRealtimeEvent(event);
174
+ await Promise.all([
175
+ pubsub.publish(realtimeTopics.call(callId), event),
176
+ pubsub.publish(realtimeTopics.user(recipientUserId), event),
177
+ ]);
178
+ return reply.code(202).send({ accepted: true });
179
+ }
180
+ catch (error) {
181
+ return handledError(reply, error) ?? Promise.reject(error);
182
+ }
183
+ });
184
+ }
185
+ async function openEventStream(request, reply, userId, auth, repository, pubsub, presenceOwners) {
186
+ const connectionId = createId();
187
+ const subscriptions = new Map();
188
+ const pending = [];
189
+ let responseReady = false;
190
+ let presenceConnected = false;
191
+ let heartbeat;
192
+ let heartbeatRunning = false;
193
+ let closed = false;
194
+ let writer;
195
+ const cleanup = () => {
196
+ if (closed)
197
+ return;
198
+ closed = true;
199
+ if (heartbeat)
200
+ clearInterval(heartbeat);
201
+ for (const unsubscribe of subscriptions.values())
202
+ unsubscribe();
203
+ subscriptions.clear();
204
+ writer?.close();
205
+ if (presenceOwners.get(connectionId) === userId)
206
+ presenceOwners.delete(connectionId);
207
+ if (presenceConnected) {
208
+ presenceConnected = false;
209
+ void pubsub.disconnectPresence(connectionId).catch((error) => {
210
+ request.log.error(error, "Could not disconnect realtime presence");
211
+ });
212
+ }
213
+ };
214
+ const terminate = () => {
215
+ cleanup();
216
+ if (!reply.raw.destroyed && !reply.raw.writableEnded)
217
+ reply.raw.end();
218
+ };
219
+ const send = (name, data) => {
220
+ if (closed)
221
+ return;
222
+ if (!responseReady || !writer) {
223
+ if (pending.length >= MAX_INITIAL_EVENTS) {
224
+ // Never silently discard signaling during stream setup. Closing makes the
225
+ // overflow explicit; durable state is recovered by getDifference on reconnect.
226
+ terminate();
227
+ return;
228
+ }
229
+ pending.push({ name, data });
230
+ return;
231
+ }
232
+ if (!writer.send(name, data))
233
+ terminate();
234
+ };
235
+ const ensureSubscription = (topic) => {
236
+ if (closed || subscriptions.has(topic))
237
+ return;
238
+ subscriptions.set(topic, pubsub.subscribe(topic, async (event) => {
239
+ const visible = await visibleRealtimeEvent(repository, userId, event);
240
+ if (!visible || closed)
241
+ return;
242
+ if (visible.type === "sync") {
243
+ for (const chat of visible.chats)
244
+ ensureSubscription(realtimeTopics.chat(chat.chatId));
245
+ }
246
+ send(visible.type, visible);
247
+ }));
248
+ };
249
+ const reconcileChatSubscriptions = async () => {
250
+ const chats = await repository.listChats(userId);
251
+ const expected = new Set(chats.map((chat) => realtimeTopics.chat(chat.id)));
252
+ for (const topic of expected)
253
+ ensureSubscription(topic);
254
+ for (const [topic, unsubscribe] of subscriptions) {
255
+ if (topic.startsWith("chat:") && !expected.has(topic)) {
256
+ unsubscribe();
257
+ subscriptions.delete(topic);
258
+ }
259
+ }
260
+ };
261
+ request.raw.once("aborted", cleanup);
262
+ reply.raw.once("close", cleanup);
263
+ reply.raw.once("error", cleanup);
264
+ try {
265
+ // Install the broad subscriptions before reading state. Anything delivered during setup is
266
+ // queued, and durable changes are still recovered from the ready-state cursor.
267
+ ensureSubscription(realtimeTopics.user(userId));
268
+ ensureSubscription(realtimeTopics.presence);
269
+ ensureSubscription(realtimeTopics.server);
270
+ await reconcileChatSubscriptions();
271
+ if (closed)
272
+ return;
273
+ await pubsub.connectPresence({ connectionId, userId });
274
+ if (closed) {
275
+ await pubsub.disconnectPresence(connectionId);
276
+ return;
277
+ }
278
+ presenceConnected = true;
279
+ presenceOwners.set(connectionId, userId);
280
+ const state = await repository.getState();
281
+ if (closed)
282
+ return;
283
+ reply.hijack();
284
+ prepareSseResponse(reply);
285
+ writer = new SseWriter(reply.raw, MAX_SSE_QUEUE_BYTES, terminate);
286
+ responseReady = true;
287
+ send("ready", { connectionId, state, heartbeatMs: HEARTBEAT_MS });
288
+ for (const event of pending.splice(0))
289
+ send(event.name, event.data);
290
+ if (closed)
291
+ return;
292
+ heartbeat = setInterval(() => {
293
+ if (closed || heartbeatRunning)
294
+ return;
295
+ heartbeatRunning = true;
296
+ void (async () => {
297
+ const authenticated = await auth.authenticate(request);
298
+ if (!authenticated || authenticated.user.id !== userId) {
299
+ terminate();
300
+ return;
301
+ }
302
+ await reconcileChatSubscriptions();
303
+ const nextState = await repository.getState();
304
+ send("heartbeat", {
305
+ serverTime: new Date().toISOString(),
306
+ state: nextState,
307
+ });
308
+ })()
309
+ .catch((error) => {
310
+ request.log.error(error, "Realtime heartbeat failed");
311
+ terminate();
312
+ })
313
+ .finally(() => {
314
+ heartbeatRunning = false;
315
+ });
316
+ }, HEARTBEAT_MS);
317
+ heartbeat.unref();
318
+ }
319
+ catch (error) {
320
+ cleanup();
321
+ throw error;
322
+ }
323
+ }
324
+ async function visibleRealtimeEvent(repository, userId, event) {
325
+ if (event.type === "presence")
326
+ return event;
327
+ if (event.type === "sync") {
328
+ const chats = [];
329
+ for (const chat of event.chats) {
330
+ if (await repository.canAccessChat(userId, chat.chatId))
331
+ chats.push(chat);
332
+ }
333
+ return { ...event, chats };
334
+ }
335
+ if (event.type === "workspace.changed")
336
+ return (await repository.canAccessChatWorkspace(userId, event.chatId)) ? event : undefined;
337
+ if (!(await repository.canAccessChat(userId, event.chatId)))
338
+ return undefined;
339
+ if (event.type === "call.signal" &&
340
+ event.recipientUserId !== undefined &&
341
+ event.recipientUserId !== userId)
342
+ return undefined;
343
+ return event;
344
+ }
345
+ function prepareSseResponse(reply) {
346
+ // Fastify lifecycle hooks have already populated response headers (notably CORS); copying them
347
+ // before the raw response is flushed preserves those headers after hijacking the response.
348
+ for (const [name, value] of Object.entries(reply.getHeaders())) {
349
+ if (value !== undefined)
350
+ reply.raw.setHeader(name, value);
351
+ }
352
+ reply.raw.statusCode = 200;
353
+ reply.raw.setHeader("content-type", "text/event-stream; charset=utf-8");
354
+ reply.raw.setHeader("cache-control", "no-cache, no-transform");
355
+ reply.raw.setHeader("connection", "keep-alive");
356
+ reply.raw.setHeader("x-accel-buffering", "no");
357
+ reply.raw.socket?.setKeepAlive(true);
358
+ reply.raw.flushHeaders();
359
+ }
360
+ class SseWriter {
361
+ response;
362
+ maxQueuedBytes;
363
+ onFailure;
364
+ queued = [];
365
+ queuedBytes = 0;
366
+ blocked = false;
367
+ closed = false;
368
+ constructor(response, maxQueuedBytes, onFailure) {
369
+ this.response = response;
370
+ this.maxQueuedBytes = maxQueuedBytes;
371
+ this.onFailure = onFailure;
372
+ }
373
+ send(name, data) {
374
+ if (this.closed || this.response.destroyed || this.response.writableEnded)
375
+ return false;
376
+ const frame = `event: ${name}\ndata: ${JSON.stringify(data)}\n\n`;
377
+ const bytes = Buffer.byteLength(frame);
378
+ if (this.blocked) {
379
+ if (this.queuedBytes + bytes > this.maxQueuedBytes)
380
+ return false;
381
+ this.queued.push(frame);
382
+ this.queuedBytes += bytes;
383
+ return true;
384
+ }
385
+ try {
386
+ if (!this.response.write(frame)) {
387
+ this.blocked = true;
388
+ this.response.once("drain", this.flush);
389
+ }
390
+ return true;
391
+ }
392
+ catch {
393
+ return false;
394
+ }
395
+ }
396
+ close() {
397
+ if (this.closed)
398
+ return;
399
+ this.closed = true;
400
+ this.response.off("drain", this.flush);
401
+ this.queued.length = 0;
402
+ this.queuedBytes = 0;
403
+ }
404
+ flush = () => {
405
+ if (this.closed)
406
+ return;
407
+ this.blocked = false;
408
+ while (this.queued.length > 0) {
409
+ const frame = this.queued.shift();
410
+ this.queuedBytes -= Buffer.byteLength(frame);
411
+ try {
412
+ if (!this.response.write(frame)) {
413
+ this.blocked = true;
414
+ this.response.once("drain", this.flush);
415
+ return;
416
+ }
417
+ }
418
+ catch {
419
+ this.onFailure();
420
+ return;
421
+ }
422
+ }
423
+ };
424
+ }
425
+ function object(value, name) {
426
+ if (!value || typeof value !== "object" || Array.isArray(value))
427
+ throw new RequestValidationError(`${name} must be an object`);
428
+ return value;
429
+ }
430
+ function id(value, name) {
431
+ if (typeof value !== "string")
432
+ throw new RequestValidationError(`${name} must be a string`);
433
+ try {
434
+ assertRealtimeId(value, name);
435
+ return value;
436
+ }
437
+ catch (error) {
438
+ throw new RequestValidationError(message(error));
439
+ }
440
+ }
441
+ function routeId(request, name) {
442
+ return id(request.params?.[name], name);
443
+ }
444
+ function sequence(value, name) {
445
+ if (typeof value !== "string")
446
+ throw new RequestValidationError(`${name} must be an unsigned decimal string`);
447
+ try {
448
+ assertSequence(value, name);
449
+ }
450
+ catch (error) {
451
+ throw new RequestValidationError(message(error));
452
+ }
453
+ const parsed = Number(value);
454
+ if (!Number.isSafeInteger(parsed))
455
+ throw new RequestValidationError(`${name} exceeds the supported integer range`);
456
+ return parsed;
457
+ }
458
+ function optionalSequence(value, name) {
459
+ return value === undefined ? undefined : sequence(value, name);
460
+ }
461
+ function limit(value, fallback, maximum) {
462
+ if (value === undefined)
463
+ return fallback;
464
+ if (!Number.isSafeInteger(value) || value < 1 || value > maximum)
465
+ throw new RequestValidationError(`limit must be an integer between 1 and ${maximum}`);
466
+ return value;
467
+ }
468
+ function typingTtl(value) {
469
+ if (value === undefined)
470
+ return DEFAULT_TYPING_TTL_MS;
471
+ if (!Number.isSafeInteger(value) ||
472
+ value < 1 ||
473
+ value > DEFAULT_REALTIME_LIMITS.maxTypingTtlMs)
474
+ throw new RequestValidationError(`ttlMs must be an integer between 1 and ${DEFAULT_REALTIME_LIMITS.maxTypingTtlMs}`);
475
+ return value;
476
+ }
477
+ function webRtcSignal(value) {
478
+ const signal = object(value, "signal");
479
+ if (signal.kind === "offer" || signal.kind === "answer") {
480
+ if (typeof signal.sdp !== "string")
481
+ throw new RequestValidationError("signal.sdp must be a string");
482
+ return { kind: signal.kind, sdp: signal.sdp };
483
+ }
484
+ if (signal.kind === "ice-candidate") {
485
+ if (typeof signal.candidate !== "string")
486
+ throw new RequestValidationError("signal.candidate must be a string");
487
+ if (signal.sdpMid !== undefined &&
488
+ signal.sdpMid !== null &&
489
+ typeof signal.sdpMid !== "string")
490
+ throw new RequestValidationError("signal.sdpMid must be a string or null");
491
+ if (signal.sdpMLineIndex !== undefined &&
492
+ signal.sdpMLineIndex !== null &&
493
+ (!Number.isSafeInteger(signal.sdpMLineIndex) || signal.sdpMLineIndex < 0))
494
+ throw new RequestValidationError("signal.sdpMLineIndex must be a non-negative integer");
495
+ if (signal.usernameFragment !== undefined &&
496
+ signal.usernameFragment !== null &&
497
+ typeof signal.usernameFragment !== "string")
498
+ throw new RequestValidationError("signal.usernameFragment must be a string or null");
499
+ return {
500
+ kind: "ice-candidate",
501
+ candidate: signal.candidate,
502
+ sdpMid: signal.sdpMid,
503
+ sdpMLineIndex: signal.sdpMLineIndex,
504
+ usernameFragment: signal.usernameFragment,
505
+ };
506
+ }
507
+ if (signal.kind === "hangup") {
508
+ if (signal.reason !== undefined &&
509
+ signal.reason !== "ended" &&
510
+ signal.reason !== "declined" &&
511
+ signal.reason !== "busy" &&
512
+ signal.reason !== "failed")
513
+ throw new RequestValidationError("signal.reason is invalid");
514
+ return {
515
+ kind: "hangup",
516
+ reason: signal.reason,
517
+ };
518
+ }
519
+ throw new RequestValidationError("signal.kind is invalid");
520
+ }
521
+ function handledError(reply, error) {
522
+ if (error instanceof RequestValidationError)
523
+ return reply.code(400).send({ error: "invalid_request", message: error.message });
524
+ if (!(error instanceof CollaborationError))
525
+ return undefined;
526
+ const status = {
527
+ not_found: 404,
528
+ forbidden: 403,
529
+ invalid: 400,
530
+ conflict: 409,
531
+ future_state: 409,
532
+ generation_mismatch: 409,
533
+ }[error.code];
534
+ const responseCode = error.code === "invalid"
535
+ ? "invalid_request"
536
+ : error.code === "future_state"
537
+ ? "future_sync_state"
538
+ : error.code;
539
+ return reply.code(status).send({ error: responseCode, message: error.message });
540
+ }
541
+ function unauthorized(reply) {
542
+ return reply.code(401).send({ error: "unauthorized" });
543
+ }
544
+ function message(error) {
545
+ return error instanceof Error ? error.message : "Invalid request";
546
+ }
547
+ class RequestValidationError extends Error {
548
+ }
549
+ //# sourceMappingURL=sync.js.map