@c15t/backend 1.0.0 → 1.1.0-canary.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 (478) hide show
  1. package/.turbo/turbo-build.log +33 -39
  2. package/.turbo/turbo-fmt.log +7 -0
  3. package/.turbo/turbo-test.log +531 -0
  4. package/README.md +19 -7
  5. package/coverage/coverage-final.json +84 -0
  6. package/coverage/coverage-summary.json +85 -0
  7. package/coverage/html/backend/index.html +116 -0
  8. package/coverage/html/backend/rslib.config.ts.html +415 -0
  9. package/coverage/html/backend/src/contracts/consent/index.html +161 -0
  10. package/coverage/html/backend/src/contracts/consent/index.ts.html +112 -0
  11. package/coverage/html/backend/src/contracts/consent/post.contract.ts.html +559 -0
  12. package/coverage/html/backend/src/contracts/consent/show-banner.contract.ts.html +220 -0
  13. package/coverage/html/backend/src/contracts/consent/verify.contract.ts.html +463 -0
  14. package/coverage/html/backend/src/contracts/index.html +116 -0
  15. package/coverage/html/backend/src/contracts/index.ts.html +139 -0
  16. package/coverage/html/backend/src/contracts/meta/index.html +131 -0
  17. package/coverage/html/backend/src/contracts/meta/index.ts.html +100 -0
  18. package/coverage/html/backend/src/contracts/meta/status.contract.ts.html +196 -0
  19. package/coverage/html/backend/src/contracts/shared/index.html +116 -0
  20. package/coverage/html/backend/src/contracts/shared/jurisdiction.schema.ts.html +175 -0
  21. package/coverage/html/backend/src/core.ts.html +1624 -0
  22. package/coverage/html/backend/src/handlers/consent/index.html +161 -0
  23. package/coverage/html/backend/src/handlers/consent/index.ts.html +112 -0
  24. package/coverage/html/backend/src/handlers/consent/post.handler.ts.html +889 -0
  25. package/coverage/html/backend/src/handlers/consent/show-banner.handler.ts.html +535 -0
  26. package/coverage/html/backend/src/handlers/consent/verify.handler.ts.html +1000 -0
  27. package/coverage/html/backend/src/handlers/meta/index.html +131 -0
  28. package/coverage/html/backend/src/handlers/meta/index.ts.html +100 -0
  29. package/coverage/html/backend/src/handlers/meta/status.handler.ts.html +226 -0
  30. package/coverage/html/backend/src/index.html +161 -0
  31. package/coverage/html/backend/src/init.ts.html +1018 -0
  32. package/coverage/html/backend/src/pkgs/api-router/hooks/index.html +116 -0
  33. package/coverage/html/backend/src/pkgs/api-router/hooks/processor.ts.html +544 -0
  34. package/coverage/html/backend/src/pkgs/api-router/index.html +116 -0
  35. package/coverage/html/backend/src/pkgs/api-router/telemetry.ts.html +334 -0
  36. package/coverage/html/backend/src/pkgs/api-router/utils/cors.ts.html +304 -0
  37. package/coverage/html/backend/src/pkgs/api-router/utils/index.html +131 -0
  38. package/coverage/html/backend/src/pkgs/api-router/utils/ip.ts.html +361 -0
  39. package/coverage/html/backend/src/pkgs/data-model/fields/field-factory.ts.html +709 -0
  40. package/coverage/html/backend/src/pkgs/data-model/fields/id-generator.ts.html +256 -0
  41. package/coverage/html/backend/src/pkgs/data-model/fields/index.html +161 -0
  42. package/coverage/html/backend/src/pkgs/data-model/fields/superjson-utils.ts.html +136 -0
  43. package/coverage/html/backend/src/pkgs/data-model/fields/zod-fields.ts.html +496 -0
  44. package/coverage/html/backend/src/pkgs/data-model/hooks/create-hooks.ts.html +349 -0
  45. package/coverage/html/backend/src/pkgs/data-model/hooks/index.html +176 -0
  46. package/coverage/html/backend/src/pkgs/data-model/hooks/update-hooks.ts.html +358 -0
  47. package/coverage/html/backend/src/pkgs/data-model/hooks/update-many-hooks.ts.html +613 -0
  48. package/coverage/html/backend/src/pkgs/data-model/hooks/utils.ts.html +538 -0
  49. package/coverage/html/backend/src/pkgs/data-model/hooks/with-hooks-factory.ts.html +289 -0
  50. package/coverage/html/backend/src/pkgs/db-adapters/adapter-factory.ts.html +289 -0
  51. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts.html +2203 -0
  52. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/index.html +116 -0
  53. package/coverage/html/backend/src/pkgs/db-adapters/adapters/index.html +116 -0
  54. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/dialect.ts.html +670 -0
  55. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/index.html +131 -0
  56. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts.html +3634 -0
  57. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/index.html +116 -0
  58. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts.html +1417 -0
  59. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/index.html +116 -0
  60. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts.html +2071 -0
  61. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/index.html +116 -0
  62. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts.html +1834 -0
  63. package/coverage/html/backend/src/pkgs/db-adapters/adapters/test.ts.html +316 -0
  64. package/coverage/html/backend/src/pkgs/db-adapters/index.html +131 -0
  65. package/coverage/html/backend/src/pkgs/db-adapters/utils.ts.html +238 -0
  66. package/coverage/html/backend/src/pkgs/migrations/get-migration.ts.html +343 -0
  67. package/coverage/html/backend/src/pkgs/migrations/get-schema/get-schema.ts.html +217 -0
  68. package/coverage/html/backend/src/pkgs/migrations/get-schema/index.html +146 -0
  69. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-fields.ts.html +280 -0
  70. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-tables.ts.html +289 -0
  71. package/coverage/html/backend/src/pkgs/migrations/index.html +176 -0
  72. package/coverage/html/backend/src/pkgs/migrations/migration-builders.ts.html +595 -0
  73. package/coverage/html/backend/src/pkgs/migrations/migration-execution.ts.html +301 -0
  74. package/coverage/html/backend/src/pkgs/migrations/schema-comparison.ts.html +694 -0
  75. package/coverage/html/backend/src/pkgs/migrations/type-mapping.ts.html +817 -0
  76. package/coverage/html/backend/src/pkgs/results/core/error-class.ts.html +976 -0
  77. package/coverage/html/backend/src/pkgs/results/core/error-codes.ts.html +703 -0
  78. package/coverage/html/backend/src/pkgs/results/core/index.html +146 -0
  79. package/coverage/html/backend/src/pkgs/results/core/tracing.ts.html +280 -0
  80. package/coverage/html/backend/src/pkgs/results/create-telemetry-options.ts.html +271 -0
  81. package/coverage/html/backend/src/pkgs/results/index.html +131 -0
  82. package/coverage/html/backend/src/pkgs/results/orpc-error-handler.ts.html +496 -0
  83. package/coverage/html/backend/src/pkgs/results/results/index.html +131 -0
  84. package/coverage/html/backend/src/pkgs/results/results/recovery-utils.ts.html +628 -0
  85. package/coverage/html/backend/src/pkgs/results/results/result-helpers.ts.html +1234 -0
  86. package/coverage/html/backend/src/pkgs/utils/env.ts.html +337 -0
  87. package/coverage/html/backend/src/pkgs/utils/index.html +146 -0
  88. package/coverage/html/backend/src/pkgs/utils/logger.ts.html +199 -0
  89. package/coverage/html/backend/src/pkgs/utils/url.ts.html +400 -0
  90. package/coverage/html/backend/src/router.ts.html +109 -0
  91. package/coverage/html/backend/src/schema/audit-log/index.html +146 -0
  92. package/coverage/html/backend/src/schema/audit-log/registry.ts.html +436 -0
  93. package/coverage/html/backend/src/schema/audit-log/schema.ts.html +223 -0
  94. package/coverage/html/backend/src/schema/audit-log/table.ts.html +640 -0
  95. package/coverage/html/backend/src/schema/consent/index.html +146 -0
  96. package/coverage/html/backend/src/schema/consent/registry.ts.html +616 -0
  97. package/coverage/html/backend/src/schema/consent/schema.ts.html +238 -0
  98. package/coverage/html/backend/src/schema/consent/table.ts.html +748 -0
  99. package/coverage/html/backend/src/schema/consent-policy/index.html +146 -0
  100. package/coverage/html/backend/src/schema/consent-policy/registry.ts.html +1063 -0
  101. package/coverage/html/backend/src/schema/consent-policy/schema.ts.html +265 -0
  102. package/coverage/html/backend/src/schema/consent-policy/table.ts.html +535 -0
  103. package/coverage/html/backend/src/schema/consent-purpose/index.html +146 -0
  104. package/coverage/html/backend/src/schema/consent-purpose/registry.ts.html +589 -0
  105. package/coverage/html/backend/src/schema/consent-purpose/schema.ts.html +259 -0
  106. package/coverage/html/backend/src/schema/consent-purpose/table.ts.html +547 -0
  107. package/coverage/html/backend/src/schema/consent-record/index.html +131 -0
  108. package/coverage/html/backend/src/schema/consent-record/schema.ts.html +211 -0
  109. package/coverage/html/backend/src/schema/consent-record/table.ts.html +457 -0
  110. package/coverage/html/backend/src/schema/create-registry.ts.html +148 -0
  111. package/coverage/html/backend/src/schema/definition.ts.html +685 -0
  112. package/coverage/html/backend/src/schema/domain/index.html +146 -0
  113. package/coverage/html/backend/src/schema/domain/registry.ts.html +973 -0
  114. package/coverage/html/backend/src/schema/domain/schema.ts.html +214 -0
  115. package/coverage/html/backend/src/schema/domain/table.ts.html +496 -0
  116. package/coverage/html/backend/src/schema/index.html +146 -0
  117. package/coverage/html/backend/src/schema/schemas.ts.html +166 -0
  118. package/coverage/html/backend/src/schema/subject/index.html +146 -0
  119. package/coverage/html/backend/src/schema/subject/registry.ts.html +973 -0
  120. package/coverage/html/backend/src/schema/subject/schema.ts.html +208 -0
  121. package/coverage/html/backend/src/schema/subject/table.ts.html +499 -0
  122. package/coverage/html/backend/src/server.ts.html +475 -0
  123. package/coverage/html/backend/src/testing/contract-testing.ts.html +1348 -0
  124. package/coverage/html/backend/src/testing/index.html +116 -0
  125. package/coverage/html/base.css +224 -0
  126. package/coverage/html/block-navigation.js +87 -0
  127. package/coverage/html/favicon.png +0 -0
  128. package/coverage/html/index.html +626 -0
  129. package/coverage/html/prettify.css +1 -0
  130. package/coverage/html/prettify.js +2 -0
  131. package/coverage/html/sort-arrow-sprite.png +0 -0
  132. package/coverage/html/sorter.js +196 -0
  133. package/dist/contracts/consent/index.d.ts +401 -0
  134. package/dist/contracts/consent/index.d.ts.map +1 -0
  135. package/dist/contracts/consent/index.test.d.ts +2 -0
  136. package/dist/contracts/consent/index.test.d.ts.map +1 -0
  137. package/dist/contracts/consent/post.contract.d.ts +212 -0
  138. package/dist/contracts/consent/post.contract.d.ts.map +1 -0
  139. package/dist/contracts/consent/post.contract.test.d.ts +2 -0
  140. package/dist/contracts/consent/post.contract.test.d.ts.map +1 -0
  141. package/dist/contracts/consent/show-banner.contract.d.ts +45 -0
  142. package/dist/contracts/consent/show-banner.contract.d.ts.map +1 -0
  143. package/dist/contracts/consent/show-banner.contract.test.d.ts +2 -0
  144. package/dist/contracts/consent/show-banner.contract.test.d.ts.map +1 -0
  145. package/dist/contracts/consent/verify.contract.d.ts +147 -0
  146. package/dist/contracts/consent/verify.contract.d.ts.map +1 -0
  147. package/dist/contracts/consent/verify.contract.test.d.ts +2 -0
  148. package/dist/contracts/consent/verify.contract.test.d.ts.map +1 -0
  149. package/dist/contracts/index.d.ts +963 -0
  150. package/dist/contracts/index.d.ts.map +1 -0
  151. package/dist/contracts/meta/index.d.ts +78 -0
  152. package/dist/contracts/meta/index.d.ts.map +1 -0
  153. package/dist/contracts/meta/index.test.d.ts +2 -0
  154. package/dist/contracts/meta/index.test.d.ts.map +1 -0
  155. package/dist/contracts/meta/status.contract.d.ts +77 -0
  156. package/dist/contracts/meta/status.contract.d.ts.map +1 -0
  157. package/dist/contracts/meta/status.contract.test.d.ts +2 -0
  158. package/dist/contracts/meta/status.contract.test.d.ts.map +1 -0
  159. package/dist/contracts/shared/jurisdiction.schema.d.ts +24 -0
  160. package/dist/contracts/shared/jurisdiction.schema.d.ts.map +1 -0
  161. package/dist/core.cjs +3584 -0
  162. package/dist/core.d.ts +533 -78
  163. package/dist/core.d.ts.map +1 -1
  164. package/dist/{index.js → core.js} +1164 -1292
  165. package/dist/handlers/consent/index.d.ts +401 -0
  166. package/dist/handlers/consent/index.d.ts.map +1 -0
  167. package/dist/handlers/consent/post.handler.d.ts +234 -0
  168. package/dist/handlers/consent/post.handler.d.ts.map +1 -0
  169. package/dist/handlers/consent/show-banner.handler.d.ts +57 -0
  170. package/dist/handlers/consent/show-banner.handler.d.ts.map +1 -0
  171. package/dist/handlers/consent/show-banner.handler.test.d.ts +2 -0
  172. package/dist/handlers/consent/show-banner.handler.test.d.ts.map +1 -0
  173. package/dist/handlers/consent/verify.handler.d.ts +169 -0
  174. package/dist/handlers/consent/verify.handler.d.ts.map +1 -0
  175. package/dist/handlers/meta/index.d.ts +78 -0
  176. package/dist/handlers/meta/index.d.ts.map +1 -0
  177. package/dist/handlers/meta/status.handler.d.ts +76 -0
  178. package/dist/handlers/meta/status.handler.d.ts.map +1 -0
  179. package/dist/init.d.ts +0 -1
  180. package/dist/init.d.ts.map +1 -1
  181. package/dist/pkgs/api-router/hooks/processor.d.ts.map +1 -1
  182. package/dist/pkgs/api-router/types/router-props.d.ts +1 -1
  183. package/dist/pkgs/api-router/types/router-props.d.ts.map +1 -1
  184. package/dist/pkgs/api-router/utils/cors.d.ts +1 -1
  185. package/dist/pkgs/api-router/utils/cors.d.ts.map +1 -1
  186. package/dist/pkgs/data-model/fields/field-types.d.ts +1 -1
  187. package/dist/pkgs/data-model/fields/zod-fields.d.ts +32 -32
  188. package/dist/pkgs/data-model/index.cjs +1433 -1799
  189. package/dist/pkgs/data-model/index.js +20 -385
  190. package/dist/pkgs/data-model/schema/index.cjs +1402 -1768
  191. package/dist/pkgs/data-model/schema/index.js +20 -385
  192. package/dist/pkgs/db-adapters/adapter-factory.d.ts +2 -2
  193. package/dist/pkgs/db-adapters/adapter-factory.d.ts.map +1 -1
  194. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts +4 -7
  195. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts.map +1 -1
  196. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.cjs +19 -151
  197. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.js +19 -151
  198. package/dist/pkgs/db-adapters/adapters/kysely-adapter/dialect.d.ts +1 -3
  199. package/dist/pkgs/db-adapters/adapters/kysely-adapter/dialect.d.ts.map +1 -1
  200. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.cjs +17 -149
  201. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.js +17 -149
  202. package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts +0 -1
  203. package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts.map +1 -1
  204. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts +2 -2
  205. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts.map +1 -1
  206. package/dist/pkgs/db-adapters/adapters/kysely-adapter/types.d.ts +0 -2
  207. package/dist/pkgs/db-adapters/adapters/kysely-adapter/types.d.ts.map +1 -1
  208. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.cjs +17 -149
  209. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.js +17 -149
  210. package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts +0 -1
  211. package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts.map +1 -1
  212. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.cjs +19 -151
  213. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.js +19 -151
  214. package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts +0 -1
  215. package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts.map +1 -1
  216. package/dist/pkgs/db-adapters/index.cjs +31 -153
  217. package/dist/pkgs/db-adapters/index.js +31 -153
  218. package/dist/pkgs/migrations/get-schema/get-schema.d.ts +2 -2
  219. package/dist/pkgs/migrations/get-schema/index.d.ts +1 -1
  220. package/dist/pkgs/migrations/index.cjs +30 -153
  221. package/dist/pkgs/migrations/index.js +30 -153
  222. package/dist/pkgs/migrations/schema-comparison.d.ts.map +1 -1
  223. package/dist/pkgs/results/core/error-class.d.ts +23 -21
  224. package/dist/pkgs/results/core/error-class.d.ts.map +1 -1
  225. package/dist/pkgs/results/index.cjs +17 -150
  226. package/dist/pkgs/results/index.d.ts +0 -3
  227. package/dist/pkgs/results/index.d.ts.map +1 -1
  228. package/dist/pkgs/results/index.js +17 -138
  229. package/dist/pkgs/results/orpc-error-handler.d.ts +65 -0
  230. package/dist/pkgs/results/orpc-error-handler.d.ts.map +1 -0
  231. package/dist/pkgs/results/types.d.ts +7 -7
  232. package/dist/pkgs/results/types.d.ts.map +1 -1
  233. package/dist/pkgs/types/context.d.ts +15 -8
  234. package/dist/pkgs/types/context.d.ts.map +1 -1
  235. package/dist/pkgs/types/endpoints.d.ts +3 -4
  236. package/dist/pkgs/types/endpoints.d.ts.map +1 -1
  237. package/dist/pkgs/types/options.d.ts +2 -4
  238. package/dist/pkgs/types/options.d.ts.map +1 -1
  239. package/dist/pkgs/types/plugins.d.ts +2 -3
  240. package/dist/pkgs/types/plugins.d.ts.map +1 -1
  241. package/dist/pkgs/utils/index.d.ts +1 -0
  242. package/dist/pkgs/utils/index.d.ts.map +1 -1
  243. package/dist/pkgs/utils/logger.d.ts +16 -0
  244. package/dist/pkgs/utils/logger.d.ts.map +1 -0
  245. package/dist/router.cjs +1213 -0
  246. package/dist/router.d.ts +480 -0
  247. package/dist/router.d.ts.map +1 -0
  248. package/dist/router.js +1169 -0
  249. package/dist/schema/audit-log/table.d.ts +1 -1
  250. package/dist/schema/consent/table.d.ts +1 -1
  251. package/dist/schema/consent-policy/registry.d.ts +12 -12
  252. package/dist/schema/consent-policy/schema.d.ts +6 -6
  253. package/dist/schema/consent-policy/table.d.ts +7 -7
  254. package/dist/schema/consent-purpose/registry.d.ts +6 -6
  255. package/dist/schema/consent-purpose/schema.d.ts +6 -6
  256. package/dist/schema/consent-purpose/table.d.ts +7 -7
  257. package/dist/schema/consent-record/table.d.ts +1 -1
  258. package/dist/schema/create-registry.d.ts +32 -32
  259. package/dist/schema/definition.d.ts +19 -19
  260. package/dist/schema/domain/registry.d.ts +10 -10
  261. package/dist/schema/domain/schema.d.ts +5 -5
  262. package/dist/schema/domain/table.d.ts +6 -6
  263. package/dist/schema/index.cjs +1409 -1775
  264. package/dist/schema/index.js +20 -385
  265. package/dist/schema/schemas.d.ts +19 -19
  266. package/dist/schema/subject/registry.d.ts +4 -4
  267. package/dist/schema/subject/schema.d.ts +2 -2
  268. package/dist/schema/subject/table.d.ts +3 -3
  269. package/dist/server.d.ts +2 -0
  270. package/dist/server.d.ts.map +1 -0
  271. package/dist/testing/contract-testing.d.ts +37 -0
  272. package/dist/testing/contract-testing.d.ts.map +1 -0
  273. package/dist/types/context.d.ts +1 -1
  274. package/dist/types/index.d.ts +2 -2
  275. package/dist/types/options.d.ts +33 -3
  276. package/dist/types/options.d.ts.map +1 -1
  277. package/dist/types/plugins.d.ts +3 -4
  278. package/dist/types/plugins.d.ts.map +1 -1
  279. package/package.json +20 -28
  280. package/rslib.config.ts +2 -5
  281. package/src/contracts/consent/index.test.ts +5 -0
  282. package/src/contracts/consent/index.ts +9 -0
  283. package/src/contracts/consent/post.contract.test.ts +526 -0
  284. package/src/contracts/consent/post.contract.ts +160 -0
  285. package/src/contracts/consent/show-banner.contract.test.ts +214 -0
  286. package/src/contracts/consent/show-banner.contract.ts +45 -0
  287. package/src/contracts/consent/verify.contract.test.ts +185 -0
  288. package/src/contracts/consent/verify.contract.ts +126 -0
  289. package/src/contracts/index.ts +18 -0
  290. package/src/contracts/meta/index.test.ts +5 -0
  291. package/src/contracts/meta/index.ts +5 -0
  292. package/src/contracts/meta/status.contract.test.ts +338 -0
  293. package/src/contracts/meta/status.contract.ts +37 -0
  294. package/src/contracts/shared/jurisdiction.schema.ts +30 -0
  295. package/src/core.ts +451 -161
  296. package/src/handlers/consent/index.ts +9 -0
  297. package/src/handlers/consent/post.handler.ts +273 -0
  298. package/src/handlers/consent/show-banner.handler.test.ts +148 -0
  299. package/src/handlers/consent/show-banner.handler.ts +150 -0
  300. package/src/handlers/consent/verify.handler.ts +305 -0
  301. package/src/handlers/meta/index.ts +5 -0
  302. package/src/handlers/meta/status.handler.ts +47 -0
  303. package/src/init.ts +8 -26
  304. package/src/pkgs/api-router/hooks/__tests__/processor.test.ts +6 -0
  305. package/src/pkgs/api-router/hooks/processor.ts +2 -0
  306. package/src/pkgs/api-router/types/router-props.ts +1 -1
  307. package/src/pkgs/api-router/utils/cors.ts +1 -1
  308. package/src/pkgs/data-model/fields/field-types.ts +1 -1
  309. package/src/pkgs/data-model/fields/id-generator.ts +1 -1
  310. package/src/pkgs/db-adapters/README.md +3 -3
  311. package/src/pkgs/db-adapters/adapter-factory.ts +8 -4
  312. package/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts +13 -16
  313. package/src/pkgs/db-adapters/adapters/kysely-adapter/dialect.ts +1 -3
  314. package/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts +0 -1
  315. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/postgres.test.ts +1 -1
  316. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/sqlite.test.ts +1 -1
  317. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts +2 -2
  318. package/src/pkgs/db-adapters/adapters/kysely-adapter/types.ts +0 -2
  319. package/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts +0 -1
  320. package/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts +0 -1
  321. package/src/pkgs/migrations/get-migration.ts +3 -3
  322. package/src/pkgs/migrations/get-schema/get-schema.ts +2 -2
  323. package/src/pkgs/migrations/get-schema/index.ts +1 -1
  324. package/src/pkgs/migrations/migration-builders.ts +2 -2
  325. package/src/pkgs/migrations/migration-execution.ts +2 -2
  326. package/src/pkgs/migrations/schema-comparison.ts +5 -4
  327. package/src/pkgs/results/__tests__/error-class.test.ts +8 -7
  328. package/src/pkgs/results/core/error-class.ts +31 -43
  329. package/src/pkgs/results/index.ts +0 -10
  330. package/src/pkgs/results/orpc-error-handler.ts +137 -0
  331. package/src/pkgs/results/types.ts +8 -7
  332. package/src/pkgs/types/context.ts +18 -9
  333. package/src/pkgs/types/endpoints.ts +3 -5
  334. package/src/pkgs/types/options.ts +2 -4
  335. package/src/pkgs/types/plugins.ts +2 -3
  336. package/src/pkgs/utils/index.ts +1 -0
  337. package/src/pkgs/utils/logger.ts +38 -0
  338. package/src/router.ts +8 -0
  339. package/src/schema/audit-log/table.ts +1 -1
  340. package/src/schema/consent/table.ts +1 -1
  341. package/src/schema/consent-policy/table.ts +1 -1
  342. package/src/schema/consent-purpose/table.ts +1 -1
  343. package/src/schema/consent-record/table.ts +1 -1
  344. package/src/schema/definition.ts +2 -2
  345. package/src/schema/domain/table.ts +1 -1
  346. package/src/schema/subject/table.ts +1 -1
  347. package/src/server.ts +130 -0
  348. package/src/testing/contract-testing.ts +437 -0
  349. package/src/types/context.ts +1 -1
  350. package/src/types/index.ts +2 -2
  351. package/src/types/options.ts +38 -3
  352. package/src/types/plugins.ts +3 -4
  353. package/dist/index.cjs +0 -3706
  354. package/dist/index.d.ts +0 -11
  355. package/dist/index.d.ts.map +0 -1
  356. package/dist/init.test.d.ts +0 -2
  357. package/dist/init.test.d.ts.map +0 -1
  358. package/dist/integrations/cloudflare.cjs +0 -312
  359. package/dist/integrations/cloudflare.d.ts +0 -32
  360. package/dist/integrations/cloudflare.d.ts.map +0 -1
  361. package/dist/integrations/cloudflare.js +0 -278
  362. package/dist/integrations/next.cjs +0 -276
  363. package/dist/integrations/next.d.ts +0 -68
  364. package/dist/integrations/next.d.ts.map +0 -1
  365. package/dist/integrations/next.js +0 -239
  366. package/dist/integrations/node.cjs +0 -257
  367. package/dist/integrations/node.d.ts +0 -29
  368. package/dist/integrations/node.d.ts.map +0 -1
  369. package/dist/integrations/node.js +0 -223
  370. package/dist/pkgs/api-router/index.d.ts +0 -9
  371. package/dist/pkgs/api-router/index.d.ts.map +0 -1
  372. package/dist/pkgs/api-router/utils/define-route.d.ts +0 -87
  373. package/dist/pkgs/api-router/utils/define-route.d.ts.map +0 -1
  374. package/dist/pkgs/logger/__tests__/console-formatter.test.d.ts +0 -2
  375. package/dist/pkgs/logger/__tests__/console-formatter.test.d.ts.map +0 -1
  376. package/dist/pkgs/logger/__tests__/integration.test.d.ts +0 -2
  377. package/dist/pkgs/logger/__tests__/integration.test.d.ts.map +0 -1
  378. package/dist/pkgs/logger/__tests__/log-levels.test.d.ts +0 -2
  379. package/dist/pkgs/logger/__tests__/log-levels.test.d.ts.map +0 -1
  380. package/dist/pkgs/logger/__tests__/logger-factory.test.d.ts +0 -2
  381. package/dist/pkgs/logger/__tests__/logger-factory.test.d.ts.map +0 -1
  382. package/dist/pkgs/logger/__tests__/result-logging.test.d.ts +0 -2
  383. package/dist/pkgs/logger/__tests__/result-logging.test.d.ts.map +0 -1
  384. package/dist/pkgs/logger/__tests__/types.test.d.ts +0 -2
  385. package/dist/pkgs/logger/__tests__/types.test.d.ts.map +0 -1
  386. package/dist/pkgs/logger/console-formatter.d.ts +0 -56
  387. package/dist/pkgs/logger/console-formatter.d.ts.map +0 -1
  388. package/dist/pkgs/logger/index.cjs +0 -240
  389. package/dist/pkgs/logger/index.d.ts +0 -35
  390. package/dist/pkgs/logger/index.d.ts.map +0 -1
  391. package/dist/pkgs/logger/index.js +0 -185
  392. package/dist/pkgs/logger/log-levels.d.ts +0 -29
  393. package/dist/pkgs/logger/log-levels.d.ts.map +0 -1
  394. package/dist/pkgs/logger/logger-factory.d.ts +0 -42
  395. package/dist/pkgs/logger/logger-factory.d.ts.map +0 -1
  396. package/dist/pkgs/logger/result-logging.d.ts +0 -71
  397. package/dist/pkgs/logger/result-logging.d.ts.map +0 -1
  398. package/dist/pkgs/logger/telemetry.d.ts +0 -14
  399. package/dist/pkgs/logger/telemetry.d.ts.map +0 -1
  400. package/dist/pkgs/logger/types.d.ts +0 -121
  401. package/dist/pkgs/logger/types.d.ts.map +0 -1
  402. package/dist/pkgs/results/__tests__/retrieval-pipeline.test.d.ts +0 -2
  403. package/dist/pkgs/results/__tests__/retrieval-pipeline.test.d.ts.map +0 -1
  404. package/dist/pkgs/results/__tests__/validation-pipeline.test.d.ts +0 -2
  405. package/dist/pkgs/results/__tests__/validation-pipeline.test.d.ts.map +0 -1
  406. package/dist/pkgs/results/h3-integration.d.ts +0 -52
  407. package/dist/pkgs/results/h3-integration.d.ts.map +0 -1
  408. package/dist/pkgs/results/pipeline/retrieval-pipeline.d.ts +0 -101
  409. package/dist/pkgs/results/pipeline/retrieval-pipeline.d.ts.map +0 -1
  410. package/dist/pkgs/results/pipeline/validation-pipeline.d.ts +0 -89
  411. package/dist/pkgs/results/pipeline/validation-pipeline.d.ts.map +0 -1
  412. package/dist/response-types.d.ts +0 -19
  413. package/dist/response-types.d.ts.map +0 -1
  414. package/dist/routes/__test__/index.test.d.ts +0 -17
  415. package/dist/routes/__test__/index.test.d.ts.map +0 -1
  416. package/dist/routes/__test__/set-consent.test.d.ts +0 -2
  417. package/dist/routes/__test__/set-consent.test.d.ts.map +0 -1
  418. package/dist/routes/__test__/show-consent-banner.test.d.ts +0 -2
  419. package/dist/routes/__test__/show-consent-banner.test.d.ts.map +0 -1
  420. package/dist/routes/__test__/status.test.d.ts +0 -2
  421. package/dist/routes/__test__/status.test.d.ts.map +0 -1
  422. package/dist/routes/__test__/verify-consent.test.d.ts +0 -2
  423. package/dist/routes/__test__/verify-consent.test.d.ts.map +0 -1
  424. package/dist/routes/index.d.ts +0 -3
  425. package/dist/routes/index.d.ts.map +0 -1
  426. package/dist/routes/set-consent.d.ts +0 -89
  427. package/dist/routes/set-consent.d.ts.map +0 -1
  428. package/dist/routes/show-consent-banner.d.ts +0 -15
  429. package/dist/routes/show-consent-banner.d.ts.map +0 -1
  430. package/dist/routes/status.d.ts +0 -44
  431. package/dist/routes/status.d.ts.map +0 -1
  432. package/dist/routes/types.d.ts +0 -7
  433. package/dist/routes/types.d.ts.map +0 -1
  434. package/dist/routes/verify-consent.d.ts +0 -38
  435. package/dist/routes/verify-consent.d.ts.map +0 -1
  436. package/src/docs/ADVANCED_JSON_HANDLING.md +0 -99
  437. package/src/docs/neverthrow.md +0 -171
  438. package/src/index.ts +0 -34
  439. package/src/init.test.ts +0 -236
  440. package/src/integrations/cloudflare.ts +0 -269
  441. package/src/integrations/next.ts +0 -204
  442. package/src/integrations/node.ts +0 -141
  443. package/src/pkgs/api-router/index.ts +0 -148
  444. package/src/pkgs/api-router/types/h3.d.ts +0 -42
  445. package/src/pkgs/api-router/utils/define-route.ts +0 -410
  446. package/src/pkgs/logger/README.md +0 -213
  447. package/src/pkgs/logger/__tests__/console-formatter.test.ts +0 -67
  448. package/src/pkgs/logger/__tests__/integration.test.ts +0 -184
  449. package/src/pkgs/logger/__tests__/log-levels.test.ts +0 -77
  450. package/src/pkgs/logger/__tests__/logger-factory.test.ts +0 -156
  451. package/src/pkgs/logger/__tests__/result-logging.test.ts +0 -209
  452. package/src/pkgs/logger/__tests__/types.test.ts +0 -94
  453. package/src/pkgs/logger/console-formatter.ts +0 -75
  454. package/src/pkgs/logger/doc.md +0 -569
  455. package/src/pkgs/logger/index.ts +0 -59
  456. package/src/pkgs/logger/log-levels.ts +0 -46
  457. package/src/pkgs/logger/logger-factory.ts +0 -121
  458. package/src/pkgs/logger/result-logging.ts +0 -134
  459. package/src/pkgs/logger/telemetry.ts +0 -96
  460. package/src/pkgs/logger/types.ts +0 -138
  461. package/src/pkgs/results/__tests__/retrieval-pipeline.test.ts +0 -157
  462. package/src/pkgs/results/__tests__/validation-pipeline.test.ts +0 -151
  463. package/src/pkgs/results/h3-integration.ts +0 -142
  464. package/src/pkgs/results/pipeline/retrieval-pipeline.ts +0 -188
  465. package/src/pkgs/results/pipeline/validation-pipeline.ts +0 -164
  466. package/src/plugins/.keep +0 -0
  467. package/src/response-types.ts +0 -29
  468. package/src/routes/__test__/index.test.ts +0 -112
  469. package/src/routes/__test__/set-consent.test.ts +0 -242
  470. package/src/routes/__test__/show-consent-banner.test.ts +0 -98
  471. package/src/routes/__test__/status.test.ts +0 -64
  472. package/src/routes/__test__/verify-consent.test.ts +0 -266
  473. package/src/routes/index.ts +0 -12
  474. package/src/routes/set-consent.ts +0 -249
  475. package/src/routes/show-consent-banner.ts +0 -131
  476. package/src/routes/status.ts +0 -61
  477. package/src/routes/types.ts +0 -7
  478. package/src/routes/verify-consent.ts +0 -206
