appos 0.3.5-0 → 0.3.6-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/bin/main.mjs +2 -2
  2. package/dist/exports/api/adapter-C2mMJKvG.mjs +1504 -0
  3. package/dist/exports/api/{auth-schema.mjs → auth-schema-CON4yFFY.mjs} +2 -3
  4. package/dist/exports/api/bun-sqlite-dialect-CPpPZa23.mjs +155 -0
  5. package/dist/exports/{cli/_virtual/rolldown_runtime.mjs → api/chunk-CyXqrcp_.mjs} +14 -1
  6. package/dist/exports/api/conditions-DjBAWfiK.mjs +116 -0
  7. package/dist/exports/api/dialect-CUUD24Ge.mjs +72 -0
  8. package/dist/exports/api/env-CwT3zhez.mjs +1 -0
  9. package/dist/exports/api/esm-_hkVMulx.mjs +15816 -0
  10. package/dist/exports/api/event-BHFSE6hY.mjs +20983 -0
  11. package/dist/exports/api/extract-blob-metadata-BMgUEPcW.mjs +4 -0
  12. package/dist/exports/api/extract-blob-metadata-_9RUEwoU.mjs +9818 -0
  13. package/dist/exports/api/generate-image-variant-DOIzj1wJ.mjs +4 -0
  14. package/dist/exports/api/generate-image-variant-DxOPoGAk.mjs +118 -0
  15. package/dist/exports/api/generate-preview-CvTFuq58.mjs +160 -0
  16. package/dist/exports/api/generate-preview-Dk3coswZ.mjs +4 -0
  17. package/dist/exports/api/index.d.mts +7347 -20
  18. package/dist/exports/api/index.mjs +146856 -18
  19. package/dist/exports/api/kysely-adapter-CmP2TbkS.mjs +296 -0
  20. package/dist/exports/api/memory-adapter-BzhRhLFK.mjs +212 -0
  21. package/dist/exports/api/node-sqlite-dialect-Bl5suBxl.mjs +155 -0
  22. package/dist/exports/api/orm-CMqufD21.mjs +153690 -0
  23. package/dist/exports/api/orm-DXqYuKvB.d.mts +11 -0
  24. package/dist/exports/api/orm.d.mts +2 -11
  25. package/dist/exports/api/orm.mjs +4 -42
  26. package/dist/exports/api/pdf-YxB2Hm1p.mjs +25822 -0
  27. package/dist/exports/api/purge-attachment-Cf6KH2Jv.mjs +34 -0
  28. package/dist/exports/api/purge-attachment-DIuil7ps.mjs +4 -0
  29. package/dist/exports/{cli/api/workflows/purge-audit-logs.mjs → api/purge-audit-logs-z6j_Pu47.mjs} +3 -3
  30. package/dist/exports/{cli/api/workflows/purge-unattached-blobs.mjs → api/purge-unattached-blobs-B0TfY5Hk.mjs} +1 -1
  31. package/dist/exports/api/react-BYhV5bYt.mjs +1131 -0
  32. package/dist/exports/api/server.node-DyVrQ6cz.mjs +19298 -0
  33. package/dist/exports/api/table-6bTIEqON.mjs +2636 -0
  34. package/dist/exports/api/{workflows/track-db-changes.mjs → track-db-changes-BysaV6nN.mjs} +14 -14
  35. package/dist/exports/api/{workflow.mjs → workflow-BuSWHcX-.mjs} +121 -10
  36. package/dist/exports/api/workflows/auth-schema-BFve3hgZ.mjs +2813 -0
  37. package/dist/exports/api/{_virtual/rolldown_runtime.mjs → workflows/chunk-B36mNPO4.mjs} +5 -1
  38. package/dist/exports/api/workflows/extract-blob-metadata-BcWKvY2K.mjs +9818 -0
  39. package/dist/exports/api/workflows/{generate-image-variant.mjs → generate-image-variant-BAFvL_zV.mjs} +20 -20
  40. package/dist/exports/{cli/api/workflows/generate-preview.mjs → api/workflows/generate-preview-BjlIVYYp.mjs} +6 -6
  41. package/dist/exports/api/workflows/index.d.mts +2011 -1
  42. package/dist/exports/api/workflows/index.mjs +2 -1
  43. package/dist/exports/api/workflows/pdf-DUB8zyIc.mjs +25822 -0
  44. package/dist/exports/{cli/api/workflows/purge-attachment.mjs → api/workflows/purge-attachment-k_sdxTPY.mjs} +3 -3
  45. package/dist/exports/api/workflows/{purge-audit-logs.mjs → purge-audit-logs-zCyWj4Mw.mjs} +12 -3
  46. package/dist/exports/api/workflows/{purge-unattached-blobs.mjs → purge-unattached-blobs-CdsuFAeW.mjs} +1 -1
  47. package/dist/exports/api/workflows/track-db-changes-CiKaI9gT.mjs +20943 -0
  48. package/dist/exports/api/workflows/track-db-changes-DEWQYryO.mjs +4 -0
  49. package/dist/exports/{cli/api/workflow.mjs → api/workflows/workflow-BjM2xCa6.mjs} +23 -3
  50. package/dist/exports/api/workflows/zod-Br0enFWK.mjs +12333 -0
  51. package/dist/exports/api/zod-CdrJdBtV.mjs +12571 -0
  52. package/dist/exports/cli/auth-schema-CNuOqPi-.mjs +2813 -0
  53. package/dist/exports/{api/workflows/_virtual/rolldown_runtime.mjs → cli/chunk-B36mNPO4.mjs} +5 -1
  54. package/dist/exports/cli/extract-blob-metadata-CV1Ke90d.mjs +9818 -0
  55. package/dist/exports/cli/{api/workflows/generate-image-variant.mjs → generate-image-variant-CM1BrVvZ.mjs} +20 -20
  56. package/dist/exports/{api/workflows/generate-preview.mjs → cli/generate-preview-DdHQ3ukz.mjs} +6 -6
  57. package/dist/exports/cli/index.d.mts +2142 -2
  58. package/dist/exports/cli/index.mjs +41 -1
  59. package/dist/exports/cli/pdf-CLUPEIdT.mjs +25822 -0
  60. package/dist/exports/{api/workflows/purge-attachment.mjs → cli/purge-attachment-Dc_J74dG.mjs} +3 -3
  61. package/dist/exports/cli/purge-audit-logs-DFhWh-Bx.mjs +56 -0
  62. package/dist/exports/cli/purge-unattached-blobs-C1MRlM_2.mjs +46 -0
  63. package/dist/exports/cli/track-db-changes-CfneOF2_.mjs +20943 -0
  64. package/dist/exports/{api/workflows/api/workflow.mjs → cli/workflow-DSbbXBMt.mjs} +23 -3
  65. package/dist/exports/cli/zod-7q0_Mtnn.mjs +12333 -0
  66. package/dist/exports/devtools/BaseTanStackRouterDevtoolsPanel-BBz1qLry-DUwdvyLv.js +2090 -0
  67. package/dist/exports/devtools/EIDV623S-B7f6114d.js +2497 -0
  68. package/dist/exports/devtools/FloatingTanStackRouterDevtools-DymJEvfG-BHuQHiRR.js +237 -0
  69. package/dist/exports/devtools/MIMHJGAX-Cb3wf11F.js +10903 -0
  70. package/dist/exports/devtools/Q7LWSL4U-BoEO3rNq.js +37 -0
  71. package/dist/exports/devtools/VLTTJS3N-CIyRc84e.js +44 -0
  72. package/dist/exports/devtools/index.js +1724 -3
  73. package/dist/exports/devtools/utils-YRTCpRgb.js +1670 -0
  74. package/dist/exports/tests/api.d.mts +7354 -5
  75. package/dist/exports/tests/api.mjs +79 -1
  76. package/dist/exports/tests/auth-schema-DUCJw-_2.mjs +1 -0
  77. package/dist/exports/tests/chunk-Cii4FAhs.mjs +1 -0
  78. package/dist/exports/tests/conditions-B0ffVJ5E.mjs +1 -0
  79. package/dist/exports/tests/constants-DHjjg05J.mjs +1 -0
  80. package/dist/exports/tests/dist-D6vgKv3t.mjs +7 -0
  81. package/dist/exports/tests/dist-EfrRkq5c.mjs +296 -0
  82. package/dist/exports/tests/extract-blob-metadata-Dv343Vcn.mjs +169 -0
  83. package/dist/exports/tests/generate-image-variant-cQc8q0kh.mjs +1 -0
  84. package/dist/exports/tests/generate-preview-HaTMd2hS.mjs +1 -0
  85. package/dist/exports/tests/magic-string.es-D6VRmdiF.mjs +14 -0
  86. package/dist/exports/tests/mock-BvkO5nlm.mjs +1 -0
  87. package/dist/exports/tests/mock.mjs +1 -1
  88. package/dist/exports/tests/pdf-BDsS3vjF.mjs +13 -0
  89. package/dist/exports/tests/purge-attachment-D4uOzHRi.mjs +1 -0
  90. package/dist/exports/tests/purge-audit-logs-DiPcc09d.mjs +1 -0
  91. package/dist/exports/tests/purge-unattached-blobs-CqW6tlIC.mjs +1 -0
  92. package/dist/exports/tests/react.mjs +6 -1
  93. package/dist/exports/tests/setup.d.mts +1 -1
  94. package/dist/exports/tests/setup.mjs +34 -1
  95. package/dist/exports/tests/table-CbU04119.mjs +1 -0
  96. package/dist/exports/tests/track-db-changes-Bd4W-P1q.mjs +1 -0
  97. package/dist/exports/tests/vi.2VT5v0um-Cme1b0Dl.mjs +348 -0
  98. package/dist/exports/tests/{api/workflow.mjs → workflow-DwZxTqdH.mjs} +1 -1
  99. package/dist/exports/tests/zod-DcpxsMPz.mjs +23 -0
  100. package/dist/exports/vendors/date.js +13236 -1
  101. package/dist/exports/vendors/toolkit.js +2206 -1
  102. package/dist/exports/vendors/zod.js +12344 -1
  103. package/dist/exports/vite/api-DGRU_RdM.mjs +27 -0
  104. package/dist/exports/vite/build-CxJAu2Bn.mjs +1 -0
  105. package/dist/exports/vite/build2-BMK0OFVt.mjs +16 -0
  106. package/dist/exports/vite/chunk-CxnlK1Zi.mjs +1 -0
  107. package/dist/exports/vite/chunk-PtveFMYu.mjs +1 -0
  108. package/dist/exports/vite/dist-Bxp8DqWh.mjs +114 -0
  109. package/dist/exports/vite/dist-CX51FKbX.mjs +1 -0
  110. package/dist/exports/vite/dist-DcyNr-KR.mjs +1 -0
  111. package/dist/exports/vite/dist-j3-Khlzt.mjs +1 -0
  112. package/dist/exports/vite/experimental-index-3KsfmUbz.mjs +1 -0
  113. package/dist/exports/vite/false-BNJbUKYT.mjs +1 -0
  114. package/dist/exports/vite/false-BvrPEDU6.mjs +1 -0
  115. package/dist/exports/vite/index.d.mts +1 -1
  116. package/dist/exports/vite/index.mjs +26 -1
  117. package/dist/exports/vite/internal-C5cVwRiK.mjs +1 -0
  118. package/dist/exports/vite/jiti-BjSPrFvg.mjs +9 -0
  119. package/dist/exports/vite/lexer-DQCqS3nf-C6xCDOEQ.mjs +3 -0
  120. package/dist/exports/vite/lib-CMv7Sfwa.mjs +1 -0
  121. package/dist/exports/vite/lib-D9TnS-7w.mjs +1 -0
  122. package/dist/exports/vite/lib-DuBRr9dH.mjs +382 -0
  123. package/dist/exports/vite/node-DI8AnY_i.mjs +437 -0
  124. package/dist/exports/vite/postcss-BtmDpj-c.mjs +32 -0
  125. package/dist/exports/vite/postcss-import-Bk_ZCd6c.mjs +5 -0
  126. package/dist/exports/vite/rolldown-build-CNW2eye_-CJNfyXdF.mjs +13 -0
  127. package/dist/exports/vitest/api-CPv6lnxG.mjs +27 -0
  128. package/dist/exports/vitest/build2-28i3OiJ3.mjs +16 -0
  129. package/dist/exports/vitest/chunk-_e2jlDPK.mjs +1 -0
  130. package/dist/exports/vitest/chunk-jwDkFoXW.mjs +1 -0
  131. package/dist/exports/vitest/config.mjs +77 -1
  132. package/dist/exports/vitest/dist-L-OpshPJ.mjs +114 -0
  133. package/dist/exports/vitest/index.mjs +348 -1
  134. package/dist/exports/vitest/jiti-eNGOyHIo.mjs +9 -0
  135. package/dist/exports/vitest/lexer-DQCqS3nf-TWLyIqlY.mjs +3 -0
  136. package/dist/exports/vitest/lib-C3G64csm.mjs +1 -0
  137. package/dist/exports/vitest/magic-string.es-CxM5Ubyl.mjs +14 -0
  138. package/dist/exports/vitest/module-runner-DsF4L04D.mjs +1 -0
  139. package/dist/exports/vitest/postcss-BxLp_Too.mjs +32 -0
  140. package/dist/exports/vitest/postcss-import-5pKj3f5q.mjs +5 -0
  141. package/dist/exports/web/browser-ponyfill-DxTJMXNq.js +443 -0
  142. package/dist/exports/web/chunk-DksrlJLg.js +49 -0
  143. package/dist/exports/web/index.d.ts +2546 -2
  144. package/dist/exports/web/index.js +9295 -6
  145. package/dist/exports/web/plugin-DqTFWG7p.js +250 -0
  146. package/package.json +1 -1
  147. package/dist/exports/api/app-context.d.mts +0 -115
  148. package/dist/exports/api/app-context.mjs +0 -24
  149. package/dist/exports/api/auth-schema.d.mts +0 -4248
  150. package/dist/exports/api/auth.d.mts +0 -402
  151. package/dist/exports/api/auth.mjs +0 -188
  152. package/dist/exports/api/cache.d.mts +0 -44
  153. package/dist/exports/api/cache.mjs +0 -28
  154. package/dist/exports/api/config.d.mts +0 -28
  155. package/dist/exports/api/config.mjs +0 -72
  156. package/dist/exports/api/constants.mjs +0 -92
  157. package/dist/exports/api/container.d.mts +0 -210
  158. package/dist/exports/api/container.mjs +0 -49
  159. package/dist/exports/api/database.d.mts +0 -101
  160. package/dist/exports/api/database.mjs +0 -219
  161. package/dist/exports/api/event.d.mts +0 -235
  162. package/dist/exports/api/event.mjs +0 -236
  163. package/dist/exports/api/i18n.d.mts +0 -34
  164. package/dist/exports/api/i18n.mjs +0 -45
  165. package/dist/exports/api/instrumentation.d.mts +0 -7
  166. package/dist/exports/api/instrumentation.mjs +0 -40
  167. package/dist/exports/api/logger.d.mts +0 -21
  168. package/dist/exports/api/logger.mjs +0 -26
  169. package/dist/exports/api/mailer.d.mts +0 -70
  170. package/dist/exports/api/mailer.mjs +0 -37
  171. package/dist/exports/api/middleware/request-logger.d.mts +0 -24
  172. package/dist/exports/api/middleware.d.mts +0 -39
  173. package/dist/exports/api/middleware.mjs +0 -73
  174. package/dist/exports/api/openapi.d.mts +0 -271
  175. package/dist/exports/api/openapi.mjs +0 -507
  176. package/dist/exports/api/otel.d.mts +0 -40
  177. package/dist/exports/api/otel.mjs +0 -56
  178. package/dist/exports/api/redis.d.mts +0 -34
  179. package/dist/exports/api/redis.mjs +0 -41
  180. package/dist/exports/api/storage-schema.d.mts +0 -707
  181. package/dist/exports/api/storage-schema.mjs +0 -72
  182. package/dist/exports/api/storage.d.mts +0 -506
  183. package/dist/exports/api/storage.mjs +0 -833
  184. package/dist/exports/api/web/auth.mjs +0 -17
  185. package/dist/exports/api/workflow.d.mts +0 -250
  186. package/dist/exports/api/workflows/api/auth-schema.mjs +0 -373
  187. package/dist/exports/api/workflows/api/auth.d.mts +0 -379
  188. package/dist/exports/api/workflows/api/cache.d.mts +0 -44
  189. package/dist/exports/api/workflows/api/config.d.mts +0 -18
  190. package/dist/exports/api/workflows/api/container.d.mts +0 -167
  191. package/dist/exports/api/workflows/api/database.d.mts +0 -47
  192. package/dist/exports/api/workflows/api/event.d.mts +0 -68
  193. package/dist/exports/api/workflows/api/event.mjs +0 -126
  194. package/dist/exports/api/workflows/api/logger.d.mts +0 -21
  195. package/dist/exports/api/workflows/api/mailer.d.mts +0 -70
  196. package/dist/exports/api/workflows/api/orm.d.mts +0 -13
  197. package/dist/exports/api/workflows/api/redis.mjs +0 -3
  198. package/dist/exports/api/workflows/api/storage-schema.d.mts +0 -699
  199. package/dist/exports/api/workflows/api/storage.d.mts +0 -396
  200. package/dist/exports/api/workflows/api/workflow.d.mts +0 -24
  201. package/dist/exports/api/workflows/constants.mjs +0 -23
  202. package/dist/exports/api/workflows/extract-blob-metadata.mjs +0 -132
  203. package/dist/exports/api/workflows/generate-image-variant.d.mts +0 -63
  204. package/dist/exports/api/workflows/track-db-changes.d.mts +0 -72
  205. package/dist/exports/cli/api/auth-schema.mjs +0 -373
  206. package/dist/exports/cli/api/auth.d.mts +0 -379
  207. package/dist/exports/cli/api/cache.d.mts +0 -44
  208. package/dist/exports/cli/api/config.d.mts +0 -18
  209. package/dist/exports/cli/api/container.d.mts +0 -167
  210. package/dist/exports/cli/api/database.d.mts +0 -47
  211. package/dist/exports/cli/api/event.d.mts +0 -68
  212. package/dist/exports/cli/api/event.mjs +0 -126
  213. package/dist/exports/cli/api/logger.d.mts +0 -21
  214. package/dist/exports/cli/api/mailer.d.mts +0 -70
  215. package/dist/exports/cli/api/orm.d.mts +0 -13
  216. package/dist/exports/cli/api/redis.mjs +0 -3
  217. package/dist/exports/cli/api/storage-schema.d.mts +0 -699
  218. package/dist/exports/cli/api/storage.d.mts +0 -396
  219. package/dist/exports/cli/api/workflow.d.mts +0 -2
  220. package/dist/exports/cli/api/workflows/extract-blob-metadata.mjs +0 -132
  221. package/dist/exports/cli/api/workflows/generate-image-variant.d.mts +0 -63
  222. package/dist/exports/cli/api/workflows/track-db-changes.mjs +0 -110
  223. package/dist/exports/cli/command.d.mts +0 -56
  224. package/dist/exports/cli/command.mjs +0 -43
  225. package/dist/exports/cli/constants.mjs +0 -23
  226. package/dist/exports/cli/context.d.mts +0 -170
  227. package/dist/exports/tests/_virtual/rolldown_runtime.mjs +0 -1
  228. package/dist/exports/tests/api/app-context.d.mts +0 -115
  229. package/dist/exports/tests/api/app-context.mjs +0 -1
  230. package/dist/exports/tests/api/auth-schema.d.mts +0 -4248
  231. package/dist/exports/tests/api/auth-schema.mjs +0 -1
  232. package/dist/exports/tests/api/auth.d.mts +0 -402
  233. package/dist/exports/tests/api/cache.d.mts +0 -44
  234. package/dist/exports/tests/api/config.d.mts +0 -28
  235. package/dist/exports/tests/api/container.d.mts +0 -210
  236. package/dist/exports/tests/api/database.d.mts +0 -101
  237. package/dist/exports/tests/api/database.mjs +0 -1
  238. package/dist/exports/tests/api/event.d.mts +0 -235
  239. package/dist/exports/tests/api/event.mjs +0 -1
  240. package/dist/exports/tests/api/i18n.d.mts +0 -34
  241. package/dist/exports/tests/api/index.d.mts +0 -26
  242. package/dist/exports/tests/api/logger.d.mts +0 -21
  243. package/dist/exports/tests/api/mailer.d.mts +0 -70
  244. package/dist/exports/tests/api/middleware/error-handler.mjs +0 -1
  245. package/dist/exports/tests/api/middleware/health.mjs +0 -1
  246. package/dist/exports/tests/api/middleware/i18n.mjs +0 -1
  247. package/dist/exports/tests/api/middleware/request-logger.d.mts +0 -24
  248. package/dist/exports/tests/api/middleware/request-logger.mjs +0 -1
  249. package/dist/exports/tests/api/middleware/shutdown.mjs +0 -1
  250. package/dist/exports/tests/api/middleware/timeout.mjs +0 -1
  251. package/dist/exports/tests/api/middleware.d.mts +0 -39
  252. package/dist/exports/tests/api/middleware.mjs +0 -1
  253. package/dist/exports/tests/api/openapi.d.mts +0 -271
  254. package/dist/exports/tests/api/openapi.mjs +0 -1
  255. package/dist/exports/tests/api/orm.d.mts +0 -13
  256. package/dist/exports/tests/api/otel.d.mts +0 -40
  257. package/dist/exports/tests/api/redis.d.mts +0 -34
  258. package/dist/exports/tests/api/redis.mjs +0 -1
  259. package/dist/exports/tests/api/server.mjs +0 -1
  260. package/dist/exports/tests/api/storage-schema.d.mts +0 -707
  261. package/dist/exports/tests/api/storage.d.mts +0 -506
  262. package/dist/exports/tests/api/workflow.d.mts +0 -250
  263. package/dist/exports/tests/api/workflows/extract-blob-metadata.mjs +0 -1
  264. package/dist/exports/tests/api/workflows/generate-image-variant.d.mts +0 -63
  265. package/dist/exports/tests/api/workflows/generate-image-variant.mjs +0 -1
  266. package/dist/exports/tests/api/workflows/generate-preview.mjs +0 -1
  267. package/dist/exports/tests/api/workflows/purge-attachment.mjs +0 -1
  268. package/dist/exports/tests/api/workflows/purge-audit-logs.mjs +0 -1
  269. package/dist/exports/tests/api/workflows/purge-unattached-blobs.mjs +0 -1
  270. package/dist/exports/tests/api/workflows/track-db-changes.mjs +0 -1
  271. package/dist/exports/tests/constants.mjs +0 -1
  272. package/dist/exports/tests/instrumentation.d.mts +0 -7
  273. package/dist/exports/tests/instrumentation.mjs +0 -1
  274. package/dist/exports/web/api/auth.d.ts +0 -125
  275. package/dist/exports/web/api/database.d.ts +0 -4
  276. package/dist/exports/web/api/logger.d.ts +0 -1
  277. package/dist/exports/web/auth.d.ts +0 -2388
  278. package/dist/exports/web/auth.js +0 -75
  279. package/dist/exports/web/i18n.d.ts +0 -42
  280. package/dist/exports/web/i18n.js +0 -45
  281. /package/dist/exports/tests/{api/middleware/youch-handler.mjs → youch-handler-Ch5yf6im.mjs} +0 -0
