@m5kdev/backend 0.1.3 → 0.1.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 (309) hide show
  1. package/dist/src/lib/posthog.d.ts +0 -1
  2. package/dist/src/lib/sentry.d.ts +0 -1
  3. package/dist/src/modules/access/access.repository.d.ts +0 -1
  4. package/dist/src/modules/access/access.service.d.ts +0 -1
  5. package/dist/src/modules/access/access.test.d.ts +0 -1
  6. package/dist/src/modules/access/access.utils.d.ts +0 -1
  7. package/dist/src/modules/ai/ai.db.d.ts +0 -1
  8. package/dist/src/modules/ai/ai.prompt.d.ts +0 -1
  9. package/dist/src/modules/ai/ai.repository.d.ts +0 -1
  10. package/dist/src/modules/ai/ai.router.d.ts +0 -1
  11. package/dist/src/modules/ai/ai.service.d.ts +0 -1
  12. package/dist/src/modules/ai/ai.trpc.d.ts +4 -5
  13. package/dist/src/modules/ai/ideogram/ideogram.constants.d.ts +0 -1
  14. package/dist/src/modules/ai/ideogram/ideogram.dto.d.ts +0 -1
  15. package/dist/src/modules/ai/ideogram/ideogram.prompt.d.ts +0 -1
  16. package/dist/src/modules/ai/ideogram/ideogram.repository.d.ts +0 -1
  17. package/dist/src/modules/ai/ideogram/ideogram.service.d.ts +0 -1
  18. package/dist/src/modules/auth/auth.db.d.ts +0 -1
  19. package/dist/src/modules/auth/auth.dto.d.ts +7 -8
  20. package/dist/src/modules/auth/auth.lib.d.ts +8 -9
  21. package/dist/src/modules/auth/auth.middleware.d.ts +0 -1
  22. package/dist/src/modules/auth/auth.repository.d.ts +0 -1
  23. package/dist/src/modules/auth/auth.service.d.ts +0 -1
  24. package/dist/src/modules/auth/auth.trpc.d.ts +17 -18
  25. package/dist/src/modules/auth/auth.utils.d.ts +0 -1
  26. package/dist/src/modules/base/base.abstract.d.ts +0 -1
  27. package/dist/src/modules/base/base.dto.d.ts +2 -3
  28. package/dist/src/modules/base/base.grants.d.ts +0 -1
  29. package/dist/src/modules/base/base.grants.test.d.ts +0 -1
  30. package/dist/src/modules/base/base.repository.d.ts +0 -1
  31. package/dist/src/modules/base/base.service.d.ts +0 -1
  32. package/dist/src/modules/base/base.types.d.ts +0 -1
  33. package/dist/src/modules/billing/billing.db.d.ts +0 -1
  34. package/dist/src/modules/billing/billing.repository.d.ts +0 -1
  35. package/dist/src/modules/billing/billing.router.d.ts +0 -1
  36. package/dist/src/modules/billing/billing.service.d.ts +0 -1
  37. package/dist/src/modules/billing/billing.trpc.d.ts +4 -5
  38. package/dist/src/modules/clay/clay.repository.d.ts +0 -1
  39. package/dist/src/modules/clay/clay.service.d.ts +0 -1
  40. package/dist/src/modules/connect/connect.db.d.ts +0 -1
  41. package/dist/src/modules/connect/connect.dto.d.ts +8 -9
  42. package/dist/src/modules/connect/connect.linkedin.d.ts +0 -1
  43. package/dist/src/modules/connect/connect.oauth.d.ts +0 -1
  44. package/dist/src/modules/connect/connect.repository.d.ts +3 -4
  45. package/dist/src/modules/connect/connect.router.d.ts +0 -1
  46. package/dist/src/modules/connect/connect.service.d.ts +6 -7
  47. package/dist/src/modules/connect/connect.trpc.d.ts +6 -7
  48. package/dist/src/modules/connect/connect.types.d.ts +0 -1
  49. package/dist/src/modules/crypto/crypto.db.d.ts +0 -1
  50. package/dist/src/modules/crypto/crypto.repository.d.ts +0 -1
  51. package/dist/src/modules/crypto/crypto.service.d.ts +0 -1
  52. package/dist/src/modules/email/email.service.d.ts +0 -1
  53. package/dist/src/modules/file/file.repository.d.ts +0 -1
  54. package/dist/src/modules/file/file.router.d.ts +0 -1
  55. package/dist/src/modules/file/file.service.d.ts +0 -1
  56. package/dist/src/modules/recurrence/recurrence.db.d.ts +0 -1
  57. package/dist/src/modules/recurrence/recurrence.repository.d.ts +0 -1
  58. package/dist/src/modules/recurrence/recurrence.service.d.ts +0 -1
  59. package/dist/src/modules/recurrence/recurrence.trpc.d.ts +5 -6
  60. package/dist/src/modules/social/social.dto.d.ts +0 -1
  61. package/dist/src/modules/social/social.linkedin.d.ts +0 -1
  62. package/dist/src/modules/social/social.linkedin.test.d.ts +0 -1
  63. package/dist/src/modules/social/social.service.d.ts +0 -1
  64. package/dist/src/modules/social/social.types.d.ts +0 -1
  65. package/dist/src/modules/tag/tag.db.d.ts +0 -1
  66. package/dist/src/modules/tag/tag.dto.d.ts +0 -1
  67. package/dist/src/modules/tag/tag.repository.d.ts +0 -1
  68. package/dist/src/modules/tag/tag.service.d.ts +0 -1
  69. package/dist/src/modules/tag/tag.trpc.d.ts +6 -7
  70. package/dist/src/modules/utils/applyPagination.d.ts +0 -1
  71. package/dist/src/modules/utils/applySorting.d.ts +0 -1
  72. package/dist/src/modules/utils/getConditionsFromFilters.d.ts +0 -1
  73. package/dist/src/modules/video/video.service.d.ts +0 -1
  74. package/dist/src/modules/webhook/webhook.constants.d.ts +0 -1
  75. package/dist/src/modules/webhook/webhook.db.d.ts +0 -1
  76. package/dist/src/modules/webhook/webhook.dto.d.ts +0 -1
  77. package/dist/src/modules/webhook/webhook.repository.d.ts +0 -1
  78. package/dist/src/modules/webhook/webhook.router.d.ts +0 -1
  79. package/dist/src/modules/webhook/webhook.service.d.ts +0 -1
  80. package/dist/src/modules/workflow/workflow.db.d.ts +0 -1
  81. package/dist/src/modules/workflow/workflow.repository.d.ts +0 -1
  82. package/dist/src/modules/workflow/workflow.service.d.ts +0 -1
  83. package/dist/src/modules/workflow/workflow.trpc.d.ts +4 -5
  84. package/dist/src/modules/workflow/workflow.types.d.ts +0 -1
  85. package/dist/src/modules/workflow/workflow.utils.d.ts +0 -1
  86. package/dist/src/test/stubs/utils.d.ts +0 -1
  87. package/dist/src/trpc/context.d.ts +4 -5
  88. package/dist/src/trpc/index.d.ts +0 -1
  89. package/dist/src/trpc/procedures.d.ts +24 -25
  90. package/dist/src/trpc/utils.d.ts +0 -1
  91. package/dist/src/types.d.ts +29 -30
  92. package/dist/src/utils/errors.d.ts +0 -1
  93. package/dist/src/utils/logger.d.ts +0 -1
  94. package/dist/src/utils/posthog.d.ts +0 -1
  95. package/dist/src/utils/types.d.ts +0 -1
  96. package/dist/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +6 -3
  98. package/.cursor/rules/backend.mdc +0 -70
  99. package/.turbo/turbo-build.log +0 -5
  100. package/.turbo/turbo-check-types.log +0 -5
  101. package/.turbo/turbo-lint$colon$fix.log +0 -255
  102. package/CHANGELOG.md +0 -28
  103. package/dist/src/lib/posthog.d.ts.map +0 -1
  104. package/dist/src/lib/sentry.d.ts.map +0 -1
  105. package/dist/src/modules/access/access.repository.d.ts.map +0 -1
  106. package/dist/src/modules/access/access.service.d.ts.map +0 -1
  107. package/dist/src/modules/access/access.test.d.ts.map +0 -1
  108. package/dist/src/modules/access/access.utils.d.ts.map +0 -1
  109. package/dist/src/modules/ai/ai.db.d.ts.map +0 -1
  110. package/dist/src/modules/ai/ai.prompt.d.ts.map +0 -1
  111. package/dist/src/modules/ai/ai.repository.d.ts.map +0 -1
  112. package/dist/src/modules/ai/ai.router.d.ts.map +0 -1
  113. package/dist/src/modules/ai/ai.service.d.ts.map +0 -1
  114. package/dist/src/modules/ai/ai.trpc.d.ts.map +0 -1
  115. package/dist/src/modules/ai/ideogram/ideogram.constants.d.ts.map +0 -1
  116. package/dist/src/modules/ai/ideogram/ideogram.dto.d.ts.map +0 -1
  117. package/dist/src/modules/ai/ideogram/ideogram.prompt.d.ts.map +0 -1
  118. package/dist/src/modules/ai/ideogram/ideogram.repository.d.ts.map +0 -1
  119. package/dist/src/modules/ai/ideogram/ideogram.service.d.ts.map +0 -1
  120. package/dist/src/modules/auth/auth.db.d.ts.map +0 -1
  121. package/dist/src/modules/auth/auth.dto.d.ts.map +0 -1
  122. package/dist/src/modules/auth/auth.lib.d.ts.map +0 -1
  123. package/dist/src/modules/auth/auth.middleware.d.ts.map +0 -1
  124. package/dist/src/modules/auth/auth.repository.d.ts.map +0 -1
  125. package/dist/src/modules/auth/auth.service.d.ts.map +0 -1
  126. package/dist/src/modules/auth/auth.trpc.d.ts.map +0 -1
  127. package/dist/src/modules/auth/auth.utils.d.ts.map +0 -1
  128. package/dist/src/modules/base/base.abstract.d.ts.map +0 -1
  129. package/dist/src/modules/base/base.dto.d.ts.map +0 -1
  130. package/dist/src/modules/base/base.grants.d.ts.map +0 -1
  131. package/dist/src/modules/base/base.grants.test.d.ts.map +0 -1
  132. package/dist/src/modules/base/base.repository.d.ts.map +0 -1
  133. package/dist/src/modules/base/base.service.d.ts.map +0 -1
  134. package/dist/src/modules/base/base.types.d.ts.map +0 -1
  135. package/dist/src/modules/billing/billing.db.d.ts.map +0 -1
  136. package/dist/src/modules/billing/billing.repository.d.ts.map +0 -1
  137. package/dist/src/modules/billing/billing.router.d.ts.map +0 -1
  138. package/dist/src/modules/billing/billing.service.d.ts.map +0 -1
  139. package/dist/src/modules/billing/billing.trpc.d.ts.map +0 -1
  140. package/dist/src/modules/clay/clay.repository.d.ts.map +0 -1
  141. package/dist/src/modules/clay/clay.service.d.ts.map +0 -1
  142. package/dist/src/modules/connect/connect.db.d.ts.map +0 -1
  143. package/dist/src/modules/connect/connect.dto.d.ts.map +0 -1
  144. package/dist/src/modules/connect/connect.linkedin.d.ts.map +0 -1
  145. package/dist/src/modules/connect/connect.oauth.d.ts.map +0 -1
  146. package/dist/src/modules/connect/connect.repository.d.ts.map +0 -1
  147. package/dist/src/modules/connect/connect.router.d.ts.map +0 -1
  148. package/dist/src/modules/connect/connect.service.d.ts.map +0 -1
  149. package/dist/src/modules/connect/connect.trpc.d.ts.map +0 -1
  150. package/dist/src/modules/connect/connect.types.d.ts.map +0 -1
  151. package/dist/src/modules/crypto/crypto.db.d.ts.map +0 -1
  152. package/dist/src/modules/crypto/crypto.repository.d.ts.map +0 -1
  153. package/dist/src/modules/crypto/crypto.service.d.ts.map +0 -1
  154. package/dist/src/modules/email/email.service.d.ts.map +0 -1
  155. package/dist/src/modules/file/file.repository.d.ts.map +0 -1
  156. package/dist/src/modules/file/file.router.d.ts.map +0 -1
  157. package/dist/src/modules/file/file.service.d.ts.map +0 -1
  158. package/dist/src/modules/recurrence/recurrence.db.d.ts.map +0 -1
  159. package/dist/src/modules/recurrence/recurrence.repository.d.ts.map +0 -1
  160. package/dist/src/modules/recurrence/recurrence.service.d.ts.map +0 -1
  161. package/dist/src/modules/recurrence/recurrence.trpc.d.ts.map +0 -1
  162. package/dist/src/modules/social/social.dto.d.ts.map +0 -1
  163. package/dist/src/modules/social/social.linkedin.d.ts.map +0 -1
  164. package/dist/src/modules/social/social.linkedin.test.d.ts.map +0 -1
  165. package/dist/src/modules/social/social.service.d.ts.map +0 -1
  166. package/dist/src/modules/social/social.types.d.ts.map +0 -1
  167. package/dist/src/modules/tag/tag.db.d.ts.map +0 -1
  168. package/dist/src/modules/tag/tag.dto.d.ts.map +0 -1
  169. package/dist/src/modules/tag/tag.repository.d.ts.map +0 -1
  170. package/dist/src/modules/tag/tag.service.d.ts.map +0 -1
  171. package/dist/src/modules/tag/tag.trpc.d.ts.map +0 -1
  172. package/dist/src/modules/utils/applyPagination.d.ts.map +0 -1
  173. package/dist/src/modules/utils/applySorting.d.ts.map +0 -1
  174. package/dist/src/modules/utils/getConditionsFromFilters.d.ts.map +0 -1
  175. package/dist/src/modules/video/video.service.d.ts.map +0 -1
  176. package/dist/src/modules/webhook/webhook.constants.d.ts.map +0 -1
  177. package/dist/src/modules/webhook/webhook.db.d.ts.map +0 -1
  178. package/dist/src/modules/webhook/webhook.dto.d.ts.map +0 -1
  179. package/dist/src/modules/webhook/webhook.repository.d.ts.map +0 -1
  180. package/dist/src/modules/webhook/webhook.router.d.ts.map +0 -1
  181. package/dist/src/modules/webhook/webhook.service.d.ts.map +0 -1
  182. package/dist/src/modules/workflow/workflow.db.d.ts.map +0 -1
  183. package/dist/src/modules/workflow/workflow.repository.d.ts.map +0 -1
  184. package/dist/src/modules/workflow/workflow.service.d.ts.map +0 -1
  185. package/dist/src/modules/workflow/workflow.trpc.d.ts.map +0 -1
  186. package/dist/src/modules/workflow/workflow.types.d.ts.map +0 -1
  187. package/dist/src/modules/workflow/workflow.utils.d.ts.map +0 -1
  188. package/dist/src/test/stubs/utils.d.ts.map +0 -1
  189. package/dist/src/trpc/context.d.ts.map +0 -1
  190. package/dist/src/trpc/index.d.ts.map +0 -1
  191. package/dist/src/trpc/procedures.d.ts.map +0 -1
  192. package/dist/src/trpc/utils.d.ts.map +0 -1
  193. package/dist/src/types.d.ts.map +0 -1
  194. package/dist/src/utils/errors.d.ts.map +0 -1
  195. package/dist/src/utils/logger.d.ts.map +0 -1
  196. package/dist/src/utils/posthog.d.ts.map +0 -1
  197. package/dist/src/utils/types.d.ts.map +0 -1
  198. package/jest.config.ts +0 -19
  199. package/src/lib/posthog.ts +0 -5
  200. package/src/lib/sentry.ts +0 -8
  201. package/src/modules/access/access.repository.ts +0 -36
  202. package/src/modules/access/access.service.ts +0 -81
  203. package/src/modules/access/access.test.ts +0 -216
  204. package/src/modules/access/access.utils.ts +0 -46
  205. package/src/modules/ai/ai.db.ts +0 -38
  206. package/src/modules/ai/ai.prompt.ts +0 -47
  207. package/src/modules/ai/ai.repository.ts +0 -53
  208. package/src/modules/ai/ai.router.ts +0 -148
  209. package/src/modules/ai/ai.service.ts +0 -310
  210. package/src/modules/ai/ai.trpc.ts +0 -22
  211. package/src/modules/ai/ideogram/ideogram.constants.ts +0 -170
  212. package/src/modules/ai/ideogram/ideogram.dto.ts +0 -64
  213. package/src/modules/ai/ideogram/ideogram.prompt.ts +0 -858
  214. package/src/modules/ai/ideogram/ideogram.repository.ts +0 -39
  215. package/src/modules/ai/ideogram/ideogram.service.ts +0 -14
  216. package/src/modules/auth/auth.db.ts +0 -224
  217. package/src/modules/auth/auth.dto.ts +0 -47
  218. package/src/modules/auth/auth.lib.ts +0 -349
  219. package/src/modules/auth/auth.middleware.ts +0 -62
  220. package/src/modules/auth/auth.repository.ts +0 -672
  221. package/src/modules/auth/auth.service.ts +0 -261
  222. package/src/modules/auth/auth.trpc.ts +0 -208
  223. package/src/modules/auth/auth.utils.ts +0 -117
  224. package/src/modules/base/base.abstract.ts +0 -62
  225. package/src/modules/base/base.dto.ts +0 -206
  226. package/src/modules/base/base.grants.test.ts +0 -861
  227. package/src/modules/base/base.grants.ts +0 -199
  228. package/src/modules/base/base.repository.ts +0 -433
  229. package/src/modules/base/base.service.ts +0 -154
  230. package/src/modules/base/base.types.ts +0 -7
  231. package/src/modules/billing/billing.db.ts +0 -27
  232. package/src/modules/billing/billing.repository.ts +0 -328
  233. package/src/modules/billing/billing.router.ts +0 -77
  234. package/src/modules/billing/billing.service.ts +0 -177
  235. package/src/modules/billing/billing.trpc.ts +0 -17
  236. package/src/modules/clay/clay.repository.ts +0 -29
  237. package/src/modules/clay/clay.service.ts +0 -61
  238. package/src/modules/connect/connect.db.ts +0 -32
  239. package/src/modules/connect/connect.dto.ts +0 -44
  240. package/src/modules/connect/connect.linkedin.ts +0 -70
  241. package/src/modules/connect/connect.oauth.ts +0 -288
  242. package/src/modules/connect/connect.repository.ts +0 -65
  243. package/src/modules/connect/connect.router.ts +0 -76
  244. package/src/modules/connect/connect.service.ts +0 -171
  245. package/src/modules/connect/connect.trpc.ts +0 -26
  246. package/src/modules/connect/connect.types.ts +0 -27
  247. package/src/modules/crypto/crypto.db.ts +0 -15
  248. package/src/modules/crypto/crypto.repository.ts +0 -13
  249. package/src/modules/crypto/crypto.service.ts +0 -57
  250. package/src/modules/email/email.service.ts +0 -222
  251. package/src/modules/file/file.repository.ts +0 -95
  252. package/src/modules/file/file.router.ts +0 -108
  253. package/src/modules/file/file.service.ts +0 -186
  254. package/src/modules/recurrence/recurrence.db.ts +0 -79
  255. package/src/modules/recurrence/recurrence.repository.ts +0 -70
  256. package/src/modules/recurrence/recurrence.service.ts +0 -105
  257. package/src/modules/recurrence/recurrence.trpc.ts +0 -82
  258. package/src/modules/social/social.dto.ts +0 -22
  259. package/src/modules/social/social.linkedin.test.ts +0 -277
  260. package/src/modules/social/social.linkedin.ts +0 -593
  261. package/src/modules/social/social.service.ts +0 -112
  262. package/src/modules/social/social.types.ts +0 -43
  263. package/src/modules/tag/tag.db.ts +0 -41
  264. package/src/modules/tag/tag.dto.ts +0 -18
  265. package/src/modules/tag/tag.repository.ts +0 -222
  266. package/src/modules/tag/tag.service.ts +0 -48
  267. package/src/modules/tag/tag.trpc.ts +0 -62
  268. package/src/modules/uploads/0581796b-8845-420d-bd95-cd7de79f6d37.webm +0 -0
  269. package/src/modules/uploads/33b1e649-6727-4bd0-94d0-a0b363646865.webm +0 -0
  270. package/src/modules/uploads/49a8c4c0-54d7-4c94-bef4-c93c029f9ed0.webm +0 -0
  271. package/src/modules/uploads/50e31e38-a2f0-47ca-8b7d-2d7fcad9267d.webm +0 -0
  272. package/src/modules/uploads/72ac8cf9-c3a7-4cd8-8a78-6d8e137a4c7e.webm +0 -0
  273. package/src/modules/uploads/75293649-d966-46cd-a675-67518958ae9c.png +0 -0
  274. package/src/modules/uploads/88b7b867-ce15-4891-bf73-81305a7de1f7.wav +0 -0
  275. package/src/modules/uploads/a5d6fee8-6a59-42c6-9d4a-ac8a3c5e7245.webm +0 -0
  276. package/src/modules/uploads/c13a9785-ca5a-4983-af30-b338ed76d370.webm +0 -0
  277. package/src/modules/uploads/caa1a5a7-71ba-4381-902d-7e2cafdf6dcb.webm +0 -0
  278. package/src/modules/uploads/cbeb0b81-374d-445b-914b-40ace7c8e031.webm +0 -0
  279. package/src/modules/uploads/d626aa82-b10f-493f-aee7-87bfb3361dfc.webm +0 -0
  280. package/src/modules/uploads/d7de4c16-de0c-495d-9612-e72260a6ecca.png +0 -0
  281. package/src/modules/uploads/e532e38a-6421-400e-8a5f-8e7bc8ce411b.wav +0 -0
  282. package/src/modules/uploads/e86ec867-6adf-4c51-84e0-00b0836625e8.webm +0 -0
  283. package/src/modules/utils/applyPagination.ts +0 -13
  284. package/src/modules/utils/applySorting.ts +0 -21
  285. package/src/modules/utils/getConditionsFromFilters.ts +0 -216
  286. package/src/modules/video/video.service.ts +0 -89
  287. package/src/modules/webhook/webhook.constants.ts +0 -9
  288. package/src/modules/webhook/webhook.db.ts +0 -15
  289. package/src/modules/webhook/webhook.dto.ts +0 -9
  290. package/src/modules/webhook/webhook.repository.ts +0 -68
  291. package/src/modules/webhook/webhook.router.ts +0 -29
  292. package/src/modules/webhook/webhook.service.ts +0 -78
  293. package/src/modules/workflow/workflow.db.ts +0 -29
  294. package/src/modules/workflow/workflow.repository.ts +0 -171
  295. package/src/modules/workflow/workflow.service.ts +0 -56
  296. package/src/modules/workflow/workflow.trpc.ts +0 -26
  297. package/src/modules/workflow/workflow.types.ts +0 -30
  298. package/src/modules/workflow/workflow.utils.ts +0 -259
  299. package/src/test/stubs/utils.ts +0 -2
  300. package/src/trpc/context.ts +0 -21
  301. package/src/trpc/index.ts +0 -3
  302. package/src/trpc/procedures.ts +0 -43
  303. package/src/trpc/utils.ts +0 -20
  304. package/src/types.ts +0 -22
  305. package/src/utils/errors.ts +0 -148
  306. package/src/utils/logger.ts +0 -8
  307. package/src/utils/posthog.ts +0 -43
  308. package/src/utils/types.ts +0 -5
  309. package/tsconfig.json +0 -21
