@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.
Files changed (47) hide show
  1. package/dist/302.js +473 -0
  2. package/dist/364.js +1140 -0
  3. package/dist/583.js +540 -0
  4. package/dist/cache.cjs +1 -1
  5. package/dist/cache.js +4 -415
  6. package/dist/core.cjs +21 -24
  7. package/dist/core.js +18 -2420
  8. package/dist/db/adapters/drizzle.cjs +1 -1
  9. package/dist/db/adapters/drizzle.js +1 -2
  10. package/dist/db/adapters/kysely.cjs +1 -1
  11. package/dist/db/adapters/kysely.js +1 -2
  12. package/dist/db/adapters/mongo.cjs +1 -1
  13. package/dist/db/adapters/mongo.js +1 -2
  14. package/dist/db/adapters/prisma.cjs +1 -1
  15. package/dist/db/adapters/prisma.js +1 -2
  16. package/dist/db/adapters/typeorm.cjs +1 -1
  17. package/dist/db/adapters/typeorm.js +1 -2
  18. package/dist/db/adapters.cjs +1 -1
  19. package/dist/db/migrator.cjs +1 -1
  20. package/dist/db/schema.cjs +1 -1
  21. package/dist/db/schema.js +1 -1
  22. package/dist/define-config.cjs +1 -1
  23. package/dist/edge.cjs +1 -1
  24. package/dist/edge.js +3 -882
  25. package/dist/router.cjs +17 -18
  26. package/dist/router.js +1 -2058
  27. package/dist/types/index.cjs +1 -1
  28. package/dist-types/cache/gvl-resolver.d.ts +1 -1
  29. package/dist-types/db/registry/runtime-policy-decision.d.ts +1 -1
  30. package/dist-types/db/schema/1.0.0/consent.d.ts +1 -1
  31. package/dist-types/db/schema/2.0.0/audit-log.d.ts +1 -1
  32. package/dist-types/db/schema/2.0.0/consent-policy.d.ts +1 -1
  33. package/dist-types/db/schema/2.0.0/consent-purpose.d.ts +1 -1
  34. package/dist-types/db/schema/2.0.0/consent.d.ts +1 -1
  35. package/dist-types/db/schema/2.0.0/domain.d.ts +1 -1
  36. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +1 -1
  37. package/dist-types/db/schema/2.0.0/subject.d.ts +1 -1
  38. package/dist-types/handlers/init/index.d.ts +1 -1
  39. package/dist-types/handlers/init/policy.d.ts +1 -1
  40. package/dist-types/handlers/init/resolve-init.d.ts +1 -1
  41. package/dist-types/handlers/policy/snapshot.d.ts +1 -1
  42. package/dist-types/policies/defaults.d.ts +1 -1
  43. package/dist-types/policies/matchers.d.ts +2 -2
  44. package/dist-types/types/index.d.ts +2 -2
  45. package/dist-types/version.d.ts +1 -1
  46. package/docs/guides/policy-packs.md +1 -1
  47. package/package.json +15 -15
