@c15t/backend 1.5.0 → 1.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 (489) hide show
  1. package/.turbo/turbo-build.log +63 -37
  2. package/CHANGELOG.md +4 -209
  3. package/README.md +86 -164
  4. package/dist/contracts/consent/index.d.ts +103 -615
  5. package/dist/contracts/consent/index.d.ts.map +1 -1
  6. package/dist/contracts/consent/post.contract.d.ts +42 -140
  7. package/dist/contracts/consent/post.contract.d.ts.map +1 -1
  8. package/dist/contracts/consent/show-banner.contract.d.ts +28 -376
  9. package/dist/contracts/consent/show-banner.contract.d.ts.map +1 -1
  10. package/dist/contracts/consent/verify.contract.d.ts +33 -99
  11. package/dist/contracts/consent/verify.contract.d.ts.map +1 -1
  12. package/dist/contracts/index.d.ts +222 -1356
  13. package/dist/contracts/index.d.ts.map +1 -1
  14. package/dist/contracts/meta/index.d.ts +8 -63
  15. package/dist/contracts/meta/index.d.ts.map +1 -1
  16. package/dist/contracts/meta/status.contract.d.ts +8 -63
  17. package/dist/contracts/meta/status.contract.d.ts.map +1 -1
  18. package/dist/contracts/shared/jurisdiction.schema.d.ts +21 -9
  19. package/dist/contracts/shared/jurisdiction.schema.d.ts.map +1 -1
  20. package/dist/contracts.cjs +100 -106
  21. package/dist/contracts.js +100 -106
  22. package/dist/core.cjs +681 -681
  23. package/dist/core.d.ts +118 -678
  24. package/dist/core.d.ts.map +1 -1
  25. package/dist/core.js +634 -637
  26. package/dist/handlers/consent/index.d.ts +103 -615
  27. package/dist/handlers/consent/index.d.ts.map +1 -1
  28. package/dist/handlers/consent/post.handler.d.ts +42 -140
  29. package/dist/handlers/consent/post.handler.d.ts.map +1 -1
  30. package/dist/handlers/consent/show-banner/handler.d.ts +28 -376
  31. package/dist/handlers/consent/show-banner/handler.d.ts.map +1 -1
  32. package/dist/handlers/consent/show-banner/translations.d.ts.map +1 -1
  33. package/dist/handlers/consent/verify.handler.d.ts +33 -99
  34. package/dist/handlers/consent/verify.handler.d.ts.map +1 -1
  35. package/dist/handlers/meta/index.d.ts +8 -63
  36. package/dist/handlers/meta/index.d.ts.map +1 -1
  37. package/dist/handlers/meta/status.handler.d.ts +8 -63
  38. package/dist/handlers/meta/status.handler.d.ts.map +1 -1
  39. package/dist/init.d.ts.map +1 -1
  40. package/dist/middleware/openapi/index.d.ts +2 -2
  41. package/dist/middleware/openapi/index.d.ts.map +1 -1
  42. package/dist/pkgs/data-model/fields/index.cjs +14 -26
  43. package/dist/pkgs/data-model/fields/index.d.ts +4 -4
  44. package/dist/pkgs/data-model/fields/index.d.ts.map +1 -1
  45. package/dist/pkgs/data-model/fields/index.js +14 -26
  46. package/dist/pkgs/data-model/fields/zod-fields.d.ts +195 -871
  47. package/dist/pkgs/data-model/fields/zod-fields.d.ts.map +1 -1
  48. package/dist/pkgs/data-model/hooks/index.d.ts +2 -2
  49. package/dist/pkgs/data-model/hooks/index.d.ts.map +1 -1
  50. package/dist/pkgs/data-model/index.cjs +346 -358
  51. package/dist/pkgs/data-model/index.d.ts +1 -1
  52. package/dist/pkgs/data-model/index.d.ts.map +1 -1
  53. package/dist/pkgs/data-model/index.js +345 -357
  54. package/dist/pkgs/data-model/schema/index.cjs +346 -358
  55. package/dist/pkgs/data-model/schema/index.d.ts +1 -1
  56. package/dist/pkgs/data-model/schema/index.d.ts.map +1 -1
  57. package/dist/pkgs/data-model/schema/index.js +345 -357
  58. package/dist/pkgs/data-model/schema/schemas.d.ts +2 -2
  59. package/dist/pkgs/data-model/schema/schemas.d.ts.map +1 -1
  60. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts +3 -0
  61. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts.map +1 -1
  62. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.cjs +158 -170
  63. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.js +157 -169
  64. package/dist/pkgs/db-adapters/adapters/index.d.ts +2 -2
  65. package/dist/pkgs/db-adapters/adapters/index.d.ts.map +1 -1
  66. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.cjs +215 -227
  67. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.d.ts +2 -2
  68. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.d.ts.map +1 -1
  69. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.js +213 -225
  70. package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts +2 -0
  71. package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts.map +1 -1
  72. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts +1 -1
  73. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts.map +1 -1
  74. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.cjs +158 -170
  75. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.js +157 -169
  76. package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts +3 -0
  77. package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts.map +1 -1
  78. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.cjs +243 -255
  79. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.d.ts +1 -1
  80. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.d.ts.map +1 -1
  81. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.js +241 -253
  82. package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts +3 -0
  83. package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts.map +1 -1
  84. package/dist/pkgs/db-adapters/index.cjs +714 -726
  85. package/dist/pkgs/db-adapters/index.d.ts +6 -6
  86. package/dist/pkgs/db-adapters/index.d.ts.map +1 -1
  87. package/dist/pkgs/db-adapters/index.js +708 -720
  88. package/dist/pkgs/migrations/get-migration.d.ts.map +1 -1
  89. package/dist/pkgs/migrations/get-schema/get-schema.d.ts.map +1 -1
  90. package/dist/pkgs/migrations/get-schema/process-tables.d.ts.map +1 -1
  91. package/dist/pkgs/migrations/index.cjs +236 -248
  92. package/dist/pkgs/migrations/index.d.ts +4 -4
  93. package/dist/pkgs/migrations/index.d.ts.map +1 -1
  94. package/dist/pkgs/migrations/index.js +235 -247
  95. package/dist/pkgs/results/index.cjs +67 -67
  96. package/dist/pkgs/results/index.d.ts +5 -5
  97. package/dist/pkgs/results/index.d.ts.map +1 -1
  98. package/dist/pkgs/results/index.js +67 -67
  99. package/dist/pkgs/results/orpc-error-handler.d.ts +1 -1
  100. package/dist/pkgs/results/orpc-error-handler.d.ts.map +1 -1
  101. package/dist/pkgs/types/index.d.ts +1 -2
  102. package/dist/pkgs/types/index.d.ts.map +1 -1
  103. package/dist/pkgs/types/options.d.ts +9 -2
  104. package/dist/pkgs/types/options.d.ts.map +1 -1
  105. package/dist/pkgs/utils/index.d.ts +1 -1
  106. package/dist/pkgs/utils/index.d.ts.map +1 -1
  107. package/dist/pkgs/utils/logger.d.ts +1 -1
  108. package/dist/pkgs/utils/logger.d.ts.map +1 -1
  109. package/dist/router.cjs +114 -117
  110. package/dist/router.d.ts +111 -678
  111. package/dist/router.d.ts.map +1 -1
  112. package/dist/router.js +114 -117
  113. package/dist/schema/audit-log/schema.d.ts +2 -24
  114. package/dist/schema/audit-log/schema.d.ts.map +1 -1
  115. package/dist/schema/audit-log/table.d.ts +2 -24
  116. package/dist/schema/audit-log/table.d.ts.map +1 -1
  117. package/dist/schema/consent/registry.d.ts +8 -8
  118. package/dist/schema/consent/schema.d.ts +9 -33
  119. package/dist/schema/consent/schema.d.ts.map +1 -1
  120. package/dist/schema/consent/table.d.ts +9 -33
  121. package/dist/schema/consent/table.d.ts.map +1 -1
  122. package/dist/schema/consent-policy/registry.d.ts +20 -20
  123. package/dist/schema/consent-policy/schema.d.ts +22 -30
  124. package/dist/schema/consent-policy/schema.d.ts.map +1 -1
  125. package/dist/schema/consent-policy/table.d.ts +13 -29
  126. package/dist/schema/consent-policy/table.d.ts.map +1 -1
  127. package/dist/schema/consent-purpose/registry.d.ts +6 -6
  128. package/dist/schema/consent-purpose/schema.d.ts +5 -27
  129. package/dist/schema/consent-purpose/schema.d.ts.map +1 -1
  130. package/dist/schema/consent-purpose/table.d.ts +5 -27
  131. package/dist/schema/consent-purpose/table.d.ts.map +1 -1
  132. package/dist/schema/consent-record/schema.d.ts +3 -19
  133. package/dist/schema/consent-record/schema.d.ts.map +1 -1
  134. package/dist/schema/consent-record/table.d.ts +3 -19
  135. package/dist/schema/consent-record/table.d.ts.map +1 -1
  136. package/dist/schema/create-registry.d.ts +58 -58
  137. package/dist/schema/definition.d.ts +42 -176
  138. package/dist/schema/definition.d.ts.map +1 -1
  139. package/dist/schema/domain/registry.d.ts +20 -20
  140. package/dist/schema/domain/schema.d.ts +6 -24
  141. package/dist/schema/domain/schema.d.ts.map +1 -1
  142. package/dist/schema/domain/table.d.ts +6 -24
  143. package/dist/schema/domain/table.d.ts.map +1 -1
  144. package/dist/schema/index.cjs +426 -438
  145. package/dist/schema/index.d.ts +12 -12
  146. package/dist/schema/index.d.ts.map +1 -1
  147. package/dist/schema/index.js +426 -438
  148. package/dist/schema/schemas.d.ts +42 -176
  149. package/dist/schema/schemas.d.ts.map +1 -1
  150. package/dist/schema/subject/registry.d.ts +4 -4
  151. package/dist/schema/subject/schema.d.ts +4 -20
  152. package/dist/schema/subject/schema.d.ts.map +1 -1
  153. package/dist/schema/subject/table.d.ts +4 -20
  154. package/dist/schema/subject/table.d.ts.map +1 -1
  155. package/dist/schema/types.d.ts +1 -1
  156. package/dist/schema/types.d.ts.map +1 -1
  157. package/dist/testing/contract-testing.d.ts +3 -2
  158. package/dist/testing/contract-testing.d.ts.map +1 -1
  159. package/dist/types/index.d.ts +5 -4
  160. package/dist/types/index.d.ts.map +1 -1
  161. package/dist/types/options.d.ts +2 -2
  162. package/dist/types/options.d.ts.map +1 -1
  163. package/dist/v2/contracts/consent/index.d.ts +260 -0
  164. package/dist/v2/contracts/consent/index.d.ts.map +1 -0
  165. package/dist/v2/contracts/consent/index.test.d.ts +2 -0
  166. package/dist/v2/contracts/consent/index.test.d.ts.map +1 -0
  167. package/dist/v2/contracts/consent/post.contract.d.ts +114 -0
  168. package/dist/v2/contracts/consent/post.contract.d.ts.map +1 -0
  169. package/dist/v2/contracts/consent/post.contract.test.d.ts +2 -0
  170. package/dist/v2/contracts/consent/post.contract.test.d.ts.map +1 -0
  171. package/dist/v2/contracts/consent/show-banner.contract.d.ts +68 -0
  172. package/dist/v2/contracts/consent/show-banner.contract.d.ts.map +1 -0
  173. package/dist/v2/contracts/consent/show-banner.contract.test.d.ts +2 -0
  174. package/dist/v2/contracts/consent/show-banner.contract.test.d.ts.map +1 -0
  175. package/dist/v2/contracts/consent/verify.contract.d.ts +81 -0
  176. package/dist/v2/contracts/consent/verify.contract.d.ts.map +1 -0
  177. package/dist/v2/contracts/consent/verify.contract.test.d.ts +2 -0
  178. package/dist/v2/contracts/consent/verify.contract.test.d.ts.map +1 -0
  179. package/dist/v2/contracts/index.cjs +644 -0
  180. package/dist/v2/contracts/index.d.ts +563 -0
  181. package/dist/v2/contracts/index.d.ts.map +1 -0
  182. package/dist/v2/contracts/index.js +607 -0
  183. package/dist/v2/contracts/meta/index.d.ts +19 -0
  184. package/dist/v2/contracts/meta/index.d.ts.map +1 -0
  185. package/dist/v2/contracts/meta/index.test.d.ts +2 -0
  186. package/dist/v2/contracts/meta/index.test.d.ts.map +1 -0
  187. package/dist/v2/contracts/meta/status.contract.d.ts +18 -0
  188. package/dist/v2/contracts/meta/status.contract.d.ts.map +1 -0
  189. package/dist/v2/contracts/meta/status.contract.test.d.ts +2 -0
  190. package/dist/v2/contracts/meta/status.contract.test.d.ts.map +1 -0
  191. package/dist/v2/contracts/shared/jurisdiction.schema.d.ts +36 -0
  192. package/dist/v2/contracts/shared/jurisdiction.schema.d.ts.map +1 -0
  193. package/dist/v2/contracts/test.utils.d.ts +38 -0
  194. package/dist/v2/contracts/test.utils.d.ts.map +1 -0
  195. package/dist/v2/core.cjs +2181 -0
  196. package/dist/v2/core.d.ts +364 -0
  197. package/dist/v2/core.d.ts.map +1 -0
  198. package/dist/v2/core.js +2130 -0
  199. package/dist/v2/db/adapters/drizzle.cjs +36 -0
  200. package/dist/v2/db/adapters/drizzle.d.ts +2 -0
  201. package/dist/v2/db/adapters/drizzle.d.ts.map +1 -0
  202. package/dist/v2/db/adapters/drizzle.js +3 -0
  203. package/dist/v2/db/adapters/index.cjs +18 -0
  204. package/dist/v2/db/adapters/index.d.ts +2 -0
  205. package/dist/v2/db/adapters/index.d.ts.map +1 -0
  206. package/dist/v2/db/adapters/index.js +0 -0
  207. package/dist/v2/db/adapters/kysely.cjs +36 -0
  208. package/dist/v2/db/adapters/kysely.d.ts +2 -0
  209. package/dist/v2/db/adapters/kysely.d.ts.map +1 -0
  210. package/dist/v2/db/adapters/kysely.js +3 -0
  211. package/dist/v2/db/adapters/mongo.cjs +36 -0
  212. package/dist/v2/db/adapters/mongo.d.ts +2 -0
  213. package/dist/v2/db/adapters/mongo.d.ts.map +1 -0
  214. package/dist/v2/db/adapters/mongo.js +3 -0
  215. package/dist/v2/db/adapters/prisma.cjs +36 -0
  216. package/dist/v2/db/adapters/prisma.d.ts +2 -0
  217. package/dist/v2/db/adapters/prisma.d.ts.map +1 -0
  218. package/dist/v2/db/adapters/prisma.js +3 -0
  219. package/dist/v2/db/adapters/typeorm.cjs +36 -0
  220. package/dist/v2/db/adapters/typeorm.d.ts +2 -0
  221. package/dist/v2/db/adapters/typeorm.d.ts.map +1 -0
  222. package/dist/v2/db/adapters/typeorm.js +3 -0
  223. package/dist/v2/db/migrator/index.cjs +61 -0
  224. package/dist/v2/db/migrator/index.d.ts +29 -0
  225. package/dist/v2/db/migrator/index.d.ts.map +1 -0
  226. package/dist/v2/db/migrator/index.js +27 -0
  227. package/dist/v2/db/registry/audit-log.d.ts +21 -0
  228. package/dist/v2/db/registry/audit-log.d.ts.map +1 -0
  229. package/dist/v2/db/registry/audit-log.test.d.ts +2 -0
  230. package/dist/v2/db/registry/audit-log.test.d.ts.map +1 -0
  231. package/dist/v2/db/registry/consent-policy.d.ts +29 -0
  232. package/dist/v2/db/registry/consent-policy.d.ts.map +1 -0
  233. package/dist/v2/db/registry/consent-policy.test.d.ts +2 -0
  234. package/dist/v2/db/registry/consent-policy.test.d.ts.map +1 -0
  235. package/dist/v2/db/registry/consent-purpose.d.ts +16 -0
  236. package/dist/v2/db/registry/consent-purpose.d.ts.map +1 -0
  237. package/dist/v2/db/registry/consent-purpose.test.d.ts +2 -0
  238. package/dist/v2/db/registry/consent-purpose.test.d.ts.map +1 -0
  239. package/dist/v2/db/registry/consent.d.ts +20 -0
  240. package/dist/v2/db/registry/consent.d.ts.map +1 -0
  241. package/dist/v2/db/registry/consent.test.d.ts +2 -0
  242. package/dist/v2/db/registry/consent.test.d.ts.map +1 -0
  243. package/dist/v2/db/registry/domain.d.ts +24 -0
  244. package/dist/v2/db/registry/domain.d.ts.map +1 -0
  245. package/dist/v2/db/registry/domain.test.d.ts +2 -0
  246. package/dist/v2/db/registry/domain.test.d.ts.map +1 -0
  247. package/dist/v2/db/registry/index.d.ts +102 -0
  248. package/dist/v2/db/registry/index.d.ts.map +1 -0
  249. package/dist/v2/db/registry/subject.d.ts +18 -0
  250. package/dist/v2/db/registry/subject.d.ts.map +1 -0
  251. package/dist/v2/db/registry/subject.test.d.ts +2 -0
  252. package/dist/v2/db/registry/subject.test.d.ts.map +1 -0
  253. package/dist/v2/db/registry/types.d.ts +10 -0
  254. package/dist/v2/db/registry/types.d.ts.map +1 -0
  255. package/dist/v2/db/registry/utils/generate-id.d.ts +25 -0
  256. package/dist/v2/db/registry/utils/generate-id.d.ts.map +1 -0
  257. package/dist/v2/db/registry/utils/generate-id.test.d.ts +2 -0
  258. package/dist/v2/db/registry/utils/generate-id.test.d.ts.map +1 -0
  259. package/dist/v2/db/registry/utils.d.ts +25 -0
  260. package/dist/v2/db/registry/utils.d.ts.map +1 -0
  261. package/dist/v2/db/schema/1.0.0/audit-log.d.ts +29 -0
  262. package/dist/v2/db/schema/1.0.0/audit-log.d.ts.map +1 -0
  263. package/dist/v2/db/schema/1.0.0/consent-policy.d.ts +45 -0
  264. package/dist/v2/db/schema/1.0.0/consent-policy.d.ts.map +1 -0
  265. package/dist/v2/db/schema/1.0.0/consent-purpose.d.ts +27 -0
  266. package/dist/v2/db/schema/1.0.0/consent-purpose.d.ts.map +1 -0
  267. package/dist/v2/db/schema/1.0.0/consent-record.d.ts +19 -0
  268. package/dist/v2/db/schema/1.0.0/consent-record.d.ts.map +1 -0
  269. package/dist/v2/db/schema/1.0.0/consent.d.ts +42 -0
  270. package/dist/v2/db/schema/1.0.0/consent.d.ts.map +1 -0
  271. package/dist/v2/db/schema/1.0.0/domain.d.ts +23 -0
  272. package/dist/v2/db/schema/1.0.0/domain.d.ts.map +1 -0
  273. package/dist/v2/db/schema/1.0.0/index.d.ts +1513 -0
  274. package/dist/v2/db/schema/1.0.0/index.d.ts.map +1 -0
  275. package/dist/v2/db/schema/1.0.0/subject.d.ts +23 -0
  276. package/dist/v2/db/schema/1.0.0/subject.d.ts.map +1 -0
  277. package/dist/v2/db/schema/index.cjs +326 -0
  278. package/dist/v2/db/schema/index.d.ts +1507 -0
  279. package/dist/v2/db/schema/index.d.ts.map +1 -0
  280. package/dist/v2/db/schema/index.js +241 -0
  281. package/dist/v2/define-config.cjs +36 -0
  282. package/dist/v2/define-config.d.ts +5 -0
  283. package/dist/v2/define-config.d.ts.map +1 -0
  284. package/dist/v2/define-config.js +2 -0
  285. package/dist/v2/handlers/consent/index.d.ts +260 -0
  286. package/dist/v2/handlers/consent/index.d.ts.map +1 -0
  287. package/dist/v2/handlers/consent/post.handler.d.ts +136 -0
  288. package/dist/v2/handlers/consent/post.handler.d.ts.map +1 -0
  289. package/dist/v2/handlers/consent/show-banner/geo.d.ts +10 -0
  290. package/dist/v2/handlers/consent/show-banner/geo.d.ts.map +1 -0
  291. package/dist/v2/handlers/consent/show-banner/geo.test.d.ts +2 -0
  292. package/dist/v2/handlers/consent/show-banner/geo.test.d.ts.map +1 -0
  293. package/dist/v2/handlers/consent/show-banner/handler.d.ts +71 -0
  294. package/dist/v2/handlers/consent/show-banner/handler.d.ts.map +1 -0
  295. package/dist/v2/handlers/consent/show-banner/handler.test.d.ts +2 -0
  296. package/dist/v2/handlers/consent/show-banner/handler.test.d.ts.map +1 -0
  297. package/dist/v2/handlers/consent/show-banner/translations.d.ts +13 -0
  298. package/dist/v2/handlers/consent/show-banner/translations.d.ts.map +1 -0
  299. package/dist/v2/handlers/consent/show-banner/translations.test.d.ts +2 -0
  300. package/dist/v2/handlers/consent/show-banner/translations.test.d.ts.map +1 -0
  301. package/dist/v2/handlers/consent/verify.handler.d.ts +103 -0
  302. package/dist/v2/handlers/consent/verify.handler.d.ts.map +1 -0
  303. package/dist/v2/handlers/meta/index.d.ts +19 -0
  304. package/dist/v2/handlers/meta/index.d.ts.map +1 -0
  305. package/dist/v2/handlers/meta/status.handler.d.ts +17 -0
  306. package/dist/v2/handlers/meta/status.handler.d.ts.map +1 -0
  307. package/dist/v2/init.d.ts +3 -0
  308. package/dist/v2/init.d.ts.map +1 -0
  309. package/dist/v2/init.test.d.ts +2 -0
  310. package/dist/v2/init.test.d.ts.map +1 -0
  311. package/dist/v2/middleware/cors/cors.d.ts +37 -0
  312. package/dist/v2/middleware/cors/cors.d.ts.map +1 -0
  313. package/dist/v2/middleware/cors/cors.test.d.ts +2 -0
  314. package/dist/v2/middleware/cors/cors.test.d.ts.map +1 -0
  315. package/dist/v2/middleware/cors/index.d.ts +30 -0
  316. package/dist/v2/middleware/cors/index.d.ts.map +1 -0
  317. package/dist/v2/middleware/cors/is-origin-trusted.d.ts +49 -0
  318. package/dist/v2/middleware/cors/is-origin-trusted.d.ts.map +1 -0
  319. package/dist/v2/middleware/cors/is-origin-trusted.test.d.ts +2 -0
  320. package/dist/v2/middleware/cors/is-origin-trusted.test.d.ts.map +1 -0
  321. package/dist/v2/middleware/cors/process-cors.d.ts +31 -0
  322. package/dist/v2/middleware/cors/process-cors.d.ts.map +1 -0
  323. package/dist/v2/middleware/openapi/config.d.ts +28 -0
  324. package/dist/v2/middleware/openapi/config.d.ts.map +1 -0
  325. package/dist/v2/middleware/openapi/handlers.d.ts +29 -0
  326. package/dist/v2/middleware/openapi/handlers.d.ts.map +1 -0
  327. package/dist/v2/middleware/openapi/index.d.ts +11 -0
  328. package/dist/v2/middleware/openapi/index.d.ts.map +1 -0
  329. package/dist/v2/middleware/process-ip/index.d.ts +3 -0
  330. package/dist/v2/middleware/process-ip/index.d.ts.map +1 -0
  331. package/dist/v2/router.cjs +1275 -0
  332. package/dist/v2/router.d.ts +280 -0
  333. package/dist/v2/router.d.ts.map +1 -0
  334. package/dist/v2/router.js +1231 -0
  335. package/dist/v2/types/api.d.ts +27 -0
  336. package/dist/v2/types/api.d.ts.map +1 -0
  337. package/dist/v2/types/index.cjs +40 -0
  338. package/dist/v2/types/index.d.ts +104 -0
  339. package/dist/v2/types/index.d.ts.map +1 -0
  340. package/dist/v2/types/index.js +6 -0
  341. package/dist/v2/utils/create-telemetry-options.d.ts +28 -0
  342. package/dist/v2/utils/create-telemetry-options.d.ts.map +1 -0
  343. package/dist/v2/utils/env.d.ts +60 -0
  344. package/dist/v2/utils/env.d.ts.map +1 -0
  345. package/dist/v2/utils/index.d.ts +3 -0
  346. package/dist/v2/utils/index.d.ts.map +1 -0
  347. package/dist/v2/utils/logger.d.ts +16 -0
  348. package/dist/v2/utils/logger.d.ts.map +1 -0
  349. package/dist/version.d.ts +1 -1
  350. package/package.json +106 -15
  351. package/readme.json +30 -0
  352. package/rslib.config.ts +13 -14
  353. package/src/__tests__/server.test.ts +1 -1
  354. package/src/contracts/consent/post.contract.test.ts +3 -8
  355. package/src/contracts/consent/post.contract.ts +13 -13
  356. package/src/contracts/consent/show-banner.contract.test.ts +9 -0
  357. package/src/contracts/consent/show-banner.contract.ts +2 -0
  358. package/src/contracts/consent/verify.contract.ts +19 -23
  359. package/src/core.ts +7 -0
  360. package/src/handlers/consent/show-banner/handler.ts +12 -9
  361. package/src/handlers/consent/show-banner/translations.ts +2 -2
  362. package/src/init.ts +9 -6
  363. package/src/middleware/openapi/index.ts +2 -2
  364. package/src/pkgs/api-router/hooks/__tests__/processor.test.ts +1 -1
  365. package/src/pkgs/data-model/fields/index.ts +17 -22
  366. package/src/pkgs/data-model/fields/zod-fields.ts +14 -26
  367. package/src/pkgs/data-model/hooks/index.ts +3 -2
  368. package/src/pkgs/data-model/index.ts +2 -4
  369. package/src/pkgs/data-model/schema/index.ts +6 -7
  370. package/src/pkgs/data-model/schema/schemas.ts +3 -3
  371. package/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts +4 -1
  372. package/src/pkgs/db-adapters/adapters/index.ts +2 -2
  373. package/src/pkgs/db-adapters/adapters/kysely-adapter/index.ts +4 -4
  374. package/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts +4 -5
  375. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/postgres.test.ts +2 -4
  376. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/sqlite.test.ts +2 -3
  377. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts +1 -6
  378. package/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts +4 -1
  379. package/src/pkgs/db-adapters/adapters/prisma-adapter/index.ts +1 -1
  380. package/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts +5 -2
  381. package/src/pkgs/db-adapters/index.ts +12 -13
  382. package/src/pkgs/migrations/get-migration.ts +4 -2
  383. package/src/pkgs/migrations/get-schema/get-schema.ts +0 -1
  384. package/src/pkgs/migrations/get-schema/process-fields.ts +1 -1
  385. package/src/pkgs/migrations/get-schema/process-tables.ts +0 -2
  386. package/src/pkgs/migrations/index.ts +7 -8
  387. package/src/pkgs/results/__tests__/error-codes.test.ts +2 -2
  388. package/src/pkgs/results/index.ts +22 -27
  389. package/src/pkgs/results/orpc-error-handler.ts +1 -1
  390. package/src/pkgs/results/results/result-helpers.ts +1 -1
  391. package/src/pkgs/types/index.ts +4 -4
  392. package/src/pkgs/types/options.ts +10 -3
  393. package/src/pkgs/utils/index.ts +1 -1
  394. package/src/pkgs/utils/logger.ts +1 -1
  395. package/src/schema/audit-log/schema.ts +3 -3
  396. package/src/schema/consent/schema.ts +4 -4
  397. package/src/schema/consent-policy/schema.ts +3 -3
  398. package/src/schema/consent-purpose/schema.ts +4 -4
  399. package/src/schema/consent-record/schema.ts +3 -3
  400. package/src/schema/definition.ts +1 -1
  401. package/src/schema/domain/schema.ts +5 -5
  402. package/src/schema/index.ts +14 -17
  403. package/src/schema/subject/schema.ts +3 -3
  404. package/src/schema/types.ts +1 -1
  405. package/src/testing/contract-testing.ts +15 -52
  406. package/src/types/index.ts +8 -8
  407. package/src/types/options.ts +2 -3
  408. package/src/v2/contracts/consent/index.test.ts +5 -0
  409. package/src/v2/contracts/consent/index.ts +9 -0
  410. package/src/v2/contracts/consent/post.contract.test.ts +521 -0
  411. package/src/v2/contracts/consent/post.contract.ts +155 -0
  412. package/src/v2/contracts/consent/show-banner.contract.test.ts +252 -0
  413. package/src/v2/contracts/consent/show-banner.contract.ts +73 -0
  414. package/src/v2/contracts/consent/verify.contract.test.ts +185 -0
  415. package/src/v2/contracts/consent/verify.contract.ts +122 -0
  416. package/src/v2/contracts/index.ts +20 -0
  417. package/src/v2/contracts/meta/index.test.ts +5 -0
  418. package/src/v2/contracts/meta/index.ts +5 -0
  419. package/src/v2/contracts/meta/status.contract.test.ts +226 -0
  420. package/src/v2/contracts/meta/status.contract.ts +34 -0
  421. package/src/v2/contracts/shared/jurisdiction.schema.ts +30 -0
  422. package/src/v2/contracts/test.utils.ts +400 -0
  423. package/src/v2/core.ts +379 -0
  424. package/src/v2/db/adapters/drizzle.ts +1 -0
  425. package/src/v2/db/adapters/index.ts +1 -0
  426. package/src/v2/db/adapters/kysely.ts +1 -0
  427. package/src/v2/db/adapters/mongo.ts +1 -0
  428. package/src/v2/db/adapters/prisma.ts +1 -0
  429. package/src/v2/db/adapters/typeorm.ts +1 -0
  430. package/src/v2/db/migrator/index.ts +80 -0
  431. package/src/v2/db/registry/audit-log.test.ts +77 -0
  432. package/src/v2/db/registry/audit-log.ts +46 -0
  433. package/src/v2/db/registry/consent-policy.test.ts +778 -0
  434. package/src/v2/db/registry/consent-policy.ts +74 -0
  435. package/src/v2/db/registry/consent-purpose.test.ts +485 -0
  436. package/src/v2/db/registry/consent-purpose.ts +41 -0
  437. package/src/v2/db/registry/consent.test.ts +843 -0
  438. package/src/v2/db/registry/consent.ts +42 -0
  439. package/src/v2/db/registry/domain.test.ts +463 -0
  440. package/src/v2/db/registry/domain.ts +51 -0
  441. package/src/v2/db/registry/index.ts +18 -0
  442. package/src/v2/db/registry/subject.test.ts +497 -0
  443. package/src/v2/db/registry/subject.ts +101 -0
  444. package/src/v2/db/registry/types.ts +10 -0
  445. package/src/v2/db/registry/utils/generate-id.test.ts +217 -0
  446. package/src/v2/db/registry/utils/generate-id.ts +134 -0
  447. package/src/v2/db/registry/utils.ts +134 -0
  448. package/src/v2/db/schema/1.0.0/audit-log.ts +32 -0
  449. package/src/v2/db/schema/1.0.0/consent-policy.ts +41 -0
  450. package/src/v2/db/schema/1.0.0/consent-purpose.ts +30 -0
  451. package/src/v2/db/schema/1.0.0/consent-record.ts +22 -0
  452. package/src/v2/db/schema/1.0.0/consent.ts +38 -0
  453. package/src/v2/db/schema/1.0.0/domain.ts +26 -0
  454. package/src/v2/db/schema/1.0.0/index.ts +56 -0
  455. package/src/v2/db/schema/1.0.0/subject.ts +26 -0
  456. package/src/v2/db/schema/index.ts +9 -0
  457. package/src/v2/define-config.ts +5 -0
  458. package/src/v2/handlers/consent/index.ts +9 -0
  459. package/src/v2/handlers/consent/post.handler.ts +254 -0
  460. package/src/v2/handlers/consent/show-banner/geo.test.ts +281 -0
  461. package/src/v2/handlers/consent/show-banner/geo.ts +96 -0
  462. package/src/v2/handlers/consent/show-banner/handler.test.ts +374 -0
  463. package/src/v2/handlers/consent/show-banner/handler.ts +123 -0
  464. package/src/v2/handlers/consent/show-banner/translations.test.ts +121 -0
  465. package/src/v2/handlers/consent/show-banner/translations.ts +79 -0
  466. package/src/v2/handlers/consent/verify.handler.ts +288 -0
  467. package/src/v2/handlers/meta/index.ts +5 -0
  468. package/src/v2/handlers/meta/status.handler.ts +43 -0
  469. package/src/v2/init.test.ts +114 -0
  470. package/src/v2/init.ts +126 -0
  471. package/src/v2/middleware/cors/cors.test.ts +111 -0
  472. package/src/v2/middleware/cors/cors.ts +192 -0
  473. package/src/v2/middleware/cors/index.ts +30 -0
  474. package/src/v2/middleware/cors/is-origin-trusted.test.ts +104 -0
  475. package/src/v2/middleware/cors/is-origin-trusted.ts +126 -0
  476. package/src/v2/middleware/cors/process-cors.ts +91 -0
  477. package/src/v2/middleware/openapi/config.ts +27 -0
  478. package/src/v2/middleware/openapi/handlers.ts +132 -0
  479. package/src/v2/middleware/openapi/index.ts +11 -0
  480. package/src/v2/middleware/process-ip/index.ts +39 -0
  481. package/src/v2/router.ts +8 -0
  482. package/src/v2/types/api.ts +32 -0
  483. package/src/v2/types/index.ts +121 -0
  484. package/src/v2/utils/create-telemetry-options.ts +115 -0
  485. package/src/v2/utils/env.ts +84 -0
  486. package/src/v2/utils/index.ts +2 -0
  487. package/src/v2/utils/logger.ts +38 -0
  488. package/src/version.ts +1 -1
  489. package/vitest.config.ts +11 -2