@@ -1,199 +0,0 @@
1
- import { err, ok } from "neverthrow";
2
- import type { Session, User } from "#modules/auth/auth.lib";
3
- import type { ServerResultAsync } from "#modules/base/base.dto";
4
-
5
- type Level = "user" | "team" | "organization";
6
- type Access = "all" | "own";
7
-
8
- export type Entity = Partial<{
9
- userId: string | null;
10
- teamId: string | null;
11
- organizationId: string | null;
12
- }>;
13
-
14
- export type Grant = {
15
- level: Level;
16
- role: string;
17
- action: string;
18
- resource: string;
19
- access: Access;
20
- attributes?: string[];
21
- };
22
-
23
- export type NestedGrants = Record<
24
- string,
25
- Partial<Record<Level, Record<string, Record<string, Access>>>>
26
- >;
27
-
28
- export type ResourceGrant = Omit<Grant, "resource">;
29
-
30
- export type ResourceActionGrant = Omit<ResourceGrant, "action">;
31
-
32
- export function flattenNestedGrants(nestedGrants: NestedGrants): Grant[] {
33
- return Object.entries(nestedGrants).flatMap(([resource, levels]) => {
34
- return Object.entries(levels).flatMap(([level, roles]) => {
35
- return Object.entries(roles).flatMap(([role, actions]) => {
36
- return Object.entries(actions).map(([action, access]) => {
37
- return {
38
- resource,
39
- level: level as Level,
40
- role,
41
- action,
42
- access,
43
- };
44
- });
45
- });
46
- });
47
- });
48
- }
49
-
50
- function checkOwnership(
51
- entityField: keyof Entity,
52
- contextValue: string | null | undefined,
53
- entities?: Entity | Entity[]
54
- ): boolean {
55
- if (!contextValue) return false;
56
- if (!entities) return false;
57
- return Array.isArray(entities)
58
- ? entities.every((e) => e[entityField] === contextValue)
59
- : entities[entityField] === contextValue;
60
- }
61
-
62
- interface PermissionContext {
63
- session: Session;
64
- user: User;
65
- }
66
-
67
- type GrantLevel = "user" | "team" | "organization";
68
-
69
- // Level priority: user -> team -> organization (bottom-up)
70
- const LEVEL_PRIORITY: readonly GrantLevel[] = ["user", "team", "organization"];
71
-
72
- interface RoleContext {
73
- userRole: string | null;
74
- teamRole: string | null;
75
- organizationRole: string | null;
76
- }
77
-
78
- interface ContextValues {
79
- userId: string;
80
- teamId: string | null;
81
- organizationId: string | null;
82
- }
83
-
84
- function getRoleForLevel(level: GrantLevel, ctx: RoleContext): string | null {
85
- switch (level) {
86
- case "user":
87
- return ctx.userRole;
88
- case "team":
89
- return ctx.teamRole;
90
- case "organization":
91
- return ctx.organizationRole;
92
- }
93
- }
94
-
95
- function getContextValueForLevel(level: GrantLevel, ctx: ContextValues): string | null {
96
- switch (level) {
97
- case "user":
98
- return ctx.userId;
99
- case "team":
100
- return ctx.teamId;
101
- case "organization":
102
- return ctx.organizationId;
103
- }
104
- }
105
-
106
- function getOwnershipFieldForLevel(level: GrantLevel): keyof Entity {
107
- switch (level) {
108
- case "user":
109
- return "userId";
110
- case "team":
111
- return "teamId";
112
- case "organization":
113
- return "organizationId";
114
- }
115
- }
116
-
117
- function hasAllAccess(grants: ResourceActionGrant[], roles: RoleContext): boolean {
118
- for (const level of LEVEL_PRIORITY) {
119
- for (const grant of grants) {
120
- if (grant.level !== level) continue;
121
- if (grant.access !== "all") continue;
122
- if (grant.role === getRoleForLevel(level, roles)) return true;
123
- }
124
- }
125
- return false;
126
- }
127
-
128
- function checkOwnAccess(
129
- grants: ResourceActionGrant[],
130
- roles: RoleContext,
131
- contextValues: ContextValues,
132
- entities: Entity | Entity[] | undefined
133
- ): boolean {
134
- for (const level of LEVEL_PRIORITY) {
135
- for (const grant of grants) {
136
- if (grant.level !== level) continue;
137
- if (grant.access !== "own") continue;
138
- if (grant.role !== getRoleForLevel(level, roles)) continue;
139
-
140
- const ownershipField = getOwnershipFieldForLevel(level);
141
- const contextValue = getContextValueForLevel(level, contextValues);
142
-
143
- if (checkOwnership(ownershipField, contextValue, entities)) return true;
144
- }
145
- }
146
- return false;
147
- }
148
-
149
- export function checkPermissionSync<T extends Entity>(
150
- ctx: PermissionContext,
151
- grants: ResourceActionGrant[],
152
- entities?: T | T[]
153
- ): boolean {
154
- if (!grants || grants.length === 0) return false;
155
-
156
- const { id: userId, role: userRole } = ctx.user;
157
- const {
158
- activeOrganizationRole: organizationRole,
159
- activeTeamRole: teamRole,
160
- activeOrganizationId: organizationId,
161
- activeTeamId: teamId,
162
- } = ctx.session;
163
-
164
- const roles = { userRole, teamRole, organizationRole };
165
- const contextValues = { userId, teamId, organizationId };
166
-
167
- // Pass 1: Check for "all" access first (no ownership check needed)
168
- if (hasAllAccess(grants, roles)) return true;
169
-
170
- // Pass 2: Check "own" access with ownership validation
171
- return checkOwnAccess(grants, roles, contextValues, entities);
172
- }
173
-
174
- export async function checkPermissionAsync<T extends Entity>(
175
- ctx: PermissionContext,
176
- grants: ResourceActionGrant[],
177
- getEntities: () => ServerResultAsync<T | T[] | undefined>
178
- ): ServerResultAsync<boolean> {
179
- if (!grants || grants.length === 0) return ok(false);
180
-
181
- const { id: userId, role: userRole } = ctx.user;
182
- const {
183
- activeOrganizationRole: organizationRole,
184
- activeTeamRole: teamRole,
185
- activeOrganizationId: organizationId,
186
- activeTeamId: teamId,
187
- } = ctx.session;
188
-
189
- const roles = { userRole, teamRole, organizationRole };
190
- const contextValues = { userId, teamId, organizationId };
191
-
192
- // Pass 1: Check for "all" access first (no entity fetch needed)
193
- if (hasAllAccess(grants, roles)) return ok(true);
194
-
195
- // Pass 2: Only fetch entities if we need to check ownership
196
- const entities = await getEntities();
197
- if (entities.isErr()) return err(entities.error);
198
- return ok(checkOwnAccess(grants, roles, contextValues, entities.value));
199
- }
@@ -1,433 +0,0 @@
1
- import type {
2
- QueryFilter,
3
- QueryFilters,
4
- QueryInput,
5
- } from "@m5kdev/commons/modules/schemas/query.schema";
6
- import {
7
- and,
8
- count,
9
- eq,
10
- type InferInsertModel,
11
- type InferSelectModel,
12
- inArray,
13
- like,
14
- or,
15
- type SelectedFields,
16
- type SQL,
17
- } from "drizzle-orm";
18
- import type { LibSQLDatabase } from "drizzle-orm/libsql";
19
- import type { SQLiteColumn, SQLiteTableWithColumns } from "drizzle-orm/sqlite-core";
20
- import { ok } from "neverthrow";
21
- import { Base } from "#modules/base/base.abstract";
22
- import { pickColumns, type ServerResult, type ServerResultAsync } from "#modules/base/base.dto";
23
- import { applyPagination } from "#modules/utils/applyPagination";
24
- import { applySorting } from "#modules/utils/applySorting";
25
- import { getConditionsFromFilters } from "#modules/utils/getConditionsFromFilters";
26
-
27
- /** Payload for update/updateMany: id key required (string), other table fields optional. */
28
- export type TableUpdatePayload<
29
- TTable extends SQLiteTableWithColumns<any>,
30
- TIdKey extends Extract<keyof InferSelectModel<TTable>, string> = "id",
31
- > = Record<TIdKey, string> & Partial<Omit<InferSelectModel<TTable>, TIdKey>>;
32
-
33
- export class ConditionBuilder {
34
- constructor(private conditions: SQL[] = []) {
35
- this.conditions = conditions;
36
- }
37
-
38
- push(condition?: SQL) {
39
- if (condition) this.conditions.push(condition);
40
- }
41
-
42
- join(type: "and" | "or" = "and") {
43
- if (this.conditions.length === 0) return undefined;
44
- if (this.conditions.length === 1) return this.conditions[0];
45
- return type === "and" ? and(...this.conditions) : or(...this.conditions);
46
- }
47
-
48
- [Symbol.iterator]() {
49
- return this.conditions[Symbol.iterator]();
50
- }
51
- }
52
-
53
- export class TableConditionBuilder<
54
- TTable extends SQLiteTableWithColumns<any>,
55
- > extends ConditionBuilder {
56
- private table: TTable;
57
-
58
- constructor(table: TTable) {
59
- super();
60
- this.table = table;
61
- }
62
-
63
- applyFilters({ filters }: { filters?: QueryFilters } = {}) {
64
- if (filters && filters.length > 0) getConditionsFromFilters(this, filters, this.table);
65
- }
66
- }
67
-
68
- export const arrayContains = (table: SQLiteColumn, values: string[]) => {
69
- const arrayContains: SQL[] = [];
70
- for (const value of values) {
71
- arrayContains.push(like(table, `%"${value}%"`));
72
- }
73
- return or(...arrayContains);
74
- };
75
-
76
- export class BaseRepository<
77
- O extends LibSQLDatabase<any>,
78
- S extends Record<string, SQLiteTableWithColumns<any>>,
79
- R extends Record<string, BaseRepository<any, any, any> | BaseExternaRepository>,
80
- > extends Base {
81
- protected orm: O;
82
- protected schema: S;
83
- public repository?: R;
84
-
85
- constructor(options: { orm: O; schema: S }, repository?: R) {
86
- super("repository");
87
- this.orm = options.orm;
88
- this.schema = options.schema;
89
- this.repository = repository;
90
- }
91
- getConditionBuilder(): ConditionBuilder;
92
- getConditionBuilder(table: undefined): ConditionBuilder;
93
- getConditionBuilder<TTable extends SQLiteTableWithColumns<any>>(
94
- table: TTable
95
- ): TableConditionBuilder<TTable>;
96
- getConditionBuilder<TTable extends SQLiteTableWithColumns<any>>(
97
- table?: TTable
98
- ): ConditionBuilder | TableConditionBuilder<TTable> {
99
- if (table === undefined) {
100
- return new ConditionBuilder();
101
- }
102
- return new TableConditionBuilder(table);
103
- }
104
-
105
- withPagination<TQuery>(
106
- query: TQuery,
107
- { page, limit }: Pick<QueryInput, "page" | "limit">
108
- ): TQuery {
109
- return applyPagination(query, limit, page);
110
- }
111
-
112
- withSorting<TTable extends SQLiteTableWithColumns<any>, TQuery>(
113
- query: TQuery,
114
- { sort, order }: Pick<QueryInput, "sort" | "order">,
115
- table?: TTable
116
- ): TQuery {
117
- if (!table) throw new Error("No table provided");
118
- return applySorting(query, table, sort, order);
119
- }
120
-
121
- withSortingAndPagination<TTable extends SQLiteTableWithColumns<any>, TQuery>(
122
- query: TQuery,
123
- { sort, order, page, limit }: Pick<QueryInput, "sort" | "order" | "page" | "limit">,
124
- table?: TTable
125
- ): TQuery {
126
- if (!table) throw new Error("No table provided");
127
- return this.withSorting(this.withPagination(query, { page, limit }), { sort, order }, table);
128
- }
129
-
130
- addUserIdFilter(userId: string, query?: QueryInput): QueryInput {
131
- const userIdFilter: QueryFilter = {
132
- columnId: "userId",
133
- type: "string",
134
- method: "equals",
135
- value: userId,
136
- };
137
- return query
138
- ? { ...query, filters: [...(query?.filters ?? []), userIdFilter] }
139
- : { filters: [userIdFilter] };
140
- }
141
-
142
- helpers = {
143
- pickColumns,
144
- arrayContains,
145
- ConditionBuilder,
146
- };
147
- }
148
-
149
- /**
150
- * Generic table-bound repository with typed CRUD, returning ServerResultAsync via throwableAsync.
151
- *
152
- * Example:
153
- * const userRepo = new UserRepository(db, schema);
154
- * class UserRepository extends BaseTableRepository<typeof schema.user> {
155
- * constructor(db: LibSQLDatabase<typeof schema>, schema: typeof schema) {
156
- * super(db, schema, schema.user);
157
- * }
158
- * }
159
- */
160
- export class BaseTableRepository<
161
- O extends LibSQLDatabase<any>,
162
- S extends Record<string, SQLiteTableWithColumns<any>>,
163
- R extends Record<string, BaseRepository<any, any, any> | BaseExternaRepository>,
164
- TTable extends SQLiteTableWithColumns<any>,
165
- TIdKey extends Extract<keyof InferSelectModel<TTable>, string> = "id",
166
- > extends BaseRepository<O, S, R> {
167
- protected readonly table: TTable;
168
- protected readonly idKey: TIdKey;
169
- protected readonly idColumn: SQLiteColumn;
170
-
171
- constructor(options: { orm: O; schema: S; table: TTable; idKey?: TIdKey }, repository?: R) {
172
- super({ orm: options.orm, schema: options.schema }, repository);
173
- this.table = options.table;
174
- this.idKey = options.idKey ?? ("id" as TIdKey);
175
- this.idColumn = (this.table as any)[this.idKey] as SQLiteColumn;
176
- }
177
-
178
- override withSorting<TQuery>(
179
- query: TQuery,
180
- { sort, order }: Pick<QueryInput, "sort" | "order">,
181
- table?: SQLiteTableWithColumns<any>
182
- ): TQuery {
183
- return super.withSorting(query, { sort, order }, table || this.table);
184
- }
185
-
186
- override withSortingAndPagination<MTable extends SQLiteTableWithColumns<any>, TQuery>(
187
- query: TQuery,
188
- { sort, order, page, limit }: Pick<QueryInput, "sort" | "order" | "page" | "limit">,
189
- table?: MTable
190
- ): TQuery {
191
- return super.withSortingAndPagination(query, { sort, order, page, limit }, table || this.table);
192
- }
193
-
194
- async queryList(
195
- query?: QueryInput,
196
- options?: {
197
- conditions?: TableConditionBuilder<TTable>;
198
- select?: SelectedFields<SQLiteColumn, TTable>;
199
- },
200
- tx?: O
201
- ): ServerResultAsync<{ rows: InferSelectModel<TTable>[]; total: number }> {
202
- return this.throwableAsync(async () => {
203
- type Row = InferSelectModel<TTable>;
204
-
205
- const db = tx ?? this.orm;
206
- const conditions = options?.conditions ?? this.getConditionBuilder(this.table);
207
- conditions.applyFilters(query);
208
- const whereClause = conditions.join();
209
- const rowsQuery = this.withSortingAndPagination(
210
- (options?.select ? db.select(options.select) : db.select())
211
- .from(this.table as any)
212
- .where(whereClause),
213
- query || {}
214
- );
215
- const countQuery = db
216
- .select({ count: count() })
217
- .from(this.table as any)
218
- .where(whereClause);
219
- const [rows, [totalResult]] = await Promise.all([rowsQuery, countQuery]);
220
-
221
- return ok({ rows: rows as Row[], total: totalResult?.count ?? 0 });
222
- });
223
- }
224
-
225
- async findById(id: string, tx?: O): ServerResultAsync<InferSelectModel<TTable> | undefined> {
226
- return this.throwableAsync(async () => {
227
- const db = tx ?? this.orm;
228
- type Row = InferSelectModel<TTable>;
229
-
230
- const rows = (await db
231
- .select()
232
- .from(this.table as any)
233
- .where(eq(this.idColumn as SQLiteColumn, id))) as Row[];
234
-
235
- return ok(rows[0]);
236
- });
237
- }
238
-
239
- async findManyById(
240
- ids: readonly string[],
241
- tx?: O
242
- ): ServerResultAsync<Array<InferSelectModel<TTable>>> {
243
- return this.throwableAsync(async () => {
244
- const db = tx ?? this.orm;
245
- type Row = InferSelectModel<TTable>;
246
-
247
- if (ids.length === 0) {
248
- return ok<Row[]>([]);
249
- }
250
-
251
- const rows = (await db
252
- .select()
253
- .from(this.table as any)
254
- .where(inArray(this.idColumn as SQLiteColumn, ids as string[]))) as Row[];
255
-
256
- return ok(rows);
257
- });
258
- }
259
-
260
- async create(
261
- data: InferInsertModel<TTable>,
262
- tx?: O
263
- ): ServerResultAsync<InferSelectModel<TTable>> {
264
- return this.throwableAsync(async () => {
265
- const db = tx ?? this.orm;
266
- type Row = InferSelectModel<TTable>;
267
-
268
- const rows = (await db
269
- .insert(this.table as any)
270
- .values(data as any)
271
- .returning()) as unknown as Row[];
272
-
273
- if (rows.length === 0) return this.error("UNPROCESSABLE_CONTENT");
274
- return ok(rows[0] as Row);
275
- });
276
- }
277
-
278
- async createMany(
279
- data: readonly InferInsertModel<TTable>[],
280
- tx?: O
281
- ): ServerResultAsync<Array<InferSelectModel<TTable>>> {
282
- return this.throwableAsync(async () => {
283
- const db = tx ?? this.orm;
284
- type Row = InferSelectModel<TTable>;
285
-
286
- if (data.length === 0) {
287
- return ok<Row[]>([]);
288
- }
289
-
290
- const rows = (await db
291
- .insert(this.table as any)
292
- .values(data as any)
293
- .returning()) as unknown as Row[];
294
-
295
- return ok(rows as Row[]);
296
- });
297
- }
298
-
299
- async update(
300
- data: TableUpdatePayload<TTable, TIdKey>,
301
- tx?: O
302
- ): ServerResultAsync<InferSelectModel<TTable>> {
303
- return this.throwableAsync(async () => {
304
- const db = tx ?? this.orm;
305
- type Row = InferSelectModel<TTable>;
306
-
307
- const single = data as Record<string, unknown>;
308
- const id = String(single[this.idKey]);
309
- const { [this.idKey]: _removed, ...rest } = single;
310
- const update = rest;
311
- if (this.table.updatedAt) (update as any).updatedAt = new Date();
312
- const rows = (await db
313
- .update(this.table as any)
314
- .set(update as unknown as Partial<InferInsertModel<TTable>>)
315
- .where(eq(this.idColumn as SQLiteColumn, id))
316
- .returning()) as unknown as Row[];
317
- const [row] = rows;
318
-
319
- if (!row) return this.error("NOT_FOUND");
320
- return ok(row) as ServerResult<Row>;
321
- });
322
- }
323
-
324
- async updateMany(
325
- data: readonly TableUpdatePayload<TTable, TIdKey>[],
326
- tx?: O
327
- ): ServerResultAsync<Array<InferSelectModel<TTable>>> {
328
- return this.throwableAsync(async () => {
329
- const db = tx ?? this.orm;
330
- type Row = InferSelectModel<TTable>;
331
-
332
- if (data.length === 0) {
333
- return ok<Row[]>([]);
334
- }
335
-
336
- const results: Row[] = [];
337
- for (const item of data) {
338
- const record = item as Record<string, unknown>;
339
- const id = String(record[this.idKey]);
340
- const { [this.idKey]: _removed, ...rest } = record;
341
- const update = rest;
342
- if (this.table.updatedAt) (update as any).updatedAt = new Date();
343
- const rows = (await db
344
- .update(this.table as any)
345
- .set(update as unknown as Partial<InferInsertModel<TTable>>)
346
- .where(eq(this.idColumn as SQLiteColumn, id))
347
- .returning()) as unknown as Row[];
348
- if (rows[0]) results.push(rows[0]);
349
- }
350
-
351
- return ok(results) as ServerResult<Row[]>;
352
- });
353
- }
354
-
355
- async softDeleteById(id: string, tx?: O): ServerResultAsync<{ id: string }> {
356
- return this.throwableAsync(async () => {
357
- const db = tx ?? this.orm;
358
- if (!this.table.deletedAt) return this.error("METHOD_NOT_SUPPORTED");
359
-
360
- const rows = await db
361
- .update(this.table as any)
362
- .set({ deletedAt: new Date() })
363
- .where(eq(this.idColumn as SQLiteColumn, id))
364
- .returning({
365
- id: this.idColumn as SQLiteColumn,
366
- });
367
-
368
- if (rows.length === 0) return this.error("NOT_FOUND");
369
- return ok(rows[0] as { id: string });
370
- });
371
- }
372
-
373
- async softDeleteManyById(
374
- ids: readonly string[],
375
- tx?: O
376
- ): ServerResultAsync<Array<{ id: string }>> {
377
- return this.throwableAsync(async () => {
378
- const db = tx ?? this.orm;
379
- if (!this.table.deletedAt) return this.error("METHOD_NOT_SUPPORTED");
380
-
381
- const rows = await db
382
- .update(this.table as any)
383
- .set({ deletedAt: new Date() })
384
- .where(inArray(this.idColumn as SQLiteColumn, ids as string[]))
385
- .returning({
386
- id: this.idColumn as SQLiteColumn,
387
- });
388
- if (rows.length === 0) return this.error("NOT_FOUND");
389
- return ok(rows as { id: string }[]);
390
- });
391
- }
392
-
393
- async deleteById(id: string, tx?: O): ServerResultAsync<{ id: string }> {
394
- return this.throwableAsync(async () => {
395
- const db = tx ?? this.orm;
396
-
397
- const rows = await db
398
- .delete(this.table as any)
399
- .where(eq(this.idColumn as SQLiteColumn, id))
400
- .returning({
401
- id: this.idColumn as SQLiteColumn,
402
- });
403
-
404
- if (rows.length === 0) return this.error("NOT_FOUND");
405
- return ok(rows[0] as { id: string });
406
- });
407
- }
408
-
409
- async deleteManyById(ids: readonly string[], tx?: O): ServerResultAsync<Array<{ id: string }>> {
410
- return this.throwableAsync(async () => {
411
- const db = tx ?? this.orm;
412
-
413
- if (ids.length === 0) {
414
- return ok<{ id: string }[]>([]);
415
- }
416
-
417
- const rows = await db
418
- .delete(this.table as any)
419
- .where(inArray(this.idColumn as SQLiteColumn, ids as string[]))
420
- .returning({
421
- id: this.idColumn as SQLiteColumn,
422
- });
423
-
424
- return ok(rows as { id: string }[]);
425
- });
426
- }
427
- }
428
-
429
- export class BaseExternaRepository extends Base {
430
- constructor() {
431
- super("repository");
432
- }
433
- }