@c15t/backend 2.0.0-rc.4 → 2.0.0-rc.5

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 (308) hide show
  1. package/dist/core.cjs +830 -74
  2. package/dist/core.js +807 -75
  3. package/dist/db/schema.cjs +37 -0
  4. package/dist/db/schema.js +33 -2
  5. package/dist/edge.cjs +1106 -0
  6. package/dist/edge.js +1069 -0
  7. package/dist/router.cjs +613 -64
  8. package/dist/router.js +613 -64
  9. package/{dist → dist-types}/cache/adapters/cloudflare-kv.d.ts +0 -1
  10. package/{dist → dist-types}/cache/adapters/index.d.ts +0 -1
  11. package/{dist → dist-types}/cache/adapters/memory.d.ts +0 -1
  12. package/{dist → dist-types}/cache/adapters/upstash-redis.d.ts +0 -1
  13. package/{dist → dist-types}/cache/gvl-resolver.d.ts +1 -2
  14. package/{dist → dist-types}/cache/index.d.ts +0 -1
  15. package/{dist → dist-types}/cache/keys.d.ts +0 -1
  16. package/{dist → dist-types}/cache/types.d.ts +0 -1
  17. package/{dist → dist-types}/core.d.ts +8 -1
  18. package/{dist → dist-types}/db/migrator/index.d.ts +0 -1
  19. package/{dist → dist-types}/db/registry/consent-policy.d.ts +0 -1
  20. package/{dist → dist-types}/db/registry/consent-purpose.d.ts +0 -1
  21. package/{dist → dist-types}/db/registry/domain.d.ts +0 -1
  22. package/{dist → dist-types}/db/registry/index.d.ts +22 -2
  23. package/dist-types/db/registry/runtime-policy-decision.d.ts +60 -0
  24. package/{dist → dist-types}/db/registry/subject.d.ts +0 -1
  25. package/{dist → dist-types}/db/registry/types.d.ts +1 -2
  26. package/{dist → dist-types}/db/registry/utils/generate-id.d.ts +0 -1
  27. package/{dist → dist-types}/db/registry/utils.d.ts +0 -1
  28. package/{dist → dist-types}/db/schema/1.0.0/audit-log.d.ts +0 -1
  29. package/{dist → dist-types}/db/schema/1.0.0/consent-policy.d.ts +0 -1
  30. package/{dist → dist-types}/db/schema/1.0.0/consent-purpose.d.ts +0 -1
  31. package/{dist → dist-types}/db/schema/1.0.0/consent-record.d.ts +0 -1
  32. package/{dist → dist-types}/db/schema/1.0.0/consent.d.ts +1 -2
  33. package/{dist → dist-types}/db/schema/1.0.0/domain.d.ts +0 -1
  34. package/{dist → dist-types}/db/schema/1.0.0/index.d.ts +0 -1
  35. package/{dist → dist-types}/db/schema/1.0.0/subject.d.ts +0 -1
  36. package/{dist → dist-types}/db/schema/2.0.0/audit-log.d.ts +1 -2
  37. package/{dist → dist-types}/db/schema/2.0.0/consent-policy.d.ts +1 -2
  38. package/{dist → dist-types}/db/schema/2.0.0/consent-purpose.d.ts +1 -2
  39. package/{dist → dist-types}/db/schema/2.0.0/consent.d.ts +5 -2
  40. package/{dist → dist-types}/db/schema/2.0.0/domain.d.ts +1 -2
  41. package/{dist → dist-types}/db/schema/2.0.0/index.d.ts +432 -17
  42. package/dist-types/db/schema/2.0.0/runtime-policy-decision.d.ts +23 -0
  43. package/{dist → dist-types}/db/schema/2.0.0/subject.d.ts +1 -2
  44. package/{dist → dist-types}/db/schema/index.d.ts +862 -33
  45. package/{dist → dist-types}/db/tenant-scope.d.ts +0 -1
  46. package/{dist → dist-types}/define-config.d.ts +0 -1
  47. package/dist-types/edge/index.d.ts +5 -0
  48. package/dist-types/edge/init-handler.d.ts +38 -0
  49. package/dist-types/edge/resolve-consent.d.ts +80 -0
  50. package/dist-types/edge/types.d.ts +13 -0
  51. package/{dist → dist-types}/handlers/consent/check.handler.d.ts +0 -1
  52. package/{src/handlers/consent/index.ts → dist-types/handlers/consent/index.d.ts} +0 -1
  53. package/{dist → dist-types}/handlers/init/geo.d.ts +2 -3
  54. package/{dist → dist-types}/handlers/init/index.d.ts +4 -5
  55. package/dist-types/handlers/init/policy.d.ts +26 -0
  56. package/dist-types/handlers/init/resolve-init.d.ts +44 -0
  57. package/dist-types/handlers/init/translations.d.ts +48 -0
  58. package/dist-types/handlers/policy/snapshot.d.ts +99 -0
  59. package/{src/handlers/status/index.ts → dist-types/handlers/status/index.d.ts} +0 -1
  60. package/{dist → dist-types}/handlers/status/status.handler.d.ts +0 -1
  61. package/{dist → dist-types}/handlers/subject/get.handler.d.ts +0 -1
  62. package/{src/handlers/subject/index.ts → dist-types/handlers/subject/index.d.ts} +0 -1
  63. package/{dist → dist-types}/handlers/subject/list.handler.d.ts +0 -1
  64. package/{dist → dist-types}/handlers/subject/patch.handler.d.ts +0 -1
  65. package/{dist → dist-types}/handlers/subject/post.handler.d.ts +12 -1
  66. package/{dist → dist-types}/handlers/utils/consent-enrichment.d.ts +0 -1
  67. package/{dist → dist-types}/init.d.ts +0 -1
  68. package/{dist → dist-types}/middleware/auth/index.d.ts +0 -1
  69. package/{dist → dist-types}/middleware/auth/validate-api-key.d.ts +0 -1
  70. package/{dist → dist-types}/middleware/cors/cors.d.ts +0 -1
  71. package/{src/middleware/cors/index.ts → dist-types/middleware/cors/index.d.ts} +0 -1
  72. package/{dist → dist-types}/middleware/cors/is-origin-trusted.d.ts +1 -2
  73. package/{dist → dist-types}/middleware/cors/process-cors.d.ts +0 -1
  74. package/{dist → dist-types}/middleware/openapi/config.d.ts +0 -1
  75. package/{dist → dist-types}/middleware/openapi/handlers.d.ts +0 -1
  76. package/{src/middleware/openapi/index.ts → dist-types/middleware/openapi/index.d.ts} +0 -1
  77. package/{dist → dist-types}/middleware/process-ip/index.d.ts +0 -1
  78. package/dist-types/policies/builder.d.ts +127 -0
  79. package/dist-types/policies/defaults.d.ts +2 -0
  80. package/dist-types/policies/matchers.d.ts +3 -0
  81. package/{dist → dist-types}/router.d.ts +0 -1
  82. package/{dist → dist-types}/routes/consent.d.ts +0 -1
  83. package/{src/routes/index.ts → dist-types/routes/index.d.ts} +0 -1
  84. package/{dist → dist-types}/routes/init.d.ts +0 -1
  85. package/{dist → dist-types}/routes/status.d.ts +0 -1
  86. package/{dist → dist-types}/routes/subject.d.ts +0 -1
  87. package/{dist → dist-types}/types/api.d.ts +0 -1
  88. package/{dist → dist-types}/types/index.d.ts +110 -6
  89. package/dist-types/utils/background.d.ts +6 -0
  90. package/{dist → dist-types}/utils/create-telemetry-options.d.ts +0 -1
  91. package/{dist → dist-types}/utils/env.d.ts +0 -1
  92. package/{dist → dist-types}/utils/extract-error-message.d.ts +0 -1
  93. package/{dist → dist-types}/utils/instrumentation.d.ts +0 -1
  94. package/{dist → dist-types}/utils/logger.d.ts +1 -2
  95. package/{dist → dist-types}/utils/metrics.d.ts +0 -1
  96. package/dist-types/version.d.ts +1 -0
  97. package/docs/README.md +49 -0
  98. package/docs/api/configuration.md +197 -0
  99. package/docs/api/endpoints.md +211 -0
  100. package/docs/guides/caching.md +85 -0
  101. package/docs/guides/database-setup.md +128 -0
  102. package/docs/guides/edge-deployment.md +248 -0
  103. package/docs/guides/framework-integration.md +142 -0
  104. package/docs/guides/iab-tcf.md +89 -0
  105. package/docs/guides/observability.md +96 -0
  106. package/docs/guides/policy-packs.md +396 -0
  107. package/docs/quickstart.md +129 -0
  108. package/package.json +33 -19
  109. package/.turbo/turbo-build.log +0 -49
  110. package/CHANGELOG.md +0 -123
  111. package/dist/cache/adapters/cloudflare-kv.d.ts.map +0 -1
  112. package/dist/cache/adapters/index.d.ts.map +0 -1
  113. package/dist/cache/adapters/memory.d.ts.map +0 -1
  114. package/dist/cache/adapters/upstash-redis.d.ts.map +0 -1
  115. package/dist/cache/gvl-resolver.d.ts.map +0 -1
  116. package/dist/cache/index.d.ts.map +0 -1
  117. package/dist/cache/keys.d.ts.map +0 -1
  118. package/dist/cache/types.d.ts.map +0 -1
  119. package/dist/core.d.ts.map +0 -1
  120. package/dist/db/adapters/drizzle.d.ts +0 -2
  121. package/dist/db/adapters/drizzle.d.ts.map +0 -1
  122. package/dist/db/adapters/index.d.ts +0 -2
  123. package/dist/db/adapters/index.d.ts.map +0 -1
  124. package/dist/db/adapters/kysely.d.ts +0 -2
  125. package/dist/db/adapters/kysely.d.ts.map +0 -1
  126. package/dist/db/adapters/mongo.d.ts +0 -2
  127. package/dist/db/adapters/mongo.d.ts.map +0 -1
  128. package/dist/db/adapters/prisma.d.ts +0 -2
  129. package/dist/db/adapters/prisma.d.ts.map +0 -1
  130. package/dist/db/adapters/typeorm.d.ts +0 -2
  131. package/dist/db/adapters/typeorm.d.ts.map +0 -1
  132. package/dist/db/migrator/index.d.ts.map +0 -1
  133. package/dist/db/registry/consent-policy.d.ts.map +0 -1
  134. package/dist/db/registry/consent-purpose.d.ts.map +0 -1
  135. package/dist/db/registry/domain.d.ts.map +0 -1
  136. package/dist/db/registry/index.d.ts.map +0 -1
  137. package/dist/db/registry/subject.d.ts.map +0 -1
  138. package/dist/db/registry/types.d.ts.map +0 -1
  139. package/dist/db/registry/utils/generate-id.d.ts.map +0 -1
  140. package/dist/db/registry/utils.d.ts.map +0 -1
  141. package/dist/db/schema/1.0.0/audit-log.d.ts.map +0 -1
  142. package/dist/db/schema/1.0.0/consent-policy.d.ts.map +0 -1
  143. package/dist/db/schema/1.0.0/consent-purpose.d.ts.map +0 -1
  144. package/dist/db/schema/1.0.0/consent-record.d.ts.map +0 -1
  145. package/dist/db/schema/1.0.0/consent.d.ts.map +0 -1
  146. package/dist/db/schema/1.0.0/domain.d.ts.map +0 -1
  147. package/dist/db/schema/1.0.0/index.d.ts.map +0 -1
  148. package/dist/db/schema/1.0.0/subject.d.ts.map +0 -1
  149. package/dist/db/schema/2.0.0/audit-log.d.ts.map +0 -1
  150. package/dist/db/schema/2.0.0/consent-policy.d.ts.map +0 -1
  151. package/dist/db/schema/2.0.0/consent-purpose.d.ts.map +0 -1
  152. package/dist/db/schema/2.0.0/consent.d.ts.map +0 -1
  153. package/dist/db/schema/2.0.0/domain.d.ts.map +0 -1
  154. package/dist/db/schema/2.0.0/index.d.ts.map +0 -1
  155. package/dist/db/schema/2.0.0/subject.d.ts.map +0 -1
  156. package/dist/db/schema/index.d.ts.map +0 -1
  157. package/dist/db/tenant-scope.d.ts.map +0 -1
  158. package/dist/define-config.d.ts.map +0 -1
  159. package/dist/handlers/consent/check.handler.d.ts.map +0 -1
  160. package/dist/handlers/consent/index.d.ts +0 -12
  161. package/dist/handlers/consent/index.d.ts.map +0 -1
  162. package/dist/handlers/init/geo.d.ts.map +0 -1
  163. package/dist/handlers/init/index.d.ts.map +0 -1
  164. package/dist/handlers/init/translations.d.ts +0 -26
  165. package/dist/handlers/init/translations.d.ts.map +0 -1
  166. package/dist/handlers/status/index.d.ts +0 -7
  167. package/dist/handlers/status/index.d.ts.map +0 -1
  168. package/dist/handlers/status/status.handler.d.ts.map +0 -1
  169. package/dist/handlers/subject/get.handler.d.ts.map +0 -1
  170. package/dist/handlers/subject/index.d.ts +0 -10
  171. package/dist/handlers/subject/index.d.ts.map +0 -1
  172. package/dist/handlers/subject/list.handler.d.ts.map +0 -1
  173. package/dist/handlers/subject/patch.handler.d.ts.map +0 -1
  174. package/dist/handlers/subject/post.handler.d.ts.map +0 -1
  175. package/dist/handlers/utils/consent-enrichment.d.ts.map +0 -1
  176. package/dist/init.d.ts.map +0 -1
  177. package/dist/middleware/auth/index.d.ts.map +0 -1
  178. package/dist/middleware/auth/validate-api-key.d.ts.map +0 -1
  179. package/dist/middleware/cors/cors.d.ts.map +0 -1
  180. package/dist/middleware/cors/index.d.ts +0 -30
  181. package/dist/middleware/cors/index.d.ts.map +0 -1
  182. package/dist/middleware/cors/is-origin-trusted.d.ts.map +0 -1
  183. package/dist/middleware/cors/process-cors.d.ts.map +0 -1
  184. package/dist/middleware/openapi/config.d.ts.map +0 -1
  185. package/dist/middleware/openapi/handlers.d.ts.map +0 -1
  186. package/dist/middleware/openapi/index.d.ts +0 -12
  187. package/dist/middleware/openapi/index.d.ts.map +0 -1
  188. package/dist/middleware/process-ip/index.d.ts.map +0 -1
  189. package/dist/router.d.ts.map +0 -1
  190. package/dist/routes/consent.d.ts.map +0 -1
  191. package/dist/routes/index.d.ts +0 -10
  192. package/dist/routes/index.d.ts.map +0 -1
  193. package/dist/routes/init.d.ts.map +0 -1
  194. package/dist/routes/status.d.ts.map +0 -1
  195. package/dist/routes/subject.d.ts.map +0 -1
  196. package/dist/types/api.d.ts.map +0 -1
  197. package/dist/types/index.d.ts.map +0 -1
  198. package/dist/utils/create-telemetry-options.d.ts.map +0 -1
  199. package/dist/utils/env.d.ts.map +0 -1
  200. package/dist/utils/extract-error-message.d.ts.map +0 -1
  201. package/dist/utils/index.d.ts +0 -4
  202. package/dist/utils/index.d.ts.map +0 -1
  203. package/dist/utils/instrumentation.d.ts.map +0 -1
  204. package/dist/utils/logger.d.ts.map +0 -1
  205. package/dist/utils/metrics.d.ts.map +0 -1
  206. package/dist/version.d.ts +0 -2
  207. package/dist/version.d.ts.map +0 -1
  208. package/knip.json +0 -31
  209. package/rslib.config.ts +0 -93
  210. package/src/cache/adapters/cloudflare-kv.ts +0 -71
  211. package/src/cache/adapters/index.ts +0 -22
  212. package/src/cache/adapters/memory.ts +0 -111
  213. package/src/cache/adapters/upstash-redis.ts +0 -113
  214. package/src/cache/gvl-resolver.ts +0 -289
  215. package/src/cache/index.ts +0 -34
  216. package/src/cache/keys.ts +0 -68
  217. package/src/cache/types.ts +0 -66
  218. package/src/core.ts +0 -369
  219. package/src/db/migrator/index.ts +0 -80
  220. package/src/db/registry/consent-policy.test.ts +0 -451
  221. package/src/db/registry/consent-policy.ts +0 -82
  222. package/src/db/registry/consent-purpose.test.ts +0 -428
  223. package/src/db/registry/consent-purpose.ts +0 -61
  224. package/src/db/registry/domain.test.ts +0 -445
  225. package/src/db/registry/domain.ts +0 -91
  226. package/src/db/registry/index.ts +0 -14
  227. package/src/db/registry/subject.test.ts +0 -371
  228. package/src/db/registry/subject.ts +0 -126
  229. package/src/db/registry/types.ts +0 -10
  230. package/src/db/registry/utils/generate-id.test.ts +0 -216
  231. package/src/db/registry/utils/generate-id.ts +0 -133
  232. package/src/db/registry/utils.ts +0 -133
  233. package/src/db/schema/1.0.0/audit-log.ts +0 -15
  234. package/src/db/schema/1.0.0/consent-policy.ts +0 -14
  235. package/src/db/schema/1.0.0/consent-purpose.ts +0 -14
  236. package/src/db/schema/1.0.0/consent-record.ts +0 -10
  237. package/src/db/schema/1.0.0/consent.ts +0 -20
  238. package/src/db/schema/1.0.0/domain.ts +0 -12
  239. package/src/db/schema/1.0.0/index.ts +0 -48
  240. package/src/db/schema/1.0.0/subject.ts +0 -11
  241. package/src/db/schema/2.0.0/audit-log.ts +0 -18
  242. package/src/db/schema/2.0.0/consent-policy.ts +0 -28
  243. package/src/db/schema/2.0.0/consent-purpose.ts +0 -12
  244. package/src/db/schema/2.0.0/consent.ts +0 -28
  245. package/src/db/schema/2.0.0/domain.ts +0 -12
  246. package/src/db/schema/2.0.0/index.ts +0 -47
  247. package/src/db/schema/2.0.0/subject.ts +0 -13
  248. package/src/db/schema/index.ts +0 -15
  249. package/src/db/tenant-scope.test.ts +0 -747
  250. package/src/db/tenant-scope.ts +0 -103
  251. package/src/define-config.ts +0 -19
  252. package/src/handlers/consent/check.handler.ts +0 -126
  253. package/src/handlers/init/geo.test.ts +0 -317
  254. package/src/handlers/init/geo.ts +0 -195
  255. package/src/handlers/init/index.test.ts +0 -205
  256. package/src/handlers/init/index.ts +0 -114
  257. package/src/handlers/init/translations.test.ts +0 -121
  258. package/src/handlers/init/translations.ts +0 -69
  259. package/src/handlers/status/status.handler.test.ts +0 -155
  260. package/src/handlers/status/status.handler.ts +0 -51
  261. package/src/handlers/subject/get.handler.ts +0 -92
  262. package/src/handlers/subject/list.handler.ts +0 -92
  263. package/src/handlers/subject/patch.handler.ts +0 -119
  264. package/src/handlers/subject/post.handler.test.ts +0 -294
  265. package/src/handlers/subject/post.handler.ts +0 -268
  266. package/src/handlers/utils/consent-enrichment.test.ts +0 -380
  267. package/src/handlers/utils/consent-enrichment.ts +0 -218
  268. package/src/init.test.ts +0 -122
  269. package/src/init.ts +0 -88
  270. package/src/middleware/auth/index.ts +0 -11
  271. package/src/middleware/auth/validate-api-key.test.ts +0 -86
  272. package/src/middleware/auth/validate-api-key.ts +0 -107
  273. package/src/middleware/cors/cors.test.ts +0 -135
  274. package/src/middleware/cors/cors.ts +0 -186
  275. package/src/middleware/cors/is-origin-trusted.test.ts +0 -164
  276. package/src/middleware/cors/is-origin-trusted.ts +0 -130
  277. package/src/middleware/cors/process-cors.ts +0 -91
  278. package/src/middleware/openapi/config.ts +0 -29
  279. package/src/middleware/openapi/handlers.ts +0 -34
  280. package/src/middleware/process-ip/index.test.ts +0 -193
  281. package/src/middleware/process-ip/index.ts +0 -199
  282. package/src/router.ts +0 -15
  283. package/src/routes/consent.ts +0 -52
  284. package/src/routes/init.ts +0 -105
  285. package/src/routes/status.ts +0 -46
  286. package/src/routes/subject.ts +0 -152
  287. package/src/types/api.ts +0 -48
  288. package/src/types/index.ts +0 -391
  289. package/src/utils/create-telemetry-options.test.ts +0 -286
  290. package/src/utils/create-telemetry-options.ts +0 -229
  291. package/src/utils/env.ts +0 -84
  292. package/src/utils/extract-error-message.ts +0 -21
  293. package/src/utils/instrumentation.test.ts +0 -183
  294. package/src/utils/instrumentation.ts +0 -194
  295. package/src/utils/logger.ts +0 -41
  296. package/src/utils/metrics.test.ts +0 -311
  297. package/src/utils/metrics.ts +0 -402
  298. package/src/utils/telemetry-pii.test.ts +0 -323
  299. package/src/version.ts +0 -2
  300. package/tsconfig.json +0 -11
  301. package/vitest.config.ts +0 -28
  302. /package/{src/db/adapters/drizzle.ts → dist-types/db/adapters/drizzle.d.ts} +0 -0
  303. /package/{src/db/adapters/index.ts → dist-types/db/adapters/index.d.ts} +0 -0
  304. /package/{src/db/adapters/kysely.ts → dist-types/db/adapters/kysely.d.ts} +0 -0
  305. /package/{src/db/adapters/mongo.ts → dist-types/db/adapters/mongo.d.ts} +0 -0
  306. /package/{src/db/adapters/prisma.ts → dist-types/db/adapters/prisma.d.ts} +0 -0
  307. /package/{src/db/adapters/typeorm.ts → dist-types/db/adapters/typeorm.d.ts} +0 -0
  308. /package/{src/utils/index.ts → dist-types/utils/index.d.ts} +0 -0
