@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
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
enrichConsents,
|
|
4
|
-
parsePurposeIds,
|
|
5
|
-
resolveConsentPolicies,
|
|
6
|
-
} from './consent-enrichment';
|
|
7
|
-
|
|
8
|
-
describe('consent-enrichment', () => {
|
|
9
|
-
// ── parsePurposeIds ─────────────────────────────────────────────────
|
|
10
|
-
describe('parsePurposeIds', () => {
|
|
11
|
-
it('extracts IDs from { json: [...] } wrapper', () => {
|
|
12
|
-
expect(parsePurposeIds({ json: ['a', 'b'] })).toEqual(['a', 'b']);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('passes through raw string[]', () => {
|
|
16
|
-
expect(parsePurposeIds(['x', 'y'])).toEqual(['x', 'y']);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('returns [] for null', () => {
|
|
20
|
-
expect(parsePurposeIds(null)).toEqual([]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('returns [] for undefined', () => {
|
|
24
|
-
expect(parsePurposeIds(undefined)).toEqual([]);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('returns [] for empty array', () => {
|
|
28
|
-
expect(parsePurposeIds([])).toEqual([]);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('returns [] for empty { json: [] }', () => {
|
|
32
|
-
expect(parsePurposeIds({ json: [] })).toEqual([]);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('returns [] for non-array values', () => {
|
|
36
|
-
expect(parsePurposeIds('not-an-array')).toEqual([]);
|
|
37
|
-
expect(parsePurposeIds(42)).toEqual([]);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// ── enrichConsents ──────────────────────────────────────────────────
|
|
42
|
-
describe('enrichConsents', () => {
|
|
43
|
-
function createMockCtx(
|
|
44
|
-
policies: Array<{ id: string; type: string }> = [],
|
|
45
|
-
purposes: Array<{ id: string; code: string }> = [],
|
|
46
|
-
latestByType: Record<string, { id: string }> = {}
|
|
47
|
-
) {
|
|
48
|
-
const db = {
|
|
49
|
-
findMany: vi.fn((table: string, opts?: { where?: unknown }) => {
|
|
50
|
-
if (table === 'consentPolicy') return Promise.resolve(policies);
|
|
51
|
-
if (table === 'consentPurpose') return Promise.resolve(purposes);
|
|
52
|
-
return Promise.resolve([]);
|
|
53
|
-
}),
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const registry = {
|
|
57
|
-
findOrCreatePolicy: vi.fn((type: string) =>
|
|
58
|
-
Promise.resolve(latestByType[type] ?? { id: `latest_${type}` })
|
|
59
|
-
),
|
|
60
|
-
findConsentPolicyById: vi.fn(),
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return { db, registry } as unknown as Parameters<
|
|
64
|
-
typeof enrichConsents
|
|
65
|
-
>[1];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
it('returns [] for empty consents', async () => {
|
|
69
|
-
const ctx = createMockCtx();
|
|
70
|
-
const result = await enrichConsents([], ctx);
|
|
71
|
-
expect(result).toEqual([]);
|
|
72
|
-
// No DB calls should be made
|
|
73
|
-
expect((ctx.db as any).findMany).not.toHaveBeenCalled();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('enriches a single consent with policy and purposes', async () => {
|
|
77
|
-
const ctx = createMockCtx(
|
|
78
|
-
[{ id: 'pol_1', type: 'cookie_banner' }],
|
|
79
|
-
[
|
|
80
|
-
{ id: 'pur_1', code: 'analytics' },
|
|
81
|
-
{ id: 'pur_2', code: 'marketing' },
|
|
82
|
-
],
|
|
83
|
-
{ cookie_banner: { id: 'pol_1' } }
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const result = await enrichConsents(
|
|
87
|
-
[
|
|
88
|
-
{
|
|
89
|
-
id: 'con_1',
|
|
90
|
-
policyId: 'pol_1',
|
|
91
|
-
purposeIds: ['pur_1', 'pur_2'],
|
|
92
|
-
givenAt: new Date('2024-01-01'),
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
ctx
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
expect(result).toHaveLength(1);
|
|
99
|
-
expect(result[0]).toEqual({
|
|
100
|
-
id: 'con_1',
|
|
101
|
-
type: 'cookie_banner',
|
|
102
|
-
policyId: 'pol_1',
|
|
103
|
-
isLatestPolicy: true,
|
|
104
|
-
preferences: { analytics: true, marketing: true },
|
|
105
|
-
givenAt: new Date('2024-01-01'),
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('uses batch findMany with "in" operator (not N individual calls)', async () => {
|
|
110
|
-
const policies = [
|
|
111
|
-
{ id: 'pol_1', type: 'cookie_banner' },
|
|
112
|
-
{ id: 'pol_2', type: 'privacy_policy' },
|
|
113
|
-
];
|
|
114
|
-
const purposes = [
|
|
115
|
-
{ id: 'pur_1', code: 'analytics' },
|
|
116
|
-
{ id: 'pur_2', code: 'marketing' },
|
|
117
|
-
];
|
|
118
|
-
const ctx = createMockCtx(policies, purposes, {
|
|
119
|
-
cookie_banner: { id: 'pol_1' },
|
|
120
|
-
privacy_policy: { id: 'pol_2' },
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await enrichConsents(
|
|
124
|
-
[
|
|
125
|
-
{
|
|
126
|
-
id: 'c1',
|
|
127
|
-
policyId: 'pol_1',
|
|
128
|
-
purposeIds: ['pur_1'],
|
|
129
|
-
givenAt: new Date(),
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
id: 'c2',
|
|
133
|
-
policyId: 'pol_2',
|
|
134
|
-
purposeIds: ['pur_2'],
|
|
135
|
-
givenAt: new Date(),
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
ctx
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
const findManyCalls = (ctx.db as any).findMany.mock.calls;
|
|
142
|
-
// Exactly 2 findMany calls: one for policies, one for purposes
|
|
143
|
-
expect(findManyCalls).toHaveLength(2);
|
|
144
|
-
expect(findManyCalls[0][0]).toBe('consentPolicy');
|
|
145
|
-
expect(findManyCalls[1][0]).toBe('consentPurpose');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('sets type = "unknown" and isLatestPolicy = false for null policyId', async () => {
|
|
149
|
-
const ctx = createMockCtx([], [{ id: 'pur_1', code: 'analytics' }]);
|
|
150
|
-
|
|
151
|
-
const result = await enrichConsents(
|
|
152
|
-
[
|
|
153
|
-
{
|
|
154
|
-
id: 'con_1',
|
|
155
|
-
policyId: null,
|
|
156
|
-
purposeIds: ['pur_1'],
|
|
157
|
-
givenAt: new Date('2024-01-01'),
|
|
158
|
-
},
|
|
159
|
-
],
|
|
160
|
-
ctx
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
expect(result[0]!.type).toBe('unknown');
|
|
164
|
-
expect(result[0]!.isLatestPolicy).toBe(false);
|
|
165
|
-
expect(result[0]!.policyId).toBeUndefined();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('isLatestPolicy is false when consent has an older policy', async () => {
|
|
169
|
-
const ctx = createMockCtx(
|
|
170
|
-
[{ id: 'pol_old', type: 'cookie_banner' }],
|
|
171
|
-
[],
|
|
172
|
-
{ cookie_banner: { id: 'pol_new' } } // latest is different
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
const result = await enrichConsents(
|
|
176
|
-
[
|
|
177
|
-
{
|
|
178
|
-
id: 'con_1',
|
|
179
|
-
policyId: 'pol_old',
|
|
180
|
-
purposeIds: null,
|
|
181
|
-
givenAt: new Date(),
|
|
182
|
-
},
|
|
183
|
-
],
|
|
184
|
-
ctx
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
expect(result[0]!.isLatestPolicy).toBe(false);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('handles { json: [...] } wrapper for purposeIds', async () => {
|
|
191
|
-
const ctx = createMockCtx(
|
|
192
|
-
[{ id: 'pol_1', type: 'cookie_banner' }],
|
|
193
|
-
[{ id: 'pur_1', code: 'analytics' }],
|
|
194
|
-
{ cookie_banner: { id: 'pol_1' } }
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
const result = await enrichConsents(
|
|
198
|
-
[
|
|
199
|
-
{
|
|
200
|
-
id: 'con_1',
|
|
201
|
-
policyId: 'pol_1',
|
|
202
|
-
purposeIds: { json: ['pur_1'] },
|
|
203
|
-
givenAt: new Date(),
|
|
204
|
-
},
|
|
205
|
-
],
|
|
206
|
-
ctx
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
expect(result[0]!.preferences).toEqual({ analytics: true });
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('skips purposes not found in DB', async () => {
|
|
213
|
-
const ctx = createMockCtx(
|
|
214
|
-
[{ id: 'pol_1', type: 'cookie_banner' }],
|
|
215
|
-
[{ id: 'pur_1', code: 'analytics' }], // pur_2 intentionally missing
|
|
216
|
-
{ cookie_banner: { id: 'pol_1' } }
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
const result = await enrichConsents(
|
|
220
|
-
[
|
|
221
|
-
{
|
|
222
|
-
id: 'con_1',
|
|
223
|
-
policyId: 'pol_1',
|
|
224
|
-
purposeIds: ['pur_1', 'pur_2_missing'],
|
|
225
|
-
givenAt: new Date(),
|
|
226
|
-
},
|
|
227
|
-
],
|
|
228
|
-
ctx
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
expect(result[0]!.preferences).toEqual({ analytics: true });
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('leaves preferences undefined when purposeIds is empty', async () => {
|
|
235
|
-
const ctx = createMockCtx([{ id: 'pol_1', type: 'cookie_banner' }], [], {
|
|
236
|
-
cookie_banner: { id: 'pol_1' },
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
const result = await enrichConsents(
|
|
240
|
-
[
|
|
241
|
-
{
|
|
242
|
-
id: 'con_1',
|
|
243
|
-
policyId: 'pol_1',
|
|
244
|
-
purposeIds: [],
|
|
245
|
-
givenAt: new Date(),
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
ctx
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
expect(result[0]!.preferences).toBeUndefined();
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('does not call findMany for policies when no consents have policyId', async () => {
|
|
255
|
-
const ctx = createMockCtx();
|
|
256
|
-
|
|
257
|
-
await enrichConsents(
|
|
258
|
-
[
|
|
259
|
-
{
|
|
260
|
-
id: 'con_1',
|
|
261
|
-
policyId: null,
|
|
262
|
-
purposeIds: null,
|
|
263
|
-
givenAt: new Date(),
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
ctx
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
const findManyCalls = (ctx.db as any).findMany.mock.calls;
|
|
270
|
-
// Should not call findMany for consentPolicy (empty policyIds set)
|
|
271
|
-
const policyCalls = findManyCalls.filter(
|
|
272
|
-
(c: unknown[]) => c[0] === 'consentPolicy'
|
|
273
|
-
);
|
|
274
|
-
expect(policyCalls).toHaveLength(0);
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
// ── resolveConsentPolicies ──────────────────────────────────────────
|
|
279
|
-
describe('resolveConsentPolicies', () => {
|
|
280
|
-
function createMockCtx(
|
|
281
|
-
policies: Array<{ id: string; type: string }> = [],
|
|
282
|
-
latestByType: Record<string, { id: string }> = {}
|
|
283
|
-
) {
|
|
284
|
-
const db = {
|
|
285
|
-
findMany: vi.fn(() => Promise.resolve(policies)),
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const registry = {
|
|
289
|
-
findOrCreatePolicy: vi.fn((type: string) =>
|
|
290
|
-
Promise.resolve(latestByType[type] ?? { id: `latest_${type}` })
|
|
291
|
-
),
|
|
292
|
-
findConsentPolicyById: vi.fn(),
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
return { db, registry } as unknown as Parameters<
|
|
296
|
-
typeof resolveConsentPolicies
|
|
297
|
-
>[1];
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
it('returns [] for empty consents', async () => {
|
|
301
|
-
const ctx = createMockCtx();
|
|
302
|
-
const result = await resolveConsentPolicies([], ctx);
|
|
303
|
-
expect(result).toEqual([]);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it('returns correct policy info with isLatestPolicy', async () => {
|
|
307
|
-
const ctx = createMockCtx([{ id: 'pol_1', type: 'cookie_banner' }], {
|
|
308
|
-
cookie_banner: { id: 'pol_1' },
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
const result = await resolveConsentPolicies(
|
|
312
|
-
[{ id: 'con_1', policyId: 'pol_1' }],
|
|
313
|
-
ctx
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
expect(result).toEqual([
|
|
317
|
-
{
|
|
318
|
-
consentId: 'con_1',
|
|
319
|
-
policyType: 'cookie_banner',
|
|
320
|
-
policyId: 'pol_1',
|
|
321
|
-
isLatestPolicy: true,
|
|
322
|
-
},
|
|
323
|
-
]);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('returns unknown type for null policyId', async () => {
|
|
327
|
-
const ctx = createMockCtx();
|
|
328
|
-
|
|
329
|
-
const result = await resolveConsentPolicies(
|
|
330
|
-
[{ id: 'con_1', policyId: null }],
|
|
331
|
-
ctx
|
|
332
|
-
);
|
|
333
|
-
|
|
334
|
-
expect(result[0]).toEqual({
|
|
335
|
-
consentId: 'con_1',
|
|
336
|
-
policyType: 'unknown',
|
|
337
|
-
policyId: undefined,
|
|
338
|
-
isLatestPolicy: false,
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it('does not load purposes (no consentPurpose findMany call)', async () => {
|
|
343
|
-
const ctx = createMockCtx([{ id: 'pol_1', type: 'cookie_banner' }], {
|
|
344
|
-
cookie_banner: { id: 'pol_1' },
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
await resolveConsentPolicies([{ id: 'con_1', policyId: 'pol_1' }], ctx);
|
|
348
|
-
|
|
349
|
-
const findManyCalls = (ctx.db as any).findMany.mock.calls;
|
|
350
|
-
const purposeCalls = findManyCalls.filter(
|
|
351
|
-
(c: unknown[]) => c[0] === 'consentPurpose'
|
|
352
|
-
);
|
|
353
|
-
expect(purposeCalls).toHaveLength(0);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it('handles multiple consents with different policy types', async () => {
|
|
357
|
-
const ctx = createMockCtx(
|
|
358
|
-
[
|
|
359
|
-
{ id: 'pol_1', type: 'cookie_banner' },
|
|
360
|
-
{ id: 'pol_2', type: 'privacy_policy' },
|
|
361
|
-
],
|
|
362
|
-
{
|
|
363
|
-
cookie_banner: { id: 'pol_1' },
|
|
364
|
-
privacy_policy: { id: 'pol_latest' }, // different from pol_2
|
|
365
|
-
}
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
const result = await resolveConsentPolicies(
|
|
369
|
-
[
|
|
370
|
-
{ id: 'con_1', policyId: 'pol_1' },
|
|
371
|
-
{ id: 'con_2', policyId: 'pol_2' },
|
|
372
|
-
],
|
|
373
|
-
ctx
|
|
374
|
-
);
|
|
375
|
-
|
|
376
|
-
expect(result[0]!.isLatestPolicy).toBe(true);
|
|
377
|
-
expect(result[1]!.isLatestPolicy).toBe(false);
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
});
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared consent enrichment utilities.
|
|
3
|
-
*
|
|
4
|
-
* Extracts duplicated consent-building logic from get/list/check handlers
|
|
5
|
-
* and batch-loads policies + purposes to eliminate N+1 queries.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { PolicyType } from '~/db/schema';
|
|
11
|
-
import type { C15TContext } from '~/types';
|
|
12
|
-
|
|
13
|
-
type EnrichmentContext = Pick<C15TContext, 'db' | 'registry'>;
|
|
14
|
-
|
|
15
|
-
export interface EnrichedConsentItem {
|
|
16
|
-
id: string;
|
|
17
|
-
type: string;
|
|
18
|
-
policyId: string | undefined;
|
|
19
|
-
isLatestPolicy: boolean;
|
|
20
|
-
preferences: Record<string, boolean> | undefined;
|
|
21
|
-
givenAt: Date;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ConsentPolicyInfo {
|
|
25
|
-
consentId: string;
|
|
26
|
-
policyType: string;
|
|
27
|
-
policyId: string | undefined;
|
|
28
|
-
isLatestPolicy: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Parse purposeIds from DB — handles both `{ json: string[] }` wrapper
|
|
33
|
-
* (some adapters) and raw `string[]` format.
|
|
34
|
-
*/
|
|
35
|
-
export function parsePurposeIds(purposeIds: unknown): string[] {
|
|
36
|
-
if (purposeIds == null) return [];
|
|
37
|
-
|
|
38
|
-
const ids =
|
|
39
|
-
typeof purposeIds === 'object' && 'json' in (purposeIds as object)
|
|
40
|
-
? (purposeIds as { json: unknown }).json
|
|
41
|
-
: purposeIds;
|
|
42
|
-
|
|
43
|
-
return Array.isArray(ids) ? ids : [];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Batch-fetch all referenced policies and resolve the latest policy per type.
|
|
48
|
-
*
|
|
49
|
-
* 1 query for findMany('consentPolicy', { where: id IN ... })
|
|
50
|
-
* ≤7 calls for findOrCreatePolicy (one per unique PolicyType)
|
|
51
|
-
*/
|
|
52
|
-
async function batchLoadPolicies(
|
|
53
|
-
policyIds: Set<string>,
|
|
54
|
-
ctx: EnrichmentContext
|
|
55
|
-
) {
|
|
56
|
-
const { db, registry } = ctx;
|
|
57
|
-
|
|
58
|
-
// Fetch all referenced policies in one query
|
|
59
|
-
const policyMap = new Map<
|
|
60
|
-
string,
|
|
61
|
-
{ id: string; type: string; [key: string]: unknown }
|
|
62
|
-
>();
|
|
63
|
-
|
|
64
|
-
if (policyIds.size > 0) {
|
|
65
|
-
const policies = await db.findMany('consentPolicy', {
|
|
66
|
-
where: (b) => b('id', 'in', [...policyIds]),
|
|
67
|
-
});
|
|
68
|
-
for (const p of policies) {
|
|
69
|
-
policyMap.set(p.id, p);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Resolve the latest policy for each unique type
|
|
74
|
-
const uniqueTypes = new Set<string>();
|
|
75
|
-
for (const p of policyMap.values()) {
|
|
76
|
-
uniqueTypes.add(p.type);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const latestPolicyByType = new Map<string, string>();
|
|
80
|
-
for (const type of uniqueTypes) {
|
|
81
|
-
const latest = await registry.findOrCreatePolicy(type as PolicyType);
|
|
82
|
-
if (latest) {
|
|
83
|
-
latestPolicyByType.set(type, latest.id);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return { policyMap, latestPolicyByType };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Full consent enrichment for get/list handlers.
|
|
92
|
-
*
|
|
93
|
-
* Resolves policy types, isLatestPolicy, and purpose preferences
|
|
94
|
-
* using batch queries instead of per-consent lookups.
|
|
95
|
-
*/
|
|
96
|
-
export async function enrichConsents(
|
|
97
|
-
consents: Array<{
|
|
98
|
-
id: string;
|
|
99
|
-
policyId: string | null;
|
|
100
|
-
purposeIds: unknown;
|
|
101
|
-
givenAt: Date;
|
|
102
|
-
}>,
|
|
103
|
-
ctx: EnrichmentContext
|
|
104
|
-
): Promise<EnrichedConsentItem[]> {
|
|
105
|
-
if (consents.length === 0) return [];
|
|
106
|
-
|
|
107
|
-
// Collect all policy IDs
|
|
108
|
-
const policyIds = new Set<string>();
|
|
109
|
-
for (const c of consents) {
|
|
110
|
-
if (c.policyId) policyIds.add(c.policyId);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const { policyMap, latestPolicyByType } = await batchLoadPolicies(
|
|
114
|
-
policyIds,
|
|
115
|
-
ctx
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Collect all purpose IDs across all consents
|
|
119
|
-
const allPurposeIds = new Set<string>();
|
|
120
|
-
for (const c of consents) {
|
|
121
|
-
for (const id of parsePurposeIds(c.purposeIds)) {
|
|
122
|
-
allPurposeIds.add(id);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Batch-fetch all purposes in one query
|
|
127
|
-
const purposeMap = new Map<string, string>(); // id → code
|
|
128
|
-
if (allPurposeIds.size > 0) {
|
|
129
|
-
const purposes = await ctx.db.findMany('consentPurpose', {
|
|
130
|
-
where: (b) => b('id', 'in', [...allPurposeIds]),
|
|
131
|
-
});
|
|
132
|
-
for (const p of purposes) {
|
|
133
|
-
purposeMap.set(p.id, p.code);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Map consents synchronously — zero additional queries
|
|
138
|
-
return consents.map((consent) => {
|
|
139
|
-
let policyType = 'unknown';
|
|
140
|
-
let isLatestPolicy = false;
|
|
141
|
-
|
|
142
|
-
if (consent.policyId) {
|
|
143
|
-
const policy = policyMap.get(consent.policyId);
|
|
144
|
-
if (policy) {
|
|
145
|
-
policyType = policy.type;
|
|
146
|
-
isLatestPolicy =
|
|
147
|
-
latestPolicyByType.get(policyType) === consent.policyId;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
let preferences: Record<string, boolean> | undefined;
|
|
152
|
-
const ids = parsePurposeIds(consent.purposeIds);
|
|
153
|
-
if (ids.length > 0) {
|
|
154
|
-
preferences = {};
|
|
155
|
-
for (const purposeId of ids) {
|
|
156
|
-
const code = purposeMap.get(purposeId);
|
|
157
|
-
if (code) {
|
|
158
|
-
preferences[code] = true;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
id: consent.id,
|
|
165
|
-
type: policyType,
|
|
166
|
-
policyId: consent.policyId ?? undefined,
|
|
167
|
-
isLatestPolicy,
|
|
168
|
-
preferences,
|
|
169
|
-
givenAt: consent.givenAt,
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Policy-only enrichment for check handler.
|
|
176
|
-
*
|
|
177
|
-
* Resolves policy type and isLatestPolicy without loading purposes.
|
|
178
|
-
*/
|
|
179
|
-
export async function resolveConsentPolicies(
|
|
180
|
-
consents: Array<{
|
|
181
|
-
id: string;
|
|
182
|
-
policyId: string | null;
|
|
183
|
-
}>,
|
|
184
|
-
ctx: EnrichmentContext
|
|
185
|
-
): Promise<ConsentPolicyInfo[]> {
|
|
186
|
-
if (consents.length === 0) return [];
|
|
187
|
-
|
|
188
|
-
const policyIds = new Set<string>();
|
|
189
|
-
for (const c of consents) {
|
|
190
|
-
if (c.policyId) policyIds.add(c.policyId);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const { policyMap, latestPolicyByType } = await batchLoadPolicies(
|
|
194
|
-
policyIds,
|
|
195
|
-
ctx
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
return consents.map((consent) => {
|
|
199
|
-
let policyType = 'unknown';
|
|
200
|
-
let isLatestPolicy = false;
|
|
201
|
-
|
|
202
|
-
if (consent.policyId) {
|
|
203
|
-
const policy = policyMap.get(consent.policyId);
|
|
204
|
-
if (policy) {
|
|
205
|
-
policyType = policy.type;
|
|
206
|
-
isLatestPolicy =
|
|
207
|
-
latestPolicyByType.get(policyType) === consent.policyId;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
consentId: consent.id,
|
|
213
|
-
policyType,
|
|
214
|
-
policyId: consent.policyId ?? undefined,
|
|
215
|
-
isLatestPolicy,
|
|
216
|
-
};
|
|
217
|
-
});
|
|
218
|
-
}
|
package/src/init.test.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { init } from './init';
|
|
3
|
-
import type { C15TOptions } from './types';
|
|
4
|
-
|
|
5
|
-
// Use vi.hoisted so these are available inside vi.mock factories (which are hoisted)
|
|
6
|
-
const { mockLogger, mockClient, mockClientOrm } = vi.hoisted(() => {
|
|
7
|
-
const mockLogger = {
|
|
8
|
-
debug: vi.fn(),
|
|
9
|
-
info: vi.fn(),
|
|
10
|
-
warn: vi.fn(),
|
|
11
|
-
error: vi.fn(),
|
|
12
|
-
success: vi.fn(),
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const mockClientOrm = vi.fn().mockReturnValue({});
|
|
16
|
-
const mockClient = vi.fn().mockReturnValue({
|
|
17
|
-
orm: mockClientOrm,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
return { mockLogger, mockClient, mockClientOrm };
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Mock local modules
|
|
24
|
-
vi.mock('./utils/logger', () => ({
|
|
25
|
-
initLogger: vi.fn(() => mockLogger),
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
vi.mock('./utils/create-telemetry-options', () => ({
|
|
29
|
-
createTelemetryOptions: vi.fn((appName, config) => ({
|
|
30
|
-
enabled: config?.enabled ?? false,
|
|
31
|
-
tracer: config?.tracer,
|
|
32
|
-
meter: config?.meter,
|
|
33
|
-
defaultAttributes: {
|
|
34
|
-
'service.name': appName,
|
|
35
|
-
'service.version': '1.0.0',
|
|
36
|
-
...config?.defaultAttributes,
|
|
37
|
-
},
|
|
38
|
-
})),
|
|
39
|
-
isTelemetryEnabled: vi.fn(
|
|
40
|
-
(options) => options?.advanced?.telemetry?.enabled === true
|
|
41
|
-
),
|
|
42
|
-
}));
|
|
43
|
-
|
|
44
|
-
vi.mock('./db/registry', () => ({
|
|
45
|
-
createRegistry: vi.fn().mockReturnValue({}),
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
vi.mock('./db/schema', () => ({
|
|
49
|
-
DB: {
|
|
50
|
-
client: mockClient,
|
|
51
|
-
},
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
vi.clearAllMocks();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
afterEach(() => {
|
|
59
|
-
vi.clearAllMocks();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
function createOptions(overrides: Partial<C15TOptions> = {}): C15TOptions {
|
|
63
|
-
return {
|
|
64
|
-
trustedOrigins: [],
|
|
65
|
-
adapter: {} as C15TOptions['adapter'],
|
|
66
|
-
...overrides,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
describe('init', () => {
|
|
71
|
-
it('uses "c15t" as default appName when none is provided', () => {
|
|
72
|
-
const options = createOptions();
|
|
73
|
-
const context = init(options);
|
|
74
|
-
|
|
75
|
-
expect(context.appName).toBe('c15t');
|
|
76
|
-
expect(mockClient).toHaveBeenCalledTimes(1);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('uses the provided appName', () => {
|
|
80
|
-
const options = createOptions({ appName: 'MyAmazingApp' });
|
|
81
|
-
const context = init(options);
|
|
82
|
-
|
|
83
|
-
expect(context.appName).toBe('MyAmazingApp');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('telemetry is disabled by default (opt-in)', () => {
|
|
87
|
-
const options = createOptions();
|
|
88
|
-
init(options);
|
|
89
|
-
|
|
90
|
-
// Check that logger was called with telemetry disabled message
|
|
91
|
-
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
92
|
-
'Telemetry is disabled (opt-in required)'
|
|
93
|
-
);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('logs telemetry enabled when explicitly enabled', () => {
|
|
97
|
-
const options = createOptions({
|
|
98
|
-
advanced: {
|
|
99
|
-
telemetry: {
|
|
100
|
-
enabled: true,
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
init(options);
|
|
105
|
-
|
|
106
|
-
// Check that logger was called with telemetry enabled message
|
|
107
|
-
expect(mockLogger.debug).toHaveBeenCalledWith(
|
|
108
|
-
'Telemetry is enabled',
|
|
109
|
-
expect.objectContaining({
|
|
110
|
-
hasTracer: false,
|
|
111
|
-
hasMeter: false,
|
|
112
|
-
})
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('creates context with required properties', () => {
|
|
117
|
-
const options = createOptions();
|
|
118
|
-
const context = init(options);
|
|
119
|
-
|
|
120
|
-
expect(context).toHaveProperty('appName');
|
|
121
|
-
expect(context).toHaveProperty('logger');
|
|
122
|
-
expect(context).toHaveProperty('db');
|
|
123
|
-
expect(context).toHaveProperty('registry');
|
|
124
|
-
expect(context).toHaveProperty('trustedOrigins');
|
|
125
|
-
});
|
|
126
|
-
});
|