package/dist/cache.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Redis } from "@upstash/redis";
2
- import { SpanKind as api_SpanKind, SpanStatusCode as api_SpanStatusCode, context, metrics, trace as api_trace } from "@opentelemetry/api";
3
- const GVL_TTL_MS = 259200000;
2
+ import { GVL_TTL_MS } from "./302.js";
4
3
  function createCloudflareKVAdapter(kv) {
5
4
  return {
6
5
  async get (key) {
@@ -24,44 +23,6 @@ function createCloudflareKVAdapter(kv) {
24
23
  }
25
24
  };
26
25
  }
27
- const memory_memoryCache = new Map();
28
- function createMemoryCacheAdapter() {
29
- return {
30
- async get (key) {
31
- const entry = memory_memoryCache.get(key);
32
- if (!entry) return null;
33
- if (Date.now() > entry.expiresAt) {
34
- memory_memoryCache.delete(key);
35
- return null;
36
- }
37
- return entry.value;
38
- },
39
- async set (key, value, ttlMs = 300000) {
40
- memory_memoryCache.set(key, {
41
- value,
42
- expiresAt: Date.now() + ttlMs
43
- });
44
- },
45
- async delete (key) {
46
- memory_memoryCache.delete(key);
47
- },
48
- async has (key) {
49
- const entry = memory_memoryCache.get(key);
50
- if (!entry) return false;
51
- if (Date.now() > entry.expiresAt) {
52
- memory_memoryCache.delete(key);
53
- return false;
54
- }
55
- return true;
56
- }
57
- };
58
- }
59
- function clearMemoryCache() {
60
- memory_memoryCache.clear();
61
- }
62
- function getMemoryCacheSize() {
63
- return memory_memoryCache.size;
64
- }
65
26
  function createUpstashRedisAdapter(options) {
66
27
  const client = new Redis({
67
28
  url: options.url,
@@ -90,378 +51,6 @@ function createUpstashRedisAdapterFromClient(client) {
90
51
  }
91
52
  };
92
53
  }
93
- function extractErrorMessage(error) {
94
- if (error instanceof AggregateError && error.errors?.length > 0) {
95
- const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
96
- return `AggregateError: ${inner}`;
97
- }
98
- if (error instanceof Error) return error.message || error.name;
99
- return String(error);
100
- }
101
- let cachedConfig = null;
102
- let cachedDefaultAttributes = {};
103
- function create_telemetry_options_isTelemetryEnabled(options) {
104
- if (options) return options.telemetry?.enabled === true;
105
- return cachedConfig?.enabled === true;
106
- }
107
- const create_telemetry_options_getTracer = (options)=>{
108
- if (!create_telemetry_options_isTelemetryEnabled(options)) return api_trace.getTracer('c15t-noop');
109
- const tracer = options?.telemetry?.tracer ?? cachedConfig?.tracer;
110
- if (tracer) return tracer;
111
- return api_trace.getTracer(options?.appName ?? 'c15t');
112
- };
113
- const getMeter = (options)=>{
114
- if (!create_telemetry_options_isTelemetryEnabled(options)) return metrics.getMeter('c15t-noop');
115
- const meter = options?.telemetry?.meter ?? cachedConfig?.meter;
116
- if (meter) return meter;
117
- return metrics.getMeter(options?.appName ?? 'c15t');
118
- };
119
- function getDefaultAttributes() {
120
- return cachedDefaultAttributes;
121
- }
122
- const handleSpanError = (span, error)=>{
123
- span.setStatus({
124
- code: api_SpanStatusCode.ERROR,
125
- message: extractErrorMessage(error)
126
- });
127
- if (error instanceof Error) span.setAttribute('error.type', error.name);
128
- };
129
- const withSpanContext = async (span, operation)=>context["with"](api_trace.setSpan(context.active(), span), operation);
130
- async function executeWithSpan(span, operation) {
131
- try {
132
- const result = await withSpanContext(span, operation);
133
- span.setStatus({
134
- code: api_SpanStatusCode.OK
135
- });
136
- return result;
137
- } catch (error) {
138
- handleSpanError(span, error);
139
- throw error;
140
- } finally{
141
- span.end();
142
- }
143
- }
144
- function resolveDefaultAttributes(options) {
145
- return options?.telemetry?.defaultAttributes || getDefaultAttributes();
146
- }
147
- async function withExternalSpan(attributes, operation, options) {
148
- if (!create_telemetry_options_isTelemetryEnabled(options)) return operation();
149
- const tracer = create_telemetry_options_getTracer(options);
150
- const url = new URL(attributes.url);
151
- const spanName = `HTTP ${attributes.method} ${url.hostname}`;
152
- const span = tracer.startSpan(spanName, {
153
- kind: api_SpanKind.CLIENT,
154
- attributes: {
155
- 'http.method': attributes.method,
156
- 'http.url': `${url.origin}${url.pathname}`,
157
- 'http.host': url.hostname,
158
- ...resolveDefaultAttributes(options),
159
- ...Object.fromEntries(Object.entries(attributes).filter(([key])=>![
160
- 'url',
161
- 'method'
162
- ].includes(key)))
163
- }
164
- });
165
- return executeWithSpan(span, operation);
166
- }
167
- async function withCacheSpan(operation, layer, fn, options) {
168
- if (!create_telemetry_options_isTelemetryEnabled(options)) return fn();
169
- const tracer = create_telemetry_options_getTracer(options);
170
- const spanName = `cache.${layer}.${operation}`;
171
- const span = tracer.startSpan(spanName, {
172
- kind: api_SpanKind.CLIENT,
173
- attributes: {
174
- 'cache.operation': operation,
175
- 'cache.layer': layer,
176
- ...resolveDefaultAttributes(options)
177
- }
178
- });
179
- return executeWithSpan(span, fn);
180
- }
181
- function sanitizeAttributes(attrs) {
182
- return Object.fromEntries(Object.entries(attrs).filter(([_, v])=>null != v));
183
- }
184
- function createMetrics(meter) {
185
- const consentCreated = meter.createCounter('c15t.consent.created', {
186
- description: 'Number of consent submissions',
187
- unit: '1'
188
- });
189
- const consentAccepted = meter.createCounter('c15t.consent.accepted', {
190
- description: 'Number of consents accepted',
191
- unit: '1'
192
- });
193
- const consentRejected = meter.createCounter('c15t.consent.rejected', {
194
- description: 'Number of consents rejected',
195
- unit: '1'
196
- });
197
- const subjectCreated = meter.createCounter('c15t.subject.created', {
198
- description: 'Number of new subjects created',
199
- unit: '1'
200
- });
201
- const subjectLinked = meter.createCounter('c15t.subject.linked', {
202
- description: 'Number of subjects linked to external ID',
203
- unit: '1'
204
- });
205
- const consentCheckCount = meter.createCounter('c15t.consent_check.count', {
206
- description: 'Number of cross-device consent checks',
207
- unit: '1'
208
- });
209
- const initCount = meter.createCounter('c15t.init.count', {
210
- description: 'Number of init endpoint calls',
211
- unit: '1'
212
- });
213
- const httpRequestDuration = meter.createHistogram('c15t.http.request.duration', {
214
- description: 'HTTP request latency',
215
- unit: 'ms'
216
- });
217
- const httpRequestCount = meter.createCounter('c15t.http.request.count', {
218
- description: 'Number of HTTP requests',
219
- unit: '1'
220
- });
221
- const httpErrorCount = meter.createCounter('c15t.http.error.count', {
222
- description: 'Number of HTTP errors',
223
- unit: '1'
224
- });
225
- const dbQueryDuration = meter.createHistogram('c15t.db.query.duration', {
226
- description: 'Database query latency',
227
- unit: 'ms'
228
- });
229
- const dbQueryCount = meter.createCounter('c15t.db.query.count', {
230
- description: 'Number of database queries',
231
- unit: '1'
232
- });
233
- const dbErrorCount = meter.createCounter('c15t.db.error.count', {
234
- description: 'Number of database errors',
235
- unit: '1'
236
- });
237
- const cacheHit = meter.createCounter('c15t.cache.hit', {
238
- description: 'Number of cache hits',
239
- unit: '1'
240
- });
241
- const cacheMiss = meter.createCounter('c15t.cache.miss', {
242
- description: 'Number of cache misses',
243
- unit: '1'
244
- });
245
- const cacheLatency = meter.createHistogram('c15t.cache.latency', {
246
- description: 'Cache operation latency',
247
- unit: 'ms'
248
- });
249
- const gvlFetchDuration = meter.createHistogram('c15t.gvl.fetch.duration', {
250
- description: 'GVL fetch latency',
251
- unit: 'ms'
252
- });
253
- const gvlFetchCount = meter.createCounter('c15t.gvl.fetch.count', {
254
- description: 'Number of GVL fetches',
255
- unit: '1'
256
- });
257
- const gvlFetchError = meter.createCounter('c15t.gvl.fetch.error', {
258
- description: 'Number of GVL fetch errors',
259
- unit: '1'
260
- });
261
- return {
262
- consentCreated,
263
- consentAccepted,
264
- consentRejected,
265
- subjectCreated,
266
- subjectLinked,
267
- consentCheckCount,
268
- initCount,
269
- httpRequestDuration,
270
- httpRequestCount,
271
- httpErrorCount,
272
- dbQueryDuration,
273
- dbQueryCount,
274
- dbErrorCount,
275
- cacheHit,
276
- cacheMiss,
277
- cacheLatency,
278
- gvlFetchDuration,
279
- gvlFetchCount,
280
- gvlFetchError,
281
- recordConsentCreated (attributes) {
282
- consentCreated.add(1, sanitizeAttributes(attributes));
283
- },
284
- recordConsentAccepted (attributes) {
285
- consentAccepted.add(1, sanitizeAttributes(attributes));
286
- },
287
- recordConsentRejected (attributes) {
288
- consentRejected.add(1, sanitizeAttributes(attributes));
289
- },
290
- recordSubjectCreated (attributes) {
291
- subjectCreated.add(1, sanitizeAttributes(attributes));
292
- },
293
- recordSubjectLinked (identityProvider) {
294
- subjectLinked.add(1, {
295
- identityProvider: identityProvider || 'unknown'
296
- });
297
- },
298
- recordConsentCheck (type, found) {
299
- consentCheckCount.add(1, {
300
- type,
301
- found: String(found)
302
- });
303
- },
304
- recordInit (attributes) {
305
- initCount.add(1, sanitizeAttributes(attributes));
306
- },
307
- recordHttpRequest (attributes, durationMs) {
308
- const attrs = sanitizeAttributes(attributes);
309
- httpRequestCount.add(1, attrs);
310
- httpRequestDuration.record(durationMs, attrs);
311
- if (attributes.status >= 400) httpErrorCount.add(1, attrs);
312
- },
313
- recordDbQuery (attributes, durationMs) {
314
- const attrs = sanitizeAttributes(attributes);
315
- dbQueryCount.add(1, attrs);
316
- dbQueryDuration.record(durationMs, attrs);
317
- },
318
- recordDbError (attributes) {
319
- dbErrorCount.add(1, sanitizeAttributes(attributes));
320
- },
321
- recordCacheHit (layer) {
322
- cacheHit.add(1, {
323
- layer
324
- });
325
- },
326
- recordCacheMiss (layer) {
327
- cacheMiss.add(1, {
328
- layer
329
- });
330
- },
331
- recordCacheLatency (attributes, durationMs) {
332
- cacheLatency.record(durationMs, sanitizeAttributes(attributes));
333
- },
334
- recordGvlFetch (attributes, durationMs) {
335
- const attrs = sanitizeAttributes(attributes);
336
- gvlFetchCount.add(1, attrs);
337
- gvlFetchDuration.record(durationMs, attrs);
338
- },
339
- recordGvlError (attributes) {
340
- gvlFetchError.add(1, sanitizeAttributes(attributes));
341
- }
342
- };
343
- }
344
- let metricsInstance = null;
345
- function getMetrics(options) {
346
- if (metricsInstance) return metricsInstance;
347
- if (!create_telemetry_options_isTelemetryEnabled(options)) return null;
348
- metricsInstance = createMetrics(getMeter(options));
349
- return metricsInstance;
350
- }
351
- function createGVLCacheKey(appName, language, vendorIds) {
352
- const sortedIds = vendorIds ? [
353
- ...vendorIds
354
- ].sort((a, b)=>a - b).join(',') : 'all';
355
- return `${appName}:gvl:${language}:${sortedIds}`;
356
- }
357
- function createCacheKey(appName, namespace, ...parts) {
358
- const allParts = [
359
- appName,
360
- namespace,
361
- ...parts
362
- ];
363
- return allParts.join(':');
364
- }
365
- const GVL_ENDPOINT = 'https://gvl.consent.io';
366
- const inflightRequests = new Map();
367
- async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
368
- const sortedVendorIds = vendorIds ? [
369
- ...vendorIds
370
- ].sort((a, b)=>a - b) : [];
371
- const dedupeKey = `${endpoint}|${language}|${sortedVendorIds.join(',')}`;
372
- const existingRequest = inflightRequests.get(dedupeKey);
373
- if (existingRequest) return existingRequest;
374
- const url = new URL(endpoint);
375
- if (sortedVendorIds.length > 0) url.searchParams.set('vendorIds', sortedVendorIds.join(','));
376
- const promise = (async ()=>{
377
- const fetchStart = Date.now();
378
- try {
379
- const gvl = await withExternalSpan({
380
- url: url.toString(),
381
- method: 'GET'
382
- }, async ()=>{
383
- const response = await fetch(url.toString(), {
384
- headers: {
385
- 'Accept-Language': language
386
- }
387
- });
388
- if (204 === response.status) return null;
389
- if (!response.ok) throw new Error(`Failed to fetch GVL: ${response.status} ${response.statusText}`);
390
- const text = await response.text();
391
- const trimmed = text.trim().replace(/^\uFEFF/, '');
392
- let parsed;
393
- try {
394
- parsed = JSON.parse(trimmed);
395
- } catch {
396
- let depth = 0;
397
- let end = -1;
398
- const start = trimmed.indexOf('{');
399
- if (start >= 0) for(let i = start; i < trimmed.length; i++){
400
- const c = trimmed[i];
401
- if ('{' === c) depth++;
402
- else if ('}' === c) {
403
- depth--;
404
- if (0 === depth) {
405
- end = i + 1;
406
- break;
407
- }
408
- }
409
- }
410
- if (end > 0) parsed = JSON.parse(trimmed.slice(0, end));
411
- else throw new SyntaxError('Invalid GVL response: not valid JSON');
412
- }
413
- if (!parsed.vendorListVersion || !parsed.purposes || !parsed.vendors) throw new Error('Invalid GVL response: missing required fields');
414
- return parsed;
415
- });
416
- getMetrics()?.recordGvlFetch({
417
- language,
418
- source: 'fetch',
419
- status: 200
420
- }, Date.now() - fetchStart);
421
- return gvl;
422
- } catch (error) {
423
- getMetrics()?.recordGvlError({
424
- language,
425
- errorType: error instanceof Error ? error.name : 'UnknownError'
426
- });
427
- throw error;
428
- } finally{
429
- inflightRequests.delete(dedupeKey);
430
- }
431
- })();
432
- inflightRequests.set(dedupeKey, promise);
433
- return promise;
434
- }
435
- function createGVLResolver(options) {
436
- const { appName, bundled, cacheAdapter, vendorIds, endpoint } = options;
437
- const memoryCache = createMemoryCacheAdapter();
438
- return {
439
- async get (language) {
440
- const cacheKey = createGVLCacheKey(appName, language, vendorIds);
441
- if (bundled?.[language]) return bundled[language];
442
- const memoryHit = await withCacheSpan('get', 'memory', ()=>memoryCache.get(cacheKey));
443
- if (memoryHit) {
444
- getMetrics()?.recordCacheHit('memory');
445
- return memoryHit;
446
- }
447
- getMetrics()?.recordCacheMiss('memory');
448
- if (cacheAdapter) {
449
- const externalHit = await withCacheSpan('get', 'external', ()=>cacheAdapter.get(cacheKey));
450
- if (externalHit) {
451
- getMetrics()?.recordCacheHit('external');
452
- await withCacheSpan('set', 'memory', ()=>memoryCache.set(cacheKey, externalHit, 300000));
453
- return externalHit;
454
- }
455
- getMetrics()?.recordCacheMiss('external');
456
- }
457
- const gvl = await fetchGVLWithLanguage(language, vendorIds, endpoint);
458
- if (gvl) {
459
- await withCacheSpan('set', 'memory', ()=>memoryCache.set(cacheKey, gvl, 300000));
460
- if (cacheAdapter) await withCacheSpan('set', 'external', ()=>cacheAdapter.set(cacheKey, gvl, GVL_TTL_MS));
461
- }
462
- return gvl;
463
- }
464
- };
465
- }
466
- var __webpack_exports__MEMORY_TTL_MS = 300000;
467
- export { GVL_TTL_MS, clearMemoryCache, createCacheKey, createCloudflareKVAdapter, createGVLCacheKey, createGVLResolver, createMemoryCacheAdapter, createUpstashRedisAdapter, createUpstashRedisAdapterFromClient, getMemoryCacheSize, __webpack_exports__MEMORY_TTL_MS as MEMORY_TTL_MS };
54
+ var cache_MEMORY_TTL_MS = 300000;
55
+ export { GVL_TTL_MS, clearMemoryCache, createCacheKey, createGVLCacheKey, createGVLResolver, createMemoryCacheAdapter, getMemoryCacheSize } from "./302.js";
56
+ export { cache_MEMORY_TTL_MS as MEMORY_TTL_MS, createCloudflareKVAdapter, createUpstashRedisAdapter, createUpstashRedisAdapterFromClient };
package/dist/core.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
- "./src/db/schema/index.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
3
+ "./src/db/schema/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
4
  __webpack_require__.d(__webpack_exports__, {
5
5
  DB: ()=>DB
6
6
  });
@@ -294,7 +294,7 @@ var __webpack_modules__ = {
294
294
  ]
295
295
  });
