@c15t/backend 1.2.0-canary.13 → 1.2.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/.turbo/turbo-build.log +20 -22
  2. package/.turbo/turbo-fmt.log +4 -4
  3. package/.turbo/turbo-test.log +531 -0
  4. package/coverage/coverage-final.json +84 -0
  5. package/coverage/coverage-summary.json +85 -0
  6. package/coverage/html/backend/index.html +116 -0
  7. package/coverage/html/backend/rslib.config.ts.html +415 -0
  8. package/coverage/html/backend/src/contracts/consent/index.html +161 -0
  9. package/coverage/html/backend/src/contracts/consent/index.ts.html +112 -0
  10. package/coverage/html/backend/src/contracts/consent/post.contract.ts.html +559 -0
  11. package/coverage/html/backend/src/contracts/consent/show-banner.contract.ts.html +220 -0
  12. package/coverage/html/backend/src/contracts/consent/verify.contract.ts.html +463 -0
  13. package/coverage/html/backend/src/contracts/index.html +116 -0
  14. package/coverage/html/backend/src/contracts/index.ts.html +139 -0
  15. package/coverage/html/backend/src/contracts/meta/index.html +131 -0
  16. package/coverage/html/backend/src/contracts/meta/index.ts.html +100 -0
  17. package/coverage/html/backend/src/contracts/meta/status.contract.ts.html +196 -0
  18. package/coverage/html/backend/src/contracts/shared/index.html +116 -0
  19. package/coverage/html/backend/src/contracts/shared/jurisdiction.schema.ts.html +175 -0
  20. package/coverage/html/backend/src/core.ts.html +1624 -0
  21. package/coverage/html/backend/src/handlers/consent/index.html +161 -0
  22. package/coverage/html/backend/src/handlers/consent/index.ts.html +112 -0
  23. package/coverage/html/backend/src/handlers/consent/post.handler.ts.html +889 -0
  24. package/coverage/html/backend/src/handlers/consent/show-banner.handler.ts.html +535 -0
  25. package/coverage/html/backend/src/handlers/consent/verify.handler.ts.html +1000 -0
  26. package/coverage/html/backend/src/handlers/meta/index.html +131 -0
  27. package/coverage/html/backend/src/handlers/meta/index.ts.html +100 -0
  28. package/coverage/html/backend/src/handlers/meta/status.handler.ts.html +226 -0
  29. package/coverage/html/backend/src/index.html +161 -0
  30. package/coverage/html/backend/src/init.ts.html +1018 -0
  31. package/coverage/html/backend/src/pkgs/api-router/hooks/index.html +116 -0
  32. package/coverage/html/backend/src/pkgs/api-router/hooks/processor.ts.html +544 -0
  33. package/coverage/html/backend/src/pkgs/api-router/index.html +116 -0
  34. package/coverage/html/backend/src/pkgs/api-router/telemetry.ts.html +334 -0
  35. package/coverage/html/backend/src/pkgs/api-router/utils/cors.ts.html +304 -0
  36. package/coverage/html/backend/src/pkgs/api-router/utils/index.html +131 -0
  37. package/coverage/html/backend/src/pkgs/api-router/utils/ip.ts.html +361 -0
  38. package/coverage/html/backend/src/pkgs/data-model/fields/field-factory.ts.html +709 -0
  39. package/coverage/html/backend/src/pkgs/data-model/fields/id-generator.ts.html +256 -0
  40. package/coverage/html/backend/src/pkgs/data-model/fields/index.html +161 -0
  41. package/coverage/html/backend/src/pkgs/data-model/fields/superjson-utils.ts.html +136 -0
  42. package/coverage/html/backend/src/pkgs/data-model/fields/zod-fields.ts.html +496 -0
  43. package/coverage/html/backend/src/pkgs/data-model/hooks/create-hooks.ts.html +349 -0
  44. package/coverage/html/backend/src/pkgs/data-model/hooks/index.html +176 -0
  45. package/coverage/html/backend/src/pkgs/data-model/hooks/update-hooks.ts.html +358 -0
  46. package/coverage/html/backend/src/pkgs/data-model/hooks/update-many-hooks.ts.html +613 -0
  47. package/coverage/html/backend/src/pkgs/data-model/hooks/utils.ts.html +538 -0
  48. package/coverage/html/backend/src/pkgs/data-model/hooks/with-hooks-factory.ts.html +289 -0
  49. package/coverage/html/backend/src/pkgs/db-adapters/adapter-factory.ts.html +289 -0
  50. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/drizzle-adapter.ts.html +2203 -0
  51. package/coverage/html/backend/src/pkgs/db-adapters/adapters/drizzle-adapter/index.html +116 -0
  52. package/coverage/html/backend/src/pkgs/db-adapters/adapters/index.html +116 -0
  53. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/dialect.ts.html +670 -0
  54. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/index.html +131 -0
  55. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/kysely-adapter.ts.html +3634 -0
  56. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/index.html +116 -0
  57. package/coverage/html/backend/src/pkgs/db-adapters/adapters/kysely-adapter/tests/test-utils.ts.html +1417 -0
  58. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/index.html +116 -0
  59. package/coverage/html/backend/src/pkgs/db-adapters/adapters/memory-adapter/memory-adapter.ts.html +2071 -0
  60. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/index.html +116 -0
  61. package/coverage/html/backend/src/pkgs/db-adapters/adapters/prisma-adapter/prisma-adapter.ts.html +1834 -0
  62. package/coverage/html/backend/src/pkgs/db-adapters/adapters/test.ts.html +316 -0
  63. package/coverage/html/backend/src/pkgs/db-adapters/index.html +131 -0
  64. package/coverage/html/backend/src/pkgs/db-adapters/utils.ts.html +238 -0
  65. package/coverage/html/backend/src/pkgs/migrations/get-migration.ts.html +343 -0
  66. package/coverage/html/backend/src/pkgs/migrations/get-schema/get-schema.ts.html +217 -0
  67. package/coverage/html/backend/src/pkgs/migrations/get-schema/index.html +146 -0
  68. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-fields.ts.html +280 -0
  69. package/coverage/html/backend/src/pkgs/migrations/get-schema/process-tables.ts.html +289 -0
  70. package/coverage/html/backend/src/pkgs/migrations/index.html +176 -0
  71. package/coverage/html/backend/src/pkgs/migrations/migration-builders.ts.html +595 -0
  72. package/coverage/html/backend/src/pkgs/migrations/migration-execution.ts.html +301 -0
  73. package/coverage/html/backend/src/pkgs/migrations/schema-comparison.ts.html +694 -0
  74. package/coverage/html/backend/src/pkgs/migrations/type-mapping.ts.html +817 -0
  75. package/coverage/html/backend/src/pkgs/results/core/error-class.ts.html +976 -0
  76. package/coverage/html/backend/src/pkgs/results/core/error-codes.ts.html +703 -0
  77. package/coverage/html/backend/src/pkgs/results/core/index.html +146 -0
  78. package/coverage/html/backend/src/pkgs/results/core/tracing.ts.html +280 -0
  79. package/coverage/html/backend/src/pkgs/results/create-telemetry-options.ts.html +271 -0
  80. package/coverage/html/backend/src/pkgs/results/index.html +131 -0
  81. package/coverage/html/backend/src/pkgs/results/orpc-error-handler.ts.html +496 -0
  82. package/coverage/html/backend/src/pkgs/results/results/index.html +131 -0
  83. package/coverage/html/backend/src/pkgs/results/results/recovery-utils.ts.html +628 -0
  84. package/coverage/html/backend/src/pkgs/results/results/result-helpers.ts.html +1234 -0
  85. package/coverage/html/backend/src/pkgs/utils/env.ts.html +337 -0
  86. package/coverage/html/backend/src/pkgs/utils/index.html +146 -0
  87. package/coverage/html/backend/src/pkgs/utils/logger.ts.html +199 -0
  88. package/coverage/html/backend/src/pkgs/utils/url.ts.html +400 -0
  89. package/coverage/html/backend/src/router.ts.html +109 -0
  90. package/coverage/html/backend/src/schema/audit-log/index.html +146 -0
  91. package/coverage/html/backend/src/schema/audit-log/registry.ts.html +436 -0
  92. package/coverage/html/backend/src/schema/audit-log/schema.ts.html +223 -0
  93. package/coverage/html/backend/src/schema/audit-log/table.ts.html +640 -0
  94. package/coverage/html/backend/src/schema/consent/index.html +146 -0
  95. package/coverage/html/backend/src/schema/consent/registry.ts.html +616 -0
  96. package/coverage/html/backend/src/schema/consent/schema.ts.html +238 -0
  97. package/coverage/html/backend/src/schema/consent/table.ts.html +748 -0
  98. package/coverage/html/backend/src/schema/consent-policy/index.html +146 -0
  99. package/coverage/html/backend/src/schema/consent-policy/registry.ts.html +1063 -0
  100. package/coverage/html/backend/src/schema/consent-policy/schema.ts.html +265 -0
  101. package/coverage/html/backend/src/schema/consent-policy/table.ts.html +535 -0
  102. package/coverage/html/backend/src/schema/consent-purpose/index.html +146 -0
  103. package/coverage/html/backend/src/schema/consent-purpose/registry.ts.html +589 -0
  104. package/coverage/html/backend/src/schema/consent-purpose/schema.ts.html +259 -0
  105. package/coverage/html/backend/src/schema/consent-purpose/table.ts.html +547 -0
  106. package/coverage/html/backend/src/schema/consent-record/index.html +131 -0
  107. package/coverage/html/backend/src/schema/consent-record/schema.ts.html +211 -0
  108. package/coverage/html/backend/src/schema/consent-record/table.ts.html +457 -0
  109. package/coverage/html/backend/src/schema/create-registry.ts.html +148 -0
  110. package/coverage/html/backend/src/schema/definition.ts.html +685 -0
  111. package/coverage/html/backend/src/schema/domain/index.html +146 -0
  112. package/coverage/html/backend/src/schema/domain/registry.ts.html +973 -0
  113. package/coverage/html/backend/src/schema/domain/schema.ts.html +214 -0
  114. package/coverage/html/backend/src/schema/domain/table.ts.html +496 -0
  115. package/coverage/html/backend/src/schema/index.html +146 -0
  116. package/coverage/html/backend/src/schema/schemas.ts.html +166 -0
  117. package/coverage/html/backend/src/schema/subject/index.html +146 -0
  118. package/coverage/html/backend/src/schema/subject/registry.ts.html +973 -0
  119. package/coverage/html/backend/src/schema/subject/schema.ts.html +208 -0
  120. package/coverage/html/backend/src/schema/subject/table.ts.html +499 -0
  121. package/coverage/html/backend/src/server.ts.html +475 -0
  122. package/coverage/html/backend/src/testing/contract-testing.ts.html +1348 -0
  123. package/coverage/html/backend/src/testing/index.html +116 -0
  124. package/coverage/html/base.css +224 -0
  125. package/coverage/html/block-navigation.js +87 -0
  126. package/coverage/html/favicon.png +0 -0
  127. package/coverage/html/index.html +626 -0
  128. package/coverage/html/prettify.css +1 -0
  129. package/coverage/html/prettify.js +2 -0
  130. package/coverage/html/sort-arrow-sprite.png +0 -0
  131. package/coverage/html/sorter.js +196 -0
  132. package/dist/contracts/consent/index.d.ts +2 -2
  133. package/dist/contracts/consent/post.contract.d.ts +2 -2
  134. package/dist/contracts/consent/post.contract.d.ts.map +1 -1
  135. package/dist/contracts/index.d.ts +5 -5
  136. package/dist/contracts/index.d.ts.map +1 -1
  137. package/dist/core.cjs +244 -388
  138. package/dist/core.d.ts +5 -3
  139. package/dist/core.d.ts.map +1 -1
  140. package/dist/core.js +244 -388
  141. package/dist/handlers/consent/index.d.ts +2 -2
  142. package/dist/handlers/consent/post.handler.d.ts +2 -2
  143. package/dist/handlers/consent/show-banner.handler.d.ts.map +1 -1
  144. package/dist/pkgs/api-router/utils/core.test.d.ts +2 -0
  145. package/dist/pkgs/api-router/utils/core.test.d.ts.map +1 -0
  146. package/dist/pkgs/api-router/utils/cors.d.ts +14 -0
  147. package/dist/pkgs/api-router/utils/cors.d.ts.map +1 -0
  148. package/dist/pkgs/data-model/fields/zod-fields.d.ts +32 -32
  149. package/dist/pkgs/data-model/index.cjs +39 -59
  150. package/dist/pkgs/data-model/index.js +39 -59
  151. package/dist/pkgs/data-model/schema/index.cjs +39 -59
  152. package/dist/pkgs/data-model/schema/index.js +39 -59
  153. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.cjs +1 -0
  154. package/dist/pkgs/db-adapters/adapters/drizzle-adapter/index.js +1 -0
  155. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.cjs +1 -0
  156. package/dist/pkgs/db-adapters/adapters/kysely-adapter/index.js +1 -0
  157. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.cjs +1 -0
  158. package/dist/pkgs/db-adapters/adapters/memory-adapter/index.js +1 -0
  159. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.cjs +1 -0
  160. package/dist/pkgs/db-adapters/adapters/prisma-adapter/index.js +1 -0
  161. package/dist/pkgs/db-adapters/index.cjs +1 -0
  162. package/dist/pkgs/db-adapters/index.js +1 -0
  163. package/dist/pkgs/migrations/index.cjs +1 -0
  164. package/dist/pkgs/migrations/index.js +1 -0
  165. package/dist/router.cjs +5 -3
  166. package/dist/router.d.ts +2 -2
  167. package/dist/router.js +5 -3
  168. package/dist/schema/consent-policy/registry.d.ts +4 -4
  169. package/dist/schema/consent-policy/registry.d.ts.map +1 -1
  170. package/dist/schema/consent-policy/schema.d.ts +2 -2
  171. package/dist/schema/consent-policy/table.d.ts +2 -2
  172. package/dist/schema/consent-purpose/registry.d.ts +2 -2
  173. package/dist/schema/consent-purpose/schema.d.ts +2 -2
  174. package/dist/schema/consent-purpose/table.d.ts +2 -2
  175. package/dist/schema/create-registry.d.ts +6 -6
  176. package/dist/schema/create-registry.d.ts.map +1 -1
  177. package/dist/schema/definition.d.ts +4 -4
  178. package/dist/schema/index.cjs +39 -59
  179. package/dist/schema/index.js +39 -59
  180. package/dist/schema/schemas.d.ts +4 -4
  181. package/package.json +2 -8
  182. package/rslib.config.ts +0 -1
  183. package/src/contracts/consent/post.contract.ts +6 -1
  184. package/src/contracts/index.ts +0 -2
  185. package/src/core.ts +195 -96
  186. package/src/handlers/consent/show-banner.handler.test.ts +1 -1
  187. package/src/handlers/consent/show-banner.handler.ts +2 -1
  188. package/src/{middleware/cors/is-origin-trusted.test.ts → pkgs/api-router/utils/core.test.ts} +1 -1
  189. package/src/pkgs/api-router/utils/cors.ts +73 -0
  190. package/src/schema/consent-policy/registry.ts +50 -76
  191. package/src/server.ts +5 -1
  192. package/dist/__tests__/server.test.d.ts +0 -2
  193. package/dist/__tests__/server.test.d.ts.map +0 -1
  194. package/dist/contracts.cjs +0 -708
  195. package/dist/contracts.js +0 -661
  196. package/dist/middleware/cors/cors.d.ts +0 -37
  197. package/dist/middleware/cors/cors.d.ts.map +0 -1
  198. package/dist/middleware/cors/cors.test.d.ts +0 -2
  199. package/dist/middleware/cors/cors.test.d.ts.map +0 -1
  200. package/dist/middleware/cors/index.d.ts +0 -30
  201. package/dist/middleware/cors/index.d.ts.map +0 -1
  202. package/dist/middleware/cors/is-origin-trusted.d.ts +0 -49
  203. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  204. package/dist/middleware/cors/is-origin-trusted.test.d.ts +0 -2
  205. package/dist/middleware/cors/is-origin-trusted.test.d.ts.map +0 -1
  206. package/dist/middleware/cors/process-cors.d.ts +0 -31
  207. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  208. package/dist/middleware/openapi/config.d.ts +0 -28
  209. package/dist/middleware/openapi/config.d.ts.map +0 -1
  210. package/dist/middleware/openapi/handlers.d.ts +0 -29
  211. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  212. package/dist/middleware/openapi/index.d.ts +0 -11
  213. package/dist/middleware/openapi/index.d.ts.map +0 -1
  214. package/src/__tests__/server.test.ts +0 -96
  215. package/src/middleware/cors/cors.test.ts +0 -419
  216. package/src/middleware/cors/cors.ts +0 -192
  217. package/src/middleware/cors/index.ts +0 -30
  218. package/src/middleware/cors/is-origin-trusted.ts +0 -126
  219. package/src/middleware/cors/process-cors.ts +0 -91
  220. package/src/middleware/openapi/config.ts +0 -28
  221. package/src/middleware/openapi/handlers.ts +0 -132
  222. package/src/middleware/openapi/index.ts +0 -11
