@c15t/backend 1.0.5 → 1.2.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 (462) hide show
  1. package/.turbo/turbo-build.log +33 -39
  2. package/.turbo/turbo-fmt.log +3 -3
  3. package/.turbo/turbo-test.log +531 -0
  4. package/coverage/coverage-final.json +84 -0
  5. package/coverage/coverage-summary.json +85 -0
  6. package/coverage/html/backend/index.html +116 -0
  7. package/coverage/html/backend/rslib.config.ts.html +415 -0
  8. package/coverage/html/backend/src/contracts/consent/index.html +161 -0
  9. package/coverage/html/backend/src/contracts/consent/index.ts.html +112 -0
  10. package/coverage/html/backend/src/contracts/consent/post.contract.ts.html +559 -0
  11. package/coverage/html/backend/src/contracts/consent/show-banner.contract.ts.html +220 -0
  12. package/coverage/html/backend/src/contracts/consent/verify.contract.ts.html +463 -0
  13. package/coverage/html/backend/src/contracts/index.html +116 -0
  14. package/coverage/html/backend/src/contracts/index.ts.html +139 -0
  15. package/coverage/html/backend/src/contracts/meta/index.html +131 -0
  16. package/coverage/html/backend/src/contracts/meta/index.ts.html +100 -0
  17. package/coverage/html/backend/src/contracts/meta/status.contract.ts.html +196 -0
  18. package/coverage/html/backend/src/contracts/shared/index.html +116 -0
  19. package/coverage/html/backend/src/contracts/shared/jurisdiction.schema.ts.html +175 -0
  20. package/coverage/html/backend/src/core.ts.html +1624 -0
  21. package/coverage/html/backend/src/handlers/consent/index.html +161 -0
  22. package/coverage/html/backend/src/handlers/consent/index.ts.html +112 -0
  23. package/coverage/html/backend/src/handlers/consent/post.handler.ts.html +889 -0
  24. package/coverage/html/backend/src/handlers/consent/show-banner.handler.ts.html +535 -0
  25. package/coverage/html/backend/src/handlers/consent/verify.handler.ts.html +1000 -0
  26. package/coverage/html/backend/src/handlers/meta/index.html +131 -0
  27. package/coverage/html/backend/src/handlers/meta/index.ts.html +100 -0
  28. package/coverage/html/backend/src/handlers/meta/status.handler.ts.html +226 -0
  29. package/coverage/html/backend/src/index.html +161 -0
  30. package/coverage/html/backend/src/init.ts.html +1018 -0
  31. package/coverage/html/backend/src/pkgs/api-router/hooks/index.html +116 -0
  32. package/coverage/html/backend/src/pkgs/api-router/hooks/processor.ts.html +544 -0
  33. package/coverage/html/backend/src/pkgs/api-router/index.html +116 -0
  34. package/coverage/html/backend/src/pkgs/api-router/telemetry.ts.html +334 -0
  35. package/coverage/html/backend/src/pkgs/api-router/utils/cors.ts.html +304 -0
  36. package/coverage/html/backend/src/pkgs/api-router/utils/index.html +131 -0
  37. package/coverage/html/backend/src/pkgs/api-router/utils/ip.ts.html +361 -0
  38. package/coverage/html/backend/src/pkgs/data-model/fields/field-factory.ts.html +709 -0
  39. package/coverage/html/backend/src/pkgs/data-model/fields/id-generator.ts.html +256 -0
  40. package/coverage/html/backend/src/pkgs/data-model/fields/index.html +161 -0
  41. package/coverage/html/backend/src/pkgs/data-model/fields/superjson-utils.ts.html +136 -0
  42. package/coverage/html/backend/src/pkgs/data-model/fields/zod-fields.ts.html +496 -0
  43. package/coverage/html/backend/src/pkgs/data-model/hooks/create-hooks.ts.html +349 -0
  44. package/coverage/html/backend/src/pkgs/data-model/hooks/index.html +176 -0
  45. package/coverage/html/backend/src/pkgs/data-model/hooks/update-hooks.ts.html +358 -0
  46. package/coverage/html/backend/src/pkgs/data-model/hooks/update-many-hooks.ts.html +613 -0
  47. package/coverage/html/backend/src/pkgs/data-model/hooks/utils.ts.html +538 -0
  48. package/coverage/html/backend/src/pkgs/data-model/hooks/with-hooks-factory.ts.html +289 -0
  49. package/coverage/html/backend/src/pkgs/db-adapters/adapter-factory.ts.html +289 -0
  50. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts.html +2203 -0
  51. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/index.html +116 -0
  52. package/coverage/html/backend/src/pkgs/db-adapters/adapters/index.html +116 -0
  53. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/dialect.ts.html +670 -0
  54. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/index.html +131 -0
  55. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts.html +3634 -0
  56. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/index.html +116 -0
  57. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts.html +1417 -0
  58. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/index.html +116 -0
  59. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts.html +2071 -0
  60. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/index.html +116 -0
  61. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts.html +1834 -0
  62. package/coverage/html/backend/src/pkgs/db-adapters/adapters/test.ts.html +316 -0
  63. package/coverage/html/backend/src/pkgs/db-adapters/index.html +131 -0
  64. package/coverage/html/backend/src/pkgs/db-adapters/utils.ts.html +238 -0
  65. package/coverage/html/backend/src/pkgs/migrations/get-migration.ts.html +343 -0
  66. package/coverage/html/backend/src/pkgs/migrations/get-schema/get-schema.ts.html +217 -0
  67. package/coverage/html/backend/src/pkgs/migrations/get-schema/index.html +146 -0
  68. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-fields.ts.html +280 -0
  69. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-tables.ts.html +289 -0
  70. package/coverage/html/backend/src/pkgs/migrations/index.html +176 -0
  71. package/coverage/html/backend/src/pkgs/migrations/migration-builders.ts.html +595 -0
  72. package/coverage/html/backend/src/pkgs/migrations/migration-execution.ts.html +301 -0
  73. package/coverage/html/backend/src/pkgs/migrations/schema-comparison.ts.html +694 -0
  74. package/coverage/html/backend/src/pkgs/migrations/type-mapping.ts.html +817 -0
  75. package/coverage/html/backend/src/pkgs/results/core/error-class.ts.html +976 -0
  76. package/coverage/html/backend/src/pkgs/results/core/error-codes.ts.html +703 -0
  77. package/coverage/html/backend/src/pkgs/results/core/index.html +146 -0
  78. package/coverage/html/backend/src/pkgs/results/core/tracing.ts.html +280 -0
  79. package/coverage/html/backend/src/pkgs/results/create-telemetry-options.ts.html +271 -0
  80. package/coverage/html/backend/src/pkgs/results/index.html +131 -0
  81. package/coverage/html/backend/src/pkgs/results/orpc-error-handler.ts.html +496 -0
  82. package/coverage/html/backend/src/pkgs/results/results/index.html +131 -0
  83. package/coverage/html/backend/src/pkgs/results/results/recovery-utils.ts.html +628 -0
  84. package/coverage/html/backend/src/pkgs/results/results/result-helpers.ts.html +1234 -0
  85. package/coverage/html/backend/src/pkgs/utils/env.ts.html +337 -0
  86. package/coverage/html/backend/src/pkgs/utils/index.html +146 -0
  87. package/coverage/html/backend/src/pkgs/utils/logger.ts.html +199 -0
  88. package/coverage/html/backend/src/pkgs/utils/url.ts.html +400 -0
  89. package/coverage/html/backend/src/router.ts.html +109 -0
  90. package/coverage/html/backend/src/schema/audit-log/index.html +146 -0
  91. package/coverage/html/backend/src/schema/audit-log/registry.ts.html +436 -0
  92. package/coverage/html/backend/src/schema/audit-log/schema.ts.html +223 -0
  93. package/coverage/html/backend/src/schema/audit-log/table.ts.html +640 -0
  94. package/coverage/html/backend/src/schema/consent/index.html +146 -0
  95. package/coverage/html/backend/src/schema/consent/registry.ts.html +616 -0
  96. package/coverage/html/backend/src/schema/consent/schema.ts.html +238 -0
  97. package/coverage/html/backend/src/schema/consent/table.ts.html +748 -0
  98. package/coverage/html/backend/src/schema/consent-policy/index.html +146 -0
  99. package/coverage/html/backend/src/schema/consent-policy/registry.ts.html +1063 -0
  100. package/coverage/html/backend/src/schema/consent-policy/schema.ts.html +265 -0
  101. package/coverage/html/backend/src/schema/consent-policy/table.ts.html +535 -0
  102. package/coverage/html/backend/src/schema/consent-purpose/index.html +146 -0
  103. package/coverage/html/backend/src/schema/consent-purpose/registry.ts.html +589 -0
  104. package/coverage/html/backend/src/schema/consent-purpose/schema.ts.html +259 -0
  105. package/coverage/html/backend/src/schema/consent-purpose/table.ts.html +547 -0
  106. package/coverage/html/backend/src/schema/consent-record/index.html +131 -0
  107. package/coverage/html/backend/src/schema/consent-record/schema.ts.html +211 -0
  108. package/coverage/html/backend/src/schema/consent-record/table.ts.html +457 -0
  109. package/coverage/html/backend/src/schema/create-registry.ts.html +148 -0
  110. package/coverage/html/backend/src/schema/definition.ts.html +685 -0
  111. package/coverage/html/backend/src/schema/domain/index.html +146 -0
  112. package/coverage/html/backend/src/schema/domain/registry.ts.html +973 -0
  113. package/coverage/html/backend/src/schema/domain/schema.ts.html +214 -0
  114. package/coverage/html/backend/src/schema/domain/table.ts.html +496 -0
  115. package/coverage/html/backend/src/schema/index.html +146 -0
  116. package/coverage/html/backend/src/schema/schemas.ts.html +166 -0
  117. package/coverage/html/backend/src/schema/subject/index.html +146 -0
  118. package/coverage/html/backend/src/schema/subject/registry.ts.html +973 -0
  119. package/coverage/html/backend/src/schema/subject/schema.ts.html +208 -0
  120. package/coverage/html/backend/src/schema/subject/table.ts.html +499 -0
  121. package/coverage/html/backend/src/server.ts.html +475 -0
  122. package/coverage/html/backend/src/testing/contract-testing.ts.html +1348 -0
  123. package/coverage/html/backend/src/testing/index.html +116 -0
  124. package/coverage/html/base.css +224 -0
  125. package/coverage/html/block-navigation.js +87 -0
  126. package/coverage/html/favicon.png +0 -0
  127. package/coverage/html/index.html +626 -0
  128. package/coverage/html/prettify.css +1 -0
  129. package/coverage/html/prettify.js +2 -0
  130. package/coverage/html/sort-arrow-sprite.png +0 -0
  131. package/coverage/html/sorter.js +196 -0
  132. package/dist/contracts/consent/index.d.ts +401 -0
  133. package/dist/contracts/consent/index.d.ts.map +1 -0
  134. package/dist/contracts/consent/index.test.d.ts +2 -0
  135. package/dist/contracts/consent/index.test.d.ts.map +1 -0
  136. package/dist/contracts/consent/post.contract.d.ts +212 -0
  137. package/dist/contracts/consent/post.contract.d.ts.map +1 -0
  138. package/dist/contracts/consent/post.contract.test.d.ts +2 -0
  139. package/dist/contracts/consent/post.contract.test.d.ts.map +1 -0
  140. package/dist/contracts/consent/show-banner.contract.d.ts +45 -0
  141. package/dist/contracts/consent/show-banner.contract.d.ts.map +1 -0
  142. package/dist/contracts/consent/show-banner.contract.test.d.ts +2 -0
  143. package/dist/contracts/consent/show-banner.contract.test.d.ts.map +1 -0
  144. package/dist/contracts/consent/verify.contract.d.ts +147 -0
  145. package/dist/contracts/consent/verify.contract.d.ts.map +1 -0
  146. package/dist/contracts/consent/verify.contract.test.d.ts +2 -0
  147. package/dist/contracts/consent/verify.contract.test.d.ts.map +1 -0
  148. package/dist/contracts/index.d.ts +963 -0
  149. package/dist/contracts/index.d.ts.map +1 -0
  150. package/dist/contracts/meta/index.d.ts +78 -0
  151. package/dist/contracts/meta/index.d.ts.map +1 -0
  152. package/dist/contracts/meta/index.test.d.ts +2 -0
  153. package/dist/contracts/meta/index.test.d.ts.map +1 -0
  154. package/dist/contracts/meta/status.contract.d.ts +77 -0
  155. package/dist/contracts/meta/status.contract.d.ts.map +1 -0
  156. package/dist/contracts/meta/status.contract.test.d.ts +2 -0
  157. package/dist/contracts/meta/status.contract.test.d.ts.map +1 -0
  158. package/dist/contracts/shared/jurisdiction.schema.d.ts +24 -0
  159. package/dist/contracts/shared/jurisdiction.schema.d.ts.map +1 -0
  160. package/dist/core.cjs +3584 -0
  161. package/dist/core.d.ts +533 -76
  162. package/dist/core.d.ts.map +1 -1
  163. package/dist/{index.js → core.js} +1163 -1286
  164. package/dist/handlers/consent/index.d.ts +401 -0
  165. package/dist/handlers/consent/index.d.ts.map +1 -0
  166. package/dist/handlers/consent/post.handler.d.ts +234 -0
  167. package/dist/handlers/consent/post.handler.d.ts.map +1 -0
  168. package/dist/handlers/consent/show-banner.handler.d.ts +57 -0
  169. package/dist/handlers/consent/show-banner.handler.d.ts.map +1 -0
  170. package/dist/handlers/consent/show-banner.handler.test.d.ts +2 -0
  171. package/dist/handlers/consent/show-banner.handler.test.d.ts.map +1 -0
  172. package/dist/handlers/consent/verify.handler.d.ts +169 -0
  173. package/dist/handlers/consent/verify.handler.d.ts.map +1 -0
  174. package/dist/handlers/meta/index.d.ts +78 -0
  175. package/dist/handlers/meta/index.d.ts.map +1 -0
  176. package/dist/handlers/meta/status.handler.d.ts +76 -0
  177. package/dist/handlers/meta/status.handler.d.ts.map +1 -0
  178. package/dist/init.d.ts.map +1 -1
  179. package/dist/pkgs/api-router/hooks/processor.d.ts.map +1 -1
  180. package/dist/pkgs/api-router/types/router-props.d.ts +1 -1
  181. package/dist/pkgs/api-router/types/router-props.d.ts.map +1 -1
  182. package/dist/pkgs/api-router/utils/cors.d.ts +1 -1
  183. package/dist/pkgs/api-router/utils/cors.d.ts.map +1 -1
  184. package/dist/pkgs/data-model/fields/field-types.d.ts +1 -1
  185. package/dist/pkgs/data-model/fields/zod-fields.d.ts +32 -32
  186. package/dist/pkgs/data-model/index.cjs +1433 -1799
  187. package/dist/pkgs/data-model/index.js +20 -385
  188. package/dist/pkgs/data-model/schema/index.cjs +1402 -1768
  189. package/dist/pkgs/data-model/schema/index.js +20 -385
  190. package/dist/pkgs/db-adapters/adapter-factory.d.ts +2 -2
  191. package/dist/pkgs/db-adapters/adapter-factory.d.ts.map +1 -1
  192. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts +4 -4
  193. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.cjs +19 -151
  194. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.js +19 -151
  195. package/dist/pkgs/db-adapters/adapters/kysely-adapter/dialect.d.ts +1 -1
  196. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.cjs +17 -149
  197. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.js +17 -149
  198. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts +2 -2
  199. package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts.map +1 -1
  200. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.cjs +17 -149
  201. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.js +17 -149
  202. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.cjs +19 -151
  203. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.js +19 -151
  204. package/dist/pkgs/db-adapters/index.cjs +31 -153
  205. package/dist/pkgs/db-adapters/index.js +31 -153
  206. package/dist/pkgs/migrations/get-schema/get-schema.d.ts +2 -2
  207. package/dist/pkgs/migrations/get-schema/index.d.ts +1 -1
  208. package/dist/pkgs/migrations/index.cjs +30 -153
  209. package/dist/pkgs/migrations/index.js +30 -153
  210. package/dist/pkgs/migrations/schema-comparison.d.ts.map +1 -1
  211. package/dist/pkgs/results/core/error-class.d.ts +23 -21
  212. package/dist/pkgs/results/core/error-class.d.ts.map +1 -1
  213. package/dist/pkgs/results/index.cjs +17 -150
  214. package/dist/pkgs/results/index.d.ts +0 -3
  215. package/dist/pkgs/results/index.d.ts.map +1 -1
  216. package/dist/pkgs/results/index.js +17 -138
  217. package/dist/pkgs/results/orpc-error-handler.d.ts +65 -0
  218. package/dist/pkgs/results/orpc-error-handler.d.ts.map +1 -0
  219. package/dist/pkgs/results/types.d.ts +7 -7
  220. package/dist/pkgs/results/types.d.ts.map +1 -1
  221. package/dist/pkgs/types/context.d.ts +15 -4
  222. package/dist/pkgs/types/context.d.ts.map +1 -1
  223. package/dist/pkgs/types/endpoints.d.ts +3 -4
  224. package/dist/pkgs/types/endpoints.d.ts.map +1 -1
  225. package/dist/pkgs/types/options.d.ts +2 -3
  226. package/dist/pkgs/types/options.d.ts.map +1 -1
  227. package/dist/pkgs/types/plugins.d.ts +2 -3
  228. package/dist/pkgs/types/plugins.d.ts.map +1 -1
  229. package/dist/pkgs/utils/index.d.ts +1 -0
  230. package/dist/pkgs/utils/index.d.ts.map +1 -1
  231. package/dist/pkgs/utils/logger.d.ts +16 -0
  232. package/dist/pkgs/utils/logger.d.ts.map +1 -0
  233. package/dist/router.cjs +1213 -0
  234. package/dist/router.d.ts +480 -0
  235. package/dist/router.d.ts.map +1 -0
  236. package/dist/router.js +1169 -0
  237. package/dist/schema/audit-log/table.d.ts +1 -1
  238. package/dist/schema/consent/table.d.ts +1 -1
  239. package/dist/schema/consent-policy/registry.d.ts +12 -12
  240. package/dist/schema/consent-policy/schema.d.ts +6 -6
  241. package/dist/schema/consent-policy/table.d.ts +7 -7
  242. package/dist/schema/consent-purpose/registry.d.ts +6 -6
  243. package/dist/schema/consent-purpose/schema.d.ts +6 -6
  244. package/dist/schema/consent-purpose/table.d.ts +7 -7
  245. package/dist/schema/consent-record/table.d.ts +1 -1
  246. package/dist/schema/create-registry.d.ts +32 -32
  247. package/dist/schema/definition.d.ts +19 -19
  248. package/dist/schema/domain/registry.d.ts +10 -10
  249. package/dist/schema/domain/schema.d.ts +5 -5
  250. package/dist/schema/domain/table.d.ts +6 -6
  251. package/dist/schema/index.cjs +1409 -1775
  252. package/dist/schema/index.js +20 -385
  253. package/dist/schema/schemas.d.ts +19 -19
  254. package/dist/schema/subject/registry.d.ts +4 -4
  255. package/dist/schema/subject/schema.d.ts +2 -2
  256. package/dist/schema/subject/table.d.ts +3 -3
  257. package/dist/server.d.ts +2 -0
  258. package/dist/server.d.ts.map +1 -0
  259. package/dist/testing/contract-testing.d.ts +37 -0
  260. package/dist/testing/contract-testing.d.ts.map +1 -0
  261. package/dist/types/context.d.ts +1 -1
  262. package/dist/types/index.d.ts +2 -2
  263. package/dist/types/options.d.ts +33 -2
  264. package/dist/types/options.d.ts.map +1 -1
  265. package/dist/types/plugins.d.ts +3 -4
  266. package/dist/types/plugins.d.ts.map +1 -1
  267. package/package.json +22 -30
  268. package/rslib.config.ts +2 -5
  269. package/src/contracts/consent/index.test.ts +5 -0
  270. package/src/contracts/consent/index.ts +9 -0
  271. package/src/contracts/consent/post.contract.test.ts +526 -0
  272. package/src/contracts/consent/post.contract.ts +160 -0
  273. package/src/contracts/consent/show-banner.contract.test.ts +214 -0
  274. package/src/contracts/consent/show-banner.contract.ts +45 -0
  275. package/src/contracts/consent/verify.contract.test.ts +185 -0
  276. package/src/contracts/consent/verify.contract.ts +126 -0
  277. package/src/contracts/index.ts +18 -0
  278. package/src/contracts/meta/index.test.ts +5 -0
  279. package/src/contracts/meta/index.ts +5 -0
  280. package/src/contracts/meta/status.contract.test.ts +338 -0
  281. package/src/contracts/meta/status.contract.ts +37 -0
  282. package/src/contracts/shared/jurisdiction.schema.ts +30 -0
  283. package/src/core.ts +451 -159
  284. package/src/handlers/consent/index.ts +9 -0
  285. package/src/handlers/consent/post.handler.ts +273 -0
  286. package/src/handlers/consent/show-banner.handler.test.ts +148 -0
  287. package/src/handlers/consent/show-banner.handler.ts +150 -0
  288. package/src/handlers/consent/verify.handler.ts +305 -0
  289. package/src/handlers/meta/index.ts +5 -0
  290. package/src/handlers/meta/status.handler.ts +47 -0
  291. package/src/init.ts +8 -5
  292. package/src/pkgs/api-router/hooks/__tests__/processor.test.ts +6 -0
  293. package/src/pkgs/api-router/hooks/processor.ts +2 -0
  294. package/src/pkgs/api-router/types/router-props.ts +1 -1
  295. package/src/pkgs/api-router/utils/cors.ts +1 -1
  296. package/src/pkgs/data-model/fields/field-types.ts +1 -1
  297. package/src/pkgs/data-model/fields/id-generator.ts +1 -1
  298. package/src/pkgs/db-adapters/README.md +3 -3
  299. package/src/pkgs/db-adapters/adapter-factory.ts +8 -4
  300. package/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts +13 -13
  301. package/src/pkgs/db-adapters/adapters/kysely-adapter/dialect.ts +1 -1
  302. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/postgres.test.ts +1 -1
  303. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/sqlite.test.ts +1 -1
  304. package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts +2 -2
  305. package/src/pkgs/migrations/get-migration.ts +3 -3
  306. package/src/pkgs/migrations/get-schema/get-schema.ts +2 -2
  307. package/src/pkgs/migrations/get-schema/index.ts +1 -1
  308. package/src/pkgs/migrations/migration-builders.ts +2 -2
  309. package/src/pkgs/migrations/migration-execution.ts +2 -2
  310. package/src/pkgs/migrations/schema-comparison.ts +5 -4
  311. package/src/pkgs/results/__tests__/error-class.test.ts +8 -7
  312. package/src/pkgs/results/core/error-class.ts +31 -43
  313. package/src/pkgs/results/index.ts +0 -10
  314. package/src/pkgs/results/orpc-error-handler.ts +137 -0
  315. package/src/pkgs/results/types.ts +8 -7
  316. package/src/pkgs/types/context.ts +18 -4
  317. package/src/pkgs/types/endpoints.ts +3 -5
  318. package/src/pkgs/types/options.ts +2 -3
  319. package/src/pkgs/types/plugins.ts +2 -3
  320. package/src/pkgs/utils/index.ts +1 -0
  321. package/src/pkgs/utils/logger.ts +38 -0
  322. package/src/router.ts +8 -0
  323. package/src/schema/audit-log/table.ts +1 -1
  324. package/src/schema/consent/table.ts +1 -1
  325. package/src/schema/consent-policy/table.ts +1 -1
  326. package/src/schema/consent-purpose/table.ts +1 -1
  327. package/src/schema/consent-record/table.ts +1 -1
  328. package/src/schema/definition.ts +2 -2
  329. package/src/schema/domain/table.ts +1 -1
  330. package/src/schema/subject/table.ts +1 -1
  331. package/src/server.ts +130 -0
  332. package/src/testing/contract-testing.ts +437 -0
  333. package/src/types/context.ts +1 -1
  334. package/src/types/index.ts +2 -2
  335. package/src/types/options.ts +38 -2
  336. package/src/types/plugins.ts +3 -4
  337. package/dist/index.cjs +0 -3701
  338. package/dist/index.d.ts +0 -11
  339. package/dist/index.d.ts.map +0 -1
  340. package/dist/init.test.d.ts +0 -2
  341. package/dist/init.test.d.ts.map +0 -1
  342. package/dist/integrations/cloudflare.cjs +0 -312
  343. package/dist/integrations/cloudflare.d.ts +0 -32
  344. package/dist/integrations/cloudflare.d.ts.map +0 -1
  345. package/dist/integrations/cloudflare.js +0 -278
  346. package/dist/integrations/next.cjs +0 -276
  347. package/dist/integrations/next.d.ts +0 -68
  348. package/dist/integrations/next.d.ts.map +0 -1
  349. package/dist/integrations/next.js +0 -239
  350. package/dist/integrations/node.cjs +0 -257
  351. package/dist/integrations/node.d.ts +0 -29
  352. package/dist/integrations/node.d.ts.map +0 -1
  353. package/dist/integrations/node.js +0 -223
  354. package/dist/pkgs/api-router/index.d.ts +0 -9
  355. package/dist/pkgs/api-router/index.d.ts.map +0 -1
  356. package/dist/pkgs/api-router/utils/define-route.d.ts +0 -87
  357. package/dist/pkgs/api-router/utils/define-route.d.ts.map +0 -1
  358. package/dist/pkgs/logger/__tests__/console-formatter.test.d.ts +0 -2
  359. package/dist/pkgs/logger/__tests__/console-formatter.test.d.ts.map +0 -1
  360. package/dist/pkgs/logger/__tests__/integration.test.d.ts +0 -2
  361. package/dist/pkgs/logger/__tests__/integration.test.d.ts.map +0 -1
  362. package/dist/pkgs/logger/__tests__/log-levels.test.d.ts +0 -2
  363. package/dist/pkgs/logger/__tests__/log-levels.test.d.ts.map +0 -1
  364. package/dist/pkgs/logger/__tests__/logger-factory.test.d.ts +0 -2
  365. package/dist/pkgs/logger/__tests__/logger-factory.test.d.ts.map +0 -1
  366. package/dist/pkgs/logger/__tests__/result-logging.test.d.ts +0 -2
  367. package/dist/pkgs/logger/__tests__/result-logging.test.d.ts.map +0 -1
  368. package/dist/pkgs/logger/__tests__/types.test.d.ts +0 -2
  369. package/dist/pkgs/logger/__tests__/types.test.d.ts.map +0 -1
  370. package/dist/pkgs/logger/console-formatter.d.ts +0 -56
  371. package/dist/pkgs/logger/console-formatter.d.ts.map +0 -1
  372. package/dist/pkgs/logger/index.cjs +0 -240
  373. package/dist/pkgs/logger/index.d.ts +0 -35
  374. package/dist/pkgs/logger/index.d.ts.map +0 -1
  375. package/dist/pkgs/logger/index.js +0 -185
  376. package/dist/pkgs/logger/log-levels.d.ts +0 -29
  377. package/dist/pkgs/logger/log-levels.d.ts.map +0 -1
  378. package/dist/pkgs/logger/logger-factory.d.ts +0 -42
  379. package/dist/pkgs/logger/logger-factory.d.ts.map +0 -1
  380. package/dist/pkgs/logger/result-logging.d.ts +0 -71
  381. package/dist/pkgs/logger/result-logging.d.ts.map +0 -1
  382. package/dist/pkgs/logger/telemetry.d.ts +0 -14
  383. package/dist/pkgs/logger/telemetry.d.ts.map +0 -1
  384. package/dist/pkgs/logger/types.d.ts +0 -121
  385. package/dist/pkgs/logger/types.d.ts.map +0 -1
  386. package/dist/pkgs/results/__tests__/retrieval-pipeline.test.d.ts +0 -2
  387. package/dist/pkgs/results/__tests__/retrieval-pipeline.test.d.ts.map +0 -1
  388. package/dist/pkgs/results/__tests__/validation-pipeline.test.d.ts +0 -2
  389. package/dist/pkgs/results/__tests__/validation-pipeline.test.d.ts.map +0 -1
  390. package/dist/pkgs/results/h3-integration.d.ts +0 -52
  391. package/dist/pkgs/results/h3-integration.d.ts.map +0 -1
  392. package/dist/pkgs/results/pipeline/retrieval-pipeline.d.ts +0 -101
  393. package/dist/pkgs/results/pipeline/retrieval-pipeline.d.ts.map +0 -1
  394. package/dist/pkgs/results/pipeline/validation-pipeline.d.ts +0 -89
  395. package/dist/pkgs/results/pipeline/validation-pipeline.d.ts.map +0 -1
  396. package/dist/response-types.d.ts +0 -19
  397. package/dist/response-types.d.ts.map +0 -1
  398. package/dist/routes/__test__/index.test.d.ts +0 -17
  399. package/dist/routes/__test__/index.test.d.ts.map +0 -1
  400. package/dist/routes/__test__/set-consent.test.d.ts +0 -2
  401. package/dist/routes/__test__/set-consent.test.d.ts.map +0 -1
  402. package/dist/routes/__test__/show-consent-banner.test.d.ts +0 -2
  403. package/dist/routes/__test__/show-consent-banner.test.d.ts.map +0 -1
  404. package/dist/routes/__test__/status.test.d.ts +0 -2
  405. package/dist/routes/__test__/status.test.d.ts.map +0 -1
  406. package/dist/routes/__test__/verify-consent.test.d.ts +0 -2
  407. package/dist/routes/__test__/verify-consent.test.d.ts.map +0 -1
  408. package/dist/routes/index.d.ts +0 -3
  409. package/dist/routes/index.d.ts.map +0 -1
  410. package/dist/routes/set-consent.d.ts +0 -89
  411. package/dist/routes/set-consent.d.ts.map +0 -1
  412. package/dist/routes/show-consent-banner.d.ts +0 -15
  413. package/dist/routes/show-consent-banner.d.ts.map +0 -1
  414. package/dist/routes/status.d.ts +0 -44
  415. package/dist/routes/status.d.ts.map +0 -1
  416. package/dist/routes/types.d.ts +0 -7
  417. package/dist/routes/types.d.ts.map +0 -1
  418. package/dist/routes/verify-consent.d.ts +0 -38
  419. package/dist/routes/verify-consent.d.ts.map +0 -1
  420. package/src/docs/ADVANCED_JSON_HANDLING.md +0 -99
  421. package/src/docs/neverthrow.md +0 -171
  422. package/src/index.ts +0 -34
  423. package/src/init.test.ts +0 -219
  424. package/src/integrations/cloudflare.ts +0 -269
  425. package/src/integrations/next.ts +0 -204
  426. package/src/integrations/node.ts +0 -141
  427. package/src/pkgs/api-router/index.ts +0 -148
  428. package/src/pkgs/api-router/types/h3.d.ts +0 -42
  429. package/src/pkgs/api-router/utils/define-route.ts +0 -410
  430. package/src/pkgs/logger/README.md +0 -213
  431. package/src/pkgs/logger/__tests__/console-formatter.test.ts +0 -67
  432. package/src/pkgs/logger/__tests__/integration.test.ts +0 -184
  433. package/src/pkgs/logger/__tests__/log-levels.test.ts +0 -77
  434. package/src/pkgs/logger/__tests__/logger-factory.test.ts +0 -156
  435. package/src/pkgs/logger/__tests__/result-logging.test.ts +0 -209
  436. package/src/pkgs/logger/__tests__/types.test.ts +0 -94
  437. package/src/pkgs/logger/console-formatter.ts +0 -75
  438. package/src/pkgs/logger/doc.md +0 -569
  439. package/src/pkgs/logger/index.ts +0 -59
  440. package/src/pkgs/logger/log-levels.ts +0 -46
  441. package/src/pkgs/logger/logger-factory.ts +0 -121
  442. package/src/pkgs/logger/result-logging.ts +0 -134
  443. package/src/pkgs/logger/telemetry.ts +0 -96
  444. package/src/pkgs/logger/types.ts +0 -138
  445. package/src/pkgs/results/__tests__/retrieval-pipeline.test.ts +0 -157
  446. package/src/pkgs/results/__tests__/validation-pipeline.test.ts +0 -151
  447. package/src/pkgs/results/h3-integration.ts +0 -142
  448. package/src/pkgs/results/pipeline/retrieval-pipeline.ts +0 -188
  449. package/src/pkgs/results/pipeline/validation-pipeline.ts +0 -164
  450. package/src/plugins/.keep +0 -0
  451. package/src/response-types.ts +0 -29
  452. package/src/routes/__test__/index.test.ts +0 -112
  453. package/src/routes/__test__/set-consent.test.ts +0 -242
  454. package/src/routes/__test__/show-consent-banner.test.ts +0 -98
  455. package/src/routes/__test__/status.test.ts +0 -64
  456. package/src/routes/__test__/verify-consent.test.ts +0 -266
  457. package/src/routes/index.ts +0 -12
  458. package/src/routes/set-consent.ts +0 -249
  459. package/src/routes/show-consent-banner.ts +0 -131
  460. package/src/routes/status.ts +0 -61
  461. package/src/routes/types.ts +0 -7
  462. package/src/routes/verify-consent.ts +0 -206
