@c15t/backend 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +63 -37
- package/CHANGELOG.md +4 -209
- package/README.md +86 -164
- package/dist/contracts/consent/index.d.ts +103 -615
- package/dist/contracts/consent/index.d.ts.map +1 -1
- package/dist/contracts/consent/post.contract.d.ts +42 -140
- package/dist/contracts/consent/post.contract.d.ts.map +1 -1
- package/dist/contracts/consent/show-banner.contract.d.ts +28 -376
- package/dist/contracts/consent/show-banner.contract.d.ts.map +1 -1
- package/dist/contracts/consent/verify.contract.d.ts +33 -99
- package/dist/contracts/consent/verify.contract.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +222 -1356
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/meta/index.d.ts +8 -63
- package/dist/contracts/meta/index.d.ts.map +1 -1
- package/dist/contracts/meta/status.contract.d.ts +8 -63
- package/dist/contracts/meta/status.contract.d.ts.map +1 -1
- package/dist/contracts/shared/jurisdiction.schema.d.ts +21 -9
- package/dist/contracts/shared/jurisdiction.schema.d.ts.map +1 -1
- package/dist/contracts.cjs +100 -106
- package/dist/contracts.js +100 -106
- package/dist/core.cjs +681 -681
- package/dist/core.d.ts +118 -678
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +634 -637
- package/dist/handlers/consent/index.d.ts +103 -615
- package/dist/handlers/consent/index.d.ts.map +1 -1
- package/dist/handlers/consent/post.handler.d.ts +42 -140
- package/dist/handlers/consent/post.handler.d.ts.map +1 -1
- package/dist/handlers/consent/show-banner/handler.d.ts +28 -376
- package/dist/handlers/consent/show-banner/handler.d.ts.map +1 -1
- package/dist/handlers/consent/show-banner/translations.d.ts.map +1 -1
- package/dist/handlers/consent/verify.handler.d.ts +33 -99
- package/dist/handlers/consent/verify.handler.d.ts.map +1 -1
- package/dist/handlers/meta/index.d.ts +8 -63
- package/dist/handlers/meta/index.d.ts.map +1 -1
- package/dist/handlers/meta/status.handler.d.ts +8 -63
- package/dist/handlers/meta/status.handler.d.ts.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/middleware/openapi/index.d.ts +2 -2
- package/dist/middleware/openapi/index.d.ts.map +1 -1
- package/dist/pkgs/data-model/fields/index.cjs +14 -26
- package/dist/pkgs/data-model/fields/index.d.ts +4 -4
- package/dist/pkgs/data-model/fields/index.d.ts.map +1 -1
- package/dist/pkgs/data-model/fields/index.js +14 -26
- package/dist/pkgs/data-model/fields/zod-fields.d.ts +195 -871
- package/dist/pkgs/data-model/fields/zod-fields.d.ts.map +1 -1
- package/dist/pkgs/data-model/hooks/index.d.ts +2 -2
- package/dist/pkgs/data-model/hooks/index.d.ts.map +1 -1
- package/dist/pkgs/data-model/index.cjs +346 -358
- package/dist/pkgs/data-model/index.d.ts +1 -1
- package/dist/pkgs/data-model/index.d.ts.map +1 -1
- package/dist/pkgs/data-model/index.js +345 -357
- package/dist/pkgs/data-model/schema/index.cjs +346 -358
- package/dist/pkgs/data-model/schema/index.d.ts +1 -1
- package/dist/pkgs/data-model/schema/index.d.ts.map +1 -1
- package/dist/pkgs/data-model/schema/index.js +345 -357
- package/dist/pkgs/data-model/schema/schemas.d.ts +2 -2
- package/dist/pkgs/data-model/schema/schemas.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts +3 -0
- package/dist/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.cjs +158 -170
- package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.js +157 -169
- package/dist/pkgs/db-adapters/adapters/index.d.ts +2 -2
- package/dist/pkgs/db-adapters/adapters/index.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.cjs +215 -227
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.d.ts +2 -2
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.js +213 -225
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts +2 -0
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts +1 -1
- package/dist/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/memory-adapter/index.cjs +158 -170
- package/dist/pkgs/db-adapters/adapters/memory-adapter/index.js +157 -169
- package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts +3 -0
- package/dist/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.cjs +243 -255
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.d.ts +1 -1
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.js +241 -253
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts +3 -0
- package/dist/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/index.cjs +714 -726
- package/dist/pkgs/db-adapters/index.d.ts +6 -6
- package/dist/pkgs/db-adapters/index.d.ts.map +1 -1
- package/dist/pkgs/db-adapters/index.js +708 -720
- package/dist/pkgs/migrations/get-migration.d.ts.map +1 -1
- package/dist/pkgs/migrations/get-schema/get-schema.d.ts.map +1 -1
- package/dist/pkgs/migrations/get-schema/process-tables.d.ts.map +1 -1
- package/dist/pkgs/migrations/index.cjs +236 -248
- package/dist/pkgs/migrations/index.d.ts +4 -4
- package/dist/pkgs/migrations/index.d.ts.map +1 -1
- package/dist/pkgs/migrations/index.js +235 -247
- package/dist/pkgs/results/index.cjs +67 -67
- package/dist/pkgs/results/index.d.ts +5 -5
- package/dist/pkgs/results/index.d.ts.map +1 -1
- package/dist/pkgs/results/index.js +67 -67
- package/dist/pkgs/results/orpc-error-handler.d.ts +1 -1
- package/dist/pkgs/results/orpc-error-handler.d.ts.map +1 -1
- package/dist/pkgs/types/index.d.ts +1 -2
- package/dist/pkgs/types/index.d.ts.map +1 -1
- package/dist/pkgs/types/options.d.ts +9 -2
- package/dist/pkgs/types/options.d.ts.map +1 -1
- package/dist/pkgs/utils/index.d.ts +1 -1
- package/dist/pkgs/utils/index.d.ts.map +1 -1
- package/dist/pkgs/utils/logger.d.ts +1 -1
- package/dist/pkgs/utils/logger.d.ts.map +1 -1
- package/dist/router.cjs +114 -117
- package/dist/router.d.ts +111 -678
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +114 -117
- package/dist/schema/audit-log/schema.d.ts +2 -24
- package/dist/schema/audit-log/schema.d.ts.map +1 -1
- package/dist/schema/audit-log/table.d.ts +2 -24
- package/dist/schema/audit-log/table.d.ts.map +1 -1
- package/dist/schema/consent/registry.d.ts +8 -8
- package/dist/schema/consent/schema.d.ts +9 -33
- package/dist/schema/consent/schema.d.ts.map +1 -1
- package/dist/schema/consent/table.d.ts +9 -33
- package/dist/schema/consent/table.d.ts.map +1 -1
- package/dist/schema/consent-policy/registry.d.ts +20 -20
- package/dist/schema/consent-policy/schema.d.ts +22 -30
- package/dist/schema/consent-policy/schema.d.ts.map +1 -1
- package/dist/schema/consent-policy/table.d.ts +13 -29
- package/dist/schema/consent-policy/table.d.ts.map +1 -1
- package/dist/schema/consent-purpose/registry.d.ts +6 -6
- package/dist/schema/consent-purpose/schema.d.ts +5 -27
- package/dist/schema/consent-purpose/schema.d.ts.map +1 -1
- package/dist/schema/consent-purpose/table.d.ts +5 -27
- package/dist/schema/consent-purpose/table.d.ts.map +1 -1
- package/dist/schema/consent-record/schema.d.ts +3 -19
- package/dist/schema/consent-record/schema.d.ts.map +1 -1
- package/dist/schema/consent-record/table.d.ts +3 -19
- package/dist/schema/consent-record/table.d.ts.map +1 -1
- package/dist/schema/create-registry.d.ts +58 -58
- package/dist/schema/definition.d.ts +42 -176
- package/dist/schema/definition.d.ts.map +1 -1
- package/dist/schema/domain/registry.d.ts +20 -20
- package/dist/schema/domain/schema.d.ts +6 -24
- package/dist/schema/domain/schema.d.ts.map +1 -1
- package/dist/schema/domain/table.d.ts +6 -24
- package/dist/schema/domain/table.d.ts.map +1 -1
- package/dist/schema/index.cjs +426 -438
- package/dist/schema/index.d.ts +12 -12
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +426 -438
- package/dist/schema/schemas.d.ts +42 -176
- package/dist/schema/schemas.d.ts.map +1 -1
- package/dist/schema/subject/registry.d.ts +4 -4
- package/dist/schema/subject/schema.d.ts +4 -20
- package/dist/schema/subject/schema.d.ts.map +1 -1
- package/dist/schema/subject/table.d.ts +4 -20
- package/dist/schema/subject/table.d.ts.map +1 -1
- package/dist/schema/types.d.ts +1 -1
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/testing/contract-testing.d.ts +3 -2
- package/dist/testing/contract-testing.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/options.d.ts +2 -2
- package/dist/types/options.d.ts.map +1 -1
- package/dist/v2/contracts/consent/index.d.ts +260 -0
- package/dist/v2/contracts/consent/index.d.ts.map +1 -0
- package/dist/v2/contracts/consent/index.test.d.ts +2 -0
- package/dist/v2/contracts/consent/index.test.d.ts.map +1 -0
- package/dist/v2/contracts/consent/post.contract.d.ts +114 -0
- package/dist/v2/contracts/consent/post.contract.d.ts.map +1 -0
- package/dist/v2/contracts/consent/post.contract.test.d.ts +2 -0
- package/dist/v2/contracts/consent/post.contract.test.d.ts.map +1 -0
- package/dist/v2/contracts/consent/show-banner.contract.d.ts +68 -0
- package/dist/v2/contracts/consent/show-banner.contract.d.ts.map +1 -0
- package/dist/v2/contracts/consent/show-banner.contract.test.d.ts +2 -0
- package/dist/v2/contracts/consent/show-banner.contract.test.d.ts.map +1 -0
- package/dist/v2/contracts/consent/verify.contract.d.ts +81 -0
- package/dist/v2/contracts/consent/verify.contract.d.ts.map +1 -0
- package/dist/v2/contracts/consent/verify.contract.test.d.ts +2 -0
- package/dist/v2/contracts/consent/verify.contract.test.d.ts.map +1 -0
- package/dist/v2/contracts/index.cjs +644 -0
- package/dist/v2/contracts/index.d.ts +563 -0
- package/dist/v2/contracts/index.d.ts.map +1 -0
- package/dist/v2/contracts/index.js +607 -0
- package/dist/v2/contracts/meta/index.d.ts +19 -0
- package/dist/v2/contracts/meta/index.d.ts.map +1 -0
- package/dist/v2/contracts/meta/index.test.d.ts +2 -0
- package/dist/v2/contracts/meta/index.test.d.ts.map +1 -0
- package/dist/v2/contracts/meta/status.contract.d.ts +18 -0
- package/dist/v2/contracts/meta/status.contract.d.ts.map +1 -0
- package/dist/v2/contracts/meta/status.contract.test.d.ts +2 -0
- package/dist/v2/contracts/meta/status.contract.test.d.ts.map +1 -0
- package/dist/v2/contracts/shared/jurisdiction.schema.d.ts +36 -0
- package/dist/v2/contracts/shared/jurisdiction.schema.d.ts.map +1 -0
- package/dist/v2/contracts/test.utils.d.ts +38 -0
- package/dist/v2/contracts/test.utils.d.ts.map +1 -0
- package/dist/v2/core.cjs +2181 -0
- package/dist/v2/core.d.ts +364 -0
- package/dist/v2/core.d.ts.map +1 -0
- package/dist/v2/core.js +2130 -0
- package/dist/v2/db/adapters/drizzle.cjs +36 -0
- package/dist/v2/db/adapters/drizzle.d.ts +2 -0
- package/dist/v2/db/adapters/drizzle.d.ts.map +1 -0
- package/dist/v2/db/adapters/drizzle.js +3 -0
- package/dist/v2/db/adapters/index.cjs +18 -0
- package/dist/v2/db/adapters/index.d.ts +2 -0
- package/dist/v2/db/adapters/index.d.ts.map +1 -0
- package/dist/v2/db/adapters/index.js +0 -0
- package/dist/v2/db/adapters/kysely.cjs +36 -0
- package/dist/v2/db/adapters/kysely.d.ts +2 -0
- package/dist/v2/db/adapters/kysely.d.ts.map +1 -0
- package/dist/v2/db/adapters/kysely.js +3 -0
- package/dist/v2/db/adapters/mongo.cjs +36 -0
- package/dist/v2/db/adapters/mongo.d.ts +2 -0
- package/dist/v2/db/adapters/mongo.d.ts.map +1 -0
- package/dist/v2/db/adapters/mongo.js +3 -0
- package/dist/v2/db/adapters/prisma.cjs +36 -0
- package/dist/v2/db/adapters/prisma.d.ts +2 -0
- package/dist/v2/db/adapters/prisma.d.ts.map +1 -0
- package/dist/v2/db/adapters/prisma.js +3 -0
- package/dist/v2/db/adapters/typeorm.cjs +36 -0
- package/dist/v2/db/adapters/typeorm.d.ts +2 -0
- package/dist/v2/db/adapters/typeorm.d.ts.map +1 -0
- package/dist/v2/db/adapters/typeorm.js +3 -0
- package/dist/v2/db/migrator/index.cjs +61 -0
- package/dist/v2/db/migrator/index.d.ts +29 -0
- package/dist/v2/db/migrator/index.d.ts.map +1 -0
- package/dist/v2/db/migrator/index.js +27 -0
- package/dist/v2/db/registry/audit-log.d.ts +21 -0
- package/dist/v2/db/registry/audit-log.d.ts.map +1 -0
- package/dist/v2/db/registry/audit-log.test.d.ts +2 -0
- package/dist/v2/db/registry/audit-log.test.d.ts.map +1 -0
- package/dist/v2/db/registry/consent-policy.d.ts +29 -0
- package/dist/v2/db/registry/consent-policy.d.ts.map +1 -0
- package/dist/v2/db/registry/consent-policy.test.d.ts +2 -0
- package/dist/v2/db/registry/consent-policy.test.d.ts.map +1 -0
- package/dist/v2/db/registry/consent-purpose.d.ts +16 -0
- package/dist/v2/db/registry/consent-purpose.d.ts.map +1 -0
- package/dist/v2/db/registry/consent-purpose.test.d.ts +2 -0
- package/dist/v2/db/registry/consent-purpose.test.d.ts.map +1 -0
- package/dist/v2/db/registry/consent.d.ts +20 -0
- package/dist/v2/db/registry/consent.d.ts.map +1 -0
- package/dist/v2/db/registry/consent.test.d.ts +2 -0
- package/dist/v2/db/registry/consent.test.d.ts.map +1 -0
- package/dist/v2/db/registry/domain.d.ts +24 -0
- package/dist/v2/db/registry/domain.d.ts.map +1 -0
- package/dist/v2/db/registry/domain.test.d.ts +2 -0
- package/dist/v2/db/registry/domain.test.d.ts.map +1 -0
- package/dist/v2/db/registry/index.d.ts +102 -0
- package/dist/v2/db/registry/index.d.ts.map +1 -0
- package/dist/v2/db/registry/subject.d.ts +18 -0
- package/dist/v2/db/registry/subject.d.ts.map +1 -0
- package/dist/v2/db/registry/subject.test.d.ts +2 -0
- package/dist/v2/db/registry/subject.test.d.ts.map +1 -0
- package/dist/v2/db/registry/types.d.ts +10 -0
- package/dist/v2/db/registry/types.d.ts.map +1 -0
- package/dist/v2/db/registry/utils/generate-id.d.ts +25 -0
- package/dist/v2/db/registry/utils/generate-id.d.ts.map +1 -0
- package/dist/v2/db/registry/utils/generate-id.test.d.ts +2 -0
- package/dist/v2/db/registry/utils/generate-id.test.d.ts.map +1 -0
- package/dist/v2/db/registry/utils.d.ts +25 -0
- package/dist/v2/db/registry/utils.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/audit-log.d.ts +29 -0
- package/dist/v2/db/schema/1.0.0/audit-log.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/consent-policy.d.ts +45 -0
- package/dist/v2/db/schema/1.0.0/consent-policy.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/consent-purpose.d.ts +27 -0
- package/dist/v2/db/schema/1.0.0/consent-purpose.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/consent-record.d.ts +19 -0
- package/dist/v2/db/schema/1.0.0/consent-record.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/consent.d.ts +42 -0
- package/dist/v2/db/schema/1.0.0/consent.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/domain.d.ts +23 -0
- package/dist/v2/db/schema/1.0.0/domain.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/index.d.ts +1513 -0
- package/dist/v2/db/schema/1.0.0/index.d.ts.map +1 -0
- package/dist/v2/db/schema/1.0.0/subject.d.ts +23 -0
- package/dist/v2/db/schema/1.0.0/subject.d.ts.map +1 -0
- package/dist/v2/db/schema/index.cjs +326 -0
- package/dist/v2/db/schema/index.d.ts +1507 -0
- package/dist/v2/db/schema/index.d.ts.map +1 -0
- package/dist/v2/db/schema/index.js +241 -0
- package/dist/v2/define-config.cjs +36 -0
- package/dist/v2/define-config.d.ts +5 -0
- package/dist/v2/define-config.d.ts.map +1 -0
- package/dist/v2/define-config.js +2 -0
- package/dist/v2/handlers/consent/index.d.ts +260 -0
- package/dist/v2/handlers/consent/index.d.ts.map +1 -0
- package/dist/v2/handlers/consent/post.handler.d.ts +136 -0
- package/dist/v2/handlers/consent/post.handler.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/geo.d.ts +10 -0
- package/dist/v2/handlers/consent/show-banner/geo.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/geo.test.d.ts +2 -0
- package/dist/v2/handlers/consent/show-banner/geo.test.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/handler.d.ts +71 -0
- package/dist/v2/handlers/consent/show-banner/handler.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/handler.test.d.ts +2 -0
- package/dist/v2/handlers/consent/show-banner/handler.test.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/translations.d.ts +13 -0
- package/dist/v2/handlers/consent/show-banner/translations.d.ts.map +1 -0
- package/dist/v2/handlers/consent/show-banner/translations.test.d.ts +2 -0
- package/dist/v2/handlers/consent/show-banner/translations.test.d.ts.map +1 -0
- package/dist/v2/handlers/consent/verify.handler.d.ts +103 -0
- package/dist/v2/handlers/consent/verify.handler.d.ts.map +1 -0
- package/dist/v2/handlers/meta/index.d.ts +19 -0
- package/dist/v2/handlers/meta/index.d.ts.map +1 -0
- package/dist/v2/handlers/meta/status.handler.d.ts +17 -0
- package/dist/v2/handlers/meta/status.handler.d.ts.map +1 -0
- package/dist/v2/init.d.ts +3 -0
- package/dist/v2/init.d.ts.map +1 -0
- package/dist/v2/init.test.d.ts +2 -0
- package/dist/v2/init.test.d.ts.map +1 -0
- package/dist/v2/middleware/cors/cors.d.ts +37 -0
- package/dist/v2/middleware/cors/cors.d.ts.map +1 -0
- package/dist/v2/middleware/cors/cors.test.d.ts +2 -0
- package/dist/v2/middleware/cors/cors.test.d.ts.map +1 -0
- package/dist/v2/middleware/cors/index.d.ts +30 -0
- package/dist/v2/middleware/cors/index.d.ts.map +1 -0
- package/dist/v2/middleware/cors/is-origin-trusted.d.ts +49 -0
- package/dist/v2/middleware/cors/is-origin-trusted.d.ts.map +1 -0
- package/dist/v2/middleware/cors/is-origin-trusted.test.d.ts +2 -0
- package/dist/v2/middleware/cors/is-origin-trusted.test.d.ts.map +1 -0
- package/dist/v2/middleware/cors/process-cors.d.ts +31 -0
- package/dist/v2/middleware/cors/process-cors.d.ts.map +1 -0
- package/dist/v2/middleware/openapi/config.d.ts +28 -0
- package/dist/v2/middleware/openapi/config.d.ts.map +1 -0
- package/dist/v2/middleware/openapi/handlers.d.ts +29 -0
- package/dist/v2/middleware/openapi/handlers.d.ts.map +1 -0
- package/dist/v2/middleware/openapi/index.d.ts +11 -0
- package/dist/v2/middleware/openapi/index.d.ts.map +1 -0
- package/dist/v2/middleware/process-ip/index.d.ts +3 -0
- package/dist/v2/middleware/process-ip/index.d.ts.map +1 -0
- package/dist/v2/router.cjs +1275 -0
- package/dist/v2/router.d.ts +280 -0
- package/dist/v2/router.d.ts.map +1 -0
- package/dist/v2/router.js +1231 -0
- package/dist/v2/types/api.d.ts +27 -0
- package/dist/v2/types/api.d.ts.map +1 -0
- package/dist/v2/types/index.cjs +40 -0
- package/dist/v2/types/index.d.ts +104 -0
- package/dist/v2/types/index.d.ts.map +1 -0
- package/dist/v2/types/index.js +6 -0
- package/dist/v2/utils/create-telemetry-options.d.ts +28 -0
- package/dist/v2/utils/create-telemetry-options.d.ts.map +1 -0
- package/dist/v2/utils/env.d.ts +60 -0
- package/dist/v2/utils/env.d.ts.map +1 -0
- package/dist/v2/utils/index.d.ts +3 -0
- package/dist/v2/utils/index.d.ts.map +1 -0
- package/dist/v2/utils/logger.d.ts +16 -0
- package/dist/v2/utils/logger.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +106 -15
- package/readme.json +30 -0
- package/rslib.config.ts +13 -14
- package/src/__tests__/server.test.ts +1 -1
- package/src/contracts/consent/post.contract.test.ts +3 -8
- package/src/contracts/consent/post.contract.ts +13 -13
- package/src/contracts/consent/show-banner.contract.test.ts +9 -0
- package/src/contracts/consent/show-banner.contract.ts +2 -0
- package/src/contracts/consent/verify.contract.ts +19 -23
- package/src/core.ts +7 -0
- package/src/handlers/consent/show-banner/handler.ts +12 -9
- package/src/handlers/consent/show-banner/translations.ts +2 -2
- package/src/init.ts +9 -6
- package/src/middleware/openapi/index.ts +2 -2
- package/src/pkgs/api-router/hooks/__tests__/processor.test.ts +1 -1
- package/src/pkgs/data-model/fields/index.ts +17 -22
- package/src/pkgs/data-model/fields/zod-fields.ts +14 -26
- package/src/pkgs/data-model/hooks/index.ts +3 -2
- package/src/pkgs/data-model/index.ts +2 -4
- package/src/pkgs/data-model/schema/index.ts +6 -7
- package/src/pkgs/data-model/schema/schemas.ts +3 -3
- package/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts +4 -1
- package/src/pkgs/db-adapters/adapters/index.ts +2 -2
- package/src/pkgs/db-adapters/adapters/kysely-adapter/index.ts +4 -4
- package/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts +4 -5
- package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/postgres.test.ts +2 -4
- package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/sqlite.test.ts +2 -3
- package/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts +1 -6
- package/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts +4 -1
- package/src/pkgs/db-adapters/adapters/prisma-adapter/index.ts +1 -1
- package/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts +5 -2
- package/src/pkgs/db-adapters/index.ts +12 -13
- package/src/pkgs/migrations/get-migration.ts +4 -2
- package/src/pkgs/migrations/get-schema/get-schema.ts +0 -1
- package/src/pkgs/migrations/get-schema/process-fields.ts +1 -1
- package/src/pkgs/migrations/get-schema/process-tables.ts +0 -2
- package/src/pkgs/migrations/index.ts +7 -8
- package/src/pkgs/results/__tests__/error-codes.test.ts +2 -2
- package/src/pkgs/results/index.ts +22 -27
- package/src/pkgs/results/orpc-error-handler.ts +1 -1
- package/src/pkgs/results/results/result-helpers.ts +1 -1
- package/src/pkgs/types/index.ts +4 -4
- package/src/pkgs/types/options.ts +10 -3
- package/src/pkgs/utils/index.ts +1 -1
- package/src/pkgs/utils/logger.ts +1 -1
- package/src/schema/audit-log/schema.ts +3 -3
- package/src/schema/consent/schema.ts +4 -4
- package/src/schema/consent-policy/schema.ts +3 -3
- package/src/schema/consent-purpose/schema.ts +4 -4
- package/src/schema/consent-record/schema.ts +3 -3
- package/src/schema/definition.ts +1 -1
- package/src/schema/domain/schema.ts +5 -5
- package/src/schema/index.ts +14 -17
- package/src/schema/subject/schema.ts +3 -3
- package/src/schema/types.ts +1 -1
- package/src/testing/contract-testing.ts +15 -52
- package/src/types/index.ts +8 -8
- package/src/types/options.ts +2 -3
- package/src/v2/contracts/consent/index.test.ts +5 -0
- package/src/v2/contracts/consent/index.ts +9 -0
- package/src/v2/contracts/consent/post.contract.test.ts +521 -0
- package/src/v2/contracts/consent/post.contract.ts +155 -0
- package/src/v2/contracts/consent/show-banner.contract.test.ts +252 -0
- package/src/v2/contracts/consent/show-banner.contract.ts +73 -0
- package/src/v2/contracts/consent/verify.contract.test.ts +185 -0
- package/src/v2/contracts/consent/verify.contract.ts +122 -0
- package/src/v2/contracts/index.ts +20 -0
- package/src/v2/contracts/meta/index.test.ts +5 -0
- package/src/v2/contracts/meta/index.ts +5 -0
- package/src/v2/contracts/meta/status.contract.test.ts +226 -0
- package/src/v2/contracts/meta/status.contract.ts +34 -0
- package/src/v2/contracts/shared/jurisdiction.schema.ts +30 -0
- package/src/v2/contracts/test.utils.ts +400 -0
- package/src/v2/core.ts +379 -0
- package/src/v2/db/adapters/drizzle.ts +1 -0
- package/src/v2/db/adapters/index.ts +1 -0
- package/src/v2/db/adapters/kysely.ts +1 -0
- package/src/v2/db/adapters/mongo.ts +1 -0
- package/src/v2/db/adapters/prisma.ts +1 -0
- package/src/v2/db/adapters/typeorm.ts +1 -0
- package/src/v2/db/migrator/index.ts +80 -0
- package/src/v2/db/registry/audit-log.test.ts +77 -0
- package/src/v2/db/registry/audit-log.ts +46 -0
- package/src/v2/db/registry/consent-policy.test.ts +778 -0
- package/src/v2/db/registry/consent-policy.ts +74 -0
- package/src/v2/db/registry/consent-purpose.test.ts +485 -0
- package/src/v2/db/registry/consent-purpose.ts +41 -0
- package/src/v2/db/registry/consent.test.ts +843 -0
- package/src/v2/db/registry/consent.ts +42 -0
- package/src/v2/db/registry/domain.test.ts +463 -0
- package/src/v2/db/registry/domain.ts +51 -0
- package/src/v2/db/registry/index.ts +18 -0
- package/src/v2/db/registry/subject.test.ts +497 -0
- package/src/v2/db/registry/subject.ts +101 -0
- package/src/v2/db/registry/types.ts +10 -0
- package/src/v2/db/registry/utils/generate-id.test.ts +217 -0
- package/src/v2/db/registry/utils/generate-id.ts +134 -0
- package/src/v2/db/registry/utils.ts +134 -0
- package/src/v2/db/schema/1.0.0/audit-log.ts +32 -0
- package/src/v2/db/schema/1.0.0/consent-policy.ts +41 -0
- package/src/v2/db/schema/1.0.0/consent-purpose.ts +30 -0
- package/src/v2/db/schema/1.0.0/consent-record.ts +22 -0
- package/src/v2/db/schema/1.0.0/consent.ts +38 -0
- package/src/v2/db/schema/1.0.0/domain.ts +26 -0
- package/src/v2/db/schema/1.0.0/index.ts +56 -0
- package/src/v2/db/schema/1.0.0/subject.ts +26 -0
- package/src/v2/db/schema/index.ts +9 -0
- package/src/v2/define-config.ts +5 -0
- package/src/v2/handlers/consent/index.ts +9 -0
- package/src/v2/handlers/consent/post.handler.ts +254 -0
- package/src/v2/handlers/consent/show-banner/geo.test.ts +281 -0
- package/src/v2/handlers/consent/show-banner/geo.ts +96 -0
- package/src/v2/handlers/consent/show-banner/handler.test.ts +374 -0
- package/src/v2/handlers/consent/show-banner/handler.ts +123 -0
- package/src/v2/handlers/consent/show-banner/translations.test.ts +121 -0
- package/src/v2/handlers/consent/show-banner/translations.ts +79 -0
- package/src/v2/handlers/consent/verify.handler.ts +288 -0
- package/src/v2/handlers/meta/index.ts +5 -0
- package/src/v2/handlers/meta/status.handler.ts +43 -0
- package/src/v2/init.test.ts +114 -0
- package/src/v2/init.ts +126 -0
- package/src/v2/middleware/cors/cors.test.ts +111 -0
- package/src/v2/middleware/cors/cors.ts +192 -0
- package/src/v2/middleware/cors/index.ts +30 -0
- package/src/v2/middleware/cors/is-origin-trusted.test.ts +104 -0
- package/src/v2/middleware/cors/is-origin-trusted.ts +126 -0
- package/src/v2/middleware/cors/process-cors.ts +91 -0
- package/src/v2/middleware/openapi/config.ts +27 -0
- package/src/v2/middleware/openapi/handlers.ts +132 -0
- package/src/v2/middleware/openapi/index.ts +11 -0
- package/src/v2/middleware/process-ip/index.ts +39 -0
- package/src/v2/router.ts +8 -0
- package/src/v2/types/api.ts +32 -0
- package/src/v2/types/index.ts +121 -0
- package/src/v2/utils/create-telemetry-options.ts +115 -0
- package/src/v2/utils/env.ts +84 -0
- package/src/v2/utils/index.ts +2 -0
- package/src/v2/utils/logger.ts +38 -0
- package/src/version.ts +1 -1
- package/vitest.config.ts +11 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createCORSOptions } from './cors';
|
|
3
|
+
|
|
4
|
+
describe('createCORSOptions (unit)', () => {
|
|
5
|
+
describe('configuration shape', () => {
|
|
6
|
+
it('returns expected defaults when no trustedOrigins provided', async () => {
|
|
7
|
+
const config = createCORSOptions();
|
|
8
|
+
expect(config.credentials).toBe(true);
|
|
9
|
+
expect(config.maxAge).toBe(600);
|
|
10
|
+
expect(config.allowHeaders).toEqual([
|
|
11
|
+
'Content-Type',
|
|
12
|
+
'Authorization',
|
|
13
|
+
'x-request-id',
|
|
14
|
+
]);
|
|
15
|
+
expect(config.methods).toEqual([
|
|
16
|
+
'GET',
|
|
17
|
+
'POST',
|
|
18
|
+
'PUT',
|
|
19
|
+
'DELETE',
|
|
20
|
+
'PATCH',
|
|
21
|
+
'OPTIONS',
|
|
22
|
+
]);
|
|
23
|
+
// origin present -> echo
|
|
24
|
+
expect(await config.origin('http://localhost:3002')).toBe(
|
|
25
|
+
'http://localhost:3002'
|
|
26
|
+
);
|
|
27
|
+
// no origin -> '*'
|
|
28
|
+
expect(await config.origin('')).toBe('*');
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('wildcard "*"', () => {
|
|
33
|
+
it('allows any concrete origin and echoes it back', async () => {
|
|
34
|
+
const config = createCORSOptions(['*']);
|
|
35
|
+
expect(await config.origin('http://localhost:3002')).toBe(
|
|
36
|
+
'http://localhost:3002'
|
|
37
|
+
);
|
|
38
|
+
// missing origin -> '*'
|
|
39
|
+
expect(await config.origin('')).toBe('*');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('specific origins', () => {
|
|
44
|
+
it('allows trusted origin and rejects untrusted', async () => {
|
|
45
|
+
const config = createCORSOptions(['http://localhost:3002']);
|
|
46
|
+
expect(await config.origin('http://localhost:3002')).toBe(
|
|
47
|
+
'http://localhost:3002'
|
|
48
|
+
);
|
|
49
|
+
expect(await config.origin('http://malicious-site.com')).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('treats localhost variants (ports, IPs) as trusted when "localhost" provided', async () => {
|
|
53
|
+
const config = createCORSOptions(['localhost']);
|
|
54
|
+
expect(await config.origin('http://localhost:1234')).toBe(
|
|
55
|
+
'http://localhost:1234'
|
|
56
|
+
);
|
|
57
|
+
expect(await config.origin('http://127.0.0.1:3000')).toBe(
|
|
58
|
+
'http://127.0.0.1:3000'
|
|
59
|
+
);
|
|
60
|
+
expect(await config.origin('http://[::1]:3000')).toBe(
|
|
61
|
+
'http://[::1]:3000'
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('www and non-www variants', () => {
|
|
67
|
+
it('allows www when non-www is trusted', async () => {
|
|
68
|
+
const config = createCORSOptions(['http://c15t.com']);
|
|
69
|
+
expect(await config.origin('http://www.c15t.com')).toBe(
|
|
70
|
+
'http://www.c15t.com'
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('allows non-www when www is trusted', async () => {
|
|
75
|
+
const config = createCORSOptions(['http://www.c15t.com']);
|
|
76
|
+
expect(await config.origin('http://c15t.com')).toBe('http://c15t.com');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('ports and protocols', () => {
|
|
81
|
+
it('matches with exact port when provided', async () => {
|
|
82
|
+
const config = createCORSOptions(['localhost:3002']);
|
|
83
|
+
expect(await config.origin('http://localhost:3002')).toBe(
|
|
84
|
+
'http://localhost:3002'
|
|
85
|
+
);
|
|
86
|
+
expect(await config.origin('http://localhost:4000')).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('is protocol-agnostic for host comparison', async () => {
|
|
90
|
+
const config = createCORSOptions(['example.com']);
|
|
91
|
+
expect(await config.origin('http://example.com')).toBe(
|
|
92
|
+
'http://example.com'
|
|
93
|
+
);
|
|
94
|
+
expect(await config.origin('https://www.example.com')).toBe(
|
|
95
|
+
'https://www.example.com'
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('invalid or missing origins', () => {
|
|
101
|
+
it('returns null for clearly invalid origins', async () => {
|
|
102
|
+
const config = createCORSOptions(['example.com']);
|
|
103
|
+
expect(await config.origin('::::invalid::::')).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('returns "*" when origin header is missing/empty', async () => {
|
|
107
|
+
const config = createCORSOptions(['*']);
|
|
108
|
+
expect(await config.origin('')).toBe('*');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS middleware utility for c15t that handles origin validation and CORS headers
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Regular expression to match www prefix in domain names */
|
|
8
|
+
const WWW_REGEX = /^www\./;
|
|
9
|
+
|
|
10
|
+
/** Regular expression to match protocol and www prefix in URLs */
|
|
11
|
+
const PROTOCOL_WWW_REGEX = /^https?:\/\/(www\.)?/;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Supported HTTP methods for CORS
|
|
15
|
+
*/
|
|
16
|
+
const SUPPORTED_METHODS = [
|
|
17
|
+
'GET',
|
|
18
|
+
'POST',
|
|
19
|
+
'PUT',
|
|
20
|
+
'DELETE',
|
|
21
|
+
'PATCH',
|
|
22
|
+
'OPTIONS',
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Supported headers for CORS requests
|
|
27
|
+
*/
|
|
28
|
+
const SUPPORTED_HEADERS = [
|
|
29
|
+
'Content-Type',
|
|
30
|
+
'Authorization',
|
|
31
|
+
'x-request-id',
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* CORS configuration options type
|
|
36
|
+
*/
|
|
37
|
+
export interface CORSConfig {
|
|
38
|
+
/** Origin validation function */
|
|
39
|
+
origin: (origin: string) => Promise<string | null>;
|
|
40
|
+
/** Whether to allow credentials */
|
|
41
|
+
credentials: boolean;
|
|
42
|
+
/** Allowed headers */
|
|
43
|
+
allowHeaders: readonly string[];
|
|
44
|
+
/** Max age for preflight requests */
|
|
45
|
+
maxAge: number;
|
|
46
|
+
/** Allowed HTTP methods */
|
|
47
|
+
methods: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Default CORS configuration for unrestricted access
|
|
52
|
+
*/
|
|
53
|
+
const DEFAULT_CORS_CONFIG: CORSConfig = {
|
|
54
|
+
origin: async (origin: string) => {
|
|
55
|
+
// For default config, always return the origin if it exists, or '*' if it doesn't
|
|
56
|
+
return await Promise.resolve(origin || '*');
|
|
57
|
+
},
|
|
58
|
+
credentials: true,
|
|
59
|
+
allowHeaders: SUPPORTED_HEADERS,
|
|
60
|
+
maxAge: 600,
|
|
61
|
+
methods: SUPPORTED_METHODS,
|
|
62
|
+
} as const;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates CORS options configuration for the c15t middleware
|
|
66
|
+
*
|
|
67
|
+
* @param trustedOrigins - Array of allowed origin patterns or single string. Can include wildcards ('*').
|
|
68
|
+
* If undefined, defaults to allowing all origins without credentials.
|
|
69
|
+
*
|
|
70
|
+
* @returns CORS configuration object with origin validation function and header settings
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const corsOptions = createCORSOptions(['http://localhost:3000', 'https://example.com']);
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @throws {TypeError} When URL parsing fails in origin validation
|
|
78
|
+
*/
|
|
79
|
+
export function createCORSOptions(
|
|
80
|
+
trustedOrigins?: string[] | string
|
|
81
|
+
): CORSConfig {
|
|
82
|
+
// If trustedOrigins is undefined or empty, return default config that allows all origins
|
|
83
|
+
if (!trustedOrigins) {
|
|
84
|
+
return DEFAULT_CORS_CONFIG;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Convert string to array if needed
|
|
88
|
+
const origins = Array.isArray(trustedOrigins)
|
|
89
|
+
? trustedOrigins
|
|
90
|
+
: [trustedOrigins];
|
|
91
|
+
if (origins.length === 0) {
|
|
92
|
+
return DEFAULT_CORS_CONFIG;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Normalizes an origin string by removing protocol and www prefix
|
|
97
|
+
*
|
|
98
|
+
* @param origin - The origin URL to normalize
|
|
99
|
+
* @returns Normalized origin string without protocol and www prefix
|
|
100
|
+
*
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
function normalizeOrigin(origin: string): string {
|
|
104
|
+
try {
|
|
105
|
+
// Handle bare domains like 'localhost' or 'example.com'
|
|
106
|
+
if (
|
|
107
|
+
!origin.includes('://') &&
|
|
108
|
+
!origin.includes(':') &&
|
|
109
|
+
!origin.includes('/')
|
|
110
|
+
) {
|
|
111
|
+
return origin.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
// Add protocol if missing
|
|
114
|
+
const originWithProtocol =
|
|
115
|
+
origin.startsWith('http://') ||
|
|
116
|
+
origin.startsWith('https://') ||
|
|
117
|
+
origin.startsWith('ws://') ||
|
|
118
|
+
origin.startsWith('wss://')
|
|
119
|
+
? origin
|
|
120
|
+
: `http://${origin}`;
|
|
121
|
+
const url = new URL(originWithProtocol);
|
|
122
|
+
const hostname = url.hostname.replace(WWW_REGEX, '');
|
|
123
|
+
// Return without protocol to match both http and https
|
|
124
|
+
return `${hostname}${url.port ? `:${url.port}` : ''}`;
|
|
125
|
+
} catch {
|
|
126
|
+
// Fallback: remove www manually and protocol
|
|
127
|
+
return origin.replace(PROTOCOL_WWW_REGEX, '').replace(WWW_REGEX, '');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Expands a list of origins to include www variants
|
|
133
|
+
*
|
|
134
|
+
* @param origins - Array of origin strings to expand
|
|
135
|
+
* @returns Array of origins including www variants
|
|
136
|
+
*
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
function expandWithWWW(origins: string[]): string[] {
|
|
140
|
+
const expanded = new Set<string>();
|
|
141
|
+
for (const origin of origins) {
|
|
142
|
+
if (origin === '*') {
|
|
143
|
+
expanded.add('*');
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const normalized = normalizeOrigin(origin);
|
|
147
|
+
expanded.add(normalized);
|
|
148
|
+
// Add www version if not already present
|
|
149
|
+
if (!normalized.includes('www.')) {
|
|
150
|
+
expanded.add(`www.${normalized}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return Array.from(expanded);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const expandedTrusted = expandWithWWW(origins);
|
|
157
|
+
|
|
158
|
+
const returnConfig = {
|
|
159
|
+
origin: async (origin: string) => {
|
|
160
|
+
if (!origin) {
|
|
161
|
+
return '*';
|
|
162
|
+
}
|
|
163
|
+
const normalizedOrigin = normalizeOrigin(origin);
|
|
164
|
+
if (expandedTrusted.includes('*')) {
|
|
165
|
+
return origin;
|
|
166
|
+
}
|
|
167
|
+
// Check if the origin matches any trusted origin
|
|
168
|
+
const isTrusted = expandedTrusted.some((trusted) => {
|
|
169
|
+
const normalizedTrusted = normalizeOrigin(trusted);
|
|
170
|
+
// For localhost, match both with and without port
|
|
171
|
+
if (normalizedTrusted === 'localhost') {
|
|
172
|
+
return (
|
|
173
|
+
normalizedOrigin === 'localhost' ||
|
|
174
|
+
normalizedOrigin.startsWith('localhost:') ||
|
|
175
|
+
normalizedOrigin === '127.0.0.1' ||
|
|
176
|
+
normalizedOrigin.startsWith('127.0.0.1:') ||
|
|
177
|
+
normalizedOrigin === '[::1]' ||
|
|
178
|
+
normalizedOrigin.startsWith('[::1]:')
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return normalizedTrusted === normalizedOrigin;
|
|
182
|
+
});
|
|
183
|
+
return isTrusted ? origin : null;
|
|
184
|
+
},
|
|
185
|
+
credentials: true,
|
|
186
|
+
allowHeaders: SUPPORTED_HEADERS,
|
|
187
|
+
maxAge: 600,
|
|
188
|
+
methods: SUPPORTED_METHODS,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return returnConfig;
|
|
192
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS middleware for c15t
|
|
3
|
+
*
|
|
4
|
+
* This module provides comprehensive CORS (Cross-Origin Resource Sharing) functionality including:
|
|
5
|
+
* - Origin validation with support for wildcards and subdomains
|
|
6
|
+
* - Flexible CORS options configuration
|
|
7
|
+
* - Context processing and enrichment
|
|
8
|
+
* - Protocol-agnostic matching
|
|
9
|
+
* - Support for www and non-www variants
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { createCORSOptions, isOriginTrusted, processCors } from '@c15t/backend/middleware/cors';
|
|
14
|
+
*
|
|
15
|
+
* // Create CORS options with trusted origins
|
|
16
|
+
* const corsOptions = createCORSOptions(['https://example.com', '*.trusted-domain.com']);
|
|
17
|
+
*
|
|
18
|
+
* // Process CORS for a request
|
|
19
|
+
* const enrichedContext = processCors(request, context, trustedOrigins);
|
|
20
|
+
*
|
|
21
|
+
* // Validate an origin directly
|
|
22
|
+
* const isTrusted = isOriginTrusted('https://api.trusted-domain.com', trustedOrigins);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @packageDocumentation
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export { createCORSOptions } from './cors';
|
|
29
|
+
export { isOriginTrusted } from './is-origin-trusted';
|
|
30
|
+
export { processCors } from './process-cors';
|
|
@@ -0,0 +1,104 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin validation utilities for CORS security
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Logger } from '@doubletie/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 = /^(https?:\/\/)|(wss?:\/\/)|(\/+$)|:\d+/g;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a domain matches a wildcard pattern
|
|
23
|
+
*
|
|
24
|
+
* @param hostname - The hostname to check
|
|
25
|
+
* @param wildcardPattern - The wildcard pattern (e.g. *.example.com)
|
|
26
|
+
* @param logger - Optional logger for debugging
|
|
27
|
+
* @returns true if the hostname matches the wildcard pattern
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
function matchesWildcard(
|
|
32
|
+
hostname: string,
|
|
33
|
+
wildcardPattern: string,
|
|
34
|
+
logger?: Logger
|
|
35
|
+
): boolean {
|
|
36
|
+
const wildcardDomain = wildcardPattern.slice(2); // Remove *. prefix
|
|
37
|
+
const parts = hostname.split('.');
|
|
38
|
+
const isValid = parts.length > 2 && hostname.endsWith(wildcardDomain);
|
|
39
|
+
|
|
40
|
+
logger?.debug(
|
|
41
|
+
`Wildcard match result: ${isValid} ${hostname} ends with ${wildcardDomain} ${parts.length > 2} ${hostname.endsWith(wildcardDomain)}`
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return isValid;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validates if a given origin matches any of the trusted domain patterns
|
|
49
|
+
*
|
|
50
|
+
* Supports:
|
|
51
|
+
* - Exact domain matches
|
|
52
|
+
* - Wildcard subdomains (e.g. *.example.com)
|
|
53
|
+
* - Protocol-agnostic matching
|
|
54
|
+
* - Case-insensitive comparison
|
|
55
|
+
*
|
|
56
|
+
* @param origin - The origin URL to validate (e.g. https://example.com)
|
|
57
|
+
* @param trustedDomains - Array of trusted domain patterns. Can include wildcards (e.g. *.example.com)
|
|
58
|
+
* @param logger - Optional logger for debugging validation process
|
|
59
|
+
*
|
|
60
|
+
* @returns `true` if the origin matches any trusted domain pattern, `false` otherwise
|
|
61
|
+
*
|
|
62
|
+
* @throws {Error} When trustedDomains array is empty
|
|
63
|
+
* @throws {TypeError} When origin URL is invalid
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* // Simple domain matching
|
|
68
|
+
* isOriginTrusted('https://example.com', ['example.com']); // true
|
|
69
|
+
*
|
|
70
|
+
* // Wildcard subdomain matching
|
|
71
|
+
* isOriginTrusted('https://api.example.com', ['*.example.com']); // true
|
|
72
|
+
*
|
|
73
|
+
* // Allow all origins
|
|
74
|
+
* isOriginTrusted('https://any-domain.com', ['*']); // true
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function isOriginTrusted(
|
|
78
|
+
origin: string,
|
|
79
|
+
trustedDomains: string[],
|
|
80
|
+
logger?: Logger
|
|
81
|
+
): boolean {
|
|
82
|
+
try {
|
|
83
|
+
if (trustedDomains.length === 0) {
|
|
84
|
+
throw new Error('No trusted domains');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger?.debug(
|
|
88
|
+
`Checking if origin ${origin} is trusted in ${trustedDomains}`
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Special case: if "*" is in trusted domains, allow all origins
|
|
92
|
+
if (trustedDomains.includes('*')) {
|
|
93
|
+
logger?.debug('Allowing all origins');
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Parse the origin URL to get just the hostname
|
|
98
|
+
const url = new URL(origin);
|
|
99
|
+
const originHostname = url.hostname.toLowerCase();
|
|
100
|
+
logger?.debug(`Parsed origin hostname: ${originHostname}`);
|
|
101
|
+
|
|
102
|
+
return trustedDomains.some((domain) => {
|
|
103
|
+
// Handle empty domains (which might come from splitting empty strings)
|
|
104
|
+
if (!domain || domain.trim() === '') {
|
|
105
|
+
logger?.debug('Skipping empty domain');
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const strippedDomain = domain.replace(STRIP_REGEX, '').toLowerCase();
|
|
110
|
+
logger?.debug(`Checking against stripped domain: ${strippedDomain}`);
|
|
111
|
+
|
|
112
|
+
if (strippedDomain.startsWith('*.')) {
|
|
113
|
+
return matchesWildcard(originHostname, strippedDomain, logger);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const isMatch = originHostname === strippedDomain;
|
|
117
|
+
logger?.debug(
|
|
118
|
+
`Exact match result: ${isMatch} ${originHostname} === ${strippedDomain}`
|
|
119
|
+
);
|
|
120
|
+
return isMatch;
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logger?.error('Error validating origin:', error);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS processing middleware for c15t
|
|
3
|
+
* Handles origin validation and context enrichment
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { C15TContext } from '~/v2/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
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { C15TOptions } from '~/v2/types';
|
|
2
|
+
import { version } from '~/version';
|
|
3
|
+
/**
|
|
4
|
+
* Default OpenAPI configuration
|
|
5
|
+
*/
|
|
6
|
+
export const createOpenAPIConfig = (options: C15TOptions) => {
|
|
7
|
+
const basePath = options.basePath || '';
|
|
8
|
+
return {
|
|
9
|
+
enabled: true,
|
|
10
|
+
specPath: `${basePath}/spec.json`,
|
|
11
|
+
docsPath: `${basePath}/docs`,
|
|
12
|
+
...(options.advanced?.openapi || {}),
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Default OpenAPI options
|
|
18
|
+
*/
|
|
19
|
+
export const createDefaultOpenAPIOptions = (options: C15TOptions) => ({
|
|
20
|
+
info: {
|
|
21
|
+
title: options.appName || 'c15t API',
|
|
22
|
+
version,
|
|
23
|
+
description: 'API for consent management',
|
|
24
|
+
},
|
|
25
|
+
servers: [{ url: options.basePath || '/' }],
|
|
26
|
+
security: [{ bearerAuth: [] }],
|
|
27
|
+
});
|