@c15t/backend 2.0.0-rc.4 → 2.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/302.js +473 -0
- package/dist/364.js +1140 -0
- package/dist/583.js +540 -0
- package/dist/cache.cjs +1 -1
- package/dist/cache.js +4 -415
- package/dist/core.cjs +849 -96
- package/dist/core.js +147 -1817
- package/dist/db/adapters/drizzle.cjs +1 -1
- package/dist/db/adapters/drizzle.js +1 -2
- package/dist/db/adapters/kysely.cjs +1 -1
- package/dist/db/adapters/kysely.js +1 -2
- package/dist/db/adapters/mongo.cjs +1 -1
- package/dist/db/adapters/mongo.js +1 -2
- package/dist/db/adapters/prisma.cjs +1 -1
- package/dist/db/adapters/prisma.js +1 -2
- package/dist/db/adapters/typeorm.cjs +1 -1
- package/dist/db/adapters/typeorm.js +1 -2
- package/dist/db/adapters.cjs +1 -1
- package/dist/db/migrator.cjs +1 -1
- package/dist/db/schema.cjs +38 -1
- package/dist/db/schema.js +33 -2
- package/dist/define-config.cjs +1 -1
- package/dist/edge.cjs +1106 -0
- package/dist/edge.js +190 -0
- package/dist/router.cjs +629 -81
- package/dist/router.js +1 -1509
- package/dist/types/index.cjs +1 -1
- package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
- package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
- package/{dist → dist-types}/cache/index.d.ts +0 -1
- package/{dist → dist-types}/cache/keys.d.ts +0 -1
- package/{dist → dist-types}/cache/types.d.ts +0 -1
- package/{dist → dist-types}/core.d.ts +8 -1
- package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
- package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
- package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
- package/{dist → dist-types}/db/registry/index.d.ts +22 -2
- package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
- package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
- package/{dist → dist-types}/db/registry/types.d.ts +1 -2
- package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
- package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +2 -3
- package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
- package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +2 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +2 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +2 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +6 -3
- package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +2 -3
- package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
- package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
- package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +2 -3
- package/{dist → dist-types}/db/schema/index.d.ts +862 -33
- package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
- package/{dist → dist-types}/define-config.d.ts +0 -1
- package/dist-types/edge/index.d.ts +5 -0
- package/dist-types/edge/init-handler.d.ts +38 -0
- package/dist-types/edge/resolve-consent.d.ts +80 -0
- package/dist-types/edge/types.d.ts +13 -0
- package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
- package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
- package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
- package/dist-types/handlers/init/policy.d.ts +26 -0
- package/dist-types/handlers/init/resolve-init.d.ts +44 -0
- package/dist-types/handlers/init/translations.d.ts +48 -0
- package/dist-types/handlers/policy/snapshot.d.ts +99 -0
- package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
- package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
- package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
- package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
- package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
- package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
- package/{dist → dist-types}/init.d.ts +0 -1
- package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
- package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
- package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
- package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
- package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
- package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
- package/dist-types/policies/builder.d.ts +127 -0
- package/dist-types/policies/defaults.d.ts +2 -0
- package/dist-types/policies/matchers.d.ts +3 -0
- package/{dist → dist-types}/router.d.ts +0 -1
- package/{dist → dist-types}/routes/consent.d.ts +0 -1
- package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
- package/{dist → dist-types}/routes/init.d.ts +0 -1
- package/{dist → dist-types}/routes/status.d.ts +0 -1
- package/{dist → dist-types}/routes/subject.d.ts +0 -1
- package/{dist → dist-types}/types/api.d.ts +0 -1
- package/{dist → dist-types}/types/index.d.ts +110 -6
- package/dist-types/utils/background.d.ts +6 -0
- package/{dist → dist-types}/utils/create-telemetry-options.d.ts +0 -1
- package/{dist → dist-types}/utils/env.d.ts +0 -1
- package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
- package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
- package/{dist → dist-types}/utils/logger.d.ts +1 -2
- package/{dist → dist-types}/utils/metrics.d.ts +0 -1
- package/dist-types/version.d.ts +1 -0
- package/docs/README.md +49 -0
- package/docs/api/configuration.md +197 -0
- package/docs/api/endpoints.md +211 -0
- package/docs/guides/caching.md +85 -0
- package/docs/guides/database-setup.md +128 -0
- package/docs/guides/edge-deployment.md +248 -0
- package/docs/guides/framework-integration.md +142 -0
- package/docs/guides/iab-tcf.md +89 -0
- package/docs/guides/observability.md +96 -0
- package/docs/guides/policy-packs.md +396 -0
- package/docs/quickstart.md +129 -0
- package/package.json +45 -31
- package/.turbo/turbo-build.log +0 -49
- package/CHANGELOG.md +0 -123
- package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
- package/dist/cache/adapters/index.d.ts.map +0 -1
- package/dist/cache/adapters/memory.d.ts.map +0 -1
- package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
- package/dist/cache/gvl-resolver.d.ts.map +0 -1
- package/dist/cache/index.d.ts.map +0 -1
- package/dist/cache/keys.d.ts.map +0 -1
- package/dist/cache/types.d.ts.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/db/adapters/drizzle.d.ts +0 -2
- package/dist/db/adapters/drizzle.d.ts.map +0 -1
- package/dist/db/adapters/index.d.ts +0 -2
- package/dist/db/adapters/index.d.ts.map +0 -1
- package/dist/db/adapters/kysely.d.ts +0 -2
- package/dist/db/adapters/kysely.d.ts.map +0 -1
- package/dist/db/adapters/mongo.d.ts +0 -2
- package/dist/db/adapters/mongo.d.ts.map +0 -1
- package/dist/db/adapters/prisma.d.ts +0 -2
- package/dist/db/adapters/prisma.d.ts.map +0 -1
- package/dist/db/adapters/typeorm.d.ts +0 -2
- package/dist/db/adapters/typeorm.d.ts.map +0 -1
- package/dist/db/migrator/index.d.ts.map +0 -1
- package/dist/db/registry/consent-policy.d.ts.map +0 -1
- package/dist/db/registry/consent-purpose.d.ts.map +0 -1
- package/dist/db/registry/domain.d.ts.map +0 -1
- package/dist/db/registry/index.d.ts.map +0 -1
- package/dist/db/registry/subject.d.ts.map +0 -1
- package/dist/db/registry/types.d.ts.map +0 -1
- package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
- package/dist/db/registry/utils.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/index.d.ts.map +0 -1
- package/dist/db/tenant-scope.d.ts.map +0 -1
- package/dist/define-config.d.ts.map +0 -1
- package/dist/handlers/consent/check.handler.d.ts.map +0 -1
- package/dist/handlers/consent/index.d.ts +0 -12
- package/dist/handlers/consent/index.d.ts.map +0 -1
- package/dist/handlers/init/geo.d.ts.map +0 -1
- package/dist/handlers/init/index.d.ts.map +0 -1
- package/dist/handlers/init/translations.d.ts +0 -26
- package/dist/handlers/init/translations.d.ts.map +0 -1
- package/dist/handlers/status/index.d.ts +0 -7
- package/dist/handlers/status/index.d.ts.map +0 -1
- package/dist/handlers/status/status.handler.d.ts.map +0 -1
- package/dist/handlers/subject/get.handler.d.ts.map +0 -1
- package/dist/handlers/subject/index.d.ts +0 -10
- package/dist/handlers/subject/index.d.ts.map +0 -1
- package/dist/handlers/subject/list.handler.d.ts.map +0 -1
- package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
- package/dist/handlers/subject/post.handler.d.ts.map +0 -1
- package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/middleware/auth/index.d.ts.map +0 -1
- package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
- package/dist/middleware/cors/cors.d.ts.map +0 -1
- package/dist/middleware/cors/index.d.ts +0 -30
- package/dist/middleware/cors/index.d.ts.map +0 -1
- package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
- package/dist/middleware/cors/process-cors.d.ts.map +0 -1
- package/dist/middleware/openapi/config.d.ts.map +0 -1
- package/dist/middleware/openapi/handlers.d.ts.map +0 -1
- package/dist/middleware/openapi/index.d.ts +0 -12
- package/dist/middleware/openapi/index.d.ts.map +0 -1
- package/dist/middleware/process-ip/index.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/routes/consent.d.ts.map +0 -1
- package/dist/routes/index.d.ts +0 -10
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/init.d.ts.map +0 -1
- package/dist/routes/status.d.ts.map +0 -1
- package/dist/routes/subject.d.ts.map +0 -1
- package/dist/types/api.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/create-telemetry-options.d.ts.map +0 -1
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/extract-error-message.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/instrumentation.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/metrics.d.ts.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/knip.json +0 -31
- package/rslib.config.ts +0 -93
- package/src/cache/adapters/cloudflare-kv.ts +0 -71
- package/src/cache/adapters/index.ts +0 -22
- package/src/cache/adapters/memory.ts +0 -111
- package/src/cache/adapters/upstash-redis.ts +0 -113
- package/src/cache/gvl-resolver.ts +0 -289
- package/src/cache/index.ts +0 -34
- package/src/cache/keys.ts +0 -68
- package/src/cache/types.ts +0 -66
- package/src/core.ts +0 -369
- package/src/db/migrator/index.ts +0 -80
- package/src/db/registry/consent-policy.test.ts +0 -451
- package/src/db/registry/consent-policy.ts +0 -82
- package/src/db/registry/consent-purpose.test.ts +0 -428
- package/src/db/registry/consent-purpose.ts +0 -61
- package/src/db/registry/domain.test.ts +0 -445
- package/src/db/registry/domain.ts +0 -91
- package/src/db/registry/index.ts +0 -14
- package/src/db/registry/subject.test.ts +0 -371
- package/src/db/registry/subject.ts +0 -126
- package/src/db/registry/types.ts +0 -10
- package/src/db/registry/utils/generate-id.test.ts +0 -216
- package/src/db/registry/utils/generate-id.ts +0 -133
- package/src/db/registry/utils.ts +0 -133
- package/src/db/schema/1.0.0/audit-log.ts +0 -15
- package/src/db/schema/1.0.0/consent-policy.ts +0 -14
- package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
- package/src/db/schema/1.0.0/consent-record.ts +0 -10
- package/src/db/schema/1.0.0/consent.ts +0 -20
- package/src/db/schema/1.0.0/domain.ts +0 -12
- package/src/db/schema/1.0.0/index.ts +0 -48
- package/src/db/schema/1.0.0/subject.ts +0 -11
- package/src/db/schema/2.0.0/audit-log.ts +0 -18
- package/src/db/schema/2.0.0/consent-policy.ts +0 -28
- package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
- package/src/db/schema/2.0.0/consent.ts +0 -28
- package/src/db/schema/2.0.0/domain.ts +0 -12
- package/src/db/schema/2.0.0/index.ts +0 -47
- package/src/db/schema/2.0.0/subject.ts +0 -13
- package/src/db/schema/index.ts +0 -15
- package/src/db/tenant-scope.test.ts +0 -747
- package/src/db/tenant-scope.ts +0 -103
- package/src/define-config.ts +0 -19
- package/src/handlers/consent/check.handler.ts +0 -126
- package/src/handlers/init/geo.test.ts +0 -317
- package/src/handlers/init/geo.ts +0 -195
- package/src/handlers/init/index.test.ts +0 -205
- package/src/handlers/init/index.ts +0 -114
- package/src/handlers/init/translations.test.ts +0 -121
- package/src/handlers/init/translations.ts +0 -69
- package/src/handlers/status/status.handler.test.ts +0 -155
- package/src/handlers/status/status.handler.ts +0 -51
- package/src/handlers/subject/get.handler.ts +0 -92
- package/src/handlers/subject/list.handler.ts +0 -92
- package/src/handlers/subject/patch.handler.ts +0 -119
- package/src/handlers/subject/post.handler.test.ts +0 -294
- package/src/handlers/subject/post.handler.ts +0 -268
- package/src/handlers/utils/consent-enrichment.test.ts +0 -380
- package/src/handlers/utils/consent-enrichment.ts +0 -218
- package/src/init.test.ts +0 -122
- package/src/init.ts +0 -88
- package/src/middleware/auth/index.ts +0 -11
- package/src/middleware/auth/validate-api-key.test.ts +0 -86
- package/src/middleware/auth/validate-api-key.ts +0 -107
- package/src/middleware/cors/cors.test.ts +0 -135
- package/src/middleware/cors/cors.ts +0 -186
- package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
- package/src/middleware/cors/is-origin-trusted.ts +0 -130
- package/src/middleware/cors/process-cors.ts +0 -91
- package/src/middleware/openapi/config.ts +0 -29
- package/src/middleware/openapi/handlers.ts +0 -34
- package/src/middleware/process-ip/index.test.ts +0 -193
- package/src/middleware/process-ip/index.ts +0 -199
- package/src/router.ts +0 -15
- package/src/routes/consent.ts +0 -52
- package/src/routes/init.ts +0 -105
- package/src/routes/status.ts +0 -46
- package/src/routes/subject.ts +0 -152
- package/src/types/api.ts +0 -48
- package/src/types/index.ts +0 -391
- package/src/utils/create-telemetry-options.test.ts +0 -286
- package/src/utils/create-telemetry-options.ts +0 -229
- package/src/utils/env.ts +0 -84
- package/src/utils/extract-error-message.ts +0 -21
- package/src/utils/instrumentation.test.ts +0 -183
- package/src/utils/instrumentation.ts +0 -194
- package/src/utils/logger.ts +0 -41
- package/src/utils/metrics.test.ts +0 -311
- package/src/utils/metrics.ts +0 -402
- package/src/utils/telemetry-pii.test.ts +0 -323
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -28
- /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
- /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
- /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
- /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
- /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
- /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
- /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
|
@@ -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
|
-
}
|
package/src/cache/index.ts
DELETED
|
@@ -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
|
-
}
|
package/src/cache/types.ts
DELETED
|
@@ -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
|