296
296
  },
297
- "./src/define-config.ts" (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
297
+ "./src/define-config.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
298
298
  __webpack_require__.d(__webpack_exports__, {
299
299
  defineConfig: ()=>defineConfig
300
300
  });
@@ -336,7 +336,7 @@ function __webpack_require__(moduleId) {
336
336
  })();
337
337
  (()=>{
338
338
  __webpack_require__.r = (exports1)=>{
339
- if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
339
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
340
340
  value: 'Module'
341
341
  });
342
342
  Object.defineProperty(exports1, '__esModule', {
@@ -737,7 +737,7 @@ var __webpack_exports__ = {};
737
737
  language
738
738
  };
739
739
  }
740
- const version_version = '2.0.0-rc.5';
740
+ const version_version = '2.0.0-rc.6';
741
741
  function extractErrorMessage(error) {
742
742
  if (error instanceof AggregateError && error.errors?.length > 0) {
743
743
  const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
@@ -1772,11 +1772,7 @@ var __webpack_exports__ = {};
1772
1772
  const app = new external_hono_namespaceObject.Hono();
1773
1773
  app.get('/check', (0, external_hono_openapi_namespaceObject.describeRoute)({
1774
1774
  summary: 'Check consent by external user ID',
1775
- description: `Pre-banner cross-device consent check. Use to avoid showing the banner when the user has already consented on another device.
1776
-
1777
- **Query parameters:**
1778
- - \`externalId\` – External user ID to check
1779
- - \`type\` – Consent type(s) to check (comma-separated)`,
1775
+ description: "Pre-banner cross-device consent check. Use to avoid showing the banner when the user has already consented on another device.\n\n**Query parameters:**\n- `externalId` – External user ID to check\n- `type` – Consent type(s) to check (comma-separated)",
1780
1776
  tags: [
1781
1777
  'Consent'
1782
1778
  ],
@@ -2442,6 +2438,12 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2442
2438
  const subjectId = c.req.param('id');
2443
2439
  const type = c.req.query('type');
2444
2440
  const typeFilter = type?.split(',').map((t)=>t.trim()) || [];
2441
+ if (!subjectId) throw new http_exception_namespaceObject.HTTPException(400, {
2442
+ message: 'Subject ID is required',
2443
+ cause: {
2444
+ code: 'SUBJECT_ID_REQUIRED'
2445
+ }
2446
+ });
2445
2447
  logger.debug('Request parameters', {
2446
2448
  subjectId,
2447
2449
  typeFilter
@@ -2633,6 +2635,12 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
2633
2635
  const subjectId = c.req.param('id');
2634
2636
  const body = await c.req.json();
2635
2637
  const { externalId, identityProvider = 'external' } = body;
2638
+ if (!subjectId) throw new http_exception_namespaceObject.HTTPException(400, {
2639
+ message: 'Subject ID is required',
2640
+ cause: {
2641
+ code: 'SUBJECT_ID_REQUIRED'
2642
+ }
2643
+ });
2636
2644
  logger.debug('Request parameters', {
2637
2645
  subjectId,
2638
2646
  externalId,
@@ -3150,11 +3158,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3150
3158
  const app = new external_hono_namespaceObject.Hono();
3151
3159
  app.get('/:id', (0, external_hono_openapi_namespaceObject.describeRoute)({
3152
3160
  summary: 'Get subject consent status',
3153
- description: `Returns the subject's consent status for this device. Use to check if the subject has valid consent for given policy types.
3154
-
3155
- **Query:** \`type\` – Filter by consent type(s), comma-separated (e.g. \`privacy_policy,cookie_banner\`).
3156
-
3157
- **Response:** \`subject\`, \`consents\` (matching filter), \`isValid\` (valid consent for requested type(s)).`,
3161
+ description: "Returns the subject's consent status for this device. Use to check if the subject has valid consent for given policy types.\n\n**Query:** `type` – Filter by consent type(s), comma-separated (e.g. `privacy_policy,cookie_banner`).\n\n**Response:** `subject`, `consents` (matching filter), `isValid` (valid consent for requested type(s)).",
3158
3162
  tags: [
3159
3163
  'Subject',
3160
3164
  'Consent'
@@ -3175,12 +3179,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3175
3179
  }), (0, external_hono_openapi_namespaceObject.validator)('param', schema_.getSubjectInputSchema), getSubjectHandler);
3176
3180
  app.post('/', (0, external_hono_openapi_namespaceObject.describeRoute)({
3177
3181
  summary: 'Record consent for a subject',
3178
- description: `Creates a new consent record (append-only). Creates the subject if it does not exist.
3179
-
3180
- **Request body by \`type\`:**
3181
- - \`cookie_banner\` – Requires \`preferences\` object
3182
- - \`privacy_policy\`, \`dpa\`, \`terms_and_conditions\` – Optional \`policyId\`
3183
- - \`marketing_communications\`, \`age_verification\`, \`other\` – Optional \`preferences\``,
3182
+ description: "Creates a new consent record (append-only). Creates the subject if it does not exist.\n\n**Request body by `type`:**\n- `cookie_banner` – Requires `preferences` object\n- `privacy_policy`, `dpa`, `terms_and_conditions` – Optional `policyId`\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
3184
3183
  tags: [
3185
3184
  'Subject',
3186
3185
  'Consent'
@@ -3265,7 +3264,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3265
3264
  if (!value) return;
3266
3265
  return (0, schema_.compactDefined)({
3267
3266
  allowedActions: (0, schema_.dedupeTrimmedStrings)(value.allowedActions),
3268
- primaryAction: value.primaryAction,
3267
+ primaryActions: value.primaryActions,
3269
3268
  layout: value.layout,
3270
3269
  direction: value.direction,
3271
3270
  uiProfile: value.uiProfile,
@@ -3413,9 +3412,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3413
3412
  }));
3414
3413
  const publicSpecUrl = `${basePath}${openApiConfig.specPath}`.replace(/\/+/g, '/');
3415
3414
  app.get(openApiConfig.docsPath, (0, hono_api_reference_namespaceObject.apiReference)({
3416
- spec: {
3417
- url: publicSpecUrl
3418
- },
3415
+ url: publicSpecUrl,
3419
3416
  pageTitle: `${options.appName || 'c15t API'} Documentation`
3420
3417
  }));
3421
3418
  }