@c15t/backend 2.0.0-rc.0 → 2.0.0-rc.10

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 (336) hide show
  1. package/README.md +3 -3
  2. package/dist/302.js +473 -0
  3. package/dist/583.js +540 -0
  4. package/dist/915.js +1771 -0
  5. package/dist/cache.cjs +5 -5
  6. package/dist/cache.js +4 -415
  7. package/dist/core.cjs +1356 -120
  8. package/dist/core.js +163 -1981
  9. package/dist/db/adapters/drizzle.cjs +1 -1
  10. package/dist/db/adapters/drizzle.js +1 -2
  11. package/dist/db/adapters/kysely.cjs +1 -1
  12. package/dist/db/adapters/kysely.js +1 -2
  13. package/dist/db/adapters/mongo.cjs +1 -1
  14. package/dist/db/adapters/mongo.js +1 -2
  15. package/dist/db/adapters/prisma.cjs +1 -1
  16. package/dist/db/adapters/prisma.js +1 -2
  17. package/dist/db/adapters/typeorm.cjs +1 -1
  18. package/dist/db/adapters/typeorm.js +1 -2
  19. package/dist/db/adapters.cjs +1 -1
  20. package/dist/db/migrator.cjs +1 -1
  21. package/dist/db/schema.cjs +43 -3
  22. package/dist/db/schema.js +35 -4
  23. package/dist/define-config.cjs +1 -1
  24. package/dist/edge.cjs +1106 -0
  25. package/dist/edge.js +190 -0
  26. package/dist/router.cjs +885 -123
  27. package/dist/router.js +1 -1507
  28. package/dist/{types.cjs → types/index.cjs} +1 -1
  29. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  30. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  31. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  32. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  33. package/{dist → dist-types}/cache/gvl-resolver.d.ts +0 -1
  34. package/{dist → dist-types}/cache/index.d.ts +0 -1
  35. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  36. package/{dist → dist-types}/cache/types.d.ts +0 -1
  37. package/{dist → dist-types}/core.d.ts +8 -1
  38. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  39. package/dist-types/db/registry/consent-policy.d.ts +78 -0
  40. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  41. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  42. package/dist-types/db/registry/index.d.ts +118 -0
  43. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  44. package/{dist → dist-types}/db/registry/subject.d.ts +0 -2
  45. package/{dist → dist-types}/db/registry/types.d.ts +1 -1
  46. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  47. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  48. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  49. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  50. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  51. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  52. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  53. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  54. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -32
  55. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -2
  56. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  57. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +3 -3
  58. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  59. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +7 -2
  60. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  61. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +455 -28
  62. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  63. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -3
  64. package/{dist → dist-types}/db/schema/index.d.ts +908 -86
  65. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  66. package/dist-types/define-config.d.ts +17 -0
  67. package/dist-types/edge/index.d.ts +5 -0
  68. package/dist-types/edge/init-handler.d.ts +40 -0
  69. package/dist-types/edge/resolve-consent.d.ts +80 -0
  70. package/dist-types/edge/types.d.ts +13 -0
  71. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  72. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  73. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  74. package/{dist → dist-types}/handlers/init/index.d.ts +2 -3
  75. package/dist-types/handlers/init/policy.d.ts +26 -0
  76. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  77. package/dist-types/handlers/init/translations.d.ts +48 -0
  78. package/dist-types/handlers/legal-document/current.handler.d.ts +11 -0
  79. package/dist-types/handlers/legal-document/snapshot.d.ts +39 -0
  80. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  81. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  82. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  83. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +3 -2
  84. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  85. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +3 -2
  86. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -2
  87. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  88. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +3 -1
  89. package/{dist → dist-types}/init.d.ts +4 -7
  90. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  91. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  92. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  93. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  94. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +0 -1
  95. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  96. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  97. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  98. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  99. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  100. package/dist-types/policies/builder.d.ts +127 -0
  101. package/dist-types/policies/defaults.d.ts +2 -0
  102. package/dist-types/policies/matchers.d.ts +3 -0
  103. package/{dist → dist-types}/router.d.ts +0 -1
  104. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  105. package/{dist → dist-types}/routes/index.d.ts +1 -1
  106. package/{dist → dist-types}/routes/init.d.ts +0 -1
  107. package/dist-types/routes/legal-document.d.ts +7 -0
  108. package/{dist → dist-types}/routes/status.d.ts +0 -1
  109. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  110. package/{dist → dist-types}/types/api.d.ts +0 -1
  111. package/dist-types/types/index.d.ts +464 -0
  112. package/dist-types/utils/background.d.ts +6 -0
  113. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
  114. package/{dist → dist-types}/utils/env.d.ts +0 -1
  115. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  116. package/{dist → dist-types}/utils/instrumentation.d.ts +2 -3
  117. package/{dist → dist-types}/utils/logger.d.ts +0 -1
  118. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  119. package/dist-types/version.d.ts +1 -0
  120. package/docs/README.md +49 -0
  121. package/docs/api/configuration.md +208 -0
  122. package/docs/api/endpoints.md +211 -0
  123. package/docs/guides/caching.md +85 -0
  124. package/docs/guides/database-setup.md +128 -0
  125. package/docs/guides/edge-deployment.md +251 -0
  126. package/docs/guides/framework-integration.md +142 -0
  127. package/docs/guides/iab-tcf.md +89 -0
  128. package/docs/guides/observability.md +96 -0
  129. package/docs/guides/policy-packs.md +396 -0
  130. package/docs/quickstart.md +129 -0
  131. package/package.json +53 -39
  132. package/.turbo/turbo-build.log +0 -49
  133. package/CHANGELOG.md +0 -89
  134. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  135. package/dist/cache/adapters/index.d.ts.map +0 -1
  136. package/dist/cache/adapters/memory.d.ts.map +0 -1
  137. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  138. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  139. package/dist/cache/index.d.ts.map +0 -1
  140. package/dist/cache/keys.d.ts.map +0 -1
  141. package/dist/cache/types.d.ts.map +0 -1
  142. package/dist/core.d.ts.map +0 -1
  143. package/dist/db/adapters/drizzle.d.ts +0 -2
  144. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  145. package/dist/db/adapters/index.d.ts +0 -2
  146. package/dist/db/adapters/index.d.ts.map +0 -1
  147. package/dist/db/adapters/kysely.d.ts +0 -2
  148. package/dist/db/adapters/kysely.d.ts.map +0 -1
  149. package/dist/db/adapters/mongo.d.ts +0 -2
  150. package/dist/db/adapters/mongo.d.ts.map +0 -1
  151. package/dist/db/adapters/prisma.d.ts +0 -2
  152. package/dist/db/adapters/prisma.d.ts.map +0 -1
  153. package/dist/db/adapters/typeorm.d.ts +0 -2
  154. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  155. package/dist/db/migrator/index.d.ts.map +0 -1
  156. package/dist/db/registry/consent-policy.d.ts +0 -23
  157. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  158. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  159. package/dist/db/registry/domain.d.ts.map +0 -1
  160. package/dist/db/registry/index.d.ts +0 -57
  161. package/dist/db/registry/index.d.ts.map +0 -1
  162. package/dist/db/registry/subject.d.ts.map +0 -1
  163. package/dist/db/registry/types.d.ts.map +0 -1
  164. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  165. package/dist/db/registry/utils.d.ts.map +0 -1
  166. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  167. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  168. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  169. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  170. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  171. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  172. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  173. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  174. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  175. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  176. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  177. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  178. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  179. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  180. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  181. package/dist/db/schema/index.d.ts.map +0 -1
  182. package/dist/db/tenant-scope.d.ts.map +0 -1
  183. package/dist/define-config.d.ts +0 -5
  184. package/dist/define-config.d.ts.map +0 -1
  185. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  186. package/dist/handlers/consent/index.d.ts +0 -12
  187. package/dist/handlers/consent/index.d.ts.map +0 -1
  188. package/dist/handlers/init/geo.d.ts.map +0 -1
  189. package/dist/handlers/init/index.d.ts.map +0 -1
  190. package/dist/handlers/init/translations.d.ts +0 -28
  191. package/dist/handlers/init/translations.d.ts.map +0 -1
  192. package/dist/handlers/status/index.d.ts +0 -7
  193. package/dist/handlers/status/index.d.ts.map +0 -1
  194. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  195. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  196. package/dist/handlers/subject/index.d.ts +0 -10
  197. package/dist/handlers/subject/index.d.ts.map +0 -1
  198. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  199. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  200. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  201. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  202. package/dist/init.d.ts.map +0 -1
  203. package/dist/middleware/auth/index.d.ts.map +0 -1
  204. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  205. package/dist/middleware/cors/cors.d.ts.map +0 -1
  206. package/dist/middleware/cors/index.d.ts +0 -30
  207. package/dist/middleware/cors/index.d.ts.map +0 -1
  208. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  209. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  210. package/dist/middleware/openapi/config.d.ts.map +0 -1
  211. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  212. package/dist/middleware/openapi/index.d.ts +0 -12
  213. package/dist/middleware/openapi/index.d.ts.map +0 -1
  214. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  215. package/dist/router.d.ts.map +0 -1
  216. package/dist/routes/consent.d.ts.map +0 -1
  217. package/dist/routes/index.d.ts.map +0 -1
  218. package/dist/routes/init.d.ts.map +0 -1
  219. package/dist/routes/status.d.ts.map +0 -1
  220. package/dist/routes/subject.d.ts.map +0 -1
  221. package/dist/types/api.d.ts.map +0 -1
  222. package/dist/types/index.d.ts +0 -255
  223. package/dist/types/index.d.ts.map +0 -1
  224. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  225. package/dist/utils/env.d.ts.map +0 -1
  226. package/dist/utils/extract-error-message.d.ts.map +0 -1
  227. package/dist/utils/index.d.ts +0 -4
  228. package/dist/utils/index.d.ts.map +0 -1
  229. package/dist/utils/instrumentation.d.ts.map +0 -1
  230. package/dist/utils/logger.d.ts.map +0 -1
  231. package/dist/utils/metrics.d.ts.map +0 -1
  232. package/dist/version.d.ts +0 -2
  233. package/dist/version.d.ts.map +0 -1
  234. package/knip.json +0 -31
  235. package/rslib.config.ts +0 -93
  236. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  237. package/src/cache/adapters/index.ts +0 -22
  238. package/src/cache/adapters/memory.ts +0 -111
  239. package/src/cache/adapters/upstash-redis.ts +0 -113
  240. package/src/cache/gvl-resolver.ts +0 -289
  241. package/src/cache/index.ts +0 -34
  242. package/src/cache/keys.ts +0 -68
  243. package/src/cache/types.ts +0 -66
  244. package/src/core.ts +0 -368
  245. package/src/db/migrator/index.ts +0 -80
  246. package/src/db/registry/consent-policy.test.ts +0 -451
  247. package/src/db/registry/consent-policy.ts +0 -82
  248. package/src/db/registry/consent-purpose.test.ts +0 -428
  249. package/src/db/registry/consent-purpose.ts +0 -61
  250. package/src/db/registry/domain.test.ts +0 -445
  251. package/src/db/registry/domain.ts +0 -91
  252. package/src/db/registry/index.ts +0 -14
  253. package/src/db/registry/subject.test.ts +0 -388
  254. package/src/db/registry/subject.ts +0 -129
  255. package/src/db/registry/types.ts +0 -10
  256. package/src/db/registry/utils/generate-id.test.ts +0 -216
  257. package/src/db/registry/utils/generate-id.ts +0 -133
  258. package/src/db/registry/utils.ts +0 -133
  259. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  260. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  261. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  262. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  263. package/src/db/schema/1.0.0/consent.ts +0 -20
  264. package/src/db/schema/1.0.0/domain.ts +0 -12
  265. package/src/db/schema/1.0.0/index.ts +0 -48
  266. package/src/db/schema/1.0.0/subject.ts +0 -12
  267. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  268. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  269. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  270. package/src/db/schema/2.0.0/consent.ts +0 -26
  271. package/src/db/schema/2.0.0/domain.ts +0 -12
  272. package/src/db/schema/2.0.0/index.ts +0 -47
  273. package/src/db/schema/2.0.0/subject.ts +0 -14
  274. package/src/db/schema/index.ts +0 -15
  275. package/src/db/tenant-scope.test.ts +0 -750
  276. package/src/db/tenant-scope.ts +0 -103
  277. package/src/define-config.ts +0 -5
  278. package/src/handlers/consent/check.handler.ts +0 -126
  279. package/src/handlers/init/geo.test.ts +0 -317
  280. package/src/handlers/init/geo.ts +0 -195
  281. package/src/handlers/init/index.test.ts +0 -205
  282. package/src/handlers/init/index.ts +0 -114
  283. package/src/handlers/init/translations.test.ts +0 -121
  284. package/src/handlers/init/translations.ts +0 -72
  285. package/src/handlers/status/status.handler.test.ts +0 -155
  286. package/src/handlers/status/status.handler.ts +0 -51
  287. package/src/handlers/subject/get.handler.ts +0 -93
  288. package/src/handlers/subject/list.handler.ts +0 -93
  289. package/src/handlers/subject/patch.handler.ts +0 -122
  290. package/src/handlers/subject/post.handler.test.ts +0 -294
  291. package/src/handlers/subject/post.handler.ts +0 -254
  292. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  293. package/src/handlers/utils/consent-enrichment.ts +0 -218
  294. package/src/init.test.ts +0 -126
  295. package/src/init.ts +0 -87
  296. package/src/middleware/auth/index.ts +0 -11
  297. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  298. package/src/middleware/auth/validate-api-key.ts +0 -107
  299. package/src/middleware/cors/cors.test.ts +0 -135
  300. package/src/middleware/cors/cors.ts +0 -186
  301. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  302. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  303. package/src/middleware/cors/process-cors.ts +0 -91
  304. package/src/middleware/openapi/config.ts +0 -29
  305. package/src/middleware/openapi/handlers.ts +0 -34
  306. package/src/middleware/process-ip/index.test.ts +0 -195
  307. package/src/middleware/process-ip/index.ts +0 -199
  308. package/src/router.ts +0 -15
  309. package/src/routes/consent.ts +0 -52
  310. package/src/routes/index.ts +0 -10
  311. package/src/routes/init.ts +0 -102
  312. package/src/routes/status.ts +0 -46
  313. package/src/routes/subject.ts +0 -152
  314. package/src/types/api.ts +0 -48
  315. package/src/types/index.ts +0 -288
  316. package/src/utils/create-telemetry-options.test.ts +0 -302
  317. package/src/utils/create-telemetry-options.ts +0 -229
  318. package/src/utils/env.ts +0 -84
  319. package/src/utils/extract-error-message.ts +0 -21
  320. package/src/utils/instrumentation.test.ts +0 -185
  321. package/src/utils/instrumentation.ts +0 -196
  322. package/src/utils/logger.ts +0 -41
  323. package/src/utils/metrics.test.ts +0 -323
  324. package/src/utils/metrics.ts +0 -402
  325. package/src/utils/telemetry-pii.test.ts +0 -325
  326. package/src/version.ts +0 -2
  327. package/tsconfig.json +0 -11
  328. package/vitest.config.ts +0 -28
  329. /package/dist/{types.js → types/index.js} +0 -0
  330. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  331. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  332. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  333. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  334. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  335. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  336. /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
