@c15t/backend 2.0.0-rc.1 → 2.0.0-rc.10

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 (336) hide show
  1. package/README.md +3 -3
  2. package/dist/302.js +473 -0
  3. package/dist/583.js +540 -0
  4. package/dist/915.js +1771 -0
  5. package/dist/cache.cjs +5 -5
  6. package/dist/cache.js +4 -415
  7. package/dist/core.cjs +1356 -120
  8. package/dist/core.js +163 -1981
  9. package/dist/db/adapters/drizzle.cjs +1 -1
  10. package/dist/db/adapters/drizzle.js +1 -2
  11. package/dist/db/adapters/kysely.cjs +1 -1
  12. package/dist/db/adapters/kysely.js +1 -2
  13. package/dist/db/adapters/mongo.cjs +1 -1
  14. package/dist/db/adapters/mongo.js +1 -2
  15. package/dist/db/adapters/prisma.cjs +1 -1
  16. package/dist/db/adapters/prisma.js +1 -2
  17. package/dist/db/adapters/typeorm.cjs +1 -1
  18. package/dist/db/adapters/typeorm.js +1 -2
  19. package/dist/db/adapters.cjs +1 -1
  20. package/dist/db/migrator.cjs +1 -1
  21. package/dist/db/schema.cjs +43 -3
  22. package/dist/db/schema.js +35 -4
  23. package/dist/define-config.cjs +1 -1
  24. package/dist/edge.cjs +1106 -0
  25. package/dist/edge.js +190 -0
  26. package/dist/router.cjs +885 -123
  27. package/dist/router.js +1 -1507
  28. package/dist/{types.cjs → types/index.cjs} +1 -1
  29. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  30. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  31. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  32. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  33. package/{dist → dist-types}/cache/gvl-resolver.d.ts +0 -1
  34. package/{dist → dist-types}/cache/index.d.ts +0 -1
  35. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  36. package/{dist → dist-types}/cache/types.d.ts +0 -1
  37. package/{dist → dist-types}/core.d.ts +8 -1
  38. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  39. package/dist-types/db/registry/consent-policy.d.ts +78 -0
  40. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  41. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  42. package/dist-types/db/registry/index.d.ts +118 -0
  43. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  44. package/{dist → dist-types}/db/registry/subject.d.ts +0 -2
  45. package/{dist → dist-types}/db/registry/types.d.ts +1 -1
  46. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  47. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  48. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  49. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  50. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  51. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  52. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  53. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  54. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -32
  55. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -2
  56. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  57. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +3 -3
  58. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  59. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +7 -2
  60. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  61. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +455 -28
  62. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  63. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -3
  64. package/{dist → dist-types}/db/schema/index.d.ts +908 -86
  65. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  66. package/dist-types/define-config.d.ts +17 -0
  67. package/dist-types/edge/index.d.ts +5 -0
  68. package/dist-types/edge/init-handler.d.ts +40 -0
  69. package/dist-types/edge/resolve-consent.d.ts +80 -0
  70. package/dist-types/edge/types.d.ts +13 -0
  71. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  72. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  73. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  74. package/{dist → dist-types}/handlers/init/index.d.ts +2 -3
  75. package/dist-types/handlers/init/policy.d.ts +26 -0
  76. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  77. package/dist-types/handlers/init/translations.d.ts +48 -0
  78. package/dist-types/handlers/legal-document/current.handler.d.ts +11 -0
  79. package/dist-types/handlers/legal-document/snapshot.d.ts +39 -0
  80. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  81. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  82. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  83. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +3 -2
  84. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  85. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +3 -2
  86. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -2
  87. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  88. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +3 -1
  89. package/{dist → dist-types}/init.d.ts +4 -7
  90. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  91. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  92. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  93. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  94. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +0 -1
  95. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  96. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  97. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  98. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  99. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  100. package/dist-types/policies/builder.d.ts +127 -0
  101. package/dist-types/policies/defaults.d.ts +2 -0
  102. package/dist-types/policies/matchers.d.ts +3 -0
  103. package/{dist → dist-types}/router.d.ts +0 -1
  104. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  105. package/{dist → dist-types}/routes/index.d.ts +1 -1
  106. package/{dist → dist-types}/routes/init.d.ts +0 -1
  107. package/dist-types/routes/legal-document.d.ts +7 -0
  108. package/{dist → dist-types}/routes/status.d.ts +0 -1
  109. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  110. package/{dist → dist-types}/types/api.d.ts +0 -1
  111. package/dist-types/types/index.d.ts +464 -0
  112. package/dist-types/utils/background.d.ts +6 -0
  113. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
  114. package/{dist → dist-types}/utils/env.d.ts +0 -1
  115. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  116. package/{dist → dist-types}/utils/instrumentation.d.ts +2 -3
  117. package/{dist → dist-types}/utils/logger.d.ts +0 -1
  118. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  119. package/dist-types/version.d.ts +1 -0
  120. package/docs/README.md +49 -0
  121. package/docs/api/configuration.md +208 -0
  122. package/docs/api/endpoints.md +211 -0
  123. package/docs/guides/caching.md +85 -0
  124. package/docs/guides/database-setup.md +128 -0
  125. package/docs/guides/edge-deployment.md +251 -0
  126. package/docs/guides/framework-integration.md +142 -0
  127. package/docs/guides/iab-tcf.md +89 -0
  128. package/docs/guides/observability.md +96 -0
  129. package/docs/guides/policy-packs.md +396 -0
  130. package/docs/quickstart.md +129 -0
  131. package/package.json +51 -37
  132. package/.turbo/turbo-build.log +0 -49
  133. package/CHANGELOG.md +0 -99
  134. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  135. package/dist/cache/adapters/index.d.ts.map +0 -1
  136. package/dist/cache/adapters/memory.d.ts.map +0 -1
  137. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  138. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  139. package/dist/cache/index.d.ts.map +0 -1
  140. package/dist/cache/keys.d.ts.map +0 -1
  141. package/dist/cache/types.d.ts.map +0 -1
  142. package/dist/core.d.ts.map +0 -1
  143. package/dist/db/adapters/drizzle.d.ts +0 -2
  144. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  145. package/dist/db/adapters/index.d.ts +0 -2
  146. package/dist/db/adapters/index.d.ts.map +0 -1
  147. package/dist/db/adapters/kysely.d.ts +0 -2
  148. package/dist/db/adapters/kysely.d.ts.map +0 -1
  149. package/dist/db/adapters/mongo.d.ts +0 -2
  150. package/dist/db/adapters/mongo.d.ts.map +0 -1
  151. package/dist/db/adapters/prisma.d.ts +0 -2
  152. package/dist/db/adapters/prisma.d.ts.map +0 -1
  153. package/dist/db/adapters/typeorm.d.ts +0 -2
  154. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  155. package/dist/db/migrator/index.d.ts.map +0 -1
  156. package/dist/db/registry/consent-policy.d.ts +0 -23
  157. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  158. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  159. package/dist/db/registry/domain.d.ts.map +0 -1
  160. package/dist/db/registry/index.d.ts +0 -57
  161. package/dist/db/registry/index.d.ts.map +0 -1
  162. package/dist/db/registry/subject.d.ts.map +0 -1
  163. package/dist/db/registry/types.d.ts.map +0 -1
  164. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  165. package/dist/db/registry/utils.d.ts.map +0 -1
  166. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  167. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  168. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  169. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  170. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  171. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  172. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  173. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  174. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  175. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  176. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  177. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  178. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  179. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  180. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  181. package/dist/db/schema/index.d.ts.map +0 -1
  182. package/dist/db/tenant-scope.d.ts.map +0 -1
  183. package/dist/define-config.d.ts +0 -5
  184. package/dist/define-config.d.ts.map +0 -1
  185. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  186. package/dist/handlers/consent/index.d.ts +0 -12
  187. package/dist/handlers/consent/index.d.ts.map +0 -1
  188. package/dist/handlers/init/geo.d.ts.map +0 -1
  189. package/dist/handlers/init/index.d.ts.map +0 -1
  190. package/dist/handlers/init/translations.d.ts +0 -28
  191. package/dist/handlers/init/translations.d.ts.map +0 -1
  192. package/dist/handlers/status/index.d.ts +0 -7
  193. package/dist/handlers/status/index.d.ts.map +0 -1
  194. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  195. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  196. package/dist/handlers/subject/index.d.ts +0 -10
  197. package/dist/handlers/subject/index.d.ts.map +0 -1
  198. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  199. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  200. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  201. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  202. package/dist/init.d.ts.map +0 -1
  203. package/dist/middleware/auth/index.d.ts.map +0 -1
  204. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  205. package/dist/middleware/cors/cors.d.ts.map +0 -1
  206. package/dist/middleware/cors/index.d.ts +0 -30
  207. package/dist/middleware/cors/index.d.ts.map +0 -1
  208. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  209. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  210. package/dist/middleware/openapi/config.d.ts.map +0 -1
  211. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  212. package/dist/middleware/openapi/index.d.ts +0 -12
  213. package/dist/middleware/openapi/index.d.ts.map +0 -1
  214. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  215. package/dist/router.d.ts.map +0 -1
  216. package/dist/routes/consent.d.ts.map +0 -1
  217. package/dist/routes/index.d.ts.map +0 -1
  218. package/dist/routes/init.d.ts.map +0 -1
  219. package/dist/routes/status.d.ts.map +0 -1
  220. package/dist/routes/subject.d.ts.map +0 -1
  221. package/dist/types/api.d.ts.map +0 -1
  222. package/dist/types/index.d.ts +0 -255
  223. package/dist/types/index.d.ts.map +0 -1
  224. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  225. package/dist/utils/env.d.ts.map +0 -1
  226. package/dist/utils/extract-error-message.d.ts.map +0 -1
  227. package/dist/utils/index.d.ts +0 -4
  228. package/dist/utils/index.d.ts.map +0 -1
  229. package/dist/utils/instrumentation.d.ts.map +0 -1
  230. package/dist/utils/logger.d.ts.map +0 -1
  231. package/dist/utils/metrics.d.ts.map +0 -1
  232. package/dist/version.d.ts +0 -2
  233. package/dist/version.d.ts.map +0 -1
  234. package/knip.json +0 -31
  235. package/rslib.config.ts +0 -93
  236. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  237. package/src/cache/adapters/index.ts +0 -22
  238. package/src/cache/adapters/memory.ts +0 -111
  239. package/src/cache/adapters/upstash-redis.ts +0 -113
  240. package/src/cache/gvl-resolver.ts +0 -289
  241. package/src/cache/index.ts +0 -34
  242. package/src/cache/keys.ts +0 -68
  243. package/src/cache/types.ts +0 -66
  244. package/src/core.ts +0 -368
  245. package/src/db/migrator/index.ts +0 -80
  246. package/src/db/registry/consent-policy.test.ts +0 -451
  247. package/src/db/registry/consent-policy.ts +0 -82
  248. package/src/db/registry/consent-purpose.test.ts +0 -428
  249. package/src/db/registry/consent-purpose.ts +0 -61
  250. package/src/db/registry/domain.test.ts +0 -445
  251. package/src/db/registry/domain.ts +0 -91
  252. package/src/db/registry/index.ts +0 -14
  253. package/src/db/registry/subject.test.ts +0 -388
  254. package/src/db/registry/subject.ts +0 -129
  255. package/src/db/registry/types.ts +0 -10
  256. package/src/db/registry/utils/generate-id.test.ts +0 -216
  257. package/src/db/registry/utils/generate-id.ts +0 -133
  258. package/src/db/registry/utils.ts +0 -133
  259. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  260. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  261. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  262. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  263. package/src/db/schema/1.0.0/consent.ts +0 -20
  264. package/src/db/schema/1.0.0/domain.ts +0 -12
  265. package/src/db/schema/1.0.0/index.ts +0 -48
  266. package/src/db/schema/1.0.0/subject.ts +0 -12
  267. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  268. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  269. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  270. package/src/db/schema/2.0.0/consent.ts +0 -26
  271. package/src/db/schema/2.0.0/domain.ts +0 -12
  272. package/src/db/schema/2.0.0/index.ts +0 -47
  273. package/src/db/schema/2.0.0/subject.ts +0 -14
  274. package/src/db/schema/index.ts +0 -15
  275. package/src/db/tenant-scope.test.ts +0 -750
  276. package/src/db/tenant-scope.ts +0 -103
  277. package/src/define-config.ts +0 -5
  278. package/src/handlers/consent/check.handler.ts +0 -126
  279. package/src/handlers/init/geo.test.ts +0 -317
  280. package/src/handlers/init/geo.ts +0 -195
  281. package/src/handlers/init/index.test.ts +0 -205
  282. package/src/handlers/init/index.ts +0 -114
  283. package/src/handlers/init/translations.test.ts +0 -121
  284. package/src/handlers/init/translations.ts +0 -72
  285. package/src/handlers/status/status.handler.test.ts +0 -155
  286. package/src/handlers/status/status.handler.ts +0 -51
  287. package/src/handlers/subject/get.handler.ts +0 -93
  288. package/src/handlers/subject/list.handler.ts +0 -93
  289. package/src/handlers/subject/patch.handler.ts +0 -122
  290. package/src/handlers/subject/post.handler.test.ts +0 -294
  291. package/src/handlers/subject/post.handler.ts +0 -254
  292. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  293. package/src/handlers/utils/consent-enrichment.ts +0 -218
  294. package/src/init.test.ts +0 -126
  295. package/src/init.ts +0 -87
  296. package/src/middleware/auth/index.ts +0 -11
  297. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  298. package/src/middleware/auth/validate-api-key.ts +0 -107
  299. package/src/middleware/cors/cors.test.ts +0 -135
  300. package/src/middleware/cors/cors.ts +0 -186
  301. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  302. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  303. package/src/middleware/cors/process-cors.ts +0 -91
  304. package/src/middleware/openapi/config.ts +0 -29
  305. package/src/middleware/openapi/handlers.ts +0 -34
  306. package/src/middleware/process-ip/index.test.ts +0 -195
  307. package/src/middleware/process-ip/index.ts +0 -199
  308. package/src/router.ts +0 -15
  309. package/src/routes/consent.ts +0 -52
  310. package/src/routes/index.ts +0 -10
  311. package/src/routes/init.ts +0 -102
  312. package/src/routes/status.ts +0 -46
  313. package/src/routes/subject.ts +0 -152
  314. package/src/types/api.ts +0 -48
  315. package/src/types/index.ts +0 -288
  316. package/src/utils/create-telemetry-options.test.ts +0 -302
  317. package/src/utils/create-telemetry-options.ts +0 -229
  318. package/src/utils/env.ts +0 -84
  319. package/src/utils/extract-error-message.ts +0 -21
  320. package/src/utils/instrumentation.test.ts +0 -185
  321. package/src/utils/instrumentation.ts +0 -196
  322. package/src/utils/logger.ts +0 -41
  323. package/src/utils/metrics.test.ts +0 -323
  324. package/src/utils/metrics.ts +0 -402
  325. package/src/utils/telemetry-pii.test.ts +0 -325
  326. package/src/version.ts +0 -2
  327. package/tsconfig.json +0 -11
  328. package/vitest.config.ts +0 -28
  329. /package/dist/{types.js → types/index.js} +0 -0
  330. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  331. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  332. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  333. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  334. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  335. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  336. /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
- });