@@ -0,0 +1,74 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import type { PolicyType } from '../schema';
3
+ import type { Registry } from './types';
4
+ import { generateUniqueId } from './utils/generate-id';
5
+
6
+ export function policyRegistry({ db, ctx }: Registry) {
7
+ const { logger } = ctx;
8
+ async function generatePolicyPlaceholder(name: string, date: Date) {
9
+ const content = `[PLACEHOLDER] This is an automatically generated version of the ${name} policy.\n\nThis placeholder content should be replaced with actual policy terms before being presented to users.\n\nGenerated on: ${date.toISOString()}`;
10
+
11
+ let contentHash: string;
12
+ try {
13
+ // Use Web Crypto API which is available in both browsers and edge environments
14
+ const encoder = new TextEncoder();
15
+ const data = encoder.encode(content);
16
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
17
+ contentHash = Array.from(new Uint8Array(hashBuffer))
18
+ .map((b) => b.toString(16).padStart(2, '0'))
19
+ .join('');
20
+ } catch {
21
+ throw new ORPCError('POLICY_CREATION_FAILED', {
22
+ message: 'Failed to generate policy content hash',
23
+ status: 500,
24
+ data: { name },
25
+ });
26
+ }
27
+
28
+ return { content, contentHash };
29
+ }
30
+
31
+ return {
32
+ findConsentPolicyById: async (policyId: string) => {
33
+ const policy = await db.findFirst('consentPolicy', {
34
+ where: (b) => b('id', '=', policyId),
35
+ });
36
+
37
+ return policy;
38
+ },
39
+ findOrCreatePolicy: async (type: PolicyType) => {
40
+ // Gets most recent active policy for a given type
41
+ const existingPolicy = await db.findFirst('consentPolicy', {
42
+ where: (b) => b.and(b('isActive', '=', true), b('type', '=', type)),
43
+ orderBy: ['effectiveDate', 'desc'],
44
+ });
45
+
46
+ if (existingPolicy) {
47
+ logger.debug('Found existing policy', {
48
+ type,
49
+ policyId: existingPolicy.id,
50
+ });
51
+ return existingPolicy;
52
+ }
53
+
54
+ const { content, contentHash } = await generatePolicyPlaceholder(
55
+ type,
56
+ new Date()
57
+ );
58
+
59
+ const policy = await db.create('consentPolicy', {
60
+ id: await generateUniqueId(db, 'consentPolicy', ctx),
61
+ version: '1.0.0',
62
+ type,
63
+ name: type,
64
+ effectiveDate: new Date(),
65
+ content,
66
+ contentHash,
67
+ isActive: true,
68
+ expirationDate: null,
69
+ });
70
+
71
+ return policy;
72
+ },
73
+ };
74
+ }
@@ -0,0 +1,485 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import type { ConsentPurpose } from '../schema';
4
+ import { consentPurposeRegistry } from './consent-purpose';
5
+ import type { Registry } from './types';
6
+
7
+ // Mock generateUniqueId to return a predictable value for assertions
8
+ vi.mock('./utils/generate-id', () => ({
9
+ generateUniqueId: vi.fn().mockResolvedValue('cp_test_123'),
10
+ }));
11
+
12
+ describe('consentPurposeRegistry', () => {
13
+ const mockLogger = {
14
+ debug: vi.fn(),
15
+ error: vi.fn(),
16
+ info: vi.fn(),
17
+ warn: vi.fn(),
18
+ };
19
+
20
+ /**
21
+ * Creates a mock consent purpose object with the specified overrides
22
+ *
23
+ * @param overrides - Partial consent purpose properties to override defaults
24
+ * @returns A complete ConsentPurpose object for testing
25
+ */
26
+ const createMockConsentPurpose = (
27
+ overrides: Partial<ConsentPurpose> = {}
28
+ ): ConsentPurpose => ({
29
+ id: 'cp_test_123',
30
+ code: 'marketing',
31
+ name: 'marketing',
32
+ description: 'Auto-created consentPurpose for marketing',
33
+ isEssential: false,
34
+ dataCategory: null,
35
+ legalBasis: 'consent',
36
+ isActive: true,
37
+ createdAt: new Date('2024-01-01T00:00:00.000Z'),
38
+ updatedAt: new Date('2024-01-01T00:00:00.000Z'),
39
+ ...overrides,
40
+ });
41
+
42
+ afterEach(() => {
43
+ vi.clearAllMocks();
44
+ });
45
+
46
+ describe('findOrCreateConsentPurposeByCode', () => {
47
+ describe('when consent purpose exists', () => {
48
+ it('should return existing consent purpose when found by code', async () => {
49
+ const mockPurpose = createMockConsentPurpose({
50
+ code: 'analytics',
51
+ name: 'Analytics',
52
+ description: 'Analytics and performance tracking',
53
+ isEssential: true,
54
+ });
55
+
56
+ const db = {
57
+ findFirst: vi.fn().mockResolvedValue(mockPurpose),
58
+ create: vi.fn(),
59
+ };
60
+
61
+ const registry = consentPurposeRegistry({
62
+ db,
63
+ ctx: { logger: mockLogger },
64
+ } as unknown as Registry);
65
+
66
+ const result =
67
+ await registry.findOrCreateConsentPurposeByCode('analytics');
68
+
69
+ expect(db.findFirst).toHaveBeenCalledWith('consentPurpose', {
70
+ where: expect.any(Function),
71
+ });
72
+
73
+ expect(db.create).not.toHaveBeenCalled();
74
+ expect(result).toEqual(mockPurpose);
75
+ expect(mockLogger.debug).toHaveBeenCalledWith(
76
+ 'Found existing consent purpose',
77
+ { code: 'analytics' }
78
+ );
79
+ });
80
+
81
+ it('should handle different existing consent purpose types', async () => {
82
+ const testCases = [
83
+ {
84
+ code: 'essential',
85
+ name: 'Essential',
86
+ isEssential: true,
87
+ legalBasis: 'legitimate_interest',
88
+ },
89
+ {
90
+ code: 'preferences',
91
+ name: 'User Preferences',
92
+ isEssential: false,
93
+ legalBasis: 'consent',
94
+ },
95
+ {
96
+ code: 'functional',
97
+ name: 'Functional Cookies',
98
+ isEssential: false,
99
+ legalBasis: 'consent',
100
+ dataCategory: 'functional',
101
+ },
102
+ ];
103
+
104
+ for (const testCase of testCases) {
105
+ const mockPurpose = createMockConsentPurpose(testCase);
106
+
107
+ const db = {
108
+ findFirst: vi.fn().mockResolvedValue(mockPurpose),
109
+ create: vi.fn(),
110
+ };
111
+
112
+ const registry = consentPurposeRegistry({
113
+ db,
114
+ ctx: { logger: mockLogger },
115
+ } as unknown as Registry);
116
+
117
+ const result = await registry.findOrCreateConsentPurposeByCode(
118
+ testCase.code
119
+ );
120
+
121
+ expect(result).toEqual(mockPurpose);
122
+ expect(result.code).toBe(testCase.code);
123
+ expect(result.isEssential).toBe(testCase.isEssential);
124
+ expect(result.legalBasis).toBe(testCase.legalBasis);
125
+
126
+ vi.clearAllMocks();
127
+ }
128
+ });
129
+ });
130
+
131
+ describe('when consent purpose does not exist', () => {
132
+ it('should create and return new consent purpose', async () => {
133
+ const newMockPurpose = createMockConsentPurpose({
134
+ code: 'new-purpose',
135
+ name: 'new-purpose',
136
+ description: 'Auto-created consentPurpose for new-purpose',
137
+ });
138
+
139
+ const db = {
140
+ findFirst: vi.fn().mockResolvedValue(null),
141
+ create: vi.fn().mockResolvedValue(newMockPurpose),
142
+ };
143
+
144
+ const registry = consentPurposeRegistry({
145
+ db,
146
+ ctx: { logger: mockLogger },
147
+ } as unknown as Registry);
148
+
149
+ const result =
150
+ await registry.findOrCreateConsentPurposeByCode('new-purpose');
151
+
152
+ expect(db.findFirst).toHaveBeenCalledWith('consentPurpose', {
153
+ where: expect.any(Function),
154
+ });
155
+
156
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
157
+ id: 'cp_test_123',
158
+ code: 'new-purpose',
159
+ name: 'new-purpose',
160
+ description: 'Auto-created consentPurpose for new-purpose',
161
+ isActive: true,
162
+ isEssential: false,
163
+ legalBasis: 'consent',
164
+ });
165
+
166
+ expect(result).toEqual(newMockPurpose);
167
+ expect(mockLogger.debug).toHaveBeenCalledWith(
168
+ 'Creating consent purpose',
169
+ {
170
+ code: 'new-purpose',
171
+ }
172
+ );
173
+ });
174
+
175
+ it('should create consent purpose with correct default values', async () => {
176
+ const newMockPurpose = createMockConsentPurpose({
177
+ code: 'test-defaults',
178
+ });
179
+
180
+ const db = {
181
+ findFirst: vi.fn().mockResolvedValue(null),
182
+ create: vi.fn().mockResolvedValue(newMockPurpose),
183
+ };
184
+
185
+ const registry = consentPurposeRegistry({
186
+ db,
187
+ ctx: { logger: mockLogger },
188
+ } as unknown as Registry);
189
+
190
+ await registry.findOrCreateConsentPurposeByCode('test-defaults');
191
+
192
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
193
+ id: 'cp_test_123',
194
+ code: 'test-defaults',
195
+ name: 'test-defaults',
196
+ description: 'Auto-created consentPurpose for test-defaults',
197
+ isActive: true,
198
+ isEssential: false,
199
+ legalBasis: 'consent',
200
+ });
201
+ });
202
+
203
+ it('should handle special consent purpose codes correctly', async () => {
204
+ const specialCodes = [
205
+ 'strictly-necessary',
206
+ 'performance_analytics',
207
+ 'marketing.targeting',
208
+ 'social-media_integration',
209
+ 'third_party.advertising',
210
+ ];
211
+
212
+ for (const code of specialCodes) {
213
+ const mockPurpose = createMockConsentPurpose({
214
+ code,
215
+ name: code,
216
+ description: `Auto-created consentPurpose for ${code}`,
217
+ });
218
+
219
+ const db = {
220
+ findFirst: vi.fn().mockResolvedValue(null),
221
+ create: vi.fn().mockResolvedValue(mockPurpose),
222
+ };
223
+
224
+ const registry = consentPurposeRegistry({
225
+ db,
226
+ ctx: { logger: mockLogger },
227
+ } as unknown as Registry);
228
+
229
+ const result = await registry.findOrCreateConsentPurposeByCode(code);
230
+
231
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
232
+ id: 'cp_test_123',
233
+ code,
234
+ name: code,
235
+ description: `Auto-created consentPurpose for ${code}`,
236
+ isActive: true,
237
+ isEssential: false,
238
+ legalBasis: 'consent',
239
+ });
240
+
241
+ expect(result).toEqual(mockPurpose);
242
+
243
+ vi.clearAllMocks();
244
+ }
245
+ });
246
+ });
247
+
248
+ describe('error handling', () => {
249
+ it('should throw ORPCError when consent purpose creation fails', async () => {
250
+ const db = {
251
+ findFirst: vi.fn().mockResolvedValue(null),
252
+ create: vi.fn().mockResolvedValue(null),
253
+ };
254
+
255
+ const registry = consentPurposeRegistry({
256
+ db,
257
+ ctx: { logger: mockLogger },
258
+ } as unknown as Registry);
259
+
260
+ const promise =
261
+ registry.findOrCreateConsentPurposeByCode('failed-code');
262
+
263
+ await expect(promise).rejects.toBeInstanceOf(ORPCError);
264
+ await expect(promise).rejects.toEqual(
265
+ expect.objectContaining({
266
+ message: 'Failed to create consent purpose',
267
+ code: 'PURPOSE_CREATION_FAILED',
268
+ status: 500,
269
+ data: { purposeCode: 'failed-code' },
270
+ })
271
+ );
272
+
273
+ expect(db.findFirst).toHaveBeenCalledWith('consentPurpose', {
274
+ where: expect.any(Function),
275
+ });
276
+
277
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
278
+ id: 'cp_test_123',
279
+ code: 'failed-code',
280
+ name: 'failed-code',
281
+ description: 'Auto-created consentPurpose for failed-code',
282
+ isActive: true,
283
+ isEssential: false,
284
+ legalBasis: 'consent',
285
+ });
286
+
287
+ expect(mockLogger.debug).toHaveBeenCalledWith(
288
+ 'Creating consent purpose',
289
+ {
290
+ code: 'failed-code',
291
+ }
292
+ );
293
+ });
294
+
295
+ it('should throw ORPCError when consent purpose creation returns undefined', async () => {
296
+ const db = {
297
+ findFirst: vi.fn().mockResolvedValue(null),
298
+ create: vi.fn().mockResolvedValue(undefined),
299
+ };
300
+
301
+ const registry = consentPurposeRegistry({
302
+ db,
303
+ ctx: { logger: mockLogger },
304
+ } as unknown as Registry);
305
+
306
+ const promise =
307
+ registry.findOrCreateConsentPurposeByCode('undefined-code');
308
+
309
+ await expect(promise).rejects.toBeInstanceOf(ORPCError);
310
+ await expect(promise).rejects.toEqual(
311
+ expect.objectContaining({
312
+ message: 'Failed to create consent purpose',
313
+ code: 'PURPOSE_CREATION_FAILED',
314
+ status: 500,
315
+ data: { purposeCode: 'undefined-code' },
316
+ })
317
+ );
318
+ });
319
+
320
+ it('should propagate database findFirst errors', async () => {
321
+ const dbError = new Error('Database connection failed');
322
+ const db = {
323
+ findFirst: vi.fn().mockRejectedValue(dbError),
324
+ };
325
+
326
+ const registry = consentPurposeRegistry({
327
+ db,
328
+ ctx: { logger: mockLogger },
329
+ } as unknown as Registry);
330
+
331
+ const promise = registry.findOrCreateConsentPurposeByCode('error-code');
332
+
333
+ await expect(promise).rejects.toThrow('Database connection failed');
334
+ });
335
+
336
+ it('should propagate database create errors', async () => {
337
+ const dbError = new Error('Create operation failed');
338
+ const db = {
339
+ findFirst: vi.fn().mockResolvedValue(null),
340
+ create: vi.fn().mockRejectedValue(dbError),
341
+ };
342
+
343
+ const registry = consentPurposeRegistry({
344
+ db,
345
+ ctx: { logger: mockLogger },
346
+ } as unknown as Registry);
347
+
348
+ const promise =
349
+ registry.findOrCreateConsentPurposeByCode('create-error-code');
350
+
351
+ await expect(promise).rejects.toThrow('Create operation failed');
352
+ });
353
+ });
354
+ });
355
+
356
+ describe('database query construction', () => {
357
+ it('should construct correct query for consent purpose lookup by code', async () => {
358
+ const db = {
359
+ findFirst: vi.fn().mockResolvedValue(null),
360
+ create: vi.fn().mockResolvedValue(createMockConsentPurpose()),
361
+ };
362
+
363
+ const registry = consentPurposeRegistry({
364
+ db,
365
+ ctx: { logger: mockLogger },
366
+ } as unknown as Registry);
367
+
368
+ await registry.findOrCreateConsentPurposeByCode('query-test-code');
369
+
370
+ expect(db.findFirst).toHaveBeenCalledWith('consentPurpose', {
371
+ where: expect.any(Function),
372
+ });
373
+
374
+ // Verify the where function is properly constructed
375
+ const whereCall = db.findFirst.mock.calls[0]?.[1];
376
+ expect(whereCall).toHaveProperty('where');
377
+ expect(typeof whereCall?.where).toBe('function');
378
+ });
379
+ });
380
+
381
+ describe('edge cases', () => {
382
+ it('should handle consent purpose codes with various formats', async () => {
383
+ const edgeCaseCodes = [
384
+ 'a', // Single character
385
+ 'very-long-consent-purpose-code-name', // Long code
386
+ 'CODE_WITH_UNDERSCORES', // Uppercase with underscores
387
+ 'mixed.Case-code_123', // Mixed case with special chars
388
+ '数据处理', // Unicode/international characters
389
+ ];
390
+
391
+ for (const code of edgeCaseCodes) {
392
+ const mockPurpose = createMockConsentPurpose({
393
+ code,
394
+ name: code,
395
+ description: `Auto-created consentPurpose for ${code}`,
396
+ });
397
+
398
+ const db = {
399
+ findFirst: vi.fn().mockResolvedValue(null),
400
+ create: vi.fn().mockResolvedValue(mockPurpose),
401
+ };
402
+
403
+ const registry = consentPurposeRegistry({
404
+ db,
405
+ ctx: { logger: mockLogger },
406
+ } as unknown as Registry);
407
+
408
+ const result = await registry.findOrCreateConsentPurposeByCode(code);
409
+
410
+ expect(result.code).toBe(code);
411
+ expect(result.name).toBe(code);
412
+ expect(result.description).toBe(
413
+ `Auto-created consentPurpose for ${code}`
414
+ );
415
+
416
+ vi.clearAllMocks();
417
+ }
418
+ });
419
+
420
+ it('should maintain code case sensitivity', async () => {
421
+ const mixedCaseCode = 'Analytics_Tracking';
422
+ const mockPurpose = createMockConsentPurpose({
423
+ code: mixedCaseCode,
424
+ name: mixedCaseCode,
425
+ });
426
+
427
+ const db = {
428
+ findFirst: vi.fn().mockResolvedValue(null),
429
+ create: vi.fn().mockResolvedValue(mockPurpose),
430
+ };
431
+
432
+ const registry = consentPurposeRegistry({
433
+ db,
434
+ ctx: { logger: mockLogger },
435
+ } as unknown as Registry);
436
+
437
+ const result =
438
+ await registry.findOrCreateConsentPurposeByCode(mixedCaseCode);
439
+
440
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
441
+ id: 'cp_test_123',
442
+ code: mixedCaseCode,
443
+ name: mixedCaseCode,
444
+ description: `Auto-created consentPurpose for ${mixedCaseCode}`,
445
+ isActive: true,
446
+ isEssential: false,
447
+ legalBasis: 'consent',
448
+ });
449
+
450
+ expect(result.code).toBe(mixedCaseCode);
451
+ });
452
+
453
+ it('should handle empty string code gracefully', async () => {
454
+ const mockPurpose = createMockConsentPurpose({
455
+ code: '',
456
+ name: '',
457
+ description: 'Auto-created consentPurpose for ',
458
+ });
459
+
460
+ const db = {
461
+ findFirst: vi.fn().mockResolvedValue(null),
462
+ create: vi.fn().mockResolvedValue(mockPurpose),
463
+ };
464
+
465
+ const registry = consentPurposeRegistry({
466
+ db,
467
+ ctx: { logger: mockLogger },
468
+ } as unknown as Registry);
469
+
470
+ const result = await registry.findOrCreateConsentPurposeByCode('');
471
+
472
+ expect(db.create).toHaveBeenCalledWith('consentPurpose', {
473
+ id: 'cp_test_123',
474
+ code: '',
475
+ name: '',
476
+ description: 'Auto-created consentPurpose for ',
477
+ isActive: true,
478
+ isEssential: false,
479
+ legalBasis: 'consent',
480
+ });
481
+
482
+ expect(result.code).toBe('');
483
+ });
484
+ });
485
+ });
@@ -0,0 +1,41 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import type { Registry } from './types';
3
+ import { generateUniqueId } from './utils/generate-id';
4
+
5
+ export function consentPurposeRegistry({ db, ctx }: Registry) {
6
+ const { logger } = ctx;
7
+ return {
8
+ findOrCreateConsentPurposeByCode: async (code: string) => {
9
+ const existingPurpose = await db.findFirst('consentPurpose', {
10
+ where: (b) => b('code', '=', code),
11
+ });
12
+
13
+ if (existingPurpose) {
14
+ logger.debug('Found existing consent purpose', { code });
15
+ return existingPurpose;
16
+ }
17
+
18
+ logger.debug('Creating consent purpose', { code });
19
+
20
+ const createdPurpose = await db.create('consentPurpose', {
21
+ id: await generateUniqueId(db, 'consentPurpose', ctx),
22
+ code,
23
+ name: code,
24
+ description: `Auto-created consentPurpose for ${code}`,
25
+ isActive: true,
26
+ isEssential: false,
27
+ legalBasis: 'consent',
28
+ });
29
+
30
+ if (!createdPurpose) {
31
+ throw new ORPCError('PURPOSE_CREATION_FAILED', {
32
+ message: 'Failed to create consent purpose',
33
+ status: 500,
34
+ data: { purposeCode: code },
35
+ });
36
+ }
37
+
38
+ return createdPurpose;
39
+ },
40
+ };
41
+ }