@c15t/backend 2.0.0-rc.3 → 2.0.0-rc.5

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 (314) hide show
  1. package/dist/cache.cjs +4 -4
  2. package/dist/cache.js +4 -4
  3. package/dist/core.cjs +845 -87
  4. package/dist/core.js +821 -87
  5. package/dist/db/schema.cjs +37 -0
  6. package/dist/db/schema.js +33 -2
  7. package/dist/edge.cjs +1106 -0
  8. package/dist/edge.js +1069 -0
  9. package/dist/router.cjs +621 -71
  10. package/dist/router.js +621 -71
  11. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  12. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  13. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  14. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  15. package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
  16. package/{dist → dist-types}/cache/index.d.ts +0 -1
  17. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  18. package/{dist → dist-types}/cache/types.d.ts +0 -1
  19. package/{dist → dist-types}/core.d.ts +8 -1
  20. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  21. package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
  22. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  23. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  24. package/{dist → dist-types}/db/registry/index.d.ts +22 -2
  25. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  26. package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
  27. package/{dist → dist-types}/db/registry/types.d.ts +1 -2
  28. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  29. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  30. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  31. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  32. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  33. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  34. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  35. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  36. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
  37. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
  38. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  39. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +1 -2
  40. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  41. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +5 -2
  42. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  43. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
  44. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  45. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -2
  46. package/{dist → dist-types}/db/schema/index.d.ts +862 -33
  47. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  48. package/dist-types/define-config.d.ts +17 -0
  49. package/dist-types/edge/index.d.ts +5 -0
  50. package/dist-types/edge/init-handler.d.ts +38 -0
  51. package/dist-types/edge/resolve-consent.d.ts +80 -0
  52. package/dist-types/edge/types.d.ts +13 -0
  53. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  54. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  55. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  56. package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
  57. package/dist-types/handlers/init/policy.d.ts +26 -0
  58. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  59. package/dist-types/handlers/init/translations.d.ts +48 -0
  60. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  61. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  62. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  63. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
  64. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  65. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
  66. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
  67. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  68. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
  69. package/{dist → dist-types}/init.d.ts +4 -7
  70. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  71. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  72. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  73. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  74. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
  75. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  76. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  77. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  78. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  79. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  80. package/dist-types/policies/builder.d.ts +127 -0
  81. package/dist-types/policies/defaults.d.ts +2 -0
  82. package/dist-types/policies/matchers.d.ts +3 -0
  83. package/{dist → dist-types}/router.d.ts +0 -1
  84. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  85. package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
  86. package/{dist → dist-types}/routes/init.d.ts +0 -1
  87. package/{dist → dist-types}/routes/status.d.ts +0 -1
  88. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  89. package/{dist → dist-types}/types/api.d.ts +0 -1
  90. package/dist-types/types/index.d.ts +443 -0
  91. package/dist-types/utils/background.d.ts +6 -0
  92. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
  93. package/{dist → dist-types}/utils/env.d.ts +0 -1
  94. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  95. package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
  96. package/{dist → dist-types}/utils/logger.d.ts +1 -2
  97. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  98. package/dist-types/version.d.ts +1 -0
  99. package/docs/README.md +49 -0
  100. package/docs/api/configuration.md +197 -0
  101. package/docs/api/endpoints.md +211 -0
  102. package/docs/guides/caching.md +85 -0
  103. package/docs/guides/database-setup.md +128 -0
  104. package/docs/guides/edge-deployment.md +248 -0
  105. package/docs/guides/framework-integration.md +142 -0
  106. package/docs/guides/iab-tcf.md +89 -0
  107. package/docs/guides/observability.md +96 -0
  108. package/docs/guides/policy-packs.md +396 -0
  109. package/docs/quickstart.md +129 -0
  110. package/package.json +37 -23
  111. package/.turbo/turbo-build.log +0 -49
  112. package/CHANGELOG.md +0 -115
  113. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  114. package/dist/cache/adapters/index.d.ts.map +0 -1
  115. package/dist/cache/adapters/memory.d.ts.map +0 -1
  116. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  117. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  118. package/dist/cache/index.d.ts.map +0 -1
  119. package/dist/cache/keys.d.ts.map +0 -1
  120. package/dist/cache/types.d.ts.map +0 -1
  121. package/dist/core.d.ts.map +0 -1
  122. package/dist/db/adapters/drizzle.d.ts +0 -2
  123. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  124. package/dist/db/adapters/index.d.ts +0 -2
  125. package/dist/db/adapters/index.d.ts.map +0 -1
  126. package/dist/db/adapters/kysely.d.ts +0 -2
  127. package/dist/db/adapters/kysely.d.ts.map +0 -1
  128. package/dist/db/adapters/mongo.d.ts +0 -2
  129. package/dist/db/adapters/mongo.d.ts.map +0 -1
  130. package/dist/db/adapters/prisma.d.ts +0 -2
  131. package/dist/db/adapters/prisma.d.ts.map +0 -1
  132. package/dist/db/adapters/typeorm.d.ts +0 -2
  133. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  134. package/dist/db/migrator/index.d.ts.map +0 -1
  135. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  136. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  137. package/dist/db/registry/domain.d.ts.map +0 -1
  138. package/dist/db/registry/index.d.ts.map +0 -1
  139. package/dist/db/registry/subject.d.ts.map +0 -1
  140. package/dist/db/registry/types.d.ts.map +0 -1
  141. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  142. package/dist/db/registry/utils.d.ts.map +0 -1
  143. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  144. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  145. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  146. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  147. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  148. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  149. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  150. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  151. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  152. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  153. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  154. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  155. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  156. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  157. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  158. package/dist/db/schema/index.d.ts.map +0 -1
  159. package/dist/db/tenant-scope.d.ts.map +0 -1
  160. package/dist/define-config.d.ts +0 -5
  161. package/dist/define-config.d.ts.map +0 -1
  162. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  163. package/dist/handlers/consent/index.d.ts +0 -12
  164. package/dist/handlers/consent/index.d.ts.map +0 -1
  165. package/dist/handlers/init/geo.d.ts.map +0 -1
  166. package/dist/handlers/init/index.d.ts.map +0 -1
  167. package/dist/handlers/init/translations.d.ts +0 -28
  168. package/dist/handlers/init/translations.d.ts.map +0 -1
  169. package/dist/handlers/status/index.d.ts +0 -7
  170. package/dist/handlers/status/index.d.ts.map +0 -1
  171. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  172. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  173. package/dist/handlers/subject/index.d.ts +0 -10
  174. package/dist/handlers/subject/index.d.ts.map +0 -1
  175. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  176. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  177. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  178. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  179. package/dist/init.d.ts.map +0 -1
  180. package/dist/middleware/auth/index.d.ts.map +0 -1
  181. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  182. package/dist/middleware/cors/cors.d.ts.map +0 -1
  183. package/dist/middleware/cors/index.d.ts +0 -30
  184. package/dist/middleware/cors/index.d.ts.map +0 -1
  185. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  186. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  187. package/dist/middleware/openapi/config.d.ts.map +0 -1
  188. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  189. package/dist/middleware/openapi/index.d.ts +0 -12
  190. package/dist/middleware/openapi/index.d.ts.map +0 -1
  191. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  192. package/dist/router.d.ts.map +0 -1
  193. package/dist/routes/consent.d.ts.map +0 -1
  194. package/dist/routes/index.d.ts +0 -10
  195. package/dist/routes/index.d.ts.map +0 -1
  196. package/dist/routes/init.d.ts.map +0 -1
  197. package/dist/routes/status.d.ts.map +0 -1
  198. package/dist/routes/subject.d.ts.map +0 -1
  199. package/dist/types/api.d.ts.map +0 -1
  200. package/dist/types/index.d.ts +0 -263
  201. package/dist/types/index.d.ts.map +0 -1
  202. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  203. package/dist/utils/env.d.ts.map +0 -1
  204. package/dist/utils/extract-error-message.d.ts.map +0 -1
  205. package/dist/utils/index.d.ts +0 -4
  206. package/dist/utils/index.d.ts.map +0 -1
  207. package/dist/utils/instrumentation.d.ts.map +0 -1
  208. package/dist/utils/logger.d.ts.map +0 -1
  209. package/dist/utils/metrics.d.ts.map +0 -1
  210. package/dist/version.d.ts +0 -2
  211. package/dist/version.d.ts.map +0 -1
  212. package/knip.json +0 -31
  213. package/rslib.config.ts +0 -93
  214. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  215. package/src/cache/adapters/index.ts +0 -22
  216. package/src/cache/adapters/memory.ts +0 -111
  217. package/src/cache/adapters/upstash-redis.ts +0 -113
  218. package/src/cache/gvl-resolver.ts +0 -289
  219. package/src/cache/index.ts +0 -34
  220. package/src/cache/keys.ts +0 -68
  221. package/src/cache/types.ts +0 -66
  222. package/src/core.ts +0 -369
  223. package/src/db/migrator/index.ts +0 -80
  224. package/src/db/registry/consent-policy.test.ts +0 -451
  225. package/src/db/registry/consent-policy.ts +0 -82
  226. package/src/db/registry/consent-purpose.test.ts +0 -428
  227. package/src/db/registry/consent-purpose.ts +0 -61
  228. package/src/db/registry/domain.test.ts +0 -445
  229. package/src/db/registry/domain.ts +0 -91
  230. package/src/db/registry/index.ts +0 -14
  231. package/src/db/registry/subject.test.ts +0 -371
  232. package/src/db/registry/subject.ts +0 -126
  233. package/src/db/registry/types.ts +0 -10
  234. package/src/db/registry/utils/generate-id.test.ts +0 -216
  235. package/src/db/registry/utils/generate-id.ts +0 -133
  236. package/src/db/registry/utils.ts +0 -133
  237. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  238. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  239. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  240. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  241. package/src/db/schema/1.0.0/consent.ts +0 -20
  242. package/src/db/schema/1.0.0/domain.ts +0 -12
  243. package/src/db/schema/1.0.0/index.ts +0 -48
  244. package/src/db/schema/1.0.0/subject.ts +0 -11
  245. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  246. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  247. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  248. package/src/db/schema/2.0.0/consent.ts +0 -28
  249. package/src/db/schema/2.0.0/domain.ts +0 -12
  250. package/src/db/schema/2.0.0/index.ts +0 -47
  251. package/src/db/schema/2.0.0/subject.ts +0 -13
  252. package/src/db/schema/index.ts +0 -15
  253. package/src/db/tenant-scope.test.ts +0 -747
  254. package/src/db/tenant-scope.ts +0 -103
  255. package/src/define-config.ts +0 -5
  256. package/src/handlers/consent/check.handler.ts +0 -126
  257. package/src/handlers/init/geo.test.ts +0 -317
  258. package/src/handlers/init/geo.ts +0 -195
  259. package/src/handlers/init/index.test.ts +0 -205
  260. package/src/handlers/init/index.ts +0 -114
  261. package/src/handlers/init/translations.test.ts +0 -121
  262. package/src/handlers/init/translations.ts +0 -72
  263. package/src/handlers/status/status.handler.test.ts +0 -155
  264. package/src/handlers/status/status.handler.ts +0 -51
  265. package/src/handlers/subject/get.handler.ts +0 -92
  266. package/src/handlers/subject/list.handler.ts +0 -92
  267. package/src/handlers/subject/patch.handler.ts +0 -119
  268. package/src/handlers/subject/post.handler.test.ts +0 -294
  269. package/src/handlers/subject/post.handler.ts +0 -268
  270. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  271. package/src/handlers/utils/consent-enrichment.ts +0 -218
  272. package/src/init.test.ts +0 -126
  273. package/src/init.ts +0 -87
  274. package/src/middleware/auth/index.ts +0 -11
  275. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  276. package/src/middleware/auth/validate-api-key.ts +0 -107
  277. package/src/middleware/cors/cors.test.ts +0 -135
  278. package/src/middleware/cors/cors.ts +0 -186
  279. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  280. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  281. package/src/middleware/cors/process-cors.ts +0 -91
  282. package/src/middleware/openapi/config.ts +0 -29
  283. package/src/middleware/openapi/handlers.ts +0 -34
  284. package/src/middleware/process-ip/index.test.ts +0 -195
  285. package/src/middleware/process-ip/index.ts +0 -199
  286. package/src/router.ts +0 -15
  287. package/src/routes/consent.ts +0 -52
  288. package/src/routes/init.ts +0 -105
  289. package/src/routes/status.ts +0 -46
  290. package/src/routes/subject.ts +0 -152
  291. package/src/types/api.ts +0 -48
  292. package/src/types/index.ts +0 -297
  293. package/src/utils/create-telemetry-options.test.ts +0 -302
  294. package/src/utils/create-telemetry-options.ts +0 -229
  295. package/src/utils/env.ts +0 -84
  296. package/src/utils/extract-error-message.ts +0 -21
  297. package/src/utils/instrumentation.test.ts +0 -185
  298. package/src/utils/instrumentation.ts +0 -196
  299. package/src/utils/logger.ts +0 -41
  300. package/src/utils/metrics.test.ts +0 -323
  301. package/src/utils/metrics.ts +0 -402
  302. package/src/utils/telemetry-pii.test.ts +0 -325
  303. package/src/version.ts +0 -2
  304. package/tsconfig.json +0 -11
  305. package/vitest.config.ts +0 -28
  306. /package/dist/{types.cjs → types/index.cjs} +0 -0
  307. /package/dist/{types.js → types/index.js} +0 -0
  308. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  309. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  310. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  311. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  312. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  313. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  314. /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
