@c15t/backend 2.0.0-rc.8 → 2.0.0

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 CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  [![GitHub stars](https://img.shields.io/github/stars/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t)
13
13
  [![CI](https://img.shields.io/github/actions/workflow/status/c15t/c15t/ci.yml?style=flat-square)](https://github.com/c15t/c15t/actions/workflows/ci.yml)
14
- [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](https://github.com/c15t/c15t/blob/main/LICENSE.md)
14
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](https://github.com/c15t/c15t/blob/main/LICENSE.md)
15
15
  [![Discord](https://img.shields.io/discord/1312171102268690493?style=flat-square)](https://c15t.link/discord)
16
16
  [![npm version](https://img.shields.io/npm/v/%40c15t%2Fbackend?style=flat-square)](https://www.npmjs.com/package/@c15t/backend)
17
17
  [![Top Language](https://img.shields.io/github/languages/top/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t)
@@ -82,8 +82,8 @@ Our preference is that you make use of GitHub's private vulnerability reporting
82
82
 
83
83
  ## License
84
84
 
85
- [GNU General Public License v3.0](https://github.com/c15t/c15t/blob/main/LICENSE.md)
85
+ [Apache License 2.0](https://github.com/c15t/c15t/blob/main/LICENSE.md)
86
86
 
87
87
  ---
88
88
 
89
- **Built with ❤️ by the [consent.io](https://www.consent.io?utm_source=github&utm_medium=repopage_%40c15t%2Fbackend) team**
89
+ **Built by [Inth](https://inth.com?utm_source=github&utm_medium=repopage_%40c15t%2Fbackend)**
package/dist/302.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { SpanKind, SpanStatusCode as api_SpanStatusCode, context, metrics, trace } from "@opentelemetry/api";
2
- const version = '2.0.0-rc.8';
3
2
  function extractErrorMessage(error) {
4
3
  if (error instanceof AggregateError && error.errors?.length > 0) {
5
4
  const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
@@ -14,7 +13,7 @@ function createTelemetryOptions(appName = 'c15t', telemetryConfig, tenantId) {
14
13
  const defaultAttributes = {
15
14
  ...telemetryConfig?.defaultAttributes || {},
16
15
  'service.name': String(appName),
17
- 'service.version': version
16
+ 'service.version': "2.0.0"
18
17
  };
19
18
  if (tenantId) defaultAttributes['tenant.id'] = tenantId;
20
19
  const config = {
@@ -470,4 +469,4 @@ function createGVLResolver(options) {
470
469
  }
471
470
  };
472
471
  }
473
- export { GVL_TTL_MS, clearMemoryCache, createCacheKey, createGVLCacheKey, createGVLResolver, createMemoryCacheAdapter, createRequestSpan, createTelemetryOptions, extractErrorMessage, getMemoryCacheSize, getMetrics, getTraceContext, handleSpanError, isTelemetryEnabled, version, withDatabaseSpan, withSpanContext };
472
+ export { GVL_TTL_MS, clearMemoryCache, createCacheKey, createGVLCacheKey, createGVLResolver, createMemoryCacheAdapter, createRequestSpan, createTelemetryOptions, extractErrorMessage, getMemoryCacheSize, getMetrics, getTraceContext, handleSpanError, isTelemetryEnabled, withDatabaseSpan, withSpanContext };
package/dist/915.js CHANGED
@@ -5,7 +5,7 @@ import { Hono } from "hono";
5
5
  import { describeRoute, resolver, validator } from "hono-openapi";
6
6
  import { HTTPException } from "hono/http-exception";
7
7
  import { errors, jwtVerify } from "jose";
8
- import { version, getMetrics, withDatabaseSpan, extractErrorMessage } from "./302.js";
8
+ import { extractErrorMessage, getMetrics, withDatabaseSpan } from "./302.js";
9
9
  import { getLocation, resolveInitPayload, policy_resolvePolicyDecision, verifyPolicySnapshotToken, getJurisdiction } from "./583.js";
10
10
  import * as __rspack_external_valibot from "valibot";
11
11
  const prefixes = {
@@ -709,7 +709,7 @@ const statusHandler = async (c)=>{
709
709
  try {
710
710
  await ctx.db.findFirst('subject', {});
711
711
  return c.json({
712
- version: version,
712
+ version: "2.0.0",
713
713
  timestamp: new Date(),
714
714
  client: clientInfo
715
715
  });
@@ -1372,6 +1372,7 @@ const postSubjectHandler = async (c)=>{
1372
1372
  let purposeIds = [];
1373
1373
  let appliedPreferences;
1374
1374
  const inputPolicyId = 'policyId' in input ? input.policyId : void 0;
1375
+ const inputPolicyHash = 'policyHash' in input ? input.policyHash : void 0;
1375
1376
  if (legalDocumentConsent && legalDocumentSnapshotVerification.valid) {
1376
1377
  if (legalDocumentSnapshotVerification.payload.type !== type) throw buildLegalDocumentSnapshotHttpException('invalid');
1377
1378
  const effectiveDate = new Date(legalDocumentSnapshotVerification.payload.effectiveDate);
@@ -1384,26 +1385,47 @@ const postSubjectHandler = async (c)=>{
1384
1385
  });
1385
1386
  policyId = documentPolicy.id;
1386
1387
  } else if (legalDocumentConsent) {
1387
- if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId when snapshot verification is disabled');
1388
- if (!inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires a valid document snapshot token or policyId');
1389
- policyId = inputPolicyId;
1390
- const policy = await registry.findConsentPolicyById(inputPolicyId);
1391
- if (!policy) throw new HTTPException(404, {
1392
- message: 'Policy not found',
1393
- cause: {
1394
- code: 'POLICY_NOT_FOUND',
1395
- policyId,
1396
- type
1397
- }
1398
- });
1399
- if (!policy.isActive) throw new HTTPException(400, {
1400
- message: 'Policy is inactive',
1401
- cause: {
1402
- code: 'POLICY_INACTIVE',
1403
- policyId,
1404
- type
1405
- }
1406
- });
1388
+ if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId && !inputPolicyHash) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId or policyHash when snapshot verification is disabled');
1389
+ if (inputPolicyId) {
1390
+ policyId = inputPolicyId;
1391
+ const policy = await registry.findConsentPolicyById(inputPolicyId);
1392
+ if (!policy) throw new HTTPException(404, {
1393
+ message: 'Policy not found',
1394
+ cause: {
1395
+ code: 'POLICY_NOT_FOUND',
1396
+ policyId,
1397
+ type
1398
+ }
1399
+ });
1400
+ if (!policy.isActive) throw new HTTPException(400, {
1401
+ message: 'Policy is inactive',
1402
+ cause: {
1403
+ code: 'POLICY_INACTIVE',
1404
+ policyId,
1405
+ type
1406
+ }
1407
+ });
1408
+ } else if (inputPolicyHash) {
1409
+ const policy = await registry.findLegalDocumentPolicyByHash(type, inputPolicyHash);
1410
+ if (!policy) throw new HTTPException(404, {
1411
+ message: 'Policy not found',
1412
+ cause: {
1413
+ code: 'POLICY_NOT_FOUND',
1414
+ type,
1415
+ policyHash: inputPolicyHash
1416
+ }
1417
+ });
1418
+ if (!policy.isActive) throw new HTTPException(400, {
1419
+ message: 'Policy is inactive',
1420
+ cause: {
1421
+ code: 'POLICY_INACTIVE',
1422
+ policyId: policy.id,
1423
+ type,
1424
+ policyHash: inputPolicyHash
1425
+ }
1426
+ });
1427
+ policyId = policy.id;
1428
+ }
1407
1429
  } else if (inputPolicyId) {
1408
1430
  policyId = inputPolicyId;
1409
1431
  const policy = await registry.findConsentPolicyById(inputPolicyId);
@@ -1466,6 +1488,13 @@ const postSubjectHandler = async (c)=>{
1466
1488
  });
1467
1489
  purposeIds = purposes;
1468
1490
  }
1491
+ if (!policyId) throw new HTTPException(500, {
1492
+ message: 'Failed to resolve policy',
1493
+ cause: {
1494
+ code: 'POLICY_RESOLUTION_FAILED',
1495
+ type
1496
+ }
1497
+ });
1469
1498
  const expiryDays = effectivePolicy?.consent?.expiryDays;
1470
1499
  const validUntil = 'number' == typeof expiryDays && Number.isFinite(expiryDays) ? new Date(givenAt.getTime() + 86400000 * Math.max(0, expiryDays)) : void 0;
1471
1500
  const proofConfig = effectivePolicy?.proof;
@@ -1668,7 +1697,7 @@ const createSubjectRoutes = ()=>{
1668
1697
  }), validator('param', getSubjectInputSchema), getSubjectHandler);
1669
1698
  app.post('/', describeRoute({
1670
1699
  summary: 'Record consent for a subject',
1671
- 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` – Requires a valid `documentSnapshotToken` when legal-document verification is enabled, otherwise an explicit `policyId`\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
1700
+ 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` – Prefer a signed `documentSnapshotToken`; otherwise use a release `policyHash`, with `policyId` kept only for compatibility\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
1672
1701
  tags: [
1673
1702
  'Subject',
1674
1703
  'Consent'
package/dist/core.cjs CHANGED
@@ -349,7 +349,7 @@ var __webpack_exports__ = {};
349
349
  (()=>{
350
350
  __webpack_require__.r(__webpack_exports__);
351
351
  __webpack_require__.d(__webpack_exports__, {
352
- version: ()=>version_version,
352
+ version: ()=>"2.0.0",
353
353
  c15tInstance: ()=>c15tInstance,
354
354
  EEA_COUNTRY_CODES: ()=>types_namespaceObject.EEA_COUNTRY_CODES,
355
355
  EU_COUNTRY_CODES: ()=>types_namespaceObject.EU_COUNTRY_CODES,
@@ -738,7 +738,6 @@ var __webpack_exports__ = {};
738
738
  language
739
739
  };
740
740
  }
741
- const version_version = '2.0.0-rc.8';
742
741
  function extractErrorMessage(error) {
743
742
  if (error instanceof AggregateError && error.errors?.length > 0) {
744
743
  const inner = error.errors.map((e)=>e instanceof Error ? e.message : String(e)).join('; ');
@@ -753,7 +752,7 @@ var __webpack_exports__ = {};
753
752
  const defaultAttributes = {
754
753
  ...telemetryConfig?.defaultAttributes || {},
755
754
  'service.name': String(appName),
756
- 'service.version': version_version
755
+ 'service.version': "2.0.0"
757
756
  };
758
757
  if (tenantId) defaultAttributes['tenant.id'] = tenantId;
759
758
  const config = {
@@ -2672,7 +2671,7 @@ Use for geo-targeted consent banners and regional compliance.`,
2672
2671
  try {
2673
2672
  await ctx.db.findFirst('subject', {});
2674
2673
  return c.json({
2675
- version: version_version,
2674
+ version: "2.0.0",
2676
2675
  timestamp: new Date(),
2677
2676
  client: clientInfo
2678
2677
  });
@@ -3336,6 +3335,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3336
3335
  let purposeIds = [];
3337
3336
  let appliedPreferences;
3338
3337
  const inputPolicyId = 'policyId' in input ? input.policyId : void 0;
3338
+ const inputPolicyHash = 'policyHash' in input ? input.policyHash : void 0;
3339
3339
  if (legalDocumentConsent && legalDocumentSnapshotVerification.valid) {
3340
3340
  if (legalDocumentSnapshotVerification.payload.type !== type) throw buildLegalDocumentSnapshotHttpException('invalid');
3341
3341
  const effectiveDate = new Date(legalDocumentSnapshotVerification.payload.effectiveDate);
@@ -3348,26 +3348,47 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3348
3348
  });
3349
3349
  policyId = documentPolicy.id;
3350
3350
  } else if (legalDocumentConsent) {
3351
- if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId when snapshot verification is disabled');
3352
- if (!inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires a valid document snapshot token or policyId');
3353
- policyId = inputPolicyId;
3354
- const policy = await registry.findConsentPolicyById(inputPolicyId);
3355
- if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
3356
- message: 'Policy not found',
3357
- cause: {
3358
- code: 'POLICY_NOT_FOUND',
3359
- policyId,
3360
- type
3361
- }
3362
- });
3363
- if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
3364
- message: 'Policy is inactive',
3365
- cause: {
3366
- code: 'POLICY_INACTIVE',
3367
- policyId,
3368
- type
3369
- }
3370
- });
3351
+ if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId && !inputPolicyHash) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId or policyHash when snapshot verification is disabled');
3352
+ if (inputPolicyId) {
3353
+ policyId = inputPolicyId;
3354
+ const policy = await registry.findConsentPolicyById(inputPolicyId);
3355
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
3356
+ message: 'Policy not found',
3357
+ cause: {
3358
+ code: 'POLICY_NOT_FOUND',
3359
+ policyId,
3360
+ type
3361
+ }
3362
+ });
3363
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
3364
+ message: 'Policy is inactive',
3365
+ cause: {
3366
+ code: 'POLICY_INACTIVE',
3367
+ policyId,
3368
+ type
3369
+ }
3370
+ });
3371
+ } else if (inputPolicyHash) {
3372
+ const policy = await registry.findLegalDocumentPolicyByHash(type, inputPolicyHash);
3373
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
3374
+ message: 'Policy not found',
3375
+ cause: {
3376
+ code: 'POLICY_NOT_FOUND',
3377
+ type,
3378
+ policyHash: inputPolicyHash
3379
+ }
3380
+ });
3381
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
3382
+ message: 'Policy is inactive',
3383
+ cause: {
3384
+ code: 'POLICY_INACTIVE',
3385
+ policyId: policy.id,
3386
+ type,
3387
+ policyHash: inputPolicyHash
3388
+ }
3389
+ });
3390
+ policyId = policy.id;
3391
+ }
3371
3392
  } else if (inputPolicyId) {
3372
3393
  policyId = inputPolicyId;
3373
3394
  const policy = await registry.findConsentPolicyById(inputPolicyId);
@@ -3430,6 +3451,13 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3430
3451
  });
3431
3452
  purposeIds = purposes;
3432
3453
  }
3454
+ if (!policyId) throw new http_exception_namespaceObject.HTTPException(500, {
3455
+ message: 'Failed to resolve policy',
3456
+ cause: {
3457
+ code: 'POLICY_RESOLUTION_FAILED',
3458
+ type
3459
+ }
3460
+ });
3433
3461
  const expiryDays = effectivePolicy?.consent?.expiryDays;
3434
3462
  const validUntil = 'number' == typeof expiryDays && Number.isFinite(expiryDays) ? new Date(givenAt.getTime() + 86400000 * Math.max(0, expiryDays)) : void 0;
3435
3463
  const proofConfig = effectivePolicy?.proof;
@@ -3632,7 +3660,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3632
3660
  }), (0, external_hono_openapi_namespaceObject.validator)('param', schema_.getSubjectInputSchema), getSubjectHandler);
3633
3661
  app.post('/', (0, external_hono_openapi_namespaceObject.describeRoute)({
3634
3662
  summary: 'Record consent for a subject',
3635
- 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` – Requires a valid `documentSnapshotToken` when legal-document verification is enabled, otherwise an explicit `policyId`\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
3663
+ 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` – Prefer a signed `documentSnapshotToken`; otherwise use a release `policyHash`, with `policyId` kept only for compatibility\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
3636
3664
  tags: [
3637
3665
  'Subject',
3638
3666
  'Consent'
@@ -3845,7 +3873,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
3845
3873
  openapi: '3.1.0',
3846
3874
  info: {
3847
3875
  title: options.appName || 'c15t API',
3848
- version: version_version,
3876
+ version: "2.0.0",
3849
3877
  description: 'API for consent management'
3850
3878
  },
3851
3879
  servers: [
package/dist/core.js CHANGED
@@ -7,7 +7,7 @@ import { HTTPException } from "hono/http-exception";
7
7
  import { openAPIRouteHandler } from "hono-openapi";
8
8
  import { compactDefined, dedupeTrimmedStrings, policyPackPresets } from "@c15t/schema";
9
9
  import { EEA_COUNTRY_CODES, EU_COUNTRY_CODES, POLICY_MATCH_DATASET_VERSION, UK_COUNTRY_CODES, policyMatchers } from "@c15t/schema/types";
10
- import { version as version_version, extractErrorMessage, withDatabaseSpan, getTraceContext as create_telemetry_options_getTraceContext, createRequestSpan, handleSpanError, createTelemetryOptions, getMetrics, isTelemetryEnabled, withSpanContext } from "./302.js";
10
+ import { extractErrorMessage, withDatabaseSpan, getTraceContext as create_telemetry_options_getTraceContext, createRequestSpan, handleSpanError, createTelemetryOptions, getMetrics, isTelemetryEnabled, withSpanContext } from "./302.js";
11
11
  import { createLegalDocumentRoutes, createSubjectRoutes, generateUniqueId, createStatusRoute, createInitRoute, createConsentRoutes, policyRegistry } from "./915.js";
12
12
  import { validateMessages, inspectPolicies as policy_inspectPolicies } from "./583.js";
13
13
  import { DB } from "./db/schema.js";
@@ -765,7 +765,7 @@ const c15tInstance = (options)=>{
765
765
  openapi: '3.1.0',
766
766
  info: {
767
767
  title: options.appName || 'c15t API',
768
- version: version_version,
768
+ version: "2.0.0",
769
769
  description: 'API for consent management'
770
770
  },
771
771
  servers: [
@@ -879,7 +879,7 @@ const c15tInstance = (options)=>{
879
879
  getDocsUI
880
880
  };
881
881
  };
882
+ var core_version = "2.0.0";
882
883
  export { defineConfig } from "./define-config.js";
883
884
  export { inspectPolicies } from "./583.js";
884
- export { version } from "./302.js";
885
- export { EEA_COUNTRY_CODES, EU_COUNTRY_CODES, POLICY_MATCH_DATASET_VERSION, UK_COUNTRY_CODES, c15tInstance, policyBuilder, policyMatchers, policyPackPresets };
885
+ export { EEA_COUNTRY_CODES, EU_COUNTRY_CODES, POLICY_MATCH_DATASET_VERSION, UK_COUNTRY_CODES, c15tInstance, core_version as version, policyBuilder, policyMatchers, policyPackPresets };
package/dist/router.cjs CHANGED
@@ -1212,7 +1212,6 @@ class consent_policy_LegalDocumentPolicyConflictError extends Error {
1212
1212
  this.name = 'LegalDocumentPolicyConflictError';
1213
1213
  }
1214
1214
  }
1215
- const version_version = '2.0.0-rc.8';
1216
1215
  function getHeaders(headers) {
1217
1216
  if (!headers) return {
1218
1217
  countryCode: null,
@@ -1247,7 +1246,7 @@ const statusHandler = async (c)=>{
1247
1246
  try {
1248
1247
  await ctx.db.findFirst('subject', {});
1249
1248
  return c.json({
1250
- version: version_version,
1249
+ version: "2.0.0",
1251
1250
  timestamp: new Date(),
1252
1251
  client: clientInfo
1253
1252
  });
@@ -1911,6 +1910,7 @@ const postSubjectHandler = async (c)=>{
1911
1910
  let purposeIds = [];
1912
1911
  let appliedPreferences;
1913
1912
  const inputPolicyId = 'policyId' in input ? input.policyId : void 0;
1913
+ const inputPolicyHash = 'policyHash' in input ? input.policyHash : void 0;
1914
1914
  if (legalDocumentConsent && legalDocumentSnapshotVerification.valid) {
1915
1915
  if (legalDocumentSnapshotVerification.payload.type !== type) throw buildLegalDocumentSnapshotHttpException('invalid');
1916
1916
  const effectiveDate = new Date(legalDocumentSnapshotVerification.payload.effectiveDate);
@@ -1923,26 +1923,47 @@ const postSubjectHandler = async (c)=>{
1923
1923
  });
1924
1924
  policyId = documentPolicy.id;
1925
1925
  } else if (legalDocumentConsent) {
1926
- if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId when snapshot verification is disabled');
1927
- if (!inputPolicyId) throw buildLegalDocumentProofHttpException('Legal document consent requires a valid document snapshot token or policyId');
1928
- policyId = inputPolicyId;
1929
- const policy = await registry.findConsentPolicyById(inputPolicyId);
1930
- if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
1931
- message: 'Policy not found',
1932
- cause: {
1933
- code: 'POLICY_NOT_FOUND',
1934
- policyId,
1935
- type
1936
- }
1937
- });
1938
- if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
1939
- message: 'Policy is inactive',
1940
- cause: {
1941
- code: 'POLICY_INACTIVE',
1942
- policyId,
1943
- type
1944
- }
1945
- });
1926
+ if (!ctx.legalDocumentSnapshot?.signingKey && !inputPolicyId && !inputPolicyHash) throw buildLegalDocumentProofHttpException('Legal document consent requires policyId or policyHash when snapshot verification is disabled');
1927
+ if (inputPolicyId) {
1928
+ policyId = inputPolicyId;
1929
+ const policy = await registry.findConsentPolicyById(inputPolicyId);
1930
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
1931
+ message: 'Policy not found',
1932
+ cause: {
1933
+ code: 'POLICY_NOT_FOUND',
1934
+ policyId,
1935
+ type
1936
+ }
1937
+ });
1938
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
1939
+ message: 'Policy is inactive',
1940
+ cause: {
1941
+ code: 'POLICY_INACTIVE',
1942
+ policyId,
1943
+ type
1944
+ }
1945
+ });
1946
+ } else if (inputPolicyHash) {
1947
+ const policy = await registry.findLegalDocumentPolicyByHash(type, inputPolicyHash);
1948
+ if (!policy) throw new http_exception_namespaceObject.HTTPException(404, {
1949
+ message: 'Policy not found',
1950
+ cause: {
1951
+ code: 'POLICY_NOT_FOUND',
1952
+ type,
1953
+ policyHash: inputPolicyHash
1954
+ }
1955
+ });
1956
+ if (!policy.isActive) throw new http_exception_namespaceObject.HTTPException(400, {
1957
+ message: 'Policy is inactive',
1958
+ cause: {
1959
+ code: 'POLICY_INACTIVE',
1960
+ policyId: policy.id,
1961
+ type,
1962
+ policyHash: inputPolicyHash
1963
+ }
1964
+ });
1965
+ policyId = policy.id;
1966
+ }
1946
1967
  } else if (inputPolicyId) {
1947
1968
  policyId = inputPolicyId;
1948
1969
  const policy = await registry.findConsentPolicyById(inputPolicyId);
@@ -2005,6 +2026,13 @@ const postSubjectHandler = async (c)=>{
2005
2026
  });
2006
2027
  purposeIds = purposes;
2007
2028
  }
2029
+ if (!policyId) throw new http_exception_namespaceObject.HTTPException(500, {
2030
+ message: 'Failed to resolve policy',
2031
+ cause: {
2032
+ code: 'POLICY_RESOLUTION_FAILED',
2033
+ type
2034
+ }
2035
+ });
2008
2036
  const expiryDays = effectivePolicy?.consent?.expiryDays;
2009
2037
  const validUntil = 'number' == typeof expiryDays && Number.isFinite(expiryDays) ? new Date(givenAt.getTime() + 86400000 * Math.max(0, expiryDays)) : void 0;
2010
2038
  const proofConfig = effectivePolicy?.proof;
@@ -2207,7 +2235,7 @@ const createSubjectRoutes = ()=>{
2207
2235
  }), (0, external_hono_openapi_namespaceObject.validator)('param', schema_namespaceObject.getSubjectInputSchema), getSubjectHandler);
2208
2236
  app.post('/', (0, external_hono_openapi_namespaceObject.describeRoute)({
2209
2237
  summary: 'Record consent for a subject',
2210
- 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` – Requires a valid `documentSnapshotToken` when legal-document verification is enabled, otherwise an explicit `policyId`\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
2238
+ 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` – Prefer a signed `documentSnapshotToken`; otherwise use a release `policyHash`, with `policyId` kept only for compatibility\n- `marketing_communications`, `age_verification`, `other` – Optional `preferences`",
2211
2239
  tags: [
2212
2240
  'Subject',
2213
2241
  'Consent'
@@ -8,8 +8,8 @@ import type { PolicyConfig, PolicyModel, PolicyScopeMode, PolicyUiMode, PolicyUi
8
8
  * Use the builder helpers to normalize this input into runtime-ready policy
9
9
  * configs.
10
10
  *
11
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
12
- * @see {@link https://v2.c15t.com/docs/frameworks/react/concepts/policy-packs}
11
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
12
+ * @see {@link https://c15t.com/docs/frameworks/react/concepts/policy-packs}
13
13
  */
14
14
  export interface PolicyBuilderInput {
15
15
  id: string;
@@ -57,7 +57,7 @@ export interface PolicyBuilderInput {
57
57
  * Empty optional fields are removed from the final output, matcher input is
58
58
  * merged into `match`, and duplicate string arrays are deduplicated.
59
59
  *
60
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
60
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
61
61
  */
62
62
  export declare function buildPolicyConfig(input: PolicyBuilderInput): PolicyConfig;
63
63
  /**
@@ -68,7 +68,7 @@ export declare function buildPolicyConfig(input: PolicyBuilderInput): PolicyConf
68
68
  * duplicate region/country matchers use first-match-wins semantics within the
69
69
  * same matcher type.
70
70
  *
71
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
71
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
72
72
  */
73
73
  export declare function buildPolicyPack(inputs: PolicyBuilderInput[]): PolicyConfig[];
74
74
  /**
@@ -84,7 +84,7 @@ export declare function buildPolicyPack(inputs: PolicyBuilderInput[]): PolicyCon
84
84
  * When `defaultPolicy` is provided, its `countries` and `regions` fields are
85
85
  * stripped and replaced with `match.isDefault = true`.
86
86
  *
87
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
87
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
88
88
  */
89
89
  export declare function buildPolicyPackWithDefault(inputs: PolicyBuilderInput[], defaultPolicy?: PolicyBuilderInput): PolicyConfig[];
90
90
  /**
@@ -107,7 +107,7 @@ export declare function buildPolicyPackWithDefault(inputs: PolicyBuilderInput[],
107
107
  * );
108
108
  * ```
109
109
  *
110
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
110
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
111
111
  */
112
112
  export declare function composePacks(...packs: PolicyConfig[][]): PolicyConfig[];
113
113
  /**
@@ -117,7 +117,7 @@ export declare function composePacks(...packs: PolicyConfig[][]): PolicyConfig[]
117
117
  * Useful when you prefer a grouped API such as `policyBuilder.createPack()`
118
118
  * inside backend config files.
119
119
  *
120
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
120
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
121
121
  */
122
122
  export declare const policyBuilder: {
123
123
  create: typeof buildPolicyConfig;
@@ -13,7 +13,7 @@ export interface DatabaseOptions {
13
13
  /**
14
14
  * The database adapter to use.
15
15
  *
16
- * @see {@link https://v2.c15t.com/docs/self-host/guides/database-setup}
16
+ * @see {@link https://c15t.com/docs/self-host/guides/database-setup}
17
17
  */
18
18
  adapter: FumaDB<FumaDBSchema>['adapter'];
19
19
  /**
@@ -26,7 +26,7 @@ export interface DatabaseOptions {
26
26
  * Useful when sharing a database with other applications to avoid naming conflicts.
27
27
  *
28
28
  * @example 'c15t_' // tables become: c15t_subject, c15t_consent, etc.
29
- * @see {@link https://v2.c15t.com/docs/self-host/guides/database-setup}
29
+ * @see {@link https://c15t.com/docs/self-host/guides/database-setup}
30
30
  */
31
31
  tablePrefix?: string;
32
32
  }
@@ -297,7 +297,7 @@ export interface C15TOptions {
297
297
  /**
298
298
  * The database adapter to use.
299
299
  *
300
- * @see {@link https://v2.c15t.com/docs/self-host/guides/database-setup}
300
+ * @see {@link https://c15t.com/docs/self-host/guides/database-setup}
301
301
  */
302
302
  adapter: FumaDB<FumaDBSchema>['adapter'];
303
303
  /**
@@ -310,7 +310,7 @@ export interface C15TOptions {
310
310
  * Useful when sharing a database with other applications to avoid naming conflicts.
311
311
  *
312
312
  * @example 'c15t_' // tables become: c15t_subject, c15t_consent, etc.
313
- * @see {@link https://v2.c15t.com/docs/self-host/guides/database-setup}
313
+ * @see {@link https://c15t.com/docs/self-host/guides/database-setup}
314
314
  */
315
315
  tablePrefix?: string;
316
316
  /**
@@ -319,13 +319,13 @@ export interface C15TOptions {
319
319
  * and cache key prefixing.
320
320
  *
321
321
  * @default "c15t"
322
- * @see {@link https://v2.c15t.com/docs/self-host/api/configuration}
322
+ * @see {@link https://c15t.com/docs/self-host/api/configuration}
323
323
  */
324
324
  appName?: string;
325
325
  /**
326
326
  * Base path prefix for all API routes (e.g. `/api/self-host`).
327
327
  *
328
- * @see {@link https://v2.c15t.com/docs/self-host/api/endpoints}
328
+ * @see {@link https://c15t.com/docs/self-host/api/endpoints}
329
329
  */
330
330
  basePath?: string;
331
331
  /**
@@ -333,7 +333,7 @@ export interface C15TOptions {
333
333
  * Protocol is optional; matching is protocol-agnostic and normalized.
334
334
  *
335
335
  * @example ['example.com', 'app.example.com', 'localhost:3000']
336
- * @see {@link https://v2.c15t.com/docs/self-host/api/configuration}
336
+ * @see {@link https://c15t.com/docs/self-host/api/configuration}
337
337
  */
338
338
  trustedOrigins: string[];
339
339
  /** Logger configuration. */
@@ -373,7 +373,7 @@ export interface C15TOptions {
373
373
  * explicit no-banner mode. In production, prefer including a default policy
374
374
  * so unmatched traffic still resolves deterministically.
375
375
  *
376
- * @see {@link https://v2.c15t.com/docs/self-host/guides/policy-packs}
376
+ * @see {@link https://c15t.com/docs/self-host/guides/policy-packs}
377
377
  */
378
378
  policyPacks?: PolicyConfig[];
379
379
  /**
@@ -386,7 +386,7 @@ export interface C15TOptions {
386
386
  /**
387
387
  * OpenAPI spec generation and documentation UI options.
388
388
  *
389
- * @see {@link https://v2.c15t.com/docs/self-host/api/endpoints}
389
+ * @see {@link https://c15t.com/docs/self-host/api/endpoints}
390
390
  */
391
391
  openapi?: OpenAPIOptions;
392
392
  /**
@@ -394,20 +394,20 @@ export interface C15TOptions {
394
394
  * Telemetry is opt-in and disabled by default.
395
395
  * Users must provide their own SDK setup (Node, Bun, edge, etc.).
396
396
  *
397
- * @see {@link https://v2.c15t.com/docs/self-host/guides/observability}
397
+ * @see {@link https://c15t.com/docs/self-host/guides/observability}
398
398
  */
399
399
  telemetry?: TelemetryOptions;
400
400
  /**
401
401
  * IP address tracking and masking options.
402
402
  *
403
- * @see {@link https://v2.c15t.com/docs/self-host/api/configuration}
403
+ * @see {@link https://c15t.com/docs/self-host/api/configuration}
404
404
  */
405
405
  ipAddress?: IPAddressOptions;
406
406
  /**
407
407
  * Cache configuration for external persistent storage.
408
408
  * Used for caching GVL and other data.
409
409
  *
410
- * @see {@link https://v2.c15t.com/docs/self-host/guides/caching}
410
+ * @see {@link https://c15t.com/docs/self-host/guides/caching}
411
411
  */
412
412
  cache?: CacheOptions;
413
413
  /**
@@ -425,7 +425,7 @@ export interface C15TOptions {
425
425
  * Disabled by default - most users don't need IAB TCF.
426
426
  * Set enabled: true to activate IAB support.
427
427
  *
428
- * @see {@link https://v2.c15t.com/docs/self-host/guides/iab-tcf}
428
+ * @see {@link https://c15t.com/docs/self-host/guides/iab-tcf}
429
429
  */
430
430
  iab?: IABOptions;
431
431
  /**
@@ -1 +1 @@
1
- export declare const version = "2.0.0-rc.8";
1
+ export declare const version = "2.0.0";
@@ -10,24 +10,24 @@ All options are passed to `c15tInstance()`. Only `adapter` and `trustedOrigins`
10
10
 
11
11
  |Property|Type|Description|Default|Required|
12
12
  |:--|:--|:--|:--|:--:|
13
- |adapter|[FumaDBAdapter](https://v2.c15t.com/docs/self-host/guides/database-setup)|The database adapter to use.|-|✅ Required|
13
+ |adapter|[FumaDBAdapter](https://c15t.com/docs/self-host/guides/database-setup)|The database adapter to use.|-|✅ Required|
14
14
  |tenantId|string \|undefined|Tenant ID for multi-tenant deployments. When set, all database queries are automatically scoped to this tenant.|-|Optional|
15
- |tablePrefix|[string \|undefined](https://v2.c15t.com/docs/self-host/guides/database-setup)|Optional prefix for all database table names. Useful when sharing a database with other applications to avoid naming conflicts.|-|Optional|
16
- |appName|[string \|undefined](https://v2.c15t.com/docs/self-host/api/configuration)|Application name used as backend metadata and identity. Returned by \`/init\` (\`appName\`), used in logs, telemetry defaults (\`service.name\`), and cache key prefixing.|"c15t"|Optional|
17
- |basePath|[string \|undefined](https://v2.c15t.com/docs/self-host/api/endpoints)|Base path prefix for all API routes (e.g. \`/api/self-host\`).|-|Optional|
18
- |trustedOrigins|[string\[\]](https://v2.c15t.com/docs/self-host/api/configuration)|Allowed origins for CORS. Required for browser-based consent collection. Protocol is optional; matching is protocol-agnostic and normalized.|-|✅ Required|
15
+ |tablePrefix|[string \|undefined](https://c15t.com/docs/self-host/guides/database-setup)|Optional prefix for all database table names. Useful when sharing a database with other applications to avoid naming conflicts.|-|Optional|
16
+ |appName|[string \|undefined](https://c15t.com/docs/self-host/api/configuration)|Application name used as backend metadata and identity. Returned by \`/init\` (\`appName\`), used in logs, telemetry defaults (\`service.name\`), and cache key prefixing.|"c15t"|Optional|
17
+ |basePath|[string \|undefined](https://c15t.com/docs/self-host/api/endpoints)|Base path prefix for all API routes (e.g. \`/api/self-host\`).|-|Optional|
18
+ |trustedOrigins|[string\[\]](https://c15t.com/docs/self-host/api/configuration)|Allowed origins for CORS. Required for browser-based consent collection. Protocol is optional; matching is protocol-agnostic and normalized.|-|✅ Required|
19
19
  |logger|LoggerOptions \|undefined|Logger configuration.|-|Optional|
20
20
  |disableGeoLocation|boolean \|undefined|Disables the use of Geo Location to determine the jurisdiction. When enabled, the jurisdiction will be set to "GDPR" to show the strictest version of the banner as we don't know the jurisdiction in this case.|false|Optional|
21
21
  |customTranslations|Record\<string, Partial\<Translations>> \|undefined|Override base translations.|-|Optional|
22
22
  |i18n|I18nOptions \|undefined|Internationalization message profiles used by runtime policies.|-|Optional|
23
- |policyPacks|[PolicyConfig \|undefined](https://v2.c15t.com/docs/self-host/guides/policy-packs)|Runtime regional policy pack resolved per request.|-|Optional|
23
+ |policyPacks|[PolicyConfig \|undefined](https://c15t.com/docs/self-host/guides/policy-packs)|Runtime regional policy pack resolved per request.|-|Optional|
24
24
  |branding|"c15t" \|"consent" \|"none" \|"inth" \|undefined|Select which branding to show in the consent banner. Use "inth" for the INTH brand. "consent" is a deprecated alias for "inth". Use "none" to hide branding.|"c15t"|Optional|
25
- |openapi|[OpenAPIOptions \|undefined](https://v2.c15t.com/docs/self-host/api/endpoints)|OpenAPI spec generation and documentation UI options.|-|Optional|
26
- |telemetry|[TelemetryOptions \|undefined](https://v2.c15t.com/docs/self-host/guides/observability)|OpenTelemetry configuration for tracing and metrics. Telemetry is opt-in and disabled by default. Users must provide their own SDK setup (Node, Bun, edge, etc.).|-|Optional|
27
- |ipAddress|[IPAddressOptions \|undefined](https://v2.c15t.com/docs/self-host/api/configuration)|IP address tracking and masking options.|-|Optional|
28
- |cache|[CacheOptions \|undefined](https://v2.c15t.com/docs/self-host/guides/caching)|Cache configuration for external persistent storage. Used for caching GVL and other data.|-|Optional|
25
+ |openapi|[OpenAPIOptions \|undefined](https://c15t.com/docs/self-host/api/endpoints)|OpenAPI spec generation and documentation UI options.|-|Optional|
26
+ |telemetry|[TelemetryOptions \|undefined](https://c15t.com/docs/self-host/guides/observability)|OpenTelemetry configuration for tracing and metrics. Telemetry is opt-in and disabled by default. Users must provide their own SDK setup (Node, Bun, edge, etc.).|-|Optional|
27
+ |ipAddress|[IPAddressOptions \|undefined](https://c15t.com/docs/self-host/api/configuration)|IP address tracking and masking options.|-|Optional|
28
+ |cache|[CacheOptions \|undefined](https://c15t.com/docs/self-host/guides/caching)|Cache configuration for external persistent storage. Used for caching GVL and other data.|-|Optional|
29
29
  |apiKeys|string\[] \|undefined|API keys for authenticated endpoints. Used for server-side endpoints like GET /subjects.|-|Optional|
30
- |iab|[IABOptions \|undefined](https://v2.c15t.com/docs/self-host/guides/iab-tcf)|IAB TCF configuration including GVL, CMP registration, and custom vendors. Disabled by default - most users don't need IAB TCF. Set enabled: true to activate IAB support.|-|Optional|
30
+ |iab|[IABOptions \|undefined](https://c15t.com/docs/self-host/guides/iab-tcf)|IAB TCF configuration including GVL, CMP registration, and custom vendors. Disabled by default - most users don't need IAB TCF. Set enabled: true to activate IAB support.|-|Optional|
31
31
  |policySnapshot|PolicySnapshotOptions \|undefined|Optional signed policy snapshots used to keep /init and /subjects consistent.|-|Optional|
32
32
  |legalDocumentSnapshot|LegalDocumentSnapshotOptions \|undefined|Optional signed legal-document snapshots issued by external document renderers.|-|Optional|
33
33
  |background|BackgroundOptions \|undefined|Optional background task runner for non-critical side effects.|-|Optional|
@@ -95,10 +95,10 @@ To create & update the database you can use the migrator which is included in th
95
95
 
96
96
  |Package manager|Command|
97
97
  |:--|:--|
98
- |npm|`npx @c15t/cli@rc`|
99
- |pnpm|`pnpm dlx @c15t/cli@rc`|
100
- |yarn|`yarn dlx @c15t/cli@rc`|
101
- |bun|`bunx @c15t/cli@rc`|
98
+ |npm|`npx @c15t/cli`|
99
+ |pnpm|`pnpm dlx @c15t/cli`|
100
+ |yarn|`yarn dlx @c15t/cli`|
101
+ |bun|`bunx @c15t/cli`|
102
102
 
103
103
  ## Table Prefix
104
104
 
@@ -6,7 +6,7 @@ The c15t backend optionally supports [IAB TCF v2.3](https://iabeurope.eu/transpa
6
6
 
7
7
  ## CMP Registration
8
8
 
9
- [consent.io](https://consent.io) is pending validation as an IAB Europe-registered CMP for c15t. Once approved, when using consent.io as your hosted backend, the CMP ID will be automatically provided to clients — no additional configuration needed.
9
+ [inth.com](https://inth.com) is pending validation as an IAB Europe-registered CMP for c15t. Once approved, when using inth.com as your hosted backend, the CMP ID will be automatically provided to clients — no additional configuration needed.
10
10
 
11
11
  If you self-host and have your own CMP registration with IAB Europe, configure your CMP ID via `iab.cmpId`. This value is returned to clients in the `/init` response so they use the correct CMP identity in TC Strings.
12
12
 
@@ -14,7 +14,7 @@ If you self-host and have your own CMP registration with IAB Europe, configure y
14
14
  > A valid (non-zero) CMP ID is required for IAB TCF compliance. If neither the backend nor the client provides a CMP ID, IAB initialization will fail with an error.
15
15
  >
16
16
  > ℹ️ **Info:**
17
- > If you heavily customize or build your own IAB banner or dialog (rather than using the default IABConsentBanner and IABConsentDialog components provided by c15t), you cannot use consent.io's CMP ID. You must register your own CMP with IAB Europe and configure your CMP ID via iab.cmpId.
17
+ > If you heavily customize or build your own IAB banner or dialog (rather than using the default IABConsentBanner and IABConsentDialog components provided by c15t), you cannot use inth.com's CMP ID. You must register your own CMP with IAB Europe and configure your CMP ID via iab.cmpId.
18
18
 
19
19
  ## Enable IAB
20
20
 
@@ -25,13 +25,13 @@ export const c15t = c15tInstance({
25
25
  // ...
26
26
  iab: {
27
27
  enabled: true,
28
- cmpId: 10, // your registered CMP ID (consent.io provides this automatically)
28
+ cmpId: 10, // your registered CMP ID (inth.com provides this automatically)
29
29
  vendorIds: [755, 52, 69], // only include vendors you use
30
30
  },
31
31
  });
32
32
  ```
33
33
 
34
- The backend fetches the GVL from `https://gvl.consent.io` by default and caches it. The `/init` endpoint returns the filtered GVL and your CMP ID to the frontend.
34
+ The backend fetches the GVL from `https://gvl.inth.com` by default and caches it. The `/init` endpoint returns the filtered GVL and your CMP ID to the frontend.
35
35
 
36
36
  ## Custom GVL Endpoint
37
37
 
@@ -6,7 +6,7 @@ The `@c15t/backend` package gives you a fully self-hosted consent management API
6
6
 
7
7
  The backend exposes a standard `(request: Request) => Promise<Response>` handler, so it works with any JavaScript runtime (Node.js, Bun, Deno, Cloudflare Workers) and any HTTP framework.
8
8
 
9
- If you want a fully managed experience we recommend using [consent.io](https://consent.io).
9
+ If you want a fully managed experience we recommend using [inth.com](https://inth.com).
10
10
 
11
11
  ## Installation
12
12
 
@@ -76,10 +76,10 @@ If you want a fully managed experience we recommend using [consent.io](https://c
76
76
 
77
77
  |Package manager|Command|
78
78
  |:--|:--|
79
- |npm|`npx @c15t/cli@rc`|
80
- |pnpm|`pnpm dlx @c15t/cli@rc`|
81
- |yarn|`yarn dlx @c15t/cli@rc`|
82
- |bun|`bunx @c15t/cli@rc`|
79
+ |npm|`npx @c15t/cli`|
80
+ |pnpm|`pnpm dlx @c15t/cli`|
81
+ |yarn|`yarn dlx @c15t/cli`|
82
+ |bun|`bunx @c15t/cli`|
83
83
 
84
84
  See Database Setup for adapter-specific migration guides. If you plan to use policy packs with runtime audit storage, also apply the runtime policy decision migration from the Policy Packs guide.
85
85
 
@@ -119,10 +119,10 @@ Install c15t agent skills to let AI agents help with styling, i18n, scripts & ot
119
119
 
120
120
  |Package manager|Command|
121
121
  |:--|:--|
122
- |npm|`npx @c15t/cli@rc skills`|
123
- |pnpm|`pnpm dlx @c15t/cli@rc skills`|
124
- |yarn|`yarn dlx @c15t/cli@rc skills`|
125
- |bun|`bunx @c15t/cli@rc skills`|
122
+ |npm|`npx @c15t/cli skills`|
123
+ |pnpm|`pnpm dlx @c15t/cli skills`|
124
+ |yarn|`yarn dlx @c15t/cli skills`|
125
+ |bun|`bunx @c15t/cli skills`|
126
126
 
127
127
  See [AI Agents](/docs/ai-agents) for bundled package docs and agent skills.
128
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c15t/backend",
3
- "version": "2.0.0-rc.8",
3
+ "version": "2.0.0",
4
4
  "description": "Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and preferences centre. Webhooks, audit logs, storage adapters. Self host or use consent.io",
5
5
  "keywords": [
6
6
  "consent",
@@ -25,7 +25,7 @@
25
25
  "url": "https://github.com/c15t/c15t.git",
26
26
  "directory": "packages/backend"
27
27
  },
28
- "license": "GPL-3.0-only",
28
+ "license": "Apache-2.0",
29
29
  "type": "module",
30
30
  "exports": {
31
31
  ".": {
@@ -123,9 +123,9 @@
123
123
  "test:watch": "bun prebuild && vitest"
124
124
  },
125
125
  "dependencies": {
126
- "@c15t/logger": "1.0.2-rc.1",
127
- "@c15t/schema": "2.0.0-rc.5",
128
- "@c15t/translations": "2.0.0-rc.8",
126
+ "@c15t/logger": "2.0.0",
127
+ "@c15t/schema": "2.0.0",
128
+ "@c15t/translations": "2.0.0",
129
129
  "@hono/standard-validator": "^0.2.2",
130
130
  "@hono/valibot-validator": "0.6.1",
131
131
  "@opentelemetry/api": "1.9.1",
@@ -141,7 +141,7 @@
141
141
  "valibot": "1.3.1"
142
142
  },
143
143
  "devDependencies": {
144
- "@c15t/typescript-config": "0.0.1-beta.1",
144
+ "@c15t/typescript-config": "0.0.1",
145
145
  "@c15t/vitest-config": "1.0.0",
146
146
  "@opentelemetry/sdk-trace-base": "^2.6.1",
147
147
  "@types/node": "25.5.0",