@c15t/backend 2.0.0-rc.1 → 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 +51 -37
  132. package/.turbo/turbo-build.log +0 -49
  133. package/CHANGELOG.md +0 -99
  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
package/dist/core.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
- "./src/db/schema/index.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3
+ "./src/db/schema/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
4
  __webpack_require__.d(__webpack_exports__, {
5
5
  DB: ()=>DB
6
6
  });
@@ -79,7 +79,6 @@ var __webpack_modules__ = {
79
79
  });
80
80
  const subjectTable = (0, schema_namespaceObject.table)('subject', {
81
81
  id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
82
- isIdentified: (0, schema_namespaceObject.column)('isIdentified', 'bool').defaultTo$(()=>false),
83
82
  externalId: (0, schema_namespaceObject.column)('externalId', 'string').nullable(),
84
83
  identityProvider: (0, schema_namespaceObject.column)('identityProvider', 'string').nullable(),
85
84
  lastIpAddress: (0, schema_namespaceObject.column)('lastIpAddress', 'string').nullable(),
@@ -172,12 +171,16 @@ var __webpack_modules__ = {
172
171
  jurisdictionModel: (0, schema_namespaceObject.column)('jurisdictionModel', 'string').nullable(),
173
172
  tcString: (0, schema_namespaceObject.column)('tcString', 'string').nullable(),
174
173
  uiSource: (0, schema_namespaceObject.column)('uiSource', 'string').nullable(),
174
+ consentAction: (0, schema_namespaceObject.column)('consentAction', 'string').nullable(),
175
+ runtimePolicyDecisionId: (0, schema_namespaceObject.column)('runtimePolicyDecisionId', 'string').nullable(),
176
+ runtimePolicySource: (0, schema_namespaceObject.column)('runtimePolicySource', 'string').nullable(),
175
177
  tenantId: (0, schema_namespaceObject.column)('tenantId', 'string').nullable()
176
178
  });
177
179
  const consent_policy_consentPolicyTable = (0, schema_namespaceObject.table)('consentPolicy', {
178
180
  id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
179
181
  version: (0, schema_namespaceObject.column)('version', 'string'),
180
182
  type: (0, schema_namespaceObject.column)('type', 'string'),
183
+ hash: (0, schema_namespaceObject.column)('hash', 'string').nullable(),
181
184
  effectiveDate: (0, schema_namespaceObject.column)('effectiveDate', 'timestamp'),
182
185
  isActive: (0, schema_namespaceObject.column)('isActive', 'bool').defaultTo$(()=>true),
183
186
  createdAt: (0, schema_namespaceObject.column)('createdAt', 'timestamp').defaultTo$('now'),
@@ -197,9 +200,29 @@ var __webpack_modules__ = {
197
200
  updatedAt: (0, schema_namespaceObject.column)('updatedAt', 'timestamp').defaultTo$('now'),
198
201
  tenantId: (0, schema_namespaceObject.column)('tenantId', 'string').nullable()
199
202
  });
203
+ const runtimePolicyDecisionTable = (0, schema_namespaceObject.table)('runtimePolicyDecision', {
204
+ id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
205
+ tenantId: (0, schema_namespaceObject.column)('tenantId', 'string').nullable(),
206
+ policyId: (0, schema_namespaceObject.column)('policyId', 'string'),
207
+ fingerprint: (0, schema_namespaceObject.column)('fingerprint', 'string'),
208
+ matchedBy: (0, schema_namespaceObject.column)('matchedBy', 'string'),
209
+ countryCode: (0, schema_namespaceObject.column)('countryCode', 'string').nullable(),
210
+ regionCode: (0, schema_namespaceObject.column)('regionCode', 'string').nullable(),
211
+ jurisdiction: (0, schema_namespaceObject.column)('jurisdiction', 'string'),
212
+ language: (0, schema_namespaceObject.column)('language', 'string').nullable(),
213
+ model: (0, schema_namespaceObject.column)('model', 'string'),
214
+ policyI18n: (0, schema_namespaceObject.column)('policyI18n', 'json').nullable(),
215
+ uiMode: (0, schema_namespaceObject.column)('uiMode', 'string').nullable(),
216
+ bannerUi: (0, schema_namespaceObject.column)('bannerUi', 'json').nullable(),
217
+ dialogUi: (0, schema_namespaceObject.column)('dialogUi', 'json').nullable(),
218
+ categories: (0, schema_namespaceObject.column)('categories', 'json').nullable(),
219
+ preselectedCategories: (0, schema_namespaceObject.column)('preselectedCategories', 'json').nullable(),
220
+ proofConfig: (0, schema_namespaceObject.column)('proofConfig', 'json').nullable(),
221
+ dedupeKey: (0, schema_namespaceObject.column)('dedupeKey', 'string').unique(),
222
+ createdAt: (0, schema_namespaceObject.column)('createdAt', 'timestamp').defaultTo$('now')
223
+ });
200
224
  const subject_subjectTable = (0, schema_namespaceObject.table)('subject', {
201
225
  id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
202
- isIdentified: (0, schema_namespaceObject.column)('isIdentified', 'bool').defaultTo$(()=>false),
203
226
  externalId: (0, schema_namespaceObject.column)('externalId', 'string').nullable(),
204
227
  identityProvider: (0, schema_namespaceObject.column)('identityProvider', 'string').nullable(),
205
228
  createdAt: (0, schema_namespaceObject.column)('createdAt', 'timestamp').defaultTo$('now'),
@@ -212,6 +235,7 @@ var __webpack_modules__ = {
212
235
  subject: subject_subjectTable,
213
236
  domain: domain_domainTable,
214
237
  consentPolicy: consent_policy_consentPolicyTable,
238
+ runtimePolicyDecision: runtimePolicyDecisionTable,
215
239
  consentPurpose: consent_purpose_consentPurposeTable,
216
240
  consent: consent_consentTable,
217
241
  auditLog: audit_log_auditLogTable
@@ -227,6 +251,9 @@ var __webpack_modules__ = {
227
251
  consentPolicy: ({ many })=>({
228
252
  consents: many('consent')
229
253
  }),
254
+ runtimePolicyDecision: ({ many })=>({
255
+ consents: many('consent')
256
+ }),
230
257
  consentPurpose: ()=>({}),
231
258
  consent: ({ one })=>({
232
259
  subject: one('subject', [
@@ -240,6 +267,10 @@ var __webpack_modules__ = {
240
267
  policy: one('consentPolicy', [
241
268
  'policyId',
242
269
  'id'
270
+ ]).foreignKey(),
271
+ runtimePolicyDecision: one('runtimePolicyDecision', [
272
+ 'runtimePolicyDecisionId',
273
+ 'id'
243
274
  ]).foreignKey()
244
275
  }),
245
276
  auditLog: ({ one })=>({
@@ -264,7 +295,7 @@ var __webpack_modules__ = {
264
295
  ]
265
296
  });
266
297
  },
267
- "./src/define-config.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
298
+ "./src/define-config.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
268
299
  __webpack_require__.d(__webpack_exports__, {
269
300
  defineConfig: ()=>defineConfig
270
301
  });
@@ -306,7 +337,7 @@ function __webpack_require__(moduleId) {
306
337
  })();
307
338
  (()=>{
308
339
  __webpack_require__.r = (exports1)=>{
309
- if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
340
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
310
341
  value: 'Module'
311
342
  });
312
343
  Object.defineProperty(exports1, '__esModule', {
@@ -320,7 +351,15 @@ var __webpack_exports__ = {};
320
351
  __webpack_require__.d(__webpack_exports__, {
321
352
  version: ()=>version_version,
322
353
  c15tInstance: ()=>c15tInstance,
323
- defineConfig: ()=>define_config.defineConfig
354
+ EEA_COUNTRY_CODES: ()=>types_namespaceObject.EEA_COUNTRY_CODES,
355
+ EU_COUNTRY_CODES: ()=>types_namespaceObject.EU_COUNTRY_CODES,
356
+ UK_COUNTRY_CODES: ()=>types_namespaceObject.UK_COUNTRY_CODES,
357
+ policyMatchers: ()=>types_namespaceObject.policyMatchers,
358
+ policyBuilder: ()=>policyBuilder,
359
+ policyPackPresets: ()=>schema_.policyPackPresets,
360
+ inspectPolicies: ()=>inspectPolicies,
361
+ defineConfig: ()=>define_config.defineConfig,
362
+ POLICY_MATCH_DATASET_VERSION: ()=>types_namespaceObject.POLICY_MATCH_DATASET_VERSION
324
363
  });
325
364
  const logger_namespaceObject = require("@c15t/logger");
326
365
  const api_namespaceObject = require("@opentelemetry/api");
@@ -455,10 +494,10 @@ var __webpack_exports__ = {};
455
494
  };
456
495
  }
457
496
  const createOpenAPIConfig = (options)=>({
458
- enabled: options.advanced?.openapi?.enabled !== false,
497
+ enabled: options.openapi?.enabled !== false,
459
498
  specPath: '/spec.json',
460
499
  docsPath: '/docs',
461
- ...options.advanced?.openapi || {}
500
+ ...options.openapi || {}
462
501
  });
463
502
  const DEFAULT_IP_HEADERS = [
464
503
  'x-client-ip',
@@ -553,7 +592,7 @@ var __webpack_exports__ = {};
553
592
  return ip;
554
593
  }
555
594
  function getIpAddress(req, options) {
556
- const ipAddressConfig = options.advanced?.ipAddress;
595
+ const ipAddressConfig = options.ipAddress;
557
596
  if (ipAddressConfig?.tracking === false) return null;
558
597
  const ipHeaders = ipAddressConfig?.ipAddressHeaders || DEFAULT_IP_HEADERS;
559
598
  const headers = req instanceof Request ? req.headers : req;
@@ -569,7 +608,137 @@ var __webpack_exports__ = {};
569
608
  }
570
609
  return null;
571
610
  }
572
- const version_version = '2.0.0-rc.1';
611
+ const types_namespaceObject = require("@c15t/schema/types");
612
+ const translations_namespaceObject = require("@c15t/translations");
613
+ const all_namespaceObject = require("@c15t/translations/all");
614
+ const DEFAULT_PROFILE = 'default';
615
+ const warnedKeys = new Set();
616
+ function isSupportedBaseLanguage(lang) {
617
+ return lang in all_namespaceObject.baseTranslations;
618
+ }
619
+ function warnOnce(logger, key, message, metadata) {
620
+ if (!logger || warnedKeys.has(key)) return;
621
+ warnedKeys.add(key);
622
+ logger.warn(message, metadata);
623
+ }
624
+ function normalizeLanguage(value) {
625
+ if (!value) return;
626
+ const normalized = value.split(',')[0]?.split(';')[0]?.trim().toLowerCase();
627
+ if (!normalized) return;
628
+ return normalized.split('-')[0] ?? void 0;
629
+ }
630
+ function normalizeProfiles(params) {
631
+ const profiles = params.i18n?.messages;
632
+ const legacy = params.customTranslations;
633
+ if (profiles && Object.keys(profiles).length > 0) {
634
+ if (legacy && Object.keys(legacy).length > 0) warnOnce(params.logger, 'i18n.customTranslations.ignored', '`customTranslations` is deprecated and ignored when `i18n.messages` is configured.');
635
+ return profiles;
636
+ }
637
+ if (legacy && Object.keys(legacy).length > 0) {
638
+ warnOnce(params.logger, 'i18n.customTranslations.deprecated', '`customTranslations` is deprecated. Use `i18n.messages` instead.');
639
+ return {
640
+ [DEFAULT_PROFILE]: {
641
+ translations: legacy
642
+ }
643
+ };
644
+ }
645
+ return {};
646
+ }
647
+ function buildCandidates(input) {
648
+ const raw = [
649
+ {
650
+ language: input.language,
651
+ reason: 'profile_language'
652
+ },
653
+ {
654
+ language: input.fallbackLanguage,
655
+ reason: 'profile_fallback'
656
+ }
657
+ ];
658
+ const dedupe = new Set();
659
+ return raw.filter((candidate)=>{
660
+ const key = candidate.language;
661
+ if (dedupe.has(key)) return false;
662
+ dedupe.add(key);
663
+ return true;
664
+ });
665
+ }
666
+ function getProfileLanguages(profiles, profile) {
667
+ return Object.keys(profiles[profile]?.translations ?? {}).sort();
668
+ }
669
+ function getSelectableLanguages(input) {
670
+ return getProfileLanguages(input.profiles, input.profile);
671
+ }
672
+ function resolveFallbackLanguage(input) {
673
+ const configuredFallbackLanguage = normalizeLanguage(input.profile?.fallbackLanguage) ?? 'en';
674
+ const profileLanguages = Object.keys(input.profile?.translations ?? {}).sort();
675
+ if (profileLanguages.includes(configuredFallbackLanguage)) return configuredFallbackLanguage;
676
+ if (profileLanguages.includes('en')) return 'en';
677
+ return profileLanguages[0] ?? configuredFallbackLanguage;
678
+ }
679
+ function resolveActiveProfile(input) {
680
+ const requestedProfile = input.policyProfile ?? input.defaultProfile;
681
+ if (input.profiles[requestedProfile]) return requestedProfile;
682
+ if (input.policyProfile) warnOnce(input.logger, `i18n.profile.missing:${requestedProfile}`, `Policy i18n profile '${requestedProfile}' does not exist. Falling back to default profile '${input.defaultProfile}'.`);
683
+ return input.defaultProfile;
684
+ }
685
+ function validateMessages(options) {
686
+ return (0, types_namespaceObject.validatePolicyI18nConfig)({
687
+ customTranslations: options.customTranslations,
688
+ i18n: options.i18n,
689
+ policies: options.policies
690
+ });
691
+ }
692
+ function translations_getTranslationsData(acceptLanguage, customTranslations, options) {
693
+ const profiles = normalizeProfiles({
694
+ customTranslations,
695
+ i18n: options?.i18n,
696
+ logger: options?.logger
697
+ });
698
+ const defaultProfile = options?.i18n?.defaultProfile ?? DEFAULT_PROFILE;
699
+ const profile = resolveActiveProfile({
700
+ profiles,
701
+ defaultProfile,
702
+ policyProfile: options?.policyI18n?.messageProfile,
703
+ logger: options?.logger
704
+ });
705
+ const configuredLanguages = Object.keys(profiles).length > 0 ? getSelectableLanguages({
706
+ profiles,
707
+ profile
708
+ }) : Object.keys(all_namespaceObject.baseTranslations);
709
+ const fallbackLanguage = Object.keys(profiles).length > 0 ? resolveFallbackLanguage({
710
+ profile: profiles[profile]
711
+ }) : 'en';
712
+ const policyLanguage = normalizeLanguage(options?.policyI18n?.language);
713
+ const requestedLanguage = policyLanguage ?? (0, translations_namespaceObject.selectLanguage)(configuredLanguages, {
714
+ header: acceptLanguage,
715
+ fallback: fallbackLanguage
716
+ });
717
+ const candidates = buildCandidates({
718
+ language: requestedLanguage,
719
+ fallbackLanguage
720
+ });
721
+ const selectedCandidate = candidates.find((candidate)=>!!profiles[profile]?.translations[candidate.language]);
722
+ if (selectedCandidate && 'profile_language' !== selectedCandidate.reason) warnOnce(options?.logger, `i18n.fallback:${profile}:${requestedLanguage}:${selectedCandidate.language}`, `Policy translation fallback used (${selectedCandidate.reason}).`, {
723
+ requestedProfile: profile,
724
+ requestedLanguage,
725
+ resolvedProfile: profile,
726
+ resolvedLanguage: selectedCandidate.language
727
+ });
728
+ let language = selectedCandidate?.language ?? requestedLanguage;
729
+ if (!selectedCandidate && !isSupportedBaseLanguage(language)) {
730
+ warnOnce(options?.logger, `i18n.base-fallback:${language}`, `No translation found for '${language}'. Falling back to base English translations.`);
731
+ language = 'en';
732
+ }
733
+ const base = isSupportedBaseLanguage(language) ? all_namespaceObject.baseTranslations[language] : all_namespaceObject.baseTranslations.en;
734
+ const custom = selectedCandidate ? profiles[profile]?.translations[selectedCandidate.language] : void 0;
735
+ const translations = custom ? (0, translations_namespaceObject.deepMergeTranslations)(base, custom) : base;
736
+ return {
737
+ translations: translations,
738
+ language
739
+ };
740
+ }
741
+ const version_version = '2.0.0-rc.10';
573
742
  function extractErrorMessage(error) {
574
743
  if (error instanceof AggregateError && error.errors?.length > 0) {
575
744
  const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
@@ -598,18 +767,18 @@ var __webpack_exports__ = {};
598
767
  return config;
599
768
  }
600
769
  function isTelemetryEnabled(options) {
601
- if (options) return options.advanced?.telemetry?.enabled === true;
770
+ if (options) return options.telemetry?.enabled === true;
602
771
  return cachedConfig?.enabled === true;
603
772
  }
604
773
  const getTracer = (options)=>{
605
774
  if (!isTelemetryEnabled(options)) return api_namespaceObject.trace.getTracer('c15t-noop');
606
- const tracer = options?.advanced?.telemetry?.tracer ?? cachedConfig?.tracer;
775
+ const tracer = options?.telemetry?.tracer ?? cachedConfig?.tracer;
607
776
  if (tracer) return tracer;
608
777
  return api_namespaceObject.trace.getTracer(options?.appName ?? 'c15t');
609
778
  };
610
779
  const getMeter = (options)=>{
611
780
  if (!isTelemetryEnabled(options)) return api_namespaceObject.metrics.getMeter('c15t-noop');
612
- const meter = options?.advanced?.telemetry?.meter ?? cachedConfig?.meter;
781
+ const meter = options?.telemetry?.meter ?? cachedConfig?.meter;
613
782
  if (meter) return meter;
614
783
  return api_namespaceObject.metrics.getMeter(options?.appName ?? 'c15t');
615
784
  };
@@ -619,7 +788,7 @@ var __webpack_exports__ = {};
619
788
  const createRequestSpan = (method, path, options)=>{
620
789
  if (!isTelemetryEnabled(options)) return null;
621
790
  const tracer = getTracer(options);
622
- const defaultAttrs = options?.advanced?.telemetry?.defaultAttributes || getDefaultAttributes();
791
+ const defaultAttrs = options?.telemetry?.defaultAttributes || getDefaultAttributes();
623
792
  const span = tracer.startSpan(`${method} ${path}`, {
624
793
  attributes: {
625
794
  'http.method': method,
@@ -661,7 +830,7 @@ var __webpack_exports__ = {};
661
830
  }
662
831
  }
663
832
  function resolveDefaultAttributes(options) {
664
- return options?.advanced?.telemetry?.defaultAttributes || getDefaultAttributes();
833
+ return options?.telemetry?.defaultAttributes || getDefaultAttributes();
665
834
  }
666
835
  async function withDatabaseSpan(attributes, operation, options) {
667
836
  if (!isTelemetryEnabled(options)) return operation();
@@ -894,6 +1063,7 @@ var __webpack_exports__ = {};
894
1063
  consentPolicy: 'pol',
895
1064
  consentPurpose: 'pur',
896
1065
  domain: 'dom',
1066
+ runtimePolicyDecision: 'rpd',
897
1067
  subject: 'sub'
898
1068
  };
899
1069
  const b58 = external_base_x_default()('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
@@ -963,6 +1133,23 @@ var __webpack_exports__ = {};
963
1133
  throw error;
964
1134
  }
965
1135
  }
1136
+ class LegalDocumentPolicyConflictError extends Error {
1137
+ constructor(message){
1138
+ super(message);
1139
+ this.name = 'LegalDocumentPolicyConflictError';
1140
+ }
1141
+ }
1142
+ async function buildLegalDocumentPolicyId(input) {
1143
+ const digest = await (0, types_namespaceObject.hashSha256Hex)([
1144
+ input.tenantId ?? 'default',
1145
+ input.type,
1146
+ input.hash
1147
+ ].join('|'));
1148
+ return `pol_${digest}`;
1149
+ }
1150
+ function hasLegalDocumentPolicyConflict(policy, input) {
1151
+ return policy.version !== input.version || policy.hash !== input.hash || policy.effectiveDate.getTime() !== input.effectiveDate.getTime();
1152
+ }
966
1153
  function policyRegistry({ db, ctx }) {
967
1154
  const { logger } = ctx;
968
1155
  return {
@@ -991,6 +1178,176 @@ var __webpack_exports__ = {};
991
1178
  throw error;
992
1179
  }
993
1180
  },
1181
+ findLatestPolicyByType: async (type)=>{
1182
+ const start = Date.now();
1183
+ try {
1184
+ const result = await withDatabaseSpan({
1185
+ operation: 'findLatest',
1186
+ entity: 'consentPolicy'
1187
+ }, async ()=>db.findFirst('consentPolicy', {
1188
+ where: (b)=>b.and(b('isActive', '=', true), b('type', '=', type)),
1189
+ orderBy: [
1190
+ 'effectiveDate',
1191
+ 'desc'
1192
+ ]
1193
+ }));
1194
+ getMetrics()?.recordDbQuery({
1195
+ operation: 'findLatest',
1196
+ entity: 'consentPolicy'
1197
+ }, Date.now() - start);
1198
+ return result;
1199
+ } catch (error) {
1200
+ getMetrics()?.recordDbError({
1201
+ operation: 'findLatest',
1202
+ entity: 'consentPolicy'
1203
+ });
1204
+ throw error;
1205
+ }
1206
+ },
1207
+ findLegalDocumentPolicyByHash: async (type, hash)=>{
1208
+ const start = Date.now();
1209
+ try {
1210
+ const policyId = await buildLegalDocumentPolicyId({
1211
+ tenantId: ctx.tenantId,
1212
+ type,
1213
+ hash
1214
+ });
1215
+ const result = await withDatabaseSpan({
1216
+ operation: 'findByHash',
1217
+ entity: 'consentPolicy'
1218
+ }, async ()=>db.findFirst('consentPolicy', {
1219
+ where: (b)=>b('id', '=', policyId)
1220
+ }));
1221
+ getMetrics()?.recordDbQuery({
1222
+ operation: 'findByHash',
1223
+ entity: 'consentPolicy'
1224
+ }, Date.now() - start);
1225
+ return result;
1226
+ } catch (error) {
1227
+ getMetrics()?.recordDbError({
1228
+ operation: 'findByHash',
1229
+ entity: 'consentPolicy'
1230
+ });
1231
+ throw error;
1232
+ }
1233
+ },
1234
+ syncCurrentLegalDocumentPolicy: async (input)=>{
1235
+ const start = Date.now();
1236
+ try {
1237
+ const result = await withDatabaseSpan({
1238
+ operation: 'syncCurrent',
1239
+ entity: 'consentPolicy'
1240
+ }, async ()=>{
1241
+ const policyId = await buildLegalDocumentPolicyId({
1242
+ tenantId: ctx.tenantId,
1243
+ type: input.type,
1244
+ hash: input.hash
1245
+ });
1246
+ return db.transaction(async (tx)=>{
1247
+ const existing = await tx.findFirst('consentPolicy', {
1248
+ where: (b)=>b('id', '=', policyId)
1249
+ });
1250
+ if (existing) {
1251
+ if (hasLegalDocumentPolicyConflict(existing, input)) throw new LegalDocumentPolicyConflictError('Release metadata conflicts with existing consent policy');
1252
+ await tx.updateMany('consentPolicy', {
1253
+ where: (b)=>b.and(b('type', '=', input.type), b('isActive', '=', true), b('id', '!=', existing.id)),
1254
+ set: {
1255
+ isActive: false
1256
+ }
1257
+ });
1258
+ if (!existing.isActive) {
1259
+ await tx.updateMany('consentPolicy', {
1260
+ where: (b)=>b('id', '=', existing.id),
1261
+ set: {
1262
+ isActive: true
1263
+ }
1264
+ });
1265
+ return {
1266
+ ...existing,
1267
+ isActive: true
1268
+ };
1269
+ }
1270
+ return existing;
1271
+ }
1272
+ await tx.updateMany('consentPolicy', {
1273
+ where: (b)=>b.and(b('type', '=', input.type), b('isActive', '=', true)),
1274
+ set: {
1275
+ isActive: false
1276
+ }
1277
+ });
1278
+ const policy = await tx.create('consentPolicy', {
1279
+ id: policyId,
1280
+ version: input.version,
1281
+ type: input.type,
1282
+ hash: input.hash,
1283
+ effectiveDate: input.effectiveDate,
1284
+ isActive: true
1285
+ });
1286
+ return policy;
1287
+ });
1288
+ });
1289
+ getMetrics()?.recordDbQuery({
1290
+ operation: 'syncCurrent',
1291
+ entity: 'consentPolicy'
1292
+ }, Date.now() - start);
1293
+ return result;
1294
+ } catch (error) {
1295
+ getMetrics()?.recordDbError({
1296
+ operation: 'syncCurrent',
1297
+ entity: 'consentPolicy'
1298
+ });
1299
+ throw error;
1300
+ }
1301
+ },
1302
+ findOrCreateLegalDocumentPolicy: async (input)=>{
1303
+ const start = Date.now();
1304
+ try {
1305
+ const result = await withDatabaseSpan({
1306
+ operation: 'findOrCreateLegalDocument',
1307
+ entity: 'consentPolicy'
1308
+ }, async ()=>{
1309
+ const policyId = await buildLegalDocumentPolicyId({
1310
+ tenantId: ctx.tenantId,
1311
+ type: input.type,
1312
+ hash: input.hash
1313
+ });
1314
+ const existing = await db.findFirst('consentPolicy', {
1315
+ where: (b)=>b('id', '=', policyId)
1316
+ });
1317
+ if (existing) {
1318
+ if (hasLegalDocumentPolicyConflict(existing, input)) throw new LegalDocumentPolicyConflictError('Release metadata conflicts with existing consent policy');
1319
+ return existing;
1320
+ }
1321
+ const policy = await db.create('consentPolicy', {
1322
+ id: policyId,
1323
+ version: input.version,
1324
+ type: input.type,
1325
+ hash: input.hash,
1326
+ effectiveDate: input.effectiveDate,
1327
+ isActive: false
1328
+ }).catch(async ()=>{
1329
+ const concurrent = await db.findFirst('consentPolicy', {
1330
+ where: (b)=>b('id', '=', policyId)
1331
+ });
1332
+ if (!concurrent) throw new LegalDocumentPolicyConflictError('Failed to create legal document consent policy');
1333
+ if (hasLegalDocumentPolicyConflict(concurrent, input)) throw new LegalDocumentPolicyConflictError('Release metadata conflicts with existing consent policy');
1334
+ return concurrent;
1335
+ });
1336
+ return policy;
1337
+ });
1338
+ getMetrics()?.recordDbQuery({
1339
+ operation: 'findOrCreateLegalDocument',
1340
+ entity: 'consentPolicy'
1341
+ }, Date.now() - start);
1342
+ return result;
1343
+ } catch (error) {
1344
+ getMetrics()?.recordDbError({
1345
+ operation: 'findOrCreateLegalDocument',
1346
+ entity: 'consentPolicy'
1347
+ });
1348
+ throw error;
1349
+ }
1350
+ },
994
1351
  findOrCreatePolicy: async (type)=>{
995
1352
  const start = Date.now();
996
1353
  try {
@@ -1165,6 +1522,54 @@ var __webpack_exports__ = {};
1165
1522
  }
1166
1523
  };
1167
1524
  }
1525
+ function runtimePolicyDecisionRegistry({ db, ctx }) {
1526
+ const { logger } = ctx;
1527
+ return {
1528
+ findOrCreateRuntimePolicyDecision: async (input)=>{
1529
+ const existing = await db.findFirst('runtimePolicyDecision', {
1530
+ where: (b)=>b('dedupeKey', '=', input.dedupeKey)
1531
+ });
1532
+ if (existing) return existing;
1533
+ logger.debug('Creating runtime policy decision', {
1534
+ policyId: input.policyId,
1535
+ fingerprint: input.fingerprint,
1536
+ matchedBy: input.matchedBy
1537
+ });
1538
+ return db.create('runtimePolicyDecision', {
1539
+ id: `rpd_${crypto.randomUUID().replaceAll('-', '')}`,
1540
+ tenantId: input.tenantId,
1541
+ policyId: input.policyId,
1542
+ fingerprint: input.fingerprint,
1543
+ matchedBy: input.matchedBy,
1544
+ countryCode: input.countryCode,
1545
+ regionCode: input.regionCode,
1546
+ jurisdiction: input.jurisdiction,
1547
+ language: input.language,
1548
+ model: input.model,
1549
+ policyI18n: input.policyI18n ? {
1550
+ json: input.policyI18n
1551
+ } : void 0,
1552
+ uiMode: input.uiMode,
1553
+ bannerUi: input.bannerUi ? {
1554
+ json: input.bannerUi
1555
+ } : void 0,
1556
+ dialogUi: input.dialogUi ? {
1557
+ json: input.dialogUi
1558
+ } : void 0,
1559
+ categories: input.categories ? {
1560
+ json: input.categories
1561
+ } : void 0,
1562
+ preselectedCategories: input.preselectedCategories ? {
1563
+ json: input.preselectedCategories
1564
+ } : void 0,
1565
+ proofConfig: input.proofConfig ? {
1566
+ json: input.proofConfig
1567
+ } : void 0,
1568
+ dedupeKey: input.dedupeKey
1569
+ });
1570
+ }
1571
+ };
1572
+ }
1168
1573
  function subjectRegistry({ db, ctx }) {
1169
1574
  const { logger } = ctx;
1170
1575
  return {
@@ -1194,8 +1599,7 @@ var __webpack_exports__ = {};
1194
1599
  const newSubject = await db.create('subject', {
1195
1600
  id: subjectId,
1196
1601
  externalId: externalSubjectId ?? null,
1197
- identityProvider: externalSubjectId ? identityProvider ?? 'external' : 'anonymous',
1198
- isIdentified: !!externalSubjectId
1602
+ identityProvider: externalSubjectId ? identityProvider ?? 'external' : 'anonymous'
1199
1603
  });
1200
1604
  logger.debug('Created new subject', {
1201
1605
  subject: newSubject
@@ -1209,8 +1613,7 @@ var __webpack_exports__ = {};
1209
1613
  const subject = await db.create('subject', {
1210
1614
  id: await generateUniqueId(db, 'subject', ctx),
1211
1615
  externalId: externalSubjectId,
1212
- identityProvider: identityProvider ?? 'external',
1213
- isIdentified: true
1616
+ identityProvider: identityProvider ?? 'external'
1214
1617
  });
1215
1618
  return subject;
1216
1619
  }
@@ -1218,8 +1621,7 @@ var __webpack_exports__ = {};
1218
1621
  const subject = await db.create('subject', {
1219
1622
  id: await generateUniqueId(db, 'subject', ctx),
1220
1623
  externalId: null,
1221
- identityProvider: 'anonymous',
1222
- isIdentified: false
1624
+ identityProvider: 'anonymous'
1223
1625
  });
1224
1626
  logger.debug('Created new anonymous subject', {
1225
1627
  subject
@@ -1245,7 +1647,8 @@ var __webpack_exports__ = {};
1245
1647
  ...subjectRegistry(ctx),
1246
1648
  ...consentPurposeRegistry(ctx),
1247
1649
  ...policyRegistry(ctx),
1248
- ...domainRegistry(ctx)
1650
+ ...domainRegistry(ctx),
1651
+ ...runtimePolicyDecisionRegistry(ctx)
1249
1652
  });
1250
1653
  var schema = __webpack_require__("./src/db/schema/index.ts");
1251
1654
  const SCOPED_METHODS = new Set([
@@ -1311,6 +1714,18 @@ var __webpack_exports__ = {};
1311
1714
  }
1312
1715
  });
1313
1716
  }
1717
+ function inspectPolicies(policies, options) {
1718
+ return (0, types_namespaceObject.inspectPolicies)(policies, options);
1719
+ }
1720
+ async function resolvePolicyDecision(params) {
1721
+ return (0, types_namespaceObject.resolvePolicyDecision)({
1722
+ policies: params.policies,
1723
+ countryCode: params.countryCode,
1724
+ regionCode: params.regionCode,
1725
+ jurisdiction: params.jurisdiction,
1726
+ iabEnabled: params.iabEnabled
1727
+ });
1728
+ }
1314
1729
  let globalLogger;
1315
1730
  function initLogger(options) {
1316
1731
  globalLogger = (0, logger_namespaceObject.createLogger)({
@@ -1325,7 +1740,7 @@ var __webpack_exports__ = {};
1325
1740
  ...options.logger,
1326
1741
  appName: String(appName)
1327
1742
  });
1328
- const telemetryOptions = createTelemetryOptions(String(appName), options.advanced?.telemetry, options.tenantId);
1743
+ const telemetryOptions = createTelemetryOptions(String(appName), options.telemetry, options.tenantId);
1329
1744
  if (isTelemetryEnabled(options)) logger.debug('Telemetry is enabled', {
1330
1745
  hasTracer: !!telemetryOptions?.tracer,
1331
1746
  hasMeter: !!telemetryOptions?.meter,
@@ -1336,15 +1751,29 @@ var __webpack_exports__ = {};
1336
1751
  const client = db.client(options.adapter);
1337
1752
  const rawOrm = client.orm('2.0.0');
1338
1753
  const orm = options.tenantId ? withTenantScope(rawOrm, options.tenantId) : rawOrm;
1754
+ const { ipAddress: _ipAddressConfig, ...baseOptions } = options;
1755
+ const i18nValidation = validateMessages({
1756
+ i18n: options.i18n,
1757
+ customTranslations: options.customTranslations,
1758
+ policies: options.policyPacks
1759
+ });
1760
+ for (const warning of i18nValidation.warnings)logger.warn(`i18n: ${warning}`);
1761
+ if (i18nValidation.errors.length > 0) throw new Error(`Invalid i18n configuration:\n${i18nValidation.errors.map((error)=>`- ${error}`).join('\n')}`);
1762
+ const policyValidation = inspectPolicies(options.policyPacks ?? [], {
1763
+ iabEnabled: options.iab?.enabled === true
1764
+ });
1765
+ for (const warning of policyValidation.warnings)logger.warn(`policyPacks: ${warning}`);
1766
+ if (policyValidation.errors.length > 0) throw new Error(policyValidation.errors[0]);
1339
1767
  const context = {
1340
- ...options,
1768
+ ...baseOptions,
1341
1769
  appName,
1342
1770
  logger,
1343
1771
  db: orm,
1344
1772
  registry: createRegistry({
1345
1773
  db: orm,
1346
1774
  ctx: {
1347
- logger
1775
+ logger,
1776
+ tenantId: options.tenantId
1348
1777
  }
1349
1778
  })
1350
1779
  };
@@ -1371,7 +1800,7 @@ var __webpack_exports__ = {};
1371
1800
  for (const p of policyMap.values())uniqueTypes.add(p.type);
1372
1801
  const latestPolicyByType = new Map();
1373
1802
  for (const type of uniqueTypes){
1374
- const latest = await registry.findOrCreatePolicy(type);
1803
+ const latest = await registry.findLatestPolicyByType(type);
1375
1804
  if (latest) latestPolicyByType.set(type, latest.id);
1376
1805
  }
1377
1806
  return {
@@ -1397,11 +1826,17 @@ var __webpack_exports__ = {};
1397
1826
  }
1398
1827
  return consents.map((consent)=>{
1399
1828
  let policyType = 'unknown';
1829
+ let policyVersion;
1830
+ let policyHash;
1831
+ let policyEffectiveDate;
1400
1832
  let isLatestPolicy = false;
1401
1833
  if (consent.policyId) {
1402
1834
  const policy = policyMap.get(consent.policyId);
1403
1835
  if (policy) {
1404
1836
  policyType = policy.type;
1837
+ policyVersion = policy.version;
1838
+ policyHash = policy.hash ?? void 0;
1839
+ policyEffectiveDate = policy.effectiveDate;
1405
1840
  isLatestPolicy = latestPolicyByType.get(policyType) === consent.policyId;
1406
1841
  }
1407
1842
  }
@@ -1418,6 +1853,9 @@ var __webpack_exports__ = {};
1418
1853
  id: consent.id,
1419
1854
  type: policyType,
1420
1855
  policyId: consent.policyId ?? void 0,
1856
+ policyVersion,
1857
+ policyHash,
1858
+ policyEffectiveDate,
1421
1859
  isLatestPolicy,
1422
1860
  preferences,
1423
1861
  givenAt: consent.givenAt
@@ -1532,11 +1970,7 @@ var __webpack_exports__ = {};
1532
1970
  const app = new external_hono_namespaceObject.Hono();
1533
1971
  app.get('/check', (0, external_hono_openapi_namespaceObject.describeRoute)({
1534
1972
  summary: 'Check consent by external user ID',
1535
- description: `Pre-banner cross-device consent check. Use to avoid showing the banner when the user has already consented on another device.
1536
-
1537
- **Query parameters:**
1538
- - \`externalId\` – External user ID to check
1539
- - \`type\` – Consent type(s) to check (comma-separated)`,
1973
+ description: "Pre-banner cross-device consent check. Use to avoid showing the banner when the user has already consented on another device.\n\n**Query parameters:**\n- `externalId` – External user ID to check\n- `type` – Consent type(s) to check (comma-separated)",
1540
1974
  tags: [
1541
1975
  'Consent'
1542
1976
  ],
@@ -1696,6 +2130,124 @@ var __webpack_exports__ = {};
1696
2130
  }
1697
2131
  };
1698
2132
  }
2133
+ const external_jose_namespaceObject = require("jose");
2134
+ const POLICY_SNAPSHOT_JWT_HEADER = {
2135
+ alg: 'HS256',
2136
+ typ: 'JWT'
2137
+ };
2138
+ const DEFAULT_POLICY_SNAPSHOT_ISSUER = 'c15t';
2139
+ const DEFAULT_POLICY_SNAPSHOT_AUDIENCE = 'c15t-policy-snapshot';
2140
+ function resolveSnapshotIssuer(options) {
2141
+ return options?.issuer?.trim() || DEFAULT_POLICY_SNAPSHOT_ISSUER;
2142
+ }
2143
+ function resolveSnapshotAudience(params) {
2144
+ const configuredAudience = params.options?.audience?.trim();
2145
+ if (configuredAudience) return configuredAudience;
2146
+ return params.tenantId ? `${DEFAULT_POLICY_SNAPSHOT_AUDIENCE}:${params.tenantId}` : DEFAULT_POLICY_SNAPSHOT_AUDIENCE;
2147
+ }
2148
+ function getSigningKey(secret) {
2149
+ return new TextEncoder().encode(secret);
2150
+ }
2151
+ function isPolicySnapshotPayload(payload) {
2152
+ return 'string' == typeof payload.policyId && 'string' == typeof payload.fingerprint && 'string' == typeof payload.matchedBy && 'string' == typeof payload.jurisdiction && 'string' == typeof payload.model && 'string' == typeof payload.iss && 'string' == typeof payload.aud && 'string' == typeof payload.sub && 'number' == typeof payload.iat && 'number' == typeof payload.exp;
2153
+ }
2154
+ async function createPolicySnapshotToken(params) {
2155
+ const { options } = params;
2156
+ if (!options?.signingKey) return;
2157
+ const iat = Math.floor(Date.now() / 1000);
2158
+ const ttlSeconds = options.ttlSeconds ?? 1800;
2159
+ const exp = iat + ttlSeconds;
2160
+ const iss = resolveSnapshotIssuer(options);
2161
+ const aud = resolveSnapshotAudience({
2162
+ options,
2163
+ tenantId: params.tenantId
2164
+ });
2165
+ const payload = {
2166
+ iss,
2167
+ aud,
2168
+ sub: params.policyId,
2169
+ tenantId: params.tenantId,
2170
+ policyId: params.policyId,
2171
+ fingerprint: params.fingerprint,
2172
+ matchedBy: params.matchedBy,
2173
+ country: params.country,
2174
+ region: params.region,
2175
+ jurisdiction: params.jurisdiction,
2176
+ language: params.language,
2177
+ model: params.model,
2178
+ policyI18n: params.policyI18n,
2179
+ expiryDays: params.expiryDays,
2180
+ scopeMode: params.scopeMode,
2181
+ uiMode: params.uiMode,
2182
+ bannerUi: params.bannerUi,
2183
+ dialogUi: params.dialogUi,
2184
+ categories: params.categories,
2185
+ preselectedCategories: params.preselectedCategories,
2186
+ gpc: params.gpc,
2187
+ proofConfig: params.proofConfig,
2188
+ iat,
2189
+ exp
2190
+ };
2191
+ const token = await new external_jose_namespaceObject.SignJWT(payload).setProtectedHeader(POLICY_SNAPSHOT_JWT_HEADER).setIssuedAt(iat).setExpirationTime(exp).sign(getSigningKey(options.signingKey));
2192
+ return {
2193
+ token,
2194
+ payload
2195
+ };
2196
+ }
2197
+ async function verifyPolicySnapshotToken(params) {
2198
+ const { token, options, tenantId } = params;
2199
+ if (!options?.signingKey) return {
2200
+ valid: false,
2201
+ reason: 'missing'
2202
+ };
2203
+ if (!token) return {
2204
+ valid: false,
2205
+ reason: 'missing'
2206
+ };
2207
+ if (3 !== token.split('.').length) return {
2208
+ valid: false,
2209
+ reason: 'malformed'
2210
+ };
2211
+ try {
2212
+ const { payload, protectedHeader } = await (0, external_jose_namespaceObject.jwtVerify)(token, getSigningKey(options.signingKey), {
2213
+ issuer: resolveSnapshotIssuer(options),
2214
+ audience: resolveSnapshotAudience({
2215
+ options,
2216
+ tenantId
2217
+ })
2218
+ });
2219
+ const header = protectedHeader;
2220
+ if ('HS256' !== header.alg || 'JWT' !== header.typ) return {
2221
+ valid: false,
2222
+ reason: 'invalid'
2223
+ };
2224
+ if (!isPolicySnapshotPayload(payload)) return {
2225
+ valid: false,
2226
+ reason: 'invalid'
2227
+ };
2228
+ if (payload.sub !== payload.policyId) return {
2229
+ valid: false,
2230
+ reason: 'invalid'
2231
+ };
2232
+ if ((tenantId ?? void 0) !== (payload.tenantId ?? void 0)) return {
2233
+ valid: false,
2234
+ reason: 'invalid'
2235
+ };
2236
+ return {
2237
+ valid: true,
2238
+ payload
2239
+ };
2240
+ } catch (error) {
2241
+ if (error instanceof external_jose_namespaceObject.errors.JWTExpired) return {
2242
+ valid: false,
2243
+ reason: 'expired'
2244
+ };
2245
+ return {
2246
+ valid: false,
2247
+ reason: 'invalid'
2248
+ };
2249
+ }
2250
+ }
1699
2251
  function geo_normalizeHeader(value) {
1700
2252
  if (!value) return null;
1701
2253
  return Array.isArray(value) ? value[0] ?? null : value;
@@ -1837,7 +2389,7 @@ var __webpack_exports__ = {};
1837
2389
  return jurisdiction;
1838
2390
  }
1839
2391
  async function getLocation(request, options) {
1840
- if (options.advanced?.disableGeoLocation) return {
2392
+ if (options.disableGeoLocation) return {
1841
2393
  countryCode: null,
1842
2394
  regionCode: null
1843
2395
  };
@@ -1848,30 +2400,121 @@ var __webpack_exports__ = {};
1848
2400
  };
1849
2401
  }
1850
2402
  function getJurisdiction(location, options) {
1851
- if (options.advanced?.disableGeoLocation) return 'GDPR';
2403
+ if (options.disableGeoLocation) return 'GDPR';
1852
2404
  return checkJurisdiction(location.countryCode, location.regionCode);
1853
2405
  }
1854
- const translations_namespaceObject = require("@c15t/translations");
1855
- function isSupportedBaseLanguage(lang) {
1856
- return lang in translations_namespaceObject.baseTranslations;
1857
- }
1858
- function translations_getTranslationsData(acceptLanguage, customTranslations) {
1859
- const supportedDefaultLanguages = Object.keys(translations_namespaceObject.baseTranslations);
1860
- const supportedCustomLanguages = Object.keys(customTranslations || {});
1861
- const supportedLanguages = [
1862
- ...supportedDefaultLanguages,
1863
- ...supportedCustomLanguages
1864
- ];
1865
- const preferredLanguage = (0, translations_namespaceObject.selectLanguage)(supportedLanguages, {
1866
- header: acceptLanguage,
1867
- fallback: 'en'
2406
+ function stripIabTranslations(translations) {
2407
+ const { iab: _iab, ...rest } = translations;
2408
+ return rest;
2409
+ }
2410
+ function resolveNoPolicyFallback() {
2411
+ return {
2412
+ id: 'no_banner',
2413
+ model: 'none',
2414
+ ui: {
2415
+ mode: 'none'
2416
+ }
2417
+ };
2418
+ }
2419
+ async function resolveInitPayload(request, options, logger) {
2420
+ const acceptLanguage = request.headers.get('accept-language') || 'en';
2421
+ const location = await getLocation(request, options);
2422
+ const jurisdiction = getJurisdiction(location, options);
2423
+ const hasExplicitPolicyPack = void 0 !== options.policyPacks;
2424
+ const isExplicitEmptyPolicyPack = hasExplicitPolicyPack && (options.policyPacks?.length ?? 0) === 0;
2425
+ const policyDecision = isExplicitEmptyPolicyPack ? void 0 : await resolvePolicyDecision({
2426
+ policies: options.policyPacks,
2427
+ countryCode: location.countryCode,
2428
+ regionCode: location.regionCode,
2429
+ jurisdiction,
2430
+ iabEnabled: options.iab?.enabled === true
2431
+ });
2432
+ if (hasExplicitPolicyPack && !isExplicitEmptyPolicyPack && !policyDecision) logger?.warn('Policy packs configured but no policy matched', {
2433
+ country: location.countryCode,
2434
+ region: location.regionCode
2435
+ });
2436
+ const resolvedPolicy = hasExplicitPolicyPack ? policyDecision?.policy ?? resolveNoPolicyFallback() : void 0;
2437
+ const iabOptions = options.iab;
2438
+ const shouldIncludeIabPayload = iabOptions?.enabled === true && (!hasExplicitPolicyPack || resolvedPolicy?.model === 'iab');
2439
+ const translationsResult = translations_getTranslationsData(acceptLanguage, options.customTranslations, {
2440
+ i18n: options.i18n,
2441
+ policyI18n: resolvedPolicy?.i18n,
2442
+ logger
2443
+ });
2444
+ const responseTranslations = shouldIncludeIabPayload ? translationsResult : {
2445
+ ...translationsResult,
2446
+ translations: stripIabTranslations(translationsResult.translations)
2447
+ };
2448
+ let gvl = null;
2449
+ if (shouldIncludeIabPayload && iabOptions) {
2450
+ const language = translationsResult.language.split('-')[0] || 'en';
2451
+ const gvlResolver = createGVLResolver({
2452
+ appName: options.appName || 'c15t',
2453
+ bundled: iabOptions.bundled,
2454
+ cacheAdapter: options.cache?.adapter,
2455
+ vendorIds: iabOptions.vendorIds,
2456
+ endpoint: iabOptions.endpoint
2457
+ });
2458
+ gvl = await gvlResolver.get(language);
2459
+ }
2460
+ const customVendors = shouldIncludeIabPayload ? iabOptions?.customVendors : void 0;
2461
+ const snapshot = policyDecision ? await createPolicySnapshotToken({
2462
+ options: options.policySnapshot,
2463
+ tenantId: options.tenantId,
2464
+ policyId: policyDecision.policy.id,
2465
+ fingerprint: policyDecision.fingerprint,
2466
+ matchedBy: policyDecision.matchedBy,
2467
+ country: location?.countryCode ?? null,
2468
+ region: location?.regionCode ?? null,
2469
+ jurisdiction,
2470
+ language: translationsResult.language,
2471
+ model: policyDecision.policy.model,
2472
+ policyI18n: policyDecision.policy.i18n,
2473
+ expiryDays: policyDecision.policy.consent?.expiryDays,
2474
+ scopeMode: policyDecision.policy.consent?.scopeMode,
2475
+ uiMode: policyDecision.policy.ui?.mode,
2476
+ bannerUi: policyDecision.policy.ui?.banner,
2477
+ dialogUi: policyDecision.policy.ui?.dialog,
2478
+ categories: policyDecision.policy.consent?.categories,
2479
+ preselectedCategories: policyDecision.policy.consent?.preselectedCategories,
2480
+ gpc: policyDecision.policy.consent?.gpc,
2481
+ proofConfig: policyDecision.policy.proof
2482
+ }) : void 0;
2483
+ const gpc = '1' === request.headers.get('sec-gpc');
2484
+ getMetrics()?.recordInit({
2485
+ jurisdiction,
2486
+ country: location?.countryCode ?? void 0,
2487
+ region: location?.regionCode ?? void 0,
2488
+ gpc
1868
2489
  });
1869
- const base = isSupportedBaseLanguage(preferredLanguage) ? translations_namespaceObject.baseTranslations[preferredLanguage] : translations_namespaceObject.baseTranslations.en;
1870
- const custom = supportedCustomLanguages.includes(preferredLanguage) ? customTranslations?.[preferredLanguage] : {};
1871
- const translations = custom ? (0, translations_namespaceObject.deepMergeTranslations)(base, custom) : base;
1872
2490
  return {
1873
- translations: translations,
1874
- language: preferredLanguage
2491
+ jurisdiction,
2492
+ location,
2493
+ translations: responseTranslations,
2494
+ branding: options.branding || 'c15t',
2495
+ ...shouldIncludeIabPayload && {
2496
+ gvl,
2497
+ customVendors
2498
+ },
2499
+ ...resolvedPolicy && {
2500
+ policy: resolvedPolicy
2501
+ },
2502
+ ...policyDecision && {
2503
+ policyDecision: {
2504
+ policyId: policyDecision.policy.id,
2505
+ fingerprint: policyDecision.fingerprint,
2506
+ matchedBy: policyDecision.matchedBy,
2507
+ country: location.countryCode,
2508
+ region: location.regionCode,
2509
+ jurisdiction
2510
+ }
2511
+ },
2512
+ ...snapshot?.token && {
2513
+ policySnapshotToken: snapshot.token
2514
+ },
2515
+ ...shouldIncludeIabPayload && iabOptions?.cmpId != null && {
2516
+ cmpId: iabOptions.cmpId
2517
+ }
1875
2518
  };
1876
2519
  }
1877
2520
  const createInitRoute = (options)=>{
@@ -1884,7 +2527,7 @@ var __webpack_exports__ = {};
1884
2527
  - **Location** – User's location (null if geo-location is disabled)
1885
2528
  - **Translations** – Consent manager copy (from \`Accept-Language\` header)
1886
2529
  - **Branding** – Configured branding key
1887
- - **GVL** – Global Vendor List when enabled
2530
+ - **GVL** – Global Vendor List when IAB is active for the request
1888
2531
 
1889
2532
  Use for geo-targeted consent banners and regional compliance.`,
1890
2533
  tags: [
@@ -1901,40 +2544,98 @@ Use for geo-targeted consent banners and regional compliance.`,
1901
2544
  }
1902
2545
  }
1903
2546
  }), async (c)=>{
1904
- const request = c.req.raw;
1905
- const acceptLanguage = request.headers.get('accept-language') || 'en';
1906
- const location = await getLocation(request, options);
1907
- const jurisdiction = getJurisdiction(location, options);
1908
- const translationsResult = translations_getTranslationsData(acceptLanguage, options.advanced?.customTranslations);
1909
- let gvl = null;
1910
- if (options.advanced?.gvl?.enabled) {
1911
- const language = translationsResult.language.split('-')[0] || 'en';
1912
- const gvlResolver = createGVLResolver({
1913
- appName: options.appName || 'c15t',
1914
- bundled: options.advanced.gvl.bundled,
1915
- cacheAdapter: options.advanced.cache?.adapter,
1916
- vendorIds: options.advanced.gvl.vendorIds,
1917
- endpoint: options.advanced.gvl.endpoint
1918
- });
1919
- gvl = await gvlResolver.get(language);
2547
+ const ctx = c.get('c15tContext');
2548
+ const payload = await resolveInitPayload(c.req.raw, options, ctx?.logger);
2549
+ return c.json(payload);
2550
+ });
2551
+ return app;
2552
+ };
2553
+ const syncCurrentLegalDocumentHandler = async (c)=>{
2554
+ const ctx = c.get('c15tContext');
2555
+ const logger = ctx.logger;
2556
+ logger.info('Handling PUT /legal-documents/:type/current request');
2557
+ if (!ctx.apiKeyAuthenticated) throw new http_exception_namespaceObject.HTTPException(401, {
2558
+ message: 'API key required. Use Authorization: Bearer <api_key>',
2559
+ cause: {
2560
+ code: 'UNAUTHORIZED'
1920
2561
  }
1921
- const customVendors = options.advanced?.gvl?.customVendors;
1922
- const gpc = '1' === request.headers.get('sec-gpc');
1923
- getMetrics()?.recordInit({
1924
- jurisdiction,
1925
- country: location?.countryCode ?? void 0,
1926
- region: location?.regionCode ?? void 0,
1927
- gpc
2562
+ });
2563
+ const type = c.req.param('type');
2564
+ const body = await c.req.json();
2565
+ const effectiveDate = new Date(body.effectiveDate);
2566
+ if (Number.isNaN(effectiveDate.getTime())) throw new http_exception_namespaceObject.HTTPException(422, {
2567
+ message: 'effectiveDate must be a valid ISO-8601 string',
2568
+ cause: {
2569
+ code: 'INPUT_VALIDATION_FAILED'
2570
+ }
2571
+ });
2572
+ try {
2573
+ const policy = await ctx.registry.syncCurrentLegalDocumentPolicy({
2574
+ type,
2575
+ version: body.version,
2576
+ hash: body.hash,
2577
+ effectiveDate
1928
2578
  });
1929
2579
  return c.json({
1930
- jurisdiction,
1931
- location,
1932
- translations: translationsResult,
1933
- branding: options.advanced?.branding || 'c15t',
1934
- gvl,
1935
- customVendors
2580
+ policy: {
2581
+ id: policy.id,
2582
+ type: policy.type,
2583
+ version: policy.version,
2584
+ hash: policy.hash,
2585
+ effectiveDate: policy.effectiveDate,
2586
+ isActive: policy.isActive
2587
+ }
1936
2588
  });
1937
- });
2589
+ } catch (error) {
2590
+ logger.error('Error in PUT /legal-documents/:type/current handler', {
2591
+ error: extractErrorMessage(error),
2592
+ errorType: error instanceof Error ? error.constructor.name : typeof error
2593
+ });
2594
+ if (error instanceof LegalDocumentPolicyConflictError) throw new http_exception_namespaceObject.HTTPException(409, {
2595
+ message: error.message,
2596
+ cause: {
2597
+ code: 'LEGAL_DOCUMENT_RELEASE_CONFLICT'
2598
+ }
2599
+ });
2600
+ if (error instanceof http_exception_namespaceObject.HTTPException) throw error;
2601
+ throw new http_exception_namespaceObject.HTTPException(500, {
2602
+ message: 'Internal server error',
2603
+ cause: {
2604
+ code: 'INTERNAL_SERVER_ERROR'
2605
+ }
2606
+ });
2607
+ }
2608
+ };
2609
+ const createLegalDocumentRoutes = ()=>{
2610
+ const app = new external_hono_namespaceObject.Hono();
2611
+ app.put('/:type/current', (0, external_hono_openapi_namespaceObject.describeRoute)({
2612
+ summary: 'Sync the current legal document release (API key required)',
2613
+ description: 'Marks a legal document release as the latest known version for its type. Requires a Bearer API key.',
2614
+ tags: [
2615
+ 'LegalDocument'
2616
+ ],
2617
+ security: [
2618
+ {
2619
+ bearerAuth: []
2620
+ }
2621
+ ],
2622
+ responses: {
2623
+ 200: {
2624
+ description: 'Current legal document release synced successfully',
2625
+ content: {
2626
+ 'application/json': {
2627
+ schema: (0, external_hono_openapi_namespaceObject.resolver)(schema_.legalDocumentCurrentOutputSchema)
2628
+ }
2629
+ }
2630
+ },
2631
+ 401: {
2632
+ description: 'Missing or invalid API key'
2633
+ },
2634
+ 409: {
2635
+ description: 'Release metadata conflicts with an existing release'
2636
+ }
2637
+ }
2638
+ }), (0, external_hono_openapi_namespaceObject.validator)('param', schema_.legalDocumentCurrentParamsSchema), (0, external_hono_openapi_namespaceObject.validator)('json', schema_.legalDocumentCurrentInputSchema), syncCurrentLegalDocumentHandler);
1938
2639
  return app;
1939
2640
  };
1940
2641
  function getHeaders(headers) {
@@ -2023,6 +2724,12 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2023
2724
  const subjectId = c.req.param('id');
2024
2725
  const type = c.req.query('type');
2025
2726
  const typeFilter = type?.split(',').map((t)=>t.trim()) || [];
2727
+ if (!subjectId) throw new http_exception_namespaceObject.HTTPException(400, {
2728
+ message: 'Subject ID is required',
2729
+ cause: {
2730
+ code: 'SUBJECT_ID_REQUIRED'
2731
+ }
2732
+ });
2026
2733
  logger.debug('Request parameters', {
2027
2734
  subjectId,
2028
2735
  typeFilter
@@ -2051,7 +2758,6 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2051
2758
  subject: {
2052
2759
  id: subject.id,
2053
2760
  externalId: subject.externalId ?? void 0,
2054
- isIdentified: subject.isIdentified,
2055
2761
  createdAt: subject.createdAt
2056
2762
  },
2057
2763
  consents: filteredConsents,
@@ -2107,7 +2813,6 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2107
2813
  return {
2108
2814
  id: subject.id,
2109
2815
  externalId: subject.externalId ?? externalId,
2110
- isIdentified: subject.isIdentified,
2111
2816
  createdAt: subject.createdAt,
2112
2817
  consents: consentItems
2113
2818
  };
@@ -2216,6 +2921,12 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2216
2921
  const subjectId = c.req.param('id');
2217
2922
  const body = await c.req.json();
2218
2923
  const { externalId, identityProvider = 'external' } = body;
2924
+ if (!subjectId) throw new http_exception_namespaceObject.HTTPException(400, {
2925
+ message: 'Subject ID is required',
2926
+ cause: {
2927
+ code: 'SUBJECT_ID_REQUIRED'
2928
+ }
2929
+ });
2219
2930
  logger.debug('Request parameters', {
2220
2931
  subjectId,
2221
2932
  externalId,
@@ -2238,7 +2949,6 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2238
2949
  set: {
2239
2950
  externalId,
2240
2951
  identityProvider,
2241
- isIdentified: true,
2242
2952
  updatedAt: new Date()
2243
2953
  }
2244
2954
  });
@@ -2258,10 +2968,6 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2258
2968
  identityProvider: {
2259
2969
  from: subject.identityProvider,
2260
2970
  to: identityProvider
2261
- },
2262
- isIdentified: {
2263
- from: subject.isIdentified,
2264
- to: true
2265
2971
  }
2266
2972
  },
2267
2973
  metadata: {
@@ -2280,8 +2986,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2280
2986
  success: true,
2281
2987
  subject: {
2282
2988
  id: subjectId,
2283
- externalId,
2284
- isIdentified: true
2989
+ externalId
2285
2990
  }
2286
2991
  });
2287
2992
  } catch (error) {
@@ -2298,6 +3003,234 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2298
3003
  });
2299
3004
  }
2300
3005
  };
3006
+ const DEFAULT_ISSUER = 'c15t';
3007
+ const DEFAULT_AUDIENCE = 'c15t-legal-document-snapshot';
3008
+ function isLegalDocumentPolicyType(type) {
3009
+ return 'privacy_policy' === type || 'terms_and_conditions' === type || 'dpa' === type;
3010
+ }
3011
+ function snapshot_resolveSnapshotIssuer(options) {
3012
+ return options?.issuer?.trim() || DEFAULT_ISSUER;
3013
+ }
3014
+ function snapshot_resolveSnapshotAudience(params) {
3015
+ const configuredAudience = params.options?.audience?.trim();
3016
+ if (configuredAudience) return configuredAudience;
3017
+ return params.tenantId ? `${DEFAULT_AUDIENCE}:${params.tenantId}` : DEFAULT_AUDIENCE;
3018
+ }
3019
+ function snapshot_getSigningKey(secret) {
3020
+ return new TextEncoder().encode(secret);
3021
+ }
3022
+ function isLegalDocumentSnapshotPayload(payload) {
3023
+ return 'string' == typeof payload.iss && 'string' == typeof payload.aud && 'string' == typeof payload.sub && isLegalDocumentPolicyType(payload.type) && 'string' == typeof payload.version && 'string' == typeof payload.hash && 'string' == typeof payload.effectiveDate && 'number' == typeof payload.iat && 'number' == typeof payload.exp;
3024
+ }
3025
+ async function verifyLegalDocumentSnapshotToken(params) {
3026
+ const { token, options, tenantId } = params;
3027
+ if (!options?.signingKey) return {
3028
+ valid: false,
3029
+ reason: 'missing'
3030
+ };
3031
+ if (!token) return {
3032
+ valid: false,
3033
+ reason: 'missing'
3034
+ };
3035
+ if (3 !== token.split('.').length) return {
3036
+ valid: false,
3037
+ reason: 'malformed'
3038
+ };
3039
+ try {
3040
+ const { payload, protectedHeader } = await (0, external_jose_namespaceObject.jwtVerify)(token, snapshot_getSigningKey(options.signingKey), {
3041
+ issuer: snapshot_resolveSnapshotIssuer(options),
3042
+ audience: snapshot_resolveSnapshotAudience({
3043
+ options,
3044
+ tenantId
3045
+ })
3046
+ });
3047
+ const header = protectedHeader;
3048
+ if ('HS256' !== header.alg || 'JWT' !== header.typ) return {
3049
+ valid: false,
3050
+ reason: 'invalid'
3051
+ };
3052
+ if (!isLegalDocumentSnapshotPayload(payload)) return {
3053
+ valid: false,
3054
+ reason: 'invalid'
3055
+ };
3056
+ if (payload.sub !== payload.hash) return {
3057
+ valid: false,
3058
+ reason: 'invalid'
3059
+ };
3060
+ if ((tenantId ?? void 0) !== (payload.tenantId ?? void 0)) return {
3061
+ valid: false,
3062
+ reason: 'invalid'
3063
+ };
3064
+ return {
3065
+ valid: true,
3066
+ payload
3067
+ };
3068
+ } catch (error) {
3069
+ if (error instanceof external_jose_namespaceObject.errors.JWTExpired) return {
3070
+ valid: false,
3071
+ reason: 'expired'
3072
+ };
3073
+ return {
3074
+ valid: false,
3075
+ reason: 'invalid'
3076
+ };
3077
+ }
3078
+ }
3079
+ function buildRuntimeDecisionDedupeKey(input) {
3080
+ return [
3081
+ input.tenantId ?? 'default',
3082
+ input.fingerprint,
3083
+ input.matchedBy,
3084
+ input.countryCode ?? 'none',
3085
+ input.regionCode ?? 'none',
3086
+ input.jurisdiction,
3087
+ input.language ?? 'none'
3088
+ ].join('|');
3089
+ }
3090
+ function buildDecisionPayload(params) {
3091
+ const { tenantId, snapshot, decision, location, jurisdiction, language, proofConfig } = params;
3092
+ if (snapshot?.valid && snapshot.payload) {
3093
+ const sp = snapshot.payload;
3094
+ return {
3095
+ tenantId,
3096
+ policyId: sp.policyId,
3097
+ fingerprint: sp.fingerprint,
3098
+ matchedBy: sp.matchedBy,
3099
+ countryCode: sp.country,
3100
+ regionCode: sp.region,
3101
+ jurisdiction: sp.jurisdiction,
3102
+ language: sp.language,
3103
+ model: sp.model,
3104
+ policyI18n: sp.policyI18n,
3105
+ uiMode: sp.uiMode,
3106
+ bannerUi: sp.bannerUi,
3107
+ dialogUi: sp.dialogUi,
3108
+ categories: sp.categories,
3109
+ preselectedCategories: sp.preselectedCategories,
3110
+ proofConfig: sp.proofConfig,
3111
+ dedupeKey: buildRuntimeDecisionDedupeKey({
3112
+ tenantId,
3113
+ fingerprint: sp.fingerprint,
3114
+ matchedBy: sp.matchedBy,
3115
+ countryCode: sp.country,
3116
+ regionCode: sp.region,
3117
+ jurisdiction: sp.jurisdiction,
3118
+ language: sp.language
3119
+ }),
3120
+ source: 'snapshot_token'
3121
+ };
3122
+ }
3123
+ if (decision) return {
3124
+ tenantId,
3125
+ policyId: decision.policy.id,
3126
+ fingerprint: decision.fingerprint,
3127
+ matchedBy: decision.matchedBy,
3128
+ countryCode: location.countryCode,
3129
+ regionCode: location.regionCode,
3130
+ jurisdiction,
3131
+ language,
3132
+ model: decision.policy.model,
3133
+ policyI18n: decision.policy.i18n,
3134
+ uiMode: decision.policy.ui?.mode,
3135
+ bannerUi: decision.policy.ui?.banner,
3136
+ dialogUi: decision.policy.ui?.dialog,
3137
+ categories: decision.policy.consent?.categories,
3138
+ preselectedCategories: decision.policy.consent?.preselectedCategories,
3139
+ proofConfig,
3140
+ dedupeKey: buildRuntimeDecisionDedupeKey({
3141
+ tenantId,
3142
+ fingerprint: decision.fingerprint,
3143
+ matchedBy: decision.matchedBy,
3144
+ countryCode: location.countryCode,
3145
+ regionCode: location.regionCode,
3146
+ jurisdiction,
3147
+ language
3148
+ }),
3149
+ source: 'write_time_fallback'
3150
+ };
3151
+ }
3152
+ function parseLanguageFromHeader(header) {
3153
+ if (!header) return;
3154
+ const firstLanguage = header.split(',')[0]?.split(';')[0]?.trim();
3155
+ if (!firstLanguage) return;
3156
+ return firstLanguage.split('-')[0]?.toLowerCase();
3157
+ }
3158
+ function isLegalDocumentType(type) {
3159
+ return 'privacy_policy' === type || 'terms_and_conditions' === type || 'dpa' === type;
3160
+ }
3161
+ function resolveSnapshotFailureMode(ctx) {
3162
+ return ctx.policySnapshot?.onValidationFailure ?? 'reject';
3163
+ }
3164
+ function buildSnapshotHttpException(reason) {
3165
+ switch(reason){
3166
+ case 'missing':
3167
+ return new http_exception_namespaceObject.HTTPException(409, {
3168
+ message: 'Policy snapshot token is required',
3169
+ cause: {
3170
+ code: 'POLICY_SNAPSHOT_REQUIRED'
3171
+ }
3172
+ });
3173
+ case 'expired':
3174
+ return new http_exception_namespaceObject.HTTPException(409, {
3175
+ message: 'Policy snapshot token has expired',
3176
+ cause: {
3177
+ code: 'POLICY_SNAPSHOT_EXPIRED'
3178
+ }
3179
+ });
3180
+ case 'malformed':
3181
+ case 'invalid':
3182
+ return new http_exception_namespaceObject.HTTPException(409, {
3183
+ message: 'Policy snapshot token is invalid',
3184
+ cause: {
3185
+ code: 'POLICY_SNAPSHOT_INVALID'
3186
+ }
3187
+ });
3188
+ default:
3189
+ {
3190
+ const _exhaustive = reason;
3191
+ throw new Error(`Unhandled policy snapshot verification failure reason: ${_exhaustive}`);
3192
+ }
3193
+ }
3194
+ }
3195
+ function buildLegalDocumentSnapshotHttpException(reason) {
3196
+ switch(reason){
3197
+ case 'missing':
3198
+ return new http_exception_namespaceObject.HTTPException(409, {
3199
+ message: 'Legal document snapshot token is required',
3200
+ cause: {
3201
+ code: 'LEGAL_DOCUMENT_SNAPSHOT_REQUIRED'
3202
+ }
3203
+ });
3204
+ case 'expired':
3205
+ return new http_exception_namespaceObject.HTTPException(409, {
3206
+ message: 'Legal document snapshot token has expired',
3207
+ cause: {
3208
+ code: 'LEGAL_DOCUMENT_SNAPSHOT_EXPIRED'
3209
+ }
3210
+ });
3211
+ case 'malformed':
3212
+ case 'invalid':
3213
+ return new http_exception_namespaceObject.HTTPException(409, {
3214
+ message: 'Legal document snapshot token is invalid',
3215
+ cause: {
3216
+ code: 'LEGAL_DOCUMENT_SNAPSHOT_INVALID'
3217
+ }
3218
+ });
3219
+ default:
3220
+ {
3221
+ const _exhaustive = reason;
3222
+ throw new Error(`Unhandled legal document snapshot verification failure reason: ${_exhaustive}`);
3223
+ }
3224
+ }
3225
+ }
3226
+ function buildLegalDocumentProofHttpException(message) {
3227
+ return new http_exception_namespaceObject.HTTPException(409, {
3228
+ message,
3229
+ cause: {
3230
+ code: 'LEGAL_DOCUMENT_PROOF_REQUIRED'
3231
+ }
3232
+ });
3233
+ }
2301
3234
  const postSubjectHandler = async (c)=>{
2302
3235
  const ctx = c.get('c15tContext');
2303
3236
  const logger = ctx.logger;
@@ -2307,6 +3240,8 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2307
3240
  const { type, subjectId, identityProvider, externalSubjectId, domain, metadata, givenAt: givenAtEpoch } = input;
2308
3241
  const preferences = 'preferences' in input ? input.preferences : void 0;
2309
3242
  const givenAt = new Date(givenAtEpoch);
3243
+ const rawConsentAction = 'consentAction' in input ? input.consentAction : void 0;
3244
+ let derivedConsentAction;
2310
3245
  logger.debug('Request parameters', {
2311
3246
  type,
2312
3247
  subjectId,
@@ -2315,6 +3250,64 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2315
3250
  domain
2316
3251
  });
2317
3252
  try {
3253
+ if ('cookie_banner' === type) logger.warn('`cookie_banner` policy type is deprecated in 2.0 RC and will be removed in 2.0 GA. Use backend runtime `policyPacks` for banner behavior.');
3254
+ const request = c.req.raw ?? new Request('https://c15t.local/subjects');
3255
+ const acceptLanguage = request.headers.get('accept-language');
3256
+ const requestLanguage = parseLanguageFromHeader(acceptLanguage);
3257
+ const location = await getLocation(request, ctx);
3258
+ const resolvedJurisdiction = getJurisdiction(location, ctx);
3259
+ const legalDocumentConsent = isLegalDocumentType(type);
3260
+ const runtimeSnapshotVerification = legalDocumentConsent ? {
3261
+ valid: false,
3262
+ reason: 'missing'
3263
+ } : await verifyPolicySnapshotToken({
3264
+ token: input.policySnapshotToken,
3265
+ options: ctx.policySnapshot,
3266
+ tenantId: ctx.tenantId
3267
+ });
3268
+ const legalDocumentSnapshotVerification = legalDocumentConsent ? await verifyLegalDocumentSnapshotToken({
3269
+ token: input.documentSnapshotToken,
3270
+ options: ctx.legalDocumentSnapshot,
3271
+ tenantId: ctx.tenantId
3272
+ }) : {
3273
+ valid: false,
3274
+ reason: 'missing'
3275
+ };
3276
+ const hasValidSnapshot = runtimeSnapshotVerification.valid;
3277
+ const snapshotPayload = runtimeSnapshotVerification.valid ? runtimeSnapshotVerification.payload : null;
3278
+ const shouldRequireSnapshot = !legalDocumentConsent && !!ctx.policySnapshot?.signingKey && 'reject' === resolveSnapshotFailureMode(ctx);
3279
+ if (!hasValidSnapshot && shouldRequireSnapshot) throw buildSnapshotHttpException(runtimeSnapshotVerification.reason);
3280
+ const shouldRequireLegalDocumentSnapshot = legalDocumentConsent && !!ctx.legalDocumentSnapshot?.signingKey;
3281
+ if (shouldRequireLegalDocumentSnapshot && !legalDocumentSnapshotVerification.valid) throw buildLegalDocumentSnapshotHttpException(legalDocumentSnapshotVerification.reason);
3282
+ const resolvedPolicyDecision = hasValidSnapshot ? void 0 : legalDocumentConsent ? void 0 : await resolvePolicyDecision({
3283
+ policies: ctx.policyPacks,
3284
+ countryCode: location.countryCode,
3285
+ regionCode: location.regionCode,
3286
+ jurisdiction: resolvedJurisdiction,
3287
+ iabEnabled: ctx.iab?.enabled === true
3288
+ });
3289
+ const effectivePolicy = hasValidSnapshot && snapshotPayload ? {
3290
+ id: snapshotPayload.policyId,
3291
+ model: snapshotPayload.model,
3292
+ i18n: snapshotPayload.policyI18n,
3293
+ consent: {
3294
+ expiryDays: snapshotPayload.expiryDays,
3295
+ scopeMode: snapshotPayload.scopeMode,
3296
+ categories: snapshotPayload.categories,
3297
+ preselectedCategories: snapshotPayload.preselectedCategories,
3298
+ gpc: snapshotPayload.gpc
3299
+ },
3300
+ ui: {
3301
+ mode: snapshotPayload.uiMode,
3302
+ banner: snapshotPayload.bannerUi,
3303
+ dialog: snapshotPayload.dialogUi
3304
+ },
3305
+ proof: snapshotPayload.proofConfig
3306
+ } : resolvedPolicyDecision?.policy;
3307
+ const effectiveModel = effectivePolicy?.model ?? ('opt-in' === input.jurisdictionModel || 'opt-out' === input.jurisdictionModel || 'iab' === input.jurisdictionModel ? input.jurisdictionModel : void 0);
3308
+ if ('all' === rawConsentAction) derivedConsentAction = 'accept_all';
3309
+ else if ('necessary' === rawConsentAction) derivedConsentAction = 'opt-out' === effectiveModel ? 'opt_out' : 'reject_all';
3310
+ else if ('custom' === rawConsentAction) derivedConsentAction = 'custom';
2318
3311
  const subject = await registry.findOrCreateSubject({
2319
3312
  subjectId,
2320
3313
  externalSubjectId,
@@ -2341,8 +3334,63 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2341
3334
  });
2342
3335
  let policyId;
2343
3336
  let purposeIds = [];
3337
+ let appliedPreferences;
2344
3338
  const inputPolicyId = 'policyId' in input ? input.policyId : void 0;
2345
- if (inputPolicyId) {
3339
+ const inputPolicyHash = 'policyHash' in input ? input.policyHash : void 0;
3340
+ if (legalDocumentConsent && legalDocumentSnapshotVerification.valid) {
3341
+ if (legalDocumentSnapshotVerification.payload.type !== type) throw buildLegalDocumentSnapshotHttpException('invalid');
3342
+ const effectiveDate = new Date(legalDocumentSnapshotVerification.payload.effectiveDate);
3343
+ if (Number.isNaN(effectiveDate.getTime())) throw buildLegalDocumentSnapshotHttpException('invalid');
3344
+ const documentPolicy = await registry.findOrCreateLegalDocumentPolicy({
3345
+ type,
3346
+ version: legalDocumentSnapshotVerification.payload.version,
3347
+ hash: legalDocumentSnapshotVerification.payload.hash,
3348
+ effectiveDate
3349
+ });
3350
+ policyId = documentPolicy.id;
3351
+ } else if (legalDocumentConsent) {
3352
+ if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId && !inputPolicyHash) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId or policyHash when snapshot verification is disabled');
3353
+ if (inputPolicyId) {
3354
+ policyId = inputPolicyId;
3355
+ const policy = await registry.findConsentPolicyById(inputPolicyId);
3356
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
3357
+ message: 'Policy not found',
3358
+ cause: {
3359
+ code: 'POLICY_NOT_FOUND',
3360
+ policyId,
3361
+ type
3362
+ }
3363
+ });
3364
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
3365
+ message: 'Policy is inactive',
3366
+ cause: {
3367
+ code: 'POLICY_INACTIVE',
3368
+ policyId,
3369
+ type
3370
+ }
3371
+ });
3372
+ } else if (inputPolicyHash) {
3373
+ const policy = await registry.findLegalDocumentPolicyByHash(type, inputPolicyHash);
3374
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
3375
+ message: 'Policy not found',
3376
+ cause: {
3377
+ code: 'POLICY_NOT_FOUND',
3378
+ type,
3379
+ policyHash: inputPolicyHash
3380
+ }
3381
+ });
3382
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
3383
+ message: 'Policy is inactive',
3384
+ cause: {
3385
+ code: 'POLICY_INACTIVE',
3386
+ policyId: policy.id,
3387
+ type,
3388
+ policyHash: inputPolicyHash
3389
+ }
3390
+ });
3391
+ policyId = policy.id;
3392
+ }
3393
+ } else if (inputPolicyId) {
2346
3394
  policyId = inputPolicyId;
2347
3395
  const policy = await registry.findConsentPolicyById(inputPolicyId);
2348
3396
  if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
@@ -2373,20 +3421,73 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2373
3421
  policyId = policy.id;
2374
3422
  }
2375
3423
  if (preferences) {
2376
- const consentedPurposes = Object.entries(preferences).filter(([_, isConsented])=>isConsented).map(([purposeCode])=>purposeCode);
3424
+ const allowedCategories = effectivePolicy?.consent?.categories;
3425
+ const effectiveScopeMode = effectivePolicy?.consent?.scopeMode ?? 'permissive';
3426
+ const hasWildcardCategoryScope = allowedCategories?.includes('*') === true;
3427
+ const appliedPreferenceEntries = Object.entries(preferences);
3428
+ let filteredAppliedPreferenceEntries = appliedPreferenceEntries;
3429
+ if (allowedCategories && allowedCategories.length > 0 && !hasWildcardCategoryScope) {
3430
+ const disallowed = appliedPreferenceEntries.map(([purpose])=>purpose).filter((purpose)=>!allowedCategories.includes(purpose));
3431
+ filteredAppliedPreferenceEntries = appliedPreferenceEntries.filter(([purpose])=>allowedCategories.includes(purpose));
3432
+ if (disallowed.length > 0 && 'strict' === effectiveScopeMode) throw new http_exception_namespaceObject.HTTPException(400, {
3433
+ message: 'Preferences include categories not allowed by policy',
3434
+ cause: {
3435
+ code: 'PURPOSE_NOT_ALLOWED',
3436
+ disallowed
3437
+ }
3438
+ });
3439
+ }
3440
+ appliedPreferences = Object.fromEntries(filteredAppliedPreferenceEntries);
3441
+ const filteredConsentedPurposeCodes = filteredAppliedPreferenceEntries.filter(([_, isConsented])=>isConsented).map(([purposeCode])=>purposeCode);
2377
3442
  logger.debug('Consented purposes', {
2378
- consentedPurposes
3443
+ consentedPurposes: filteredConsentedPurposeCodes
2379
3444
  });
2380
- const purposesRaw = await Promise.all(consentedPurposes.map((purposeCode)=>registry.findOrCreateConsentPurposeByCode(purposeCode)));
3445
+ const purposesRaw = await Promise.all(filteredConsentedPurposeCodes.map((purposeCode)=>registry.findOrCreateConsentPurposeByCode(purposeCode)));
2381
3446
  const purposes = purposesRaw.map((purpose)=>purpose?.id ?? null).filter((id)=>Boolean(id));
2382
3447
  logger.debug('Filtered purposes', {
2383
3448
  purposes
2384
3449
  });
2385
3450
  if (0 === purposes.length) logger.warn('No valid purpose IDs found after filtering. Using empty list.', {
2386
- consentedPurposes
3451
+ consentedPurposes: filteredConsentedPurposeCodes
2387
3452
  });
2388
3453
  purposeIds = purposes;
2389
3454
  }
3455
+ if (!policyId) throw new http_exception_namespaceObject.HTTPException(500, {
3456
+ message: 'Failed to resolve policy',
3457
+ cause: {
3458
+ code: 'POLICY_RESOLUTION_FAILED',
3459
+ type
3460
+ }
3461
+ });
3462
+ const expiryDays = effectivePolicy?.consent?.expiryDays;
3463
+ const validUntil = 'number' == typeof expiryDays && Number.isFinite(expiryDays) ? new Date(givenAt.getTime() + 86400000 * Math.max(0, expiryDays)) : void 0;
3464
+ const proofConfig = effectivePolicy?.proof;
3465
+ const shouldStoreIp = proofConfig?.storeIp ?? true;
3466
+ const shouldStoreUserAgent = proofConfig?.storeUserAgent ?? true;
3467
+ const shouldStoreLanguage = proofConfig?.storeLanguage ?? false;
3468
+ const effectiveLanguage = (snapshotPayload?.language && hasValidSnapshot ? snapshotPayload.language : requestLanguage) ?? void 0;
3469
+ const metadataWithPolicy = {
3470
+ ...metadata ?? {},
3471
+ ...shouldStoreLanguage && effectiveLanguage ? {
3472
+ policyLanguage: effectiveLanguage
3473
+ } : {}
3474
+ };
3475
+ const effectiveJurisdiction = hasValidSnapshot && snapshotPayload ? snapshotPayload.jurisdiction : resolvedJurisdiction;
3476
+ const decisionPayload = buildDecisionPayload({
3477
+ tenantId: ctx.tenantId,
3478
+ snapshot: hasValidSnapshot && snapshotPayload ? {
3479
+ valid: true,
3480
+ payload: snapshotPayload
3481
+ } : null,
3482
+ decision: resolvedPolicyDecision,
3483
+ location: {
3484
+ countryCode: location.countryCode,
3485
+ regionCode: location.regionCode
3486
+ },
3487
+ jurisdiction: resolvedJurisdiction,
3488
+ language: effectiveLanguage,
3489
+ proofConfig
3490
+ });
2390
3491
  const existingConsent = await db.findFirst('consent', {
2391
3492
  where: (b)=>b.and(b('subjectId', '=', subject.id), b('domainId', '=', domainRecord.id), b('policyId', '=', policyId), b('givenAt', '=', givenAt))
2392
3493
  });
@@ -2401,6 +3502,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2401
3502
  domain: domainRecord.name,
2402
3503
  type,
2403
3504
  metadata,
3505
+ appliedPreferences,
2404
3506
  uiSource: input.uiSource,
2405
3507
  givenAt: existingConsent.givenAt
2406
3508
  });
@@ -2412,6 +3514,42 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2412
3514
  policyId,
2413
3515
  purposeIds
2414
3516
  });
3517
+ const runtimePolicyDecision = decisionPayload ? await tx.findFirst('runtimePolicyDecision', {
3518
+ where: (b)=>b('dedupeKey', '=', decisionPayload.dedupeKey)
3519
+ }) ?? await tx.create('runtimePolicyDecision', {
3520
+ id: `rpd_${crypto.randomUUID().replaceAll('-', '')}`,
3521
+ tenantId: decisionPayload.tenantId,
3522
+ policyId: decisionPayload.policyId,
3523
+ fingerprint: decisionPayload.fingerprint,
3524
+ matchedBy: decisionPayload.matchedBy,
3525
+ countryCode: decisionPayload.countryCode,
3526
+ regionCode: decisionPayload.regionCode,
3527
+ jurisdiction: decisionPayload.jurisdiction,
3528
+ language: decisionPayload.language,
3529
+ model: decisionPayload.model,
3530
+ policyI18n: decisionPayload.policyI18n ? {
3531
+ json: decisionPayload.policyI18n
3532
+ } : void 0,
3533
+ uiMode: decisionPayload.uiMode,
3534
+ bannerUi: decisionPayload.bannerUi ? {
3535
+ json: decisionPayload.bannerUi
3536
+ } : void 0,
3537
+ dialogUi: decisionPayload.dialogUi ? {
3538
+ json: decisionPayload.dialogUi
3539
+ } : void 0,
3540
+ categories: decisionPayload.categories ? {
3541
+ json: decisionPayload.categories
3542
+ } : void 0,
3543
+ preselectedCategories: decisionPayload.preselectedCategories ? {
3544
+ json: decisionPayload.preselectedCategories
3545
+ } : void 0,
3546
+ proofConfig: decisionPayload.proofConfig ? {
3547
+ json: decisionPayload.proofConfig
3548
+ } : void 0,
3549
+ dedupeKey: decisionPayload.dedupeKey
3550
+ }).catch(async ()=>tx.findFirst('runtimePolicyDecision', {
3551
+ where: (b)=>b('dedupeKey', '=', decisionPayload.dedupeKey)
3552
+ })) : void 0;
2415
3553
  const consentRecord = await tx.create('consent', {
2416
3554
  id: await utils_generateUniqueId(tx, 'consent', ctx),
2417
3555
  subjectId: subject.id,
@@ -2420,16 +3558,20 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2420
3558
  purposeIds: {
2421
3559
  json: purposeIds
2422
3560
  },
2423
- metadata: metadata ? {
2424
- json: metadata
3561
+ metadata: Object.keys(metadataWithPolicy).length > 0 ? {
3562
+ json: metadataWithPolicy
2425
3563
  } : void 0,
2426
- ipAddress: ctx.ipAddress,
2427
- userAgent: ctx.userAgent,
2428
- jurisdiction: input.jurisdiction,
2429
- jurisdictionModel: input.jurisdictionModel,
3564
+ ipAddress: shouldStoreIp ? ctx.ipAddress : null,
3565
+ userAgent: shouldStoreUserAgent ? ctx.userAgent : null,
3566
+ jurisdiction: effectiveJurisdiction,
3567
+ jurisdictionModel: effectiveModel,
2430
3568
  tcString: input.tcString,
2431
3569
  uiSource: input.uiSource,
2432
- givenAt
3570
+ consentAction: derivedConsentAction,
3571
+ givenAt,
3572
+ validUntil,
3573
+ runtimePolicyDecisionId: runtimePolicyDecision?.id,
3574
+ runtimePolicySource: decisionPayload?.source
2433
3575
  });
2434
3576
  logger.debug('Created consent', {
2435
3577
  consentRecord: consentRecord.id
@@ -2448,7 +3590,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2448
3590
  });
2449
3591
  const metrics = getMetrics();
2450
3592
  if (metrics) {
2451
- const jurisdiction = input.jurisdiction;
3593
+ const jurisdiction = effectiveJurisdiction;
2452
3594
  metrics.recordConsentCreated({
2453
3595
  type,
2454
3596
  jurisdiction
@@ -2470,6 +3612,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2470
3612
  domain: domainRecord.name,
2471
3613
  type,
2472
3614
  metadata,
3615
+ appliedPreferences,
2473
3616
  uiSource: input.uiSource,
2474
3617
  givenAt: result.consent.givenAt
2475
3618
  });
@@ -2479,6 +3622,12 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2479
3622
  errorType: error instanceof Error ? error.constructor.name : typeof error
2480
3623
  });
2481
3624
  if (error instanceof http_exception_namespaceObject.HTTPException) throw error;
3625
+ if (error instanceof LegalDocumentPolicyConflictError) throw new http_exception_namespaceObject.HTTPException(409, {
3626
+ message: error.message,
3627
+ cause: {
3628
+ code: 'LEGAL_DOCUMENT_RELEASE_CONFLICT'
3629
+ }
3630
+ });
2482
3631
  throw new http_exception_namespaceObject.HTTPException(500, {
2483
3632
  message: 'Internal server error',
2484
3633
  cause: {
@@ -2491,11 +3640,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2491
3640
  const app = new external_hono_namespaceObject.Hono();
2492
3641
  app.get('/:id', (0, external_hono_openapi_namespaceObject.describeRoute)({
2493
3642
  summary: 'Get subject consent status',
2494
- description: `Returns the subject's consent status for this device. Use to check if the subject has valid consent for given policy types.
2495
-
2496
- **Query:** \`type\` – Filter by consent type(s), comma-separated (e.g. \`privacy_policy,cookie_banner\`).
2497
-
2498
- **Response:** \`subject\`, \`consents\` (matching filter), \`isValid\` (valid consent for requested type(s)).`,
3643
+ description: "Returns the subject's consent status for this device. Use to check if the subject has valid consent for given policy types.\n\n**Query:** `type` – Filter by consent type(s), comma-separated (e.g. `privacy_policy,cookie_banner`).\n\n**Response:** `subject`, `consents` (matching filter), `isValid` (valid consent for requested type(s)).",
2499
3644
  tags: [
2500
3645
  'Subject',
2501
3646
  'Consent'
@@ -2516,12 +3661,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2516
3661
  }), (0, external_hono_openapi_namespaceObject.validator)('param', schema_.getSubjectInputSchema), getSubjectHandler);
2517
3662
  app.post('/', (0, external_hono_openapi_namespaceObject.describeRoute)({
2518
3663
  summary: 'Record consent for a subject',
2519
- description: `Creates a new consent record (append-only). Creates the subject if it does not exist.
2520
-
2521
- **Request body by \`type\`:**
2522
- - \`cookie_banner\` – Requires \`preferences\` object
2523
- - \`privacy_policy\`, \`dpa\`, \`terms_and_conditions\` – Optional \`policyId\`
2524
- - \`marketing_communications\`, \`age_verification\`, \`other\` – Optional \`preferences\``,
3664
+ description: "Creates a new consent record (append-only). Creates the subject if it does not exist.\n\n**Request body by `type`:**\n- `cookie_banner` – Requires `preferences` object\n- `privacy_policy`, `dpa`, `terms_and_conditions` – Prefer a signed `documentSnapshotToken`; otherwise use a release `policyHash`, with `policyId` kept only for compatibility\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
2525
3665
  tags: [
2526
3666
  'Subject',
2527
3667
  'Consent'
@@ -2593,6 +3733,86 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2593
3733
  return app;
2594
3734
  };
2595
3735
  var define_config = __webpack_require__("./src/define-config.ts");
3736
+ const DEFAULT_FALLBACK_POLICY_INPUT = {
3737
+ id: 'world_no_banner',
3738
+ isDefault: true,
3739
+ model: 'none',
3740
+ uiMode: 'none'
3741
+ };
3742
+ function mergeMatch(input) {
3743
+ return types_namespaceObject.policyMatchers.merge(input.countries?.length ? types_namespaceObject.policyMatchers.countries(input.countries) : {}, input.regions?.length ? types_namespaceObject.policyMatchers.regions(input.regions) : {}, input.isDefault ? types_namespaceObject.policyMatchers["default"]() : {});
3744
+ }
3745
+ function compactUiSurface(value) {
3746
+ if (!value) return;
3747
+ return (0, schema_.compactDefined)({
3748
+ allowedActions: (0, schema_.dedupeTrimmedStrings)(value.allowedActions),
3749
+ primaryActions: value.primaryActions,
3750
+ layout: value.layout,
3751
+ direction: value.direction,
3752
+ uiProfile: value.uiProfile,
3753
+ scrollLock: value.scrollLock
3754
+ });
3755
+ }
3756
+ function buildPolicyConfig(input) {
3757
+ const categories = (0, schema_.dedupeTrimmedStrings)(input.categories);
3758
+ const preselectedCategories = (0, schema_.dedupeTrimmedStrings)(input.preselectedCategories);
3759
+ return {
3760
+ id: input.id,
3761
+ match: mergeMatch(input),
3762
+ i18n: input.i18n,
3763
+ consent: (0, schema_.compactDefined)({
3764
+ model: input.model,
3765
+ expiryDays: input.expiryDays,
3766
+ scopeMode: input.scopeMode,
3767
+ categories,
3768
+ preselectedCategories,
3769
+ gpc: input.gpc
3770
+ }),
3771
+ ui: (0, schema_.compactDefined)({
3772
+ mode: input.uiMode,
3773
+ banner: compactUiSurface(input.banner),
3774
+ dialog: compactUiSurface(input.dialog)
3775
+ }),
3776
+ proof: (0, schema_.compactDefined)({
3777
+ storeIp: input.proof?.storeIp,
3778
+ storeUserAgent: input.proof?.storeUserAgent,
3779
+ storeLanguage: input.proof?.storeLanguage
3780
+ })
3781
+ };
3782
+ }
3783
+ function buildPolicyPack(inputs) {
3784
+ return inputs.map((input)=>buildPolicyConfig(input));
3785
+ }
3786
+ function buildPolicyPackWithDefault(inputs, defaultPolicy) {
3787
+ const pack = buildPolicyPack(inputs);
3788
+ const hasDefault = pack.some((policy)=>policy.match.isDefault);
3789
+ if (hasDefault) return pack;
3790
+ const fallbackInput = defaultPolicy ? {
3791
+ ...defaultPolicy,
3792
+ isDefault: true,
3793
+ countries: void 0,
3794
+ regions: void 0
3795
+ } : DEFAULT_FALLBACK_POLICY_INPUT;
3796
+ return [
3797
+ ...pack,
3798
+ buildPolicyConfig(fallbackInput)
3799
+ ];
3800
+ }
3801
+ function composePacks(...packs) {
3802
+ const seen = new Set();
3803
+ const result = [];
3804
+ for (const pack of packs)for (const policy of pack)if (!seen.has(policy.id)) {
3805
+ seen.add(policy.id);
3806
+ result.push(policy);
3807
+ }
3808
+ return result;
3809
+ }
3810
+ const policyBuilder = {
3811
+ create: buildPolicyConfig,
3812
+ createPack: buildPolicyPack,
3813
+ createPackWithDefault: buildPolicyPackWithDefault,
3814
+ composePacks
3815
+ };
2596
3816
  const c15tInstance = (options)=>{
2597
3817
  const context = init(options);
2598
3818
  const logger = (0, logger_namespaceObject.createLogger)(options.logger);
@@ -2605,7 +3825,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2605
3825
  app.use('*', async (c, next)=>{
2606
3826
  const request = c.req.raw;
2607
3827
  const startTime = Date.now();
2608
- const apiKeyAuthenticated = validateRequestAuth(request.headers, options.advanced?.apiKeys);
3828
+ const apiKeyAuthenticated = validateRequestAuth(request.headers, options.apiKeys);
2609
3829
  const enrichedContext = {
2610
3830
  ...context,
2611
3831
  ipAddress: getIpAddress(request, options),
@@ -2674,16 +3894,16 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2674
3894
  }));
2675
3895
  const publicSpecUrl = `${basePath}${openApiConfig.specPath}`.replace(/\/+/g, '/');
2676
3896
  app.get(openApiConfig.docsPath, (0, hono_api_reference_namespaceObject.apiReference)({
2677
- spec: {
2678
- url: publicSpecUrl
2679
- },
3897
+ url: publicSpecUrl,
2680
3898
  pageTitle: `${options.appName || 'c15t API'} Documentation`
2681
3899
  }));
2682
3900
  }
2683
3901
  app.route('/init', createInitRoute(options));
3902
+ app.route('/legal-documents', createLegalDocumentRoutes());
2684
3903
  app.route('/subjects', createSubjectRoutes());
2685
3904
  app.route('/consents', createConsentRoutes());
2686
3905
  app.route('/status', createStatusRoute());
3906
+ app.route('/', createStatusRoute());
2687
3907
  app.onError((err, c)=>{
2688
3908
  const ctx = c.get('c15tContext');
2689
3909
  const log = ctx?.logger || logger;
@@ -2769,12 +3989,28 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2769
3989
  };
2770
3990
  };
2771
3991
  })();
3992
+ exports.EEA_COUNTRY_CODES = __webpack_exports__.EEA_COUNTRY_CODES;
3993
+ exports.EU_COUNTRY_CODES = __webpack_exports__.EU_COUNTRY_CODES;
3994
+ exports.POLICY_MATCH_DATASET_VERSION = __webpack_exports__.POLICY_MATCH_DATASET_VERSION;
3995
+ exports.UK_COUNTRY_CODES = __webpack_exports__.UK_COUNTRY_CODES;
2772
3996
  exports.c15tInstance = __webpack_exports__.c15tInstance;
2773
3997
  exports.defineConfig = __webpack_exports__.defineConfig;
3998
+ exports.inspectPolicies = __webpack_exports__.inspectPolicies;
3999
+ exports.policyBuilder = __webpack_exports__.policyBuilder;
4000
+ exports.policyMatchers = __webpack_exports__.policyMatchers;
4001
+ exports.policyPackPresets = __webpack_exports__.policyPackPresets;
2774
4002
  exports.version = __webpack_exports__.version;
2775
4003
  for(var __rspack_i in __webpack_exports__)if (-1 === [
4004
+ "EEA_COUNTRY_CODES",
4005
+ "EU_COUNTRY_CODES",
4006
+ "POLICY_MATCH_DATASET_VERSION",
4007
+ "UK_COUNTRY_CODES",
2776
4008
  "c15tInstance",
2777
4009
  "defineConfig",
4010
+ "inspectPolicies",
4011
+ "policyBuilder",
4012
+ "policyMatchers",
4013
+ "policyPackPresets",
2778
4014
  "version"
2779
4015
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
2780
4016
  Object.defineProperty(exports, '__esModule', {