@@ -1,164 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { isOriginTrusted } from './is-origin-trusted';
3
-
4
- /**
5
- * Test suite for CORS utility functions
6
- */
7
- describe('CORS utilities', () => {
8
- describe('isOriginTrusted', () => {
9
- it('should match exact origins', () => {
10
- const trustedDomains = ['example.com'];
11
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
12
- expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
13
- });
14
-
15
- it('should handle origins with trailing slashes', () => {
16
- const trustedDomains = ['example.com'];
17
- expect(isOriginTrusted('https://example.com/', trustedDomains)).toBe(
18
- true
19
- );
20
- expect(isOriginTrusted('https://example.com//', trustedDomains)).toBe(
21
- true
22
- );
23
- });
24
-
25
- it('should handle origins with paths', () => {
26
- const trustedDomains = ['example.com'];
27
- expect(isOriginTrusted('https://example.com/path', trustedDomains)).toBe(
28
- true
29
- );
30
- expect(
31
- isOriginTrusted('https://example.com/path/subpath', trustedDomains)
32
- ).toBe(true);
33
- });
34
-
35
- it('should handle multiple trusted domains', () => {
36
- const trustedDomains = ['example.com', 'test.com'];
37
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
38
- expect(isOriginTrusted('https://test.com', trustedDomains)).toBe(true);
39
- expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
40
- });
41
-
42
- it('should handle wildcard subdomains', () => {
43
- const trustedDomains = ['*.example.com'];
44
- expect(isOriginTrusted('https://sub.example.com', trustedDomains)).toBe(
45
- true
46
- );
47
- expect(
48
- isOriginTrusted('https://other.sub.example.com', trustedDomains)
49
- ).toBe(true);
50
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
51
- false
52
- );
53
- expect(isOriginTrusted('https://other.com', trustedDomains)).toBe(false);
54
- });
55
-
56
- it('should handle different protocols', () => {
57
- const trustedDomains = ['example.com'];
58
- expect(isOriginTrusted('http://example.com', trustedDomains)).toBe(true);
59
- expect(isOriginTrusted('wss://example.com', trustedDomains)).toBe(true);
60
- });
61
-
62
- it('should handle ports in origins', () => {
63
- const trustedDomains = ['example.com'];
64
- expect(isOriginTrusted('https://example.com:3000', trustedDomains)).toBe(
65
- true
66
- );
67
- expect(isOriginTrusted('http://example.com:8080', trustedDomains)).toBe(
68
- true
69
- );
70
- });
71
-
72
- it('should handle empty trusted domains array', () => {
73
- const trustedDomains: string[] = [];
74
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
75
- false
76
- );
77
- });
78
-
79
- it('should handle invalid origin formats', () => {
80
- const trustedDomains = ['example.com'];
81
- expect(isOriginTrusted('invalid-url', trustedDomains)).toBe(false);
82
- expect(isOriginTrusted('', trustedDomains)).toBe(false);
83
- });
84
-
85
- it('should handle case sensitivity', () => {
86
- const trustedDomains = ['EXAMPLE.com'];
87
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(true);
88
- expect(isOriginTrusted('https://EXAMPLE.COM', trustedDomains)).toBe(true);
89
- });
90
-
91
- it('should handle subdomain levels with wildcards', () => {
92
- const trustedDomains = ['*.example.com'];
93
- expect(isOriginTrusted('https://a.b.example.com', trustedDomains)).toBe(
94
- true
95
- );
96
- expect(isOriginTrusted('https://a.example.com', trustedDomains)).toBe(
97
- true
98
- );
99
- expect(isOriginTrusted('https://example.com', trustedDomains)).toBe(
100
- false
101
- );
102
- });
103
-
104
- describe('multiple subdomain levels', () => {
105
- it('should match base domain when explicitly listed', () => {
106
- const trustedDomains = ['my-site.com'];
107
- expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
108
- true
109
- );
110
- });
111
-
112
- it('should match single-level subdomain with wildcard pattern', () => {
113
- const trustedDomains = ['*.my-site.com'];
114
- expect(
115
- isOriginTrusted('https://foobar.my-site.com', trustedDomains)
116
- ).toBe(true);
117
- });
118
-
119
- it('should match multi-level subdomain with wildcard pattern', () => {
120
- const trustedDomains = ['*.my-site.com'];
121
- expect(
122
- isOriginTrusted('https://foo.bar.my-site.com', trustedDomains)
123
- ).toBe(true);
124
- });
125
-
126
- it('should match three-level subdomain with wildcard pattern', () => {
127
- const trustedDomains = ['*.my-site.com'];
128
- expect(
129
- isOriginTrusted('https://a.b.c.my-site.com', trustedDomains)
130
- ).toBe(true);
131
- });
132
-
133
- it('should not match base domain with wildcard pattern', () => {
134
- const trustedDomains = ['*.my-site.com'];
135
- expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
136
- false
137
- );
138
- });
139
-
140
- it('should not match similar domain that is not a subdomain', () => {
141
- const trustedDomains = ['*.my-site.com'];
142
- expect(isOriginTrusted('https://notmy-site.com', trustedDomains)).toBe(
143
- false
144
- );
145
- expect(
146
- isOriginTrusted('https://foobar-my-site.com', trustedDomains)
147
- ).toBe(false);
148
- });
149
-
150
- it('should match both base domain and subdomains when both are configured', () => {
151
- const trustedDomains = ['my-site.com', '*.my-site.com'];
152
- expect(isOriginTrusted('https://my-site.com', trustedDomains)).toBe(
153
- true
154
- );
155
- expect(
156
- isOriginTrusted('https://foobar.my-site.com', trustedDomains)
157
- ).toBe(true);
158
- expect(
159
- isOriginTrusted('https://foo.bar.my-site.com', trustedDomains)
160
- ).toBe(true);
161
- });
162
- });
163
- });
164
- });
@@ -1,130 +0,0 @@
1
- /**
2
- * Origin validation utilities for CORS security
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- import type { Logger } from '@c15t/logger';
8
-
9
- /**
10
- * Regular expression to strip protocol, trailing slashes, and port numbers from URLs
11
- * Matches:
12
- * - http:// or https:// protocol
13
- * - ws:// or wss:// protocol
14
- * - trailing slashes
15
- * - port numbers with colon
16
- *
17
- * @internal
18
- */
19
- export const STRIP_REGEX =
20
- /^(?:https?:\/\/)|^(?:wss?:\/\/)|(?:\/+$)|(?::\d+$)/g;
21
-
22
- /**
23
- * Checks if a domain matches a wildcard pattern
24
- *
25
- * @param hostname - The hostname to check
26
- * @param wildcardPattern - The wildcard pattern (e.g. *.example.com)
27
- * @param logger - Optional logger for debugging
28
- * @returns true if the hostname matches the wildcard pattern
29
- *
30
- * @internal
31
- */
32
- function matchesWildcard(
33
- hostname: string,
34
- wildcardPattern: string,
35
- logger?: Logger
36
- ): boolean {
37
- const wildcardDomain = wildcardPattern.slice(2); // Remove *. prefix
38
-
39
- // Ensure the hostname is not the base domain and ends with .wildcardDomain
40
- // This prevents matching domains like 'foobar-my-site.com' against '*.my-site.com'
41
- const isValid =
42
- hostname !== wildcardDomain && hostname.endsWith(`.${wildcardDomain}`);
43
-
44
- logger?.debug(
45
- `Wildcard match result: ${isValid} ${hostname} ends with .${wildcardDomain}`
46
- );
47
-
48
- return isValid;
49
- }
50
-
51
- /**
52
- * Validates if a given origin matches any of the trusted domain patterns
53
- *
54
- * Supports:
55
- * - Exact domain matches
56
- * - Wildcard subdomains (e.g. *.example.com)
57
- * - Protocol-agnostic matching
58
- * - Case-insensitive comparison
59
- *
60
- * @param origin - The origin URL to validate (e.g. https://example.com)
61
- * @param trustedDomains - Array of trusted domain patterns. Can include wildcards (e.g. *.example.com)
62
- * @param logger - Optional logger for debugging validation process
63
- *
64
- * @returns `true` if the origin matches any trusted domain pattern, `false` otherwise
65
- *
66
- * @throws {Error} When trustedDomains array is empty
67
- * @throws {TypeError} When origin URL is invalid
68
- *
69
- * @example
70
- * ```ts
71
- * // Simple domain matching
72
- * isOriginTrusted('https://example.com', ['example.com']); // true
73
- *
74
- * // Wildcard subdomain matching
75
- * isOriginTrusted('https://api.example.com', ['*.example.com']); // true
76
- *
77
- * // Allow all origins
78
- * isOriginTrusted('https://any-domain.com', ['*']); // true
79
- * ```
80
- */
81
- export function isOriginTrusted(
82
- origin: string,
83
- trustedDomains: string[],
84
- logger?: Logger
85
- ): boolean {
86
- try {
87
- if (trustedDomains.length === 0) {
88
- throw new Error('No trusted domains');
89
- }
90
-
91
- logger?.debug(
92
- `Checking if origin ${origin} is trusted in ${trustedDomains}`
93
- );
94
-
95
- // Special case: if "*" is in trusted domains, allow all origins
96
- if (trustedDomains.includes('*')) {
97
- logger?.debug('Allowing all origins');
98
- return true;
99
- }
100
-
101
- // Parse the origin URL to get just the hostname
102
- const url = new URL(origin);
103
- const originHostname = url.hostname.toLowerCase();
104
- logger?.debug(`Parsed origin hostname: ${originHostname}`);
105
-
106
- return trustedDomains.some((domain) => {
107
- // Handle empty domains (which might come from splitting empty strings)
108
- if (!domain || domain.trim() === '') {
109
- logger?.debug('Skipping empty domain');
110
- return false;
111
- }
112
-
113
- const strippedDomain = domain.replace(STRIP_REGEX, '').toLowerCase();
114
- logger?.debug(`Checking against stripped domain: ${strippedDomain}`);
115
-
116
- if (strippedDomain.startsWith('*.')) {
117
- return matchesWildcard(originHostname, strippedDomain, logger);
118
- }
119
-
120
- const isMatch = originHostname === strippedDomain;
121
- logger?.debug(
122
- `Exact match result: ${isMatch} ${originHostname} === ${strippedDomain}`
123
- );
124
- return isMatch;
125
- });
126
- } catch (error) {
127
- logger?.error('Error validating origin:', error);
128
- return false;
129
- }
130
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * CORS processing middleware for c15t
3
- * Handles origin validation and context enrichment
4
- *
5
- * @packageDocumentation
6
- */
7
-
8
- import type { C15TContext } from '~/types';
9
- import { isOriginTrusted } from './is-origin-trusted';
10
-
11
- /**
12
- * Result of CORS processing
13
- * @internal
14
- */
15
- interface CORSProcessingResult {
16
- /** The origin from the request */
17
- origin: string | null;
18
- /** Whether the origin is trusted */
19
- isTrusted: boolean;
20
- }
21
-
22
- /**
23
- * Extracts and validates CORS information from a request
24
- *
25
- * @param request - The request to process
26
- * @param trustedOrigins - Array of trusted origins
27
- * @param logger - Optional logger for debugging
28
- * @returns CORS processing result
29
- *
30
- * @internal
31
- */
32
- function extractCORSInfo(
33
- request: Request,
34
- trustedOrigins?: string[],
35
- logger?: C15TContext['logger']
36
- ): CORSProcessingResult {
37
- const origin = request.headers.get('origin');
38
-
39
- if (!origin || !trustedOrigins) {
40
- return {
41
- origin: origin,
42
- isTrusted: false,
43
- };
44
- }
45
-
46
- return {
47
- origin,
48
- isTrusted: isOriginTrusted(origin, trustedOrigins, logger),
49
- };
50
- }
51
-
52
- /**
53
- * Processes CORS validation for an incoming request and enriches the context
54
- * with origin information. This middleware function validates the origin against
55
- * trusted patterns and updates the context with the validation results.
56
- *
57
- * @param request - The incoming HTTP request to process
58
- * @param context - The c15t middleware context to enrich
59
- * @param trustedOrigins - Array of trusted origin patterns. Can include wildcards ('*')
60
- *
61
- * @returns The enriched context with origin validation results
62
- *
63
- * @example
64
- * ```ts
65
- * const enrichedContext = processCors(
66
- * request,
67
- * context,
68
- * ['https://example.com', '*.trusted-domain.com']
69
- * );
70
- * ```
71
- *
72
- * @see {@link isOriginTrusted} for origin validation details
73
- */
74
- export const processCors = (
75
- request: Request,
76
- context: C15TContext,
77
- trustedOrigins?: string[]
78
- ): C15TContext => {
79
- const { origin, isTrusted } = extractCORSInfo(
80
- request,
81
- trustedOrigins,
82
- context.logger
83
- );
84
-
85
- if (origin) {
86
- context.origin = origin;
87
- context.trustedOrigin = isTrusted;
88
- }
89
-
90
- return context;
91
- };
@@ -1,29 +0,0 @@
1
- import type { C15TOptions } from '~/types';
2
- import { version } from '~/version';
3
- /**
4
- * Default OpenAPI configuration
5
- *
6
- * Note: specPath and docsPath should NOT include the basePath,
7
- * as the basePath is stripped from incoming requests before routing.
8
- */
9
- export const createOpenAPIConfig = (options: C15TOptions) => {
10
- return {
11
- enabled: options.advanced?.openapi?.enabled !== false,
12
- specPath: '/spec.json',
13
- docsPath: '/docs',
14
- ...(options.advanced?.openapi || {}),
15
- };
16
- };
17
-
18
- /**
19
- * Default OpenAPI options
20
- */
21
- export const createDefaultOpenAPIOptions = (options: C15TOptions) => ({
22
- info: {
23
- title: options.appName || 'c15t API',
24
- version,
25
- description: 'API for consent management',
26
- },
27
- servers: [{ url: options.basePath || '/' }],
28
- security: [{ bearerAuth: [] }],
29
- });
@@ -1,34 +0,0 @@
1
- import type { C15TOptions } from '~/types';
2
- import { createOpenAPIConfig } from './config';
3
-
4
- /**
5
- * Generate the default UI for API documentation
6
- */
7
- export const createDocsUI = (options: C15TOptions) => {
8
- const config = createOpenAPIConfig(options);
9
-
10
- // If a custom template is provided, use it
11
- if (config.customUiTemplate) {
12
- return config.customUiTemplate;
13
- }
14
-
15
- // Otherwise, return the default Scalar UI
16
- return `
17
- <!doctype html>
18
- <html>
19
- <head>
20
- <title>${options.appName || 'c15t API'} Documentation</title>
21
- <meta charset="utf-8" />
22
- <meta name="viewport" content="width=device-width, initial-scale=1" />
23
- <link rel="icon" type="image/svg+xml" href="https://c15t.com/icon.svg" />
24
- </head>
25
- <body>
26
- <script
27
- id="api-reference"
28
- data-url="${encodeURI(config.specPath)}">
29
- </script>
30
- <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
31
- </body>
32
- </html>
33
- `;
34
- };
@@ -1,195 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import type { C15TOptions } from '~/types';
3
- import { getIpAddress, maskIpAddress } from './index';
4
-
5
- describe('maskIpAddress', () => {
6
- describe('IPv4 addresses', () => {
7
- it('should mask the last octet of a standard IPv4 address', () => {
8
- expect(maskIpAddress('192.168.1.100')).toBe('192.168.1.0');
9
- });
10
-
11
- it('should mask the last octet of localhost', () => {
12
- expect(maskIpAddress('127.0.0.1')).toBe('127.0.0.0');
13
- });
14
-
15
- it('should mask the last octet of a public IP', () => {
16
- expect(maskIpAddress('8.8.8.8')).toBe('8.8.8.0');
17
- });
18
-
19
- it('should handle IP with last octet already zero', () => {
20
- expect(maskIpAddress('10.0.0.0')).toBe('10.0.0.0');
21
- });
22
-
23
- it('should handle IP with max values', () => {
24
- expect(maskIpAddress('255.255.255.255')).toBe('255.255.255.0');
25
- });
26
- });
27
-
28
- describe('IPv6 addresses', () => {
29
- it('should mask the last 80 bits of a full IPv6 address', () => {
30
- const result = maskIpAddress('2001:0db8:85a3:0000:0000:8a2e:0370:7334');
31
- expect(result).toBe('2001:db8:85a3::');
32
- });
33
-
34
- it('should mask a compressed IPv6 address', () => {
35
- const result = maskIpAddress('2001:db8:85a3::1');
36
- expect(result).toBe('2001:db8:85a3::');
37
- });
38
-
39
- it('should handle localhost IPv6', () => {
40
- const result = maskIpAddress('::1');
41
- expect(result).toBe('::');
42
- });
43
-
44
- it('should handle full zeros IPv6', () => {
45
- const result = maskIpAddress('::');
46
- expect(result).toBe('::');
47
- });
48
-
49
- it('should mask IPv6 with leading zeros compressed', () => {
50
- const result = maskIpAddress('::ffff:0:0:1');
51
- expect(result).toBe('::');
52
- });
53
- });
54
-
55
- describe('IPv4-mapped IPv6 addresses', () => {
56
- it('should mask the IPv4 portion of IPv4-mapped IPv6', () => {
57
- const result = maskIpAddress('::ffff:192.168.1.100');
58
- expect(result).toBe('::ffff:192.168.1.0');
59
- });
60
-
61
- it('should handle IPv4-mapped IPv6 localhost', () => {
62
- const result = maskIpAddress('::ffff:127.0.0.1');
63
- expect(result).toBe('::ffff:127.0.0.0');
64
- });
65
- });
66
-
67
- describe('edge cases', () => {
68
- it('should return null for null input', () => {
69
- expect(maskIpAddress(null)).toBeNull();
70
- });
71
-
72
- it('should return null for empty string', () => {
73
- expect(maskIpAddress('')).toBeNull();
74
- });
75
-
76
- it('should handle malformed IPv4 gracefully', () => {
77
- expect(maskIpAddress('192.168.1')).toBe('192.168.1');
78
- });
79
- });
80
- });
81
-
82
- describe('getIpAddress', () => {
83
- const createMockHeaders = (headers: Record<string, string>): Headers => {
84
- return new Headers(headers);
85
- };
86
-
87
- const createBaseOptions = (
88
- ipAddressOverrides?: NonNullable<C15TOptions['advanced']>['ipAddress']
89
- ): C15TOptions => ({
90
- trustedOrigins: ['http://localhost'],
91
- adapter: {} as C15TOptions['adapter'],
92
- advanced: {
93
- ipAddress: ipAddressOverrides,
94
- },
95
- });
96
-
97
- describe('IP extraction', () => {
98
- it('should extract and mask IP from x-forwarded-for header by default', () => {
99
- const headers = createMockHeaders({
100
- 'x-forwarded-for': '192.168.1.100, 10.0.0.1',
101
- });
102
- const options = createBaseOptions();
103
-
104
- expect(getIpAddress(headers, options)).toBe('192.168.1.0');
105
- });
106
-
107
- it('should extract and mask IP from cf-connecting-ip header by default', () => {
108
- const headers = createMockHeaders({
109
- 'cf-connecting-ip': '8.8.8.8',
110
- });
111
- const options = createBaseOptions();
112
-
113
- expect(getIpAddress(headers, options)).toBe('8.8.8.0');
114
- });
115
-
116
- it('should return null when no IP headers present', () => {
117
- const headers = createMockHeaders({});
118
- const options = createBaseOptions();
119
-
120
- expect(getIpAddress(headers, options)).toBeNull();
121
- });
122
- });
123
-
124
- describe('IP tracking disabled', () => {
125
- it('should return null when IP tracking is disabled', () => {
126
- const headers = createMockHeaders({
127
- 'x-forwarded-for': '192.168.1.100',
128
- });
129
- const options = createBaseOptions({
130
- tracking: false,
131
- });
132
-
133
- expect(getIpAddress(headers, options)).toBeNull();
134
- });
135
- });
136
-
137
- describe('IP masking enabled', () => {
138
- it('should mask IPv4 address when masking is enabled', () => {
139
- const headers = createMockHeaders({
140
- 'x-forwarded-for': '192.168.1.100',
141
- });
142
- const options = createBaseOptions({
143
- masking: true,
144
- });
145
-
146
- expect(getIpAddress(headers, options)).toBe('192.168.1.0');
147
- });
148
-
149
- it('should mask IPv6 address when masking is enabled', () => {
150
- const headers = createMockHeaders({
151
- 'x-forwarded-for': '2001:db8:85a3::8a2e:370:7334',
152
- });
153
- const options = createBaseOptions({
154
- masking: true,
155
- });
156
-
157
- expect(getIpAddress(headers, options)).toBe('2001:db8:85a3::');
158
- });
159
-
160
- it('should mask by default when masking is not explicitly disabled', () => {
161
- const headers = createMockHeaders({
162
- 'x-forwarded-for': '192.168.1.100',
163
- });
164
- const options = createBaseOptions();
165
-
166
- expect(getIpAddress(headers, options)).toBe('192.168.1.0');
167
- });
168
-
169
- it('should not mask when masking is explicitly false', () => {
170
- const headers = createMockHeaders({
171
- 'x-forwarded-for': '192.168.1.100',
172
- });
173
- const options = createBaseOptions({
174
- masking: false,
175
- });
176
-
177
- expect(getIpAddress(headers, options)).toBe('192.168.1.100');
178
- });
179
- });
180
-
181
- describe('custom headers', () => {
182
- it('should use custom IP headers when provided', () => {
183
- const headers = createMockHeaders({
184
- 'x-custom-ip': '10.0.0.1',
185
- 'x-forwarded-for': '192.168.1.100',
186
- });
187
- const options = createBaseOptions({
188
- ipAddressHeaders: ['x-custom-ip'],
189
- });
190
-
191
- // Masking is on by default, so last octet is zeroed
192
- expect(getIpAddress(headers, options)).toBe('10.0.0.0');
193
- });
194
- });
195
- });