@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,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.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,105 +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.customTranslations
62
- );
63
-
64
- // Get GVL if enabled
65
- let gvl = null;
66
- if (options.iab?.enabled) {
67
- const language = translationsResult.language.split('-')[0] || 'en';
68
- const gvlResolver = createGVLResolver({
69
- appName: options.appName || 'c15t',
70
- bundled: options.iab.bundled,
71
- cacheAdapter: options.cache?.adapter,
72
- vendorIds: options.iab.vendorIds,
73
- endpoint: options.iab.endpoint,
74
- });
75
- gvl = await gvlResolver.get(language);
76
- }
77
-
78
- // Get custom vendors if configured
79
- const customVendors = options.iab?.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.branding || 'c15t',
95
- gvl,
96
- customVendors,
97
- ...(options.iab?.cmpId != null && {
98
- cmpId: options.iab.cmpId,
99
- }),
100
- });
101
- }
102
- );
103
-
104
- return app;
105
- };
@@ -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`;