@c15t/backend 2.0.0-rc.4 → 2.0.0-rc.6

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 (327) hide show
  1. package/dist/302.js +473 -0
  2. package/dist/364.js +1140 -0
  3. package/dist/583.js +540 -0
  4. package/dist/cache.cjs +1 -1
  5. package/dist/cache.js +4 -415
  6. package/dist/core.cjs +849 -96
  7. package/dist/core.js +147 -1817
  8. package/dist/db/adapters/drizzle.cjs +1 -1
  9. package/dist/db/adapters/drizzle.js +1 -2
  10. package/dist/db/adapters/kysely.cjs +1 -1
  11. package/dist/db/adapters/kysely.js +1 -2
  12. package/dist/db/adapters/mongo.cjs +1 -1
  13. package/dist/db/adapters/mongo.js +1 -2
  14. package/dist/db/adapters/prisma.cjs +1 -1
  15. package/dist/db/adapters/prisma.js +1 -2
  16. package/dist/db/adapters/typeorm.cjs +1 -1
  17. package/dist/db/adapters/typeorm.js +1 -2
  18. package/dist/db/adapters.cjs +1 -1
  19. package/dist/db/migrator.cjs +1 -1
  20. package/dist/db/schema.cjs +38 -1
  21. package/dist/db/schema.js +33 -2
  22. package/dist/define-config.cjs +1 -1
  23. package/dist/edge.cjs +1106 -0
  24. package/dist/edge.js +190 -0
  25. package/dist/router.cjs +629 -81
  26. package/dist/router.js +1 -1509
  27. package/dist/types/index.cjs +1 -1
  28. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  29. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  30. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  31. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  32. package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
  33. package/{dist → dist-types}/cache/index.d.ts +0 -1
  34. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  35. package/{dist → dist-types}/cache/types.d.ts +0 -1
  36. package/{dist → dist-types}/core.d.ts +8 -1
  37. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  38. package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
  39. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  40. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  41. package/{dist → dist-types}/db/registry/index.d.ts +22 -2
  42. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  43. package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
  44. package/{dist → dist-types}/db/registry/types.d.ts +1 -2
  45. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  46. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  47. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  48. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  49. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  50. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  51. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +2 -3
  52. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  53. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
  54. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
  55. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +2 -3
  56. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +2 -3
  57. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +2 -3
  58. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +6 -3
  59. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +2 -3
  60. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
  61. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  62. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +2 -3
  63. package/{dist → dist-types}/db/schema/index.d.ts +862 -33
  64. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  65. package/{dist → dist-types}/define-config.d.ts +0 -1
  66. package/dist-types/edge/index.d.ts +5 -0
  67. package/dist-types/edge/init-handler.d.ts +38 -0
  68. package/dist-types/edge/resolve-consent.d.ts +80 -0
  69. package/dist-types/edge/types.d.ts +13 -0
  70. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  71. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  72. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  73. package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
  74. package/dist-types/handlers/init/policy.d.ts +26 -0
  75. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  76. package/dist-types/handlers/init/translations.d.ts +48 -0
  77. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  78. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  79. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  80. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
  81. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  82. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
  83. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
  84. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  85. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
  86. package/{dist → dist-types}/init.d.ts +0 -1
  87. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  88. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  89. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  90. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  91. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
  92. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  93. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  94. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  95. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  96. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  97. package/dist-types/policies/builder.d.ts +127 -0
  98. package/dist-types/policies/defaults.d.ts +2 -0
  99. package/dist-types/policies/matchers.d.ts +3 -0
  100. package/{dist → dist-types}/router.d.ts +0 -1
  101. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  102. package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
  103. package/{dist → dist-types}/routes/init.d.ts +0 -1
  104. package/{dist → dist-types}/routes/status.d.ts +0 -1
  105. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  106. package/{dist → dist-types}/types/api.d.ts +0 -1
  107. package/{dist → dist-types}/types/index.d.ts +110 -6
  108. package/dist-types/utils/background.d.ts +6 -0
  109. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +0 -1
  110. package/{dist → dist-types}/utils/env.d.ts +0 -1
  111. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  112. package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
  113. package/{dist → dist-types}/utils/logger.d.ts +1 -2
  114. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  115. package/dist-types/version.d.ts +1 -0
  116. package/docs/README.md +49 -0
  117. package/docs/api/configuration.md +197 -0
  118. package/docs/api/endpoints.md +211 -0
  119. package/docs/guides/caching.md +85 -0
  120. package/docs/guides/database-setup.md +128 -0
  121. package/docs/guides/edge-deployment.md +248 -0
  122. package/docs/guides/framework-integration.md +142 -0
  123. package/docs/guides/iab-tcf.md +89 -0
  124. package/docs/guides/observability.md +96 -0
  125. package/docs/guides/policy-packs.md +396 -0
  126. package/docs/quickstart.md +129 -0
  127. package/package.json +45 -31
  128. package/.turbo/turbo-build.log +0 -49
  129. package/CHANGELOG.md +0 -123
  130. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  131. package/dist/cache/adapters/index.d.ts.map +0 -1
  132. package/dist/cache/adapters/memory.d.ts.map +0 -1
  133. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  134. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  135. package/dist/cache/index.d.ts.map +0 -1
  136. package/dist/cache/keys.d.ts.map +0 -1
  137. package/dist/cache/types.d.ts.map +0 -1
  138. package/dist/core.d.ts.map +0 -1
  139. package/dist/db/adapters/drizzle.d.ts +0 -2
  140. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  141. package/dist/db/adapters/index.d.ts +0 -2
  142. package/dist/db/adapters/index.d.ts.map +0 -1
  143. package/dist/db/adapters/kysely.d.ts +0 -2
  144. package/dist/db/adapters/kysely.d.ts.map +0 -1
  145. package/dist/db/adapters/mongo.d.ts +0 -2
  146. package/dist/db/adapters/mongo.d.ts.map +0 -1
  147. package/dist/db/adapters/prisma.d.ts +0 -2
  148. package/dist/db/adapters/prisma.d.ts.map +0 -1
  149. package/dist/db/adapters/typeorm.d.ts +0 -2
  150. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  151. package/dist/db/migrator/index.d.ts.map +0 -1
  152. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  153. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  154. package/dist/db/registry/domain.d.ts.map +0 -1
  155. package/dist/db/registry/index.d.ts.map +0 -1
  156. package/dist/db/registry/subject.d.ts.map +0 -1
  157. package/dist/db/registry/types.d.ts.map +0 -1
  158. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  159. package/dist/db/registry/utils.d.ts.map +0 -1
  160. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  161. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  162. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  163. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  164. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  165. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  166. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  167. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  168. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  169. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  170. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  171. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  172. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  173. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  174. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  175. package/dist/db/schema/index.d.ts.map +0 -1
  176. package/dist/db/tenant-scope.d.ts.map +0 -1
  177. package/dist/define-config.d.ts.map +0 -1
  178. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  179. package/dist/handlers/consent/index.d.ts +0 -12
  180. package/dist/handlers/consent/index.d.ts.map +0 -1
  181. package/dist/handlers/init/geo.d.ts.map +0 -1
  182. package/dist/handlers/init/index.d.ts.map +0 -1
  183. package/dist/handlers/init/translations.d.ts +0 -26
  184. package/dist/handlers/init/translations.d.ts.map +0 -1
  185. package/dist/handlers/status/index.d.ts +0 -7
  186. package/dist/handlers/status/index.d.ts.map +0 -1
  187. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  188. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  189. package/dist/handlers/subject/index.d.ts +0 -10
  190. package/dist/handlers/subject/index.d.ts.map +0 -1
  191. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  192. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  193. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  194. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  195. package/dist/init.d.ts.map +0 -1
  196. package/dist/middleware/auth/index.d.ts.map +0 -1
  197. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  198. package/dist/middleware/cors/cors.d.ts.map +0 -1
  199. package/dist/middleware/cors/index.d.ts +0 -30
  200. package/dist/middleware/cors/index.d.ts.map +0 -1
  201. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  202. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  203. package/dist/middleware/openapi/config.d.ts.map +0 -1
  204. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  205. package/dist/middleware/openapi/index.d.ts +0 -12
  206. package/dist/middleware/openapi/index.d.ts.map +0 -1
  207. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  208. package/dist/router.d.ts.map +0 -1
  209. package/dist/routes/consent.d.ts.map +0 -1
  210. package/dist/routes/index.d.ts +0 -10
  211. package/dist/routes/index.d.ts.map +0 -1
  212. package/dist/routes/init.d.ts.map +0 -1
  213. package/dist/routes/status.d.ts.map +0 -1
  214. package/dist/routes/subject.d.ts.map +0 -1
  215. package/dist/types/api.d.ts.map +0 -1
  216. package/dist/types/index.d.ts.map +0 -1
  217. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  218. package/dist/utils/env.d.ts.map +0 -1
  219. package/dist/utils/extract-error-message.d.ts.map +0 -1
  220. package/dist/utils/index.d.ts +0 -4
  221. package/dist/utils/index.d.ts.map +0 -1
  222. package/dist/utils/instrumentation.d.ts.map +0 -1
  223. package/dist/utils/logger.d.ts.map +0 -1
  224. package/dist/utils/metrics.d.ts.map +0 -1
  225. package/dist/version.d.ts +0 -2
  226. package/dist/version.d.ts.map +0 -1
  227. package/knip.json +0 -31
  228. package/rslib.config.ts +0 -93
  229. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  230. package/src/cache/adapters/index.ts +0 -22
  231. package/src/cache/adapters/memory.ts +0 -111
  232. package/src/cache/adapters/upstash-redis.ts +0 -113
  233. package/src/cache/gvl-resolver.ts +0 -289
  234. package/src/cache/index.ts +0 -34
  235. package/src/cache/keys.ts +0 -68
  236. package/src/cache/types.ts +0 -66
  237. package/src/core.ts +0 -369
  238. package/src/db/migrator/index.ts +0 -80
  239. package/src/db/registry/consent-policy.test.ts +0 -451
  240. package/src/db/registry/consent-policy.ts +0 -82
  241. package/src/db/registry/consent-purpose.test.ts +0 -428
  242. package/src/db/registry/consent-purpose.ts +0 -61
  243. package/src/db/registry/domain.test.ts +0 -445
  244. package/src/db/registry/domain.ts +0 -91
  245. package/src/db/registry/index.ts +0 -14
  246. package/src/db/registry/subject.test.ts +0 -371
  247. package/src/db/registry/subject.ts +0 -126
  248. package/src/db/registry/types.ts +0 -10
  249. package/src/db/registry/utils/generate-id.test.ts +0 -216
  250. package/src/db/registry/utils/generate-id.ts +0 -133
  251. package/src/db/registry/utils.ts +0 -133
  252. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  253. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  254. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  255. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  256. package/src/db/schema/1.0.0/consent.ts +0 -20
  257. package/src/db/schema/1.0.0/domain.ts +0 -12
  258. package/src/db/schema/1.0.0/index.ts +0 -48
  259. package/src/db/schema/1.0.0/subject.ts +0 -11
  260. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  261. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  262. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  263. package/src/db/schema/2.0.0/consent.ts +0 -28
  264. package/src/db/schema/2.0.0/domain.ts +0 -12
  265. package/src/db/schema/2.0.0/index.ts +0 -47
  266. package/src/db/schema/2.0.0/subject.ts +0 -13
  267. package/src/db/schema/index.ts +0 -15
  268. package/src/db/tenant-scope.test.ts +0 -747
  269. package/src/db/tenant-scope.ts +0 -103
  270. package/src/define-config.ts +0 -19
  271. package/src/handlers/consent/check.handler.ts +0 -126
  272. package/src/handlers/init/geo.test.ts +0 -317
  273. package/src/handlers/init/geo.ts +0 -195
  274. package/src/handlers/init/index.test.ts +0 -205
  275. package/src/handlers/init/index.ts +0 -114
  276. package/src/handlers/init/translations.test.ts +0 -121
  277. package/src/handlers/init/translations.ts +0 -69
  278. package/src/handlers/status/status.handler.test.ts +0 -155
  279. package/src/handlers/status/status.handler.ts +0 -51
  280. package/src/handlers/subject/get.handler.ts +0 -92
  281. package/src/handlers/subject/list.handler.ts +0 -92
  282. package/src/handlers/subject/patch.handler.ts +0 -119
  283. package/src/handlers/subject/post.handler.test.ts +0 -294
  284. package/src/handlers/subject/post.handler.ts +0 -268
  285. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  286. package/src/handlers/utils/consent-enrichment.ts +0 -218
  287. package/src/init.test.ts +0 -122
  288. package/src/init.ts +0 -88
  289. package/src/middleware/auth/index.ts +0 -11
  290. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  291. package/src/middleware/auth/validate-api-key.ts +0 -107
  292. package/src/middleware/cors/cors.test.ts +0 -135
  293. package/src/middleware/cors/cors.ts +0 -186
  294. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  295. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  296. package/src/middleware/cors/process-cors.ts +0 -91
  297. package/src/middleware/openapi/config.ts +0 -29
  298. package/src/middleware/openapi/handlers.ts +0 -34
  299. package/src/middleware/process-ip/index.test.ts +0 -193
  300. package/src/middleware/process-ip/index.ts +0 -199
  301. package/src/router.ts +0 -15
  302. package/src/routes/consent.ts +0 -52
  303. package/src/routes/init.ts +0 -105
  304. package/src/routes/status.ts +0 -46
  305. package/src/routes/subject.ts +0 -152
  306. package/src/types/api.ts +0 -48
  307. package/src/types/index.ts +0 -391
  308. package/src/utils/create-telemetry-options.test.ts +0 -286
  309. package/src/utils/create-telemetry-options.ts +0 -229
  310. package/src/utils/env.ts +0 -84
  311. package/src/utils/extract-error-message.ts +0 -21
  312. package/src/utils/instrumentation.test.ts +0 -183
  313. package/src/utils/instrumentation.ts +0 -194
  314. package/src/utils/logger.ts +0 -41
  315. package/src/utils/metrics.test.ts +0 -311
  316. package/src/utils/metrics.ts +0 -402
  317. package/src/utils/telemetry-pii.test.ts +0 -323
  318. package/src/version.ts +0 -2
  319. package/tsconfig.json +0 -11
  320. package/vitest.config.ts +0 -28
  321. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  322. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  323. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  324. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  325. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  326. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  327. /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,19 +0,0 @@
1
- import type { C15TOptions } from './types';
2
-
3
- /**
4
- * c15t backend config accepted by `defineConfig`.
5
- *
6
- * Keep this as an intersection with `C15TOptions` (instead of `Omit`) so
7
- * TypeScript preserves property-level JSDoc in editor completions.
8
- */
9
- export type C15TConfig = C15TOptions & {
10
- /**
11
- * Logger config is managed internally and is not supported via config files.
12
- */
13
- logger?: never;
14
- };
15
-
16
- /**
17
- * Helper for typed backend configuration in `c15t-backend.config.ts`.
18
- */
19
- export const defineConfig = (config: C15TConfig) => 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
- });