@c15t/backend 2.0.0-rc.0 → 2.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/302.js +473 -0
- package/dist/583.js +540 -0
- package/dist/915.js +1771 -0
- package/dist/cache.cjs +5 -5
- package/dist/cache.js +4 -415
- package/dist/core.cjs +1356 -120
- package/dist/core.js +163 -1981
- 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 +43 -3
- package/dist/db/schema.js +35 -4
- package/dist/define-config.cjs +1 -1
- package/dist/edge.cjs +1106 -0
- package/dist/edge.js +190 -0
- package/dist/router.cjs +885 -123
- package/dist/router.js +1 -1507
- package/dist/{types.cjs → 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 +0 -1
- 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-types/db/registry/consent-policy.d.ts +78 -0
- 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-types/db/registry/index.d.ts +118 -0
- package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
- package/{dist → dist-types}/db/registry/subject.d.ts +0 -2
- package/{dist → dist-types}/db/registry/types.d.ts +1 -1
- 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 +1 -2
- 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 -32
- package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -2
- package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +3 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +7 -2
- package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +455 -28
- 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 +1 -3
- package/{dist → dist-types}/db/schema/index.d.ts +908 -86
- package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
- package/dist-types/define-config.d.ts +17 -0
- package/dist-types/edge/index.d.ts +5 -0
- package/dist-types/edge/init-handler.d.ts +40 -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 +2 -3
- 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/legal-document/current.handler.d.ts +11 -0
- package/dist-types/handlers/legal-document/snapshot.d.ts +39 -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 +3 -2
- 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 +3 -2
- package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -2
- package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
- package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +3 -1
- package/{dist → dist-types}/init.d.ts +4 -7
- 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 +0 -1
- 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/{dist → dist-types}/routes/index.d.ts +1 -1
- package/{dist → dist-types}/routes/init.d.ts +0 -1
- package/dist-types/routes/legal-document.d.ts +7 -0
- 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-types/types/index.d.ts +464 -0
- package/dist-types/utils/background.d.ts +6 -0
- package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
- 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 +2 -3
- package/{dist → dist-types}/utils/logger.d.ts +0 -1
- 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 +208 -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 +251 -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 +53 -39
- package/.turbo/turbo-build.log +0 -49
- package/CHANGELOG.md +0 -89
- 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 +0 -23
- 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 +0 -57
- 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 +0 -5
- 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 -28
- 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.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 +0 -255
- 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 -368
- 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 -388
- package/src/db/registry/subject.ts +0 -129
- 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 -12
- 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 -26
- 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 -14
- package/src/db/schema/index.ts +0 -15
- package/src/db/tenant-scope.test.ts +0 -750
- package/src/db/tenant-scope.ts +0 -103
- package/src/define-config.ts +0 -5
- 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 -72
- 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 -93
- package/src/handlers/subject/list.handler.ts +0 -93
- package/src/handlers/subject/patch.handler.ts +0 -122
- package/src/handlers/subject/post.handler.test.ts +0 -294
- package/src/handlers/subject/post.handler.ts +0 -254
- 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 -126
- package/src/init.ts +0 -87
- 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 -195
- 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/index.ts +0 -10
- package/src/routes/init.ts +0 -102
- 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 -288
- package/src/utils/create-telemetry-options.test.ts +0 -302
- 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 -185
- package/src/utils/instrumentation.ts +0 -196
- package/src/utils/logger.ts +0 -41
- package/src/utils/metrics.test.ts +0 -323
- package/src/utils/metrics.ts +0 -402
- package/src/utils/telemetry-pii.test.ts +0 -325
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -28
- /package/dist/{types.js → types/index.js} +0 -0
- /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
package/rslib.config.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from '@rslib/core';
|
|
2
|
-
import { getRsdoctorPlugins } from '../shared/rslib-utils';
|
|
3
|
-
|
|
4
|
-
const externals = [
|
|
5
|
-
// Frameworks
|
|
6
|
-
'hono',
|
|
7
|
-
'express',
|
|
8
|
-
'next',
|
|
9
|
-
|
|
10
|
-
// UI frameworks
|
|
11
|
-
'react',
|
|
12
|
-
'vue',
|
|
13
|
-
'solid-js',
|
|
14
|
-
'solid-js/store',
|
|
15
|
-
'next/headers',
|
|
16
|
-
'$app/environment',
|
|
17
|
-
'@vue/runtime-dom',
|
|
18
|
-
'@vue/runtime-core',
|
|
19
|
-
'@vue/shared',
|
|
20
|
-
'@vue/reactivity',
|
|
21
|
-
'@vue/compiler-dom',
|
|
22
|
-
'@vue/compiler-core',
|
|
23
|
-
'csstype',
|
|
24
|
-
|
|
25
|
-
// Testing libraries
|
|
26
|
-
'vitest',
|
|
27
|
-
'@vitest/runner',
|
|
28
|
-
'@vitest/utils',
|
|
29
|
-
'@vitest/expect',
|
|
30
|
-
'@vitest/snapshot',
|
|
31
|
-
'@vitest/spy',
|
|
32
|
-
'chai',
|
|
33
|
-
'tinyspy',
|
|
34
|
-
|
|
35
|
-
// Utilities and others
|
|
36
|
-
'pathe',
|
|
37
|
-
'std-env',
|
|
38
|
-
'magic-string',
|
|
39
|
-
'pretty-format',
|
|
40
|
-
'p-limit',
|
|
41
|
-
'next/dist/compiled/@edge-runtime/cookies',
|
|
42
|
-
'@babel/types',
|
|
43
|
-
'@babel/parser',
|
|
44
|
-
'punycode',
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
export default defineConfig({
|
|
48
|
-
source: {
|
|
49
|
-
entry: {
|
|
50
|
-
core: ['./src/core.ts'],
|
|
51
|
-
router: ['./src/router.ts'],
|
|
52
|
-
'db/schema': ['./src/db/schema/index.ts'],
|
|
53
|
-
'db/adapters': ['./src/db/adapters/index.ts'],
|
|
54
|
-
'db/adapters/kysely': ['./src/db/adapters/kysely.ts'],
|
|
55
|
-
'db/adapters/drizzle': ['./src/db/adapters/drizzle.ts'],
|
|
56
|
-
'db/adapters/prisma': ['./src/db/adapters/prisma.ts'],
|
|
57
|
-
'db/adapters/typeorm': ['./src/db/adapters/typeorm.ts'],
|
|
58
|
-
'db/adapters/mongo': ['./src/db/adapters/mongo.ts'],
|
|
59
|
-
'db/migrator': ['./src/db/migrator/index.ts'],
|
|
60
|
-
'define-config': ['./src/define-config.ts'],
|
|
61
|
-
types: ['./src/types/index.ts'],
|
|
62
|
-
cache: ['./src/cache/index.ts'],
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
lib: [
|
|
66
|
-
{
|
|
67
|
-
dts: true,
|
|
68
|
-
bundle: true,
|
|
69
|
-
format: 'esm',
|
|
70
|
-
output: {
|
|
71
|
-
externals,
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
dts: true,
|
|
76
|
-
bundle: true,
|
|
77
|
-
format: 'cjs',
|
|
78
|
-
output: {
|
|
79
|
-
externals,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
output: {
|
|
84
|
-
target: 'node',
|
|
85
|
-
cleanDistPath: true,
|
|
86
|
-
externals,
|
|
87
|
-
},
|
|
88
|
-
tools: {
|
|
89
|
-
rspack: {
|
|
90
|
-
plugins: [...getRsdoctorPlugins()],
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cloudflare KV Cache Adapter
|
|
3
|
-
*
|
|
4
|
-
* Cache adapter for Cloudflare Workers KV storage.
|
|
5
|
-
*
|
|
6
|
-
* @packageDocumentation
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { CacheAdapter } from '../types';
|
|
10
|
-
import { GVL_TTL_MS } from '../types';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Cloudflare KV Namespace interface.
|
|
14
|
-
* Matches the KVNamespace type from @cloudflare/workers-types.
|
|
15
|
-
*
|
|
16
|
-
* @public
|
|
17
|
-
*/
|
|
18
|
-
export interface KVNamespace {
|
|
19
|
-
get(key: string, options?: { type?: 'text' | 'json' }): Promise<unknown>;
|
|
20
|
-
put(
|
|
21
|
-
key: string,
|
|
22
|
-
value: string,
|
|
23
|
-
options?: { expirationTtl?: number }
|
|
24
|
-
): Promise<void>;
|
|
25
|
-
delete(key: string): Promise<void>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Creates a Cloudflare KV cache adapter.
|
|
30
|
-
*
|
|
31
|
-
* @param kv - Cloudflare KV namespace binding
|
|
32
|
-
* @returns A CacheAdapter backed by Cloudflare KV
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```typescript
|
|
36
|
-
* // In your Cloudflare Worker
|
|
37
|
-
* export default {
|
|
38
|
-
* async fetch(request, env) {
|
|
39
|
-
* const kvAdapter = createCloudflareKVAdapter(env.GVL_CACHE);
|
|
40
|
-
*
|
|
41
|
-
* await kvAdapter.set('key', { data: 'value' }, 3600000);
|
|
42
|
-
* const value = await kvAdapter.get('key');
|
|
43
|
-
* }
|
|
44
|
-
* };
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* @public
|
|
48
|
-
*/
|
|
49
|
-
export function createCloudflareKVAdapter(kv: KVNamespace): CacheAdapter {
|
|
50
|
-
return {
|
|
51
|
-
async get<T>(key: string): Promise<T | null> {
|
|
52
|
-
const value = await kv.get(key, { type: 'json' });
|
|
53
|
-
return value as T | null;
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
async set<T>(key: string, value: T, ttlMs = GVL_TTL_MS): Promise<void> {
|
|
57
|
-
// Convert milliseconds to seconds for KV expirationTtl
|
|
58
|
-
const ttlSeconds = Math.ceil(ttlMs / 1000);
|
|
59
|
-
await kv.put(key, JSON.stringify(value), { expirationTtl: ttlSeconds });
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
async delete(key: string): Promise<void> {
|
|
63
|
-
await kv.delete(key);
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
async has(key: string): Promise<boolean> {
|
|
67
|
-
const value = await kv.get(key);
|
|
68
|
-
return value !== null;
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cache Adapters
|
|
3
|
-
*
|
|
4
|
-
* Pluggable cache adapter implementations for different storage backends.
|
|
5
|
-
*
|
|
6
|
-
* @packageDocumentation
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
createCloudflareKVAdapter,
|
|
11
|
-
type KVNamespace,
|
|
12
|
-
} from './cloudflare-kv';
|
|
13
|
-
export {
|
|
14
|
-
clearMemoryCache,
|
|
15
|
-
createMemoryCacheAdapter,
|
|
16
|
-
getMemoryCacheSize,
|
|
17
|
-
} from './memory';
|
|
18
|
-
export {
|
|
19
|
-
createUpstashRedisAdapter,
|
|
20
|
-
createUpstashRedisAdapterFromClient,
|
|
21
|
-
type UpstashRedisAdapterOptions,
|
|
22
|
-
} from './upstash-redis';
|
|
@@ -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
|
-
}
|