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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/dist/cache.cjs +4 -4
  2. package/dist/cache.js +4 -4
  3. package/dist/core.cjs +845 -87
  4. package/dist/core.js +821 -87
  5. package/dist/db/schema.cjs +37 -0
  6. package/dist/db/schema.js +33 -2
  7. package/dist/edge.cjs +1106 -0
  8. package/dist/edge.js +1069 -0
  9. package/dist/router.cjs +621 -71
  10. package/dist/router.js +621 -71
  11. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  12. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  13. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  14. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  15. package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
  16. package/{dist → dist-types}/cache/index.d.ts +0 -1
  17. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  18. package/{dist → dist-types}/cache/types.d.ts +0 -1
  19. package/{dist → dist-types}/core.d.ts +8 -1
  20. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  21. package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
  22. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  23. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  24. package/{dist → dist-types}/db/registry/index.d.ts +22 -2
  25. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  26. package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
  27. package/{dist → dist-types}/db/registry/types.d.ts +1 -2
  28. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  29. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  30. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  31. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  32. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  33. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  34. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  35. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  36. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
  37. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
  38. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  39. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +1 -2
  40. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  41. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +5 -2
  42. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  43. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
  44. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  45. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -2
  46. package/{dist → dist-types}/db/schema/index.d.ts +862 -33
  47. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  48. package/dist-types/define-config.d.ts +17 -0
  49. package/dist-types/edge/index.d.ts +5 -0
  50. package/dist-types/edge/init-handler.d.ts +38 -0
  51. package/dist-types/edge/resolve-consent.d.ts +80 -0
  52. package/dist-types/edge/types.d.ts +13 -0
  53. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  54. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  55. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  56. package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
  57. package/dist-types/handlers/init/policy.d.ts +26 -0
  58. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  59. package/dist-types/handlers/init/translations.d.ts +48 -0
  60. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  61. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  62. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  63. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
  64. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  65. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
  66. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
  67. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  68. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
  69. package/{dist → dist-types}/init.d.ts +4 -7
  70. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  71. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  72. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  73. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  74. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
  75. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  76. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  77. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  78. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  79. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  80. package/dist-types/policies/builder.d.ts +127 -0
  81. package/dist-types/policies/defaults.d.ts +2 -0
  82. package/dist-types/policies/matchers.d.ts +3 -0
  83. package/{dist → dist-types}/router.d.ts +0 -1
  84. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  85. package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
  86. package/{dist → dist-types}/routes/init.d.ts +0 -1
  87. package/{dist → dist-types}/routes/status.d.ts +0 -1
  88. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  89. package/{dist → dist-types}/types/api.d.ts +0 -1
  90. package/dist-types/types/index.d.ts +443 -0
  91. package/dist-types/utils/background.d.ts +6 -0
  92. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
  93. package/{dist → dist-types}/utils/env.d.ts +0 -1
  94. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  95. package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
  96. package/{dist → dist-types}/utils/logger.d.ts +1 -2
  97. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  98. package/dist-types/version.d.ts +1 -0
  99. package/docs/README.md +49 -0
  100. package/docs/api/configuration.md +197 -0
  101. package/docs/api/endpoints.md +211 -0
  102. package/docs/guides/caching.md +85 -0
  103. package/docs/guides/database-setup.md +128 -0
  104. package/docs/guides/edge-deployment.md +248 -0
  105. package/docs/guides/framework-integration.md +142 -0
  106. package/docs/guides/iab-tcf.md +89 -0
  107. package/docs/guides/observability.md +96 -0
  108. package/docs/guides/policy-packs.md +396 -0
  109. package/docs/quickstart.md +129 -0
  110. package/package.json +37 -23
  111. package/.turbo/turbo-build.log +0 -49
  112. package/CHANGELOG.md +0 -115
  113. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  114. package/dist/cache/adapters/index.d.ts.map +0 -1
  115. package/dist/cache/adapters/memory.d.ts.map +0 -1
  116. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  117. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  118. package/dist/cache/index.d.ts.map +0 -1
  119. package/dist/cache/keys.d.ts.map +0 -1
  120. package/dist/cache/types.d.ts.map +0 -1
  121. package/dist/core.d.ts.map +0 -1
  122. package/dist/db/adapters/drizzle.d.ts +0 -2
  123. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  124. package/dist/db/adapters/index.d.ts +0 -2
  125. package/dist/db/adapters/index.d.ts.map +0 -1
  126. package/dist/db/adapters/kysely.d.ts +0 -2
  127. package/dist/db/adapters/kysely.d.ts.map +0 -1
  128. package/dist/db/adapters/mongo.d.ts +0 -2
  129. package/dist/db/adapters/mongo.d.ts.map +0 -1
  130. package/dist/db/adapters/prisma.d.ts +0 -2
  131. package/dist/db/adapters/prisma.d.ts.map +0 -1
  132. package/dist/db/adapters/typeorm.d.ts +0 -2
  133. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  134. package/dist/db/migrator/index.d.ts.map +0 -1
  135. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  136. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  137. package/dist/db/registry/domain.d.ts.map +0 -1
  138. package/dist/db/registry/index.d.ts.map +0 -1
  139. package/dist/db/registry/subject.d.ts.map +0 -1
  140. package/dist/db/registry/types.d.ts.map +0 -1
  141. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  142. package/dist/db/registry/utils.d.ts.map +0 -1
  143. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  144. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  145. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  146. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  147. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  148. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  149. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  150. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  151. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  152. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  153. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  154. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  155. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  156. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  157. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  158. package/dist/db/schema/index.d.ts.map +0 -1
  159. package/dist/db/tenant-scope.d.ts.map +0 -1
  160. package/dist/define-config.d.ts +0 -5
  161. package/dist/define-config.d.ts.map +0 -1
  162. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  163. package/dist/handlers/consent/index.d.ts +0 -12
  164. package/dist/handlers/consent/index.d.ts.map +0 -1
  165. package/dist/handlers/init/geo.d.ts.map +0 -1
  166. package/dist/handlers/init/index.d.ts.map +0 -1
  167. package/dist/handlers/init/translations.d.ts +0 -28
  168. package/dist/handlers/init/translations.d.ts.map +0 -1
  169. package/dist/handlers/status/index.d.ts +0 -7
  170. package/dist/handlers/status/index.d.ts.map +0 -1
  171. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  172. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  173. package/dist/handlers/subject/index.d.ts +0 -10
  174. package/dist/handlers/subject/index.d.ts.map +0 -1
  175. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  176. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  177. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  178. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  179. package/dist/init.d.ts.map +0 -1
  180. package/dist/middleware/auth/index.d.ts.map +0 -1
  181. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  182. package/dist/middleware/cors/cors.d.ts.map +0 -1
  183. package/dist/middleware/cors/index.d.ts +0 -30
  184. package/dist/middleware/cors/index.d.ts.map +0 -1
  185. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  186. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  187. package/dist/middleware/openapi/config.d.ts.map +0 -1
  188. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  189. package/dist/middleware/openapi/index.d.ts +0 -12
  190. package/dist/middleware/openapi/index.d.ts.map +0 -1
  191. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  192. package/dist/router.d.ts.map +0 -1
  193. package/dist/routes/consent.d.ts.map +0 -1
  194. package/dist/routes/index.d.ts +0 -10
  195. package/dist/routes/index.d.ts.map +0 -1
  196. package/dist/routes/init.d.ts.map +0 -1
  197. package/dist/routes/status.d.ts.map +0 -1
  198. package/dist/routes/subject.d.ts.map +0 -1
  199. package/dist/types/api.d.ts.map +0 -1
  200. package/dist/types/index.d.ts +0 -263
  201. package/dist/types/index.d.ts.map +0 -1
  202. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  203. package/dist/utils/env.d.ts.map +0 -1
  204. package/dist/utils/extract-error-message.d.ts.map +0 -1
  205. package/dist/utils/index.d.ts +0 -4
  206. package/dist/utils/index.d.ts.map +0 -1
  207. package/dist/utils/instrumentation.d.ts.map +0 -1
  208. package/dist/utils/logger.d.ts.map +0 -1
  209. package/dist/utils/metrics.d.ts.map +0 -1
  210. package/dist/version.d.ts +0 -2
  211. package/dist/version.d.ts.map +0 -1
  212. package/knip.json +0 -31
  213. package/rslib.config.ts +0 -93
  214. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  215. package/src/cache/adapters/index.ts +0 -22
  216. package/src/cache/adapters/memory.ts +0 -111
  217. package/src/cache/adapters/upstash-redis.ts +0 -113
  218. package/src/cache/gvl-resolver.ts +0 -289
  219. package/src/cache/index.ts +0 -34
  220. package/src/cache/keys.ts +0 -68
  221. package/src/cache/types.ts +0 -66
  222. package/src/core.ts +0 -369
  223. package/src/db/migrator/index.ts +0 -80
  224. package/src/db/registry/consent-policy.test.ts +0 -451
  225. package/src/db/registry/consent-policy.ts +0 -82
  226. package/src/db/registry/consent-purpose.test.ts +0 -428
  227. package/src/db/registry/consent-purpose.ts +0 -61
  228. package/src/db/registry/domain.test.ts +0 -445
  229. package/src/db/registry/domain.ts +0 -91
  230. package/src/db/registry/index.ts +0 -14
  231. package/src/db/registry/subject.test.ts +0 -371
  232. package/src/db/registry/subject.ts +0 -126
  233. package/src/db/registry/types.ts +0 -10
  234. package/src/db/registry/utils/generate-id.test.ts +0 -216
  235. package/src/db/registry/utils/generate-id.ts +0 -133
  236. package/src/db/registry/utils.ts +0 -133
  237. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  238. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  239. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  240. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  241. package/src/db/schema/1.0.0/consent.ts +0 -20
  242. package/src/db/schema/1.0.0/domain.ts +0 -12
  243. package/src/db/schema/1.0.0/index.ts +0 -48
  244. package/src/db/schema/1.0.0/subject.ts +0 -11
  245. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  246. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  247. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  248. package/src/db/schema/2.0.0/consent.ts +0 -28
  249. package/src/db/schema/2.0.0/domain.ts +0 -12
  250. package/src/db/schema/2.0.0/index.ts +0 -47
  251. package/src/db/schema/2.0.0/subject.ts +0 -13
  252. package/src/db/schema/index.ts +0 -15
  253. package/src/db/tenant-scope.test.ts +0 -747
  254. package/src/db/tenant-scope.ts +0 -103
  255. package/src/define-config.ts +0 -5
  256. package/src/handlers/consent/check.handler.ts +0 -126
  257. package/src/handlers/init/geo.test.ts +0 -317
  258. package/src/handlers/init/geo.ts +0 -195
  259. package/src/handlers/init/index.test.ts +0 -205
  260. package/src/handlers/init/index.ts +0 -114
  261. package/src/handlers/init/translations.test.ts +0 -121
  262. package/src/handlers/init/translations.ts +0 -72
  263. package/src/handlers/status/status.handler.test.ts +0 -155
  264. package/src/handlers/status/status.handler.ts +0 -51
  265. package/src/handlers/subject/get.handler.ts +0 -92
  266. package/src/handlers/subject/list.handler.ts +0 -92
  267. package/src/handlers/subject/patch.handler.ts +0 -119
  268. package/src/handlers/subject/post.handler.test.ts +0 -294
  269. package/src/handlers/subject/post.handler.ts +0 -268
  270. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  271. package/src/handlers/utils/consent-enrichment.ts +0 -218
  272. package/src/init.test.ts +0 -126
  273. package/src/init.ts +0 -87
  274. package/src/middleware/auth/index.ts +0 -11
  275. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  276. package/src/middleware/auth/validate-api-key.ts +0 -107
  277. package/src/middleware/cors/cors.test.ts +0 -135
  278. package/src/middleware/cors/cors.ts +0 -186
  279. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  280. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  281. package/src/middleware/cors/process-cors.ts +0 -91
  282. package/src/middleware/openapi/config.ts +0 -29
  283. package/src/middleware/openapi/handlers.ts +0 -34
  284. package/src/middleware/process-ip/index.test.ts +0 -195
  285. package/src/middleware/process-ip/index.ts +0 -199
  286. package/src/router.ts +0 -15
  287. package/src/routes/consent.ts +0 -52
  288. package/src/routes/init.ts +0 -105
  289. package/src/routes/status.ts +0 -46
  290. package/src/routes/subject.ts +0 -152
  291. package/src/types/api.ts +0 -48
  292. package/src/types/index.ts +0 -297
  293. package/src/utils/create-telemetry-options.test.ts +0 -302
  294. package/src/utils/create-telemetry-options.ts +0 -229
  295. package/src/utils/env.ts +0 -84
  296. package/src/utils/extract-error-message.ts +0 -21
  297. package/src/utils/instrumentation.test.ts +0 -185
  298. package/src/utils/instrumentation.ts +0 -196
  299. package/src/utils/logger.ts +0 -41
  300. package/src/utils/metrics.test.ts +0 -323
  301. package/src/utils/metrics.ts +0 -402
  302. package/src/utils/telemetry-pii.test.ts +0 -325
  303. package/src/version.ts +0 -2
  304. package/tsconfig.json +0 -11
  305. package/vitest.config.ts +0 -28
  306. /package/dist/{types.cjs → types/index.cjs} +0 -0
  307. /package/dist/{types.js → types/index.js} +0 -0
  308. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  309. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  310. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  311. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  312. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  313. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  314. /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