@@ -0,0 +1,526 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { z } from 'zod';
3
+
4
+ import { PolicyTypeSchema } from '~/schema';
5
+ import { createContractTests } from '~/testing/contract-testing';
6
+
7
+ import { postConsentContract } from './post.contract';
8
+
9
+ // Create base tests for the contract using the utility
10
+ const tester = createContractTests('Post Consent', postConsentContract);
11
+
12
+ // Keep the detailed custom tests to maintain existing coverage
13
+ describe('Post Consent Contract Custom Tests', () => {
14
+ // Helper to access schemas consistently throughout tests
15
+ const schemas = {
16
+ input: postConsentContract['~orpc'].inputSchema,
17
+ output: postConsentContract['~orpc'].outputSchema,
18
+ };
19
+
20
+ // Helper functions for common test patterns
21
+ const validateInput = (input: unknown) => {
22
+ return schemas.input?.safeParse(input);
23
+ };
24
+
25
+ const validateOutput = (output: unknown) => {
26
+ return schemas.output?.safeParse(output);
27
+ };
28
+
29
+ describe('Schema Structure', () => {
30
+ it('input schema is a discriminated union based on type', () => {
31
+ // Using explicit type cast to avoid linter warnings
32
+ const schema = schemas.input as z.ZodDiscriminatedUnion<
33
+ string,
34
+ z.ZodObject<z.ZodRawShape>[]
35
+ >;
36
+ expect(schema._def.typeName).toBe('ZodDiscriminatedUnion');
37
+ expect(schema._def.discriminator).toBe('type');
38
+ });
39
+
40
+ it('supports all defined policy types', () => {
41
+ const policyTypes = PolicyTypeSchema.options;
42
+
43
+ for (const type of policyTypes) {
44
+ const input = {
45
+ type,
46
+ domain: 'example.com',
47
+ ...(type === 'cookie_banner' ? { preferences: { test: true } } : {}),
48
+ };
49
+
50
+ const result = validateInput(input);
51
+ expect(result?.success).toBe(true);
52
+ }
53
+ });
54
+ });
55
+
56
+ describe('Input Validation', () => {
57
+ describe('cookie_banner type', () => {
58
+ it('accepts valid input with preferences', () => {
59
+ const validInput = {
60
+ type: 'cookie_banner',
61
+ domain: 'example.com',
62
+ preferences: { analytics: true, marketing: false },
63
+ } as const;
64
+
65
+ const result = validateInput(validInput);
66
+ expect(result?.success).toBe(true);
67
+ });
68
+
69
+ it('rejects input without required preferences', () => {
70
+ const invalidInput = {
71
+ type: 'cookie_banner',
72
+ domain: 'example.com',
73
+ } as const;
74
+
75
+ const result = validateInput(invalidInput);
76
+ if (!result) {
77
+ throw new Error('Result is undefined');
78
+ }
79
+
80
+ expect(result.success).toBe(false);
81
+ if (!result.success) {
82
+ // Use optional chaining to safely access potentially undefined properties
83
+ expect(result.error.issues?.[0]?.path).toContain('preferences');
84
+ }
85
+ });
86
+
87
+ it('verifies boolean values in preferences', () => {
88
+ const invalidPreferences = {
89
+ type: 'cookie_banner',
90
+ domain: 'example.com',
91
+ preferences: { analytics: 'yes' }, // Should be boolean
92
+ };
93
+
94
+ const result = validateInput(invalidPreferences);
95
+ if (!result) {
96
+ throw new Error('Result is undefined');
97
+ }
98
+
99
+ expect(result.success).toBe(false);
100
+ if (!result.success) {
101
+ expect(result.error.issues?.[0]?.path).toContain('preferences');
102
+ }
103
+ });
104
+ });
105
+
106
+ describe('policy-based types', () => {
107
+ it('validates privacy_policy input', () => {
108
+ const validInput = {
109
+ type: 'privacy_policy',
110
+ domain: 'example.com',
111
+ policyId: 'policy-123',
112
+ } as const;
113
+
114
+ const result = validateInput(validInput);
115
+ expect(result?.success).toBe(true);
116
+ });
117
+
118
+ it('validates dpa input', () => {
119
+ const validInput = {
120
+ type: 'dpa',
121
+ domain: 'example.com',
122
+ policyId: 'dpa-123',
123
+ };
124
+
125
+ const result = validateInput(validInput);
126
+ expect(result?.success).toBe(true);
127
+ });
128
+
129
+ it('validates terms_and_conditions input', () => {
130
+ const validInput = {
131
+ type: 'terms_and_conditions',
132
+ domain: 'example.com',
133
+ policyId: 'terms-123',
134
+ };
135
+
136
+ const result = validateInput(validInput);
137
+ expect(result?.success).toBe(true);
138
+ });
139
+
140
+ it('accepts optional preferences for policy-based consents', () => {
141
+ const validInput = {
142
+ type: 'privacy_policy',
143
+ domain: 'example.com',
144
+ policyId: 'policy-123',
145
+ preferences: { acceptAll: true, marketing: false },
146
+ };
147
+
148
+ const result = validateInput(validInput);
149
+ expect(result?.success).toBe(true);
150
+ });
151
+ });
152
+
153
+ describe('other consent types', () => {
154
+ it('validates marketing_communications input', () => {
155
+ const validInput = {
156
+ type: 'marketing_communications',
157
+ domain: 'example.com',
158
+ subjectId: 'user-123',
159
+ } as const;
160
+
161
+ const result = validateInput(validInput);
162
+ if (!result) {
163
+ throw new Error('Result is undefined');
164
+ }
165
+
166
+ expect(result.success).toBe(true);
167
+ });
168
+
169
+ it('validates age_verification input', () => {
170
+ const validInput = {
171
+ type: 'age_verification',
172
+ domain: 'example.com',
173
+ };
174
+
175
+ const result = validateInput(validInput);
176
+ expect(result?.success).toBe(true);
177
+ });
178
+
179
+ it('validates other type input', () => {
180
+ const validInput = {
181
+ type: 'other',
182
+ domain: 'example.com',
183
+ metadata: { customField: 'value' },
184
+ };
185
+
186
+ const result = validateInput(validInput);
187
+ expect(result?.success).toBe(true);
188
+ });
189
+ });
190
+
191
+ describe('common requirements', () => {
192
+ it('rejects input with invalid type', () => {
193
+ const invalidInput = {
194
+ // Type cast to bypass TS errors for testing
195
+ type: 'invalid_type' as unknown as z.infer<typeof PolicyTypeSchema>,
196
+ domain: 'example.com',
197
+ };
198
+
199
+ const result = validateInput(invalidInput);
200
+
201
+ if (!result) {
202
+ throw new Error('Result is undefined');
203
+ }
204
+
205
+ expect(result.success).toBe(false);
206
+ if (!result.success) {
207
+ expect(result.error.issues?.[0]?.path).toContain('type');
208
+ }
209
+ });
210
+
211
+ it('requires domain field', () => {
212
+ const invalidInput = {
213
+ type: 'marketing_communications' as z.infer<typeof PolicyTypeSchema>,
214
+ };
215
+
216
+ const result = validateInput(invalidInput);
217
+ if (!result) {
218
+ throw new Error('Result is undefined');
219
+ }
220
+
221
+ expect(result.success).toBe(false);
222
+ if (!result.success) {
223
+ expect(result.error.issues?.[0]?.path).toContain('domain');
224
+ }
225
+ });
226
+
227
+ it('accepts additional metadata', () => {
228
+ const validInput = {
229
+ type: 'marketing_communications',
230
+ domain: 'example.com',
231
+ metadata: {
232
+ source: 'web',
233
+ campaign: 'summer2023',
234
+ customData: { nested: true },
235
+ },
236
+ };
237
+
238
+ const result = validateInput(validInput);
239
+ expect(result?.success).toBe(true);
240
+ });
241
+
242
+ it('accepts optional subjectId', () => {
243
+ const validInput = {
244
+ type: 'privacy_policy',
245
+ domain: 'example.com',
246
+ subjectId: 'user-abc-123',
247
+ };
248
+
249
+ const result = validateInput(validInput);
250
+ expect(result?.success).toBe(true);
251
+ });
252
+
253
+ it('accepts optional externalSubjectId', () => {
254
+ const validInput = {
255
+ type: 'privacy_policy',
256
+ domain: 'example.com',
257
+ externalSubjectId: 'external-user-123',
258
+ };
259
+
260
+ const result = validateInput(validInput);
261
+ expect(result?.success).toBe(true);
262
+ });
263
+ });
264
+ });
265
+
266
+ describe('Output Validation', () => {
267
+ it('validates complete output object', () => {
268
+ const validOutput = {
269
+ id: '123',
270
+ domainId: '456',
271
+ domain: 'example.com',
272
+ type: 'marketing_communications',
273
+ status: 'granted',
274
+ recordId: '789',
275
+ givenAt: new Date(),
276
+ metadata: { source: 'web' },
277
+ } as const;
278
+
279
+ const result = validateOutput(validOutput);
280
+ if (!result) {
281
+ throw new Error('Result is undefined');
282
+ }
283
+
284
+ expect(result.success).toBe(true);
285
+ });
286
+
287
+ it('rejects output without required fields', () => {
288
+ const invalidOutput = {
289
+ id: '123',
290
+ domain: 'example.com',
291
+ type: 'marketing_communications',
292
+ // Missing required fields: domainId, status, recordId, givenAt
293
+ } as const;
294
+
295
+ const result = validateOutput(invalidOutput);
296
+ if (!result) {
297
+ throw new Error('Result is undefined');
298
+ }
299
+
300
+ expect(result.success).toBe(false);
301
+ });
302
+
303
+ it('validates output with all possible status values', () => {
304
+ const statusValues = ['granted', 'denied', 'pending', 'withdrawn'];
305
+
306
+ for (const status of statusValues) {
307
+ const output = {
308
+ id: '123',
309
+ domainId: '456',
310
+ domain: 'example.com',
311
+ type: 'marketing_communications',
312
+ status,
313
+ recordId: '789',
314
+ givenAt: new Date(),
315
+ };
316
+
317
+ const result = validateOutput(output);
318
+ expect(result?.success).toBe(true);
319
+ }
320
+ });
321
+
322
+ it('validates output with different policy types', () => {
323
+ const policyTypes = PolicyTypeSchema.options;
324
+
325
+ for (const type of policyTypes) {
326
+ const output = {
327
+ id: '123',
328
+ domainId: '456',
329
+ domain: 'example.com',
330
+ type,
331
+ status: 'granted',
332
+ recordId: '789',
333
+ givenAt: new Date(),
334
+ };
335
+
336
+ const result = validateOutput(output);
337
+ expect(result?.success).toBe(true);
338
+ }
339
+ });
340
+
341
+ describe('givenAt field', () => {
342
+ it('rejects string values', () => {
343
+ const invalidOutput = {
344
+ id: '123',
345
+ domainId: '456',
346
+ domain: 'example.com',
347
+ type: 'marketing_communications',
348
+ status: 'granted',
349
+ recordId: '789',
350
+ givenAt: 'not-a-date', // This should now fail with z.date()
351
+ metadata: {},
352
+ } as const;
353
+
354
+ const result = validateOutput(invalidOutput);
355
+ if (!result) {
356
+ throw new Error('Result is undefined');
357
+ }
358
+
359
+ expect(result.success).toBe(false);
360
+ });
361
+
362
+ it('accepts Date objects', () => {
363
+ const validOutput = {
364
+ id: '123',
365
+ domainId: '456',
366
+ domain: 'example.com',
367
+ type: 'marketing_communications',
368
+ status: 'granted',
369
+ recordId: '789',
370
+ givenAt: new Date(),
371
+ metadata: {},
372
+ };
373
+
374
+ const result = validateOutput(validOutput);
375
+ expect(result?.success).toBe(true);
376
+ });
377
+
378
+ it('rejects non-date values', () => {
379
+ const invalidOutput = {
380
+ id: '123',
381
+ domainId: '456',
382
+ domain: 'example.com',
383
+ type: 'marketing_communications',
384
+ status: 'granted',
385
+ recordId: '789',
386
+ givenAt: 123, // Number instead of Date
387
+ metadata: {},
388
+ };
389
+
390
+ const result = validateOutput(invalidOutput);
391
+ expect(result?.success).toBe(false);
392
+ });
393
+
394
+ it('accepts ISO date strings', () => {
395
+ const validOutput = {
396
+ id: '123',
397
+ domainId: '456',
398
+ domain: 'example.com',
399
+ type: 'marketing_communications',
400
+ status: 'granted',
401
+ recordId: '789',
402
+ givenAt: new Date(),
403
+ metadata: {},
404
+ };
405
+
406
+ const result = validateOutput(validOutput);
407
+ expect(result?.success).toBe(true);
408
+ });
409
+
410
+ it('rejects non-string values', () => {
411
+ // Create an object with a number for givenAt (should fail validation)
412
+ const invalidOutput = {
413
+ id: '123',
414
+ domainId: '456',
415
+ domain: 'example.com',
416
+ type: 'marketing_communications',
417
+ status: 'granted',
418
+ recordId: '789',
419
+ givenAt: 123, // Number instead of string (intentionally invalid)
420
+ metadata: {},
421
+ };
422
+
423
+ // We need to cast here because TypeScript wouldn't allow this invalid type normally
424
+ const result = validateOutput(invalidOutput);
425
+ if (!result) {
426
+ throw new Error('Result is undefined');
427
+ }
428
+
429
+ expect(result.success).toBe(false);
430
+ if (!result.success) {
431
+ expect(result.error.issues?.[0]?.path).toContain('givenAt');
432
+ }
433
+ });
434
+ });
435
+
436
+ describe('Optional fields validation', () => {
437
+ it('accepts output without optional fields', () => {
438
+ const validOutput = {
439
+ id: '123',
440
+ domainId: '456',
441
+ domain: 'example.com',
442
+ type: 'marketing_communications',
443
+ status: 'granted',
444
+ recordId: '789',
445
+ givenAt: new Date(),
446
+ // No metadata, subjectId or externalSubjectId
447
+ };
448
+
449
+ const result = validateOutput(validOutput);
450
+ expect(result?.success).toBe(true);
451
+ });
452
+
453
+ it('accepts output with optional subjectId', () => {
454
+ const validOutput = {
455
+ id: '123',
456
+ domainId: '456',
457
+ domain: 'example.com',
458
+ type: 'marketing_communications',
459
+ status: 'granted',
460
+ recordId: '789',
461
+ givenAt: new Date(),
462
+ subjectId: 'user-123',
463
+ };
464
+
465
+ const result = validateOutput(validOutput);
466
+ expect(result?.success).toBe(true);
467
+ });
468
+
469
+ it('accepts output with optional externalSubjectId', () => {
470
+ const validOutput = {
471
+ id: '123',
472
+ domainId: '456',
473
+ domain: 'example.com',
474
+ type: 'marketing_communications',
475
+ status: 'granted',
476
+ recordId: '789',
477
+ givenAt: new Date(),
478
+ externalSubjectId: 'external-user-123',
479
+ };
480
+
481
+ const result = validateOutput(validOutput);
482
+ expect(result?.success).toBe(true);
483
+ });
484
+
485
+ it('accepts output with complex metadata', () => {
486
+ const validOutput = {
487
+ id: '123',
488
+ domainId: '456',
489
+ domain: 'example.com',
490
+ type: 'marketing_communications',
491
+ status: 'granted',
492
+ recordId: '789',
493
+ givenAt: new Date(),
494
+ metadata: {
495
+ source: 'web',
496
+ platform: 'mobile',
497
+ browser: { name: 'Chrome', version: '115' },
498
+ consentMethod: 'explicit',
499
+ nestedData: {
500
+ level1: {
501
+ level2: {
502
+ level3: true,
503
+ },
504
+ },
505
+ },
506
+ },
507
+ };
508
+
509
+ const result = validateOutput(validOutput);
510
+ expect(result?.success).toBe(true);
511
+ });
512
+ });
513
+ });
514
+ });
515
+
516
+ // Add required fields testing using the utility
517
+ tester.testRequiredFields('input', ['domain', 'type']);
518
+ tester.testRequiredFields('output', [
519
+ 'id',
520
+ 'domainId',
521
+ 'domain',
522
+ 'type',
523
+ 'status',
524
+ 'recordId',
525
+ 'givenAt',
526
+ ]);
@@ -0,0 +1,160 @@
1
+ import { oc } from '@orpc/contract';
2
+ import { z } from 'zod';
3
+
4
+ import { PolicyTypeSchema } from '~/schema';
5
+
6
+ const baseConsentSchema = z.object({
7
+ subjectId: z.string().optional(),
8
+ externalSubjectId: z.string().optional(),
9
+ domain: z
10
+ .string()
11
+ .regex(
12
+ /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i,
13
+ 'invalid domain'
14
+ ),
15
+ type: PolicyTypeSchema,
16
+ metadata: z.record(z.unknown()).optional(),
17
+ });
18
+
19
+ // Cookie banner needs preferences
20
+ const cookieBannerSchema = baseConsentSchema.extend({
21
+ type: z.literal('cookie_banner'),
22
+ preferences: z.record(z.boolean()),
23
+ });
24
+
25
+ // Policy based consent just needs the policy ID
26
+ const policyBasedSchema = baseConsentSchema.extend({
27
+ type: z.enum(['privacy_policy', 'dpa', 'terms_and_conditions']),
28
+ policyId: z.string().optional(),
29
+ preferences: z.record(z.boolean()).optional(),
30
+ });
31
+
32
+ // Other consent types just need the base fields
33
+ const otherConsentSchema = baseConsentSchema.extend({
34
+ type: z.enum(['marketing_communications', 'age_verification', 'other']),
35
+ preferences: z.record(z.boolean()).optional(),
36
+ });
37
+
38
+ export const postConsentContract = oc
39
+ .route({
40
+ method: 'POST',
41
+ path: '/consent/set',
42
+ description: `Records a user's consent preferences and creates necessary consent records.
43
+ This endpoint handles various types of consent submissions:
44
+
45
+ 1. Cookie Banner Consent:
46
+ - Records granular cookie preferences
47
+ - Supports multiple consent purposes
48
+ - Creates audit trail for compliance
49
+
50
+ 2. Policy-Based Consent:
51
+ - Privacy Policy acceptance
52
+ - Data Processing Agreement (DPA) consent
53
+ - Terms and Conditions acceptance
54
+ - Links consent to specific policy versions
55
+
56
+ 3. Other Consent Types:
57
+ - Marketing communications preferences
58
+ - Age verification consent
59
+ - Custom consent types
60
+
61
+ The endpoint performs the following operations:
62
+ - Creates or retrieves subject records
63
+ - Validates domain and policy information
64
+ - Creates consent records with audit trails
65
+ - Records consent purposes and preferences
66
+ - Generates audit logs for compliance
67
+
68
+ Use this endpoint to record user consent and maintain a compliant consent management system.`,
69
+ tags: ['consent', 'cookie-banner'],
70
+ })
71
+ .errors({
72
+ // Input validation errors
73
+ INPUT_VALIDATION_FAILED: {
74
+ status: 422,
75
+ message: 'Invalid input parameters',
76
+ data: z.object({
77
+ formErrors: z.array(z.string()),
78
+ fieldErrors: z.record(z.string(), z.array(z.string())),
79
+ }),
80
+ },
81
+ // Subject errors
82
+ SUBJECT_CREATION_FAILED: {
83
+ status: 400,
84
+ message: 'Failed to create or find subject',
85
+ data: z.object({
86
+ subjectId: z.string().optional(),
87
+ externalSubjectId: z.string().optional(),
88
+ }),
89
+ },
90
+ // Domain errors
91
+ DOMAIN_CREATION_FAILED: {
92
+ status: 500,
93
+ message: 'Failed to create or find domain',
94
+ data: z.object({
95
+ domain: z.string(),
96
+ }),
97
+ },
98
+ // Policy errors
99
+ POLICY_NOT_FOUND: {
100
+ status: 404,
101
+ message: 'Policy not found',
102
+ data: z.object({
103
+ policyId: z.string(),
104
+ type: z.string(),
105
+ }),
106
+ },
107
+ POLICY_INACTIVE: {
108
+ status: 409,
109
+ message: 'Policy is not active',
110
+ data: z.object({
111
+ policyId: z.string(),
112
+ type: z.string(),
113
+ }),
114
+ },
115
+ POLICY_CREATION_FAILED: {
116
+ status: 500,
117
+ message: 'Failed to create or find policy',
118
+ data: z.object({
119
+ type: z.string(),
120
+ }),
121
+ },
122
+ // Purpose errors
123
+ PURPOSE_CREATION_FAILED: {
124
+ status: 500,
125
+ message: 'Failed to create consent purpose',
126
+ data: z.object({
127
+ purposeCode: z.string(),
128
+ }),
129
+ },
130
+ // Transaction errors
131
+ CONSENT_CREATION_FAILED: {
132
+ status: 500,
133
+ message: 'Failed to create consent record',
134
+ data: z.object({
135
+ subjectId: z.string(),
136
+ domain: z.string(),
137
+ }),
138
+ },
139
+ })
140
+ .input(
141
+ z.discriminatedUnion('type', [
142
+ cookieBannerSchema,
143
+ policyBasedSchema,
144
+ otherConsentSchema,
145
+ ])
146
+ )
147
+ .output(
148
+ z.object({
149
+ id: z.string(),
150
+ subjectId: z.string().optional(),
151
+ externalSubjectId: z.string().optional(),
152
+ domainId: z.string(),
153
+ domain: z.string(),
154
+ type: PolicyTypeSchema,
155
+ status: z.string(),
156
+ recordId: z.string(),
157
+ metadata: z.record(z.unknown()).optional(),
158
+ givenAt: z.date(),
159
+ })
160
+ );