@@ -1,419 +0,0 @@
1
- import { setupServer } from 'msw/node';
2
- import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest';
3
- import { c15tInstance } from '../../core';
4
-
5
- // Create MSW server instance
6
- const server = setupServer();
7
-
8
- // Setup and teardown
9
- beforeAll(() => server.listen());
10
- afterEach(() => server.resetHandlers());
11
- afterAll(() => server.close());
12
-
13
- describe('C15T CORS Configuration', () => {
14
- const baseUrl = 'https://api.example.com';
15
- const testEndpoint = '/show-consent-banner';
16
-
17
- // Helper function to create a test request
18
- const createTestRequest = (origin?: string, method = 'GET') => {
19
- const headers: Record<string, string> = {
20
- 'content-type': 'application/json',
21
- };
22
- if (origin) {
23
- headers.origin = origin;
24
- }
25
- return new Request(`${baseUrl}${testEndpoint}`, {
26
- method,
27
- headers,
28
- });
29
- };
30
-
31
- // Helper function to create a test instance
32
- const createTestInstance = (trustedOrigins?: string[]) => {
33
- return c15tInstance({
34
- trustedOrigins,
35
- appName: 'Test App',
36
- });
37
- };
38
-
39
- describe('Wildcard Origin Configuration', () => {
40
- it('should allow any origin when trustedOrigins includes "*"', async () => {
41
- const c15t = createTestInstance(['*']);
42
- const request = createTestRequest('http://localhost:3002');
43
-
44
- const response = await c15t.handler(request);
45
- expect(response.status).toBe(200);
46
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
47
- 'http://localhost:3002'
48
- );
49
- });
50
-
51
- it('should handle requests without origin header', async () => {
52
- const c15t = createTestInstance(['*']);
53
- const request = createTestRequest();
54
-
55
- const response = await c15t.handler(request);
56
- expect(response.status).toBe(200);
57
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
58
- });
59
- });
60
-
61
- describe('Specific Origin Configuration', () => {
62
- it('should allow requests from trusted origins', async () => {
63
- const c15t = createTestInstance(['http://localhost:3002']);
64
- const request = createTestRequest('http://localhost:3002');
65
-
66
- const response = await c15t.handler(request);
67
- expect(response.status).toBe(200);
68
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
69
- 'http://localhost:3002'
70
- );
71
- });
72
-
73
- it('should deny requests from untrusted origins', async () => {
74
- const c15t = createTestInstance(['http://localhost:3002']);
75
- const request = createTestRequest('http://malicious-site.com');
76
-
77
- const response = await c15t.handler(request);
78
- expect(response.status).toBe(200);
79
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
80
- });
81
- });
82
-
83
- describe('Default Configuration', () => {
84
- it('should use default CORS settings when no trustedOrigins specified', async () => {
85
- const c15t = createTestInstance();
86
- const request = createTestRequest('http://localhost:3002');
87
-
88
- const response = await c15t.handler(request);
89
- expect(response.status).toBe(200);
90
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
91
- 'http://localhost:3002'
92
- );
93
- });
94
-
95
- it('should handle undefined trustedOrigins gracefully', async () => {
96
- const c15t = createTestInstance(undefined);
97
- const request = createTestRequest('http://localhost:3002');
98
-
99
- const response = await c15t.handler(request);
100
- expect(response.status).toBe(200);
101
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
102
- 'http://localhost:3002'
103
- );
104
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
105
- 'true'
106
- );
107
- });
108
- });
109
-
110
- describe('Preflight Requests', () => {
111
- it('should handle OPTIONS requests correctly', async () => {
112
- const c15t = createTestInstance(['http://localhost:3002']);
113
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
114
-
115
- const response = await c15t.handler(request);
116
- expect(response.status).toBe(204);
117
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
118
- 'http://localhost:3002'
119
- );
120
- expect(response.headers.get('Access-Control-Allow-Methods')).toContain(
121
- 'GET'
122
- );
123
- });
124
-
125
- it('should handle preflight requests with undefined trustedOrigins', async () => {
126
- const c15t = createTestInstance(undefined);
127
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
128
-
129
- const response = await c15t.handler(request);
130
- expect(response.status).toBe(204);
131
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
132
- 'http://localhost:3002'
133
- );
134
- expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
135
- 'GET, HEAD, PUT, POST, DELETE, PATCH'
136
- );
137
- expect(response.headers.get('Access-Control-Allow-Headers')).toBe(
138
- 'Content-Type, Authorization, x-request-id'
139
- );
140
- expect(response.headers.get('Access-Control-Max-Age')).toBe('600');
141
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
142
- 'true'
143
- );
144
- });
145
-
146
- it('should handle preflight requests without origin header when trustedOrigins is undefined', async () => {
147
- const c15t = createTestInstance(undefined);
148
- const request = createTestRequest(undefined, 'OPTIONS');
149
-
150
- const response = await c15t.handler(request);
151
- expect(response.status).toBe(204);
152
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
153
- expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
154
- 'GET, HEAD, PUT, POST, DELETE, PATCH'
155
- );
156
- expect(response.headers.get('Access-Control-Allow-Headers')).toBe(
157
- 'Content-Type, Authorization, x-request-id'
158
- );
159
- expect(response.headers.get('Access-Control-Max-Age')).toBe('600');
160
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
161
- 'true'
162
- );
163
- });
164
- });
165
-
166
- describe('Method Support', () => {
167
- it('should support all required HTTP methods', async () => {
168
- const c15t = createTestInstance(['http://localhost:3002']);
169
- const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;
170
-
171
- for (const method of methods) {
172
- const request = createTestRequest('http://localhost:3002', method);
173
- const response = await c15t.handler(request);
174
-
175
- // For methods other than GET, we expect 404 since we only defined GET endpoints
176
- const expectedStatus = method === 'GET' ? 200 : 404;
177
- expect(response.status).toBe(expectedStatus);
178
- }
179
- });
180
- });
181
-
182
- describe('CORS Blocking Scenarios', () => {
183
- it('should block preflight requests from untrusted origins', async () => {
184
- const c15t = createTestInstance(['http://localhost:3001']);
185
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
186
-
187
- const response = await c15t.handler(request);
188
- expect(response.status).toBe(204);
189
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
190
- expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
191
- 'GET, HEAD, PUT, POST, DELETE, PATCH'
192
- );
193
- });
194
-
195
- it('should block actual requests from untrusted origins', async () => {
196
- const c15t = createTestInstance(['http://localhost:3001']);
197
- const request = createTestRequest('http://localhost:3002', 'POST');
198
-
199
- const response = await c15t.handler(request);
200
- expect(response.status).toBe(404);
201
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
202
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
203
- null
204
- );
205
- });
206
-
207
- it('should handle preflight requests with missing origin header', async () => {
208
- const c15t = createTestInstance(['http://localhost:3001']);
209
- const request = createTestRequest(undefined, 'OPTIONS');
210
-
211
- const response = await c15t.handler(request);
212
- expect(response.status).toBe(204);
213
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe('*');
214
- expect(response.headers.get('Access-Control-Allow-Methods')).toContain(
215
- 'GET'
216
- );
217
- });
218
- });
219
-
220
- describe('CORS Header Requirements', () => {
221
- it('should include all required CORS headers for preflight requests from trusted origins', async () => {
222
- const c15t = createTestInstance(['http://localhost:3002']);
223
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
224
- const response = await c15t.handler(request);
225
- expect(response.status).toBe(204);
226
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
227
- 'http://localhost:3002'
228
- );
229
- expect(response.headers.get('Access-Control-Allow-Methods')).toContain(
230
- 'GET'
231
- );
232
- expect(response.headers.get('Access-Control-Allow-Headers')).toContain(
233
- 'Content-Type'
234
- );
235
- expect(response.headers.get('Access-Control-Allow-Headers')).toContain(
236
- 'Authorization'
237
- );
238
- expect(response.headers.get('Access-Control-Max-Age')).toBe('600');
239
- });
240
-
241
- it('should NOT include CORS headers for preflight requests from untrusted origins', async () => {
242
- const c15t = createTestInstance(['http://localhost:3001']);
243
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
244
- const response = await c15t.handler(request);
245
- expect(response.status).toBe(204);
246
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
247
- expect(response.headers.get('Access-Control-Allow-Methods')).toBe(
248
- 'GET, HEAD, PUT, POST, DELETE, PATCH'
249
- );
250
- expect(response.headers.get('Access-Control-Allow-Headers')).toBe(
251
- 'Content-Type, Authorization, x-request-id'
252
- );
253
- expect(response.headers.get('Access-Control-Max-Age')).toBe('600');
254
- });
255
-
256
- it('should include all required CORS headers for actual requests from trusted origins', async () => {
257
- const c15t = createTestInstance(['http://localhost:3002']);
258
- const request = createTestRequest('http://localhost:3002', 'GET');
259
- const response = await c15t.handler(request);
260
- expect(response.status).toBe(200);
261
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
262
- 'http://localhost:3002'
263
- );
264
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
265
- 'true'
266
- );
267
- });
268
-
269
- it('should NOT include Access-Control-Allow-Origin for actual requests from untrusted origins', async () => {
270
- const c15t = createTestInstance(['http://localhost:3001']);
271
- const request = createTestRequest('http://localhost:3002', 'GET');
272
- const response = await c15t.handler(request);
273
- expect(response.status).toBe(200);
274
- expect(response.headers.get('Vary')).toBe('origin');
275
- expect(response.headers.get('Access-Control-Allow-Credentials')).toBe(
276
- 'true'
277
- );
278
- });
279
- });
280
-
281
- describe('C15T CORS www/non-www Origin Handling', () => {
282
- const baseUrl = 'https://api.example.com';
283
- const testEndpoint = '/show-consent-banner';
284
- const wwwOrigin = 'http://www.c15t.com';
285
- const nonWwwOrigin = 'http://c15t.com';
286
-
287
- const createTestRequest = (origin?: string, method = 'GET') => {
288
- const headers: Record<string, string> = {
289
- 'content-type': 'application/json',
290
- };
291
- if (origin) {
292
- headers.origin = origin;
293
- }
294
- return new Request(`${baseUrl}${testEndpoint}`, { method, headers });
295
- };
296
-
297
- it('should allow www origin if non-www is trusted', async () => {
298
- const c15t = c15tInstance({
299
- trustedOrigins: [nonWwwOrigin],
300
- appName: 'Test App',
301
- });
302
- const request = createTestRequest(wwwOrigin);
303
- const response = await c15t.handler(request);
304
- expect(response.status).toBe(200);
305
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
306
- wwwOrigin
307
- );
308
- });
309
-
310
- it('should allow non-www origin if www is trusted', async () => {
311
- const c15t = c15tInstance({
312
- trustedOrigins: [wwwOrigin],
313
- appName: 'Test App',
314
- });
315
- const request = createTestRequest(nonWwwOrigin);
316
- const response = await c15t.handler(request);
317
- expect(response.status).toBe(200);
318
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
319
- nonWwwOrigin
320
- );
321
- });
322
-
323
- it('should allow both www and non-www origins if both are trusted', async () => {
324
- const c15t = c15tInstance({
325
- trustedOrigins: [wwwOrigin, nonWwwOrigin],
326
- appName: 'Test App',
327
- });
328
- const requestWww = createTestRequest(wwwOrigin);
329
- const requestNonWww = createTestRequest(nonWwwOrigin);
330
- const responseWww = await c15t.handler(requestWww);
331
- const responseNonWww = await c15t.handler(requestNonWww);
332
- expect(responseWww.status).toBe(200);
333
- expect(responseWww.headers.get('Access-Control-Allow-Origin')).toBe(
334
- wwwOrigin
335
- );
336
- expect(responseNonWww.status).toBe(200);
337
- expect(responseNonWww.headers.get('Access-Control-Allow-Origin')).toBe(
338
- nonWwwOrigin
339
- );
340
- });
341
-
342
- it('should deny unrelated origins', async () => {
343
- const c15t = c15tInstance({
344
- trustedOrigins: [nonWwwOrigin],
345
- appName: 'Test App',
346
- });
347
- const unrelatedOrigin = 'http://malicious.com';
348
- const request = createTestRequest(unrelatedOrigin);
349
- const response = await c15t.handler(request);
350
- expect(response.status).toBe(200);
351
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
352
- });
353
- });
354
-
355
- describe('CORS trustedOrigins normalization and matching', () => {
356
- const baseUrl = 'https://api.example.com';
357
- const testEndpoint = '/show-consent-banner';
358
-
359
- const createTestRequest = (origin?: string, method = 'GET') => {
360
- const headers: Record<string, string> = {
361
- 'content-type': 'application/json',
362
- };
363
- if (origin) {
364
- headers.origin = origin;
365
- }
366
- return new Request(`${baseUrl}${testEndpoint}`, { method, headers });
367
- };
368
-
369
- it('should match http and https with and without www', async () => {
370
- const c15t = createTestInstance(['localhost:3002', 'example.com']);
371
- // Should match both http and https, with and without www
372
- const origins = [
373
- 'http://localhost:3002',
374
- 'https://localhost:3002',
375
- 'http://www.example.com',
376
- 'https://example.com',
377
- ];
378
- for (const origin of origins) {
379
- const request = createTestRequest(origin, 'OPTIONS');
380
- const response = await c15t.handler(request);
381
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
382
- origin
383
- );
384
- }
385
- });
386
-
387
- it('should not match unrelated origins', async () => {
388
- const c15t = createTestInstance(['localhost:3002']);
389
- const request = createTestRequest('http://malicious.com', 'OPTIONS');
390
- const response = await c15t.handler(request);
391
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
392
- });
393
-
394
- it('should match wildcard *', async () => {
395
- const c15t = createTestInstance(['*']);
396
- const request = createTestRequest('http://any-origin.com', 'OPTIONS');
397
- const response = await c15t.handler(request);
398
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
399
- 'http://any-origin.com'
400
- );
401
- });
402
-
403
- it('should match with port', async () => {
404
- const c15t = createTestInstance(['localhost:3002']);
405
- const request = createTestRequest('http://localhost:3002', 'OPTIONS');
406
- const response = await c15t.handler(request);
407
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(
408
- 'http://localhost:3002'
409
- );
410
- });
411
-
412
- it('should not match if port is different', async () => {
413
- const c15t = createTestInstance(['localhost:3002']);
414
- const request = createTestRequest('http://localhost:4000', 'OPTIONS');
415
- const response = await c15t.handler(request);
416
- expect(response.headers.get('Access-Control-Allow-Origin')).toBe(null);
417
- });
418
- });
419
- });
@@ -1,192 +0,0 @@
1
- /**
2
- * CORS middleware utility for c15t that handles origin validation and CORS headers
3
- *
4
- * @packageDocumentation
5
- */
6
-
7
- /** Regular expression to match www prefix in domain names */
8
- const WWW_REGEX = /^www\./;
9
-
10
- /** Regular expression to match protocol and www prefix in URLs */
11
- const PROTOCOL_WWW_REGEX = /^https?:\/\/(www\.)?/;
12
-
13
- /**
14
- * Supported HTTP methods for CORS
15
- */
16
- const SUPPORTED_METHODS = [
17
- 'GET',
18
- 'POST',
19
- 'PUT',
20
- 'DELETE',
21
- 'PATCH',
22
- 'OPTIONS',
23
- ] as const;
24
-
25
- /**
26
- * Supported headers for CORS requests
27
- */
28
- const SUPPORTED_HEADERS = [
29
- 'Content-Type',
30
- 'Authorization',
31
- 'x-request-id',
32
- ] as const;
33
-
34
- /**
35
- * CORS configuration options type
36
- */
37
- export interface CORSConfig {
38
- /** Origin validation function */
39
- origin: (origin: string) => Promise<string | null>;
40
- /** Whether to allow credentials */
41
- credentials: boolean;
42
- /** Allowed headers */
43
- allowHeaders: readonly string[];
44
- /** Max age for preflight requests */
45
- maxAge: number;
46
- /** Allowed HTTP methods */
47
- methods: readonly string[];
48
- }
49
-
50
- /**
51
- * Default CORS configuration for unrestricted access
52
- */
53
- const DEFAULT_CORS_CONFIG: CORSConfig = {
54
- origin: async (origin: string) => {
55
- // For default config, always return the origin if it exists, or '*' if it doesn't
56
- return await Promise.resolve(origin || '*');
57
- },
58
- credentials: true,
59
- allowHeaders: SUPPORTED_HEADERS,
60
- maxAge: 600,
61
- methods: SUPPORTED_METHODS,
62
- } as const;
63
-
64
- /**
65
- * Creates CORS options configuration for the c15t middleware
66
- *
67
- * @param trustedOrigins - Array of allowed origin patterns or single string. Can include wildcards ('*').
68
- * If undefined, defaults to allowing all origins without credentials.
69
- *
70
- * @returns CORS configuration object with origin validation function and header settings
71
- *
72
- * @example
73
- * ```ts
74
- * const corsOptions = createCORSOptions(['http://localhost:3000', 'https://example.com']);
75
- * ```
76
- *
77
- * @throws {TypeError} When URL parsing fails in origin validation
78
- */
79
- export function createCORSOptions(
80
- trustedOrigins?: string[] | string
81
- ): CORSConfig {
82
- // If trustedOrigins is undefined or empty, return default config that allows all origins
83
- if (!trustedOrigins) {
84
- return DEFAULT_CORS_CONFIG;
85
- }
86
-
87
- // Convert string to array if needed
88
- const origins = Array.isArray(trustedOrigins)
89
- ? trustedOrigins
90
- : [trustedOrigins];
91
- if (origins.length === 0) {
92
- return DEFAULT_CORS_CONFIG;
93
- }
94
-
95
- /**
96
- * Normalizes an origin string by removing protocol and www prefix
97
- *
98
- * @param origin - The origin URL to normalize
99
- * @returns Normalized origin string without protocol and www prefix
100
- *
101
- * @internal
102
- */
103
- function normalizeOrigin(origin: string): string {
104
- try {
105
- // Handle bare domains like 'localhost' or 'example.com'
106
- if (
107
- !origin.includes('://') &&
108
- !origin.includes(':') &&
109
- !origin.includes('/')
110
- ) {
111
- return origin.toLowerCase();
112
- }
113
- // Add protocol if missing
114
- const originWithProtocol =
115
- origin.startsWith('http://') ||
116
- origin.startsWith('https://') ||
117
- origin.startsWith('ws://') ||
118
- origin.startsWith('wss://')
119
- ? origin
120
- : `http://${origin}`;
121
- const url = new URL(originWithProtocol);
122
- const hostname = url.hostname.replace(WWW_REGEX, '');
123
- // Return without protocol to match both http and https
124
- return `${hostname}${url.port ? `:${url.port}` : ''}`;
125
- } catch {
126
- // Fallback: remove www manually and protocol
127
- return origin.replace(PROTOCOL_WWW_REGEX, '').replace(WWW_REGEX, '');
128
- }
129
- }
130
-
131
- /**
132
- * Expands a list of origins to include www variants
133
- *
134
- * @param origins - Array of origin strings to expand
135
- * @returns Array of origins including www variants
136
- *
137
- * @internal
138
- */
139
- function expandWithWWW(origins: string[]): string[] {
140
- const expanded = new Set<string>();
141
- for (const origin of origins) {
142
- if (origin === '*') {
143
- expanded.add('*');
144
- continue;
145
- }
146
- const normalized = normalizeOrigin(origin);
147
- expanded.add(normalized);
148
- // Add www version if not already present
149
- if (!normalized.includes('www.')) {
150
- expanded.add(`www.${normalized}`);
151
- }
152
- }
153
- return Array.from(expanded);
154
- }
155
-
156
- const expandedTrusted = expandWithWWW(origins);
157
-
158
- const returnConfig = {
159
- origin: async (origin: string) => {
160
- if (!origin) {
161
- return '*';
162
- }
163
- const normalizedOrigin = normalizeOrigin(origin);
164
- if (expandedTrusted.includes('*')) {
165
- return origin;
166
- }
167
- // Check if the origin matches any trusted origin
168
- const isTrusted = expandedTrusted.some((trusted) => {
169
- const normalizedTrusted = normalizeOrigin(trusted);
170
- // For localhost, match both with and without port
171
- if (normalizedTrusted === 'localhost') {
172
- return (
173
- normalizedOrigin === 'localhost' ||
174
- normalizedOrigin.startsWith('localhost:') ||
175
- normalizedOrigin === '127.0.0.1' ||
176
- normalizedOrigin.startsWith('127.0.0.1:') ||
177
- normalizedOrigin === '[::1]' ||
178
- normalizedOrigin.startsWith('[::1]:')
179
- );
180
- }
181
- return normalizedTrusted === normalizedOrigin;
182
- });
183
- return isTrusted ? origin : null;
184
- },
185
- credentials: true,
186
- allowHeaders: SUPPORTED_HEADERS,
187
- maxAge: 600,
188
- methods: SUPPORTED_METHODS,
189
- };
190
-
191
- return returnConfig;
192
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * CORS middleware for c15t
3
- *
4
- * This module provides comprehensive CORS (Cross-Origin Resource Sharing) functionality including:
5
- * - Origin validation with support for wildcards and subdomains
6
- * - Flexible CORS options configuration
7
- * - Context processing and enrichment
8
- * - Protocol-agnostic matching
9
- * - Support for www and non-www variants
10
- *
11
- * @example
12
- * ```ts
13
- * import { createCORSOptions, isOriginTrusted, processCors } from '@c15t/backend/middleware/cors';
14
- *
15
- * // Create CORS options with trusted origins
16
- * const corsOptions = createCORSOptions(['https://example.com', '*.trusted-domain.com']);
17
- *
18
- * // Process CORS for a request
19
- * const enrichedContext = processCors(request, context, trustedOrigins);
20
- *
21
- * // Validate an origin directly
22
- * const isTrusted = isOriginTrusted('https://api.trusted-domain.com', trustedOrigins);
23
- * ```
24
- *
25
- * @packageDocumentation
26
- */
27
-
28
- export { createCORSOptions } from './cors';
29
- export { isOriginTrusted } from './is-origin-trusted';
30
- export { processCors } from './process-cors';