@@ -1,219 +0,0 @@
1
- import { APPOS_DIR, DATABASES_DIR } from "./constants.mjs";
2
- import { getTableName, sql } from "drizzle-orm";
3
- import { join } from "node:path";
4
- import { drizzle } from "drizzle-orm/node-postgres";
5
- import { migrate } from "drizzle-orm/node-postgres/migrator";
6
- import pg from "pg";
7
-
8
- //#region src/api/database.ts
9
- const { Client, Pool: Pool$1 } = pg;
10
- /**
11
- * The schema used for migrations.
12
- */
13
- const migrationsSchema = "public";
14
- /**
15
- * Get the migration options for a specific database.
16
- *
17
- * @param name Name of the database to get migration options for
18
- * @param type Type of migration (schema or data), defaults to "schema"
19
- * @returns Migration configuration for drizzle-orm
20
- */
21
- function defineMigrationOpts(name, type = "schema") {
22
- const folder = type === "schema" ? "schema-migrations" : "data-migrations";
23
- const table = type === "schema" ? "schema-migrations" : "data-migrations";
24
- return {
25
- migrationsFolder: `${join(APPOS_DIR, DATABASES_DIR)}/${name}/${folder}`,
26
- migrationsSchema,
27
- migrationsTable: table
28
- };
29
- }
30
- /**
31
- * The database logger.
32
- */
33
- var DatabaseLogger = class {
34
- #logger;
35
- constructor(logger) {
36
- this.#logger = logger;
37
- }
38
- logQuery(query, params) {
39
- this.#logger.info(params, query);
40
- }
41
- };
42
- /**
43
- * Generate old and new row JSONB representations for delete/insert/update queries.
44
- * Uses PostgreSQL 18's OLD/NEW support in RETURNING clause.
45
- *
46
- * @param table The table to generate changes for.
47
- * @returns Object containing `_table`, `old` and `new` JSONB columns.
48
- */
49
- function dbChanges(table) {
50
- const tableName = getTableName(table);
51
- return {
52
- _table: sql`${sql.raw(`'${tableName}'`)}`.as("_table"),
53
- old: sql`to_jsonb(OLD.*)`.as("old"),
54
- new: sql`to_jsonb(NEW.*)`.as("new")
55
- };
56
- }
57
- /**
58
- * Define the database with the provided options.
59
- *
60
- * Algorithm:
61
- * 1. Create a connection pool with sensible defaults
62
- * 2. Initialize drizzle ORM with schema and relations
63
- *
64
- * @param opts The options for defining the database, including pool configuration, relations, and schema.
65
- * @template TSchema The schema type for the database.
66
- * @template TRelations The relations type for the database.
67
- * @returns The defined database instance.
68
- */
69
- async function defineDatabase(opts) {
70
- return drizzle({
71
- client: new Pool$1({
72
- application_name: "appos",
73
- max: 16,
74
- ...opts.poolConfig
75
- }),
76
- logger: new DatabaseLogger(opts.logger),
77
- relations: opts.relations,
78
- schema: opts.schema
79
- });
80
- }
81
- /**
82
- * Create a single test database with isolated schema.
83
- *
84
- * @param connectionString - Database connection string
85
- * @param name - Name of the test database
86
- * @returns Test database instance and cleanup function
87
- */
88
- async function defineTestDatabase(opts) {
89
- const dbName = `test_w${process.env.VITEST_POOL_ID || "0"}_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
90
- await ensureTemplateDatabase(opts.connectionString, opts.name, opts.logger);
91
- const templateDbName = `${opts.name}_test_template`;
92
- const maintenanceUrl = getMaintenanceDbUrl(opts.connectionString);
93
- const maintenanceClient = new Client({ connectionString: maintenanceUrl });
94
- await maintenanceClient.connect();
95
- try {
96
- await maintenanceClient.query(`CREATE DATABASE ${dbName} WITH TEMPLATE ${templateDbName}`);
97
- } finally {
98
- await maintenanceClient.end();
99
- }
100
- const testComponents = parsePostgresUrl(opts.connectionString);
101
- testComponents.database = dbName;
102
- const testPool = new Pool$1({ connectionString: buildPostgresUrl(testComponents) });
103
- const db = drizzle({
104
- client: testPool,
105
- logger: opts.logger ? new DatabaseLogger(opts.logger) : void 0,
106
- relations: opts.relations,
107
- schema: opts.schema
108
- });
109
- const cleanUp = async () => {
110
- await testPool.end();
111
- const cleanupClient = new Client({ connectionString: maintenanceUrl });
112
- await cleanupClient.connect();
113
- try {
114
- await cleanupClient.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1`, [dbName]);
115
- await cleanupClient.query(`DROP DATABASE IF EXISTS ${dbName}`);
116
- } catch (error) {
117
- console.error("Could not drop test database:", error);
118
- } finally {
119
- await cleanupClient.end();
120
- }
121
- };
122
- return {
123
- cleanUp,
124
- db,
125
- dbName
126
- };
127
- }
128
- /**
129
- * Parse PostgreSQL connection URL into components.
130
- *
131
- * @param connectionString - PostgreSQL connection URL
132
- * @returns Parsed URL components
133
- */
134
- function parsePostgresUrl(connectionString) {
135
- const url = new URL(connectionString);
136
- return {
137
- database: url.pathname.slice(1) || "postgres",
138
- host: url.hostname,
139
- password: decodeURIComponent(url.password),
140
- port: Number.parseInt(url.port || "5432", 10),
141
- user: decodeURIComponent(url.username)
142
- };
143
- }
144
- /**
145
- * Build PostgreSQL connection URL from components.
146
- *
147
- * @param components - URL components
148
- * @returns PostgreSQL connection URL
149
- */
150
- function buildPostgresUrl(components) {
151
- const { user, password, host, port, database } = components;
152
- return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
153
- }
154
- /**
155
- * Get connection URL for maintenance database operations.
156
- *
157
- * @param connectionString - Original connection string
158
- * @returns Connection string to maintenance database
159
- */
160
- function getMaintenanceDbUrl(connectionString) {
161
- const components = parsePostgresUrl(connectionString);
162
- components.database = "postgres";
163
- return buildPostgresUrl(components);
164
- }
165
- /**
166
- * Generate deterministic advisory lock ID from template database name.
167
- *
168
- * @param templateDbName - Template database name
169
- * @returns 32-bit integer lock ID
170
- */
171
- function getAdvisoryLockId(templateDbName) {
172
- let hash = 0;
173
- for (let i = 0; i < templateDbName.length; i++) {
174
- const char = templateDbName.charCodeAt(i);
175
- hash = (hash << 5) - hash + char;
176
- hash = hash & hash;
177
- }
178
- return Math.abs(hash);
179
- }
180
- /**
181
- * Ensure template database exists with migrations applied.
182
- *
183
- * Uses PostgreSQL advisory locks to prevent race conditions when multiple
184
- * test workers try to create the same template database concurrently.
185
- *
186
- * @param connectionString - Database connection string
187
- * @param name - Database name (e.g., "platform")
188
- * @param rootFolder - Root folder for migrations
189
- * @param logger - Optional logger
190
- */
191
- async function ensureTemplateDatabase(connectionString, name, logger) {
192
- const templateDbName = `${name}_test_template`;
193
- const maintenanceClient = new Client({ connectionString: getMaintenanceDbUrl(connectionString) });
194
- await maintenanceClient.connect();
195
- const lockId = getAdvisoryLockId(templateDbName);
196
- try {
197
- await maintenanceClient.query("SELECT pg_advisory_lock($1)", [lockId]);
198
- if ((await maintenanceClient.query("SELECT 1 FROM pg_database WHERE datname = $1", [templateDbName])).rowCount === 0) {
199
- await maintenanceClient.query(`CREATE DATABASE ${templateDbName} WITH IS_TEMPLATE = true`);
200
- const components = parsePostgresUrl(connectionString);
201
- components.database = templateDbName;
202
- const templatePool = new Pool$1({ connectionString: buildPostgresUrl(components) });
203
- try {
204
- await migrate(drizzle({
205
- client: templatePool,
206
- logger: logger ? new DatabaseLogger(logger) : void 0
207
- }), defineMigrationOpts(name));
208
- } finally {
209
- await templatePool.end();
210
- }
211
- }
212
- } finally {
213
- await maintenanceClient.query("SELECT pg_advisory_unlock($1)", [lockId]);
214
- await maintenanceClient.end();
215
- }
216
- }
217
-
218
- //#endregion
219
- export { dbChanges, defineDatabase, defineMigrationOpts, defineTestDatabase, migrationsSchema };
@@ -1,235 +0,0 @@
1
- import { Logger } from "./logger.mjs";
2
- import { Container } from "./container.mjs";
3
- import { z } from "zod";
4
-
5
- //#region src/api/event.d.ts
6
-
7
- /**
8
- * Context available to event handlers.
9
- */
10
- interface EventContext<TInput> {
11
- /**
12
- * The application container with access to db, mailer, logger, etc.
13
- */
14
- container: Container;
15
- /**
16
- * The validated input passed to this event.
17
- */
18
- input: TInput;
19
- }
20
- /**
21
- * Options for defining an event bus.
22
- */
23
- interface DefineEventBusOptions {
24
- /**
25
- * Redis URL for pub/sub.
26
- */
27
- dbUrl: string;
28
- /**
29
- * Logger instance for error reporting.
30
- */
31
- logger: Logger;
32
- }
33
- /**
34
- * The event bus type for container.
35
- */
36
- type EventBus = ReturnType<typeof defineEventBus>;
37
- /**
38
- * Defines the event bus for pub/sub messaging.
39
- * Uses Redis for cross-server communication.
40
- *
41
- * Algorithm:
42
- * 1. Create lazy Redis publisher client
43
- * 2. Create lazy Redis subscriber client
44
- * 3. Manage subscriptions via callback registry
45
- * 4. Provide publish/subscribe/close methods
46
- *
47
- * @param opts - Event bus configuration
48
- * @returns Event bus instance
49
- */
50
- declare function defineEventBus(opts: DefineEventBusOptions): {
51
- /**
52
- * Publish a message to a channel.
53
- * Auto-connects on first call if not already connected.
54
- *
55
- * @param channel - Channel name
56
- * @param message - Message payload (will be JSON stringified)
57
- */
58
- publish(channel: string, message: unknown): Promise<void>;
59
- /**
60
- * Subscribe to a channel. Returns unsubscribe function.
61
- * Uses single connection with callback management.
62
- *
63
- * @param channel - Channel name
64
- * @param callback - Callback for received messages
65
- * @returns Unsubscribe function
66
- */
67
- subscribe(channel: string, callback: (message: unknown) => void): Promise<() => void>;
68
- /**
69
- * Check if a channel has any subscribers.
70
- *
71
- * @param channel - Channel name
72
- * @returns true if channel has subscribers
73
- */
74
- hasSubscribers(channel: string): boolean;
75
- /**
76
- * Close the Redis connections.
77
- */
78
- close(): Promise<void>;
79
- };
80
- /**
81
- * Options for defining an event.
82
- */
83
- interface DefineEventOptions<TInput extends z.ZodType> {
84
- /**
85
- * Zod schema for validating event input.
86
- */
87
- input: TInput;
88
- /**
89
- * In-memory handler that runs only on the emitting server.
90
- *
91
- * @param ctx - Event context with container and input
92
- */
93
- run: (ctx: EventContext<z.infer<TInput>>) => Promise<void>;
94
- }
95
- /**
96
- * Event object returned by defineEvent.
97
- */
98
- interface Event<TInput> {
99
- /**
100
- * The event name (set during registration from filename).
101
- */
102
- readonly name: string | null;
103
- /**
104
- * Emit this event with the given input.
105
- * Runs in-memory handler, then publishes to Redis (fire-and-forget).
106
- *
107
- * @param input - Input matching the event's input schema.
108
- */
109
- emit(input: TInput): Promise<void>;
110
- /**
111
- * The Zod schema for validating input.
112
- */
113
- inputSchema: z.ZodType<TInput>;
114
- /**
115
- * Register this event with the container. Called by the event loader.
116
- *
117
- * @param container - The application container
118
- * @param name - The event name (derived from filename)
119
- */
120
- register(container: Container, name: string): void;
121
- /**
122
- * Subscribe to this event via Redis pub/sub.
123
- * Use for tRPC subscriptions, SSE, WebSockets.
124
- *
125
- * @param handler - Handler called when event is emitted on any server
126
- * @returns Unsubscribe function to cleanup the subscription
127
- */
128
- subscribe(handler: (ctx: EventContext<TInput>) => Promise<void>): Promise<() => void>;
129
- }
130
- /**
131
- * Defines a type-safe event with in-memory and Redis pub/sub support.
132
- *
133
- * Algorithm:
134
- * 1. Define event with input schema and in-memory run handler
135
- * 2. On emit(): validate input, run in-memory handler, publish to Redis (fire-and-forget)
136
- * 3. .subscribe() creates Redis subscription for tRPC/SSE/WebSocket handlers
137
- *
138
- * @example
139
- * ```typescript
140
- * // api/events/order-status.ts
141
- * export default defineEvent({
142
- * input: z.object({
143
- * orderId: z.string(),
144
- * status: z.enum(["pending", "shipped", "delivered"]),
145
- * }),
146
- * async run(ctx) {
147
- * ctx.container.logger.info(`Order ${ctx.input.orderId} is ${ctx.input.status}`);
148
- * },
149
- * });
150
- *
151
- * // Emit from anywhere
152
- * await orderStatus.emit({ orderId: "123", status: "shipped" });
153
- *
154
- * // Subscribe (e.g., in tRPC router)
155
- * const unsubscribe = await orderStatus.subscribe(async (ctx) => {
156
- * // Push to client via SSE/WebSocket
157
- * });
158
- * // Cleanup when client disconnects
159
- * unsubscribe();
160
- * ```
161
- */
162
- declare function defineEvent<TInput extends z.ZodType>(options: DefineEventOptions<TInput>): Event<z.infer<TInput>>;
163
- /**
164
- * Input schema for dbChangesEvent.
165
- */
166
- declare const dbChangeInputSchema: z.ZodObject<{
167
- action: z.ZodEnum<{
168
- DELETE: "DELETE";
169
- INSERT: "INSERT";
170
- UPDATE: "UPDATE";
171
- }>;
172
- newData: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
173
- oldData: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
174
- organizationId: z.ZodNullable<z.ZodString>;
175
- tableName: z.ZodString;
176
- timestamp: z.ZodString;
177
- userId: z.ZodNullable<z.ZodString>;
178
- }, z.core.$strip>;
179
- /**
180
- * Type for dbChangesEvent input.
181
- */
182
- type DbChangeInput = z.infer<typeof dbChangeInputSchema>;
183
- /**
184
- * Built-in event for database changes.
185
- * Emitted by trackDbChanges workflow.
186
- *
187
- * @example
188
- * ```typescript
189
- * // Subscribe to DB changes (e.g., in tRPC subscription)
190
- * import { dbChangesEvent } from "appos/api";
191
- *
192
- * const unsubscribe = await dbChangesEvent.subscribe(async (ctx) => {
193
- * wsServer.publish("db-changes", JSON.stringify(ctx.input));
194
- * });
195
- *
196
- * // Cleanup when done
197
- * unsubscribe();
198
- * ```
199
- */
200
- declare const dbChangesEvent: Event<{
201
- action: "DELETE" | "INSERT" | "UPDATE";
202
- newData: Record<string, unknown> | null;
203
- oldData: Record<string, unknown> | null;
204
- organizationId: string | null;
205
- tableName: string;
206
- timestamp: string;
207
- userId: string | null;
208
- }>;
209
- /**
210
- * Options for loading events.
211
- */
212
- interface LoadEventsOptions {
213
- /**
214
- * The application container.
215
- */
216
- container: Container;
217
- /**
218
- * Optional custom events directory path.
219
- */
220
- eventsDir?: string;
221
- }
222
- /**
223
- * Auto-discovers and registers all events from the given directory.
224
- *
225
- * Algorithm:
226
- * 1. Register built-in dbChangesEvent
227
- * 2. Glob all .ts files in the directory (excluding test files)
228
- * 3. Import each module's default export
229
- * 4. If it's an Event (has emit + subscribe), call register(container, name)
230
- *
231
- * @param opts - Load events options
232
- */
233
- declare function loadEvents(opts: LoadEventsOptions): Promise<void>;
234
- //#endregion
235
- export { DbChangeInput, DefineEventBusOptions, Event, EventBus, EventContext, dbChangeInputSchema, dbChangesEvent, defineEvent, defineEventBus, loadEvents };
@@ -1,236 +0,0 @@
1
- import { defineRedisClient } from "./redis.mjs";
2
- import { APPOS_DIR, EVENTS_DIR, FILE_EXT } from "./constants.mjs";
3
- import { z } from "zod";
4
- import { basename, join } from "node:path";
5
- import { glob } from "node:fs/promises";
6
- import { camelCase } from "es-toolkit";
7
-
8
- //#region src/api/event.ts
9
- /**
10
- * Defines the event bus for pub/sub messaging.
11
- * Uses Redis for cross-server communication.
12
- *
13
- * Algorithm:
14
- * 1. Create lazy Redis publisher client
15
- * 2. Create lazy Redis subscriber client
16
- * 3. Manage subscriptions via callback registry
17
- * 4. Provide publish/subscribe/close methods
18
- *
19
- * @param opts - Event bus configuration
20
- * @returns Event bus instance
21
- */
22
- function defineEventBus(opts) {
23
- const publisherClient = defineRedisClient({
24
- logger: opts.logger,
25
- url: opts.dbUrl
26
- });
27
- let subscriberClient = null;
28
- const subscribers = /* @__PURE__ */ new Map();
29
- return {
30
- async publish(channel, message) {
31
- await publisherClient.publish(channel, JSON.stringify(message));
32
- },
33
- async subscribe(channel, callback) {
34
- if (!subscriberClient) {
35
- subscriberClient = publisherClient.duplicate();
36
- await subscriberClient.connect();
37
- }
38
- if (!subscribers.has(channel)) {
39
- subscribers.set(channel, /* @__PURE__ */ new Set());
40
- await subscriberClient.subscribe(channel, (msg) => {
41
- const callbacks = subscribers.get(channel);
42
- if (callbacks) {
43
- let parsed;
44
- try {
45
- parsed = JSON.parse(msg);
46
- } catch (err) {
47
- opts.logger.error({
48
- err,
49
- channel,
50
- msg
51
- }, "Failed to parse event message");
52
- return;
53
- }
54
- for (const cb of callbacks) try {
55
- cb(parsed);
56
- } catch (err) {
57
- opts.logger.error({
58
- err,
59
- channel
60
- }, "Event handler error");
61
- }
62
- }
63
- });
64
- }
65
- subscribers.get(channel).add(callback);
66
- return () => {
67
- const callbacks = subscribers.get(channel);
68
- if (callbacks) callbacks.delete(callback);
69
- };
70
- },
71
- hasSubscribers(channel) {
72
- const callbacks = subscribers.get(channel);
73
- return callbacks !== void 0 && callbacks.size > 0;
74
- },
75
- async close() {
76
- if (subscriberClient?.isOpen) await subscriberClient.quit();
77
- if (publisherClient.isOpen) await publisherClient.quit();
78
- }
79
- };
80
- }
81
- /**
82
- * Defines a type-safe event with in-memory and Redis pub/sub support.
83
- *
84
- * Algorithm:
85
- * 1. Define event with input schema and in-memory run handler
86
- * 2. On emit(): validate input, run in-memory handler, publish to Redis (fire-and-forget)
87
- * 3. .subscribe() creates Redis subscription for tRPC/SSE/WebSocket handlers
88
- *
89
- * @example
90
- * ```typescript
91
- * // api/events/order-status.ts
92
- * export default defineEvent({
93
- * input: z.object({
94
- * orderId: z.string(),
95
- * status: z.enum(["pending", "shipped", "delivered"]),
96
- * }),
97
- * async run(ctx) {
98
- * ctx.container.logger.info(`Order ${ctx.input.orderId} is ${ctx.input.status}`);
99
- * },
100
- * });
101
- *
102
- * // Emit from anywhere
103
- * await orderStatus.emit({ orderId: "123", status: "shipped" });
104
- *
105
- * // Subscribe (e.g., in tRPC router)
106
- * const unsubscribe = await orderStatus.subscribe(async (ctx) => {
107
- * // Push to client via SSE/WebSocket
108
- * });
109
- * // Cleanup when client disconnects
110
- * unsubscribe();
111
- * ```
112
- */
113
- function defineEvent(options) {
114
- let container = null;
115
- let eventName = null;
116
- return {
117
- inputSchema: options.input,
118
- get name() {
119
- return eventName;
120
- },
121
- register(c, name) {
122
- container = c;
123
- eventName = name;
124
- },
125
- async emit(input) {
126
- if (!container || !eventName) throw new Error("Event not registered. Ensure the worker is started before emitting events.");
127
- const validated = options.input.parse(input);
128
- const ctx = {
129
- container,
130
- input: validated
131
- };
132
- await options.run(ctx);
133
- container.eventBus.publish(eventName, validated).catch((err) => {
134
- container.logger.error({
135
- err,
136
- event: eventName
137
- }, "Redis publish failed");
138
- });
139
- },
140
- async subscribe(handler) {
141
- if (!container || !eventName) throw new Error("Event not registered. Ensure the worker is started before subscribing.");
142
- return container.eventBus.subscribe(eventName, async (message) => {
143
- const validated = options.input.parse(message);
144
- const ctx = {
145
- container,
146
- input: validated
147
- };
148
- try {
149
- await handler(ctx);
150
- } catch (err) {
151
- container.logger.error({
152
- err,
153
- event: eventName
154
- }, "Event subscription handler error");
155
- }
156
- });
157
- }
158
- };
159
- }
160
- /**
161
- * Input schema for dbChangesEvent.
162
- */
163
- const dbChangeInputSchema = z.object({
164
- action: z.enum([
165
- "INSERT",
166
- "UPDATE",
167
- "DELETE"
168
- ]),
169
- newData: z.record(z.string(), z.unknown()).nullable(),
170
- oldData: z.record(z.string(), z.unknown()).nullable(),
171
- organizationId: z.string().nullable(),
172
- tableName: z.string(),
173
- timestamp: z.string(),
174
- userId: z.string().nullable()
175
- });
176
- /**
177
- * Built-in event for database changes.
178
- * Emitted by trackDbChanges workflow.
179
- *
180
- * @example
181
- * ```typescript
182
- * // Subscribe to DB changes (e.g., in tRPC subscription)
183
- * import { dbChangesEvent } from "appos/api";
184
- *
185
- * const unsubscribe = await dbChangesEvent.subscribe(async (ctx) => {
186
- * wsServer.publish("db-changes", JSON.stringify(ctx.input));
187
- * });
188
- *
189
- * // Cleanup when done
190
- * unsubscribe();
191
- * ```
192
- */
193
- const dbChangesEvent = defineEvent({
194
- input: dbChangeInputSchema,
195
- async run() {}
196
- });
197
- /**
198
- * Extracts event name from filepath as camelCase.
199
- */
200
- function getEventName(filepath) {
201
- return camelCase(basename(filepath, ".ts"));
202
- }
203
- /**
204
- * Auto-discovers and registers all events from the given directory.
205
- *
206
- * Algorithm:
207
- * 1. Register built-in dbChangesEvent
208
- * 2. Glob all .ts files in the directory (excluding test files)
209
- * 3. Import each module's default export
210
- * 4. If it's an Event (has emit + subscribe), call register(container, name)
211
- *
212
- * @param opts - Load events options
213
- */
214
- async function loadEvents(opts) {
215
- const { container } = opts;
216
- const eventsDir = opts.eventsDir ?? join(process.cwd(), APPOS_DIR, EVENTS_DIR);
217
- dbChangesEvent.register(container, "dbChanges");
218
- const files = await Array.fromAsync(glob(`${eventsDir}/**/*.${FILE_EXT}`, { exclude: [
219
- "**/*.test.ts",
220
- "**/*.spec.ts",
221
- "**/*.test.js",
222
- "**/*.spec.js"
223
- ] }));
224
- for (const file of files) {
225
- const mod = await import(file);
226
- if (mod.default && typeof mod.default === "object") {
227
- if ("emit" in mod.default && "subscribe" in mod.default) {
228
- const name = getEventName(file);
229
- mod.default.register(container, name);
230
- }
231
- }
232
- }
233
- }
234
-
235
- //#endregion
236
- export { dbChangeInputSchema, dbChangesEvent, defineEvent, defineEventBus, loadEvents };