@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,217 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import type { InferFumaDB } from 'fumadb';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import type { DB } from '~/v2/db/schema';
|
|
5
|
+
import { generateUniqueId } from './generate-id';
|
|
6
|
+
|
|
7
|
+
type MockDB = ReturnType<InferFumaDB<typeof DB>['orm']>;
|
|
8
|
+
|
|
9
|
+
// Define regex patterns at the top level for performance
|
|
10
|
+
const SUBJECT_ID_PATTERN = /^sub_[A-Za-z0-9]+$/;
|
|
11
|
+
const CONSENT_ID_PATTERN = /^cns_[A-Za-z0-9]+$/;
|
|
12
|
+
const DOMAIN_ID_PATTERN = /^dom_[A-Za-z0-9]+$/;
|
|
13
|
+
|
|
14
|
+
describe('generateUniqueId', () => {
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Ensure crypto.getRandomValues exists in Node/Vitest environments
|
|
20
|
+
// that may not provide a Web Crypto global by default.
|
|
21
|
+
if (
|
|
22
|
+
!(globalThis as { crypto?: { getRandomValues?: unknown } }).crypto
|
|
23
|
+
?.getRandomValues
|
|
24
|
+
) {
|
|
25
|
+
(
|
|
26
|
+
globalThis as {
|
|
27
|
+
crypto: { getRandomValues: (a: Uint8Array) => Uint8Array };
|
|
28
|
+
}
|
|
29
|
+
).crypto = {
|
|
30
|
+
getRandomValues: (array: Uint8Array) => {
|
|
31
|
+
const bytes = randomBytes(array.length);
|
|
32
|
+
array.set(bytes);
|
|
33
|
+
return array;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
it('should return unique ID on first attempt when no collision exists', async () => {
|
|
39
|
+
const mockDb = {
|
|
40
|
+
findFirst: vi.fn().mockResolvedValue(null), // No existing record found
|
|
41
|
+
} as unknown as MockDB;
|
|
42
|
+
|
|
43
|
+
const result = await generateUniqueId(mockDb, 'subject');
|
|
44
|
+
|
|
45
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(1);
|
|
46
|
+
expect(mockDb.findFirst).toHaveBeenCalledWith('subject', {
|
|
47
|
+
where: expect.any(Function),
|
|
48
|
+
});
|
|
49
|
+
expect(result).toMatch(SUBJECT_ID_PATTERN); // Should have 'sub_' prefix
|
|
50
|
+
expect(result.length).toBeGreaterThan(4); // Should be longer than just prefix
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should retry when ID collision occurs and return unique ID on second attempt', async () => {
|
|
54
|
+
const mockExistingRecord = { id: 'mock_existing' };
|
|
55
|
+
const mockDb = {
|
|
56
|
+
findFirst: vi
|
|
57
|
+
.fn()
|
|
58
|
+
.mockResolvedValueOnce(mockExistingRecord) // First call returns existing record
|
|
59
|
+
.mockResolvedValueOnce(null), // Second call returns null (unique)
|
|
60
|
+
} as unknown as MockDB;
|
|
61
|
+
|
|
62
|
+
const result = await generateUniqueId(mockDb, 'consent');
|
|
63
|
+
|
|
64
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(2);
|
|
65
|
+
expect(result).toMatch(CONSENT_ID_PATTERN); // Should have 'cns_' prefix
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle multiple collisions before finding unique ID', async () => {
|
|
69
|
+
const mockExistingRecord = { id: 'mock_existing' };
|
|
70
|
+
const mockDb = {
|
|
71
|
+
findFirst: vi
|
|
72
|
+
.fn()
|
|
73
|
+
.mockResolvedValueOnce(mockExistingRecord) // First collision
|
|
74
|
+
.mockResolvedValueOnce(mockExistingRecord) // Second collision
|
|
75
|
+
.mockResolvedValueOnce(mockExistingRecord) // Third collision
|
|
76
|
+
.mockResolvedValueOnce(null), // Finally unique
|
|
77
|
+
} as unknown as MockDB;
|
|
78
|
+
|
|
79
|
+
const result = await generateUniqueId(mockDb, 'domain');
|
|
80
|
+
|
|
81
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(4);
|
|
82
|
+
expect(result).toMatch(DOMAIN_ID_PATTERN); // Should have 'dom_' prefix
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should work with different model types and use correct prefixes', async () => {
|
|
86
|
+
const mockDb = {
|
|
87
|
+
findFirst: vi.fn().mockResolvedValue(null),
|
|
88
|
+
} as unknown as MockDB;
|
|
89
|
+
|
|
90
|
+
const testCases = [
|
|
91
|
+
{ model: 'auditLog' as const, expectedPrefix: 'log_' },
|
|
92
|
+
{ model: 'consent' as const, expectedPrefix: 'cns_' },
|
|
93
|
+
{ model: 'consentPolicy' as const, expectedPrefix: 'pol_' },
|
|
94
|
+
{ model: 'consentPurpose' as const, expectedPrefix: 'pur_' },
|
|
95
|
+
{ model: 'consentRecord' as const, expectedPrefix: 'rec_' },
|
|
96
|
+
{ model: 'domain' as const, expectedPrefix: 'dom_' },
|
|
97
|
+
{ model: 'subject' as const, expectedPrefix: 'sub_' },
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
for (const { model, expectedPrefix } of testCases) {
|
|
101
|
+
const result = await generateUniqueId(mockDb, model);
|
|
102
|
+
expect(result).toMatch(
|
|
103
|
+
new RegExp(
|
|
104
|
+
`^${expectedPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[A-Za-z0-9]+$`
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(testCases.length);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should call findFirst with correct where clause function', async () => {
|
|
113
|
+
const mockDb = {
|
|
114
|
+
findFirst: vi.fn().mockResolvedValue(null),
|
|
115
|
+
} as unknown as MockDB;
|
|
116
|
+
|
|
117
|
+
await generateUniqueId(mockDb, 'subject');
|
|
118
|
+
|
|
119
|
+
const mockFindFirst = vi.mocked(mockDb.findFirst);
|
|
120
|
+
const [model, options] = mockFindFirst.mock.calls[0] as [
|
|
121
|
+
string,
|
|
122
|
+
{ where: (builder: unknown) => void },
|
|
123
|
+
];
|
|
124
|
+
expect(mockFindFirst.mock.calls).toHaveLength(1);
|
|
125
|
+
expect(model).toBe('subject');
|
|
126
|
+
expect(options).toHaveProperty('where');
|
|
127
|
+
expect(typeof options.where).toBe('function');
|
|
128
|
+
|
|
129
|
+
// Test the where function behavior
|
|
130
|
+
const mockBuilder = vi.fn();
|
|
131
|
+
options.where(mockBuilder);
|
|
132
|
+
expect(mockBuilder).toHaveBeenCalledWith(
|
|
133
|
+
'id',
|
|
134
|
+
'=',
|
|
135
|
+
expect.stringMatching(SUBJECT_ID_PATTERN)
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should generate different IDs on subsequent calls', async () => {
|
|
140
|
+
const mockDb = {
|
|
141
|
+
findFirst: vi.fn().mockResolvedValue(null),
|
|
142
|
+
} as unknown as MockDB;
|
|
143
|
+
|
|
144
|
+
const id1 = await generateUniqueId(mockDb, 'subject');
|
|
145
|
+
const id2 = await generateUniqueId(mockDb, 'subject');
|
|
146
|
+
const id3 = await generateUniqueId(mockDb, 'subject');
|
|
147
|
+
|
|
148
|
+
expect(id1).not.toBe(id2);
|
|
149
|
+
expect(id2).not.toBe(id3);
|
|
150
|
+
expect(id1).not.toBe(id3);
|
|
151
|
+
|
|
152
|
+
// All should have the same prefix
|
|
153
|
+
expect(id1).toMatch(SUBJECT_ID_PATTERN);
|
|
154
|
+
expect(id2).toMatch(SUBJECT_ID_PATTERN);
|
|
155
|
+
expect(id3).toMatch(SUBJECT_ID_PATTERN);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw an error when max retries is exceeded', async () => {
|
|
159
|
+
const mockExistingRecord = { id: 'mock_existing' };
|
|
160
|
+
const mockLogger = {
|
|
161
|
+
error: vi.fn(),
|
|
162
|
+
debug: vi.fn(),
|
|
163
|
+
info: vi.fn(),
|
|
164
|
+
success: vi.fn(),
|
|
165
|
+
warn: vi.fn(),
|
|
166
|
+
};
|
|
167
|
+
const mockCtx = { logger: mockLogger };
|
|
168
|
+
|
|
169
|
+
const mockDb = {
|
|
170
|
+
findFirst: vi.fn().mockResolvedValue(mockExistingRecord), // Always return a collision
|
|
171
|
+
} as unknown as MockDB;
|
|
172
|
+
|
|
173
|
+
// Use a small maxRetries value for faster test execution
|
|
174
|
+
await expect(
|
|
175
|
+
generateUniqueId(mockDb, 'subject', mockCtx, { maxRetries: 3 })
|
|
176
|
+
).rejects.toThrow(
|
|
177
|
+
'Failed to generate unique ID for subject after 3 attempts'
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// Should have attempted exactly maxRetries times
|
|
181
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(3);
|
|
182
|
+
expect(mockLogger.error).toHaveBeenCalledWith(
|
|
183
|
+
'ID generation failed',
|
|
184
|
+
expect.objectContaining({ model: 'subject', maxRetries: 3 })
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should respect custom retry options', async () => {
|
|
189
|
+
const mockExistingRecord = { id: 'mock_existing' };
|
|
190
|
+
const mockDb = {
|
|
191
|
+
findFirst: vi
|
|
192
|
+
.fn()
|
|
193
|
+
.mockResolvedValueOnce(mockExistingRecord) // First call returns existing record
|
|
194
|
+
.mockResolvedValueOnce(null), // Second call returns null (unique)
|
|
195
|
+
} as unknown as MockDB;
|
|
196
|
+
|
|
197
|
+
// Mock the setTimeout function directly
|
|
198
|
+
const originalSetTimeout = global.setTimeout;
|
|
199
|
+
global.setTimeout = vi.fn((callback) => {
|
|
200
|
+
// Execute callback immediately
|
|
201
|
+
callback();
|
|
202
|
+
return 1; // Return a timeout ID
|
|
203
|
+
}) as any;
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const result = await generateUniqueId(mockDb, 'subject', undefined, {
|
|
207
|
+
baseDelay: 100,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
expect(mockDb.findFirst).toHaveBeenCalledTimes(2);
|
|
211
|
+
expect(result).toMatch(SUBJECT_ID_PATTERN);
|
|
212
|
+
} finally {
|
|
213
|
+
// Restore original setTimeout
|
|
214
|
+
global.setTimeout = originalSetTimeout;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import baseX from 'base-x';
|
|
2
|
+
import type { InferFumaDB } from 'fumadb';
|
|
3
|
+
import type { DB } from '~/v2/db/schema';
|
|
4
|
+
import type { C15TContext } from '~/v2/types';
|
|
5
|
+
|
|
6
|
+
type Tables = InferFumaDB<typeof DB>['schemas'][-1]['tables'];
|
|
7
|
+
|
|
8
|
+
const prefixes: Record<keyof Tables, string> = {
|
|
9
|
+
auditLog: 'log',
|
|
10
|
+
consent: 'cns',
|
|
11
|
+
consentPolicy: 'pol',
|
|
12
|
+
consentPurpose: 'pur',
|
|
13
|
+
consentRecord: 'rec',
|
|
14
|
+
domain: 'dom',
|
|
15
|
+
subject: 'sub',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
const b58 = baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates time-ordered, prefixed, base58-encoded identifiers that:
|
|
22
|
+
* - Start with the provided prefix for clear identification
|
|
23
|
+
* - Embed a timestamp for chronological ordering
|
|
24
|
+
* - Include random data for uniqueness
|
|
25
|
+
*/
|
|
26
|
+
function generateId(model: keyof typeof prefixes): string {
|
|
27
|
+
const buf = crypto.getRandomValues(new Uint8Array(20));
|
|
28
|
+
const prefix = prefixes[model];
|
|
29
|
+
|
|
30
|
+
const EPOCH_TIMESTAMP = 1_700_000_000_000;
|
|
31
|
+
|
|
32
|
+
const t = Date.now() - EPOCH_TIMESTAMP;
|
|
33
|
+
|
|
34
|
+
// Use 8 bytes for the timestamp (0..7) and shift accordingly:
|
|
35
|
+
const high = Math.floor(t / 0x100000000);
|
|
36
|
+
const low = t >>> 0;
|
|
37
|
+
buf[0] = (high >>> 24) & 255;
|
|
38
|
+
buf[1] = (high >>> 16) & 255;
|
|
39
|
+
buf[2] = (high >>> 8) & 255;
|
|
40
|
+
buf[3] = high & 255;
|
|
41
|
+
buf[4] = (low >>> 24) & 255;
|
|
42
|
+
buf[5] = (low >>> 16) & 255;
|
|
43
|
+
buf[6] = (low >>> 8) & 255;
|
|
44
|
+
buf[7] = low & 255;
|
|
45
|
+
|
|
46
|
+
return `${prefix}_${b58.encode(buf)}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Generates a unique ID for the specified model with conflict handling
|
|
51
|
+
*
|
|
52
|
+
* @param db - Database ORM instance
|
|
53
|
+
* @param model - The model/table name to generate ID for
|
|
54
|
+
* @param ctx - Application context containing logger (optional)
|
|
55
|
+
* @param options - Configuration options for ID generation
|
|
56
|
+
* @returns Promise resolving to a unique ID
|
|
57
|
+
*
|
|
58
|
+
* @throws {Error} When max retry attempts are exceeded
|
|
59
|
+
*/
|
|
60
|
+
export async function generateUniqueId(
|
|
61
|
+
db: ReturnType<InferFumaDB<typeof DB>['orm']>,
|
|
62
|
+
model: keyof Tables,
|
|
63
|
+
ctx?: Partial<C15TContext> | undefined,
|
|
64
|
+
options: {
|
|
65
|
+
/** Maximum number of retry attempts (default: 10) */
|
|
66
|
+
maxRetries?: number;
|
|
67
|
+
/** Current retry attempt (used internally) */
|
|
68
|
+
attempt?: number;
|
|
69
|
+
/** Base delay for exponential backoff in ms (default: 5) */
|
|
70
|
+
baseDelay?: number;
|
|
71
|
+
} = {}
|
|
72
|
+
): Promise<string> {
|
|
73
|
+
const { maxRetries = 10, attempt = 0, baseDelay = 5 } = options;
|
|
74
|
+
|
|
75
|
+
// Check if we've exceeded the maximum retry attempts
|
|
76
|
+
if (attempt >= maxRetries) {
|
|
77
|
+
const error = new Error(
|
|
78
|
+
`Failed to generate unique ID for ${model} after ${maxRetries} attempts`
|
|
79
|
+
);
|
|
80
|
+
ctx?.logger?.error?.('ID generation failed', { model, maxRetries });
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const id = generateId(model);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const existing = await db.findFirst(model, {
|
|
88
|
+
where: (b) => b('id', '=', id),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (existing) {
|
|
92
|
+
ctx?.logger?.debug?.('ID conflict detected', {
|
|
93
|
+
id,
|
|
94
|
+
model,
|
|
95
|
+
attempt: attempt + 1,
|
|
96
|
+
maxRetries,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Implement exponential backoff
|
|
100
|
+
const delay = Math.min(baseDelay * 2 ** attempt, 1000);
|
|
101
|
+
|
|
102
|
+
// Wait before retrying to reduce contention in high-volume scenarios
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
104
|
+
|
|
105
|
+
return generateUniqueId(db, model, ctx, {
|
|
106
|
+
maxRetries,
|
|
107
|
+
attempt: attempt + 1,
|
|
108
|
+
baseDelay,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return id;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
ctx?.logger?.error?.('Error checking ID uniqueness', {
|
|
115
|
+
error: (error as Error).message,
|
|
116
|
+
model,
|
|
117
|
+
attempt,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// If database error occurs, retry with backoff
|
|
121
|
+
if (attempt < maxRetries - 1) {
|
|
122
|
+
const delay = Math.min(baseDelay * 2 ** attempt, 2000);
|
|
123
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
124
|
+
|
|
125
|
+
return generateUniqueId(db, model, ctx, {
|
|
126
|
+
maxRetries,
|
|
127
|
+
attempt: attempt + 1,
|
|
128
|
+
baseDelay,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import baseX from 'base-x';
|
|
2
|
+
import type { InferFumaDB } from 'fumadb';
|
|
3
|
+
import type { DB } from '~/v2/db/schema';
|
|
4
|
+
import type { C15TContext } from '~/v2/types';
|
|
5
|
+
|
|
6
|
+
type Tables = InferFumaDB<typeof DB>['schemas'][-1]['tables'];
|
|
7
|
+
|
|
8
|
+
const prefixes: Record<keyof Tables, string> = {
|
|
9
|
+
auditLog: 'log',
|
|
10
|
+
consent: 'cns',
|
|
11
|
+
consentPolicy: 'pol',
|
|
12
|
+
consentPurpose: 'pur',
|
|
13
|
+
consentRecord: 'rec',
|
|
14
|
+
domain: 'dom',
|
|
15
|
+
subject: 'sub',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
const b58 = baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates time-ordered, prefixed, base58-encoded identifiers that:
|
|
22
|
+
* - Start with the provided prefix for clear identification
|
|
23
|
+
* - Embed a timestamp for chronological ordering
|
|
24
|
+
* - Include random data for uniqueness
|
|
25
|
+
*/
|
|
26
|
+
function generateId(model: keyof typeof prefixes): string {
|
|
27
|
+
const buf = crypto.getRandomValues(new Uint8Array(20));
|
|
28
|
+
const prefix = prefixes[model];
|
|
29
|
+
|
|
30
|
+
const EPOCH_TIMESTAMP = 1_700_000_000_000;
|
|
31
|
+
|
|
32
|
+
const t = Date.now() - EPOCH_TIMESTAMP;
|
|
33
|
+
|
|
34
|
+
// Use 8 bytes for the timestamp (0..7) and shift accordingly:
|
|
35
|
+
const high = Math.floor(t / 0x100000000);
|
|
36
|
+
const low = t >>> 0;
|
|
37
|
+
buf[0] = (high >>> 24) & 255;
|
|
38
|
+
buf[1] = (high >>> 16) & 255;
|
|
39
|
+
buf[2] = (high >>> 8) & 255;
|
|
40
|
+
buf[3] = high & 255;
|
|
41
|
+
buf[4] = (low >>> 24) & 255;
|
|
42
|
+
buf[5] = (low >>> 16) & 255;
|
|
43
|
+
buf[6] = (low >>> 8) & 255;
|
|
44
|
+
buf[7] = low & 255;
|
|
45
|
+
|
|
46
|
+
return `${prefix}_${b58.encode(buf)}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Generates a unique ID for the specified model with conflict handling
|
|
51
|
+
*
|
|
52
|
+
* @param db - Database ORM instance
|
|
53
|
+
* @param model - The model/table name to generate ID for
|
|
54
|
+
* @param ctx - Application context containing logger (optional)
|
|
55
|
+
* @param options - Configuration options for ID generation
|
|
56
|
+
* @returns Promise resolving to a unique ID
|
|
57
|
+
*
|
|
58
|
+
* @throws {Error} When max retry attempts are exceeded
|
|
59
|
+
*/
|
|
60
|
+
export async function generateUniqueId(
|
|
61
|
+
db: ReturnType<InferFumaDB<typeof DB>['orm']>,
|
|
62
|
+
model: keyof Tables,
|
|
63
|
+
ctx?: Partial<C15TContext> | undefined,
|
|
64
|
+
options: {
|
|
65
|
+
/** Maximum number of retry attempts (default: 10) */
|
|
66
|
+
maxRetries?: number;
|
|
67
|
+
/** Current retry attempt (used internally) */
|
|
68
|
+
attempt?: number;
|
|
69
|
+
/** Base delay for exponential backoff in ms (default: 5) */
|
|
70
|
+
baseDelay?: number;
|
|
71
|
+
} = {}
|
|
72
|
+
): Promise<string> {
|
|
73
|
+
const { maxRetries = 10, attempt = 0, baseDelay = 5 } = options;
|
|
74
|
+
|
|
75
|
+
// Check if we've exceeded the maximum retry attempts
|
|
76
|
+
if (attempt >= maxRetries) {
|
|
77
|
+
const error = new Error(
|
|
78
|
+
`Failed to generate unique ID for ${model} after ${maxRetries} attempts`
|
|
79
|
+
);
|
|
80
|
+
ctx?.logger?.error?.('ID generation failed', { model, maxRetries });
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const id = generateId(model);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const existing = await db.findFirst(model, {
|
|
88
|
+
where: (b) => b('id', '=', id),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (existing) {
|
|
92
|
+
ctx?.logger?.debug?.('ID conflict detected', {
|
|
93
|
+
id,
|
|
94
|
+
model,
|
|
95
|
+
attempt: attempt + 1,
|
|
96
|
+
maxRetries,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Implement exponential backoff
|
|
100
|
+
const delay = Math.min(baseDelay * 2 ** attempt, 1000);
|
|
101
|
+
|
|
102
|
+
// Wait before retrying to reduce contention in high-volume scenarios
|
|
103
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
104
|
+
|
|
105
|
+
return generateUniqueId(db, model, ctx, {
|
|
106
|
+
maxRetries,
|
|
107
|
+
attempt: attempt + 1,
|
|
108
|
+
baseDelay,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return id;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
ctx?.logger?.error?.('Error checking ID uniqueness', {
|
|
115
|
+
error: (error as Error).message,
|
|
116
|
+
model,
|
|
117
|
+
attempt,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// If database error occurs, retry with backoff
|
|
121
|
+
if (attempt < maxRetries - 1) {
|
|
122
|
+
const delay = Math.min(baseDelay * 2 ** attempt, 2000);
|
|
123
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
124
|
+
|
|
125
|
+
return generateUniqueId(db, model, ctx, {
|
|
126
|
+
maxRetries,
|
|
127
|
+
attempt: attempt + 1,
|
|
128
|
+
baseDelay,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const auditLogTable = table('auditLog', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
entityType: column('entityType', 'string'),
|
|
7
|
+
entityId: column('entityId', 'string'),
|
|
8
|
+
actionType: column('actionType', 'string'),
|
|
9
|
+
subjectId: column('subjectId', 'string').nullable(),
|
|
10
|
+
ipAddress: column('ipAddress', 'string').nullable(),
|
|
11
|
+
userAgent: column('userAgent', 'string').nullable(),
|
|
12
|
+
changes: column('changes', 'json').nullable(),
|
|
13
|
+
metadata: column('metadata', 'json').nullable(),
|
|
14
|
+
createdAt: column('createdAt', 'timestamp').defaultTo$('now'),
|
|
15
|
+
eventTimezone: column('eventTimezone', 'string').defaultTo$(() => 'UTC'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const auditLogSchema = z.object({
|
|
19
|
+
id: z.string(),
|
|
20
|
+
entityType: z.string(),
|
|
21
|
+
entityId: z.string(),
|
|
22
|
+
actionType: z.string(),
|
|
23
|
+
subjectId: z.string().optional(),
|
|
24
|
+
ipAddress: z.string().optional(),
|
|
25
|
+
userAgent: z.string().optional(),
|
|
26
|
+
changes: z.record(z.string(), z.unknown()).optional(),
|
|
27
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
28
|
+
createdAt: z.date().prefault(() => new Date()),
|
|
29
|
+
eventTimezone: z.string().prefault('UTC'),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export type AuditLog = z.infer<typeof auditLogSchema>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const consentPolicyTable = table('consentPolicy', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
version: column('version', 'string'),
|
|
7
|
+
type: column('type', 'string'),
|
|
8
|
+
name: column('name', 'string'),
|
|
9
|
+
effectiveDate: column('effectiveDate', 'timestamp'),
|
|
10
|
+
expirationDate: column('expirationDate', 'timestamp').nullable(),
|
|
11
|
+
content: column('content', 'string'),
|
|
12
|
+
contentHash: column('contentHash', 'string'),
|
|
13
|
+
isActive: column('isActive', 'bool').defaultTo$(() => true),
|
|
14
|
+
createdAt: column('createdAt', 'timestamp').defaultTo$('now'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const PolicyTypeSchema = z.enum([
|
|
18
|
+
'cookie_banner',
|
|
19
|
+
'privacy_policy',
|
|
20
|
+
'dpa',
|
|
21
|
+
'terms_and_conditions',
|
|
22
|
+
'marketing_communications',
|
|
23
|
+
'age_verification',
|
|
24
|
+
'other',
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export const consentPolicySchema = z.object({
|
|
28
|
+
id: z.string(),
|
|
29
|
+
version: z.string(),
|
|
30
|
+
type: PolicyTypeSchema,
|
|
31
|
+
name: z.string(),
|
|
32
|
+
effectiveDate: z.date(),
|
|
33
|
+
expirationDate: z.date().nullish(),
|
|
34
|
+
content: z.string(),
|
|
35
|
+
contentHash: z.string(),
|
|
36
|
+
isActive: z.boolean().prefault(true),
|
|
37
|
+
createdAt: z.date().prefault(() => new Date()),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type ConsentPolicy = z.infer<typeof consentPolicySchema>;
|
|
41
|
+
export type PolicyType = z.infer<typeof PolicyTypeSchema>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const consentPurposeTable = table('consentPurpose', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
code: column('code', 'string'),
|
|
7
|
+
name: column('name', 'string'),
|
|
8
|
+
description: column('description', 'string'),
|
|
9
|
+
isEssential: column('isEssential', 'bool'),
|
|
10
|
+
dataCategory: column('dataCategory', 'string').nullable(),
|
|
11
|
+
legalBasis: column('legalBasis', 'string').nullable(),
|
|
12
|
+
isActive: column('isActive', 'bool').defaultTo$(() => true),
|
|
13
|
+
createdAt: column('createdAt', 'timestamp').defaultTo$('now'),
|
|
14
|
+
updatedAt: column('updatedAt', 'timestamp').defaultTo$('now'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const consentPurposeSchema = z.object({
|
|
18
|
+
id: z.string(),
|
|
19
|
+
code: z.string(),
|
|
20
|
+
name: z.string(),
|
|
21
|
+
description: z.string(),
|
|
22
|
+
isEssential: z.boolean(),
|
|
23
|
+
dataCategory: z.string().nullish(),
|
|
24
|
+
legalBasis: z.string().nullish(),
|
|
25
|
+
isActive: z.boolean().prefault(true),
|
|
26
|
+
createdAt: z.date().prefault(() => new Date()),
|
|
27
|
+
updatedAt: z.date().prefault(() => new Date()),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export type ConsentPurpose = z.infer<typeof consentPurposeSchema>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const consentRecordTable = table('consentRecord', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
subjectId: column('subjectId', 'string'),
|
|
7
|
+
consentId: column('consentId', 'string').nullable(),
|
|
8
|
+
actionType: column('actionType', 'string'),
|
|
9
|
+
details: column('details', 'json').nullable(),
|
|
10
|
+
createdAt: column('createdAt', 'timestamp').defaultTo$('now'),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const consentRecordSchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
subjectId: z.string(),
|
|
16
|
+
consentId: z.string().nullish(),
|
|
17
|
+
actionType: z.string(),
|
|
18
|
+
details: z.record(z.string(), z.unknown()).nullish(),
|
|
19
|
+
createdAt: z.date().prefault(() => new Date()),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export type ConsentRecord = z.infer<typeof consentRecordSchema>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const consentTable = table('consent', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
subjectId: column('subjectId', 'string'),
|
|
7
|
+
domainId: column('domainId', 'string'),
|
|
8
|
+
policyId: column('policyId', 'string').nullable(),
|
|
9
|
+
purposeIds: column('purposeIds', 'json'),
|
|
10
|
+
metadata: column('metadata', 'json').nullable(),
|
|
11
|
+
ipAddress: column('ipAddress', 'string').nullable(),
|
|
12
|
+
userAgent: column('userAgent', 'string').nullable(),
|
|
13
|
+
status: column('status', 'string').defaultTo$(() => 'active'),
|
|
14
|
+
withdrawalReason: column('withdrawalReason', 'string').nullable(),
|
|
15
|
+
givenAt: column('givenAt', 'timestamp').defaultTo$('now'),
|
|
16
|
+
validUntil: column('validUntil', 'timestamp').nullable(),
|
|
17
|
+
isActive: column('isActive', 'bool').defaultTo$(() => true),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const consentStatusSchema = z.enum(['active', 'withdrawn', 'expired']);
|
|
21
|
+
|
|
22
|
+
export const consentSchema = z.object({
|
|
23
|
+
id: z.string(),
|
|
24
|
+
subjectId: z.string(),
|
|
25
|
+
domainId: z.string(),
|
|
26
|
+
purposeIds: z.array(z.string()),
|
|
27
|
+
metadata: z.record(z.string(), z.unknown()).nullish(),
|
|
28
|
+
policyId: z.string().optional(),
|
|
29
|
+
ipAddress: z.string().nullish(),
|
|
30
|
+
userAgent: z.string().nullish(),
|
|
31
|
+
status: consentStatusSchema.prefault('active'),
|
|
32
|
+
withdrawalReason: z.string().nullish(),
|
|
33
|
+
givenAt: z.date().prefault(() => new Date()),
|
|
34
|
+
validUntil: z.date().nullish(),
|
|
35
|
+
isActive: z.boolean().prefault(true),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export type Consent = z.infer<typeof consentSchema>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { column, idColumn, table } from 'fumadb/schema';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const domainTable = table('domain', {
|
|
5
|
+
id: idColumn('id', 'varchar(255)'),
|
|
6
|
+
name: column('name', 'string').unique(),
|
|
7
|
+
description: column('description', 'string').nullable(),
|
|
8
|
+
allowedOrigins: column('allowedOrigins', 'json').nullable(),
|
|
9
|
+
isVerified: column('isVerified', 'bool').defaultTo$(() => true),
|
|
10
|
+
isActive: column('isActive', 'bool').defaultTo$(() => true),
|
|
11
|
+
createdAt: column('createdAt', 'timestamp').defaultTo$('now'),
|
|
12
|
+
updatedAt: column('updatedAt', 'timestamp').defaultTo$('now'),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const domainSchema = z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
name: z.string(),
|
|
18
|
+
description: z.string().nullish(),
|
|
19
|
+
allowedOrigins: z.array(z.string()).nullish(),
|
|
20
|
+
isVerified: z.boolean().prefault(true),
|
|
21
|
+
isActive: z.boolean().prefault(true),
|
|
22
|
+
createdAt: z.date().prefault(() => new Date()),
|
|
23
|
+
updatedAt: z.date().prefault(() => new Date()),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export type Domain = z.infer<typeof domainSchema>;
|