@@ -1,229 +0,0 @@
1
- import {
2
- context,
3
- type Meter,
4
- metrics,
5
- type Span,
6
- SpanStatusCode,
7
- trace,
8
- } from '@opentelemetry/api';
9
- import type { C15TOptions } from '../types';
10
- import { version } from '../version';
11
- import { extractErrorMessage } from './extract-error-message';
12
-
13
- type TelemetryConfig = C15TOptions['telemetry'];
14
-
15
- // ── Cached config (set once during init) ──────────────────────────────
16
- let cachedConfig: TelemetryConfig | null = null;
17
- let cachedDefaultAttributes: Record<string, string | number | boolean> = {};
18
-
19
- /**
20
- * Creates telemetry configuration from provided options
21
- *
22
- * This function merges user-provided telemetry options with sensible defaults,
23
- * ensuring that service name and version are always properly set.
24
- *
25
- * Telemetry is opt-in by default - users must explicitly set enabled: true.
26
- *
27
- * @param appName - The application name to use for service.name attribute
28
- * @param telemetryConfig - Optional user-provided telemetry configuration
29
- * @param tenantId - Optional tenant ID for multi-tenant deployments
30
- * @returns Properly structured telemetry options for the OpenTelemetry SDK
31
- */
32
- export function createTelemetryOptions(
33
- appName = 'c15t',
34
- telemetryConfig?: TelemetryConfig,
35
- tenantId?: string
36
- ): TelemetryConfig {
37
- const defaultAttributes: Record<string, string | number | boolean> = {
38
- ...(telemetryConfig?.defaultAttributes || {}),
39
-
40
- // Always ensure these core attributes are set
41
- 'service.name': String(appName),
42
- 'service.version': version,
43
- };
44
-
45
- if (tenantId) {
46
- defaultAttributes['tenant.id'] = tenantId;
47
- }
48
-
49
- const config: TelemetryConfig = {
50
- // Opt-in: disabled by default, must be explicitly enabled
51
- enabled: telemetryConfig?.enabled ?? false,
52
- tracer: telemetryConfig?.tracer,
53
- meter: telemetryConfig?.meter,
54
- defaultAttributes,
55
- };
56
-
57
- // Cache for use without explicit options
58
- cachedConfig = config;
59
- cachedDefaultAttributes = defaultAttributes;
60
-
61
- return config;
62
- }
63
-
64
- /**
65
- * Checks if telemetry is enabled.
66
- * When called without options, uses the cached config from init.
67
- */
68
- export function isTelemetryEnabled(options?: C15TOptions): boolean {
69
- if (options) {
70
- return options.telemetry?.enabled === true;
71
- }
72
- return cachedConfig?.enabled === true;
73
- }
74
-
75
- /**
76
- * Gets the tracer for the c15t backend.
77
- * When called without options, uses the cached config from init.
78
- */
79
- export const getTracer = (options?: C15TOptions) => {
80
- if (!isTelemetryEnabled(options)) {
81
- // Return a no-op tracer when telemetry is disabled
82
- return trace.getTracer('c15t-noop');
83
- }
84
- const tracer = options?.telemetry?.tracer ?? cachedConfig?.tracer;
85
- if (tracer) {
86
- return tracer;
87
- }
88
- return trace.getTracer(options?.appName ?? 'c15t');
89
- };
90
-
91
- /**
92
- * Gets the meter for the c15t backend.
93
- * When called without options, uses the cached config from init.
94
- */
95
- export const getMeter = (options?: C15TOptions): Meter => {
96
- if (!isTelemetryEnabled(options)) {
97
- // Return a no-op meter when telemetry is disabled
98
- return metrics.getMeter('c15t-noop');
99
- }
100
- const meter = options?.telemetry?.meter ?? cachedConfig?.meter;
101
- if (meter) {
102
- return meter;
103
- }
104
- return metrics.getMeter(options?.appName ?? 'c15t');
105
- };
106
-
107
- /**
108
- * Gets the cached default attributes.
109
- * Used by span wrappers when no explicit options are provided.
110
- */
111
- export function getDefaultAttributes(): Record<
112
- string,
113
- string | number | boolean
114
- > {
115
- return cachedDefaultAttributes;
116
- }
117
-
118
- /**
119
- * Resets the cached telemetry config (for testing).
120
- */
121
- export function resetTelemetryConfig(): void {
122
- cachedConfig = null;
123
- cachedDefaultAttributes = {};
124
- }
125
-
126
- /**
127
- * Creates a span for an API request
128
- */
129
- export const createRequestSpan = (
130
- method: string,
131
- path: string,
132
- options?: C15TOptions
133
- ) => {
134
- if (!isTelemetryEnabled(options)) {
135
- return null;
136
- }
137
-
138
- const tracer = getTracer(options);
139
- const defaultAttrs =
140
- options?.telemetry?.defaultAttributes || getDefaultAttributes();
141
-
142
- const span = tracer.startSpan(`${method} ${path}`, {
143
- attributes: {
144
- 'http.method': method,
145
- ...defaultAttrs,
146
- },
147
- });
148
-
149
- return span;
150
- };
151
-
152
- /**
153
- * Wraps an API request handler in a span.
154
- * The span is set as active context so child spans nest correctly.
155
- */
156
- export const withRequestSpan = async <T>(
157
- method: string,
158
- path: string,
159
- operation: () => Promise<T>,
160
- options?: C15TOptions
161
- ): Promise<T> => {
162
- const span = createRequestSpan(method, path, options);
163
-
164
- if (!span) {
165
- return operation();
166
- }
167
-
168
- try {
169
- const result = await withSpanContext(span, operation);
170
- span.setStatus({ code: SpanStatusCode.OK });
171
- return result;
172
- } catch (error) {
173
- handleSpanError(span, error);
174
- throw error;
175
- } finally {
176
- span.end();
177
- }
178
- };
179
-
180
- /**
181
- * Handles errors in spans
182
- */
183
- export const handleSpanError = (span: Span, error: unknown) => {
184
- span.setStatus({
185
- code: SpanStatusCode.ERROR,
186
- message: extractErrorMessage(error),
187
- });
188
-
189
- if (error instanceof Error) {
190
- span.setAttribute('error.type', error.name);
191
- }
192
- };
193
-
194
- /**
195
- * Gets the current trace context for log correlation.
196
- * Returns trace and span IDs from the active span.
197
- *
198
- * @returns Object with traceId and spanId, or null if no active span
199
- */
200
- export function getTraceContext(): {
201
- traceId: string;
202
- spanId: string;
203
- } | null {
204
- const activeSpan = trace.getActiveSpan();
205
- if (!activeSpan) {
206
- return null;
207
- }
208
-
209
- const spanContext = activeSpan.spanContext();
210
- if (!spanContext) {
211
- return null;
212
- }
213
-
214
- return {
215
- traceId: spanContext.traceId,
216
- spanId: spanContext.spanId,
217
- };
218
- }
219
-
220
- /**
221
- * Runs a function within a span context, making the span active.
222
- * This allows nested operations to access the parent span via trace.getActiveSpan().
223
- */
224
- export const withSpanContext = async <T>(
225
- span: Span,
226
- operation: () => Promise<T>
227
- ): Promise<T> => {
228
- return context.with(trace.setSpan(context.active(), span), operation);
229
- };
package/src/utils/env.ts DELETED
@@ -1,84 +0,0 @@
1
- /**
2
- * Environment variables object
3
- *
4
- * Provides access to environment variables in a way that works in both
5
- * browser and Node.js environments. In Node.js, this will be process.env,
6
- * and in browsers, it will be an empty object.
7
- *
8
- * @returns An object containing environment variables accessible in the current runtime
9
- *
10
- * @example
11
- * ```ts
12
- * // Access an environment variable
13
- * const apiKey = env.API_KEY;
14
- * ```
15
- */
16
- export const env = typeof process !== 'undefined' ? process.env : {};
17
-
18
- /**
19
- * Determines if the application is running in production mode
20
- *
21
- * Checks if NODE_ENV is set to 'production'. This is useful for
22
- * conditionally enabling or disabling features based on the environment.
23
- *
24
- * @returns Boolean indicating whether the application is running in production mode
25
- *
26
- * @example
27
- * ```ts
28
- * // Conditionally execute code based on environment
29
- * if (isProduction) {
30
- * // Production-only code
31
- * }
32
- * ```
33
- */
34
- export const isProduction =
35
- typeof process !== 'undefined' && process.env.NODE_ENV === 'production';
36
-
37
- /**
38
- * Converts a string or boolean value to a boolean
39
- *
40
- * @param val - The value to convert to boolean
41
- * @returns `false` if the value is falsy or the string 'false', otherwise `true`
42
- *
43
- * @example
44
- * ```ts
45
- * toBoolean('true'); // true
46
- * toBoolean('false'); // false
47
- * toBoolean(undefined); // false
48
- * toBoolean(true); // true
49
- * ```
50
- *
51
- * @internal Used for environment variable parsing
52
- */
53
- function toBoolean(val: boolean | string | undefined) {
54
- return val ? val !== 'false' : false;
55
- }
56
-
57
- /**
58
- * The current Node.js environment value
59
- *
60
- * Retrieves the NODE_ENV environment variable value if available,
61
- * otherwise returns an empty string.
62
- *
63
- * @returns The current NODE_ENV value or empty string if not set
64
- */
65
- export const nodeENV =
66
- (typeof process !== 'undefined' && process.env && process.env.NODE_ENV) || '';
67
-
68
- /**
69
- * Determines if the application is running in test mode
70
- *
71
- * Checks if NODE_ENV is set to 'test' or if the TEST environment
72
- * variable is truthy and not 'false'.
73
- *
74
- * @returns Boolean indicating whether the application is running in test mode
75
- *
76
- * @example
77
- * ```ts
78
- * // Skip expensive operations in tests
79
- * if (!isTest) {
80
- * runExpensiveOperation();
81
- * }
82
- * ```
83
- */
84
- export const isTest = nodeENV === 'test' || toBoolean(env.TEST);
@@ -1,21 +0,0 @@
1
- /**
2
- * Extracts a useful error message from any error type.
3
- *
4
- * Handles `AggregateError` (e.g. from Node.js `net.connect` failing on both
5
- * IPv4/IPv6) where `error.message` is empty but `error.errors[]` contains the
6
- * real messages.
7
- */
8
- export function extractErrorMessage(error: unknown): string {
9
- if (error instanceof AggregateError && error.errors?.length > 0) {
10
- const inner = error.errors
11
- .map((e: unknown) => (e instanceof Error ? e.message : String(e)))
12
- .join('; ');
13
- return `AggregateError: ${inner}`;
14
- }
15
-
16
- if (error instanceof Error) {
17
- return error.message || error.name;
18
- }
19
-
20
- return String(error);
21
- }
@@ -1,183 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from 'vitest';
2
- import type { C15TOptions } from '../types';
3
- import {
4
- withCacheSpan,
5
- withDatabaseSpan,
6
- withExternalSpan,
7
- } from './instrumentation';
8
-
9
- // Mock create-telemetry-options
10
- vi.mock('./create-telemetry-options', () => {
11
- const { SpanStatusCode } = require('@opentelemetry/api');
12
-
13
- const mockSpan = () => ({
14
- setStatus: vi.fn(),
15
- setAttribute: vi.fn(),
16
- updateName: vi.fn(),
17
- end: vi.fn(),
18
- });
19
-
20
- return {
21
- isTelemetryEnabled: vi.fn(
22
- (options) => options?.telemetry?.enabled === true
23
- ),
24
- getTracer: vi.fn(() => ({
25
- startSpan: vi.fn(() => mockSpan()),
26
- })),
27
- getDefaultAttributes: vi.fn(() => ({
28
- 'service.name': 'test',
29
- 'service.version': '1.0.0',
30
- })),
31
- withSpanContext: vi.fn((_span, operation) => operation()),
32
- handleSpanError: vi.fn((span, error) => {
33
- span.setStatus({
34
- code: SpanStatusCode.ERROR,
35
- message: error instanceof Error ? error.message : String(error),
36
- });
37
- if (error instanceof Error) {
38
- span.setAttribute('error.type', error.name);
39
- }
40
- }),
41
- };
42
- });
43
-
44
- afterEach(() => {
45
- vi.clearAllMocks();
46
- });
47
-
48
- const enabledOptions: C15TOptions = {
49
- trustedOrigins: [],
50
- adapter: {} as C15TOptions['adapter'],
51
- telemetry: {
52
- enabled: true,
53
- },
54
- };
55
-
56
- describe('withDatabaseSpan', () => {
57
- it('returns operation result when telemetry is disabled', async () => {
58
- const result = await withDatabaseSpan(
59
- { operation: 'find', entity: 'subject' },
60
- async () => ({ id: '123', name: 'test' })
61
- );
62
-
63
- expect(result).toEqual({ id: '123', name: 'test' });
64
- });
65
-
66
- it('returns operation result when telemetry is enabled', async () => {
67
- const result = await withDatabaseSpan(
68
- { operation: 'find', entity: 'subject' },
69
- async () => ({ id: '123', name: 'test' }),
70
- enabledOptions
71
- );
72
-
73
- expect(result).toEqual({ id: '123', name: 'test' });
74
- });
75
-
76
- it('propagates errors from operation', async () => {
77
- const error = new Error('DB connection failed');
78
-
79
- await expect(
80
- withDatabaseSpan(
81
- { operation: 'find', entity: 'subject' },
82
- async () => {
83
- throw error;
84
- },
85
- enabledOptions
86
- )
87
- ).rejects.toThrow('DB connection failed');
88
- });
89
-
90
- it('executes operation without span when telemetry is disabled', async () => {
91
- const operation = vi.fn().mockResolvedValue('result');
92
-
93
- const result = await withDatabaseSpan(
94
- { operation: 'create', entity: 'consent' },
95
- operation
96
- );
97
-
98
- expect(result).toBe('result');
99
- expect(operation).toHaveBeenCalledTimes(1);
100
- });
101
- });
102
-
103
- describe('withExternalSpan', () => {
104
- it('returns operation result when telemetry is disabled', async () => {
105
- const result = await withExternalSpan(
106
- { url: 'https://example.com/api', method: 'GET' },
107
- async () => ({ status: 200 })
108
- );
109
-
110
- expect(result).toEqual({ status: 200 });
111
- });
112
-
113
- it('returns operation result when telemetry is enabled', async () => {
114
- const result = await withExternalSpan(
115
- { url: 'https://example.com/api', method: 'GET' },
116
- async () => ({ status: 200 }),
117
- enabledOptions
118
- );
119
-
120
- expect(result).toEqual({ status: 200 });
121
- });
122
-
123
- it('propagates errors from operation', async () => {
124
- const error = new Error('Network error');
125
-
126
- await expect(
127
- withExternalSpan(
128
- { url: 'https://example.com/api', method: 'POST' },
129
- async () => {
130
- throw error;
131
- },
132
- enabledOptions
133
- )
134
- ).rejects.toThrow('Network error');
135
- });
136
- });
137
-
138
- describe('withCacheSpan', () => {
139
- it('returns operation result when telemetry is disabled', async () => {
140
- const result = await withCacheSpan('get', 'memory', async () => ({
141
- data: 'cached',
142
- }));
143
-
144
- expect(result).toEqual({ data: 'cached' });
145
- });
146
-
147
- it('returns operation result when telemetry is enabled', async () => {
148
- const result = await withCacheSpan(
149
- 'get',
150
- 'external',
151
- async () => ({ data: 'cached' }),
152
- enabledOptions
153
- );
154
-
155
- expect(result).toEqual({ data: 'cached' });
156
- });
157
-
158
- it('returns null for cache miss', async () => {
159
- const result = await withCacheSpan(
160
- 'get',
161
- 'memory',
162
- async () => null,
163
- enabledOptions
164
- );
165
-
166
- expect(result).toBeNull();
167
- });
168
-
169
- it('propagates errors from operation', async () => {
170
- const error = new Error('Cache connection failed');
171
-
172
- await expect(
173
- withCacheSpan(
174
- 'get',
175
- 'external',
176
- async () => {
177
- throw error;
178
- },
179
- enabledOptions
180
- )
181
- ).rejects.toThrow('Cache connection failed');
182
- });
183
- });
@@ -1,194 +0,0 @@
1
- import type { Span } from '@opentelemetry/api';
2
- import { SpanKind, SpanStatusCode } from '@opentelemetry/api';
3
- import type { C15TOptions } from '../types';
4
- import {
5
- getDefaultAttributes,
6
- getTracer,
7
- handleSpanError,
8
- isTelemetryEnabled,
9
- withSpanContext,
10
- } from './create-telemetry-options';
11
-
12
- /**
13
- * Span attributes for database operations
14
- */
15
- export interface DatabaseSpanAttributes {
16
- /** The database operation type (find, create, update, delete) */
17
- operation: 'find' | 'create' | 'update' | 'delete' | 'findOrCreate';
18
- /** The entity type being operated on */
19
- entity: string;
20
- /** Optional additional attributes */
21
- [key: string]: string | number | boolean | undefined;
22
- }
23
-
24
- /**
25
- * Span attributes for external API calls
26
- */
27
- export interface ExternalSpanAttributes {
28
- /** The URL being called */
29
- url: string;
30
- /** The HTTP method */
31
- method: string;
32
- /** Optional additional attributes */
33
- [key: string]: string | number | boolean | undefined;
34
- }
35
-
36
- /**
37
- * Execute an async operation within a span, handling status and error recording.
38
- *
39
- * Sets SpanStatusCode.OK on success, records error attributes and sets
40
- * SpanStatusCode.ERROR on failure, and always ends the span.
41
- */
42
- async function executeWithSpan<T>(
43
- span: Span,
44
- operation: () => Promise<T>
45
- ): Promise<T> {
46
- try {
47
- const result = await withSpanContext(span, operation);
48
- span.setStatus({ code: SpanStatusCode.OK });
49
- return result;
50
- } catch (error) {
51
- handleSpanError(span, error);
52
- throw error;
53
- } finally {
54
- span.end();
55
- }
56
- }
57
-
58
- /**
59
- * Resolves default attributes from explicit options or the cached config.
60
- */
61
- function resolveDefaultAttributes(
62
- options?: C15TOptions
63
- ): Record<string, string | number | boolean> {
64
- return options?.telemetry?.defaultAttributes || getDefaultAttributes();
65
- }
66
-
67
- /**
68
- * Wraps a database operation in a span for tracing.
69
- *
70
- * @param attributes - Span attributes describing the operation
71
- * @param operation - The async operation to wrap
72
- * @param options - C15T options for telemetry configuration
73
- * @returns The result of the operation
74
- *
75
- * @example
76
- * ```typescript
77
- * const subject = await withDatabaseSpan(
78
- * { operation: 'find', entity: 'subject' },
79
- * async () => db.subject.findUnique({ where: { id } }),
80
- * options
81
- * );
82
- * ```
83
- */
84
- export async function withDatabaseSpan<T>(
85
- attributes: DatabaseSpanAttributes,
86
- operation: () => Promise<T>,
87
- options?: C15TOptions
88
- ): Promise<T> {
89
- if (!isTelemetryEnabled(options)) {
90
- return operation();
91
- }
92
-
93
- const tracer = getTracer(options);
94
- const spanName = `db.${attributes.entity}.${attributes.operation}`;
95
-
96
- const span = tracer.startSpan(spanName, {
97
- kind: SpanKind.CLIENT,
98
- attributes: {
99
- 'db.system': 'c15t',
100
- 'db.operation': attributes.operation,
101
- 'db.entity': attributes.entity,
102
- ...resolveDefaultAttributes(options),
103
- ...Object.fromEntries(
104
- Object.entries(attributes).filter(
105
- ([key]) => !['operation', 'entity'].includes(key)
106
- )
107
- ),
108
- },
109
- });
110
-
111
- return executeWithSpan(span, operation);
112
- }
113
-
114
- /**
115
- * Wraps an external API call in a span for tracing.
116
- *
117
- * @param attributes - Span attributes describing the external call
118
- * @param operation - The async operation to wrap
119
- * @param options - C15T options for telemetry configuration
120
- * @returns The result of the operation
121
- *
122
- * @example
123
- * ```typescript
124
- * const response = await withExternalSpan(
125
- * { url: 'https://api.example.com/data', method: 'GET' },
126
- * async () => fetch('https://api.example.com/data'),
127
- * options
128
- * );
129
- * ```
130
- */
131
- export async function withExternalSpan<T>(
132
- attributes: ExternalSpanAttributes,
133
- operation: () => Promise<T>,
134
- options?: C15TOptions
135
- ): Promise<T> {
136
- if (!isTelemetryEnabled(options)) {
137
- return operation();
138
- }
139
-
140
- const tracer = getTracer(options);
141
- const url = new URL(attributes.url);
142
- const spanName = `HTTP ${attributes.method} ${url.hostname}`;
143
-
144
- const span = tracer.startSpan(spanName, {
145
- kind: SpanKind.CLIENT,
146
- attributes: {
147
- 'http.method': attributes.method,
148
- 'http.url': `${url.origin}${url.pathname}`,
149
- 'http.host': url.hostname,
150
- ...resolveDefaultAttributes(options),
151
- ...Object.fromEntries(
152
- Object.entries(attributes).filter(
153
- ([key]) => !['url', 'method'].includes(key)
154
- )
155
- ),
156
- },
157
- });
158
-
159
- return executeWithSpan(span, operation);
160
- }
161
-
162
- /**
163
- * Wraps a cache operation in a span for tracing.
164
- *
165
- * @param operation - The cache operation type
166
- * @param layer - The cache layer (bundled, memory, external)
167
- * @param fn - The async operation to wrap
168
- * @param options - C15T options for telemetry configuration
169
- * @returns The result of the operation
170
- */
171
- export async function withCacheSpan<T>(
172
- operation: 'get' | 'set' | 'delete',
173
- layer: 'bundled' | 'memory' | 'external',
174
- fn: () => Promise<T>,
175
- options?: C15TOptions
176
- ): Promise<T> {
177
- if (!isTelemetryEnabled(options)) {
178
- return fn();
179
- }
180
-
181
- const tracer = getTracer(options);
182
- const spanName = `cache.${layer}.${operation}`;
183
-
184
- const span = tracer.startSpan(spanName, {
185
- kind: SpanKind.CLIENT,
186
- attributes: {
187
- 'cache.operation': operation,
188
- 'cache.layer': layer,
189
- ...resolveDefaultAttributes(options),
190
- },
191
- });
192
-
193
- return executeWithSpan(span, fn);
194
- }