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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/dist/cache.cjs +4 -4
  2. package/dist/cache.js +4 -4
  3. package/dist/core.cjs +845 -87
  4. package/dist/core.js +821 -87
  5. package/dist/db/schema.cjs +37 -0
  6. package/dist/db/schema.js +33 -2
  7. package/dist/edge.cjs +1106 -0
  8. package/dist/edge.js +1069 -0
  9. package/dist/router.cjs +621 -71
  10. package/dist/router.js +621 -71
  11. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  12. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  13. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  14. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  15. package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
  16. package/{dist → dist-types}/cache/index.d.ts +0 -1
  17. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  18. package/{dist → dist-types}/cache/types.d.ts +0 -1
  19. package/{dist → dist-types}/core.d.ts +8 -1
  20. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  21. package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
  22. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  23. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  24. package/{dist → dist-types}/db/registry/index.d.ts +22 -2
  25. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  26. package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
  27. package/{dist → dist-types}/db/registry/types.d.ts +1 -2
  28. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  29. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  30. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  31. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  32. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  33. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  34. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  35. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  36. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
  37. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
  38. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  39. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +1 -2
  40. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  41. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +5 -2
  42. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  43. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
  44. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  45. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -2
  46. package/{dist → dist-types}/db/schema/index.d.ts +862 -33
  47. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  48. package/dist-types/define-config.d.ts +17 -0
  49. package/dist-types/edge/index.d.ts +5 -0
  50. package/dist-types/edge/init-handler.d.ts +38 -0
  51. package/dist-types/edge/resolve-consent.d.ts +80 -0
  52. package/dist-types/edge/types.d.ts +13 -0
  53. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  54. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  55. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  56. package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
  57. package/dist-types/handlers/init/policy.d.ts +26 -0
  58. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  59. package/dist-types/handlers/init/translations.d.ts +48 -0
  60. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  61. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  62. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  63. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
  64. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  65. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
  66. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
  67. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  68. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
  69. package/{dist → dist-types}/init.d.ts +4 -7
  70. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  71. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  72. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  73. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  74. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
  75. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  76. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  77. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  78. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  79. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  80. package/dist-types/policies/builder.d.ts +127 -0
  81. package/dist-types/policies/defaults.d.ts +2 -0
  82. package/dist-types/policies/matchers.d.ts +3 -0
  83. package/{dist → dist-types}/router.d.ts +0 -1
  84. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  85. package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
  86. package/{dist → dist-types}/routes/init.d.ts +0 -1
  87. package/{dist → dist-types}/routes/status.d.ts +0 -1
  88. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  89. package/{dist → dist-types}/types/api.d.ts +0 -1
  90. package/dist-types/types/index.d.ts +443 -0
  91. package/dist-types/utils/background.d.ts +6 -0
  92. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
  93. package/{dist → dist-types}/utils/env.d.ts +0 -1
  94. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  95. package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
  96. package/{dist → dist-types}/utils/logger.d.ts +1 -2
  97. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  98. package/dist-types/version.d.ts +1 -0
  99. package/docs/README.md +49 -0
  100. package/docs/api/configuration.md +197 -0
  101. package/docs/api/endpoints.md +211 -0
  102. package/docs/guides/caching.md +85 -0
  103. package/docs/guides/database-setup.md +128 -0
  104. package/docs/guides/edge-deployment.md +248 -0
  105. package/docs/guides/framework-integration.md +142 -0
  106. package/docs/guides/iab-tcf.md +89 -0
  107. package/docs/guides/observability.md +96 -0
  108. package/docs/guides/policy-packs.md +396 -0
  109. package/docs/quickstart.md +129 -0
  110. package/package.json +37 -23
  111. package/.turbo/turbo-build.log +0 -49
  112. package/CHANGELOG.md +0 -115
  113. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  114. package/dist/cache/adapters/index.d.ts.map +0 -1
  115. package/dist/cache/adapters/memory.d.ts.map +0 -1
  116. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  117. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  118. package/dist/cache/index.d.ts.map +0 -1
  119. package/dist/cache/keys.d.ts.map +0 -1
  120. package/dist/cache/types.d.ts.map +0 -1
  121. package/dist/core.d.ts.map +0 -1
  122. package/dist/db/adapters/drizzle.d.ts +0 -2
  123. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  124. package/dist/db/adapters/index.d.ts +0 -2
  125. package/dist/db/adapters/index.d.ts.map +0 -1
  126. package/dist/db/adapters/kysely.d.ts +0 -2
  127. package/dist/db/adapters/kysely.d.ts.map +0 -1
  128. package/dist/db/adapters/mongo.d.ts +0 -2
  129. package/dist/db/adapters/mongo.d.ts.map +0 -1
  130. package/dist/db/adapters/prisma.d.ts +0 -2
  131. package/dist/db/adapters/prisma.d.ts.map +0 -1
  132. package/dist/db/adapters/typeorm.d.ts +0 -2
  133. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  134. package/dist/db/migrator/index.d.ts.map +0 -1
  135. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  136. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  137. package/dist/db/registry/domain.d.ts.map +0 -1
  138. package/dist/db/registry/index.d.ts.map +0 -1
  139. package/dist/db/registry/subject.d.ts.map +0 -1
  140. package/dist/db/registry/types.d.ts.map +0 -1
  141. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  142. package/dist/db/registry/utils.d.ts.map +0 -1
  143. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  144. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  145. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  146. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  147. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  148. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  149. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  150. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  151. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  152. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  153. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  154. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  155. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  156. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  157. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  158. package/dist/db/schema/index.d.ts.map +0 -1
  159. package/dist/db/tenant-scope.d.ts.map +0 -1
  160. package/dist/define-config.d.ts +0 -5
  161. package/dist/define-config.d.ts.map +0 -1
  162. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  163. package/dist/handlers/consent/index.d.ts +0 -12
  164. package/dist/handlers/consent/index.d.ts.map +0 -1
  165. package/dist/handlers/init/geo.d.ts.map +0 -1
  166. package/dist/handlers/init/index.d.ts.map +0 -1
  167. package/dist/handlers/init/translations.d.ts +0 -28
  168. package/dist/handlers/init/translations.d.ts.map +0 -1
  169. package/dist/handlers/status/index.d.ts +0 -7
  170. package/dist/handlers/status/index.d.ts.map +0 -1
  171. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  172. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  173. package/dist/handlers/subject/index.d.ts +0 -10
  174. package/dist/handlers/subject/index.d.ts.map +0 -1
  175. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  176. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  177. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  178. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  179. package/dist/init.d.ts.map +0 -1
  180. package/dist/middleware/auth/index.d.ts.map +0 -1
  181. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  182. package/dist/middleware/cors/cors.d.ts.map +0 -1
  183. package/dist/middleware/cors/index.d.ts +0 -30
  184. package/dist/middleware/cors/index.d.ts.map +0 -1
  185. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  186. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  187. package/dist/middleware/openapi/config.d.ts.map +0 -1
  188. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  189. package/dist/middleware/openapi/index.d.ts +0 -12
  190. package/dist/middleware/openapi/index.d.ts.map +0 -1
  191. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  192. package/dist/router.d.ts.map +0 -1
  193. package/dist/routes/consent.d.ts.map +0 -1
  194. package/dist/routes/index.d.ts +0 -10
  195. package/dist/routes/index.d.ts.map +0 -1
  196. package/dist/routes/init.d.ts.map +0 -1
  197. package/dist/routes/status.d.ts.map +0 -1
  198. package/dist/routes/subject.d.ts.map +0 -1
  199. package/dist/types/api.d.ts.map +0 -1
  200. package/dist/types/index.d.ts +0 -263
  201. package/dist/types/index.d.ts.map +0 -1
  202. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  203. package/dist/utils/env.d.ts.map +0 -1
  204. package/dist/utils/extract-error-message.d.ts.map +0 -1
  205. package/dist/utils/index.d.ts +0 -4
  206. package/dist/utils/index.d.ts.map +0 -1
  207. package/dist/utils/instrumentation.d.ts.map +0 -1
  208. package/dist/utils/logger.d.ts.map +0 -1
  209. package/dist/utils/metrics.d.ts.map +0 -1
  210. package/dist/version.d.ts +0 -2
  211. package/dist/version.d.ts.map +0 -1
  212. package/knip.json +0 -31
  213. package/rslib.config.ts +0 -93
  214. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  215. package/src/cache/adapters/index.ts +0 -22
  216. package/src/cache/adapters/memory.ts +0 -111
  217. package/src/cache/adapters/upstash-redis.ts +0 -113
  218. package/src/cache/gvl-resolver.ts +0 -289
  219. package/src/cache/index.ts +0 -34
  220. package/src/cache/keys.ts +0 -68
  221. package/src/cache/types.ts +0 -66
  222. package/src/core.ts +0 -369
  223. package/src/db/migrator/index.ts +0 -80
  224. package/src/db/registry/consent-policy.test.ts +0 -451
  225. package/src/db/registry/consent-policy.ts +0 -82
  226. package/src/db/registry/consent-purpose.test.ts +0 -428
  227. package/src/db/registry/consent-purpose.ts +0 -61
  228. package/src/db/registry/domain.test.ts +0 -445
  229. package/src/db/registry/domain.ts +0 -91
  230. package/src/db/registry/index.ts +0 -14
  231. package/src/db/registry/subject.test.ts +0 -371
  232. package/src/db/registry/subject.ts +0 -126
  233. package/src/db/registry/types.ts +0 -10
  234. package/src/db/registry/utils/generate-id.test.ts +0 -216
  235. package/src/db/registry/utils/generate-id.ts +0 -133
  236. package/src/db/registry/utils.ts +0 -133
  237. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  238. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  239. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  240. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  241. package/src/db/schema/1.0.0/consent.ts +0 -20
  242. package/src/db/schema/1.0.0/domain.ts +0 -12
  243. package/src/db/schema/1.0.0/index.ts +0 -48
  244. package/src/db/schema/1.0.0/subject.ts +0 -11
  245. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  246. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  247. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  248. package/src/db/schema/2.0.0/consent.ts +0 -28
  249. package/src/db/schema/2.0.0/domain.ts +0 -12
  250. package/src/db/schema/2.0.0/index.ts +0 -47
  251. package/src/db/schema/2.0.0/subject.ts +0 -13
  252. package/src/db/schema/index.ts +0 -15
  253. package/src/db/tenant-scope.test.ts +0 -747
  254. package/src/db/tenant-scope.ts +0 -103
  255. package/src/define-config.ts +0 -5
  256. package/src/handlers/consent/check.handler.ts +0 -126
  257. package/src/handlers/init/geo.test.ts +0 -317
  258. package/src/handlers/init/geo.ts +0 -195
  259. package/src/handlers/init/index.test.ts +0 -205
  260. package/src/handlers/init/index.ts +0 -114
  261. package/src/handlers/init/translations.test.ts +0 -121
  262. package/src/handlers/init/translations.ts +0 -72
  263. package/src/handlers/status/status.handler.test.ts +0 -155
  264. package/src/handlers/status/status.handler.ts +0 -51
  265. package/src/handlers/subject/get.handler.ts +0 -92
  266. package/src/handlers/subject/list.handler.ts +0 -92
  267. package/src/handlers/subject/patch.handler.ts +0 -119
  268. package/src/handlers/subject/post.handler.test.ts +0 -294
  269. package/src/handlers/subject/post.handler.ts +0 -268
  270. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  271. package/src/handlers/utils/consent-enrichment.ts +0 -218
  272. package/src/init.test.ts +0 -126
  273. package/src/init.ts +0 -87
  274. package/src/middleware/auth/index.ts +0 -11
  275. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  276. package/src/middleware/auth/validate-api-key.ts +0 -107
  277. package/src/middleware/cors/cors.test.ts +0 -135
  278. package/src/middleware/cors/cors.ts +0 -186
  279. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  280. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  281. package/src/middleware/cors/process-cors.ts +0 -91
  282. package/src/middleware/openapi/config.ts +0 -29
  283. package/src/middleware/openapi/handlers.ts +0 -34
  284. package/src/middleware/process-ip/index.test.ts +0 -195
  285. package/src/middleware/process-ip/index.ts +0 -199
  286. package/src/router.ts +0 -15
  287. package/src/routes/consent.ts +0 -52
  288. package/src/routes/init.ts +0 -105
  289. package/src/routes/status.ts +0 -46
  290. package/src/routes/subject.ts +0 -152
  291. package/src/types/api.ts +0 -48
  292. package/src/types/index.ts +0 -297
  293. package/src/utils/create-telemetry-options.test.ts +0 -302
  294. package/src/utils/create-telemetry-options.ts +0 -229
  295. package/src/utils/env.ts +0 -84
  296. package/src/utils/extract-error-message.ts +0 -21
  297. package/src/utils/instrumentation.test.ts +0 -185
  298. package/src/utils/instrumentation.ts +0 -196
  299. package/src/utils/logger.ts +0 -41
  300. package/src/utils/metrics.test.ts +0 -323
  301. package/src/utils/metrics.ts +0 -402
  302. package/src/utils/telemetry-pii.test.ts +0 -325
  303. package/src/version.ts +0 -2
  304. package/tsconfig.json +0 -11
  305. package/vitest.config.ts +0 -28
  306. /package/dist/{types.cjs → types/index.cjs} +0 -0
  307. /package/dist/{types.js → types/index.js} +0 -0
  308. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  309. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  310. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  311. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  312. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  313. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  314. /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
