@c15t/backend 2.0.0-rc.0 → 2.0.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/302.js +473 -0
- package/dist/583.js +540 -0
- package/dist/915.js +1771 -0
- package/dist/cache.cjs +5 -5
- package/dist/cache.js +4 -415
- package/dist/core.cjs +1356 -120
- package/dist/core.js +163 -1981
- package/dist/db/adapters/drizzle.cjs +1 -1
- package/dist/db/adapters/drizzle.js +1 -2
- package/dist/db/adapters/kysely.cjs +1 -1
- package/dist/db/adapters/kysely.js +1 -2
- package/dist/db/adapters/mongo.cjs +1 -1
- package/dist/db/adapters/mongo.js +1 -2
- package/dist/db/adapters/prisma.cjs +1 -1
- package/dist/db/adapters/prisma.js +1 -2
- package/dist/db/adapters/typeorm.cjs +1 -1
- package/dist/db/adapters/typeorm.js +1 -2
- package/dist/db/adapters.cjs +1 -1
- package/dist/db/migrator.cjs +1 -1
- package/dist/db/schema.cjs +43 -3
- package/dist/db/schema.js +35 -4
- package/dist/define-config.cjs +1 -1
- package/dist/edge.cjs +1106 -0
- package/dist/edge.js +190 -0
- package/dist/router.cjs +885 -123
- package/dist/router.js +1 -1507
- package/dist/{types.cjs → types/index.cjs} +1 -1
- package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
- package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
- package/{dist → dist-types}/cache/gvl-resolver.d.ts +0 -1
- package/{dist → dist-types}/cache/index.d.ts +0 -1
- package/{dist → dist-types}/cache/keys.d.ts +0 -1
- package/{dist → dist-types}/cache/types.d.ts +0 -1
- package/{dist → dist-types}/core.d.ts +8 -1
- package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
- package/dist-types/db/registry/consent-policy.d.ts +78 -0
- package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
- package/dist-types/db/registry/index.d.ts +118 -0
- package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
- package/{dist → dist-types}/db/registry/subject.d.ts +0 -2
- package/{dist → dist-types}/db/registry/types.d.ts +1 -1
- package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
- package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
- package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
- package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -32
- package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -2
- package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +3 -3
- package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +7 -2
- package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
- package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +455 -28
- package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
- package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -3
- package/{dist → dist-types}/db/schema/index.d.ts +908 -86
- package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
- package/dist-types/define-config.d.ts +17 -0
- package/dist-types/edge/index.d.ts +5 -0
- package/dist-types/edge/init-handler.d.ts +40 -0
- package/dist-types/edge/resolve-consent.d.ts +80 -0
- package/dist-types/edge/types.d.ts +13 -0
- package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
- package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
- package/{dist → dist-types}/handlers/init/index.d.ts +2 -3
- package/dist-types/handlers/init/policy.d.ts +26 -0
- package/dist-types/handlers/init/resolve-init.d.ts +44 -0
- package/dist-types/handlers/init/translations.d.ts +48 -0
- package/dist-types/handlers/legal-document/current.handler.d.ts +11 -0
- package/dist-types/handlers/legal-document/snapshot.d.ts +39 -0
- package/dist-types/handlers/policy/snapshot.d.ts +99 -0
- package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
- package/{dist → dist-types}/handlers/subject/get.handler.d.ts +3 -2
- package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
- package/{dist → dist-types}/handlers/subject/list.handler.d.ts +3 -2
- package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -2
- package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
- package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +3 -1
- package/{dist → dist-types}/init.d.ts +4 -7
- package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
- package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
- package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
- package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +0 -1
- package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
- package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
- package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
- package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
- package/dist-types/policies/builder.d.ts +127 -0
- package/dist-types/policies/defaults.d.ts +2 -0
- package/dist-types/policies/matchers.d.ts +3 -0
- package/{dist → dist-types}/router.d.ts +0 -1
- package/{dist → dist-types}/routes/consent.d.ts +0 -1
- package/{dist → dist-types}/routes/index.d.ts +1 -1
- package/{dist → dist-types}/routes/init.d.ts +0 -1
- package/dist-types/routes/legal-document.d.ts +7 -0
- package/{dist → dist-types}/routes/status.d.ts +0 -1
- package/{dist → dist-types}/routes/subject.d.ts +0 -1
- package/{dist → dist-types}/types/api.d.ts +0 -1
- package/dist-types/types/index.d.ts +464 -0
- package/dist-types/utils/background.d.ts +6 -0
- package/{dist → dist-types}/utils/create-telemetry-options.d.ts +1 -2
- package/{dist → dist-types}/utils/env.d.ts +0 -1
- package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
- package/{dist → dist-types}/utils/instrumentation.d.ts +2 -3
- package/{dist → dist-types}/utils/logger.d.ts +0 -1
- package/{dist → dist-types}/utils/metrics.d.ts +0 -1
- package/dist-types/version.d.ts +1 -0
- package/docs/README.md +49 -0
- package/docs/api/configuration.md +208 -0
- package/docs/api/endpoints.md +211 -0
- package/docs/guides/caching.md +85 -0
- package/docs/guides/database-setup.md +128 -0
- package/docs/guides/edge-deployment.md +251 -0
- package/docs/guides/framework-integration.md +142 -0
- package/docs/guides/iab-tcf.md +89 -0
- package/docs/guides/observability.md +96 -0
- package/docs/guides/policy-packs.md +396 -0
- package/docs/quickstart.md +129 -0
- package/package.json +53 -39
- package/.turbo/turbo-build.log +0 -49
- package/CHANGELOG.md +0 -89
- package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
- package/dist/cache/adapters/index.d.ts.map +0 -1
- package/dist/cache/adapters/memory.d.ts.map +0 -1
- package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
- package/dist/cache/gvl-resolver.d.ts.map +0 -1
- package/dist/cache/index.d.ts.map +0 -1
- package/dist/cache/keys.d.ts.map +0 -1
- package/dist/cache/types.d.ts.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/db/adapters/drizzle.d.ts +0 -2
- package/dist/db/adapters/drizzle.d.ts.map +0 -1
- package/dist/db/adapters/index.d.ts +0 -2
- package/dist/db/adapters/index.d.ts.map +0 -1
- package/dist/db/adapters/kysely.d.ts +0 -2
- package/dist/db/adapters/kysely.d.ts.map +0 -1
- package/dist/db/adapters/mongo.d.ts +0 -2
- package/dist/db/adapters/mongo.d.ts.map +0 -1
- package/dist/db/adapters/prisma.d.ts +0 -2
- package/dist/db/adapters/prisma.d.ts.map +0 -1
- package/dist/db/adapters/typeorm.d.ts +0 -2
- package/dist/db/adapters/typeorm.d.ts.map +0 -1
- package/dist/db/migrator/index.d.ts.map +0 -1
- package/dist/db/registry/consent-policy.d.ts +0 -23
- package/dist/db/registry/consent-policy.d.ts.map +0 -1
- package/dist/db/registry/consent-purpose.d.ts.map +0 -1
- package/dist/db/registry/domain.d.ts.map +0 -1
- package/dist/db/registry/index.d.ts +0 -57
- package/dist/db/registry/index.d.ts.map +0 -1
- package/dist/db/registry/subject.d.ts.map +0 -1
- package/dist/db/registry/types.d.ts.map +0 -1
- package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
- package/dist/db/registry/utils.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
- package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
- package/dist/db/schema/index.d.ts.map +0 -1
- package/dist/db/tenant-scope.d.ts.map +0 -1
- package/dist/define-config.d.ts +0 -5
- package/dist/define-config.d.ts.map +0 -1
- package/dist/handlers/consent/check.handler.d.ts.map +0 -1
- package/dist/handlers/consent/index.d.ts +0 -12
- package/dist/handlers/consent/index.d.ts.map +0 -1
- package/dist/handlers/init/geo.d.ts.map +0 -1
- package/dist/handlers/init/index.d.ts.map +0 -1
- package/dist/handlers/init/translations.d.ts +0 -28
- package/dist/handlers/init/translations.d.ts.map +0 -1
- package/dist/handlers/status/index.d.ts +0 -7
- package/dist/handlers/status/index.d.ts.map +0 -1
- package/dist/handlers/status/status.handler.d.ts.map +0 -1
- package/dist/handlers/subject/get.handler.d.ts.map +0 -1
- package/dist/handlers/subject/index.d.ts +0 -10
- package/dist/handlers/subject/index.d.ts.map +0 -1
- package/dist/handlers/subject/list.handler.d.ts.map +0 -1
- package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
- package/dist/handlers/subject/post.handler.d.ts.map +0 -1
- package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
- package/dist/init.d.ts.map +0 -1
- package/dist/middleware/auth/index.d.ts.map +0 -1
- package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
- package/dist/middleware/cors/cors.d.ts.map +0 -1
- package/dist/middleware/cors/index.d.ts +0 -30
- package/dist/middleware/cors/index.d.ts.map +0 -1
- package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
- package/dist/middleware/cors/process-cors.d.ts.map +0 -1
- package/dist/middleware/openapi/config.d.ts.map +0 -1
- package/dist/middleware/openapi/handlers.d.ts.map +0 -1
- package/dist/middleware/openapi/index.d.ts +0 -12
- package/dist/middleware/openapi/index.d.ts.map +0 -1
- package/dist/middleware/process-ip/index.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/routes/consent.d.ts.map +0 -1
- package/dist/routes/index.d.ts.map +0 -1
- package/dist/routes/init.d.ts.map +0 -1
- package/dist/routes/status.d.ts.map +0 -1
- package/dist/routes/subject.d.ts.map +0 -1
- package/dist/types/api.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -255
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/create-telemetry-options.d.ts.map +0 -1
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/extract-error-message.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/instrumentation.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/metrics.d.ts.map +0 -1
- package/dist/version.d.ts +0 -2
- package/dist/version.d.ts.map +0 -1
- package/knip.json +0 -31
- package/rslib.config.ts +0 -93
- package/src/cache/adapters/cloudflare-kv.ts +0 -71
- package/src/cache/adapters/index.ts +0 -22
- package/src/cache/adapters/memory.ts +0 -111
- package/src/cache/adapters/upstash-redis.ts +0 -113
- package/src/cache/gvl-resolver.ts +0 -289
- package/src/cache/index.ts +0 -34
- package/src/cache/keys.ts +0 -68
- package/src/cache/types.ts +0 -66
- package/src/core.ts +0 -368
- package/src/db/migrator/index.ts +0 -80
- package/src/db/registry/consent-policy.test.ts +0 -451
- package/src/db/registry/consent-policy.ts +0 -82
- package/src/db/registry/consent-purpose.test.ts +0 -428
- package/src/db/registry/consent-purpose.ts +0 -61
- package/src/db/registry/domain.test.ts +0 -445
- package/src/db/registry/domain.ts +0 -91
- package/src/db/registry/index.ts +0 -14
- package/src/db/registry/subject.test.ts +0 -388
- package/src/db/registry/subject.ts +0 -129
- package/src/db/registry/types.ts +0 -10
- package/src/db/registry/utils/generate-id.test.ts +0 -216
- package/src/db/registry/utils/generate-id.ts +0 -133
- package/src/db/registry/utils.ts +0 -133
- package/src/db/schema/1.0.0/audit-log.ts +0 -15
- package/src/db/schema/1.0.0/consent-policy.ts +0 -14
- package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
- package/src/db/schema/1.0.0/consent-record.ts +0 -10
- package/src/db/schema/1.0.0/consent.ts +0 -20
- package/src/db/schema/1.0.0/domain.ts +0 -12
- package/src/db/schema/1.0.0/index.ts +0 -48
- package/src/db/schema/1.0.0/subject.ts +0 -12
- package/src/db/schema/2.0.0/audit-log.ts +0 -18
- package/src/db/schema/2.0.0/consent-policy.ts +0 -28
- package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
- package/src/db/schema/2.0.0/consent.ts +0 -26
- package/src/db/schema/2.0.0/domain.ts +0 -12
- package/src/db/schema/2.0.0/index.ts +0 -47
- package/src/db/schema/2.0.0/subject.ts +0 -14
- package/src/db/schema/index.ts +0 -15
- package/src/db/tenant-scope.test.ts +0 -750
- package/src/db/tenant-scope.ts +0 -103
- package/src/define-config.ts +0 -5
- package/src/handlers/consent/check.handler.ts +0 -126
- package/src/handlers/init/geo.test.ts +0 -317
- package/src/handlers/init/geo.ts +0 -195
- package/src/handlers/init/index.test.ts +0 -205
- package/src/handlers/init/index.ts +0 -114
- package/src/handlers/init/translations.test.ts +0 -121
- package/src/handlers/init/translations.ts +0 -72
- package/src/handlers/status/status.handler.test.ts +0 -155
- package/src/handlers/status/status.handler.ts +0 -51
- package/src/handlers/subject/get.handler.ts +0 -93
- package/src/handlers/subject/list.handler.ts +0 -93
- package/src/handlers/subject/patch.handler.ts +0 -122
- package/src/handlers/subject/post.handler.test.ts +0 -294
- package/src/handlers/subject/post.handler.ts +0 -254
- package/src/handlers/utils/consent-enrichment.test.ts +0 -380
- package/src/handlers/utils/consent-enrichment.ts +0 -218
- package/src/init.test.ts +0 -126
- package/src/init.ts +0 -87
- package/src/middleware/auth/index.ts +0 -11
- package/src/middleware/auth/validate-api-key.test.ts +0 -86
- package/src/middleware/auth/validate-api-key.ts +0 -107
- package/src/middleware/cors/cors.test.ts +0 -135
- package/src/middleware/cors/cors.ts +0 -186
- package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
- package/src/middleware/cors/is-origin-trusted.ts +0 -130
- package/src/middleware/cors/process-cors.ts +0 -91
- package/src/middleware/openapi/config.ts +0 -29
- package/src/middleware/openapi/handlers.ts +0 -34
- package/src/middleware/process-ip/index.test.ts +0 -195
- package/src/middleware/process-ip/index.ts +0 -199
- package/src/router.ts +0 -15
- package/src/routes/consent.ts +0 -52
- package/src/routes/index.ts +0 -10
- package/src/routes/init.ts +0 -102
- package/src/routes/status.ts +0 -46
- package/src/routes/subject.ts +0 -152
- package/src/types/api.ts +0 -48
- package/src/types/index.ts +0 -288
- package/src/utils/create-telemetry-options.test.ts +0 -302
- package/src/utils/create-telemetry-options.ts +0 -229
- package/src/utils/env.ts +0 -84
- package/src/utils/extract-error-message.ts +0 -21
- package/src/utils/instrumentation.test.ts +0 -185
- package/src/utils/instrumentation.ts +0 -196
- package/src/utils/logger.ts +0 -41
- package/src/utils/metrics.test.ts +0 -323
- package/src/utils/metrics.ts +0 -402
- package/src/utils/telemetry-pii.test.ts +0 -325
- package/src/version.ts +0 -2
- package/tsconfig.json +0 -11
- package/vitest.config.ts +0 -28
- /package/dist/{types.js → types/index.js} +0 -0
- /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
- /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
- /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
- /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
- /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
- /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
- /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { postSubjectHandler } from './post.handler';
|
|
3
|
-
|
|
4
|
-
vi.mock('~/utils/metrics', () => ({
|
|
5
|
-
getMetrics: vi.fn(() => ({
|
|
6
|
-
recordConsentCreated: vi.fn(),
|
|
7
|
-
recordConsentAccepted: vi.fn(),
|
|
8
|
-
recordConsentRejected: vi.fn(),
|
|
9
|
-
})),
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
vi.mock('~/db/registry/utils', () => ({
|
|
13
|
-
generateUniqueId: vi.fn().mockResolvedValue('con_new'),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
const GIVEN_AT = 1700000000000;
|
|
17
|
-
const GIVEN_AT_DATE = new Date(GIVEN_AT);
|
|
18
|
-
|
|
19
|
-
const baseInput = {
|
|
20
|
-
type: 'cookie_consent',
|
|
21
|
-
subjectId: 'sub_user1',
|
|
22
|
-
domain: 'example.com',
|
|
23
|
-
givenAt: GIVEN_AT,
|
|
24
|
-
metadata: { source: 'banner' },
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const mockSubject = { id: 'sub_user1' };
|
|
28
|
-
const mockDomain = { id: 'dom_1', name: 'example.com' };
|
|
29
|
-
const mockPolicy = { id: 'pol_1', isActive: true };
|
|
30
|
-
|
|
31
|
-
function createMockRegistry() {
|
|
32
|
-
return {
|
|
33
|
-
findOrCreateSubject: vi.fn().mockResolvedValue(mockSubject),
|
|
34
|
-
findOrCreateDomain: vi.fn().mockResolvedValue(mockDomain),
|
|
35
|
-
findOrCreatePolicy: vi.fn().mockResolvedValue(mockPolicy),
|
|
36
|
-
findConsentPolicyById: vi.fn(),
|
|
37
|
-
findOrCreateConsentPurposeByCode: vi.fn(),
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function createMockDb(findFirstResult: unknown = null) {
|
|
42
|
-
return {
|
|
43
|
-
findFirst: vi.fn().mockResolvedValue(findFirstResult),
|
|
44
|
-
transaction: vi.fn(async (fn: (tx: unknown) => unknown) => {
|
|
45
|
-
const tx = {
|
|
46
|
-
create: vi.fn().mockResolvedValue({
|
|
47
|
-
id: 'con_new',
|
|
48
|
-
givenAt: GIVEN_AT_DATE,
|
|
49
|
-
}),
|
|
50
|
-
};
|
|
51
|
-
return fn(tx);
|
|
52
|
-
}),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function createMockContext(db: unknown, registry: unknown) {
|
|
57
|
-
const logger = {
|
|
58
|
-
info: vi.fn(),
|
|
59
|
-
debug: vi.fn(),
|
|
60
|
-
warn: vi.fn(),
|
|
61
|
-
error: vi.fn(),
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const ctx = {
|
|
65
|
-
db,
|
|
66
|
-
registry,
|
|
67
|
-
logger,
|
|
68
|
-
ipAddress: '127.0.0.1',
|
|
69
|
-
userAgent: 'TestAgent/1.0',
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
let jsonData: unknown;
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
get: (key: string) => {
|
|
76
|
-
if (key === 'c15tContext') return ctx;
|
|
77
|
-
return undefined;
|
|
78
|
-
},
|
|
79
|
-
json: vi.fn((data) => {
|
|
80
|
-
jsonData = data;
|
|
81
|
-
return data;
|
|
82
|
-
}),
|
|
83
|
-
req: {
|
|
84
|
-
json: vi.fn().mockResolvedValue(baseInput),
|
|
85
|
-
},
|
|
86
|
-
getJsonData: () => jsonData,
|
|
87
|
-
_ctx: ctx,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
describe('postSubjectHandler idempotency', () => {
|
|
92
|
-
afterEach(() => {
|
|
93
|
-
vi.clearAllMocks();
|
|
94
|
-
vi.restoreAllMocks();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should return existing consent on duplicate submission', async () => {
|
|
98
|
-
const existingConsent = {
|
|
99
|
-
id: 'con_existing',
|
|
100
|
-
givenAt: GIVEN_AT_DATE,
|
|
101
|
-
};
|
|
102
|
-
const db = createMockDb(existingConsent);
|
|
103
|
-
const registry = createMockRegistry();
|
|
104
|
-
const mockCtx = createMockContext(db, registry);
|
|
105
|
-
|
|
106
|
-
// @ts-expect-error - simplified test context
|
|
107
|
-
await postSubjectHandler(mockCtx);
|
|
108
|
-
|
|
109
|
-
const result = mockCtx.getJsonData() as {
|
|
110
|
-
consentId: string;
|
|
111
|
-
subjectId: string;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
expect(result.consentId).toBe('con_existing');
|
|
115
|
-
expect(result.subjectId).toBe('sub_user1');
|
|
116
|
-
expect(db.findFirst).toHaveBeenCalledWith('consent', {
|
|
117
|
-
where: expect.any(Function),
|
|
118
|
-
});
|
|
119
|
-
expect(db.transaction).not.toHaveBeenCalled();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should create new consent when no duplicate exists', async () => {
|
|
123
|
-
const db = createMockDb(null);
|
|
124
|
-
const registry = createMockRegistry();
|
|
125
|
-
const mockCtx = createMockContext(db, registry);
|
|
126
|
-
|
|
127
|
-
// @ts-expect-error - simplified test context
|
|
128
|
-
await postSubjectHandler(mockCtx);
|
|
129
|
-
|
|
130
|
-
const result = mockCtx.getJsonData() as {
|
|
131
|
-
consentId: string;
|
|
132
|
-
subjectId: string;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
expect(result.consentId).toBe('con_new');
|
|
136
|
-
expect(db.findFirst).toHaveBeenCalled();
|
|
137
|
-
expect(db.transaction).toHaveBeenCalled();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('should create separate records for different givenAt timestamps', async () => {
|
|
141
|
-
const db = createMockDb(null);
|
|
142
|
-
const registry = createMockRegistry();
|
|
143
|
-
|
|
144
|
-
// First call
|
|
145
|
-
const mockCtx1 = createMockContext(db, registry);
|
|
146
|
-
// @ts-expect-error - simplified test context
|
|
147
|
-
await postSubjectHandler(mockCtx1);
|
|
148
|
-
|
|
149
|
-
// Second call with different givenAt
|
|
150
|
-
const mockCtx2 = createMockContext(db, registry);
|
|
151
|
-
mockCtx2.req.json = vi.fn().mockResolvedValue({
|
|
152
|
-
...baseInput,
|
|
153
|
-
givenAt: GIVEN_AT + 1000,
|
|
154
|
-
});
|
|
155
|
-
// @ts-expect-error - simplified test context
|
|
156
|
-
await postSubjectHandler(mockCtx2);
|
|
157
|
-
|
|
158
|
-
// Both calls should go through the transaction (findFirst returns null)
|
|
159
|
-
expect(db.transaction).toHaveBeenCalledTimes(2);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should persist metadata and uiSource in consent record', async () => {
|
|
163
|
-
const inputWithMeta = {
|
|
164
|
-
...baseInput,
|
|
165
|
-
metadata: { customKey: 'customValue' },
|
|
166
|
-
uiSource: 'banner',
|
|
167
|
-
};
|
|
168
|
-
const db = createMockDb(null);
|
|
169
|
-
const registry = createMockRegistry();
|
|
170
|
-
const mockCtx = createMockContext(db, registry);
|
|
171
|
-
mockCtx.req.json = vi.fn().mockResolvedValue(inputWithMeta);
|
|
172
|
-
|
|
173
|
-
// @ts-expect-error - simplified test context
|
|
174
|
-
await postSubjectHandler(mockCtx);
|
|
175
|
-
|
|
176
|
-
// Get the tx.create call
|
|
177
|
-
const transactionFn = db.transaction.mock.calls[0][0];
|
|
178
|
-
const tx = {
|
|
179
|
-
create: vi
|
|
180
|
-
.fn()
|
|
181
|
-
.mockResolvedValue({ id: 'con_new', givenAt: GIVEN_AT_DATE }),
|
|
182
|
-
};
|
|
183
|
-
await transactionFn(tx);
|
|
184
|
-
|
|
185
|
-
expect(tx.create).toHaveBeenCalledWith(
|
|
186
|
-
'consent',
|
|
187
|
-
expect.objectContaining({
|
|
188
|
-
metadata: { json: { customKey: 'customValue' } },
|
|
189
|
-
uiSource: 'banner',
|
|
190
|
-
})
|
|
191
|
-
);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should include uiSource in response for new consent', async () => {
|
|
195
|
-
const inputWithSource = {
|
|
196
|
-
...baseInput,
|
|
197
|
-
uiSource: 'dialog',
|
|
198
|
-
};
|
|
199
|
-
const db = createMockDb(null);
|
|
200
|
-
const registry = createMockRegistry();
|
|
201
|
-
const mockCtx = createMockContext(db, registry);
|
|
202
|
-
mockCtx.req.json = vi.fn().mockResolvedValue(inputWithSource);
|
|
203
|
-
|
|
204
|
-
// @ts-expect-error - simplified test context
|
|
205
|
-
await postSubjectHandler(mockCtx);
|
|
206
|
-
|
|
207
|
-
const result = mockCtx.getJsonData() as {
|
|
208
|
-
uiSource: string;
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
expect(result.uiSource).toBe('dialog');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('should include uiSource in response for duplicate consent', async () => {
|
|
215
|
-
const inputWithSource = {
|
|
216
|
-
...baseInput,
|
|
217
|
-
uiSource: 'widget',
|
|
218
|
-
};
|
|
219
|
-
const existingConsent = {
|
|
220
|
-
id: 'con_existing',
|
|
221
|
-
givenAt: GIVEN_AT_DATE,
|
|
222
|
-
};
|
|
223
|
-
const db = createMockDb(existingConsent);
|
|
224
|
-
const registry = createMockRegistry();
|
|
225
|
-
const mockCtx = createMockContext(db, registry);
|
|
226
|
-
mockCtx.req.json = vi.fn().mockResolvedValue(inputWithSource);
|
|
227
|
-
|
|
228
|
-
// @ts-expect-error - simplified test context
|
|
229
|
-
await postSubjectHandler(mockCtx);
|
|
230
|
-
|
|
231
|
-
const result = mockCtx.getJsonData() as {
|
|
232
|
-
uiSource: string;
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
expect(result.uiSource).toBe('widget');
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('should omit metadata from consent record when not provided', async () => {
|
|
239
|
-
const inputNoMeta = {
|
|
240
|
-
type: 'cookie_consent',
|
|
241
|
-
subjectId: 'sub_user1',
|
|
242
|
-
domain: 'example.com',
|
|
243
|
-
givenAt: GIVEN_AT,
|
|
244
|
-
};
|
|
245
|
-
const db = createMockDb(null);
|
|
246
|
-
const registry = createMockRegistry();
|
|
247
|
-
const mockCtx = createMockContext(db, registry);
|
|
248
|
-
mockCtx.req.json = vi.fn().mockResolvedValue(inputNoMeta);
|
|
249
|
-
|
|
250
|
-
// @ts-expect-error - simplified test context
|
|
251
|
-
await postSubjectHandler(mockCtx);
|
|
252
|
-
|
|
253
|
-
// Get the tx.create call
|
|
254
|
-
const transactionFn = db.transaction.mock.calls[0][0];
|
|
255
|
-
const tx = {
|
|
256
|
-
create: vi
|
|
257
|
-
.fn()
|
|
258
|
-
.mockResolvedValue({ id: 'con_new', givenAt: GIVEN_AT_DATE }),
|
|
259
|
-
};
|
|
260
|
-
await transactionFn(tx);
|
|
261
|
-
|
|
262
|
-
expect(tx.create).toHaveBeenCalledWith(
|
|
263
|
-
'consent',
|
|
264
|
-
expect.objectContaining({
|
|
265
|
-
metadata: undefined,
|
|
266
|
-
})
|
|
267
|
-
);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('should not record metrics for duplicate submissions', async () => {
|
|
271
|
-
const { getMetrics } = await import('~/utils/metrics');
|
|
272
|
-
const mockMetrics = {
|
|
273
|
-
recordConsentCreated: vi.fn(),
|
|
274
|
-
recordConsentAccepted: vi.fn(),
|
|
275
|
-
recordConsentRejected: vi.fn(),
|
|
276
|
-
};
|
|
277
|
-
vi.mocked(getMetrics).mockReturnValue(mockMetrics as never);
|
|
278
|
-
|
|
279
|
-
const existingConsent = {
|
|
280
|
-
id: 'con_existing',
|
|
281
|
-
givenAt: GIVEN_AT_DATE,
|
|
282
|
-
};
|
|
283
|
-
const db = createMockDb(existingConsent);
|
|
284
|
-
const registry = createMockRegistry();
|
|
285
|
-
const mockCtx = createMockContext(db, registry);
|
|
286
|
-
|
|
287
|
-
// @ts-expect-error - simplified test context
|
|
288
|
-
await postSubjectHandler(mockCtx);
|
|
289
|
-
|
|
290
|
-
expect(mockMetrics.recordConsentCreated).not.toHaveBeenCalled();
|
|
291
|
-
expect(mockMetrics.recordConsentAccepted).not.toHaveBeenCalled();
|
|
292
|
-
expect(mockMetrics.recordConsentRejected).not.toHaveBeenCalled();
|
|
293
|
-
});
|
|
294
|
-
});
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* POST /subjects handler - Records consent (append-only).
|
|
3
|
-
*
|
|
4
|
-
* @packageDocumentation
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { PostSubjectInput } from '@c15t/schema';
|
|
8
|
-
import type { Context } from 'hono';
|
|
9
|
-
import { HTTPException } from 'hono/http-exception';
|
|
10
|
-
import { generateUniqueId } from '~/db/registry/utils';
|
|
11
|
-
import type { C15TContext } from '~/types';
|
|
12
|
-
import { extractErrorMessage } from '~/utils/extract-error-message';
|
|
13
|
-
import { getMetrics } from '~/utils/metrics';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Handles the creation of a new consent record for a subject.
|
|
17
|
-
*
|
|
18
|
-
* This handler processes consent submissions with client-generated subject IDs.
|
|
19
|
-
* Each call creates a new consent record (append-only), preserving the full audit trail.
|
|
20
|
-
*/
|
|
21
|
-
export const postSubjectHandler = async (c: Context) => {
|
|
22
|
-
const ctx = c.get('c15tContext') as C15TContext;
|
|
23
|
-
const logger = ctx.logger;
|
|
24
|
-
logger.info('Handling POST /subjects request');
|
|
25
|
-
|
|
26
|
-
const { db, registry } = ctx;
|
|
27
|
-
|
|
28
|
-
const input = await c.req.json<PostSubjectInput>();
|
|
29
|
-
|
|
30
|
-
const {
|
|
31
|
-
type,
|
|
32
|
-
subjectId,
|
|
33
|
-
identityProvider,
|
|
34
|
-
externalSubjectId,
|
|
35
|
-
domain,
|
|
36
|
-
metadata,
|
|
37
|
-
givenAt: givenAtEpoch,
|
|
38
|
-
} = input;
|
|
39
|
-
|
|
40
|
-
const preferences = 'preferences' in input ? input.preferences : undefined;
|
|
41
|
-
const givenAt = new Date(givenAtEpoch);
|
|
42
|
-
|
|
43
|
-
logger.debug('Request parameters', {
|
|
44
|
-
type,
|
|
45
|
-
subjectId,
|
|
46
|
-
identityProvider,
|
|
47
|
-
externalSubjectId,
|
|
48
|
-
domain,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
// Find or create subject with the client-provided ID
|
|
53
|
-
const subject = await registry.findOrCreateSubject({
|
|
54
|
-
subjectId,
|
|
55
|
-
externalSubjectId,
|
|
56
|
-
identityProvider,
|
|
57
|
-
ipAddress: ctx.ipAddress,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (!subject) {
|
|
61
|
-
throw new HTTPException(500, {
|
|
62
|
-
message: 'Failed to create subject',
|
|
63
|
-
cause: { code: 'SUBJECT_CREATION_FAILED', subjectId },
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
logger.debug('Subject found/created', { subjectId: subject.id });
|
|
68
|
-
|
|
69
|
-
const domainRecord = await registry.findOrCreateDomain(domain);
|
|
70
|
-
|
|
71
|
-
if (!domainRecord) {
|
|
72
|
-
throw new HTTPException(500, {
|
|
73
|
-
message: 'Failed to create domain',
|
|
74
|
-
cause: { code: 'DOMAIN_CREATION_FAILED', domain },
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let policyId: string | undefined;
|
|
79
|
-
let purposeIds: string[] = [];
|
|
80
|
-
|
|
81
|
-
const inputPolicyId =
|
|
82
|
-
'policyId' in input ? (input.policyId as string | undefined) : undefined;
|
|
83
|
-
if (inputPolicyId) {
|
|
84
|
-
policyId = inputPolicyId;
|
|
85
|
-
|
|
86
|
-
// Verify the policy exists and is active
|
|
87
|
-
const policy = await registry.findConsentPolicyById(inputPolicyId);
|
|
88
|
-
if (!policy) {
|
|
89
|
-
throw new HTTPException(404, {
|
|
90
|
-
message: 'Policy not found',
|
|
91
|
-
cause: { code: 'POLICY_NOT_FOUND', policyId, type },
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
if (!policy.isActive) {
|
|
95
|
-
throw new HTTPException(400, {
|
|
96
|
-
message: 'Policy is inactive',
|
|
97
|
-
cause: { code: 'POLICY_INACTIVE', policyId, type },
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
const policy = await registry.findOrCreatePolicy(type);
|
|
102
|
-
if (!policy) {
|
|
103
|
-
throw new HTTPException(500, {
|
|
104
|
-
message: 'Failed to create policy',
|
|
105
|
-
cause: { code: 'POLICY_CREATION_FAILED', type },
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
policyId = policy.id;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Handle purposes if they exist
|
|
112
|
-
if (preferences) {
|
|
113
|
-
const consentedPurposes = Object.entries(preferences)
|
|
114
|
-
.filter(([_, isConsented]) => isConsented)
|
|
115
|
-
.map(([purposeCode]) => purposeCode);
|
|
116
|
-
|
|
117
|
-
logger.debug('Consented purposes', { consentedPurposes });
|
|
118
|
-
|
|
119
|
-
// Batch fetch all existing purposes
|
|
120
|
-
const purposesRaw = await Promise.all(
|
|
121
|
-
consentedPurposes.map((purposeCode) =>
|
|
122
|
-
registry.findOrCreateConsentPurposeByCode(purposeCode)
|
|
123
|
-
)
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const purposes = purposesRaw
|
|
127
|
-
.map((purpose) => purpose?.id ?? null)
|
|
128
|
-
.filter((id): id is string => Boolean(id));
|
|
129
|
-
|
|
130
|
-
logger.debug('Filtered purposes', { purposes });
|
|
131
|
-
|
|
132
|
-
if (purposes.length === 0) {
|
|
133
|
-
logger.warn(
|
|
134
|
-
'No valid purpose IDs found after filtering. Using empty list.',
|
|
135
|
-
{ consentedPurposes }
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
purposeIds = purposes;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check for duplicate consent (idempotency)
|
|
143
|
-
const existingConsent = await db.findFirst('consent', {
|
|
144
|
-
where: (b) =>
|
|
145
|
-
b.and(
|
|
146
|
-
b('subjectId', '=', subject.id),
|
|
147
|
-
b('domainId', '=', domainRecord.id),
|
|
148
|
-
b('policyId', '=', policyId),
|
|
149
|
-
b('givenAt', '=', givenAt)
|
|
150
|
-
),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
if (existingConsent) {
|
|
154
|
-
logger.debug('Duplicate consent detected, returning existing record', {
|
|
155
|
-
consentId: existingConsent.id,
|
|
156
|
-
});
|
|
157
|
-
return c.json({
|
|
158
|
-
subjectId: subject.id,
|
|
159
|
-
consentId: existingConsent.id,
|
|
160
|
-
domainId: domainRecord.id,
|
|
161
|
-
domain: domainRecord.name,
|
|
162
|
-
type,
|
|
163
|
-
metadata,
|
|
164
|
-
uiSource: input.uiSource,
|
|
165
|
-
givenAt: existingConsent.givenAt,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const result = await db.transaction(async (tx) => {
|
|
170
|
-
logger.debug('Creating consent record', {
|
|
171
|
-
subjectId: subject.id,
|
|
172
|
-
domainId: domainRecord.id,
|
|
173
|
-
policyId,
|
|
174
|
-
purposeIds,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// Always create a new consent record (append-only)
|
|
178
|
-
const consentRecord = await tx.create('consent', {
|
|
179
|
-
id: await generateUniqueId(tx, 'consent', ctx),
|
|
180
|
-
subjectId: subject.id,
|
|
181
|
-
domainId: domainRecord.id,
|
|
182
|
-
policyId,
|
|
183
|
-
purposeIds: { json: purposeIds },
|
|
184
|
-
metadata: metadata ? { json: metadata } : undefined,
|
|
185
|
-
ipAddress: ctx.ipAddress,
|
|
186
|
-
userAgent: ctx.userAgent,
|
|
187
|
-
jurisdiction: input.jurisdiction,
|
|
188
|
-
jurisdictionModel: input.jurisdictionModel,
|
|
189
|
-
tcString: input.tcString,
|
|
190
|
-
uiSource: input.uiSource,
|
|
191
|
-
givenAt,
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
logger.debug('Created consent', { consentRecord: consentRecord.id });
|
|
195
|
-
|
|
196
|
-
if (!consentRecord) {
|
|
197
|
-
throw new HTTPException(500, {
|
|
198
|
-
message: 'Failed to create consent',
|
|
199
|
-
cause: {
|
|
200
|
-
code: 'CONSENT_CREATION_FAILED',
|
|
201
|
-
subjectId: subject.id,
|
|
202
|
-
domain,
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return {
|
|
208
|
-
consent: consentRecord,
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// Record telemetry metrics
|
|
213
|
-
const metrics = getMetrics();
|
|
214
|
-
if (metrics) {
|
|
215
|
-
const jurisdiction = input.jurisdiction;
|
|
216
|
-
metrics.recordConsentCreated({ type, jurisdiction });
|
|
217
|
-
|
|
218
|
-
// Determine accepted vs rejected based on preferences
|
|
219
|
-
const hasAccepted =
|
|
220
|
-
preferences && Object.values(preferences).some(Boolean);
|
|
221
|
-
if (hasAccepted) {
|
|
222
|
-
metrics.recordConsentAccepted({ type, jurisdiction });
|
|
223
|
-
} else {
|
|
224
|
-
metrics.recordConsentRejected({ type, jurisdiction });
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Return the response
|
|
229
|
-
return c.json({
|
|
230
|
-
subjectId: subject.id,
|
|
231
|
-
consentId: result.consent.id,
|
|
232
|
-
domainId: domainRecord.id,
|
|
233
|
-
domain: domainRecord.name,
|
|
234
|
-
type,
|
|
235
|
-
metadata,
|
|
236
|
-
uiSource: input.uiSource,
|
|
237
|
-
givenAt: result.consent.givenAt,
|
|
238
|
-
});
|
|
239
|
-
} catch (error) {
|
|
240
|
-
logger.error('Error in POST /subjects handler', {
|
|
241
|
-
error: extractErrorMessage(error),
|
|
242
|
-
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
if (error instanceof HTTPException) {
|
|
246
|
-
throw error;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
throw new HTTPException(500, {
|
|
250
|
-
message: 'Internal server error',
|
|
251
|
-
cause: { code: 'INTERNAL_SERVER_ERROR' },
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
};
|