@c15t/backend 2.0.0 → 2.0.2
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 +10 -10
- package/dist/302.js +2 -2
- package/dist/915.js +1 -1
- package/dist/942.js +5 -0
- package/dist/cache.cjs +1 -1
- package/dist/core.cjs +10 -5
- package/dist/core.js +4 -2
- package/dist/edge.cjs +14 -9
- package/dist/edge.js +11 -9
- package/dist/router.cjs +2 -2
- package/dist-types/cache/gvl-resolver.d.ts +3 -3
- package/dist-types/middleware/cors/matches-wildcard.d.ts +13 -0
- package/dist-types/types/index.d.ts +1 -1
- package/dist-types/version.d.ts +1 -1
- package/docs/api/configuration.md +1 -1
- package/docs/guides/iab-tcf.md +8 -5
- package/package.json +7 -4
- package/readme.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://c15t.com?utm_source=
|
|
2
|
+
<a href="https://c15t.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fbackend" target="_blank" rel="noopener noreferrer">
|
|
3
3
|
<picture>
|
|
4
4
|
<source media="(prefers-color-scheme: dark)" srcset="../../docs/assets/c15t-banner-readme-dark.svg" type="image/svg+xml">
|
|
5
5
|
<img src="../../docs/assets/c15t-banner-readme-light.svg" alt="c15t Banner" type="image/svg+xml">
|
|
6
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
|
-
<br />
|
|
9
|
-
<h1 align="center">@c15t/backend: Consent Management Backend</h1>
|
|
10
8
|
</p>
|
|
11
9
|
|
|
10
|
+
# @c15t/backend: Consent Management Backend
|
|
11
|
+
|
|
12
12
|
[](https://github.com/c15t/c15t)
|
|
13
13
|
[](https://github.com/c15t/c15t/actions/workflows/ci.yml)
|
|
14
14
|
[](https://github.com/c15t/c15t/blob/main/LICENSE.md)
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
[](https://github.com/c15t/c15t/commits/main)
|
|
19
19
|
[](https://github.com/c15t/c15t/issues)
|
|
20
20
|
|
|
21
|
-
Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and
|
|
21
|
+
Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and preference center. Webhooks, audit logs, storage adapters. Self-host or use inth.com
|
|
22
22
|
|
|
23
23
|
## Key Features
|
|
24
24
|
|
|
@@ -54,24 +54,24 @@ For further information, guides, and examples visit the [reference documentation
|
|
|
54
54
|
|
|
55
55
|
- Join our [Discord community](https://c15t.link/discord)
|
|
56
56
|
- Open an issue on our [GitHub repository](https://github.com/c15t/c15t/issues)
|
|
57
|
-
- Visit [
|
|
58
|
-
- Contact our support team via email [support@
|
|
57
|
+
- Visit [inth.com](https://inth.com) and use the chat widget
|
|
58
|
+
- Contact our support team via email [support@inth.com](mailto:support@inth.com)
|
|
59
59
|
|
|
60
60
|
## Contributing
|
|
61
61
|
|
|
62
|
-
- We're open to all community contributions
|
|
62
|
+
- We're open to all community contributions.
|
|
63
63
|
- Read our [Contribution Guidelines](https://c15t.com/docs/oss/contributing)
|
|
64
64
|
- Review our [Code of Conduct](https://c15t.com/docs/oss/code-of-conduct)
|
|
65
65
|
- Fork the repository
|
|
66
66
|
- Create a new branch for your feature
|
|
67
67
|
- Submit a pull request
|
|
68
|
-
- **All contributions, big or small, are welcome and appreciated
|
|
68
|
+
- **All contributions, big or small, are welcome and appreciated.**
|
|
69
69
|
|
|
70
70
|
## Security
|
|
71
71
|
|
|
72
72
|
If you believe you have found a security vulnerability in c15t, we encourage you to **_responsibly disclose this and NOT open a public issue_**. We will investigate all legitimate reports.
|
|
73
73
|
|
|
74
|
-
Our preference is that you make use of GitHub's private vulnerability reporting feature to disclose potential security vulnerabilities in our
|
|
74
|
+
Our preference is that you make use of GitHub's private vulnerability reporting feature to disclose potential security vulnerabilities in our open-source software. To do this, please visit [https://github.com/c15t/c15t/security](https://github.com/c15t/c15t/security) and click the "Report a vulnerability" button.
|
|
75
75
|
|
|
76
76
|
### Security Policy
|
|
77
77
|
|
|
@@ -86,4 +86,4 @@ Our preference is that you make use of GitHub's private vulnerability reporting
|
|
|
86
86
|
|
|
87
87
|
---
|
|
88
88
|
|
|
89
|
-
**Built by [Inth](https://inth.com?utm_source=
|
|
89
|
+
**Built by [Inth](https://inth.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fbackend)**
|
package/dist/302.js
CHANGED
|
@@ -13,7 +13,7 @@ function createTelemetryOptions(appName = 'c15t', telemetryConfig, tenantId) {
|
|
|
13
13
|
const defaultAttributes = {
|
|
14
14
|
...telemetryConfig?.defaultAttributes || {},
|
|
15
15
|
'service.name': String(appName),
|
|
16
|
-
'service.version': "2.0.
|
|
16
|
+
'service.version': "2.0.2"
|
|
17
17
|
};
|
|
18
18
|
if (tenantId) defaultAttributes['tenant.id'] = tenantId;
|
|
19
19
|
const config = {
|
|
@@ -368,7 +368,7 @@ function createCacheKey(appName, namespace, ...parts) {
|
|
|
368
368
|
];
|
|
369
369
|
return allParts.join(':');
|
|
370
370
|
}
|
|
371
|
-
const GVL_ENDPOINT = 'https://gvl.
|
|
371
|
+
const GVL_ENDPOINT = 'https://gvl.inth.app';
|
|
372
372
|
const inflightRequests = new Map();
|
|
373
373
|
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
374
374
|
const sortedVendorIds = vendorIds ? [
|
package/dist/915.js
CHANGED
package/dist/942.js
ADDED
package/dist/cache.cjs
CHANGED
|
@@ -400,7 +400,7 @@ function createCacheKey(appName, namespace, ...parts) {
|
|
|
400
400
|
];
|
|
401
401
|
return allParts.join(':');
|
|
402
402
|
}
|
|
403
|
-
const GVL_ENDPOINT = 'https://gvl.
|
|
403
|
+
const GVL_ENDPOINT = 'https://gvl.inth.app';
|
|
404
404
|
const inflightRequests = new Map();
|
|
405
405
|
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
406
406
|
const sortedVendorIds = vendorIds ? [
|
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: ()=>"2.0.
|
|
352
|
+
version: ()=>"2.0.2",
|
|
353
353
|
c15tInstance: ()=>c15tInstance,
|
|
354
354
|
EEA_COUNTRY_CODES: ()=>types_namespaceObject.EEA_COUNTRY_CODES,
|
|
355
355
|
EU_COUNTRY_CODES: ()=>types_namespaceObject.EU_COUNTRY_CODES,
|
|
@@ -393,6 +393,10 @@ var __webpack_exports__ = {};
|
|
|
393
393
|
const token = extractBearerToken(authHeader);
|
|
394
394
|
return validateApiKey(token, validKeys);
|
|
395
395
|
}
|
|
396
|
+
function matchesWildcard(origin, wildcardPattern) {
|
|
397
|
+
const wildcardDomain = wildcardPattern.slice(2);
|
|
398
|
+
return origin !== wildcardDomain && origin.endsWith(`.${wildcardDomain}`);
|
|
399
|
+
}
|
|
396
400
|
const WWW_REGEX = /^www\./;
|
|
397
401
|
const PROTOCOL_WWW_REGEX = /^https?:\/\/(www\.)?/;
|
|
398
402
|
const SUPPORTED_METHODS = [
|
|
@@ -476,6 +480,7 @@ var __webpack_exports__ = {};
|
|
|
476
480
|
const isTrusted = expandedTrusted.some((trusted)=>{
|
|
477
481
|
const normalizedTrusted = normalizeOrigin(trusted);
|
|
478
482
|
if ('localhost' === normalizedTrusted) return 'localhost' === normalizedOrigin || normalizedOrigin.startsWith('localhost:') || '127.0.0.1' === normalizedOrigin || normalizedOrigin.startsWith('127.0.0.1:') || '[::1]' === normalizedOrigin || normalizedOrigin.startsWith('[::1]:');
|
|
483
|
+
if (normalizedTrusted.startsWith('*.')) return matchesWildcard(normalizedOrigin, normalizedTrusted);
|
|
479
484
|
return normalizedTrusted === normalizedOrigin;
|
|
480
485
|
});
|
|
481
486
|
return isTrusted ? origin : null;
|
|
@@ -752,7 +757,7 @@ var __webpack_exports__ = {};
|
|
|
752
757
|
const defaultAttributes = {
|
|
753
758
|
...telemetryConfig?.defaultAttributes || {},
|
|
754
759
|
'service.name': String(appName),
|
|
755
|
-
'service.version': "2.0.
|
|
760
|
+
'service.version': "2.0.2"
|
|
756
761
|
};
|
|
757
762
|
if (tenantId) defaultAttributes['tenant.id'] = tenantId;
|
|
758
763
|
const config = {
|
|
@@ -2028,7 +2033,7 @@ var __webpack_exports__ = {};
|
|
|
2028
2033
|
].sort((a, b)=>a - b).join(',') : 'all';
|
|
2029
2034
|
return `${appName}:gvl:${language}:${sortedIds}`;
|
|
2030
2035
|
}
|
|
2031
|
-
const GVL_ENDPOINT = 'https://gvl.
|
|
2036
|
+
const GVL_ENDPOINT = 'https://gvl.inth.app';
|
|
2032
2037
|
const inflightRequests = new Map();
|
|
2033
2038
|
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
2034
2039
|
const sortedVendorIds = vendorIds ? [
|
|
@@ -2671,7 +2676,7 @@ Use for geo-targeted consent banners and regional compliance.`,
|
|
|
2671
2676
|
try {
|
|
2672
2677
|
await ctx.db.findFirst('subject', {});
|
|
2673
2678
|
return c.json({
|
|
2674
|
-
version: "2.0.
|
|
2679
|
+
version: "2.0.2",
|
|
2675
2680
|
timestamp: new Date(),
|
|
2676
2681
|
client: clientInfo
|
|
2677
2682
|
});
|
|
@@ -3873,7 +3878,7 @@ Use for health checks, load balancer probes, and debugging. Performs a lightweig
|
|
|
3873
3878
|
openapi: '3.1.0',
|
|
3874
3879
|
info: {
|
|
3875
3880
|
title: options.appName || 'c15t API',
|
|
3876
|
-
version: "2.0.
|
|
3881
|
+
version: "2.0.2",
|
|
3877
3882
|
description: 'API for consent management'
|
|
3878
3883
|
},
|
|
3879
3884
|
servers: [
|
package/dist/core.js
CHANGED
|
@@ -7,6 +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 { matchesWildcard } from "./942.js";
|
|
10
11
|
import { extractErrorMessage, withDatabaseSpan, getTraceContext as create_telemetry_options_getTraceContext, createRequestSpan, handleSpanError, createTelemetryOptions, getMetrics, isTelemetryEnabled, withSpanContext } from "./302.js";
|
|
11
12
|
import { createLegalDocumentRoutes, createSubjectRoutes, generateUniqueId, createStatusRoute, createInitRoute, createConsentRoutes, policyRegistry } from "./915.js";
|
|
12
13
|
import { validateMessages, inspectPolicies as policy_inspectPolicies } from "./583.js";
|
|
@@ -119,6 +120,7 @@ function createCORSOptions(trustedOrigins) {
|
|
|
119
120
|
const isTrusted = expandedTrusted.some((trusted)=>{
|
|
120
121
|
const normalizedTrusted = normalizeOrigin(trusted);
|
|
121
122
|
if ('localhost' === normalizedTrusted) return 'localhost' === normalizedOrigin || normalizedOrigin.startsWith('localhost:') || '127.0.0.1' === normalizedOrigin || normalizedOrigin.startsWith('127.0.0.1:') || '[::1]' === normalizedOrigin || normalizedOrigin.startsWith('[::1]:');
|
|
123
|
+
if (normalizedTrusted.startsWith('*.')) return matchesWildcard(normalizedOrigin, normalizedTrusted);
|
|
122
124
|
return normalizedTrusted === normalizedOrigin;
|
|
123
125
|
});
|
|
124
126
|
return isTrusted ? origin : null;
|
|
@@ -765,7 +767,7 @@ const c15tInstance = (options)=>{
|
|
|
765
767
|
openapi: '3.1.0',
|
|
766
768
|
info: {
|
|
767
769
|
title: options.appName || 'c15t API',
|
|
768
|
-
version: "2.0.
|
|
770
|
+
version: "2.0.2",
|
|
769
771
|
description: 'API for consent management'
|
|
770
772
|
},
|
|
771
773
|
servers: [
|
|
@@ -879,7 +881,7 @@ const c15tInstance = (options)=>{
|
|
|
879
881
|
getDocsUI
|
|
880
882
|
};
|
|
881
883
|
};
|
|
882
|
-
var core_version = "2.0.
|
|
884
|
+
var core_version = "2.0.2";
|
|
883
885
|
export { defineConfig } from "./define-config.js";
|
|
884
886
|
export { inspectPolicies } from "./583.js";
|
|
885
887
|
export { EEA_COUNTRY_CODES, EU_COUNTRY_CODES, POLICY_MATCH_DATASET_VERSION, UK_COUNTRY_CODES, c15tInstance, core_version as version, policyBuilder, policyMatchers, policyPackPresets };
|
package/dist/edge.cjs
CHANGED
|
@@ -348,7 +348,7 @@ function createGVLCacheKey(appName, language, vendorIds) {
|
|
|
348
348
|
].sort((a, b)=>a - b).join(',') : 'all';
|
|
349
349
|
return `${appName}:gvl:${language}:${sortedIds}`;
|
|
350
350
|
}
|
|
351
|
-
const GVL_ENDPOINT = 'https://gvl.
|
|
351
|
+
const GVL_ENDPOINT = 'https://gvl.inth.app';
|
|
352
352
|
const inflightRequests = new Map();
|
|
353
353
|
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
354
354
|
const sortedVendorIds = vendorIds ? [
|
|
@@ -908,13 +908,12 @@ async function resolveInitPayload(request, options, logger) {
|
|
|
908
908
|
}
|
|
909
909
|
};
|
|
910
910
|
}
|
|
911
|
-
|
|
912
|
-
function matchesWildcard(hostname, wildcardPattern, logger) {
|
|
911
|
+
function matchesWildcard(origin, wildcardPattern) {
|
|
913
912
|
const wildcardDomain = wildcardPattern.slice(2);
|
|
914
|
-
|
|
915
|
-
logger?.debug(`Wildcard match result: ${isValid} ${hostname} ends with .${wildcardDomain}`);
|
|
916
|
-
return isValid;
|
|
913
|
+
return origin !== wildcardDomain && origin.endsWith(`.${wildcardDomain}`);
|
|
917
914
|
}
|
|
915
|
+
const STRIP_REGEX = /^(?:https?:\/\/)|^(?:wss?:\/\/)|(?:\/+$)|(?::\d+$)/g;
|
|
916
|
+
const WWW_REGEX = /^www\./;
|
|
918
917
|
function isOriginTrusted(origin, trustedDomains, logger) {
|
|
919
918
|
try {
|
|
920
919
|
if (0 === trustedDomains.length) throw new Error('No trusted domains');
|
|
@@ -933,9 +932,15 @@ function isOriginTrusted(origin, trustedDomains, logger) {
|
|
|
933
932
|
}
|
|
934
933
|
const strippedDomain = domain.replace(STRIP_REGEX, '').toLowerCase();
|
|
935
934
|
logger?.debug(`Checking against stripped domain: ${strippedDomain}`);
|
|
936
|
-
if (strippedDomain.startsWith('*.'))
|
|
937
|
-
|
|
938
|
-
|
|
935
|
+
if (strippedDomain.startsWith('*.')) {
|
|
936
|
+
const isMatch = matchesWildcard(originHostname, strippedDomain);
|
|
937
|
+
logger?.debug(`Wildcard match result: ${isMatch} ${originHostname} matches ${strippedDomain}`);
|
|
938
|
+
return isMatch;
|
|
939
|
+
}
|
|
940
|
+
const normalizedOriginHostname = originHostname.replace(WWW_REGEX, '');
|
|
941
|
+
const normalizedDomain = strippedDomain.replace(WWW_REGEX, '');
|
|
942
|
+
const isMatch = normalizedOriginHostname === normalizedDomain;
|
|
943
|
+
logger?.debug(`Exact match result: ${isMatch} ${normalizedOriginHostname} === ${normalizedDomain}`);
|
|
939
944
|
return isMatch;
|
|
940
945
|
});
|
|
941
946
|
} catch (error) {
|
package/dist/edge.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { createLogger } from "@c15t/logger";
|
|
2
|
+
import { matchesWildcard } from "./942.js";
|
|
2
3
|
import { inspectPolicies as policy_inspectPolicies, policy_resolvePolicySync, resolveInitPayload, validateMessages, checkJurisdiction } from "./583.js";
|
|
3
4
|
const STRIP_REGEX = /^(?:https?:\/\/)|^(?:wss?:\/\/)|(?:\/+$)|(?::\d+$)/g;
|
|
4
|
-
|
|
5
|
-
const wildcardDomain = wildcardPattern.slice(2);
|
|
6
|
-
const isValid = hostname !== wildcardDomain && hostname.endsWith(`.${wildcardDomain}`);
|
|
7
|
-
logger?.debug(`Wildcard match result: ${isValid} ${hostname} ends with .${wildcardDomain}`);
|
|
8
|
-
return isValid;
|
|
9
|
-
}
|
|
5
|
+
const WWW_REGEX = /^www\./;
|
|
10
6
|
function isOriginTrusted(origin, trustedDomains, logger) {
|
|
11
7
|
try {
|
|
12
8
|
if (0 === trustedDomains.length) throw new Error('No trusted domains');
|
|
@@ -25,9 +21,15 @@ function isOriginTrusted(origin, trustedDomains, logger) {
|
|
|
25
21
|
}
|
|
26
22
|
const strippedDomain = domain.replace(STRIP_REGEX, '').toLowerCase();
|
|
27
23
|
logger?.debug(`Checking against stripped domain: ${strippedDomain}`);
|
|
28
|
-
if (strippedDomain.startsWith('*.'))
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
if (strippedDomain.startsWith('*.')) {
|
|
25
|
+
const isMatch = matchesWildcard(originHostname, strippedDomain);
|
|
26
|
+
logger?.debug(`Wildcard match result: ${isMatch} ${originHostname} matches ${strippedDomain}`);
|
|
27
|
+
return isMatch;
|
|
28
|
+
}
|
|
29
|
+
const normalizedOriginHostname = originHostname.replace(WWW_REGEX, '');
|
|
30
|
+
const normalizedDomain = strippedDomain.replace(WWW_REGEX, '');
|
|
31
|
+
const isMatch = normalizedOriginHostname === normalizedDomain;
|
|
32
|
+
logger?.debug(`Exact match result: ${isMatch} ${normalizedOriginHostname} === ${normalizedDomain}`);
|
|
31
33
|
return isMatch;
|
|
32
34
|
});
|
|
33
35
|
} catch (error) {
|
package/dist/router.cjs
CHANGED
|
@@ -550,7 +550,7 @@ function createGVLCacheKey(appName, language, vendorIds) {
|
|
|
550
550
|
].sort((a, b)=>a - b).join(',') : 'all';
|
|
551
551
|
return `${appName}:gvl:${language}:${sortedIds}`;
|
|
552
552
|
}
|
|
553
|
-
const GVL_ENDPOINT = 'https://gvl.
|
|
553
|
+
const GVL_ENDPOINT = 'https://gvl.inth.app';
|
|
554
554
|
const inflightRequests = new Map();
|
|
555
555
|
async function fetchGVLWithLanguage(language, vendorIds, endpoint = GVL_ENDPOINT) {
|
|
556
556
|
const sortedVendorIds = vendorIds ? [
|
|
@@ -1246,7 +1246,7 @@ const statusHandler = async (c)=>{
|
|
|
1246
1246
|
try {
|
|
1247
1247
|
await ctx.db.findFirst('subject', {});
|
|
1248
1248
|
return c.json({
|
|
1249
|
-
version: "2.0.
|
|
1249
|
+
version: "2.0.2",
|
|
1250
1250
|
timestamp: new Date(),
|
|
1251
1251
|
client: clientInfo
|
|
1252
1252
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 1. Bundled translations (checked first)
|
|
6
6
|
* 2. In-memory cache
|
|
7
7
|
* 3. External cache (Redis/KV)
|
|
8
|
-
* 4. Fetch from gvl.
|
|
8
|
+
* 4. Fetch from gvl.inth.app
|
|
9
9
|
*
|
|
10
10
|
* @packageDocumentation
|
|
11
11
|
*/
|
|
@@ -38,7 +38,7 @@ export interface GVLResolverOptions {
|
|
|
38
38
|
vendorIds?: number[];
|
|
39
39
|
/**
|
|
40
40
|
* Override the default GVL endpoint.
|
|
41
|
-
* @default 'https://gvl.
|
|
41
|
+
* @default 'https://gvl.inth.app'
|
|
42
42
|
*/
|
|
43
43
|
endpoint?: string;
|
|
44
44
|
}
|
|
@@ -63,7 +63,7 @@ export interface GVLResolver {
|
|
|
63
63
|
* 1. **Bundled** - Check bundled translations (0ms)
|
|
64
64
|
* 2. **In-Memory** - Check worker/process memory cache (0ms)
|
|
65
65
|
* 3. **External Cache** - Check Redis/KV if configured (20-40ms)
|
|
66
|
-
* 4. **Fetch** - Fetch from gvl.
|
|
66
|
+
* 4. **Fetch** - Fetch from gvl.inth.app with Accept-Language (100-300ms)
|
|
67
67
|
*
|
|
68
68
|
* @param options - Resolver configuration
|
|
69
69
|
* @returns A GVL resolver instance
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared wildcard matching utilities for CORS origin checks.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Checks if an origin matches a wildcard domain pattern.
|
|
8
|
+
*
|
|
9
|
+
* @param origin - Hostname or normalized origin to check
|
|
10
|
+
* @param wildcardPattern - Wildcard pattern (e.g. *.example.com)
|
|
11
|
+
* @returns true if the origin is a subdomain of the wildcard pattern
|
|
12
|
+
*/
|
|
13
|
+
export declare function matchesWildcard(origin: string, wildcardPattern: string): boolean;
|
package/dist-types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.0.
|
|
1
|
+
export declare const version = "2.0.2";
|
|
@@ -157,7 +157,7 @@ OpenAPI specification options
|
|
|
157
157
|
|cmpId|number \|undefined|CMP ID registered with IAB Europe. This is returned to clients via the /init endpoint so they can use the correct CMP identity in TC Strings. See List of registered CMPs: https\://iabeurope.eu/cmp-list/|-|Optional|
|
|
158
158
|
|bundled|Object \|undefined \|null|Bundled GVL translations by language code. These are checked first before any cache or fetch.|-|Optional|
|
|
159
159
|
|vendorIds|number\[] \|undefined|Vendor IDs to filter when fetching non-bundled languages. Reduces payload size.|-|Optional|
|
|
160
|
-
|endpoint|string \|undefined|Override the default GVL endpoint.|'https\://gvl.
|
|
160
|
+
|endpoint|string \|undefined|Override the default GVL endpoint.|'https\://gvl.inth.app'|Optional|
|
|
161
161
|
|customVendors|Array\<Object> \|undefined|Custom vendors not registered with IAB. These are synced to the frontend via the /init endpoint.|-|Optional|
|
|
162
162
|
|
|
163
163
|
## Return Value
|
package/docs/guides/iab-tcf.md
CHANGED
|
@@ -6,15 +6,15 @@ The c15t backend optionally supports [IAB TCF v2.3](https://iabeurope.eu/transpa
|
|
|
6
6
|
|
|
7
7
|
## CMP Registration
|
|
8
8
|
|
|
9
|
-
[
|
|
9
|
+
[Inth](https://inth.com), c15t's hosted platform, is IAB TCF certified. If you use Inth instead of self-hosting, the CMP ID is automatically provided to clients — no additional configuration needed.
|
|
10
10
|
|
|
11
|
-
If you self-host
|
|
11
|
+
If you self-host, you need your own CMP registration with IAB Europe and must configure your CMP ID via `iab.cmpId`. Registering your own CMP may also involve IAB Europe fees, so check IAB Europe's current CMP registration terms and pricing before choosing this route. The backend returns this value in the `/init` response so clients use the correct CMP identity in TC Strings.
|
|
12
12
|
|
|
13
13
|
> ℹ️ **Info:**
|
|
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
|
|
17
|
+
> If you heavily customize or build your own IAB banner or dialog instead of using the default IABConsentBanner and IABConsentDialog components provided by c15t, you cannot use Inth'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:
|
|
28
|
+
cmpId: Number('<YOUR_CMP_ID>'), // replace with your registered CMP ID
|
|
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.inth.com` 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, so use the same `iab.cmpId` pattern in every self-hosted configuration.
|
|
35
35
|
|
|
36
36
|
## Custom GVL Endpoint
|
|
37
37
|
|
|
@@ -40,6 +40,7 @@ Point to your own GVL mirror:
|
|
|
40
40
|
```ts
|
|
41
41
|
iab: {
|
|
42
42
|
enabled: true,
|
|
43
|
+
cmpId: Number('<YOUR_CMP_ID>'), // replace with your registered CMP ID
|
|
43
44
|
endpoint: 'https://your-gvl-mirror.com',
|
|
44
45
|
vendorIds: [755, 52, 69],
|
|
45
46
|
},
|
|
@@ -55,6 +56,7 @@ import gvlDe from './gvl/de.json';
|
|
|
55
56
|
|
|
56
57
|
iab: {
|
|
57
58
|
enabled: true,
|
|
59
|
+
cmpId: Number('<YOUR_CMP_ID>'), // replace with your registered CMP ID
|
|
58
60
|
bundled: {
|
|
59
61
|
en: gvlEn,
|
|
60
62
|
de: gvlDe,
|
|
@@ -72,6 +74,7 @@ Add your own vendors alongside IAB-registered ones:
|
|
|
72
74
|
```ts
|
|
73
75
|
iab: {
|
|
74
76
|
enabled: true,
|
|
77
|
+
cmpId: Number('<YOUR_CMP_ID>'), // replace with your registered CMP ID
|
|
75
78
|
vendorIds: [755],
|
|
76
79
|
customVendors: [
|
|
77
80
|
{
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c15t/backend",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"description": "Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and preference center. Webhooks, audit logs, storage adapters. Self-host or use inth.com",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"consent",
|
|
7
7
|
"privacy",
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
"consent-banner"
|
|
21
21
|
],
|
|
22
22
|
"homepage": "https://c15t.com/docs/self-host/v2",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/c15t/c15t/issues"
|
|
25
|
+
},
|
|
23
26
|
"repository": {
|
|
24
27
|
"type": "git",
|
|
25
28
|
"url": "https://github.com/c15t/c15t.git",
|
|
@@ -113,11 +116,11 @@
|
|
|
113
116
|
"build": "bun prebuild && rslib build && bun ../../scripts/normalize-dist-types.mjs && bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/backend",
|
|
114
117
|
"build:agent-docs": "bun ../../scripts/agent-docs/generate-package-docs.ts @c15t/backend",
|
|
115
118
|
"check-types": "bun prebuild && tsc --noEmit",
|
|
116
|
-
"dev": "bun prebuild && rslib build &&
|
|
119
|
+
"dev": "sh -c 'bun prebuild && rslib build --no-dts --no-clean && rslib build --watch --no-dts --no-clean'",
|
|
117
120
|
"fmt": "bun biome format --write . && bun biome check --formatter-enabled=false --linter-enabled=false --write",
|
|
118
121
|
"knip": "knip",
|
|
119
122
|
"lint": "bun biome lint ./src",
|
|
120
|
-
"prepack": "
|
|
123
|
+
"prepack": "bun run build",
|
|
121
124
|
"start": "node dist/server.cjs",
|
|
122
125
|
"test": "bun prebuild && vitest run",
|
|
123
126
|
"test:watch": "bun prebuild && vitest"
|
package/readme.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"title": "@c15t/backend: Consent Management Backend",
|
|
3
|
-
"description": "Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and
|
|
3
|
+
"description": "Consent policy engine and API for c15t. Powers the cookie banner, consent manager, and preference center. Webhooks, audit logs, storage adapters. Self-host or use inth.com",
|
|
4
4
|
"features": [
|
|
5
5
|
"Consent Management: Track and manage user consent preferences",
|
|
6
6
|
"Geo-Location: Identify user's location to show relevant consent preferences",
|