@@ -1,103 +0,0 @@
1
- import type { InferFumaDB } from 'fumadb';
2
- import type { LatestDB } from './schema';
3
-
4
- type ORM = ReturnType<InferFumaDB<typeof LatestDB>['orm']>;
5
-
6
- const SCOPED_METHODS = new Set([
7
- 'create',
8
- 'createMany',
9
- 'findFirst',
10
- 'findMany',
11
- 'count',
12
- 'updateMany',
13
- 'deleteMany',
14
- 'upsert',
15
- 'transaction',
16
- ]);
17
-
18
- /**
19
- * Wraps a FumaDB ORM instance to automatically scope all queries to a specific tenant.
20
- *
21
- * Uses a Proxy so that any ORM method not explicitly handled will throw,
22
- * preventing future methods from silently bypassing tenant scoping.
23
- *
24
- * - `create`/`createMany`: Injects `tenantId` into the data
25
- * - `findFirst`/`findMany`/`count`: Adds `tenantId` filter to the `where` clause
26
- * - `updateMany`/`deleteMany`: Adds `tenantId` filter to the `where` clause
27
- * - `upsert`: Adds `tenantId` filter to the `where` clause and injects into create data
28
- * - `transaction`: Returns a tenant-scoped transaction
29
- *
30
- * When `tenantId` is not set, this function should not be called — the raw ORM is used directly.
31
- */
32
- export function withTenantScope(db: ORM, tenantId: string): ORM {
33
- const scopeWhere = (originalWhere: ((b: any) => any) | undefined, b: any) => {
34
- const tenantFilter = b('tenantId', '=', tenantId);
35
- return originalWhere ? b.and(originalWhere(b), tenantFilter) : tenantFilter;
36
- };
37
-
38
- const scopedMethods: Record<string, (...args: any[]) => any> = {
39
- create: (table: any, data: any) => db.create(table, { ...data, tenantId }),
40
-
41
- createMany: (table: any, items: any[]) =>
42
- db.createMany(
43
- table,
44
- items.map((d: any) => ({ ...d, tenantId }))
45
- ),
46
-
47
- findFirst: (table: any, opts: any) =>
48
- db.findFirst(table, {
49
- ...opts,
50
- where: (b: any) => scopeWhere(opts?.where, b),
51
- }),
52
-
53
- findMany: (table: any, opts?: any) =>
54
- db.findMany(table, {
55
- ...opts,
56
- where: (b: any) => scopeWhere(opts?.where, b),
57
- }),
58
-
59
- count: (table: any, opts?: any) =>
60
- db.count(table, {
61
- ...opts,
62
- where: (b: any) => scopeWhere(opts?.where, b),
63
- }),
64
-
65
- updateMany: (table: any, opts: any) =>
66
- db.updateMany(table, {
67
- ...opts,
68
- where: (b: any) => scopeWhere(opts?.where, b),
69
- }),
70
-
71
- deleteMany: (table: any, opts: any) =>
72
- db.deleteMany(table, {
73
- ...opts,
74
- where: (b: any) => scopeWhere(opts?.where, b),
75
- }),
76
-
77
- upsert: (table: any, opts: any) =>
78
- db.upsert(table, {
79
- ...opts,
80
- where: (b: any) => scopeWhere(opts?.where, b),
81
- create: { ...opts.create, tenantId },
82
- }),
83
-
84
- transaction: (fn: any) =>
85
- db.transaction((tx: any) => fn(withTenantScope(tx, tenantId))),
86
- };
87
-
88
- return new Proxy(db, {
89
- get(_target, prop, _receiver) {
90
- if (typeof prop === 'string' && SCOPED_METHODS.has(prop)) {
91
- return scopedMethods[prop];
92
- }
93
- // Allow symbol access (e.g. Symbol.toStringTag) and standard object props
94
- if (typeof prop === 'symbol') {
95
- return Reflect.get(db, prop);
96
- }
97
- throw new Error(
98
- `withTenantScope: method "${prop}" is not tenant-scoped. ` +
99
- 'Add an explicit scoped wrapper before using it.'
100
- );
101
- },
102
- }) as ORM;
103
- }
@@ -1,5 +0,0 @@
1
- import type { DatabaseOptions } from './types';
2
-
3
- export interface DatabaseConfig extends DatabaseOptions {}
4
-
5
- export const defineConfig = (config: DatabaseConfig) => config;
@@ -1,126 +0,0 @@
1
- /**
2
- * GET /consents/check handler - Pre-banner cross-device consent check.
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import type { Context } from 'hono';
8
- import { HTTPException } from 'hono/http-exception';
9
- import type { C15TContext } from '~/types';
10
- import { extractErrorMessage } from '~/utils/extract-error-message';
11
- import { getMetrics } from '~/utils/metrics';
12
- import { resolveConsentPolicies } from '../utils/consent-enrichment';
13
-
14
- /**
15
- * Handles checking if an externalId has consented to specific policies.
16
- *
17
- * Use this endpoint BEFORE showing consent banners to check if the user
18
- * has already consented on another device.
19
- *
20
- * Returns minimal data (just booleans) for privacy - no subject IDs,
21
- * no consent details, no PII.
22
- */
23
- export const checkConsentHandler = async (c: Context) => {
24
- const ctx = c.get('c15tContext') as C15TContext;
25
- const logger = ctx.logger;
26
- logger.info('Handling GET /consents/check request');
27
-
28
- const { db, registry } = ctx;
29
-
30
- const externalId = c.req.query('externalId');
31
- const type = c.req.query('type');
32
-
33
- if (!externalId) {
34
- throw new HTTPException(422, {
35
- message: 'externalId query parameter is required',
36
- cause: { code: 'EXTERNAL_ID_REQUIRED' },
37
- });
38
- }
39
-
40
- if (!type) {
41
- throw new HTTPException(422, {
42
- message: 'type query parameter is required',
43
- cause: { code: 'TYPE_REQUIRED' },
44
- });
45
- }
46
-
47
- const types = type.split(',').map((t) => t.trim());
48
-
49
- logger.debug('Request parameters', { externalId, types });
50
-
51
- try {
52
- // Find all subjects with this externalId
53
- const subjects = await db.findMany('subject', {
54
- where: (b) => b('externalId', '=', externalId),
55
- });
56
-
57
- const subjectIds = subjects.map((s) => s.id);
58
-
59
- // Initialize results
60
- const results: Record<
61
- string,
62
- { hasConsent: boolean; isLatestPolicy: boolean }
63
- > = {};
64
- for (const t of types) {
65
- results[t] = { hasConsent: false, isLatestPolicy: false };
66
- }
67
-
68
- // If no subjects found, return all false
69
- if (subjectIds.length === 0) {
70
- logger.debug('No subjects found for externalId', { externalId });
71
- return c.json({ results });
72
- }
73
-
74
- // Get all consents for these subjects
75
- const allConsents = await Promise.all(
76
- subjectIds.map((subjectId) =>
77
- db.findMany('consent', {
78
- where: (b) => b('subjectId', '=', subjectId),
79
- })
80
- )
81
- );
82
-
83
- const consents = allConsents.flat();
84
-
85
- const policyInfos = await resolveConsentPolicies(consents, {
86
- db,
87
- registry,
88
- });
89
- for (const info of policyInfos) {
90
- if (!types.includes(info.policyType)) continue;
91
- const entry = results[info.policyType];
92
- if (entry) {
93
- entry.hasConsent = true;
94
- if (info.isLatestPolicy) {
95
- entry.isLatestPolicy = true;
96
- }
97
- }
98
- }
99
-
100
- logger.debug('Consent check results', { externalId, results });
101
-
102
- // Record consent check metrics
103
- const metrics = getMetrics();
104
- if (metrics) {
105
- for (const [type, result] of Object.entries(results)) {
106
- metrics.recordConsentCheck(type, result.hasConsent);
107
- }
108
- }
109
-
110
- return c.json({ results });
111
- } catch (error) {
112
- logger.error('Error in GET /consents/check handler', {
113
- error: extractErrorMessage(error),
114
- errorType: error instanceof Error ? error.constructor.name : typeof error,
115
- });
116
-
117
- if (error instanceof HTTPException) {
118
- throw error;
119
- }
120
-
121
- throw new HTTPException(500, {
122
- message: 'Internal server error',
123
- cause: { code: 'INTERNAL_SERVER_ERROR' },
124
- });
125
- }
126
- };
@@ -1,317 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { checkJurisdiction } from './geo';
3
-
4
- describe('checkJurisdiction', () => {
5
- describe('GDPR jurisdiction (EU countries)', () => {
6
- const euCountries = [
7
- 'AT',
8
- 'BE',
9
- 'BG',
10
- 'HR',
11
- 'CY',
12
- 'CZ',
13
- 'DK',
14
- 'EE',
15
- 'FI',
16
- 'FR',
17
- 'DE',
18
- 'GR',
19
- 'HU',
20
- 'IE',
21
- 'IT',
22
- 'LV',
23
- 'LT',
24
- 'LU',
25
- 'MT',
26
- 'NL',
27
- 'PL',
28
- 'PT',
29
- 'RO',
30
- 'SK',
31
- 'SI',
32
- 'ES',
33
- 'SE',
34
- ];
35
-
36
- it.each(
37
- euCountries
38
- )('should identify %s as GDPR jurisdiction', (countryCode) => {
39
- const jurisdiction = checkJurisdiction(countryCode);
40
-
41
- expect(jurisdiction).toBe('GDPR');
42
- });
43
- });
44
-
45
- describe('GDPR jurisdiction (EEA countries)', () => {
46
- const eeaCountries = ['IS', 'NO', 'LI'];
47
-
48
- it.each(
49
- eeaCountries
50
- )('should identify %s as GDPR jurisdiction', (countryCode) => {
51
- const jurisdiction = checkJurisdiction(countryCode);
52
-
53
- expect(jurisdiction).toBe('GDPR');
54
- });
55
- });
56
-
57
- describe('GDPR jurisdiction (UK)', () => {
58
- it('should identify GB as GDPR jurisdiction', () => {
59
- const jurisdiction = checkJurisdiction('GB');
60
-
61
- expect(jurisdiction).toBe('UK_GDPR');
62
- });
63
- });
64
-
65
- describe('Other specific jurisdictions', () => {
66
- const jurisdictionCases = [
67
- { country: 'CH', code: 'CH' },
68
- { country: 'BR', code: 'BR' },
69
- { country: 'CA', code: 'PIPEDA' },
70
- { country: 'AU', code: 'AU' },
71
- { country: 'JP', code: 'APPI' },
72
- { country: 'KR', code: 'PIPA' },
73
- ] as const;
74
-
75
- it.each(
76
- jurisdictionCases
77
- )('should identify $country as $code jurisdiction', ({ country, code }) => {
78
- const jurisdiction = checkJurisdiction(country);
79
-
80
- expect(jurisdiction).toBe(code);
81
- });
82
- });
83
-
84
- describe('Non-regulated countries', () => {
85
- const nonRegulatedCountries = [
86
- 'US', // United States (outside CCPA regions)
87
- 'RU', // Russia
88
- 'CN', // China
89
- 'IN', // India
90
- 'MX', // Mexico
91
- 'AR', // Argentina
92
- 'EG', // Egypt
93
- 'ZA', // South Africa
94
- 'TH', // Thailand
95
- 'PH', // Philippines
96
- ];
97
-
98
- it.each(
99
- nonRegulatedCountries
100
- )('should identify %s as non-regulated (NONE jurisdiction)', (countryCode) => {
101
- const jurisdiction = checkJurisdiction(countryCode);
102
-
103
- expect(jurisdiction).toBe('NONE');
104
- });
105
- });
106
-
107
- describe('Edge cases', () => {
108
- it('should handle null country code by defaulting to show banner with NONE jurisdiction', () => {
109
- const jurisdiction = checkJurisdiction(null);
110
-
111
- expect(jurisdiction).toBe('NONE');
112
- });
113
-
114
- it('should handle empty string country code by defaulting to show banner with NONE jurisdiction', () => {
115
- const jurisdiction = checkJurisdiction('');
116
-
117
- expect(jurisdiction).toBe('NONE');
118
- });
119
-
120
- it('should handle lowercase country codes correctly', () => {
121
- const jurisdiction = checkJurisdiction('de');
122
-
123
- // Should now match because we normalize to uppercase
124
- expect(jurisdiction).toBe('GDPR');
125
- });
126
-
127
- it('should handle mixed case country codes across different jurisdictions', () => {
128
- const testCases = [
129
- { input: 'de', expectedJurisdiction: 'GDPR' },
130
- { input: 'De', expectedJurisdiction: 'GDPR' },
131
- { input: 'DE', expectedJurisdiction: 'GDPR' },
132
- { input: 'ch', expectedJurisdiction: 'CH' },
133
- { input: 'Ch', expectedJurisdiction: 'CH' },
134
- { input: 'CH', expectedJurisdiction: 'CH' },
135
- { input: 'ca', expectedJurisdiction: 'PIPEDA' },
136
- { input: 'Ca', expectedJurisdiction: 'PIPEDA' },
137
- { input: 'CA', expectedJurisdiction: 'PIPEDA' },
138
- ] as const;
139
-
140
- for (const { input, expectedJurisdiction } of testCases) {
141
- const jurisdiction = checkJurisdiction(input);
142
-
143
- expect(jurisdiction).toBe(expectedJurisdiction);
144
- }
145
- });
146
-
147
- it('should handle invalid country codes', () => {
148
- const invalidCodes = ['XX', 'ZZ', '123', 'ABC'];
149
-
150
- for (const code of invalidCodes) {
151
- const jurisdiction = checkJurisdiction(code);
152
-
153
- expect(jurisdiction).toBe('NONE');
154
- }
155
- });
156
- });
157
-
158
- describe('Return value structure', () => {
159
- it('should always return an object with required properties', () => {
160
- const jurisdiction = checkJurisdiction('DE');
161
-
162
- expect(jurisdiction).toBe('GDPR');
163
- });
164
-
165
- it('should return consistent types regardless of input', () => {
166
- const inputs = ['DE', 'US', 'GB', 'XX', '', null];
167
-
168
- for (const input of inputs) {
169
- const jurisdiction = checkJurisdiction(input);
170
-
171
- expect(typeof jurisdiction).toBe('string');
172
- }
173
- });
174
- });
175
-
176
- describe('Comprehensive jurisdiction mapping', () => {
177
- it('should correctly map all supported jurisdictions', () => {
178
- // Test one representative from each jurisdiction group
179
- const testCases = [
180
- {
181
- input: 'DE',
182
- expectedJurisdiction: 'GDPR' as const,
183
- },
184
- {
185
- input: 'NO',
186
- expectedJurisdiction: 'GDPR' as const,
187
- },
188
- {
189
- input: 'GB',
190
- expectedJurisdiction: 'UK_GDPR' as const,
191
- },
192
- {
193
- input: 'CH',
194
- expectedJurisdiction: 'CH' as const,
195
- },
196
- {
197
- input: 'BR',
198
- expectedJurisdiction: 'BR' as const,
199
- },
200
- {
201
- input: 'CA',
202
- expectedJurisdiction: 'PIPEDA' as const,
203
- },
204
- {
205
- input: 'AU',
206
- expectedJurisdiction: 'AU' as const,
207
- },
208
- {
209
- input: 'JP',
210
- expectedJurisdiction: 'APPI' as const,
211
- },
212
- {
213
- input: 'KR',
214
- expectedJurisdiction: 'PIPA' as const,
215
- },
216
- {
217
- input: 'US',
218
- expectedJurisdiction: 'NONE' as const,
219
- },
220
- {
221
- input: null,
222
- expectedJurisdiction: 'NONE' as const,
223
- },
224
- ];
225
-
226
- for (const { input, expectedJurisdiction } of testCases) {
227
- const jurisdiction = checkJurisdiction(input);
228
-
229
- expect(jurisdiction).toBe(expectedJurisdiction);
230
- }
231
- });
232
- });
233
-
234
- describe('Quebec Law 25 jurisdiction (CA regions)', () => {
235
- it('should identify CA-QC as QC_LAW25 jurisdiction (case-insensitive)', () => {
236
- const cases = ['QC', 'qc', 'Qc'];
237
-
238
- for (const region of cases) {
239
- const jurisdiction = checkJurisdiction('CA', region);
240
-
241
- expect(jurisdiction).toBe('QC_LAW25');
242
- }
243
- });
244
-
245
- it('should handle dash-separated region codes for Quebec', () => {
246
- const cases = ['CA-QC', 'ca-qc', 'Ca-Qc'];
247
-
248
- for (const region of cases) {
249
- const jurisdiction = checkJurisdiction('CA', region);
250
-
251
- expect(jurisdiction).toBe('QC_LAW25');
252
- }
253
- });
254
-
255
- it('should return PIPEDA for non-Quebec Canadian provinces', () => {
256
- const nonQuebecRegions = ['ON', 'BC', 'AB', null];
257
-
258
- for (const region of nonQuebecRegions) {
259
- const jurisdiction = checkJurisdiction('CA', region as string | null);
260
-
261
- expect(jurisdiction).toBe('PIPEDA');
262
- }
263
- });
264
-
265
- it('should return PIPEDA for dash-separated non-Quebec Canadian provinces', () => {
266
- const nonQuebecRegions = ['CA-ON', 'CA-BC', 'CA-AB'];
267
-
268
- for (const region of nonQuebecRegions) {
269
- const jurisdiction = checkJurisdiction('CA', region);
270
-
271
- expect(jurisdiction).toBe('PIPEDA');
272
- }
273
- });
274
- });
275
-
276
- describe('CCPA jurisdiction (US regions)', () => {
277
- it('should identify US-CA as CCPA jurisdiction (case-insensitive)', () => {
278
- const cases = ['CA', 'ca', 'Ca'];
279
-
280
- for (const region of cases) {
281
- const jurisdiction = checkJurisdiction('US', region);
282
-
283
- expect(jurisdiction).toBe('CCPA');
284
- }
285
- });
286
-
287
- it('should handle dash-separated region codes for California', () => {
288
- const cases = ['US-CA', 'us-ca', 'Us-Ca'];
289
-
290
- for (const region of cases) {
291
- const jurisdiction = checkJurisdiction('US', region);
292
-
293
- expect(jurisdiction).toBe('CCPA');
294
- }
295
- });
296
-
297
- it('should not apply CCPA for non-CCPA US regions', () => {
298
- const nonCcpaRegions = ['NY', 'TX', 'WA', 'FL', null];
299
-
300
- for (const region of nonCcpaRegions) {
301
- const jurisdiction = checkJurisdiction('US', region as string | null);
302
-
303
- expect(jurisdiction).toBe('NONE');
304
- }
305
- });
306
-
307
- it('should not apply CCPA for dash-separated non-CCPA US regions', () => {
308
- const nonCcpaRegions = ['US-NY', 'US-TX', 'US-WA'];
309
-
310
- for (const region of nonCcpaRegions) {
311
- const jurisdiction = checkJurisdiction('US', region);
312
-
313
- expect(jurisdiction).toBe('NONE');
314
- }
315
- });
316
- });
317
- });