@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,199 +0,0 @@
1
- import type { C15TOptions } from '~/types';
2
-
3
- const DEFAULT_IP_HEADERS = [
4
- 'x-client-ip',
5
- 'x-forwarded-for',
6
- 'cf-connecting-ip',
7
- 'fastly-client-ip',
8
- 'x-real-ip',
9
- 'x-cluster-client-ip',
10
- 'x-forwarded',
11
- 'forwarded-for',
12
- 'forwarded',
13
- ];
14
-
15
- /**
16
- * Expands a compressed IPv6 address to its full form.
17
- * For example: "2001:db8::1" -> "2001:0db8:0000:0000:0000:0000:0000:0001"
18
- */
19
- function expandIPv6(ip: string): string {
20
- // Handle IPv4-mapped IPv6 addresses (e.g., ::ffff:192.168.1.1)
21
- if (ip.includes('.')) {
22
- return ip;
23
- }
24
-
25
- const parts = ip.split(':');
26
- const emptyIndex = parts.indexOf('');
27
-
28
- if (emptyIndex !== -1) {
29
- // Count how many groups we need to insert
30
- const nonEmptyParts = parts.filter((p) => p !== '');
31
- const missingGroups = 8 - nonEmptyParts.length;
32
- const zeros = Array(missingGroups).fill('0000');
33
-
34
- // Handle leading ::
35
- if (emptyIndex === 0) {
36
- parts.shift();
37
- if (parts[0] === '') {
38
- parts.shift();
39
- }
40
- parts.unshift(...zeros);
41
- }
42
- // Handle trailing ::
43
- else if (emptyIndex === parts.length - 1) {
44
- parts.pop();
45
- if (parts[parts.length - 1] === '') {
46
- parts.pop();
47
- }
48
- parts.push(...zeros);
49
- }
50
- // Handle middle ::
51
- else {
52
- parts.splice(emptyIndex, 1, ...zeros);
53
- }
54
- }
55
-
56
- // Pad each group to 4 characters
57
- return parts.map((p) => p.padStart(4, '0')).join(':');
58
- }
59
-
60
- /**
61
- * Compresses an IPv6 address by removing leading zeros and using :: for consecutive zero groups.
62
- */
63
- function compressIPv6(ip: string): string {
64
- // Remove leading zeros from each group
65
- const groups = ip.split(':').map((g) => g.replace(/^0+/, '') || '0');
66
-
67
- // Find the longest run of consecutive zeros
68
- let longestStart = -1;
69
- let longestLength = 0;
70
- let currentStart = -1;
71
- let currentLength = 0;
72
-
73
- for (let i = 0; i < groups.length; i++) {
74
- if (groups[i] === '0') {
75
- if (currentStart === -1) {
76
- currentStart = i;
77
- currentLength = 1;
78
- } else {
79
- currentLength++;
80
- }
81
- } else {
82
- if (currentLength > longestLength) {
83
- longestStart = currentStart;
84
- longestLength = currentLength;
85
- }
86
- currentStart = -1;
87
- currentLength = 0;
88
- }
89
- }
90
-
91
- // Check final run
92
- if (currentLength > longestLength) {
93
- longestStart = currentStart;
94
- longestLength = currentLength;
95
- }
96
-
97
- // Replace longest run with ::
98
- if (longestLength > 1) {
99
- const before = groups.slice(0, longestStart);
100
- const after = groups.slice(longestStart + longestLength);
101
-
102
- if (before.length === 0 && after.length === 0) {
103
- return '::';
104
- }
105
- if (before.length === 0) {
106
- return `::${after.join(':')}`;
107
- }
108
- if (after.length === 0) {
109
- return `${before.join(':')}::`;
110
- }
111
- return `${before.join(':')}::${after.join(':')}`;
112
- }
113
-
114
- return groups.join(':');
115
- }
116
-
117
- /**
118
- * Masks an IP address to reduce PII.
119
- * - IPv4: Replaces last octet with 0 (e.g., 192.168.1.100 -> 192.168.1.0)
120
- * - IPv6: Masks last 80 bits (e.g., 2001:db8:85a3::1 -> 2001:db8:85a3::)
121
- *
122
- * @param ip - The IP address to mask
123
- * @returns The masked IP address
124
- */
125
- export function maskIpAddress(ip: string | null): string | null {
126
- if (!ip) {
127
- return null;
128
- }
129
-
130
- // IPv4 detection (no colons, has dots)
131
- if (ip.includes('.') && !ip.includes(':')) {
132
- const parts = ip.split('.');
133
- if (parts.length === 4) {
134
- parts[3] = '0';
135
- return parts.join('.');
136
- }
137
- return ip;
138
- }
139
-
140
- // IPv6 detection
141
- if (ip.includes(':')) {
142
- // Handle IPv4-mapped IPv6 (::ffff:192.168.1.100)
143
- if (ip.includes('.')) {
144
- const lastColon = ip.lastIndexOf(':');
145
- const ipv4Part = ip.substring(lastColon + 1);
146
- const ipv6Prefix = ip.substring(0, lastColon + 1);
147
-
148
- const ipv4Parts = ipv4Part.split('.');
149
- if (ipv4Parts.length === 4) {
150
- ipv4Parts[3] = '0';
151
- return ipv6Prefix + ipv4Parts.join('.');
152
- }
153
- return ip;
154
- }
155
-
156
- // Pure IPv6 - mask last 80 bits (keep first 48 bits / 3 groups)
157
- const expanded = expandIPv6(ip);
158
- const groups = expanded.split(':');
159
-
160
- // Zero out groups 4-8 (indices 3-7)
161
- for (let i = 3; i < 8; i++) {
162
- groups[i] = '0000';
163
- }
164
-
165
- return compressIPv6(groups.join(':'));
166
- }
167
-
168
- return ip;
169
- }
170
-
171
- export function getIpAddress(
172
- req: Request | Headers,
173
- options: C15TOptions
174
- ): string | null {
175
- const ipAddressConfig = options.advanced?.ipAddress;
176
-
177
- if (ipAddressConfig?.tracking === false) {
178
- return null;
179
- }
180
-
181
- const ipHeaders = ipAddressConfig?.ipAddressHeaders || DEFAULT_IP_HEADERS;
182
-
183
- const headers = req instanceof Request ? req.headers : req;
184
-
185
- for (const key of ipHeaders) {
186
- const value = headers.get(key);
187
- if (value) {
188
- const ip = value.split(',')[0]?.trim();
189
- if (ip) {
190
- if (ipAddressConfig?.masking !== false) {
191
- return maskIpAddress(ip);
192
- }
193
- return ip;
194
- }
195
- }
196
- }
197
-
198
- return null;
199
- }
package/src/router.ts DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Router exports
3
- *
4
- * Note: The router is now integrated into the Hono app in core.ts.
5
- * This file exports the route creators for direct usage.
6
- *
7
- * @packageDocumentation
8
- */
9
-
10
- export {
11
- createConsentRoutes,
12
- createInitRoute,
13
- createStatusRoute,
14
- createSubjectRoutes,
15
- } from './routes';
@@ -1,52 +0,0 @@
1
- /**
2
- * Consent routes - Check consent status.
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import {
8
- checkConsentOutputSchema,
9
- checkConsentQuerySchema,
10
- } from '@c15t/schema';
11
- import { Hono } from 'hono';
12
- import { describeRoute, resolver, validator as vValidator } from 'hono-openapi';
13
- import { checkConsentHandler } from '~/handlers/consent/check.handler';
14
- import type { C15TContext } from '~/types';
15
-
16
- /**
17
- * Creates the consent routes
18
- */
19
- export const createConsentRoutes = () => {
20
- const app = new Hono<{ Variables: { c15tContext: C15TContext } }>();
21
-
22
- // GET /consents/check - Check consent status for an external ID
23
- app.get(
24
- '/check',
25
- describeRoute({
26
- summary: 'Check consent by external user ID',
27
- description: `Pre-banner cross-device consent check. Use to avoid showing the banner when the user has already consented on another device.
28
-
29
- **Query parameters:**
30
- - \`externalId\` – External user ID to check
31
- - \`type\` – Consent type(s) to check (comma-separated)`,
32
- tags: ['Consent'],
33
- responses: {
34
- 200: {
35
- description: 'Consent check result per requested type(s)',
36
- content: {
37
- 'application/json': {
38
- schema: resolver(checkConsentOutputSchema),
39
- },
40
- },
41
- },
42
- 422: {
43
- description: 'Invalid or missing query parameters',
44
- },
45
- },
46
- }),
47
- vValidator('query', checkConsentQuerySchema),
48
- checkConsentHandler
49
- );
50
-
51
- return app;
52
- };
@@ -1,10 +0,0 @@
1
- /**
2
- * Route exports
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- export { createConsentRoutes } from './consent';
8
- export { createInitRoute } from './init';
9
- export { createStatusRoute } from './status';
10
- export { createSubjectRoutes } from './subject';
@@ -1,102 +0,0 @@
1
- /**
2
- * Init route - Initializes the consent manager and returns the initial state.
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import { initOutputSchema } from '@c15t/schema';
8
- import { Hono } from 'hono';
9
- import { describeRoute, resolver } from 'hono-openapi';
10
- import { createGVLResolver } from '~/cache/gvl-resolver';
11
- import { getJurisdiction, getLocation } from '~/handlers/init/geo';
12
- import { getTranslationsData } from '~/handlers/init/translations';
13
- import type { C15TContext, C15TOptions } from '~/types';
14
- import { getMetrics } from '~/utils/metrics';
15
-
16
- /**
17
- * Creates the init route handler
18
- */
19
- export const createInitRoute = (options: C15TOptions) => {
20
- const app = new Hono<{ Variables: { c15tContext: C15TContext } }>();
21
-
22
- app.get(
23
- '/',
24
- describeRoute({
25
- summary: 'Get initial consent manager state',
26
- description: `Returns the initial state required to render the consent manager.
27
-
28
- - **Jurisdiction** – User's jurisdiction (defaults to GDPR if geo-location is disabled)
29
- - **Location** – User's location (null if geo-location is disabled)
30
- - **Translations** – Consent manager copy (from \`Accept-Language\` header)
31
- - **Branding** – Configured branding key
32
- - **GVL** – Global Vendor List when enabled
33
-
34
- Use for geo-targeted consent banners and regional compliance.`,
35
- tags: ['Init'],
36
- responses: {
37
- 200: {
38
- description:
39
- 'Initialization payload (jurisdiction, location, translations, branding, GVL)',
40
- content: {
41
- 'application/json': {
42
- schema: resolver(initOutputSchema),
43
- },
44
- },
45
- },
46
- },
47
- }),
48
- async (c) => {
49
- const request = c.req.raw;
50
-
51
- // Get accept-language header
52
- const acceptLanguage = request.headers.get('accept-language') || 'en';
53
-
54
- // Get location and jurisdiction
55
- const location = await getLocation(request, options);
56
- const jurisdiction = getJurisdiction(location, options);
57
-
58
- // Get translations
59
- const translationsResult = getTranslationsData(
60
- acceptLanguage,
61
- options.advanced?.customTranslations
62
- );
63
-
64
- // Get GVL if enabled
65
- let gvl = null;
66
- if (options.advanced?.gvl?.enabled) {
67
- const language = translationsResult.language.split('-')[0] || 'en';
68
- const gvlResolver = createGVLResolver({
69
- appName: options.appName || 'c15t',
70
- bundled: options.advanced.gvl.bundled,
71
- cacheAdapter: options.advanced.cache?.adapter,
72
- vendorIds: options.advanced.gvl.vendorIds,
73
- endpoint: options.advanced.gvl.endpoint,
74
- });
75
- gvl = await gvlResolver.get(language);
76
- }
77
-
78
- // Get custom vendors if configured
79
- const customVendors = options.advanced?.gvl?.customVendors;
80
-
81
- // Record init metric
82
- const gpc = request.headers.get('sec-gpc') === '1';
83
- getMetrics()?.recordInit({
84
- jurisdiction,
85
- country: location?.countryCode ?? undefined,
86
- region: location?.regionCode ?? undefined,
87
- gpc,
88
- });
89
-
90
- return c.json({
91
- jurisdiction,
92
- location,
93
- translations: translationsResult,
94
- branding: options.advanced?.branding || 'c15t',
95
- gvl,
96
- customVendors,
97
- });
98
- }
99
- );
100
-
101
- return app;
102
- };
@@ -1,46 +0,0 @@
1
- /**
2
- * Status route - Health check and status endpoint.
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import { statusOutputSchema } from '@c15t/schema';
8
- import { Hono } from 'hono';
9
- import { describeRoute, resolver } from 'hono-openapi';
10
- import { statusHandler } from '~/handlers/status/status.handler';
11
- import type { C15TContext } from '~/types';
12
-
13
- /**
14
- * Creates the status route
15
- */
16
- export const createStatusRoute = () => {
17
- const app = new Hono<{ Variables: { c15tContext: C15TContext } }>();
18
-
19
- // GET /status - Health check and status endpoint
20
- app.get(
21
- '/',
22
- describeRoute({
23
- summary: 'Health check and API status',
24
- description: `Returns API version, timestamp, and client info (IP, region, user agent).
25
-
26
- Use for health checks, load balancer probes, and debugging. Performs a lightweight DB check; returns 503 if the database is unreachable.`,
27
- tags: ['Status'],
28
- responses: {
29
- 200: {
30
- description: 'API is healthy (version, timestamp, client info)',
31
- content: {
32
- 'application/json': {
33
- schema: resolver(statusOutputSchema),
34
- },
35
- },
36
- },
37
- 503: {
38
- description: 'Service unavailable (e.g. database unreachable)',
39
- },
40
- },
41
- }),
42
- statusHandler
43
- );
44
-
45
- return app;
46
- };
@@ -1,152 +0,0 @@
1
- /**
2
- * Subject routes - CRUD operations for consent subjects.
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import {
8
- getSubjectInputSchema,
9
- getSubjectOutputSchema,
10
- listSubjectsOutputSchema,
11
- listSubjectsQuerySchema,
12
- patchSubjectOutputSchema,
13
- postSubjectInputSchema,
14
- postSubjectOutputSchema,
15
- subjectIdSchema,
16
- } from '@c15t/schema';
17
- import { Hono } from 'hono';
18
- import { describeRoute, resolver, validator as vValidator } from 'hono-openapi';
19
- import * as v from 'valibot';
20
- import { getSubjectHandler } from '~/handlers/subject/get.handler';
21
- import { listSubjectsHandler } from '~/handlers/subject/list.handler';
22
- import { patchSubjectHandler } from '~/handlers/subject/patch.handler';
23
- import { postSubjectHandler } from '~/handlers/subject/post.handler';
24
- import type { C15TContext } from '~/types';
25
-
26
- /**
27
- * Creates the subject routes
28
- */
29
- export const createSubjectRoutes = () => {
30
- const app = new Hono<{ Variables: { c15tContext: C15TContext } }>();
31
-
32
- // GET /subjects/:id - Get a subject's consent status
33
- app.get(
34
- '/:id',
35
- describeRoute({
36
- summary: 'Get subject consent status',
37
- description: `Returns the subject's consent status for this device. Use to check if the subject has valid consent for given policy types.
38
-
39
- **Query:** \`type\` – Filter by consent type(s), comma-separated (e.g. \`privacy_policy,cookie_banner\`).
40
-
41
- **Response:** \`subject\`, \`consents\` (matching filter), \`isValid\` (valid consent for requested type(s)).`,
42
- tags: ['Subject', 'Consent'],
43
- responses: {
44
- 200: {
45
- description: 'Subject and consent records for the requested type(s)',
46
- content: {
47
- 'application/json': {
48
- schema: resolver(getSubjectOutputSchema),
49
- },
50
- },
51
- },
52
- 404: {
53
- description: 'Subject not found for the given ID',
54
- },
55
- },
56
- }),
57
- vValidator('param', getSubjectInputSchema),
58
- getSubjectHandler
59
- );
60
-
61
- // POST /subjects - Create a new consent record
62
- app.post(
63
- '/',
64
- describeRoute({
65
- summary: 'Record consent for a subject',
66
- description: `Creates a new consent record (append-only). Creates the subject if it does not exist.
67
-
68
- **Request body by \`type\`:**
69
- - \`cookie_banner\` – Requires \`preferences\` object
70
- - \`privacy_policy\`, \`dpa\`, \`terms_and_conditions\` – Optional \`policyId\`
71
- - \`marketing_communications\`, \`age_verification\`, \`other\` – Optional \`preferences\``,
72
- tags: ['Subject', 'Consent'],
73
- responses: {
74
- 200: {
75
- description: 'Consent recorded; subject and consent in response',
76
- content: {
77
- 'application/json': {
78
- schema: resolver(postSubjectOutputSchema),
79
- },
80
- },
81
- },
82
- 422: {
83
- description: 'Invalid request body (schema or validation failed)',
84
- },
85
- },
86
- }),
87
- vValidator('json', postSubjectInputSchema),
88
- postSubjectHandler
89
- );
90
-
91
- // PATCH /subjects/:id - Link external ID to subject
92
- app.patch(
93
- '/:id',
94
- describeRoute({
95
- summary: 'Link external ID to subject',
96
- description:
97
- 'Associates an external user ID with an existing subject (e.g. after login). Enables cross-device consent sync.',
98
- tags: ['Subject'],
99
- responses: {
100
- 200: {
101
- description: 'Subject updated with external ID',
102
- content: {
103
- 'application/json': {
104
- schema: resolver(patchSubjectOutputSchema),
105
- },
106
- },
107
- },
108
- 404: {
109
- description: 'Subject not found for the given ID',
110
- },
111
- },
112
- }),
113
- vValidator('param', v.object({ id: subjectIdSchema })),
114
- vValidator(
115
- 'json',
116
- v.object({
117
- externalId: v.string(),
118
- identityProvider: v.optional(v.string()),
119
- })
120
- ),
121
- patchSubjectHandler
122
- );
123
-
124
- // GET /subjects - List all subjects by external ID (requires API key)
125
- app.get(
126
- '/',
127
- describeRoute({
128
- summary: 'List subjects by external ID (API key required)',
129
- description:
130
- 'Returns all subjects linked to the given external ID. Requires Bearer token (API key). Use for server-side consent lookups.',
131
- tags: ['Subject'],
132
- security: [{ bearerAuth: [] }],
133
- responses: {
134
- 200: {
135
- description: 'List of subjects for the external ID',
136
- content: {
137
- 'application/json': {
138
- schema: resolver(listSubjectsOutputSchema),
139
- },
140
- },
141
- },
142
- 401: {
143
- description: 'Missing or invalid API key',
144
- },
145
- },
146
- }),
147
- vValidator('query', listSubjectsQuerySchema),
148
- listSubjectsHandler
149
- );
150
-
151
- return app;
152
- };
package/src/types/api.ts DELETED
@@ -1,48 +0,0 @@
1
- /**
2
- * Jurisdiction code type for privacy regulations
3
- */
4
- export type JurisdictionCode =
5
- | 'UK_GDPR' // United Kingdom's GDPR
6
- | 'GDPR' // European Union's GDPR (includes EEA)
7
- | 'CH'
8
- | 'BR'
9
- | 'PIPEDA'
10
- | 'AU'
11
- | 'APPI'
12
- | 'PIPA'
13
- | 'CCPA'
14
- | 'QC_LAW25' // Quebec's Bill 25
15
- | 'NONE';
16
-
17
- /**
18
- * Base API path template literal for c15t consent endpoints
19
- *
20
- * This type defines the base path for all consent API routes in the c15t system.
21
- * Used as a foundation for building type-safe consent API route paths.
22
- *
23
- * @see ApiPath for complete path patterns
24
- */
25
- export type ApiPathBase = `/api/c15t`;
26
-
27
- /**
28
- * Consent API route path with strict type checking
29
- *
30
- * This type union represents all valid consent API paths in the system.
31
- * It enforces type safety when defining routes or middlewares to
32
- * prevent typos and ensure consistency.
33
- *
34
- * @example
35
- * ```ts
36
- * // Valid consent API path
37
- * const consentPath: ApiPath = '/api/c15t/consent';
38
- *
39
- * // Invalid - would cause a type error
40
- * const invalidPath: ApiPath = '/api/c15t/unknown-endpoint';
41
- * ```
42
- */
43
- export type ApiPath =
44
- | `${ApiPathBase}`
45
- | `${ApiPathBase}/consent`
46
- | `${ApiPathBase}/consent/:id`
47
- | `${ApiPathBase}/jurisdictions`
48
- | `${ApiPathBase}/jurisdictions/:code`;