package/dist/core.cjs CHANGED
@@ -172,6 +172,8 @@ var __webpack_modules__ = {
172
172
  tcString: (0, schema_namespaceObject.column)('tcString', 'string').nullable(),
173
173
  uiSource: (0, schema_namespaceObject.column)('uiSource', 'string').nullable(),
174
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', {
@@ -197,6 +199,27 @@ var __webpack_modules__ = {
197
199
  updatedAt: (0, schema_namespaceObject.column)('updatedAt', 'timestamp').defaultTo$('now'),
198
200
  tenantId: (0, schema_namespaceObject.column)('tenantId', 'string').nullable()
199
201
  });
202
+ const runtimePolicyDecisionTable = (0, schema_namespaceObject.table)('runtimePolicyDecision', {
203
+ id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
204
+ tenantId: (0, schema_namespaceObject.column)('tenantId', 'string').nullable(),
205
+ policyId: (0, schema_namespaceObject.column)('policyId', 'string'),
206
+ fingerprint: (0, schema_namespaceObject.column)('fingerprint', 'string'),
207
+ matchedBy: (0, schema_namespaceObject.column)('matchedBy', 'string'),
208
+ countryCode: (0, schema_namespaceObject.column)('countryCode', 'string').nullable(),
209
+ regionCode: (0, schema_namespaceObject.column)('regionCode', 'string').nullable(),
210
+ jurisdiction: (0, schema_namespaceObject.column)('jurisdiction', 'string'),
211
+ language: (0, schema_namespaceObject.column)('language', 'string').nullable(),
212
+ model: (0, schema_namespaceObject.column)('model', 'string'),
213
+ policyI18n: (0, schema_namespaceObject.column)('policyI18n', 'json').nullable(),
214
+ uiMode: (0, schema_namespaceObject.column)('uiMode', 'string').nullable(),
215
+ bannerUi: (0, schema_namespaceObject.column)('bannerUi', 'json').nullable(),
216
+ dialogUi: (0, schema_namespaceObject.column)('dialogUi', 'json').nullable(),
217
+ categories: (0, schema_namespaceObject.column)('categories', 'json').nullable(),
218
+ preselectedCategories: (0, schema_namespaceObject.column)('preselectedCategories', 'json').nullable(),
219
+ proofConfig: (0, schema_namespaceObject.column)('proofConfig', 'json').nullable(),
220
+ dedupeKey: (0, schema_namespaceObject.column)('dedupeKey', 'string').unique(),
221
+ createdAt: (0, schema_namespaceObject.column)('createdAt', 'timestamp').defaultTo$('now')
222
+ });
200
223
  const subject_subjectTable = (0, schema_namespaceObject.table)('subject', {
201
224
  id: (0, schema_namespaceObject.idColumn)('id', 'varchar(255)'),
202
225
  externalId: (0, schema_namespaceObject.column)('externalId', 'string').nullable(),
@@ -211,6 +234,7 @@ var __webpack_modules__ = {
211
234
  subject: subject_subjectTable,
212
235
  domain: domain_domainTable,
213
236
  consentPolicy: consent_policy_consentPolicyTable,
237
+ runtimePolicyDecision: runtimePolicyDecisionTable,
214
238
  consentPurpose: consent_purpose_consentPurposeTable,
215
239
  consent: consent_consentTable,
216
240
  auditLog: audit_log_auditLogTable
@@ -226,6 +250,9 @@ var __webpack_modules__ = {
226
250
  consentPolicy: ({ many })=>({
227
251
  consents: many('consent')
228
252
  }),
253
+ runtimePolicyDecision: ({ many })=>({
254
+ consents: many('consent')
255
+ }),
229
256
  consentPurpose: ()=>({}),
230
257
  consent: ({ one })=>({
231
258
  subject: one('subject', [
@@ -239,6 +266,10 @@ var __webpack_modules__ = {
239
266
  policy: one('consentPolicy', [
240
267
  'policyId',
241
268
  'id'
269
+ ]).foreignKey(),
270
+ runtimePolicyDecision: one('runtimePolicyDecision', [
271
+ 'runtimePolicyDecisionId',
272
+ 'id'
242
273
  ]).foreignKey()
243
274
  }),
244
275
  auditLog: ({ one })=>({
@@ -319,7 +350,15 @@ var __webpack_exports__ = {};
319
350
  __webpack_require__.d(__webpack_exports__, {
320
351
  version: ()=>version_version,
321
352
  c15tInstance: ()=>c15tInstance,
322
- defineConfig: ()=>define_config.defineConfig
353
+ EEA_COUNTRY_CODES: ()=>types_namespaceObject.EEA_COUNTRY_CODES,
354
+ EU_COUNTRY_CODES: ()=>types_namespaceObject.EU_COUNTRY_CODES,
355
+ UK_COUNTRY_CODES: ()=>types_namespaceObject.UK_COUNTRY_CODES,
356
+ policyMatchers: ()=>types_namespaceObject.policyMatchers,
357
+ policyBuilder: ()=>policyBuilder,
358
+ policyPackPresets: ()=>schema_.policyPackPresets,
359
+ inspectPolicies: ()=>inspectPolicies,
360
+ defineConfig: ()=>define_config.defineConfig,
361
+ POLICY_MATCH_DATASET_VERSION: ()=>types_namespaceObject.POLICY_MATCH_DATASET_VERSION
323
362
  });
324
363
  const logger_namespaceObject = require("@c15t/logger");
325
364
  const api_namespaceObject = require("@opentelemetry/api");
@@ -454,10 +493,10 @@ var __webpack_exports__ = {};
454
493
  };
455
494
  }
456
495
  const createOpenAPIConfig = (options)=>({
457
- enabled: options.advanced?.openapi?.enabled !== false,
496
+ enabled: options.openapi?.enabled !== false,
458
497
  specPath: '/spec.json',
459
498
  docsPath: '/docs',
460
- ...options.advanced?.openapi || {}
499
+ ...options.openapi || {}
461
500
  });
462
501
  const DEFAULT_IP_HEADERS = [
463
502
  'x-client-ip',
@@ -552,7 +591,7 @@ var __webpack_exports__ = {};
552
591
  return ip;
553
592
  }
554
593
  function getIpAddress(req, options) {
555
- const ipAddressConfig = options.advanced?.ipAddress;
594
+ const ipAddressConfig = options.ipAddress;
556
595
  if (ipAddressConfig?.tracking === false) return null;
557
596
  const ipHeaders = ipAddressConfig?.ipAddressHeaders || DEFAULT_IP_HEADERS;
558
597
  const headers = req instanceof Request ? req.headers : req;
@@ -568,7 +607,137 @@ var __webpack_exports__ = {};
568
607
  }
569
608
  return null;
570
609
  }
571
- const version_version = '2.0.0-rc.3';
610
+ const types_namespaceObject = require("@c15t/schema/types");
611
+ const translations_namespaceObject = require("@c15t/translations");
612
+ const all_namespaceObject = require("@c15t/translations/all");
613
+ const DEFAULT_PROFILE = 'default';
614
+ const warnedKeys = new Set();
615
+ function isSupportedBaseLanguage(lang) {
616
+ return lang in all_namespaceObject.baseTranslations;
617
+ }
618
+ function warnOnce(logger, key, message, metadata) {
619
+ if (!logger || warnedKeys.has(key)) return;
620
+ warnedKeys.add(key);
621
+ logger.warn(message, metadata);
622
+ }
623
+ function normalizeLanguage(value) {
624
+ if (!value) return;
625
+ const normalized = value.split(',')[0]?.split(';')[0]?.trim().toLowerCase();
626
+ if (!normalized) return;
627
+ return normalized.split('-')[0] ?? void 0;
628
+ }
629
+ function normalizeProfiles(params) {
630
+ const profiles = params.i18n?.messages;
631
+ const legacy = params.customTranslations;
632
+ if (profiles && Object.keys(profiles).length > 0) {
633
+ if (legacy && Object.keys(legacy).length > 0) warnOnce(params.logger, 'i18n.customTranslations.ignored', '`customTranslations` is deprecated and ignored when `i18n.messages` is configured.');
634
+ return profiles;
635
+ }
636
+ if (legacy && Object.keys(legacy).length > 0) {
637
+ warnOnce(params.logger, 'i18n.customTranslations.deprecated', '`customTranslations` is deprecated. Use `i18n.messages` instead.');
638
+ return {
639
+ [DEFAULT_PROFILE]: {
640
+ translations: legacy
641
+ }
642
+ };
643
+ }
644
+ return {};
645
+ }
646
+ function buildCandidates(input) {
647
+ const raw = [
648
+ {
649
+ language: input.language,
650
+ reason: 'profile_language'
651
+ },
652
+ {
653
+ language: input.fallbackLanguage,
654
+ reason: 'profile_fallback'
655
+ }
656
+ ];
657
+ const dedupe = new Set();
658
+ return raw.filter((candidate)=>{
659
+ const key = candidate.language;
660
+ if (dedupe.has(key)) return false;
661
+ dedupe.add(key);
662
+ return true;
663
+ });
664
+ }
665
+ function getProfileLanguages(profiles, profile) {
666
+ return Object.keys(profiles[profile]?.translations ?? {}).sort();
667
+ }
668
+ function getSelectableLanguages(input) {
669
+ return getProfileLanguages(input.profiles, input.profile);
670
+ }
671
+ function resolveFallbackLanguage(input) {
672
+ const configuredFallbackLanguage = normalizeLanguage(input.profile?.fallbackLanguage) ?? 'en';
673
+ const profileLanguages = Object.keys(input.profile?.translations ?? {}).sort();
674
+ if (profileLanguages.includes(configuredFallbackLanguage)) return configuredFallbackLanguage;
675
+ if (profileLanguages.includes('en')) return 'en';
676
+ return profileLanguages[0] ?? configuredFallbackLanguage;
677
+ }
678
+ function resolveActiveProfile(input) {
679
+ const requestedProfile = input.policyProfile ?? input.defaultProfile;
680
+ if (input.profiles[requestedProfile]) return requestedProfile;
681
+ if (input.policyProfile) warnOnce(input.logger, `i18n.profile.missing:${requestedProfile}`, `Policy i18n profile '${requestedProfile}' does not exist. Falling back to default profile '${input.defaultProfile}'.`);
682
+ return input.defaultProfile;
683
+ }
684
+ function validateMessages(options) {
685
+ return (0, types_namespaceObject.validatePolicyI18nConfig)({
686
+ customTranslations: options.customTranslations,
687
+ i18n: options.i18n,
688
+ policies: options.policies
689
+ });
690
+ }
691
+ function translations_getTranslationsData(acceptLanguage, customTranslations, options) {
692
+ const profiles = normalizeProfiles({
693
+ customTranslations,
694
+ i18n: options?.i18n,
695
+ logger: options?.logger
696
+ });
697
+ const defaultProfile = options?.i18n?.defaultProfile ?? DEFAULT_PROFILE;
698
+ const profile = resolveActiveProfile({
699
+ profiles,
700
+ defaultProfile,
701
+ policyProfile: options?.policyI18n?.messageProfile,
702
+ logger: options?.logger
703
+ });
704
+ const configuredLanguages = Object.keys(profiles).length > 0 ? getSelectableLanguages({
705
+ profiles,
706
+ profile
707
+ }) : Object.keys(all_namespaceObject.baseTranslations);
708
+ const fallbackLanguage = Object.keys(profiles).length > 0 ? resolveFallbackLanguage({
709
+ profile: profiles[profile]
710
+ }) : 'en';
711
+ const policyLanguage = normalizeLanguage(options?.policyI18n?.language);
712
+ const requestedLanguage = policyLanguage ?? (0, translations_namespaceObject.selectLanguage)(configuredLanguages, {
713
+ header: acceptLanguage,
714
+ fallback: fallbackLanguage
715
+ });
716
+ const candidates = buildCandidates({
717
+ language: requestedLanguage,
718
+ fallbackLanguage
719
+ });
720
+ const selectedCandidate = candidates.find((candidate)=>!!profiles[profile]?.translations[candidate.language]);
721
+ if (selectedCandidate && 'profile_language' !== selectedCandidate.reason) warnOnce(options?.logger, `i18n.fallback:${profile}:${requestedLanguage}:${selectedCandidate.language}`, `Policy translation fallback used (${selectedCandidate.reason}).`, {
722
+ requestedProfile: profile,
723
+ requestedLanguage,
724
+ resolvedProfile: profile,
725
+ resolvedLanguage: selectedCandidate.language
726
+ });
727
+ let language = selectedCandidate?.language ?? requestedLanguage;
728
+ if (!selectedCandidate && !isSupportedBaseLanguage(language)) {
729
+ warnOnce(options?.logger, `i18n.base-fallback:${language}`, `No translation found for '${language}'. Falling back to base English translations.`);
730
+ language = 'en';
731
+ }
732
+ const base = isSupportedBaseLanguage(language) ? all_namespaceObject.baseTranslations[language] : all_namespaceObject.baseTranslations.en;
733
+ const custom = selectedCandidate ? profiles[profile]?.translations[selectedCandidate.language] : void 0;
734
+ const translations = custom ? (0, translations_namespaceObject.deepMergeTranslations)(base, custom) : base;
735
+ return {
736
+ translations: translations,
737
+ language
738
+ };
739
+ }
740
+ const version_version = '2.0.0-rc.5';
572
741
  function extractErrorMessage(error) {
573
742
  if (error instanceof AggregateError && error.errors?.length > 0) {
574
743
  const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
@@ -597,18 +766,18 @@ var __webpack_exports__ = {};
597
766
  return config;
598
767
  }
599
768
  function isTelemetryEnabled(options) {
600
- if (options) return options.advanced?.telemetry?.enabled === true;
769
+ if (options) return options.telemetry?.enabled === true;
601
770
  return cachedConfig?.enabled === true;
602
771
  }
603
772
  const getTracer = (options)=>{
604
773
  if (!isTelemetryEnabled(options)) return api_namespaceObject.trace.getTracer('c15t-noop');
605
- const tracer = options?.advanced?.telemetry?.tracer ?? cachedConfig?.tracer;
774
+ const tracer = options?.telemetry?.tracer ?? cachedConfig?.tracer;
606
775
  if (tracer) return tracer;
607
776
  return api_namespaceObject.trace.getTracer(options?.appName ?? 'c15t');
608
777
  };
609
778
  const getMeter = (options)=>{
610
779
  if (!isTelemetryEnabled(options)) return api_namespaceObject.metrics.getMeter('c15t-noop');
611
- const meter = options?.advanced?.telemetry?.meter ?? cachedConfig?.meter;
780
+ const meter = options?.telemetry?.meter ?? cachedConfig?.meter;
612
781
  if (meter) return meter;
613
782
  return api_namespaceObject.metrics.getMeter(options?.appName ?? 'c15t');
614
783
  };
@@ -618,7 +787,7 @@ var __webpack_exports__ = {};
618
787
  const createRequestSpan = (method, path, options)=>{
619
788
  if (!isTelemetryEnabled(options)) return null;
620
789
  const tracer = getTracer(options);
621
- const defaultAttrs = options?.advanced?.telemetry?.defaultAttributes || getDefaultAttributes();
790
+ const defaultAttrs = options?.telemetry?.defaultAttributes || getDefaultAttributes();
622
791
  const span = tracer.startSpan(`${method} ${path}`, {
623
792
  attributes: {
624
793
  'http.method': method,
@@ -660,7 +829,7 @@ var __webpack_exports__ = {};
660
829
  }
661
830
  }
662
831
  function resolveDefaultAttributes(options) {
663
- return options?.advanced?.telemetry?.defaultAttributes || getDefaultAttributes();
832
+ return options?.telemetry?.defaultAttributes || getDefaultAttributes();
664
833
  }
665
834
  async function withDatabaseSpan(attributes, operation, options) {
666
835
  if (!isTelemetryEnabled(options)) return operation();
@@ -893,6 +1062,7 @@ var __webpack_exports__ = {};
893
1062
  consentPolicy: 'pol',
894
1063
  consentPurpose: 'pur',
895
1064
  domain: 'dom',
1065
+ runtimePolicyDecision: 'rpd',
896
1066
  subject: 'sub'
897
1067
  };
898
1068
  const b58 = external_base_x_default()('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
@@ -1164,6 +1334,54 @@ var __webpack_exports__ = {};
1164
1334
  }
1165
1335
  };
1166
1336
  }
1337
+ function runtimePolicyDecisionRegistry({ db, ctx }) {
1338
+ const { logger } = ctx;
1339
+ return {
1340
+ findOrCreateRuntimePolicyDecision: async (input)=>{
1341
+ const existing = await db.findFirst('runtimePolicyDecision', {
1342
+ where: (b)=>b('dedupeKey', '=', input.dedupeKey)
1343
+ });
1344
+ if (existing) return existing;
1345
+ logger.debug('Creating runtime policy decision', {
1346
+ policyId: input.policyId,
1347
+ fingerprint: input.fingerprint,
1348
+ matchedBy: input.matchedBy
1349
+ });
1350
+ return db.create('runtimePolicyDecision', {
1351
+ id: `rpd_${crypto.randomUUID().replaceAll('-', '')}`,
1352
+ tenantId: input.tenantId,
1353
+ policyId: input.policyId,
1354
+ fingerprint: input.fingerprint,
1355
+ matchedBy: input.matchedBy,
1356
+ countryCode: input.countryCode,
1357
+ regionCode: input.regionCode,
1358
+ jurisdiction: input.jurisdiction,
1359
+ language: input.language,
1360
+ model: input.model,
1361
+ policyI18n: input.policyI18n ? {
1362
+ json: input.policyI18n
1363
+ } : void 0,
1364
+ uiMode: input.uiMode,
1365
+ bannerUi: input.bannerUi ? {
1366
+ json: input.bannerUi
1367
+ } : void 0,
1368
+ dialogUi: input.dialogUi ? {
1369
+ json: input.dialogUi
1370
+ } : void 0,
1371
+ categories: input.categories ? {
1372
+ json: input.categories
1373
+ } : void 0,
1374
+ preselectedCategories: input.preselectedCategories ? {
1375
+ json: input.preselectedCategories
1376
+ } : void 0,
1377
+ proofConfig: input.proofConfig ? {
1378
+ json: input.proofConfig
1379
+ } : void 0,
1380
+ dedupeKey: input.dedupeKey
1381
+ });
1382
+ }
1383
+ };
1384
+ }
1167
1385
  function subjectRegistry({ db, ctx }) {
1168
1386
  const { logger } = ctx;
1169
1387
  return {
@@ -1241,7 +1459,8 @@ var __webpack_exports__ = {};
1241
1459
  ...subjectRegistry(ctx),
1242
1460
  ...consentPurposeRegistry(ctx),
1243
1461
  ...policyRegistry(ctx),
1244
- ...domainRegistry(ctx)
1462
+ ...domainRegistry(ctx),
1463
+ ...runtimePolicyDecisionRegistry(ctx)
1245
1464
  });
1246
1465
  var schema = __webpack_require__("./src/db/schema/index.ts");
1247
1466
  const SCOPED_METHODS = new Set([
@@ -1307,6 +1526,18 @@ var __webpack_exports__ = {};
1307
1526
  }
1308
1527
  });
1309
1528
  }
1529
+ function inspectPolicies(policies, options) {
1530
+ return (0, types_namespaceObject.inspectPolicies)(policies, options);
1531
+ }
1532
+ async function resolvePolicyDecision(params) {
1533
+ return (0, types_namespaceObject.resolvePolicyDecision)({
1534
+ policies: params.policies,
1535
+ countryCode: params.countryCode,
1536
+ regionCode: params.regionCode,
1537
+ jurisdiction: params.jurisdiction,
1538
+ iabEnabled: params.iabEnabled
1539
+ });
1540
+ }
1310
1541
  let globalLogger;
1311
1542
  function initLogger(options) {
1312
1543
  globalLogger = (0, logger_namespaceObject.createLogger)({
@@ -1321,7 +1552,7 @@ var __webpack_exports__ = {};
1321
1552
  ...options.logger,
1322
1553
  appName: String(appName)
1323
1554
  });
1324
- const telemetryOptions = createTelemetryOptions(String(appName), options.advanced?.telemetry, options.tenantId);
1555
+ const telemetryOptions = createTelemetryOptions(String(appName), options.telemetry, options.tenantId);
1325
1556
  if (isTelemetryEnabled(options)) logger.debug('Telemetry is enabled', {
1326
1557
  hasTracer: !!telemetryOptions?.tracer,
1327
1558
  hasMeter: !!telemetryOptions?.meter,
@@ -1332,8 +1563,21 @@ var __webpack_exports__ = {};
1332
1563
  const client = db.client(options.adapter);
1333
1564
  const rawOrm = client.orm('2.0.0');
1334
1565
  const orm = options.tenantId ? withTenantScope(rawOrm, options.tenantId) : rawOrm;
1566
+ const { ipAddress: _ipAddressConfig, ...baseOptions } = options;
1567
+ const i18nValidation = validateMessages({
1568
+ i18n: options.i18n,
1569
+ customTranslations: options.customTranslations,
1570
+ policies: options.policyPacks
1571
+ });
1572
+ for (const warning of i18nValidation.warnings)logger.warn(`i18n: ${warning}`);
1573
+ if (i18nValidation.errors.length > 0) throw new Error(`Invalid i18n configuration:\n${i18nValidation.errors.map((error)=>`- ${error}`).join('\n')}`);
1574
+ const policyValidation = inspectPolicies(options.policyPacks ?? [], {
1575
+ iabEnabled: options.iab?.enabled === true
1576
+ });
1577
+ for (const warning of policyValidation.warnings)logger.warn(`policyPacks: ${warning}`);
1578
+ if (policyValidation.errors.length > 0) throw new Error(policyValidation.errors[0]);
1335
1579
  const context = {
1336
- ...options,
1580
+ ...baseOptions,
1337
1581
  appName,
1338
1582
  logger,
1339
1583
  db: orm,
@@ -1692,6 +1936,124 @@ var __webpack_exports__ = {};
1692
1936
  }
1693
1937
  };
1694
1938
  }
1939
+ const external_jose_namespaceObject = require("jose");
1940
+ const POLICY_SNAPSHOT_JWT_HEADER = {
1941
+ alg: 'HS256',
1942
+ typ: 'JWT'
1943
+ };
1944
+ const DEFAULT_POLICY_SNAPSHOT_ISSUER = 'c15t';
1945
+ const DEFAULT_POLICY_SNAPSHOT_AUDIENCE = 'c15t-policy-snapshot';
1946
+ function resolveSnapshotIssuer(options) {
1947
+ return options?.issuer?.trim() || DEFAULT_POLICY_SNAPSHOT_ISSUER;
1948
+ }
1949
+ function resolveSnapshotAudience(params) {
1950
+ const configuredAudience = params.options?.audience?.trim();
1951
+ if (configuredAudience) return configuredAudience;
1952
+ return params.tenantId ? `${DEFAULT_POLICY_SNAPSHOT_AUDIENCE}:${params.tenantId}` : DEFAULT_POLICY_SNAPSHOT_AUDIENCE;
1953
+ }
1954
+ function getSigningKey(secret) {
1955
+ return new TextEncoder().encode(secret);
1956
+ }
1957
+ function isPolicySnapshotPayload(payload) {
1958
+ 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;
1959
+ }
1960
+ async function createPolicySnapshotToken(params) {
1961
+ const { options } = params;
1962
+ if (!options?.signingKey) return;
1963
+ const iat = Math.floor(Date.now() / 1000);
1964
+ const ttlSeconds = options.ttlSeconds ?? 1800;
1965
+ const exp = iat + ttlSeconds;
1966
+ const iss = resolveSnapshotIssuer(options);
1967
+ const aud = resolveSnapshotAudience({
1968
+ options,
1969
+ tenantId: params.tenantId
1970
+ });
1971
+ const payload = {
1972
+ iss,
1973
+ aud,
1974
+ sub: params.policyId,
1975
+ tenantId: params.tenantId,
1976
+ policyId: params.policyId,
1977
+ fingerprint: params.fingerprint,
1978
+ matchedBy: params.matchedBy,
1979
+ country: params.country,
1980
+ region: params.region,
1981
+ jurisdiction: params.jurisdiction,
1982
+ language: params.language,
1983
+ model: params.model,
1984
+ policyI18n: params.policyI18n,
1985
+ expiryDays: params.expiryDays,
1986
+ scopeMode: params.scopeMode,
1987
+ uiMode: params.uiMode,
1988
+ bannerUi: params.bannerUi,
1989
+ dialogUi: params.dialogUi,
1990
+ categories: params.categories,
1991
+ preselectedCategories: params.preselectedCategories,
1992
+ gpc: params.gpc,
1993
+ proofConfig: params.proofConfig,
1994
+ iat,
1995
+ exp
1996
+ };
1997
+ const token = await new external_jose_namespaceObject.SignJWT(payload).setProtectedHeader(POLICY_SNAPSHOT_JWT_HEADER).setIssuedAt(iat).setExpirationTime(exp).sign(getSigningKey(options.signingKey));
1998
+ return {
1999
+ token,
2000
+ payload
2001
+ };
2002
+ }
2003
+ async function verifyPolicySnapshotToken(params) {
2004
+ const { token, options, tenantId } = params;
2005
+ if (!options?.signingKey) return {
2006
+ valid: false,
2007
+ reason: 'missing'
2008
+ };
2009
+ if (!token) return {
2010
+ valid: false,
2011
+ reason: 'missing'
2012
+ };
2013
+ if (3 !== token.split('.').length) return {
2014
+ valid: false,
2015
+ reason: 'malformed'
2016
+ };
2017
+ try {
2018
+ const { payload, protectedHeader } = await (0, external_jose_namespaceObject.jwtVerify)(token, getSigningKey(options.signingKey), {
2019
+ issuer: resolveSnapshotIssuer(options),
2020
+ audience: resolveSnapshotAudience({
2021
+ options,
2022
+ tenantId
2023
+ })
2024
+ });
2025
+ const header = protectedHeader;
2026
+ if ('HS256' !== header.alg || 'JWT' !== header.typ) return {
2027
+ valid: false,
2028
+ reason: 'invalid'
2029
+ };
2030
+ if (!isPolicySnapshotPayload(payload)) return {
2031
+ valid: false,
2032
+ reason: 'invalid'
2033
+ };
2034
+ if (payload.sub !== payload.policyId) return {
2035
+ valid: false,
2036
+ reason: 'invalid'
2037
+ };
2038
+ if ((tenantId ?? void 0) !== (payload.tenantId ?? void 0)) return {
2039
+ valid: false,
2040
+ reason: 'invalid'
2041
+ };
2042
+ return {
2043
+ valid: true,
2044
+ payload
2045
+ };
2046
+ } catch (error) {
2047
+ if (error instanceof external_jose_namespaceObject.errors.JWTExpired) return {
2048
+ valid: false,
2049
+ reason: 'expired'
2050
+ };
2051
+ return {
2052
+ valid: false,
2053
+ reason: 'invalid'
2054
+ };
2055
+ }
2056
+ }
1695
2057
  function geo_normalizeHeader(value) {
1696
2058
  if (!value) return null;
1697
2059
  return Array.isArray(value) ? value[0] ?? null : value;
@@ -1833,7 +2195,7 @@ var __webpack_exports__ = {};
1833
2195
  return jurisdiction;
1834
2196
  }
1835
2197
  async function getLocation(request, options) {
1836
- if (options.advanced?.disableGeoLocation) return {
2198
+ if (options.disableGeoLocation) return {
1837
2199
  countryCode: null,
1838
2200
  regionCode: null
1839
2201
  };
@@ -1844,30 +2206,121 @@ var __webpack_exports__ = {};
1844
2206
  };
1845
2207
  }
1846
2208
  function getJurisdiction(location, options) {
1847
- if (options.advanced?.disableGeoLocation) return 'GDPR';
2209
+ if (options.disableGeoLocation) return 'GDPR';
1848
2210
  return checkJurisdiction(location.countryCode, location.regionCode);
1849
2211
  }
1850
- const translations_namespaceObject = require("@c15t/translations");
1851
- function isSupportedBaseLanguage(lang) {
1852
- return lang in translations_namespaceObject.baseTranslations;
1853
- }
1854
- function translations_getTranslationsData(acceptLanguage, customTranslations) {
1855
- const supportedDefaultLanguages = Object.keys(translations_namespaceObject.baseTranslations);
1856
- const supportedCustomLanguages = Object.keys(customTranslations || {});
1857
- const supportedLanguages = [
1858
- ...supportedDefaultLanguages,
1859
- ...supportedCustomLanguages
1860
- ];
1861
- const preferredLanguage = (0, translations_namespaceObject.selectLanguage)(supportedLanguages, {
1862
- header: acceptLanguage,
1863
- fallback: 'en'
2212
+ function stripIabTranslations(translations) {
2213
+ const { iab: _iab, ...rest } = translations;
2214
+ return rest;
2215
+ }
2216
+ function resolveNoPolicyFallback() {
2217
+ return {
2218
+ id: 'no_banner',
2219
+ model: 'none',
2220
+ ui: {
2221
+ mode: 'none'
2222
+ }
2223
+ };
2224
+ }
2225
+ async function resolveInitPayload(request, options, logger) {
2226
+ const acceptLanguage = request.headers.get('accept-language') || 'en';
2227
+ const location = await getLocation(request, options);
2228
+ const jurisdiction = getJurisdiction(location, options);
2229
+ const hasExplicitPolicyPack = void 0 !== options.policyPacks;
2230
+ const isExplicitEmptyPolicyPack = hasExplicitPolicyPack && (options.policyPacks?.length ?? 0) === 0;
2231
+ const policyDecision = isExplicitEmptyPolicyPack ? void 0 : await resolvePolicyDecision({
2232
+ policies: options.policyPacks,
2233
+ countryCode: location.countryCode,
2234
+ regionCode: location.regionCode,
2235
+ jurisdiction,
2236
+ iabEnabled: options.iab?.enabled === true
2237
+ });
2238
+ if (hasExplicitPolicyPack && !isExplicitEmptyPolicyPack && !policyDecision) logger?.warn('Policy packs configured but no policy matched', {
2239
+ country: location.countryCode,
2240
+ region: location.regionCode
2241
+ });
2242
+ const resolvedPolicy = hasExplicitPolicyPack ? policyDecision?.policy ?? resolveNoPolicyFallback() : void 0;
2243
+ const iabOptions = options.iab;
2244
+ const shouldIncludeIabPayload = iabOptions?.enabled === true && (!hasExplicitPolicyPack || resolvedPolicy?.model === 'iab');
2245
+ const translationsResult = translations_getTranslationsData(acceptLanguage, options.customTranslations, {
2246
+ i18n: options.i18n,
2247
+ policyI18n: resolvedPolicy?.i18n,
2248
+ logger
2249
+ });
2250
+ const responseTranslations = shouldIncludeIabPayload ? translationsResult : {
2251
+ ...translationsResult,
2252
+ translations: stripIabTranslations(translationsResult.translations)
2253
+ };
2254
+ let gvl = null;
2255
+ if (shouldIncludeIabPayload && iabOptions) {
2256
+ const language = translationsResult.language.split('-')[0] || 'en';
2257
+ const gvlResolver = createGVLResolver({
2258
+ appName: options.appName || 'c15t',
2259
+ bundled: iabOptions.bundled,
2260
+ cacheAdapter: options.cache?.adapter,
2261
+ vendorIds: iabOptions.vendorIds,
2262
+ endpoint: iabOptions.endpoint
2263
+ });
2264
+ gvl = await gvlResolver.get(language);
2265
+ }
2266
+ const customVendors = shouldIncludeIabPayload ? iabOptions?.customVendors : void 0;
2267
+ const snapshot = policyDecision ? await createPolicySnapshotToken({
2268
+ options: options.policySnapshot,
2269
+ tenantId: options.tenantId,
2270
+ policyId: policyDecision.policy.id,
2271
+ fingerprint: policyDecision.fingerprint,
2272
+ matchedBy: policyDecision.matchedBy,
2273
+ country: location?.countryCode ?? null,
2274
+ region: location?.regionCode ?? null,
2275
+ jurisdiction,
2276
+ language: translationsResult.language,
2277
+ model: policyDecision.policy.model,
2278
+ policyI18n: policyDecision.policy.i18n,
2279
+ expiryDays: policyDecision.policy.consent?.expiryDays,
2280
+ scopeMode: policyDecision.policy.consent?.scopeMode,
2281
+ uiMode: policyDecision.policy.ui?.mode,
2282
+ bannerUi: policyDecision.policy.ui?.banner,
2283
+ dialogUi: policyDecision.policy.ui?.dialog,
2284
+ categories: policyDecision.policy.consent?.categories,
2285
+ preselectedCategories: policyDecision.policy.consent?.preselectedCategories,
2286
+ gpc: policyDecision.policy.consent?.gpc,
2287
+ proofConfig: policyDecision.policy.proof
2288
+ }) : void 0;
2289
+ const gpc = '1' === request.headers.get('sec-gpc');
2290
+ getMetrics()?.recordInit({
2291
+ jurisdiction,
2292
+ country: location?.countryCode ?? void 0,
2293
+ region: location?.regionCode ?? void 0,
2294
+ gpc
1864
2295
  });
1865
- const base = isSupportedBaseLanguage(preferredLanguage) ? translations_namespaceObject.baseTranslations[preferredLanguage] : translations_namespaceObject.baseTranslations.en;
1866
- const custom = supportedCustomLanguages.includes(preferredLanguage) ? customTranslations?.[preferredLanguage] : {};
1867
- const translations = custom ? (0, translations_namespaceObject.deepMergeTranslations)(base, custom) : base;
1868
2296
  return {
1869
- translations: translations,
1870
- language: preferredLanguage
2297
+ jurisdiction,
2298
+ location,
2299
+ translations: responseTranslations,
2300
+ branding: options.branding || 'c15t',
2301
+ ...shouldIncludeIabPayload && {
2302
+ gvl,
2303
+ customVendors
2304
+ },
2305
+ ...resolvedPolicy && {
2306
+ policy: resolvedPolicy
2307
+ },
2308
+ ...policyDecision && {
2309
+ policyDecision: {
2310
+ policyId: policyDecision.policy.id,
2311
+ fingerprint: policyDecision.fingerprint,
2312
+ matchedBy: policyDecision.matchedBy,
2313
+ country: location.countryCode,
2314
+ region: location.regionCode,
2315
+ jurisdiction
2316
+ }
2317
+ },
2318
+ ...snapshot?.token && {
2319
+ policySnapshotToken: snapshot.token
2320
+ },
2321
+ ...shouldIncludeIabPayload && iabOptions?.cmpId != null && {
2322
+ cmpId: iabOptions.cmpId
2323
+ }
1871
2324
  };
1872
2325
  }
1873
2326
  const createInitRoute = (options)=>{
@@ -1880,7 +2333,7 @@ var __webpack_exports__ = {};
1880
2333
  - **Location** – User's location (null if geo-location is disabled)
1881
2334
  - **Translations** – Consent manager copy (from \`Accept-Language\` header)
1882
2335
  - **Branding** – Configured branding key
1883
- - **GVL** – Global Vendor List when enabled
2336
+ - **GVL** – Global Vendor List when IAB is active for the request
1884
2337
 
1885
2338
  Use for geo-targeted consent banners and regional compliance.`,
1886
2339
  tags: [
@@ -1897,42 +2350,9 @@ Use for geo-targeted consent banners and regional compliance.`,
1897
2350
  }
1898
2351
  }
1899
2352
  }), async (c)=>{
1900
- const request = c.req.raw;
1901
- const acceptLanguage = request.headers.get('accept-language') || 'en';
1902
- const location = await getLocation(request, options);
1903
- const jurisdiction = getJurisdiction(location, options);
1904
- const translationsResult = translations_getTranslationsData(acceptLanguage, options.advanced?.customTranslations);
1905
- let gvl = null;
1906
- if (options.advanced?.iab?.enabled) {
1907
- const language = translationsResult.language.split('-')[0] || 'en';
1908
- const gvlResolver = createGVLResolver({
1909
- appName: options.appName || 'c15t',
1910
- bundled: options.advanced.iab.bundled,
1911
- cacheAdapter: options.advanced.cache?.adapter,
1912
- vendorIds: options.advanced.iab.vendorIds,
1913
- endpoint: options.advanced.iab.endpoint
1914
- });
1915
- gvl = await gvlResolver.get(language);
1916
- }
1917
- const customVendors = options.advanced?.iab?.customVendors;
1918
- const gpc = '1' === request.headers.get('sec-gpc');
1919
- getMetrics()?.recordInit({
1920
- jurisdiction,
1921
- country: location?.countryCode ?? void 0,
1922
- region: location?.regionCode ?? void 0,
1923
- gpc
1924
- });
1925
- return c.json({
1926
- jurisdiction,
1927
- location,
1928
- translations: translationsResult,
1929
- branding: options.advanced?.branding || 'c15t',
1930
- gvl,
1931
- customVendors,
1932
- ...options.advanced?.iab?.cmpId != null && {
1933
- cmpId: options.advanced.iab.cmpId
1934
- }
1935
- });
2353
+ const ctx = c.get('c15tContext');
2354
+ const payload = await resolveInitPayload(c.req.raw, options, ctx?.logger);
2355
+ return c.json(payload);
1936
2356
  });
1937
2357
  return app;
1938
2358
  };
@@ -2289,6 +2709,119 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2289
2709
  });
2290
2710
  }
2291
2711
  };
2712
+ function buildRuntimeDecisionDedupeKey(input) {
2713
+ return [
2714
+ input.tenantId ?? 'default',
2715
+ input.fingerprint,
2716
+ input.matchedBy,
2717
+ input.countryCode ?? 'none',
2718
+ input.regionCode ?? 'none',
2719
+ input.jurisdiction,
2720
+ input.language ?? 'none'
2721
+ ].join('|');
2722
+ }
2723
+ function buildDecisionPayload(params) {
2724
+ const { tenantId, snapshot, decision, location, jurisdiction, language, proofConfig } = params;
2725
+ if (snapshot?.valid && snapshot.payload) {
2726
+ const sp = snapshot.payload;
2727
+ return {
2728
+ tenantId,
2729
+ policyId: sp.policyId,
2730
+ fingerprint: sp.fingerprint,
2731
+ matchedBy: sp.matchedBy,
2732
+ countryCode: sp.country,
2733
+ regionCode: sp.region,
2734
+ jurisdiction: sp.jurisdiction,
2735
+ language: sp.language,
2736
+ model: sp.model,
2737
+ policyI18n: sp.policyI18n,
2738
+ uiMode: sp.uiMode,
2739
+ bannerUi: sp.bannerUi,
2740
+ dialogUi: sp.dialogUi,
2741
+ categories: sp.categories,
2742
+ preselectedCategories: sp.preselectedCategories,
2743
+ proofConfig: sp.proofConfig,
2744
+ dedupeKey: buildRuntimeDecisionDedupeKey({
2745
+ tenantId,
2746
+ fingerprint: sp.fingerprint,
2747
+ matchedBy: sp.matchedBy,
2748
+ countryCode: sp.country,
2749
+ regionCode: sp.region,
2750
+ jurisdiction: sp.jurisdiction,
2751
+ language: sp.language
2752
+ }),
2753
+ source: 'snapshot_token'
2754
+ };
2755
+ }
2756
+ if (decision) return {
2757
+ tenantId,
2758
+ policyId: decision.policy.id,
2759
+ fingerprint: decision.fingerprint,
2760
+ matchedBy: decision.matchedBy,
2761
+ countryCode: location.countryCode,
2762
+ regionCode: location.regionCode,
2763
+ jurisdiction,
2764
+ language,
2765
+ model: decision.policy.model,
2766
+ policyI18n: decision.policy.i18n,
2767
+ uiMode: decision.policy.ui?.mode,
2768
+ bannerUi: decision.policy.ui?.banner,
2769
+ dialogUi: decision.policy.ui?.dialog,
2770
+ categories: decision.policy.consent?.categories,
2771
+ preselectedCategories: decision.policy.consent?.preselectedCategories,
2772
+ proofConfig,
2773
+ dedupeKey: buildRuntimeDecisionDedupeKey({
2774
+ tenantId,
2775
+ fingerprint: decision.fingerprint,
2776
+ matchedBy: decision.matchedBy,
2777
+ countryCode: location.countryCode,
2778
+ regionCode: location.regionCode,
2779
+ jurisdiction,
2780
+ language
2781
+ }),
2782
+ source: 'write_time_fallback'
2783
+ };
2784
+ }
2785
+ function parseLanguageFromHeader(header) {
2786
+ if (!header) return;
2787
+ const firstLanguage = header.split(',')[0]?.split(';')[0]?.trim();
2788
+ if (!firstLanguage) return;
2789
+ return firstLanguage.split('-')[0]?.toLowerCase();
2790
+ }
2791
+ function resolveSnapshotFailureMode(ctx) {
2792
+ return ctx.policySnapshot?.onValidationFailure ?? 'reject';
2793
+ }
2794
+ function buildSnapshotHttpException(reason) {
2795
+ switch(reason){
2796
+ case 'missing':
2797
+ return new http_exception_namespaceObject.HTTPException(409, {
2798
+ message: 'Policy snapshot token is required',
2799
+ cause: {
2800
+ code: 'POLICY_SNAPSHOT_REQUIRED'
2801
+ }
2802
+ });
2803
+ case 'expired':
2804
+ return new http_exception_namespaceObject.HTTPException(409, {
2805
+ message: 'Policy snapshot token has expired',
2806
+ cause: {
2807
+ code: 'POLICY_SNAPSHOT_EXPIRED'
2808
+ }
2809
+ });
2810
+ case 'malformed':
2811
+ case 'invalid':
2812
+ return new http_exception_namespaceObject.HTTPException(409, {
2813
+ message: 'Policy snapshot token is invalid',
2814
+ cause: {
2815
+ code: 'POLICY_SNAPSHOT_INVALID'
2816
+ }
2817
+ });
2818
+ default:
2819
+ {
2820
+ const _exhaustive = reason;
2821
+ throw new Error(`Unhandled policy snapshot verification failure reason: ${_exhaustive}`);
2822
+ }
2823
+ }
2824
+ }
2292
2825
  const postSubjectHandler = async (c)=>{
2293
2826
  const ctx = c.get('c15tContext');
2294
2827
  const logger = ctx.logger;
@@ -2300,9 +2833,6 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2300
2833
  const givenAt = new Date(givenAtEpoch);
2301
2834
  const rawConsentAction = 'consentAction' in input ? input.consentAction : void 0;
2302
2835
  let derivedConsentAction;
2303
- if ('all' === rawConsentAction) derivedConsentAction = 'accept_all';
2304
- else if ('necessary' === rawConsentAction) derivedConsentAction = 'opt-out' === input.jurisdictionModel ? 'opt_out' : 'reject_all';
2305
- else if ('custom' === rawConsentAction) derivedConsentAction = 'custom';
2306
2836
  logger.debug('Request parameters', {
2307
2837
  type,
2308
2838
  subjectId,
@@ -2311,6 +2841,50 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2311
2841
  domain
2312
2842
  });
2313
2843
  try {
2844
+ 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.');
2845
+ const request = c.req.raw ?? new Request('https://c15t.local/subjects');
2846
+ const acceptLanguage = request.headers.get('accept-language');
2847
+ const requestLanguage = parseLanguageFromHeader(acceptLanguage);
2848
+ const location = await getLocation(request, ctx);
2849
+ const resolvedJurisdiction = getJurisdiction(location, ctx);
2850
+ const snapshotVerification = await verifyPolicySnapshotToken({
2851
+ token: input.policySnapshotToken,
2852
+ options: ctx.policySnapshot,
2853
+ tenantId: ctx.tenantId
2854
+ });
2855
+ const hasValidSnapshot = snapshotVerification.valid;
2856
+ const snapshotPayload = snapshotVerification.valid ? snapshotVerification.payload : null;
2857
+ const shouldRequireSnapshot = !!ctx.policySnapshot?.signingKey && 'reject' === resolveSnapshotFailureMode(ctx);
2858
+ if (!hasValidSnapshot && shouldRequireSnapshot) throw buildSnapshotHttpException(snapshotVerification.reason);
2859
+ const resolvedPolicyDecision = hasValidSnapshot ? void 0 : await resolvePolicyDecision({
2860
+ policies: ctx.policyPacks,
2861
+ countryCode: location.countryCode,
2862
+ regionCode: location.regionCode,
2863
+ jurisdiction: resolvedJurisdiction,
2864
+ iabEnabled: ctx.iab?.enabled === true
2865
+ });
2866
+ const effectivePolicy = hasValidSnapshot && snapshotPayload ? {
2867
+ id: snapshotPayload.policyId,
2868
+ model: snapshotPayload.model,
2869
+ i18n: snapshotPayload.policyI18n,
2870
+ consent: {
2871
+ expiryDays: snapshotPayload.expiryDays,
2872
+ scopeMode: snapshotPayload.scopeMode,
2873
+ categories: snapshotPayload.categories,
2874
+ preselectedCategories: snapshotPayload.preselectedCategories,
2875
+ gpc: snapshotPayload.gpc
2876
+ },
2877
+ ui: {
2878
+ mode: snapshotPayload.uiMode,
2879
+ banner: snapshotPayload.bannerUi,
2880
+ dialog: snapshotPayload.dialogUi
2881
+ },
2882
+ proof: snapshotPayload.proofConfig
2883
+ } : resolvedPolicyDecision?.policy;
2884
+ const effectiveModel = effectivePolicy?.model ?? ('opt-in' === input.jurisdictionModel || 'opt-out' === input.jurisdictionModel || 'iab' === input.jurisdictionModel ? input.jurisdictionModel : void 0);
2885
+ if ('all' === rawConsentAction) derivedConsentAction = 'accept_all';
2886
+ else if ('necessary' === rawConsentAction) derivedConsentAction = 'opt-out' === effectiveModel ? 'opt_out' : 'reject_all';
2887
+ else if ('custom' === rawConsentAction) derivedConsentAction = 'custom';
2314
2888
  const subject = await registry.findOrCreateSubject({
2315
2889
  subjectId,
2316
2890
  externalSubjectId,
@@ -2337,6 +2911,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2337
2911
  });
2338
2912
  let policyId;
2339
2913
  let purposeIds = [];
2914
+ let appliedPreferences;
2340
2915
  const inputPolicyId = 'policyId' in input ? input.policyId : void 0;
2341
2916
  if (inputPolicyId) {
2342
2917
  policyId = inputPolicyId;
@@ -2369,20 +2944,66 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2369
2944
  policyId = policy.id;
2370
2945
  }
2371
2946
  if (preferences) {
2372
- const consentedPurposes = Object.entries(preferences).filter(([_, isConsented])=>isConsented).map(([purposeCode])=>purposeCode);
2947
+ const allowedCategories = effectivePolicy?.consent?.categories;
2948
+ const effectiveScopeMode = effectivePolicy?.consent?.scopeMode ?? 'permissive';
2949
+ const hasWildcardCategoryScope = allowedCategories?.includes('*') === true;
2950
+ const appliedPreferenceEntries = Object.entries(preferences);
2951
+ let filteredAppliedPreferenceEntries = appliedPreferenceEntries;
2952
+ if (allowedCategories && allowedCategories.length > 0 && !hasWildcardCategoryScope) {
2953
+ const disallowed = appliedPreferenceEntries.map(([purpose])=>purpose).filter((purpose)=>!allowedCategories.includes(purpose));
2954
+ filteredAppliedPreferenceEntries = appliedPreferenceEntries.filter(([purpose])=>allowedCategories.includes(purpose));
2955
+ if (disallowed.length > 0 && 'strict' === effectiveScopeMode) throw new http_exception_namespaceObject.HTTPException(400, {
2956
+ message: 'Preferences include categories not allowed by policy',
2957
+ cause: {
2958
+ code: 'PURPOSE_NOT_ALLOWED',
2959
+ disallowed
2960
+ }
2961
+ });
2962
+ }
2963
+ appliedPreferences = Object.fromEntries(filteredAppliedPreferenceEntries);
2964
+ const filteredConsentedPurposeCodes = filteredAppliedPreferenceEntries.filter(([_, isConsented])=>isConsented).map(([purposeCode])=>purposeCode);
2373
2965
  logger.debug('Consented purposes', {
2374
- consentedPurposes
2966
+ consentedPurposes: filteredConsentedPurposeCodes
2375
2967
  });
2376
- const purposesRaw = await Promise.all(consentedPurposes.map((purposeCode)=>registry.findOrCreateConsentPurposeByCode(purposeCode)));
2968
+ const purposesRaw = await Promise.all(filteredConsentedPurposeCodes.map((purposeCode)=>registry.findOrCreateConsentPurposeByCode(purposeCode)));
2377
2969
  const purposes = purposesRaw.map((purpose)=>purpose?.id ?? null).filter((id)=>Boolean(id));
2378
2970
  logger.debug('Filtered purposes', {
2379
2971
  purposes
2380
2972
  });
2381
2973
  if (0 === purposes.length) logger.warn('No valid purpose IDs found after filtering. Using empty list.', {
2382
- consentedPurposes
2974
+ consentedPurposes: filteredConsentedPurposeCodes
2383
2975
  });
2384
2976
  purposeIds = purposes;
2385
2977
  }
2978
+ const expiryDays = effectivePolicy?.consent?.expiryDays;
2979
+ const validUntil = 'number' == typeof expiryDays && Number.isFinite(expiryDays) ? new Date(givenAt.getTime() + 86400000 * Math.max(0, expiryDays)) : void 0;
2980
+ const proofConfig = effectivePolicy?.proof;
2981
+ const shouldStoreIp = proofConfig?.storeIp ?? true;
2982
+ const shouldStoreUserAgent = proofConfig?.storeUserAgent ?? true;
2983
+ const shouldStoreLanguage = proofConfig?.storeLanguage ?? false;
2984
+ const effectiveLanguage = (snapshotPayload?.language && hasValidSnapshot ? snapshotPayload.language : requestLanguage) ?? void 0;
2985
+ const metadataWithPolicy = {
2986
+ ...metadata ?? {},
2987
+ ...shouldStoreLanguage && effectiveLanguage ? {
2988
+ policyLanguage: effectiveLanguage
2989
+ } : {}
2990
+ };
2991
+ const effectiveJurisdiction = hasValidSnapshot && snapshotPayload ? snapshotPayload.jurisdiction : resolvedJurisdiction;
2992
+ const decisionPayload = buildDecisionPayload({
2993
+ tenantId: ctx.tenantId,
2994
+ snapshot: hasValidSnapshot && snapshotPayload ? {
2995
+ valid: true,
2996
+ payload: snapshotPayload
2997
+ } : null,
2998
+ decision: resolvedPolicyDecision,
2999
+ location: {
3000
+ countryCode: location.countryCode,
3001
+ regionCode: location.regionCode
3002
+ },
3003
+ jurisdiction: resolvedJurisdiction,
3004
+ language: effectiveLanguage,
3005
+ proofConfig
3006
+ });
2386
3007
  const existingConsent = await db.findFirst('consent', {
2387
3008
  where: (b)=>b.and(b('subjectId', '=', subject.id), b('domainId', '=', domainRecord.id), b('policyId', '=', policyId), b('givenAt', '=', givenAt))
2388
3009
  });
@@ -2397,6 +3018,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2397
3018
  domain: domainRecord.name,
2398
3019
  type,
2399
3020
  metadata,
3021
+ appliedPreferences,
2400
3022
  uiSource: input.uiSource,
2401
3023
  givenAt: existingConsent.givenAt
2402
3024
  });
@@ -2408,6 +3030,42 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2408
3030
  policyId,
2409
3031
  purposeIds
2410
3032
  });
3033
+ const runtimePolicyDecision = decisionPayload ? await tx.findFirst('runtimePolicyDecision', {
3034
+ where: (b)=>b('dedupeKey', '=', decisionPayload.dedupeKey)
3035
+ }) ?? await tx.create('runtimePolicyDecision', {
3036
+ id: `rpd_${crypto.randomUUID().replaceAll('-', '')}`,
3037
+ tenantId: decisionPayload.tenantId,
3038
+ policyId: decisionPayload.policyId,
3039
+ fingerprint: decisionPayload.fingerprint,
3040
+ matchedBy: decisionPayload.matchedBy,
3041
+ countryCode: decisionPayload.countryCode,
3042
+ regionCode: decisionPayload.regionCode,
3043
+ jurisdiction: decisionPayload.jurisdiction,
3044
+ language: decisionPayload.language,
3045
+ model: decisionPayload.model,
3046
+ policyI18n: decisionPayload.policyI18n ? {
3047
+ json: decisionPayload.policyI18n
3048
+ } : void 0,
3049
+ uiMode: decisionPayload.uiMode,
3050
+ bannerUi: decisionPayload.bannerUi ? {
3051
+ json: decisionPayload.bannerUi
3052
+ } : void 0,
3053
+ dialogUi: decisionPayload.dialogUi ? {
3054
+ json: decisionPayload.dialogUi
3055
+ } : void 0,
3056
+ categories: decisionPayload.categories ? {
3057
+ json: decisionPayload.categories
3058
+ } : void 0,
3059
+ preselectedCategories: decisionPayload.preselectedCategories ? {
3060
+ json: decisionPayload.preselectedCategories
3061
+ } : void 0,
3062
+ proofConfig: decisionPayload.proofConfig ? {
3063
+ json: decisionPayload.proofConfig
3064
+ } : void 0,
3065
+ dedupeKey: decisionPayload.dedupeKey
3066
+ }).catch(async ()=>tx.findFirst('runtimePolicyDecision', {
3067
+ where: (b)=>b('dedupeKey', '=', decisionPayload.dedupeKey)
3068
+ })) : void 0;
2411
3069
  const consentRecord = await tx.create('consent', {
2412
3070
  id: await utils_generateUniqueId(tx, 'consent', ctx),
2413
3071
  subjectId: subject.id,
@@ -2416,17 +3074,20 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2416
3074
  purposeIds: {
2417
3075
  json: purposeIds
2418
3076
  },
2419
- metadata: metadata ? {
2420
- json: metadata
3077
+ metadata: Object.keys(metadataWithPolicy).length > 0 ? {
3078
+ json: metadataWithPolicy
2421
3079
  } : void 0,
2422
- ipAddress: ctx.ipAddress,
2423
- userAgent: ctx.userAgent,
2424
- jurisdiction: input.jurisdiction,
2425
- jurisdictionModel: input.jurisdictionModel,
3080
+ ipAddress: shouldStoreIp ? ctx.ipAddress : null,
3081
+ userAgent: shouldStoreUserAgent ? ctx.userAgent : null,
3082
+ jurisdiction: effectiveJurisdiction,
3083
+ jurisdictionModel: effectiveModel,
2426
3084
  tcString: input.tcString,
2427
3085
  uiSource: input.uiSource,
2428
3086
  consentAction: derivedConsentAction,
2429
- givenAt
3087
+ givenAt,
3088
+ validUntil,
3089
+ runtimePolicyDecisionId: runtimePolicyDecision?.id,
3090
+ runtimePolicySource: decisionPayload?.source
2430
3091
  });
2431
3092
  logger.debug('Created consent', {
2432
3093
  consentRecord: consentRecord.id
@@ -2445,7 +3106,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2445
3106
  });
2446
3107
  const metrics = getMetrics();
2447
3108
  if (metrics) {
2448
- const jurisdiction = input.jurisdiction;
3109
+ const jurisdiction = effectiveJurisdiction;
2449
3110
  metrics.recordConsentCreated({
2450
3111
  type,
2451
3112
  jurisdiction
@@ -2467,6 +3128,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2467
3128
  domain: domainRecord.name,
2468
3129
  type,
2469
3130
  metadata,
3131
+ appliedPreferences,
2470
3132
  uiSource: input.uiSource,
2471
3133
  givenAt: result.consent.givenAt
2472
3134
  });
@@ -2590,6 +3252,86 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2590
3252
  return app;
2591
3253
  };
2592
3254
  var define_config = __webpack_require__("./src/define-config.ts");
3255
+ const DEFAULT_FALLBACK_POLICY_INPUT = {
3256
+ id: 'world_no_banner',
3257
+ isDefault: true,
3258
+ model: 'none',
3259
+ uiMode: 'none'
3260
+ };
3261
+ function mergeMatch(input) {
3262
+ 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"]() : {});
3263
+ }
3264
+ function compactUiSurface(value) {
3265
+ if (!value) return;
3266
+ return (0, schema_.compactDefined)({
3267
+ allowedActions: (0, schema_.dedupeTrimmedStrings)(value.allowedActions),
3268
+ primaryAction: value.primaryAction,
3269
+ layout: value.layout,
3270
+ direction: value.direction,
3271
+ uiProfile: value.uiProfile,
3272
+ scrollLock: value.scrollLock
3273
+ });
3274
+ }
3275
+ function buildPolicyConfig(input) {
3276
+ const categories = (0, schema_.dedupeTrimmedStrings)(input.categories);
3277
+ const preselectedCategories = (0, schema_.dedupeTrimmedStrings)(input.preselectedCategories);
3278
+ return {
3279
+ id: input.id,
3280
+ match: mergeMatch(input),
3281
+ i18n: input.i18n,
3282
+ consent: (0, schema_.compactDefined)({
3283
+ model: input.model,
3284
+ expiryDays: input.expiryDays,
3285
+ scopeMode: input.scopeMode,
3286
+ categories,
3287
+ preselectedCategories,
3288
+ gpc: input.gpc
3289
+ }),
3290
+ ui: (0, schema_.compactDefined)({
3291
+ mode: input.uiMode,
3292
+ banner: compactUiSurface(input.banner),
3293
+ dialog: compactUiSurface(input.dialog)
3294
+ }),
3295
+ proof: (0, schema_.compactDefined)({
3296
+ storeIp: input.proof?.storeIp,
3297
+ storeUserAgent: input.proof?.storeUserAgent,
3298
+ storeLanguage: input.proof?.storeLanguage
3299
+ })
3300
+ };
3301
+ }
3302
+ function buildPolicyPack(inputs) {
3303
+ return inputs.map((input)=>buildPolicyConfig(input));
3304
+ }
3305
+ function buildPolicyPackWithDefault(inputs, defaultPolicy) {
3306
+ const pack = buildPolicyPack(inputs);
3307
+ const hasDefault = pack.some((policy)=>policy.match.isDefault);
3308
+ if (hasDefault) return pack;
3309
+ const fallbackInput = defaultPolicy ? {
3310
+ ...defaultPolicy,
3311
+ isDefault: true,
3312
+ countries: void 0,
3313
+ regions: void 0
3314
+ } : DEFAULT_FALLBACK_POLICY_INPUT;
3315
+ return [
3316
+ ...pack,
3317
+ buildPolicyConfig(fallbackInput)
3318
+ ];
3319
+ }
3320
+ function composePacks(...packs) {
3321
+ const seen = new Set();
3322
+ const result = [];
3323
+ for (const pack of packs)for (const policy of pack)if (!seen.has(policy.id)) {
3324
+ seen.add(policy.id);
3325
+ result.push(policy);
3326
+ }
3327
+ return result;
3328
+ }
3329
+ const policyBuilder = {
3330
+ create: buildPolicyConfig,
3331
+ createPack: buildPolicyPack,
3332
+ createPackWithDefault: buildPolicyPackWithDefault,
3333
+ composePacks
3334
+ };
2593
3335
  const c15tInstance = (options)=>{
2594
3336
  const context = init(options);
2595
3337
  const logger = (0, logger_namespaceObject.createLogger)(options.logger);
@@ -2602,7 +3344,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2602
3344
  app.use('*', async (c, next)=>{
2603
3345
  const request = c.req.raw;
2604
3346
  const startTime = Date.now();
2605
- const apiKeyAuthenticated = validateRequestAuth(request.headers, options.advanced?.apiKeys);
3347
+ const apiKeyAuthenticated = validateRequestAuth(request.headers, options.apiKeys);
2606
3348
  const enrichedContext = {
2607
3349
  ...context,
2608
3350
  ipAddress: getIpAddress(request, options),
@@ -2767,12 +3509,28 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2767
3509
  };
2768
3510
  };
2769
3511
  })();
3512
+ exports.EEA_COUNTRY_CODES = __webpack_exports__.EEA_COUNTRY_CODES;
3513
+ exports.EU_COUNTRY_CODES = __webpack_exports__.EU_COUNTRY_CODES;
3514
+ exports.POLICY_MATCH_DATASET_VERSION = __webpack_exports__.POLICY_MATCH_DATASET_VERSION;
3515
+ exports.UK_COUNTRY_CODES = __webpack_exports__.UK_COUNTRY_CODES;
2770
3516
  exports.c15tInstance = __webpack_exports__.c15tInstance;
2771
3517
  exports.defineConfig = __webpack_exports__.defineConfig;
3518
+ exports.inspectPolicies = __webpack_exports__.inspectPolicies;
3519
+ exports.policyBuilder = __webpack_exports__.policyBuilder;
3520
+ exports.policyMatchers = __webpack_exports__.policyMatchers;
3521
+ exports.policyPackPresets = __webpack_exports__.policyPackPresets;
2772
3522
  exports.version = __webpack_exports__.version;
2773
3523
  for(var __rspack_i in __webpack_exports__)if (-1 === [
3524
+ "EEA_COUNTRY_CODES",
3525
+ "EU_COUNTRY_CODES",
3526
+ "POLICY_MATCH_DATASET_VERSION",
3527
+ "UK_COUNTRY_CODES",
2774
3528
  "c15tInstance",
2775
3529
  "defineConfig",
3530
+ "inspectPolicies",
3531
+ "policyBuilder",
3532
+ "policyMatchers",
3533
+ "policyPackPresets",
2776
3534
  "version"
2777
3535
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
2778
3536
  Object.defineProperty(exports, '__esModule', {