@@ -1,111 +0,0 @@
1
- /**
2
- * In-Memory Cache Adapter
3
- *
4
- * A simple Map-based cache adapter with TTL support.
5
- * Used as the default first layer in the cache resolution chain.
6
- *
7
- * @packageDocumentation
8
- */
9
-
10
- import type { CacheAdapter } from '../types';
11
- import { MEMORY_TTL_MS } from '../types';
12
-
13
- interface CacheEntry<T = unknown> {
14
- value: T;
15
- expiresAt: number;
16
- }
17
-
18
- /**
19
- * Module-level cache shared across requests in the same worker/process.
20
- * This provides fast 0ms access for repeated requests.
21
- */
22
- const memoryCache = new Map<string, CacheEntry>();
23
-
24
- /**
25
- * Creates an in-memory cache adapter.
26
- *
27
- * Features:
28
- * - Uses a shared Map for fast access
29
- * - Supports TTL with lazy expiration
30
- * - Always used as the first cache layer by default
31
- *
32
- * @returns A CacheAdapter implementation backed by in-memory Map
33
- *
34
- * @example
35
- * ```typescript
36
- * const memoryAdapter = createMemoryCacheAdapter();
37
- *
38
- * await memoryAdapter.set('key', { data: 'value' }, 60000); // 1 minute TTL
39
- * const value = await memoryAdapter.get('key');
40
- * ```
41
- *
42
- * @public
43
- */
44
- export function createMemoryCacheAdapter(): CacheAdapter {
45
- return {
46
- async get<T>(key: string): Promise<T | null> {
47
- const entry = memoryCache.get(key);
48
-
49
- if (!entry) {
50
- return null;
51
- }
52
-
53
- // Check if entry has expired (lazy expiration)
54
- if (Date.now() > entry.expiresAt) {
55
- memoryCache.delete(key);
56
- return null;
57
- }
58
-
59
- return entry.value as T;
60
- },
61
-
62
- async set<T>(key: string, value: T, ttlMs = MEMORY_TTL_MS): Promise<void> {
63
- memoryCache.set(key, {
64
- value,
65
- expiresAt: Date.now() + ttlMs,
66
- });
67
- },
68
-
69
- async delete(key: string): Promise<void> {
70
- memoryCache.delete(key);
71
- },
72
-
73
- async has(key: string): Promise<boolean> {
74
- const entry = memoryCache.get(key);
75
-
76
- if (!entry) {
77
- return false;
78
- }
79
-
80
- // Check if entry has expired
81
- if (Date.now() > entry.expiresAt) {
82
- memoryCache.delete(key);
83
- return false;
84
- }
85
-
86
- return true;
87
- },
88
- };
89
- }
90
-
91
- /**
92
- * Clears the entire in-memory cache.
93
- * Primarily used for testing.
94
- *
95
- * @public
96
- */
97
- export function clearMemoryCache(): void {
98
- memoryCache.clear();
99
- }
100
-
101
- /**
102
- * Gets the current size of the in-memory cache.
103
- * Primarily used for debugging and monitoring.
104
- *
105
- * @returns The number of entries in the cache (may include expired entries)
106
- *
107
- * @public
108
- */
109
- export function getMemoryCacheSize(): number {
110
- return memoryCache.size;
111
- }
@@ -1,113 +0,0 @@
1
- /**
2
- * Upstash Redis Cache Adapter
3
- *
4
- * Cache adapter for Upstash Redis, suitable for serverless environments.
5
- *
6
- * Requires @upstash/redis to be installed as a peer dependency.
7
- *
8
- * @packageDocumentation
9
- */
10
-
11
- import { Redis } from '@upstash/redis';
12
- import type { CacheAdapter } from '../types';
13
- import { GVL_TTL_MS } from '../types';
14
-
15
- /**
16
- * Options for creating an Upstash Redis adapter.
17
- *
18
- * @public
19
- */
20
- export interface UpstashRedisAdapterOptions {
21
- /**
22
- * Upstash Redis REST URL.
23
- */
24
- url: string;
25
-
26
- /**
27
- * Upstash Redis REST token.
28
- */
29
- token: string;
30
- }
31
-
32
- /**
33
- * Creates an Upstash Redis cache adapter.
34
- *
35
- * **Note:** Requires `@upstash/redis` to be installed as a peer dependency.
36
- *
37
- * @param options - Upstash Redis connection options
38
- * @returns A CacheAdapter backed by Upstash Redis
39
- *
40
- * @example
41
- * ```typescript
42
- * import { createUpstashRedisAdapter } from '@c15t/backend/cache';
43
- *
44
- * const redisAdapter = createUpstashRedisAdapter({
45
- * url: process.env.UPSTASH_REDIS_REST_URL,
46
- * token: process.env.UPSTASH_REDIS_REST_TOKEN,
47
- * });
48
- *
49
- * await redisAdapter.set('key', { data: 'value' }, 3600000); // 1 hour TTL
50
- * const value = await redisAdapter.get('key');
51
- * ```
52
- *
53
- * @public
54
- */
55
- export function createUpstashRedisAdapter(
56
- options: UpstashRedisAdapterOptions
57
- ): CacheAdapter {
58
- const client = new Redis({
59
- url: options.url,
60
- token: options.token,
61
- });
62
-
63
- return createUpstashRedisAdapterFromClient(client);
64
- }
65
-
66
- /**
67
- * Creates an Upstash Redis cache adapter from an existing client.
68
- *
69
- * Use this if you already have an @upstash/redis client instance.
70
- *
71
- * @param client - An existing Upstash Redis client
72
- * @returns A CacheAdapter backed by the provided client
73
- *
74
- * @example
75
- * ```typescript
76
- * import { Redis } from '@upstash/redis';
77
- * import { createUpstashRedisAdapterFromClient } from '@c15t/backend/cache';
78
- *
79
- * const redis = new Redis({
80
- * url: process.env.UPSTASH_REDIS_REST_URL,
81
- * token: process.env.UPSTASH_REDIS_REST_TOKEN,
82
- * });
83
- *
84
- * const adapter = createUpstashRedisAdapterFromClient(redis);
85
- * ```
86
- *
87
- * @public
88
- */
89
- export function createUpstashRedisAdapterFromClient(
90
- client: Redis
91
- ): CacheAdapter {
92
- return {
93
- async get<T>(key: string): Promise<T | null> {
94
- const result = await client.get<T>(key);
95
- return result ?? null;
96
- },
97
-
98
- async set<T>(key: string, value: T, ttlMs = GVL_TTL_MS): Promise<void> {
99
- // Convert milliseconds to seconds for Redis EX
100
- const ttlSeconds = Math.ceil(ttlMs / 1000);
101
- await client.set(key, value, { ex: ttlSeconds });
102
- },
103
-
104
- async delete(key: string): Promise<void> {
105
- await client.del(key);
106
- },
107
-
108
- async has(key: string): Promise<boolean> {
109
- const exists = await client.exists(key);
110
- return exists > 0;
111
- },
112
- };
113
- }
@@ -1,289 +0,0 @@
1
- /**
2
- * GVL Resolution Service
3
- *
4
- * Resolves Global Vendor List with multi-layer caching:
5
- * 1. Bundled translations (checked first)
6
- * 2. In-memory cache
7
- * 3. External cache (Redis/KV)
8
- * 4. Fetch from gvl.consent.io
9
- *
10
- * @packageDocumentation
11
- */
12
-
13
- import type { GlobalVendorList } from '@c15t/schema/types';
14
- import { withCacheSpan, withExternalSpan } from '~/utils/instrumentation';
15
- import { getMetrics } from '~/utils/metrics';
16
- import { createMemoryCacheAdapter } from './adapters/memory';
17
- import { createGVLCacheKey } from './keys';
18
- import type { CacheAdapter } from './types';
19
- import { GVL_TTL_MS, MEMORY_TTL_MS } from './types';
20
-
21
- /**
22
- * Default GVL endpoint.
23
- */
24
- const GVL_ENDPOINT = 'https://gvl.consent.io';
25
-
26
- /**
27
- * Options for creating a GVL resolver.
28
- *
29
- * @public
30
- */
31
- export interface GVLResolverOptions {
32
- /**
33
- * The application name for cache key prefixing.
34
- */
35
- appName: string;
36
-
37
- /**
38
- * Bundled GVL translations by language code.
39
- * These are checked first before any cache.
40
- */
41
- bundled?: Record<string, GlobalVendorList>;
42
-
43
- /**
44
- * External cache adapter (Redis, KV, etc.).
45
- * If not provided, only in-memory cache is used.
46
- */
47
- cacheAdapter?: CacheAdapter;
48
-
49
- /**
50
- * Vendor IDs to filter when fetching from the GVL endpoint.
51
- * Reduces payload size.
52
- */
53
- vendorIds?: number[];
54
-
55
- /**
56
- * Override the default GVL endpoint.
57
- * @default 'https://gvl.consent.io'
58
- */
59
- endpoint?: string;
60
- }
61
-
62
- /**
63
- * GVL resolver interface.
64
- *
65
- * @public
66
- */
67
- export interface GVLResolver {
68
- /**
69
- * Get a localized GVL for the specified language.
70
- *
71
- * @param language - Language code (e.g., "en", "de")
72
- * @returns The GVL for the language, or null if unavailable
73
- */
74
- get(language: string): Promise<GlobalVendorList | null>;
75
- }
76
-
77
- /**
78
- * In-flight request promises for deduplication.
79
- */
80
- const inflightRequests = new Map<string, Promise<GlobalVendorList | null>>();
81
-
82
- /**
83
- * Fetches GVL from the endpoint with the specified language.
84
- *
85
- * @param language - Language code for Accept-Language header
86
- * @param vendorIds - Optional vendor IDs to filter
87
- * @param endpoint - GVL endpoint URL
88
- * @returns The GVL or null if 204 (non-IAB region)
89
- */
90
- async function fetchGVLWithLanguage(
91
- language: string,
92
- vendorIds?: number[],
93
- endpoint: string = GVL_ENDPOINT
94
- ): Promise<GlobalVendorList | null> {
95
- // Create a stable key for deduplication
96
- const sortedVendorIds = vendorIds ? [...vendorIds].sort((a, b) => a - b) : [];
97
- const dedupeKey = `${endpoint}|${language}|${sortedVendorIds.join(',')}`;
98
-
99
- // Return in-flight request if one exists
100
- const existingRequest = inflightRequests.get(dedupeKey);
101
- if (existingRequest) {
102
- return existingRequest;
103
- }
104
-
105
- // Build URL with vendor IDs filter
106
- const url = new URL(endpoint);
107
- if (sortedVendorIds.length > 0) {
108
- url.searchParams.set('vendorIds', sortedVendorIds.join(','));
109
- }
110
-
111
- // Create and store the in-flight promise
112
- const promise = (async () => {
113
- const fetchStart = Date.now();
114
- try {
115
- const gvl = await withExternalSpan(
116
- { url: url.toString(), method: 'GET' },
117
- async () => {
118
- const response = await fetch(url.toString(), {
119
- headers: {
120
- 'Accept-Language': language,
121
- },
122
- });
123
-
124
- // 204 means non-IAB region - no GVL needed
125
- if (response.status === 204) {
126
- return null;
127
- }
128
-
129
- if (!response.ok) {
130
- throw new Error(
131
- `Failed to fetch GVL: ${response.status} ${response.statusText}`
132
- );
133
- }
134
-
135
- // Use text() then JSON.parse to handle malformed responses (e.g. trailing
136
- // content or BOM) that would break response.json()
137
- const text = await response.text();
138
- const trimmed = text.trim().replace(/^\uFEFF/, ''); // Strip BOM
139
- let parsed: GlobalVendorList;
140
- try {
141
- parsed = JSON.parse(trimmed) as GlobalVendorList;
142
- } catch {
143
- // If response has valid JSON followed by extra content, try parsing
144
- // only the first complete JSON value (find matching braces)
145
- let depth = 0;
146
- let end = -1;
147
- const start = trimmed.indexOf('{');
148
- if (start >= 0) {
149
- for (let i = start; i < trimmed.length; i++) {
150
- const c = trimmed[i];
151
- if (c === '{') depth++;
152
- else if (c === '}') {
153
- depth--;
154
- if (depth === 0) {
155
- end = i + 1;
156
- break;
157
- }
158
- }
159
- }
160
- }
161
- if (end > 0) {
162
- parsed = JSON.parse(trimmed.slice(0, end)) as GlobalVendorList;
163
- } else {
164
- throw new SyntaxError('Invalid GVL response: not valid JSON');
165
- }
166
- }
167
-
168
- // Validate the response has required fields
169
- if (
170
- !parsed.vendorListVersion ||
171
- !parsed.purposes ||
172
- !parsed.vendors
173
- ) {
174
- throw new Error('Invalid GVL response: missing required fields');
175
- }
176
-
177
- return parsed;
178
- }
179
- );
180
-
181
- getMetrics()?.recordGvlFetch(
182
- { language, source: 'fetch', status: 200 },
183
- Date.now() - fetchStart
184
- );
185
-
186
- return gvl;
187
- } catch (error) {
188
- getMetrics()?.recordGvlError({
189
- language,
190
- errorType: error instanceof Error ? error.name : 'UnknownError',
191
- });
192
- throw error;
193
- } finally {
194
- // Clear in-flight request when done
195
- inflightRequests.delete(dedupeKey);
196
- }
197
- })();
198
-
199
- inflightRequests.set(dedupeKey, promise);
200
-
201
- return promise;
202
- }
203
-
204
- /**
205
- * Creates a GVL resolver with multi-layer caching.
206
- *
207
- * Resolution order:
208
- * 1. **Bundled** - Check bundled translations (0ms)
209
- * 2. **In-Memory** - Check worker/process memory cache (0ms)
210
- * 3. **External Cache** - Check Redis/KV if configured (20-40ms)
211
- * 4. **Fetch** - Fetch from gvl.consent.io with Accept-Language (100-300ms)
212
- *
213
- * @param options - Resolver configuration
214
- * @returns A GVL resolver instance
215
- *
216
- * @example
217
- * ```typescript
218
- * const resolver = createGVLResolver({
219
- * appName: 'my-app',
220
- * bundled: { en: enGVL },
221
- * cacheAdapter: redisAdapter,
222
- * vendorIds: [1, 2, 10],
223
- * });
224
- *
225
- * const gvl = await resolver.get('de');
226
- * ```
227
- *
228
- * @public
229
- */
230
- export function createGVLResolver(options: GVLResolverOptions): GVLResolver {
231
- const { appName, bundled, cacheAdapter, vendorIds, endpoint } = options;
232
-
233
- // Create the in-memory cache adapter (always used as first layer)
234
- const memoryCache = createMemoryCacheAdapter();
235
-
236
- return {
237
- async get(language: string): Promise<GlobalVendorList | null> {
238
- const cacheKey = createGVLCacheKey(appName, language, vendorIds);
239
-
240
- // 1. Check bundled languages first (0ms)
241
- if (bundled?.[language]) {
242
- return bundled[language];
243
- }
244
-
245
- // 2. Check in-memory cache (0ms)
246
- const memoryHit = await withCacheSpan('get', 'memory', () =>
247
- memoryCache.get<GlobalVendorList>(cacheKey)
248
- );
249
- if (memoryHit) {
250
- getMetrics()?.recordCacheHit('memory');
251
- return memoryHit;
252
- }
253
- getMetrics()?.recordCacheMiss('memory');
254
-
255
- // 3. Check external cache if configured (20-40ms)
256
- if (cacheAdapter) {
257
- const externalHit = await withCacheSpan('get', 'external', () =>
258
- cacheAdapter.get<GlobalVendorList>(cacheKey)
259
- );
260
- if (externalHit) {
261
- getMetrics()?.recordCacheHit('external');
262
- // Populate memory cache for next request
263
- await withCacheSpan('set', 'memory', () =>
264
- memoryCache.set(cacheKey, externalHit, MEMORY_TTL_MS)
265
- );
266
- return externalHit;
267
- }
268
- getMetrics()?.recordCacheMiss('external');
269
- }
270
-
271
- // 4. Fetch from gvl.consent.io with Accept-Language header (100-300ms)
272
- const gvl = await fetchGVLWithLanguage(language, vendorIds, endpoint);
273
-
274
- if (gvl) {
275
- // Populate both caches
276
- await withCacheSpan('set', 'memory', () =>
277
- memoryCache.set(cacheKey, gvl, MEMORY_TTL_MS)
278
- );
279
- if (cacheAdapter) {
280
- await withCacheSpan('set', 'external', () =>
281
- cacheAdapter.set(cacheKey, gvl, GVL_TTL_MS)
282
- );
283
- }
284
- }
285
-
286
- return gvl;
287
- },
288
- };
289
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * Cache Module
3
- *
4
- * Multi-layer caching system with pluggable adapters for GVL and other data.
5
- *
6
- * @packageDocumentation
7
- */
8
-
9
- // Adapters
10
- export {
11
- clearMemoryCache,
12
- // Cloudflare KV
13
- createCloudflareKVAdapter,
14
- // Memory
15
- createMemoryCacheAdapter,
16
- // Upstash Redis
17
- createUpstashRedisAdapter,
18
- createUpstashRedisAdapterFromClient,
19
- getMemoryCacheSize,
20
- type KVNamespace,
21
- type UpstashRedisAdapterOptions,
22
- } from './adapters';
23
- // GVL Resolver
24
- export {
25
- createGVLResolver,
26
- type GVLResolver,
27
- type GVLResolverOptions,
28
- } from './gvl-resolver';
29
-
30
- // Cache Key Utilities
31
- export { createCacheKey, createGVLCacheKey } from './keys';
32
- // Types
33
- export type { CacheAdapter } from './types';
34
- export { GVL_TTL_MS, MEMORY_TTL_MS } from './types';
package/src/cache/keys.ts DELETED
@@ -1,68 +0,0 @@
1
- /**
2
- * Cache Key Utilities
3
- *
4
- * Functions for generating consistent cache keys with app name prefixing.
5
- *
6
- * @packageDocumentation
7
- */
8
-
9
- /**
10
- * Create a GVL cache key.
11
- *
12
- * Format: `{appName}:gvl:{language}:{sortedVendorIds}`
13
- *
14
- * @param appName - The application name for key prefixing
15
- * @param language - The language code (e.g., "en", "de")
16
- * @param vendorIds - Optional array of vendor IDs to include in the key
17
- * @returns A unique cache key for the GVL configuration
18
- *
19
- * @example
20
- * ```typescript
21
- * // All vendors
22
- * createGVLCacheKey('my-app', 'en');
23
- * // => 'my-app:gvl:en:all'
24
- *
25
- * // Specific vendors
26
- * createGVLCacheKey('my-app', 'de', [1, 10, 2]);
27
- * // => 'my-app:gvl:de:1,2,10'
28
- * ```
29
- *
30
- * @public
31
- */
32
- export function createGVLCacheKey(
33
- appName: string,
34
- language: string,
35
- vendorIds?: number[]
36
- ): string {
37
- const sortedIds = vendorIds
38
- ? [...vendorIds].sort((a, b) => a - b).join(',')
39
- : 'all';
40
- return `${appName}:gvl:${language}:${sortedIds}`;
41
- }
42
-
43
- /**
44
- * Create a generic cache key with namespace and parts.
45
- *
46
- * Format: `{appName}:{namespace}:{part1}:{part2}:...`
47
- *
48
- * @param appName - The application name for key prefixing
49
- * @param namespace - The cache namespace (e.g., "gvl", "translations")
50
- * @param parts - Additional key parts
51
- * @returns A namespaced cache key
52
- *
53
- * @example
54
- * ```typescript
55
- * createCacheKey('my-app', 'translations', 'en', 'banner');
56
- * // => 'my-app:translations:en:banner'
57
- * ```
58
- *
59
- * @public
60
- */
61
- export function createCacheKey(
62
- appName: string,
63
- namespace: string,
64
- ...parts: (string | number)[]
65
- ): string {
66
- const allParts = [appName, namespace, ...parts];
67
- return allParts.join(':');
68
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Cache Adapter Types
3
- *
4
- * Generic cache adapter interface for pluggable caching implementations.
5
- * Supports in-memory, Redis, Cloudflare KV, and custom adapters.
6
- *
7
- * @packageDocumentation
8
- */
9
-
10
- /**
11
- * Generic cache adapter interface.
12
- *
13
- * Implementations should handle serialization/deserialization internally.
14
- * All methods are async to support both sync (memory) and async (Redis/KV) backends.
15
- *
16
- * @public
17
- */
18
- export interface CacheAdapter {
19
- /**
20
- * Get a value from the cache.
21
- *
22
- * @param key - Cache key
23
- * @returns The cached value, or null if not found or expired
24
- */
25
- get<T>(key: string): Promise<T | null>;
26
-
27
- /**
28
- * Set a value in the cache.
29
- *
30
- * @param key - Cache key
31
- * @param value - Value to cache
32
- * @param ttlMs - Time to live in milliseconds (optional)
33
- */
34
- set<T>(key: string, value: T, ttlMs?: number): Promise<void>;
35
-
36
- /**
37
- * Delete a value from the cache.
38
- *
39
- * @param key - Cache key
40
- */
41
- delete(key: string): Promise<void>;
42
-
43
- /**
44
- * Check if a key exists in the cache.
45
- *
46
- * @param key - Cache key
47
- * @returns True if the key exists and is not expired
48
- */
49
- has(key: string): Promise<boolean>;
50
- }
51
-
52
- /**
53
- * Default TTL for GVL cache entries (3 days).
54
- * Matches the typical GVL update frequency.
55
- *
56
- * @public
57
- */
58
- export const GVL_TTL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
59
-
60
- /**
61
- * Default TTL for in-memory cache entries (5 minutes).
62
- * Shorter TTL to handle worker restarts and keep memory usage low.
63
- *
64
- * @public
65
- */
66
- export const MEMORY_TTL_MS = 5 * 60 * 1000; // 5 minutes