@c15t/backend 2.0.0-rc.3 → 2.0.0-rc.5

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