@c15t/backend 2.0.0-rc.5 → 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 +21 -24
- package/dist/core.js +18 -2420
- 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 +1 -1
- package/dist/db/schema.js +1 -1
- package/dist/define-config.cjs +1 -1
- package/dist/edge.cjs +1 -1
- package/dist/edge.js +3 -882
- package/dist/router.cjs +17 -18
- package/dist/router.js +1 -2058
- package/dist/types/index.cjs +1 -1
- package/dist-types/cache/gvl-resolver.d.ts +1 -1
- package/dist-types/db/registry/runtime-policy-decision.d.ts +1 -1
- package/dist-types/db/schema/1.0.0/consent.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/audit-log.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/consent-policy.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/consent-purpose.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/consent.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/domain.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +1 -1
- package/dist-types/db/schema/2.0.0/subject.d.ts +1 -1
- package/dist-types/handlers/init/index.d.ts +1 -1
- package/dist-types/handlers/init/policy.d.ts +1 -1
- package/dist-types/handlers/init/resolve-init.d.ts +1 -1
- package/dist-types/handlers/policy/snapshot.d.ts +1 -1
- package/dist-types/policies/defaults.d.ts +1 -1
- package/dist-types/policies/matchers.d.ts +2 -2
- package/dist-types/types/index.d.ts +2 -2
- package/dist-types/version.d.ts +1 -1
- package/docs/guides/policy-packs.md +1 -1
- package/package.json +15 -15
package/dist/edge.js
CHANGED
|
@@ -1,884 +1,5 @@
|
|
|
1
1
|
import { createLogger } from "@c15t/logger";
|
|
2
|
-
import { inspectPolicies,
|
|
3
|
-
import { SpanKind as api_SpanKind, SpanStatusCode as api_SpanStatusCode, context, metrics, trace as api_trace } from "@opentelemetry/api";
|
|
4
|
-
import { SignJWT } from "jose";
|
|
5
|
-
import { deepMergeTranslations, selectLanguage } from "@c15t/translations";
|
|
6
|
-
import { baseTranslations } from "@c15t/translations/all";
|
|
7
|
-
function policy_inspectPolicies(policies, options) {
|
|
8
|
-
return inspectPolicies(policies, options);
|
|
9
|
-
}
|
|
10
|
-
async function policy_resolvePolicyDecision(params) {
|
|
11
|
-
return resolvePolicyDecision({
|
|
12
|
-
policies: params.policies,
|
|
13
|
-
countryCode: params.countryCode,
|
|
14
|
-
regionCode: params.regionCode,
|
|
15
|
-
jurisdiction: params.jurisdiction,
|
|
16
|
-
iabEnabled: params.iabEnabled
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
function policy_resolvePolicySync(params) {
|
|
20
|
-
return resolvePolicySync({
|
|
21
|
-
policies: params.policies,
|
|
22
|
-
countryCode: params.countryCode,
|
|
23
|
-
regionCode: params.regionCode,
|
|
24
|
-
jurisdiction: params.jurisdiction,
|
|
25
|
-
iabEnabled: params.iabEnabled
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
function extractErrorMessage(error) {
|
|
29
|
-
if (error instanceof AggregateError && error.errors?.length > 0) {
|
|
30
|
-
const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
|
|
31
|
-
return `AggregateError: ${inner}`;
|
|
32
|
-
}
|
|
33
|
-
if (error instanceof Error) return error.message || error.name;
|
|
34
|
-
return String(error);
|
|
35
|
-
}
|
|
36
|
-
let cachedConfig = null;
|
|
37
|
-
let cachedDefaultAttributes = {};
|
|
38
|
-
function create_telemetry_options_isTelemetryEnabled(options) {
|
|
39
|
-
if (options) return options.telemetry?.enabled === true;
|
|
40
|
-
return cachedConfig?.enabled === true;
|
|
41
|
-
}
|
|
42
|
-
const create_telemetry_options_getTracer = (options)=>{
|
|
43
|
-
if (!create_telemetry_options_isTelemetryEnabled(options)) return api_trace.getTracer('c15t-noop');
|
|
44
|
-
const tracer = options?.telemetry?.tracer ?? cachedConfig?.tracer;
|
|
45
|
-
if (tracer) return tracer;
|
|
46
|
-
return api_trace.getTracer(options?.appName ?? 'c15t');
|
|
47
|
-
};
|
|
48
|
-
const getMeter = (options)=>{
|
|
49
|
-
if (!create_telemetry_options_isTelemetryEnabled(options)) return metrics.getMeter('c15t-noop');
|
|
50
|
-
const meter = options?.telemetry?.meter ?? cachedConfig?.meter;
|
|
51
|
-
if (meter) return meter;
|
|
52
|
-
return metrics.getMeter(options?.appName ?? 'c15t');
|
|
53
|
-
};
|
|
54
|
-
function getDefaultAttributes() {
|
|
55
|
-
return cachedDefaultAttributes;
|
|
56
|
-
}
|
|
57
|
-
const handleSpanError = (span, error)=>{
|
|
58
|
-
span.setStatus({
|
|
59
|
-
code: api_SpanStatusCode.ERROR,
|
|
60
|
-
message: extractErrorMessage(error)
|
|
61
|
-
});
|
|
62
|
-
if (error instanceof Error) span.setAttribute('error.type', error.name);
|
|
63
|
-
};
|
|
64
|
-
const withSpanContext = async (span, operation)=>context["with"](api_trace.setSpan(context.active(), span), operation);
|
|
65
|
-
async function executeWithSpan(span, operation) {
|
|
66
|
-
try {
|
|
67
|
-
const result = await withSpanContext(span, operation);
|
|
68
|
-
span.setStatus({
|
|
69
|
-
code: api_SpanStatusCode.OK
|
|
70
|
-
});
|
|
71
|
-
return result;
|
|
72
|
-
} catch (error) {
|
|
73
|
-
handleSpanError(span, error);
|
|
74
|
-
throw error;
|
|
75
|
-
} finally{
|
|
76
|
-
span.end();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function resolveDefaultAttributes(options) {
|
|
80
|
-
return options?.telemetry?.defaultAttributes || getDefaultAttributes();
|
|
81
|
-
}
|
|
82
|
-
async function withExternalSpan(attributes, operation, options) {
|
|
83
|
-
if (!create_telemetry_options_isTelemetryEnabled(options)) return operation();
|
|
84
|
-
const tracer = create_telemetry_options_getTracer(options);
|
|
85
|
-
const url = new URL(attributes.url);
|
|
86
|
-
const spanName = `HTTP ${attributes.method} ${url.hostname}`;
|
|
87
|
-
const span = tracer.startSpan(spanName, {
|
|
88
|
-
kind: api_SpanKind.CLIENT,
|
|
89
|
-
attributes: {
|
|
90
|
-
'http.method': attributes.method,
|
|
91
|
-
'http.url': `${url.origin}${url.pathname}`,
|
|
92
|
-
'http.host': url.hostname,
|
|
93
|
-
...resolveDefaultAttributes(options),
|
|
94
|
-
...Object.fromEntries(Object.entries(attributes).filter(([key])=>![
|
|
95
|
-
'url',
|
|
96
|
-
'method'
|
|
97
|
-
].includes(key)))
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
return executeWithSpan(span, operation);
|
|
101
|
-
}
|
|
102
|
-
async function withCacheSpan(operation, layer, fn, options) {
|
|
103
|
-
if (!create_telemetry_options_isTelemetryEnabled(options)) return fn();
|
|
104
|
-
const tracer = create_telemetry_options_getTracer(options);
|
|
105
|
-
const spanName = `cache.${layer}.${operation}`;
|
|
106
|
-
const span = tracer.startSpan(spanName, {
|
|
107
|
-
kind: api_SpanKind.CLIENT,
|
|
108
|
-
attributes: {
|
|
109
|
-
'cache.operation': operation,
|
|
110
|
-
'cache.layer': layer,
|
|
111
|
-
...resolveDefaultAttributes(options)
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
return executeWithSpan(span, fn);
|
|
115
|
-
}
|
|
116
|
-
function sanitizeAttributes(attrs) {
|
|
117
|
-
return Object.fromEntries(Object.entries(attrs).filter(([_, v])=>null != v));
|
|
118
|
-
}
|
|
119
|
-
function createMetrics(meter) {
|
|
120
|
-
const consentCreated = meter.createCounter('c15t.consent.created', {
|
|
121
|
-
description: 'Number of consent submissions',
|
|
122
|
-
unit: '1'
|
|
123
|
-
});
|
|
124
|
-
const consentAccepted = meter.createCounter('c15t.consent.accepted', {
|
|
125
|
-
description: 'Number of consents accepted',
|
|
126
|
-
unit: '1'
|
|
127
|
-
});
|
|
128
|
-
const consentRejected = meter.createCounter('c15t.consent.rejected', {
|
|
129
|
-
description: 'Number of consents rejected',
|
|
130
|
-
unit: '1'
|
|
131
|
-
});
|
|
132
|
-
const subjectCreated = meter.createCounter('c15t.subject.created', {
|
|
133
|
-
description: 'Number of new subjects created',
|
|
134
|
-
unit: '1'
|
|
135
|
-
});
|
|
136
|
-
const subjectLinked = meter.createCounter('c15t.subject.linked', {
|
|
137
|
-
description: 'Number of subjects linked to external ID',
|
|
138
|
-
unit: '1'
|
|
139
|
-
});
|
|
140
|
-
const consentCheckCount = meter.createCounter('c15t.consent_check.count', {
|
|
141
|
-
description: 'Number of cross-device consent checks',
|
|
142
|
-
unit: '1'
|
|
143
|
-
});
|
|
144
|
-
const initCount = meter.createCounter('c15t.init.count', {
|
|
145
|
-
description: 'Number of init endpoint calls',
|
|
146
|
-
unit: '1'
|
|
147
|
-
});
|
|
148
|
-
const httpRequestDuration = meter.createHistogram('c15t.http.request.duration', {
|
|
149
|
-
description: 'HTTP request latency',
|
|
150
|
-
unit: 'ms'
|
|
151
|
-
});
|
|
152
|
-
const httpRequestCount = meter.createCounter('c15t.http.request.count', {
|
|
153
|
-
description: 'Number of HTTP requests',
|
|
154
|
-
unit: '1'
|
|
155
|
-
});
|
|
156
|
-
const httpErrorCount = meter.createCounter('c15t.http.error.count', {
|
|
157
|
-
description: 'Number of HTTP errors',
|
|
158
|
-
unit: '1'
|
|
159
|
-
});
|
|
160
|
-
const dbQueryDuration = meter.createHistogram('c15t.db.query.duration', {
|
|
161
|
-
description: 'Database query latency',
|
|
162
|
-
unit: 'ms'
|
|
163
|
-
});
|
|
164
|
-
const dbQueryCount = meter.createCounter('c15t.db.query.count', {
|
|
165
|
-
description: 'Number of database queries',
|
|
166
|
-
unit: '1'
|
|
167
|
-
});
|
|
168
|
-
const dbErrorCount = meter.createCounter('c15t.db.error.count', {
|
|
169
|
-
description: 'Number of database errors',
|
|
170
|
-
unit: '1'
|
|
171
|
-
});
|
|
172
|
-
const cacheHit = meter.createCounter('c15t.cache.hit', {
|
|
173
|
-
description: 'Number of cache hits',
|
|
174
|
-
unit: '1'
|
|
175
|
-
});
|
|
176
|
-
const cacheMiss = meter.createCounter('c15t.cache.miss', {
|
|
177
|
-
description: 'Number of cache misses',
|
|
178
|
-
unit: '1'
|
|
179
|
-
});
|
|
180
|
-
const cacheLatency = meter.createHistogram('c15t.cache.latency', {
|
|
181
|
-
description: 'Cache operation latency',
|
|
182
|
-
unit: 'ms'
|
|
183
|
-
});
|
|
184
|
-
const gvlFetchDuration = meter.createHistogram('c15t.gvl.fetch.duration', {
|
|
185
|
-
description: 'GVL fetch latency',
|
|
186
|
-
unit: 'ms'
|
|
187
|
-
});
|
|
188
|
-
const gvlFetchCount = meter.createCounter('c15t.gvl.fetch.count', {
|
|
189
|
-
description: 'Number of GVL fetches',
|
|
190
|
-
unit: '1'
|
|
191
|
-
});
|
|
192
|
-
const gvlFetchError = meter.createCounter('c15t.gvl.fetch.error', {
|
|
193
|
-
description: 'Number of GVL fetch errors',
|
|
194
|
-
unit: '1'
|
|
195
|
-
});
|
|
196
|
-
return {
|
|
197
|
-
consentCreated,
|
|
198
|
-
consentAccepted,
|
|
199
|
-
consentRejected,
|
|
200
|
-
subjectCreated,
|
|
201
|
-
subjectLinked,
|
|
202
|
-
consentCheckCount,
|
|
203
|
-
initCount,
|
|
204
|
-
httpRequestDuration,
|
|
205
|
-
httpRequestCount,
|
|
206
|
-
httpErrorCount,
|
|
207
|
-
dbQueryDuration,
|
|
208
|
-
dbQueryCount,
|
|
209
|
-
dbErrorCount,
|
|
210
|
-
cacheHit,
|
|
211
|
-
cacheMiss,
|
|
212
|
-
cacheLatency,
|
|
213
|
-
gvlFetchDuration,
|
|
214
|
-
gvlFetchCount,
|
|
215
|
-
gvlFetchError,
|
|
216
|
-
recordConsentCreated (attributes) {
|
|
217
|
-
consentCreated.add(1, sanitizeAttributes(attributes));
|
|
218
|
-
},
|
|
219
|
-
recordConsentAccepted (attributes) {
|
|
220
|
-
consentAccepted.add(1, sanitizeAttributes(attributes));
|
|
221
|
-
},
|
|
222
|
-
recordConsentRejected (attributes) {
|
|
223
|
-
consentRejected.add(1, sanitizeAttributes(attributes));
|
|
224
|
-
},
|
|
225
|
-
recordSubjectCreated (attributes) {
|
|
226
|
-
subjectCreated.add(1, sanitizeAttributes(attributes));
|
|
227
|
-
},
|
|
228
|
-
recordSubjectLinked (identityProvider) {
|
|
229
|
-
subjectLinked.add(1, {
|
|
230
|
-
identityProvider: identityProvider || 'unknown'
|
|
231
|
-
});
|
|
232
|
-
},
|
|
233
|
-
recordConsentCheck (type, found) {
|
|
234
|
-
consentCheckCount.add(1, {
|
|
235
|
-
type,
|
|
236
|
-
found: String(found)
|
|
237
|
-
});
|
|
238
|
-
},
|
|
239
|
-
recordInit (attributes) {
|
|
240
|
-
initCount.add(1, sanitizeAttributes(attributes));
|
|
241
|
-
},
|
|
242
|
-
recordHttpRequest (attributes, durationMs) {
|
|
243
|
-
const attrs = sanitizeAttributes(attributes);
|
|
244
|
-
httpRequestCount.add(1, attrs);
|
|
245
|
-
httpRequestDuration.record(durationMs, attrs);
|
|
246
|
-
if (attributes.status >= 400) httpErrorCount.add(1, attrs);
|
|
247
|
-
},
|
|
248
|
-
recordDbQuery (attributes, durationMs) {
|
|
249
|
-
const attrs = sanitizeAttributes(attributes);
|
|
250
|
-
dbQueryCount.add(1, attrs);
|
|
251
|
-
dbQueryDuration.record(durationMs, attrs);
|
|
252
|
-
},
|
|
253
|
-
recordDbError (attributes) {
|
|
254
|
-
dbErrorCount.add(1, sanitizeAttributes(attributes));
|
|
255
|
-
},
|
|
256
|
-
recordCacheHit (layer) {
|
|
257
|
-
cacheHit.add(1, {
|
|
258
|
-
layer
|
|
259
|
-
});
|
|
260
|
-
},
|
|
261
|
-
recordCacheMiss (layer) {
|
|
262
|
-
cacheMiss.add(1, {
|
|
263
|
-
layer
|
|
264
|
-
});
|
|
265
|
-
},
|
|
266
|
-
recordCacheLatency (attributes, durationMs) {
|
|
267
|
-
cacheLatency.record(durationMs, sanitizeAttributes(attributes));
|
|
268
|
-
},
|
|
269
|
-
recordGvlFetch (attributes, durationMs) {
|
|
270
|
-
const attrs = sanitizeAttributes(attributes);
|
|
271
|
-
gvlFetchCount.add(1, attrs);
|
|
272
|
-
gvlFetchDuration.record(durationMs, attrs);
|
|
273
|
-
},
|
|
274
|
-
recordGvlError (attributes) {
|
|
275
|
-
gvlFetchError.add(1, sanitizeAttributes(attributes));
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
let metricsInstance = null;
|
|
280
|
-
function getMetrics(options) {
|
|
281
|
-
if (metricsInstance) return metricsInstance;
|
|
282
|
-
if (!create_telemetry_options_isTelemetryEnabled(options)) return null;
|
|
283
|
-
metricsInstance = createMetrics(getMeter(options));
|
|
284
|
-
return metricsInstance;
|
|
285
|
-
}
|
|
286
|
-
const GVL_TTL_MS = 259200000;
|
|
287
|
-
const memory_memoryCache = new Map();
|
|
288
|
-
function createMemoryCacheAdapter() {
|
|
289
|
-
return {
|
|
290
|
-
async get (key) {
|
|
291
|
-
const entry = memory_memoryCache.get(key);
|
|
292
|
-
if (!entry) return null;
|
|
293
|
-
if (Date.now() > entry.expiresAt) {
|
|
294
|
-
memory_memoryCache.delete(key);
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
return entry.value;
|
|
298
|
-
},
|
|
299
|
-
async set (key, value, ttlMs = 300000) {
|
|
300
|
-
memory_memoryCache.set(key, {
|
|
301
|
-
value,
|
|
302
|
-
expiresAt: Date.now() + ttlMs
|
|
303
|
-
});
|
|
304
|
-
},
|
|
305
|
-
async delete (key) {
|
|
306
|
-
memory_memoryCache.delete(key);
|
|
307
|
-
},
|
|
308
|
-
async has (key) {
|
|
309
|
-
const entry = memory_memoryCache.get(key);
|
|
310
|
-
if (!entry) return false;
|
|
311
|
-
if (Date.now() > entry.expiresAt) {
|
|
312
|
-
memory_memoryCache.delete(key);
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function createGVLCacheKey(appName, language, vendorIds) {
|
|
320
|
-
const sortedIds = vendorIds ? [
|
|
321
|
-
...vendorIds
|
|
322
|
-
].sort((a, b)=>a - b).join(',') : 'all';
|
|
323
|
-
return `${appName}:gvl:${language}:${sortedIds}`;
|
|
324
|
-
}
|
|
325
|
-
const GVL_ENDPOINT = 'https://gvl.consent.io';
|
|
326
|
-
const inflightRequests = new Map();
|
|
327
|
-
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
328
|
-
const sortedVendorIds = vendorIds ? [
|
|
329
|
-
...vendorIds
|
|
330
|
-
].sort((a, b)=>a - b) : [];
|
|
331
|
-
const dedupeKey = `${endpoint}|${language}|${sortedVendorIds.join(',')}`;
|
|
332
|
-
const existingRequest = inflightRequests.get(dedupeKey);
|
|
333
|
-
if (existingRequest) return existingRequest;
|
|
334
|
-
const url = new URL(endpoint);
|
|
335
|
-
if (sortedVendorIds.length > 0) url.searchParams.set('vendorIds', sortedVendorIds.join(','));
|
|
336
|
-
const promise = (async ()=>{
|
|
337
|
-
const fetchStart = Date.now();
|
|
338
|
-
try {
|
|
339
|
-
const gvl = await withExternalSpan({
|
|
340
|
-
url: url.toString(),
|
|
341
|
-
method: 'GET'
|
|
342
|
-
}, async ()=>{
|
|
343
|
-
const response = await fetch(url.toString(), {
|
|
344
|
-
headers: {
|
|
345
|
-
'Accept-Language': language
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
if (204 === response.status) return null;
|
|
349
|
-
if (!response.ok) throw new Error(`Failed to fetch GVL: ${response.status} ${response.statusText}`);
|
|
350
|
-
const text = await response.text();
|
|
351
|
-
const trimmed = text.trim().replace(/^\uFEFF/, '');
|
|
352
|
-
let parsed;
|
|
353
|
-
try {
|
|
354
|
-
parsed = JSON.parse(trimmed);
|
|
355
|
-
} catch {
|
|
356
|
-
let depth = 0;
|
|
357
|
-
let end = -1;
|
|
358
|
-
const start = trimmed.indexOf('{');
|
|
359
|
-
if (start >= 0) for(let i = start; i < trimmed.length; i++){
|
|
360
|
-
const c = trimmed[i];
|
|
361
|
-
if ('{' === c) depth++;
|
|
362
|
-
else if ('}' === c) {
|
|
363
|
-
depth--;
|
|
364
|
-
if (0 === depth) {
|
|
365
|
-
end = i + 1;
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
if (end > 0) parsed = JSON.parse(trimmed.slice(0, end));
|
|
371
|
-
else throw new SyntaxError('Invalid GVL response: not valid JSON');
|
|
372
|
-
}
|
|
373
|
-
if (!parsed.vendorListVersion || !parsed.purposes || !parsed.vendors) throw new Error('Invalid GVL response: missing required fields');
|
|
374
|
-
return parsed;
|
|
375
|
-
});
|
|
376
|
-
getMetrics()?.recordGvlFetch({
|
|
377
|
-
language,
|
|
378
|
-
source: 'fetch',
|
|
379
|
-
status: 200
|
|
380
|
-
}, Date.now() - fetchStart);
|
|
381
|
-
return gvl;
|
|
382
|
-
} catch (error) {
|
|
383
|
-
getMetrics()?.recordGvlError({
|
|
384
|
-
language,
|
|
385
|
-
errorType: error instanceof Error ? error.name : 'UnknownError'
|
|
386
|
-
});
|
|
387
|
-
throw error;
|
|
388
|
-
} finally{
|
|
389
|
-
inflightRequests.delete(dedupeKey);
|
|
390
|
-
}
|
|
391
|
-
})();
|
|
392
|
-
inflightRequests.set(dedupeKey, promise);
|
|
393
|
-
return promise;
|
|
394
|
-
}
|
|
395
|
-
function createGVLResolver(options) {
|
|
396
|
-
const { appName, bundled, cacheAdapter, vendorIds, endpoint } = options;
|
|
397
|
-
const memoryCache = createMemoryCacheAdapter();
|
|
398
|
-
return {
|
|
399
|
-
async get (language) {
|
|
400
|
-
const cacheKey = createGVLCacheKey(appName, language, vendorIds);
|
|
401
|
-
if (bundled?.[language]) return bundled[language];
|
|
402
|
-
const memoryHit = await withCacheSpan('get', 'memory', ()=>memoryCache.get(cacheKey));
|
|
403
|
-
if (memoryHit) {
|
|
404
|
-
getMetrics()?.recordCacheHit('memory');
|
|
405
|
-
return memoryHit;
|
|
406
|
-
}
|
|
407
|
-
getMetrics()?.recordCacheMiss('memory');
|
|
408
|
-
if (cacheAdapter) {
|
|
409
|
-
const externalHit = await withCacheSpan('get', 'external', ()=>cacheAdapter.get(cacheKey));
|
|
410
|
-
if (externalHit) {
|
|
411
|
-
getMetrics()?.recordCacheHit('external');
|
|
412
|
-
await withCacheSpan('set', 'memory', ()=>memoryCache.set(cacheKey, externalHit, 300000));
|
|
413
|
-
return externalHit;
|
|
414
|
-
}
|
|
415
|
-
getMetrics()?.recordCacheMiss('external');
|
|
416
|
-
}
|
|
417
|
-
const gvl = await fetchGVLWithLanguage(language, vendorIds, endpoint);
|
|
418
|
-
if (gvl) {
|
|
419
|
-
await withCacheSpan('set', 'memory', ()=>memoryCache.set(cacheKey, gvl, 300000));
|
|
420
|
-
if (cacheAdapter) await withCacheSpan('set', 'external', ()=>cacheAdapter.set(cacheKey, gvl, GVL_TTL_MS));
|
|
421
|
-
}
|
|
422
|
-
return gvl;
|
|
423
|
-
}
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
const POLICY_SNAPSHOT_JWT_HEADER = {
|
|
427
|
-
alg: 'HS256',
|
|
428
|
-
typ: 'JWT'
|
|
429
|
-
};
|
|
430
|
-
const DEFAULT_POLICY_SNAPSHOT_ISSUER = 'c15t';
|
|
431
|
-
const DEFAULT_POLICY_SNAPSHOT_AUDIENCE = 'c15t-policy-snapshot';
|
|
432
|
-
function resolveSnapshotIssuer(options) {
|
|
433
|
-
return options?.issuer?.trim() || DEFAULT_POLICY_SNAPSHOT_ISSUER;
|
|
434
|
-
}
|
|
435
|
-
function resolveSnapshotAudience(params) {
|
|
436
|
-
const configuredAudience = params.options?.audience?.trim();
|
|
437
|
-
if (configuredAudience) return configuredAudience;
|
|
438
|
-
return params.tenantId ? `${DEFAULT_POLICY_SNAPSHOT_AUDIENCE}:${params.tenantId}` : DEFAULT_POLICY_SNAPSHOT_AUDIENCE;
|
|
439
|
-
}
|
|
440
|
-
function getSigningKey(secret) {
|
|
441
|
-
return new TextEncoder().encode(secret);
|
|
442
|
-
}
|
|
443
|
-
async function createPolicySnapshotToken(params) {
|
|
444
|
-
const { options } = params;
|
|
445
|
-
if (!options?.signingKey) return;
|
|
446
|
-
const iat = Math.floor(Date.now() / 1000);
|
|
447
|
-
const ttlSeconds = options.ttlSeconds ?? 1800;
|
|
448
|
-
const exp = iat + ttlSeconds;
|
|
449
|
-
const iss = resolveSnapshotIssuer(options);
|
|
450
|
-
const aud = resolveSnapshotAudience({
|
|
451
|
-
options,
|
|
452
|
-
tenantId: params.tenantId
|
|
453
|
-
});
|
|
454
|
-
const payload = {
|
|
455
|
-
iss,
|
|
456
|
-
aud,
|
|
457
|
-
sub: params.policyId,
|
|
458
|
-
tenantId: params.tenantId,
|
|
459
|
-
policyId: params.policyId,
|
|
460
|
-
fingerprint: params.fingerprint,
|
|
461
|
-
matchedBy: params.matchedBy,
|
|
462
|
-
country: params.country,
|
|
463
|
-
region: params.region,
|
|
464
|
-
jurisdiction: params.jurisdiction,
|
|
465
|
-
language: params.language,
|
|
466
|
-
model: params.model,
|
|
467
|
-
policyI18n: params.policyI18n,
|
|
468
|
-
expiryDays: params.expiryDays,
|
|
469
|
-
scopeMode: params.scopeMode,
|
|
470
|
-
uiMode: params.uiMode,
|
|
471
|
-
bannerUi: params.bannerUi,
|
|
472
|
-
dialogUi: params.dialogUi,
|
|
473
|
-
categories: params.categories,
|
|
474
|
-
preselectedCategories: params.preselectedCategories,
|
|
475
|
-
gpc: params.gpc,
|
|
476
|
-
proofConfig: params.proofConfig,
|
|
477
|
-
iat,
|
|
478
|
-
exp
|
|
479
|
-
};
|
|
480
|
-
const token = await new SignJWT(payload).setProtectedHeader(POLICY_SNAPSHOT_JWT_HEADER).setIssuedAt(iat).setExpirationTime(exp).sign(getSigningKey(options.signingKey));
|
|
481
|
-
return {
|
|
482
|
-
token,
|
|
483
|
-
payload
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
function normalizeHeader(value) {
|
|
487
|
-
if (!value) return null;
|
|
488
|
-
return Array.isArray(value) ? value[0] ?? null : value;
|
|
489
|
-
}
|
|
490
|
-
function getGeoHeaders(headers) {
|
|
491
|
-
const countryCode = normalizeHeader(headers.get('x-c15t-country')) ?? normalizeHeader(headers.get('cf-ipcountry')) ?? normalizeHeader(headers.get('x-vercel-ip-country')) ?? normalizeHeader(headers.get('x-amz-cf-ipcountry')) ?? normalizeHeader(headers.get('x-country-code'));
|
|
492
|
-
const regionCode = normalizeHeader(headers.get('x-c15t-region')) ?? normalizeHeader(headers.get('x-vercel-ip-country-region')) ?? normalizeHeader(headers.get('x-region-code'));
|
|
493
|
-
return {
|
|
494
|
-
countryCode,
|
|
495
|
-
regionCode
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
function checkJurisdiction(countryCode, regionCode) {
|
|
499
|
-
const jurisdictions = {
|
|
500
|
-
EU: new Set([
|
|
501
|
-
'AT',
|
|
502
|
-
'BE',
|
|
503
|
-
'BG',
|
|
504
|
-
'HR',
|
|
505
|
-
'CY',
|
|
506
|
-
'CZ',
|
|
507
|
-
'DK',
|
|
508
|
-
'EE',
|
|
509
|
-
'FI',
|
|
510
|
-
'FR',
|
|
511
|
-
'DE',
|
|
512
|
-
'GR',
|
|
513
|
-
'HU',
|
|
514
|
-
'IE',
|
|
515
|
-
'IT',
|
|
516
|
-
'LV',
|
|
517
|
-
'LT',
|
|
518
|
-
'LU',
|
|
519
|
-
'MT',
|
|
520
|
-
'NL',
|
|
521
|
-
'PL',
|
|
522
|
-
'PT',
|
|
523
|
-
'RO',
|
|
524
|
-
'SK',
|
|
525
|
-
'SI',
|
|
526
|
-
'ES',
|
|
527
|
-
'SE'
|
|
528
|
-
]),
|
|
529
|
-
EEA: new Set([
|
|
530
|
-
'IS',
|
|
531
|
-
'NO',
|
|
532
|
-
'LI'
|
|
533
|
-
]),
|
|
534
|
-
UK: new Set([
|
|
535
|
-
'GB'
|
|
536
|
-
]),
|
|
537
|
-
CH: new Set([
|
|
538
|
-
'CH'
|
|
539
|
-
]),
|
|
540
|
-
BR: new Set([
|
|
541
|
-
'BR'
|
|
542
|
-
]),
|
|
543
|
-
CA: new Set([
|
|
544
|
-
'CA'
|
|
545
|
-
]),
|
|
546
|
-
AU: new Set([
|
|
547
|
-
'AU'
|
|
548
|
-
]),
|
|
549
|
-
JP: new Set([
|
|
550
|
-
'JP'
|
|
551
|
-
]),
|
|
552
|
-
KR: new Set([
|
|
553
|
-
'KR'
|
|
554
|
-
]),
|
|
555
|
-
US_CCPA_REGIONS: new Set([
|
|
556
|
-
'CA'
|
|
557
|
-
]),
|
|
558
|
-
CA_QC_REGIONS: new Set([
|
|
559
|
-
'QC'
|
|
560
|
-
])
|
|
561
|
-
};
|
|
562
|
-
let jurisdiction = 'NONE';
|
|
563
|
-
if (countryCode) {
|
|
564
|
-
const normalizedCountryCode = countryCode.toUpperCase();
|
|
565
|
-
const normalizedRegionCode = regionCode && 'string' == typeof regionCode ? (regionCode.includes('-') ? regionCode.split('-').pop() : regionCode).toUpperCase() : null;
|
|
566
|
-
if ('US' === normalizedCountryCode && normalizedRegionCode && jurisdictions.US_CCPA_REGIONS.has(normalizedRegionCode)) return 'CCPA';
|
|
567
|
-
if ('CA' === normalizedCountryCode && normalizedRegionCode && jurisdictions.CA_QC_REGIONS.has(normalizedRegionCode)) return 'QC_LAW25';
|
|
568
|
-
const jurisdictionMap = [
|
|
569
|
-
{
|
|
570
|
-
sets: [
|
|
571
|
-
jurisdictions.UK
|
|
572
|
-
],
|
|
573
|
-
code: 'UK_GDPR'
|
|
574
|
-
},
|
|
575
|
-
{
|
|
576
|
-
sets: [
|
|
577
|
-
jurisdictions.EU,
|
|
578
|
-
jurisdictions.EEA
|
|
579
|
-
],
|
|
580
|
-
code: 'GDPR'
|
|
581
|
-
},
|
|
582
|
-
{
|
|
583
|
-
sets: [
|
|
584
|
-
jurisdictions.CH
|
|
585
|
-
],
|
|
586
|
-
code: 'CH'
|
|
587
|
-
},
|
|
588
|
-
{
|
|
589
|
-
sets: [
|
|
590
|
-
jurisdictions.BR
|
|
591
|
-
],
|
|
592
|
-
code: 'BR'
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
sets: [
|
|
596
|
-
jurisdictions.CA
|
|
597
|
-
],
|
|
598
|
-
code: 'PIPEDA'
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
sets: [
|
|
602
|
-
jurisdictions.AU
|
|
603
|
-
],
|
|
604
|
-
code: 'AU'
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
sets: [
|
|
608
|
-
jurisdictions.JP
|
|
609
|
-
],
|
|
610
|
-
code: 'APPI'
|
|
611
|
-
},
|
|
612
|
-
{
|
|
613
|
-
sets: [
|
|
614
|
-
jurisdictions.KR
|
|
615
|
-
],
|
|
616
|
-
code: 'PIPA'
|
|
617
|
-
}
|
|
618
|
-
];
|
|
619
|
-
for (const { sets, code } of jurisdictionMap)if (sets.some((set)=>set.has(normalizedCountryCode))) {
|
|
620
|
-
jurisdiction = code;
|
|
621
|
-
break;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
return jurisdiction;
|
|
625
|
-
}
|
|
626
|
-
async function getLocation(request, options) {
|
|
627
|
-
if (options.disableGeoLocation) return {
|
|
628
|
-
countryCode: null,
|
|
629
|
-
regionCode: null
|
|
630
|
-
};
|
|
631
|
-
const { countryCode, regionCode } = getGeoHeaders(request.headers);
|
|
632
|
-
return {
|
|
633
|
-
countryCode,
|
|
634
|
-
regionCode
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
function getJurisdiction(location, options) {
|
|
638
|
-
if (options.disableGeoLocation) return 'GDPR';
|
|
639
|
-
return checkJurisdiction(location.countryCode, location.regionCode);
|
|
640
|
-
}
|
|
641
|
-
const DEFAULT_PROFILE = 'default';
|
|
642
|
-
const warnedKeys = new Set();
|
|
643
|
-
function isSupportedBaseLanguage(lang) {
|
|
644
|
-
return lang in baseTranslations;
|
|
645
|
-
}
|
|
646
|
-
function warnOnce(logger, key, message, metadata) {
|
|
647
|
-
if (!logger || warnedKeys.has(key)) return;
|
|
648
|
-
warnedKeys.add(key);
|
|
649
|
-
logger.warn(message, metadata);
|
|
650
|
-
}
|
|
651
|
-
function normalizeLanguage(value) {
|
|
652
|
-
if (!value) return;
|
|
653
|
-
const normalized = value.split(',')[0]?.split(';')[0]?.trim().toLowerCase();
|
|
654
|
-
if (!normalized) return;
|
|
655
|
-
return normalized.split('-')[0] ?? void 0;
|
|
656
|
-
}
|
|
657
|
-
function normalizeProfiles(params) {
|
|
658
|
-
const profiles = params.i18n?.messages;
|
|
659
|
-
const legacy = params.customTranslations;
|
|
660
|
-
if (profiles && Object.keys(profiles).length > 0) {
|
|
661
|
-
if (legacy && Object.keys(legacy).length > 0) warnOnce(params.logger, 'i18n.customTranslations.ignored', '`customTranslations` is deprecated and ignored when `i18n.messages` is configured.');
|
|
662
|
-
return profiles;
|
|
663
|
-
}
|
|
664
|
-
if (legacy && Object.keys(legacy).length > 0) {
|
|
665
|
-
warnOnce(params.logger, 'i18n.customTranslations.deprecated', '`customTranslations` is deprecated. Use `i18n.messages` instead.');
|
|
666
|
-
return {
|
|
667
|
-
[DEFAULT_PROFILE]: {
|
|
668
|
-
translations: legacy
|
|
669
|
-
}
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
return {};
|
|
673
|
-
}
|
|
674
|
-
function buildCandidates(input) {
|
|
675
|
-
const raw = [
|
|
676
|
-
{
|
|
677
|
-
language: input.language,
|
|
678
|
-
reason: 'profile_language'
|
|
679
|
-
},
|
|
680
|
-
{
|
|
681
|
-
language: input.fallbackLanguage,
|
|
682
|
-
reason: 'profile_fallback'
|
|
683
|
-
}
|
|
684
|
-
];
|
|
685
|
-
const dedupe = new Set();
|
|
686
|
-
return raw.filter((candidate)=>{
|
|
687
|
-
const key = candidate.language;
|
|
688
|
-
if (dedupe.has(key)) return false;
|
|
689
|
-
dedupe.add(key);
|
|
690
|
-
return true;
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
function getProfileLanguages(profiles, profile) {
|
|
694
|
-
return Object.keys(profiles[profile]?.translations ?? {}).sort();
|
|
695
|
-
}
|
|
696
|
-
function getSelectableLanguages(input) {
|
|
697
|
-
return getProfileLanguages(input.profiles, input.profile);
|
|
698
|
-
}
|
|
699
|
-
function resolveFallbackLanguage(input) {
|
|
700
|
-
const configuredFallbackLanguage = normalizeLanguage(input.profile?.fallbackLanguage) ?? 'en';
|
|
701
|
-
const profileLanguages = Object.keys(input.profile?.translations ?? {}).sort();
|
|
702
|
-
if (profileLanguages.includes(configuredFallbackLanguage)) return configuredFallbackLanguage;
|
|
703
|
-
if (profileLanguages.includes('en')) return 'en';
|
|
704
|
-
return profileLanguages[0] ?? configuredFallbackLanguage;
|
|
705
|
-
}
|
|
706
|
-
function resolveActiveProfile(input) {
|
|
707
|
-
const requestedProfile = input.policyProfile ?? input.defaultProfile;
|
|
708
|
-
if (input.profiles[requestedProfile]) return requestedProfile;
|
|
709
|
-
if (input.policyProfile) warnOnce(input.logger, `i18n.profile.missing:${requestedProfile}`, `Policy i18n profile '${requestedProfile}' does not exist. Falling back to default profile '${input.defaultProfile}'.`);
|
|
710
|
-
return input.defaultProfile;
|
|
711
|
-
}
|
|
712
|
-
function validateMessages(options) {
|
|
713
|
-
return validatePolicyI18nConfig({
|
|
714
|
-
customTranslations: options.customTranslations,
|
|
715
|
-
i18n: options.i18n,
|
|
716
|
-
policies: options.policies
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
function getTranslationsData(acceptLanguage, customTranslations, options) {
|
|
720
|
-
const profiles = normalizeProfiles({
|
|
721
|
-
customTranslations,
|
|
722
|
-
i18n: options?.i18n,
|
|
723
|
-
logger: options?.logger
|
|
724
|
-
});
|
|
725
|
-
const defaultProfile = options?.i18n?.defaultProfile ?? DEFAULT_PROFILE;
|
|
726
|
-
const profile = resolveActiveProfile({
|
|
727
|
-
profiles,
|
|
728
|
-
defaultProfile,
|
|
729
|
-
policyProfile: options?.policyI18n?.messageProfile,
|
|
730
|
-
logger: options?.logger
|
|
731
|
-
});
|
|
732
|
-
const configuredLanguages = Object.keys(profiles).length > 0 ? getSelectableLanguages({
|
|
733
|
-
profiles,
|
|
734
|
-
profile
|
|
735
|
-
}) : Object.keys(baseTranslations);
|
|
736
|
-
const fallbackLanguage = Object.keys(profiles).length > 0 ? resolveFallbackLanguage({
|
|
737
|
-
profile: profiles[profile]
|
|
738
|
-
}) : 'en';
|
|
739
|
-
const policyLanguage = normalizeLanguage(options?.policyI18n?.language);
|
|
740
|
-
const requestedLanguage = policyLanguage ?? selectLanguage(configuredLanguages, {
|
|
741
|
-
header: acceptLanguage,
|
|
742
|
-
fallback: fallbackLanguage
|
|
743
|
-
});
|
|
744
|
-
const candidates = buildCandidates({
|
|
745
|
-
language: requestedLanguage,
|
|
746
|
-
fallbackLanguage
|
|
747
|
-
});
|
|
748
|
-
const selectedCandidate = candidates.find((candidate)=>!!profiles[profile]?.translations[candidate.language]);
|
|
749
|
-
if (selectedCandidate && 'profile_language' !== selectedCandidate.reason) warnOnce(options?.logger, `i18n.fallback:${profile}:${requestedLanguage}:${selectedCandidate.language}`, `Policy translation fallback used (${selectedCandidate.reason}).`, {
|
|
750
|
-
requestedProfile: profile,
|
|
751
|
-
requestedLanguage,
|
|
752
|
-
resolvedProfile: profile,
|
|
753
|
-
resolvedLanguage: selectedCandidate.language
|
|
754
|
-
});
|
|
755
|
-
let language = selectedCandidate?.language ?? requestedLanguage;
|
|
756
|
-
if (!selectedCandidate && !isSupportedBaseLanguage(language)) {
|
|
757
|
-
warnOnce(options?.logger, `i18n.base-fallback:${language}`, `No translation found for '${language}'. Falling back to base English translations.`);
|
|
758
|
-
language = 'en';
|
|
759
|
-
}
|
|
760
|
-
const base = isSupportedBaseLanguage(language) ? baseTranslations[language] : baseTranslations.en;
|
|
761
|
-
const custom = selectedCandidate ? profiles[profile]?.translations[selectedCandidate.language] : void 0;
|
|
762
|
-
const translations = custom ? deepMergeTranslations(base, custom) : base;
|
|
763
|
-
return {
|
|
764
|
-
translations: translations,
|
|
765
|
-
language
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
function stripIabTranslations(translations) {
|
|
769
|
-
const { iab: _iab, ...rest } = translations;
|
|
770
|
-
return rest;
|
|
771
|
-
}
|
|
772
|
-
function resolveNoPolicyFallback() {
|
|
773
|
-
return {
|
|
774
|
-
id: 'no_banner',
|
|
775
|
-
model: 'none',
|
|
776
|
-
ui: {
|
|
777
|
-
mode: 'none'
|
|
778
|
-
}
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
async function resolveInitPayload(request, options, logger) {
|
|
782
|
-
const acceptLanguage = request.headers.get('accept-language') || 'en';
|
|
783
|
-
const location = await getLocation(request, options);
|
|
784
|
-
const jurisdiction = getJurisdiction(location, options);
|
|
785
|
-
const hasExplicitPolicyPack = void 0 !== options.policyPacks;
|
|
786
|
-
const isExplicitEmptyPolicyPack = hasExplicitPolicyPack && (options.policyPacks?.length ?? 0) === 0;
|
|
787
|
-
const policyDecision = isExplicitEmptyPolicyPack ? void 0 : await policy_resolvePolicyDecision({
|
|
788
|
-
policies: options.policyPacks,
|
|
789
|
-
countryCode: location.countryCode,
|
|
790
|
-
regionCode: location.regionCode,
|
|
791
|
-
jurisdiction,
|
|
792
|
-
iabEnabled: options.iab?.enabled === true
|
|
793
|
-
});
|
|
794
|
-
if (hasExplicitPolicyPack && !isExplicitEmptyPolicyPack && !policyDecision) logger?.warn('Policy packs configured but no policy matched', {
|
|
795
|
-
country: location.countryCode,
|
|
796
|
-
region: location.regionCode
|
|
797
|
-
});
|
|
798
|
-
const resolvedPolicy = hasExplicitPolicyPack ? policyDecision?.policy ?? resolveNoPolicyFallback() : void 0;
|
|
799
|
-
const iabOptions = options.iab;
|
|
800
|
-
const shouldIncludeIabPayload = iabOptions?.enabled === true && (!hasExplicitPolicyPack || resolvedPolicy?.model === 'iab');
|
|
801
|
-
const translationsResult = getTranslationsData(acceptLanguage, options.customTranslations, {
|
|
802
|
-
i18n: options.i18n,
|
|
803
|
-
policyI18n: resolvedPolicy?.i18n,
|
|
804
|
-
logger
|
|
805
|
-
});
|
|
806
|
-
const responseTranslations = shouldIncludeIabPayload ? translationsResult : {
|
|
807
|
-
...translationsResult,
|
|
808
|
-
translations: stripIabTranslations(translationsResult.translations)
|
|
809
|
-
};
|
|
810
|
-
let gvl = null;
|
|
811
|
-
if (shouldIncludeIabPayload && iabOptions) {
|
|
812
|
-
const language = translationsResult.language.split('-')[0] || 'en';
|
|
813
|
-
const gvlResolver = createGVLResolver({
|
|
814
|
-
appName: options.appName || 'c15t',
|
|
815
|
-
bundled: iabOptions.bundled,
|
|
816
|
-
cacheAdapter: options.cache?.adapter,
|
|
817
|
-
vendorIds: iabOptions.vendorIds,
|
|
818
|
-
endpoint: iabOptions.endpoint
|
|
819
|
-
});
|
|
820
|
-
gvl = await gvlResolver.get(language);
|
|
821
|
-
}
|
|
822
|
-
const customVendors = shouldIncludeIabPayload ? iabOptions?.customVendors : void 0;
|
|
823
|
-
const snapshot = policyDecision ? await createPolicySnapshotToken({
|
|
824
|
-
options: options.policySnapshot,
|
|
825
|
-
tenantId: options.tenantId,
|
|
826
|
-
policyId: policyDecision.policy.id,
|
|
827
|
-
fingerprint: policyDecision.fingerprint,
|
|
828
|
-
matchedBy: policyDecision.matchedBy,
|
|
829
|
-
country: location?.countryCode ?? null,
|
|
830
|
-
region: location?.regionCode ?? null,
|
|
831
|
-
jurisdiction,
|
|
832
|
-
language: translationsResult.language,
|
|
833
|
-
model: policyDecision.policy.model,
|
|
834
|
-
policyI18n: policyDecision.policy.i18n,
|
|
835
|
-
expiryDays: policyDecision.policy.consent?.expiryDays,
|
|
836
|
-
scopeMode: policyDecision.policy.consent?.scopeMode,
|
|
837
|
-
uiMode: policyDecision.policy.ui?.mode,
|
|
838
|
-
bannerUi: policyDecision.policy.ui?.banner,
|
|
839
|
-
dialogUi: policyDecision.policy.ui?.dialog,
|
|
840
|
-
categories: policyDecision.policy.consent?.categories,
|
|
841
|
-
preselectedCategories: policyDecision.policy.consent?.preselectedCategories,
|
|
842
|
-
gpc: policyDecision.policy.consent?.gpc,
|
|
843
|
-
proofConfig: policyDecision.policy.proof
|
|
844
|
-
}) : void 0;
|
|
845
|
-
const gpc = '1' === request.headers.get('sec-gpc');
|
|
846
|
-
getMetrics()?.recordInit({
|
|
847
|
-
jurisdiction,
|
|
848
|
-
country: location?.countryCode ?? void 0,
|
|
849
|
-
region: location?.regionCode ?? void 0,
|
|
850
|
-
gpc
|
|
851
|
-
});
|
|
852
|
-
return {
|
|
853
|
-
jurisdiction,
|
|
854
|
-
location,
|
|
855
|
-
translations: responseTranslations,
|
|
856
|
-
branding: options.branding || 'c15t',
|
|
857
|
-
...shouldIncludeIabPayload && {
|
|
858
|
-
gvl,
|
|
859
|
-
customVendors
|
|
860
|
-
},
|
|
861
|
-
...resolvedPolicy && {
|
|
862
|
-
policy: resolvedPolicy
|
|
863
|
-
},
|
|
864
|
-
...policyDecision && {
|
|
865
|
-
policyDecision: {
|
|
866
|
-
policyId: policyDecision.policy.id,
|
|
867
|
-
fingerprint: policyDecision.fingerprint,
|
|
868
|
-
matchedBy: policyDecision.matchedBy,
|
|
869
|
-
country: location.countryCode,
|
|
870
|
-
region: location.regionCode,
|
|
871
|
-
jurisdiction
|
|
872
|
-
}
|
|
873
|
-
},
|
|
874
|
-
...snapshot?.token && {
|
|
875
|
-
policySnapshotToken: snapshot.token
|
|
876
|
-
},
|
|
877
|
-
...shouldIncludeIabPayload && iabOptions?.cmpId != null && {
|
|
878
|
-
cmpId: iabOptions.cmpId
|
|
879
|
-
}
|
|
880
|
-
};
|
|
881
|
-
}
|
|
2
|
+
import { inspectPolicies as policy_inspectPolicies, policy_resolvePolicySync, resolveInitPayload, validateMessages, checkJurisdiction } from "./583.js";
|
|
882
3
|
const STRIP_REGEX = /^(?:https?:\/\/)|^(?:wss?:\/\/)|(?:\/+$)|(?::\d+$)/g;
|
|
883
4
|
function matchesWildcard(hostname, wildcardPattern, logger) {
|
|
884
5
|
const wildcardDomain = wildcardPattern.slice(2);
|
|
@@ -990,7 +111,7 @@ function getLocationFromHeaders(headers) {
|
|
|
990
111
|
regionCode
|
|
991
112
|
};
|
|
992
113
|
}
|
|
993
|
-
function
|
|
114
|
+
function resolveNoPolicyFallback() {
|
|
994
115
|
return {
|
|
995
116
|
id: 'no_banner',
|
|
996
117
|
model: 'none',
|
|
@@ -1052,7 +173,7 @@ function resolveConsent(request, options, logger) {
|
|
|
1052
173
|
country: location.countryCode,
|
|
1053
174
|
region: location.regionCode
|
|
1054
175
|
});
|
|
1055
|
-
const resolvedPolicy = hasExplicitPolicyPack ? policyMatch?.policy ??
|
|
176
|
+
const resolvedPolicy = hasExplicitPolicyPack ? policyMatch?.policy ?? resolveNoPolicyFallback() : resolveNoPolicyFallback();
|
|
1056
177
|
const model = resolvedPolicy.model;
|
|
1057
178
|
const showBanner = 'none' !== model && resolvedPolicy.ui?.mode !== 'none';
|
|
1058
179
|
const defaults = resolveDefaultConsent(resolvedPolicy, gpc);
|