@@ -0,0 +1,273 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import { os } from '~/contracts';
3
+ import type { Adapter } from '~/pkgs/db-adapters/types';
4
+ import type { Consent } from '~/schema/consent';
5
+ import type { ConsentRecord } from '~/schema/consent-record';
6
+ import type { C15TContext } from '~/types';
7
+
8
+ /**
9
+ * Handles the creation of a new consent record.
10
+ *
11
+ * This handler processes consent submissions, creates necessary records in the database,
12
+ * and returns a formatted response. It handles different types of consent (cookie banner,
13
+ * policy-based, and other types) with their specific requirements.
14
+ *
15
+ * @throws {ORPCError} When:
16
+ * - Subject creation fails
17
+ * - Policy is not found or inactive
18
+ * - Database transaction fails
19
+ * - Required fields are missing
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // Cookie banner consent
24
+ * const response = await postConsent({
25
+ * type: 'cookie_banner',
26
+ * domain: 'example.com',
27
+ * preferences: { analytics: true, marketing: false }
28
+ * });
29
+ * ```
30
+ */
31
+
32
+ export const postConsent = os.consent.post.handler(
33
+ async ({ input, context }) => {
34
+ const typedContext = context as C15TContext;
35
+
36
+ const logger = typedContext.logger;
37
+ logger.info('Handling post-consent request');
38
+
39
+ const {
40
+ type,
41
+ subjectId,
42
+ externalSubjectId,
43
+ domain,
44
+ metadata,
45
+ preferences,
46
+ } = input;
47
+
48
+ logger.debug('Request parameters', {
49
+ type,
50
+ subjectId,
51
+ externalSubjectId,
52
+ domain,
53
+ });
54
+
55
+ try {
56
+ const subject = await typedContext.registry.findOrCreateSubject({
57
+ subjectId,
58
+ externalSubjectId,
59
+ ipAddress: typedContext.ipAddress || 'unknown',
60
+ });
61
+
62
+ if (!subject) {
63
+ throw new ORPCError('SUBJECT_CREATION_FAILED', {
64
+ data: {
65
+ subjectId,
66
+ externalSubjectId,
67
+ },
68
+ });
69
+ }
70
+
71
+ logger.debug('Subject found/created', { subjectId: subject.id });
72
+ const domainRecord =
73
+ await typedContext.registry.findOrCreateDomain(domain);
74
+
75
+ if (!domainRecord) {
76
+ throw new ORPCError('DOMAIN_CREATION_FAILED', {
77
+ data: {
78
+ domain,
79
+ },
80
+ });
81
+ }
82
+
83
+ const now = new Date();
84
+ let policyId: string | undefined;
85
+ let purposeIds: string[] = [];
86
+
87
+ if ('policyId' in input && input.policyId) {
88
+ policyId = input.policyId;
89
+
90
+ // Verify the policy exists and is active
91
+ const policy =
92
+ await typedContext.registry.findConsentPolicyById(policyId);
93
+ if (!policy) {
94
+ throw new ORPCError('POLICY_NOT_FOUND', {
95
+ data: {
96
+ policyId,
97
+ type,
98
+ },
99
+ });
100
+ }
101
+ if (!policy.isActive) {
102
+ throw new ORPCError('POLICY_INACTIVE', {
103
+ data: {
104
+ policyId,
105
+ type,
106
+ },
107
+ });
108
+ }
109
+ } else {
110
+ const policy = await typedContext.registry.findOrCreatePolicy(type);
111
+ if (!policy) {
112
+ throw new ORPCError('POLICY_CREATION_FAILED', {
113
+ data: {
114
+ type,
115
+ },
116
+ });
117
+ }
118
+ policyId = policy.id;
119
+ }
120
+
121
+ // Handle purposes if they exist
122
+ if (preferences) {
123
+ const consentedPurposes = Object.entries(preferences)
124
+ .filter(([_, isConsented]) => isConsented)
125
+ .map(([purposeCode]) => purposeCode);
126
+
127
+ // Batch fetch all existing purposes
128
+ const existingPurposes = await Promise.all(
129
+ consentedPurposes.map((purposeCode) =>
130
+ typedContext.registry.findConsentPurposeByCode(purposeCode)
131
+ )
132
+ );
133
+
134
+ // Find which purposes need to be created
135
+ const purposesToCreate = consentedPurposes.filter(
136
+ (_purposeCode, index) => !existingPurposes[index]
137
+ );
138
+
139
+ // Batch create missing purposes
140
+ const createdPurposes = await Promise.all(
141
+ purposesToCreate.map((purposeCode) =>
142
+ typedContext.registry.createConsentPurpose({
143
+ code: purposeCode,
144
+ name: purposeCode,
145
+ description: `Auto-created consentPurpose for ${purposeCode}`,
146
+ isActive: true,
147
+ isEssential: false,
148
+ legalBasis: 'consent',
149
+ createdAt: now,
150
+ updatedAt: now,
151
+ })
152
+ )
153
+ );
154
+
155
+ // Combine existing and newly created purposes
156
+ purposeIds = [
157
+ ...existingPurposes
158
+ .filter((p): p is NonNullable<typeof p> => p !== null)
159
+ .map((p) => p.id),
160
+ ...createdPurposes
161
+ .filter((p): p is NonNullable<typeof p> => p !== null)
162
+ .map((p) => p.id),
163
+ ];
164
+
165
+ // Verify all purposes were created successfully
166
+ if (purposeIds.length !== consentedPurposes.length) {
167
+ throw new ORPCError('PURPOSE_CREATION_FAILED', {
168
+ data: {
169
+ purposeCode:
170
+ purposesToCreate[purposeIds.length - consentedPurposes.length],
171
+ },
172
+ });
173
+ }
174
+ }
175
+
176
+ const result = await typedContext.adapter.transaction({
177
+ callback: async (tx: Adapter) => {
178
+ // Create consent record
179
+ const consentRecord = (await tx.create({
180
+ model: 'consent',
181
+ data: {
182
+ subjectId: subject.id,
183
+ domainId: domainRecord.id,
184
+ policyId,
185
+ purposeIds,
186
+ status: 'active',
187
+ isActive: true,
188
+ givenAt: now,
189
+ ipAddress: typedContext.ipAddress || 'unknown',
190
+ agent: typedContext.userAgent || 'unknown',
191
+ history: [],
192
+ },
193
+ })) as unknown as Consent;
194
+
195
+ // Create record entry
196
+ const record = (await tx.create({
197
+ model: 'consentRecord',
198
+ data: {
199
+ subjectId: subject.id,
200
+ consentId: consentRecord.id,
201
+ actionType: 'consent_given',
202
+ details: metadata,
203
+ createdAt: now,
204
+ },
205
+ })) as unknown as ConsentRecord;
206
+
207
+ // Create audit log entry
208
+ await tx.create({
209
+ model: 'auditLog',
210
+ data: {
211
+ subjectId: subject.id,
212
+ entityType: 'consent',
213
+ entityId: consentRecord.id,
214
+ actionType: 'consent_given',
215
+ details: {
216
+ consentId: consentRecord.id,
217
+ type,
218
+ },
219
+ timestamp: now,
220
+ ipAddress: typedContext.ipAddress || 'unknown',
221
+ agent: typedContext.userAgent || 'unknown',
222
+ },
223
+ });
224
+
225
+ return {
226
+ consent: consentRecord,
227
+ record,
228
+ };
229
+ },
230
+ });
231
+
232
+ if (!result || !result.consent || !result.record) {
233
+ throw new ORPCError('CONSENT_CREATION_FAILED', {
234
+ data: {
235
+ subjectId: subject.id,
236
+ domain,
237
+ },
238
+ });
239
+ }
240
+
241
+ // Return the response in the format defined by the contract
242
+ return {
243
+ id: result.consent.id,
244
+ subjectId: subject.id,
245
+ externalSubjectId: subject.externalId ?? undefined,
246
+ domainId: domainRecord.id,
247
+ domain: domainRecord.name,
248
+ type,
249
+ status: result.consent.status,
250
+ recordId: result.record.id,
251
+ metadata,
252
+ givenAt: result.consent.givenAt,
253
+ };
254
+ } catch (error) {
255
+ // Log all errors properly
256
+ logger.error('Error in post-consent handler', {
257
+ error: error instanceof Error ? error.message : String(error),
258
+ errorType:
259
+ error instanceof Error ? error.constructor.name : typeof error,
260
+ });
261
+
262
+ // Re-throw ORPCError instances
263
+ if (error instanceof ORPCError) {
264
+ throw error;
265
+ }
266
+
267
+ // Convert other errors to internal server error
268
+ throw new ORPCError('INTERNAL_SERVER_ERROR', {
269
+ message: error instanceof Error ? error.message : String(error),
270
+ });
271
+ }
272
+ }
273
+ );
@@ -0,0 +1,148 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { JurisdictionMessages } from '~/contracts/shared/jurisdiction.schema';
3
+ import { showConsentBanner } from './show-banner.handler';
4
+
5
+ // First, mock the oRPC handler
6
+ vi.mock('~/contracts', () => ({
7
+ os: {
8
+ consent: {
9
+ showBanner: {
10
+ handler: (fn: unknown) => fn, // Make the handler function directly callable for testing
11
+ },
12
+ },
13
+ },
14
+ }));
15
+
16
+ describe('Show Consent Banner Handler', () => {
17
+ // Helper to create mock context with headers
18
+ const createMockContext = (headers: Record<string, string>) => {
19
+ return {
20
+ context: {
21
+ headers: new Headers(headers),
22
+ },
23
+ };
24
+ };
25
+
26
+ describe('Header extraction', () => {
27
+ it('extracts country code from cf-ipcountry header', async () => {
28
+ //@ts-expect-error
29
+ const result = await showConsentBanner(
30
+ createMockContext({ 'cf-ipcountry': 'DE' })
31
+ );
32
+
33
+ expect(result.location.countryCode).toBe('DE');
34
+ });
35
+
36
+ it('falls back to alternative country code headers', async () => {
37
+ //@ts-expect-error
38
+ const result = await showConsentBanner(
39
+ createMockContext({ 'x-vercel-ip-country': 'FR' })
40
+ );
41
+
42
+ expect(result.location.countryCode).toBe('FR');
43
+ });
44
+
45
+ it('extracts region code from headers', async () => {
46
+ //@ts-expect-error
47
+ const result = await showConsentBanner(
48
+ createMockContext({
49
+ 'cf-ipcountry': 'US',
50
+ 'x-vercel-ip-country-region': 'CA',
51
+ })
52
+ );
53
+
54
+ expect(result.location.countryCode).toBe('US');
55
+ expect(result.location.regionCode).toBe('CA');
56
+ });
57
+
58
+ it('handles missing headers gracefully', async () => {
59
+ //@ts-expect-error
60
+ const result = await showConsentBanner(createMockContext({}));
61
+
62
+ expect(result.location.countryCode).toBeNull();
63
+ expect(result.location.regionCode).toBeNull();
64
+ });
65
+ });
66
+
67
+ describe('Jurisdiction determination', () => {
68
+ it('identifies EU countries as GDPR', async () => {
69
+ //@ts-expect-error
70
+ const result = await showConsentBanner(
71
+ createMockContext({ 'cf-ipcountry': 'DE' })
72
+ );
73
+
74
+ expect(result.showConsentBanner).toBe(true);
75
+ expect(result.jurisdiction.code).toBe('GDPR');
76
+ expect(result.jurisdiction.message).toBe(JurisdictionMessages.GDPR);
77
+ });
78
+
79
+ it('identifies UK as GDPR', async () => {
80
+ //@ts-expect-error
81
+ const result = await showConsentBanner(
82
+ createMockContext({ 'cf-ipcountry': 'GB' })
83
+ );
84
+
85
+ expect(result.showConsentBanner).toBe(true);
86
+ expect(result.jurisdiction.code).toBe('GDPR');
87
+ });
88
+
89
+ it('identifies other jurisdictions correctly', async () => {
90
+ const cases = [
91
+ { country: 'CH', code: 'CH' },
92
+ { country: 'BR', code: 'BR' },
93
+ { country: 'CA', code: 'PIPEDA' },
94
+ { country: 'AU', code: 'AU' },
95
+ { country: 'JP', code: 'APPI' },
96
+ { country: 'KR', code: 'PIPA' },
97
+ ];
98
+
99
+ for (const testCase of cases) {
100
+ //@ts-expect-error
101
+ const result = await showConsentBanner(
102
+ createMockContext({ 'cf-ipcountry': testCase.country })
103
+ );
104
+
105
+ expect(result.showConsentBanner).toBe(true);
106
+ expect(result.jurisdiction.code).toBe(testCase.code);
107
+
108
+ expect(result.jurisdiction.message).toBe(
109
+ JurisdictionMessages[
110
+ testCase.code as keyof typeof JurisdictionMessages
111
+ ]
112
+ );
113
+ }
114
+ });
115
+
116
+ it('identifies non-regulated countries', async () => {
117
+ //@ts-expect-error
118
+ const result = await showConsentBanner(
119
+ createMockContext({ 'cf-ipcountry': 'US' })
120
+ );
121
+
122
+ expect(result.showConsentBanner).toBe(false);
123
+ expect(result.jurisdiction.code).toBe('NONE');
124
+ expect(result.jurisdiction.message).toBe(JurisdictionMessages.NONE);
125
+ });
126
+ });
127
+
128
+ describe('Response format', () => {
129
+ it('returns properly structured response', async () => {
130
+ //@ts-expect-error
131
+ const result = await showConsentBanner(
132
+ createMockContext({ 'cf-ipcountry': 'DE' })
133
+ );
134
+
135
+ expect(result).toEqual({
136
+ showConsentBanner: true,
137
+ jurisdiction: {
138
+ code: 'GDPR',
139
+ message: JurisdictionMessages.GDPR,
140
+ },
141
+ location: {
142
+ countryCode: 'DE',
143
+ regionCode: null,
144
+ },
145
+ });
146
+ });
147
+ });
148
+ });
@@ -0,0 +1,150 @@
1
+ import { ORPCError } from '@orpc/server';
2
+ import { os } from '~/contracts';
3
+ import {
4
+ type JurisdictionCode,
5
+ JurisdictionMessages,
6
+ } from '~/contracts/shared/jurisdiction.schema';
7
+ import type { C15TContext } from '~/types';
8
+
9
+ /**
10
+ * Handler for the show consent banner endpoint
11
+ * Determines if a user should see a consent banner based on their location
12
+ */
13
+ export const showConsentBanner = os.consent.showBanner.handler(
14
+ ({ context }) => {
15
+ const typedContext = context as C15TContext;
16
+
17
+ // Extract country and region from request headers
18
+ const headers = typedContext.headers;
19
+ if (!headers) {
20
+ throw new ORPCError('LOCATION_DETECTION_FAILED', {
21
+ data: {
22
+ reason: 'No headers found in request context',
23
+ },
24
+ });
25
+ }
26
+
27
+ // Add this conversion to ensure headers are always string or null
28
+ const normalizeHeader = (
29
+ value: string | string[] | null | undefined
30
+ ): string | null => {
31
+ if (!value) {
32
+ return null;
33
+ }
34
+
35
+ return Array.isArray(value) ? (value[0] ?? null) : value;
36
+ };
37
+
38
+ const countryCode =
39
+ normalizeHeader(headers.get('cf-ipcountry')) ??
40
+ normalizeHeader(headers.get('x-vercel-ip-country')) ??
41
+ normalizeHeader(headers.get('x-amz-cf-ipcountry')) ??
42
+ normalizeHeader(headers.get('x-country-code'));
43
+
44
+ const regionCode =
45
+ normalizeHeader(headers.get('x-vercel-ip-country-region')) ??
46
+ normalizeHeader(headers.get('x-region-code'));
47
+
48
+ // If no location headers found, throw error
49
+
50
+ // Determine jurisdiction based on country
51
+ const { showConsentBanner, jurisdictionCode, message } =
52
+ checkJurisdiction(countryCode);
53
+
54
+ // Return properly structured response
55
+ return {
56
+ showConsentBanner,
57
+ jurisdiction: {
58
+ code: jurisdictionCode,
59
+ message,
60
+ },
61
+ location: { countryCode, regionCode },
62
+ };
63
+ }
64
+ );
65
+
66
+ /**
67
+ * Determines if a consent banner should be shown based on country code
68
+ * and returns appropriate jurisdiction information
69
+ */
70
+ export function checkJurisdiction(countryCode: string | null) {
71
+ // Country code sets for different jurisdictions
72
+ const jurisdictions = {
73
+ EU: new Set([
74
+ 'AT',
75
+ 'BE',
76
+ 'BG',
77
+ 'HR',
78
+ 'CY',
79
+ 'CZ',
80
+ 'DK',
81
+ 'EE',
82
+ 'FI',
83
+ 'FR',
84
+ 'DE',
85
+ 'GR',
86
+ 'HU',
87
+ 'IE',
88
+ 'IT',
89
+ 'LV',
90
+ 'LT',
91
+ 'LU',
92
+ 'MT',
93
+ 'NL',
94
+ 'PL',
95
+ 'PT',
96
+ 'RO',
97
+ 'SK',
98
+ 'SI',
99
+ 'ES',
100
+ 'SE',
101
+ ]),
102
+ EEA: new Set(['IS', 'NO', 'LI']),
103
+ UK: new Set(['GB']),
104
+ CH: new Set(['CH']),
105
+ BR: new Set(['BR']),
106
+ CA: new Set(['CA']),
107
+ AU: new Set(['AU']),
108
+ JP: new Set(['JP']),
109
+ KR: new Set(['KR']),
110
+ };
111
+
112
+ // Default to no jurisdiction
113
+ let showConsentBanner = false;
114
+ let jurisdictionCode: JurisdictionCode = 'NONE';
115
+
116
+ // Check country code against jurisdiction sets
117
+ if (countryCode) {
118
+ // Map jurisdiction sets to their respective codes
119
+ const jurisdictionMap = [
120
+ {
121
+ sets: [jurisdictions.EU, jurisdictions.EEA, jurisdictions.UK],
122
+ code: 'GDPR',
123
+ },
124
+ { sets: [jurisdictions.CH], code: 'CH' },
125
+ { sets: [jurisdictions.BR], code: 'BR' },
126
+ { sets: [jurisdictions.CA], code: 'PIPEDA' },
127
+ { sets: [jurisdictions.AU], code: 'AU' },
128
+ { sets: [jurisdictions.JP], code: 'APPI' },
129
+ { sets: [jurisdictions.KR], code: 'PIPA' },
130
+ ] as const;
131
+
132
+ // Find matching jurisdiction
133
+ for (const { sets, code } of jurisdictionMap) {
134
+ if (sets.some((set) => set.has(countryCode))) {
135
+ showConsentBanner = true;
136
+ jurisdictionCode = code;
137
+ break;
138
+ }
139
+ }
140
+ }
141
+
142
+ // Get corresponding message from shared schema
143
+ const message = JurisdictionMessages[jurisdictionCode];
144
+
145
+ return {
146
+ showConsentBanner,
147
+ jurisdictionCode,
148
+ message,
149
+ };
150
+ }