autotel 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1946 -0
  3. package/dist/chunk-2LNRY4QK.js +273 -0
  4. package/dist/chunk-2LNRY4QK.js.map +1 -0
  5. package/dist/chunk-3HENGDW2.js +587 -0
  6. package/dist/chunk-3HENGDW2.js.map +1 -0
  7. package/dist/chunk-4OAT42CA.cjs +73 -0
  8. package/dist/chunk-4OAT42CA.cjs.map +1 -0
  9. package/dist/chunk-5GWX5LFW.js +70 -0
  10. package/dist/chunk-5GWX5LFW.js.map +1 -0
  11. package/dist/chunk-5R2M36QB.js +195 -0
  12. package/dist/chunk-5R2M36QB.js.map +1 -0
  13. package/dist/chunk-5ZN622AO.js +73 -0
  14. package/dist/chunk-5ZN622AO.js.map +1 -0
  15. package/dist/chunk-77MSMAUQ.cjs +498 -0
  16. package/dist/chunk-77MSMAUQ.cjs.map +1 -0
  17. package/dist/chunk-ABPEQ6RK.cjs +596 -0
  18. package/dist/chunk-ABPEQ6RK.cjs.map +1 -0
  19. package/dist/chunk-BWYGJKRB.js +95 -0
  20. package/dist/chunk-BWYGJKRB.js.map +1 -0
  21. package/dist/chunk-BZHG5IZ4.js +73 -0
  22. package/dist/chunk-BZHG5IZ4.js.map +1 -0
  23. package/dist/chunk-G7VZBCD6.cjs +35 -0
  24. package/dist/chunk-G7VZBCD6.cjs.map +1 -0
  25. package/dist/chunk-GVLK7YUU.cjs +30 -0
  26. package/dist/chunk-GVLK7YUU.cjs.map +1 -0
  27. package/dist/chunk-HCCXC7XG.js +205 -0
  28. package/dist/chunk-HCCXC7XG.js.map +1 -0
  29. package/dist/chunk-HE6T6FIX.cjs +203 -0
  30. package/dist/chunk-HE6T6FIX.cjs.map +1 -0
  31. package/dist/chunk-KIXWPOCO.cjs +100 -0
  32. package/dist/chunk-KIXWPOCO.cjs.map +1 -0
  33. package/dist/chunk-KVGNW3FC.js +87 -0
  34. package/dist/chunk-KVGNW3FC.js.map +1 -0
  35. package/dist/chunk-LITNXTTT.js +3 -0
  36. package/dist/chunk-LITNXTTT.js.map +1 -0
  37. package/dist/chunk-M4ANN7RL.js +114 -0
  38. package/dist/chunk-M4ANN7RL.js.map +1 -0
  39. package/dist/chunk-NC52UBR2.cjs +32 -0
  40. package/dist/chunk-NC52UBR2.cjs.map +1 -0
  41. package/dist/chunk-NHCNRQD3.cjs +212 -0
  42. package/dist/chunk-NHCNRQD3.cjs.map +1 -0
  43. package/dist/chunk-NZ72VDNY.cjs +4 -0
  44. package/dist/chunk-NZ72VDNY.cjs.map +1 -0
  45. package/dist/chunk-P6JUDYNO.js +57 -0
  46. package/dist/chunk-P6JUDYNO.js.map +1 -0
  47. package/dist/chunk-RJYY7BWX.js +1349 -0
  48. package/dist/chunk-RJYY7BWX.js.map +1 -0
  49. package/dist/chunk-TRI4V5BF.cjs +126 -0
  50. package/dist/chunk-TRI4V5BF.cjs.map +1 -0
  51. package/dist/chunk-UL33I6IS.js +139 -0
  52. package/dist/chunk-UL33I6IS.js.map +1 -0
  53. package/dist/chunk-URRW6M2C.cjs +61 -0
  54. package/dist/chunk-URRW6M2C.cjs.map +1 -0
  55. package/dist/chunk-UY3UYPBZ.cjs +77 -0
  56. package/dist/chunk-UY3UYPBZ.cjs.map +1 -0
  57. package/dist/chunk-W3253FGB.cjs +277 -0
  58. package/dist/chunk-W3253FGB.cjs.map +1 -0
  59. package/dist/chunk-W7LHZVQF.js +26 -0
  60. package/dist/chunk-W7LHZVQF.js.map +1 -0
  61. package/dist/chunk-WBWNM6LB.cjs +1360 -0
  62. package/dist/chunk-WBWNM6LB.cjs.map +1 -0
  63. package/dist/chunk-WFJ7L2RV.js +494 -0
  64. package/dist/chunk-WFJ7L2RV.js.map +1 -0
  65. package/dist/chunk-X4RMFFMR.js +28 -0
  66. package/dist/chunk-X4RMFFMR.js.map +1 -0
  67. package/dist/chunk-Y4Y2S7BM.cjs +92 -0
  68. package/dist/chunk-Y4Y2S7BM.cjs.map +1 -0
  69. package/dist/chunk-YLPNXZFI.cjs +143 -0
  70. package/dist/chunk-YLPNXZFI.cjs.map +1 -0
  71. package/dist/chunk-YTXEZ4SD.cjs +77 -0
  72. package/dist/chunk-YTXEZ4SD.cjs.map +1 -0
  73. package/dist/chunk-Z6ZWNWWR.js +30 -0
  74. package/dist/chunk-Z6ZWNWWR.js.map +1 -0
  75. package/dist/config.cjs +26 -0
  76. package/dist/config.cjs.map +1 -0
  77. package/dist/config.d.cts +75 -0
  78. package/dist/config.d.ts +75 -0
  79. package/dist/config.js +5 -0
  80. package/dist/config.js.map +1 -0
  81. package/dist/db.cjs +233 -0
  82. package/dist/db.cjs.map +1 -0
  83. package/dist/db.d.cts +123 -0
  84. package/dist/db.d.ts +123 -0
  85. package/dist/db.js +228 -0
  86. package/dist/db.js.map +1 -0
  87. package/dist/decorators.cjs +67 -0
  88. package/dist/decorators.cjs.map +1 -0
  89. package/dist/decorators.d.cts +91 -0
  90. package/dist/decorators.d.ts +91 -0
  91. package/dist/decorators.js +65 -0
  92. package/dist/decorators.js.map +1 -0
  93. package/dist/event-subscriber.cjs +6 -0
  94. package/dist/event-subscriber.cjs.map +1 -0
  95. package/dist/event-subscriber.d.cts +116 -0
  96. package/dist/event-subscriber.d.ts +116 -0
  97. package/dist/event-subscriber.js +3 -0
  98. package/dist/event-subscriber.js.map +1 -0
  99. package/dist/event-testing.cjs +21 -0
  100. package/dist/event-testing.cjs.map +1 -0
  101. package/dist/event-testing.d.cts +110 -0
  102. package/dist/event-testing.d.ts +110 -0
  103. package/dist/event-testing.js +4 -0
  104. package/dist/event-testing.js.map +1 -0
  105. package/dist/event.cjs +30 -0
  106. package/dist/event.cjs.map +1 -0
  107. package/dist/event.d.cts +282 -0
  108. package/dist/event.d.ts +282 -0
  109. package/dist/event.js +13 -0
  110. package/dist/event.js.map +1 -0
  111. package/dist/exporters.cjs +17 -0
  112. package/dist/exporters.cjs.map +1 -0
  113. package/dist/exporters.d.cts +1 -0
  114. package/dist/exporters.d.ts +1 -0
  115. package/dist/exporters.js +4 -0
  116. package/dist/exporters.js.map +1 -0
  117. package/dist/functional.cjs +46 -0
  118. package/dist/functional.cjs.map +1 -0
  119. package/dist/functional.d.cts +478 -0
  120. package/dist/functional.d.ts +478 -0
  121. package/dist/functional.js +13 -0
  122. package/dist/functional.js.map +1 -0
  123. package/dist/http.cjs +189 -0
  124. package/dist/http.cjs.map +1 -0
  125. package/dist/http.d.cts +169 -0
  126. package/dist/http.d.ts +169 -0
  127. package/dist/http.js +184 -0
  128. package/dist/http.js.map +1 -0
  129. package/dist/index.cjs +333 -0
  130. package/dist/index.cjs.map +1 -0
  131. package/dist/index.d.cts +758 -0
  132. package/dist/index.d.ts +758 -0
  133. package/dist/index.js +143 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/instrumentation.cjs +182 -0
  136. package/dist/instrumentation.cjs.map +1 -0
  137. package/dist/instrumentation.d.cts +49 -0
  138. package/dist/instrumentation.d.ts +49 -0
  139. package/dist/instrumentation.js +179 -0
  140. package/dist/instrumentation.js.map +1 -0
  141. package/dist/logger.cjs +19 -0
  142. package/dist/logger.cjs.map +1 -0
  143. package/dist/logger.d.cts +146 -0
  144. package/dist/logger.d.ts +146 -0
  145. package/dist/logger.js +6 -0
  146. package/dist/logger.js.map +1 -0
  147. package/dist/metric-helpers.cjs +31 -0
  148. package/dist/metric-helpers.cjs.map +1 -0
  149. package/dist/metric-helpers.d.cts +13 -0
  150. package/dist/metric-helpers.d.ts +13 -0
  151. package/dist/metric-helpers.js +6 -0
  152. package/dist/metric-helpers.js.map +1 -0
  153. package/dist/metric-testing.cjs +21 -0
  154. package/dist/metric-testing.cjs.map +1 -0
  155. package/dist/metric-testing.d.cts +110 -0
  156. package/dist/metric-testing.d.ts +110 -0
  157. package/dist/metric-testing.js +4 -0
  158. package/dist/metric-testing.js.map +1 -0
  159. package/dist/metric.cjs +26 -0
  160. package/dist/metric.cjs.map +1 -0
  161. package/dist/metric.d.cts +240 -0
  162. package/dist/metric.d.ts +240 -0
  163. package/dist/metric.js +9 -0
  164. package/dist/metric.js.map +1 -0
  165. package/dist/processors.cjs +17 -0
  166. package/dist/processors.cjs.map +1 -0
  167. package/dist/processors.d.cts +1 -0
  168. package/dist/processors.d.ts +1 -0
  169. package/dist/processors.js +4 -0
  170. package/dist/processors.js.map +1 -0
  171. package/dist/sampling.cjs +40 -0
  172. package/dist/sampling.cjs.map +1 -0
  173. package/dist/sampling.d.cts +260 -0
  174. package/dist/sampling.d.ts +260 -0
  175. package/dist/sampling.js +7 -0
  176. package/dist/sampling.js.map +1 -0
  177. package/dist/semantic-helpers.cjs +35 -0
  178. package/dist/semantic-helpers.cjs.map +1 -0
  179. package/dist/semantic-helpers.d.cts +442 -0
  180. package/dist/semantic-helpers.d.ts +442 -0
  181. package/dist/semantic-helpers.js +14 -0
  182. package/dist/semantic-helpers.js.map +1 -0
  183. package/dist/tail-sampling-processor.cjs +13 -0
  184. package/dist/tail-sampling-processor.cjs.map +1 -0
  185. package/dist/tail-sampling-processor.d.cts +27 -0
  186. package/dist/tail-sampling-processor.d.ts +27 -0
  187. package/dist/tail-sampling-processor.js +4 -0
  188. package/dist/tail-sampling-processor.js.map +1 -0
  189. package/dist/testing.cjs +286 -0
  190. package/dist/testing.cjs.map +1 -0
  191. package/dist/testing.d.cts +291 -0
  192. package/dist/testing.d.ts +291 -0
  193. package/dist/testing.js +263 -0
  194. package/dist/testing.js.map +1 -0
  195. package/dist/trace-context-DRZdUvVY.d.cts +181 -0
  196. package/dist/trace-context-DRZdUvVY.d.ts +181 -0
  197. package/dist/trace-helpers.cjs +54 -0
  198. package/dist/trace-helpers.cjs.map +1 -0
  199. package/dist/trace-helpers.d.cts +524 -0
  200. package/dist/trace-helpers.d.ts +524 -0
  201. package/dist/trace-helpers.js +5 -0
  202. package/dist/trace-helpers.js.map +1 -0
  203. package/dist/tracer-provider.cjs +21 -0
  204. package/dist/tracer-provider.cjs.map +1 -0
  205. package/dist/tracer-provider.d.cts +169 -0
  206. package/dist/tracer-provider.d.ts +169 -0
  207. package/dist/tracer-provider.js +4 -0
  208. package/dist/tracer-provider.js.map +1 -0
  209. package/package.json +280 -0
  210. package/src/baggage-span-processor.test.ts +202 -0
  211. package/src/baggage-span-processor.ts +98 -0
  212. package/src/circuit-breaker.test.ts +341 -0
  213. package/src/circuit-breaker.ts +184 -0
  214. package/src/config.test.ts +94 -0
  215. package/src/config.ts +169 -0
  216. package/src/db.test.ts +252 -0
  217. package/src/db.ts +447 -0
  218. package/src/decorators.test.ts +203 -0
  219. package/src/decorators.ts +188 -0
  220. package/src/env-config.test.ts +246 -0
  221. package/src/env-config.ts +158 -0
  222. package/src/event-queue.test.ts +222 -0
  223. package/src/event-queue.ts +203 -0
  224. package/src/event-subscriber.ts +136 -0
  225. package/src/event-testing.ts +197 -0
  226. package/src/event.test.ts +718 -0
  227. package/src/event.ts +556 -0
  228. package/src/exporters.ts +96 -0
  229. package/src/functional.test.ts +1059 -0
  230. package/src/functional.ts +2295 -0
  231. package/src/http.test.ts +487 -0
  232. package/src/http.ts +424 -0
  233. package/src/index.ts +158 -0
  234. package/src/init.customization.test.ts +210 -0
  235. package/src/init.integrations.test.ts +366 -0
  236. package/src/init.openllmetry.test.ts +282 -0
  237. package/src/init.protocol.test.ts +215 -0
  238. package/src/init.ts +1426 -0
  239. package/src/instrumentation.test.ts +108 -0
  240. package/src/instrumentation.ts +308 -0
  241. package/src/logger.test.ts +117 -0
  242. package/src/logger.ts +246 -0
  243. package/src/metric-helpers.ts +47 -0
  244. package/src/metric-testing.ts +197 -0
  245. package/src/metric.ts +434 -0
  246. package/src/metrics.test.ts +205 -0
  247. package/src/operation-context.ts +93 -0
  248. package/src/processors.ts +106 -0
  249. package/src/rate-limiter.test.ts +199 -0
  250. package/src/rate-limiter.ts +98 -0
  251. package/src/sampling.test.ts +513 -0
  252. package/src/sampling.ts +428 -0
  253. package/src/semantic-helpers.test.ts +311 -0
  254. package/src/semantic-helpers.ts +584 -0
  255. package/src/shutdown.test.ts +311 -0
  256. package/src/shutdown.ts +222 -0
  257. package/src/stub.integration.test.ts +361 -0
  258. package/src/tail-sampling-processor.test.ts +226 -0
  259. package/src/tail-sampling-processor.ts +51 -0
  260. package/src/testing.ts +670 -0
  261. package/src/trace-context.ts +470 -0
  262. package/src/trace-helpers.new.test.ts +278 -0
  263. package/src/trace-helpers.test.ts +242 -0
  264. package/src/trace-helpers.ts +690 -0
  265. package/src/tracer-provider.test.ts +183 -0
  266. package/src/tracer-provider.ts +266 -0
  267. package/src/track.test.ts +153 -0
  268. package/src/track.ts +120 -0
  269. package/src/validation.test.ts +306 -0
  270. package/src/validation.ts +239 -0
  271. package/src/variable-name-inference.test.ts +178 -0
  272. package/src/variable-name-inference.ts +242 -0
@@ -0,0 +1,470 @@
1
+ /**
2
+ * Trace context types and utilities
3
+ */
4
+
5
+ import type {
6
+ Span,
7
+ SpanStatusCode,
8
+ BaggageEntry,
9
+ Context,
10
+ } from '@opentelemetry/api';
11
+ import { context, propagation } from '@opentelemetry/api';
12
+ import { AsyncLocalStorage } from 'node:async_hooks';
13
+
14
+ /**
15
+ * AsyncLocalStorage for storing the active context with baggage
16
+ * This allows setters to update the context and have it persist
17
+ */
18
+ const contextStorage = new AsyncLocalStorage<Context>();
19
+
20
+ /**
21
+ * Get the context storage instance (for initialization in functional.ts)
22
+ */
23
+ export function getContextStorage(): AsyncLocalStorage<Context> {
24
+ return contextStorage;
25
+ }
26
+
27
+ /**
28
+ * Get the active context, checking our stored context first
29
+ * This ensures baggage setters work with OpenTelemetry's propagation
30
+ */
31
+ export function getActiveContextWithBaggage(): Context {
32
+ // Check stored context first (from setters), then fall back to active context
33
+ // This ensures ctx.setBaggage() changes are visible to OpenTelemetry operations
34
+ const stored = contextStorage.getStore();
35
+ return stored ?? context.active();
36
+ }
37
+
38
+ /**
39
+ * Try to keep OpenTelemetry's context manager in sync with baggage updates
40
+ */
41
+ type ContextManagerLike = {
42
+ with?: (ctx: Context, fn: () => void) => void;
43
+ _asyncLocalStorage?: { enterWith?: (ctx: Context) => void };
44
+ };
45
+
46
+ function updateActiveContext(newContext: Context): void {
47
+ // Update our storage first so any helper reads see the new context
48
+ contextStorage.enterWith(newContext);
49
+
50
+ const contextWithManager = context as unknown as {
51
+ _getContextManager?: () => ContextManagerLike;
52
+ };
53
+
54
+ const manager = contextWithManager._getContextManager?.();
55
+ if (!manager) return;
56
+
57
+ const asyncLocal =
58
+ (manager as { _asyncLocalStorage?: { enterWith?: (ctx: Context) => void } })
59
+ ._asyncLocalStorage ?? undefined;
60
+ if (asyncLocal?.enterWith) {
61
+ asyncLocal.enterWith(newContext);
62
+ return;
63
+ }
64
+
65
+ if (typeof manager.with === 'function') {
66
+ manager.with(newContext, () => {});
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Base trace context containing trace identifiers
72
+ */
73
+ export interface TraceContextBase {
74
+ traceId: string;
75
+ spanId: string;
76
+ correlationId: string;
77
+ }
78
+
79
+ /**
80
+ * Span methods available on trace context
81
+ */
82
+ export interface SpanMethods {
83
+ setAttribute(key: string, value: string | number | boolean): void;
84
+ setAttributes(attrs: Record<string, string | number | boolean>): void;
85
+ setStatus(status: { code: SpanStatusCode; message?: string }): void;
86
+ recordException(exception: Error): void;
87
+ }
88
+
89
+ /**
90
+ * Baggage methods available on trace context
91
+ *
92
+ * @template TBaggage - Optional type for typed baggage (defaults to undefined for untyped)
93
+ */
94
+ export interface BaggageMethods<
95
+ TBaggage extends Record<string, unknown> | undefined = undefined,
96
+ > {
97
+ /**
98
+ * Get a baggage entry by key
99
+ * @param key - Baggage key
100
+ * @returns Baggage entry value or undefined
101
+ */
102
+ getBaggage(key: string): string | undefined;
103
+
104
+ /**
105
+ * Set a baggage entry
106
+ *
107
+ * Note: OpenTelemetry contexts are immutable. For proper scoping across async
108
+ * boundaries, use withBaggage() instead. This method updates baggage in the
109
+ * current context which may not propagate to all child operations.
110
+ *
111
+ * @param key - Baggage key
112
+ * @param value - Baggage value
113
+ * @returns The baggage value that was set (for chaining)
114
+ *
115
+ * @example Using withBaggage() (recommended)
116
+ * ```typescript
117
+ * await withBaggage({ baggage: { 'key': 'value' }, fn: async () => {
118
+ * // Baggage is available here and in child spans
119
+ * });
120
+ * ```
121
+ */
122
+ setBaggage(key: string, value: string): string;
123
+
124
+ /**
125
+ * Delete a baggage entry
126
+ *
127
+ * Note: OpenTelemetry contexts are immutable. For proper scoping across async
128
+ * boundaries, use withBaggage() with only the entries you want instead.
129
+ *
130
+ * @param key - Baggage key
131
+ */
132
+ deleteBaggage(key: string): void;
133
+
134
+ /**
135
+ * Get all baggage entries
136
+ * @returns Map of all baggage entries
137
+ */
138
+ getAllBaggage(): Map<string, BaggageEntry>;
139
+
140
+ /**
141
+ * Get typed baggage (only available when TBaggage is defined)
142
+ * This is used internally by defineBaggageSchema()
143
+ *
144
+ * @internal
145
+ */
146
+ getTypedBaggage?: TBaggage extends Record<string, unknown>
147
+ ? <T extends TBaggage>(namespace?: string) => Partial<T> | undefined
148
+ : never;
149
+
150
+ /**
151
+ * Set typed baggage (only available when TBaggage is defined)
152
+ * This is used internally by defineBaggageSchema()
153
+ *
154
+ * @internal
155
+ */
156
+ setTypedBaggage?: TBaggage extends Record<string, unknown>
157
+ ? <T extends TBaggage>(
158
+ namespace: string | undefined,
159
+ value: Partial<T>,
160
+ ) => void
161
+ : never;
162
+ }
163
+
164
+ /**
165
+ * Complete trace context that merges base context, span methods, and baggage methods
166
+ *
167
+ * This is the ctx parameter passed to factory functions in trace().
168
+ * It provides access to trace IDs, span manipulation methods, and baggage operations.
169
+ *
170
+ * @template TBaggage - Optional type for typed baggage support
171
+ *
172
+ * @example Untyped (default)
173
+ * ```typescript
174
+ * export const handler = trace((ctx) => async () => {
175
+ * ctx.getBaggage('key'); // returns string | undefined
176
+ * });
177
+ * ```
178
+ *
179
+ * @example Typed baggage
180
+ * ```typescript
181
+ * type TenantBaggage = { tenantId: string; region?: string };
182
+ *
183
+ * export const handler = trace<TenantBaggage>((ctx) => async () => {
184
+ * // Use typed schema helper for type-safe access
185
+ * const schema = defineBaggageSchema<TenantBaggage>('tenant');
186
+ * const tenant = schema.get(ctx); // Partial<TenantBaggage> | undefined
187
+ * });
188
+ * ```
189
+ */
190
+ export type TraceContext<
191
+ TBaggage extends Record<string, unknown> | undefined = undefined,
192
+ > = TraceContextBase & SpanMethods & BaggageMethods<TBaggage>;
193
+
194
+ /**
195
+ * Create a TraceContext from an OpenTelemetry Span
196
+ *
197
+ * This utility extracts trace context information from a span
198
+ * and provides span manipulation methods and baggage operations in a consistent format.
199
+ *
200
+ * Note: Baggage methods always operate on the currently active context,
201
+ * which may differ from the context when createTraceContext was called.
202
+ */
203
+ export function createTraceContext<
204
+ TBaggage extends Record<string, unknown> | undefined = undefined,
205
+ >(span: Span): TraceContext<TBaggage> {
206
+ const spanContext = span.spanContext();
207
+
208
+ // Store the current active context in AsyncLocalStorage so baggage setters can update it
209
+ // This ensures ctx.setBaggage() changes persist and are visible to OpenTelemetry operations
210
+ // IMPORTANT: Only initialize if not already set (preserve baggage updates from parent spans)
211
+ const existingStored = contextStorage.getStore();
212
+ if (!existingStored) {
213
+ const activeContext = context.active();
214
+ contextStorage.enterWith(activeContext);
215
+ }
216
+
217
+ // Baggage helpers that always use the current active context
218
+ // This ensures baggage operations work correctly even if context changes
219
+ const baggageHelpers: BaggageMethods<TBaggage> = {
220
+ getBaggage(key: string): string | undefined {
221
+ // Check active context first (from withBaggage, context.with, etc.)
222
+ // Then check stored context (from setters)
223
+ // This ensures both withBaggage() and ctx.setBaggage() work correctly
224
+ const activeCtx = context.active();
225
+ let baggage = propagation.getBaggage(activeCtx);
226
+ if (!baggage) {
227
+ const storedContext = contextStorage.getStore();
228
+ if (storedContext) {
229
+ baggage = propagation.getBaggage(storedContext);
230
+ }
231
+ }
232
+ return baggage?.getEntry(key)?.value;
233
+ },
234
+
235
+ setBaggage(key: string, value: string): string {
236
+ // OpenTelemetry contexts are immutable, so we create a new context with updated baggage
237
+ // Check active context first (may have baggage from withBaggage), then stored context
238
+ const activeCtx = context.active();
239
+ const storedContext = contextStorage.getStore();
240
+ const currentContext = storedContext ?? activeCtx;
241
+ const baggage =
242
+ propagation.getBaggage(currentContext) ?? propagation.createBaggage();
243
+ const updated = baggage.setEntry(key, { value });
244
+ const newContext = propagation.setBaggage(currentContext, updated);
245
+
246
+ updateActiveContext(newContext);
247
+
248
+ return value;
249
+ },
250
+
251
+ deleteBaggage(key: string): void {
252
+ // Check active context first, then stored context
253
+ const activeCtx = context.active();
254
+ const storedContext = contextStorage.getStore();
255
+ const currentContext = storedContext ?? activeCtx;
256
+ const baggage = propagation.getBaggage(currentContext);
257
+ if (baggage) {
258
+ const updated = baggage.removeEntry(key);
259
+ const newContext = propagation.setBaggage(currentContext, updated);
260
+
261
+ updateActiveContext(newContext);
262
+ }
263
+ },
264
+
265
+ getAllBaggage(): Map<string, BaggageEntry> {
266
+ // Check active context first, then stored context
267
+ const activeCtx = context.active();
268
+ let baggage = propagation.getBaggage(activeCtx);
269
+ if (!baggage) {
270
+ const storedContext = contextStorage.getStore();
271
+ if (storedContext) {
272
+ baggage = propagation.getBaggage(storedContext);
273
+ }
274
+ }
275
+ if (!baggage) {
276
+ return new Map();
277
+ }
278
+
279
+ // Convert baggage entries to a Map
280
+ const entries = new Map<string, BaggageEntry>();
281
+ for (const [key, entry] of baggage.getAllEntries()) {
282
+ entries.set(key, entry);
283
+ }
284
+ return entries;
285
+ },
286
+
287
+ // Typed baggage helpers (used by defineBaggageSchema)
288
+ getTypedBaggage: (<T extends Record<string, unknown>>(
289
+ namespace?: string,
290
+ ) => {
291
+ // Check active context first, then stored context
292
+ const activeCtx = context.active();
293
+ let baggage = propagation.getBaggage(activeCtx);
294
+ if (!baggage) {
295
+ const storedContext = contextStorage.getStore();
296
+ if (storedContext) {
297
+ baggage = propagation.getBaggage(storedContext);
298
+ }
299
+ }
300
+ if (!baggage) return;
301
+
302
+ const prefix = namespace ? `${namespace}.` : '';
303
+ const result: Record<string, unknown> = {};
304
+
305
+ for (const [key, entry] of baggage.getAllEntries()) {
306
+ if (namespace && key.startsWith(prefix)) {
307
+ const fieldName = key.slice(prefix.length);
308
+ result[fieldName] = entry.value;
309
+ } else if (!namespace) {
310
+ result[key] = entry.value;
311
+ }
312
+ }
313
+
314
+ return Object.keys(result).length > 0
315
+ ? (result as Partial<T>)
316
+ : undefined;
317
+ }) as TBaggage extends Record<string, unknown>
318
+ ? <T extends TBaggage>(namespace?: string) => Partial<T> | undefined
319
+ : never,
320
+
321
+ setTypedBaggage: (<T extends Record<string, unknown>>(
322
+ namespace: string | undefined,
323
+ value: Partial<T>,
324
+ ) => {
325
+ // Check active context first, then stored context
326
+ const activeCtx = context.active();
327
+ const storedContext = contextStorage.getStore();
328
+ const currentContext = storedContext ?? activeCtx;
329
+ let baggage =
330
+ propagation.getBaggage(currentContext) ?? propagation.createBaggage();
331
+
332
+ const prefix = namespace ? `${namespace}.` : '';
333
+ for (const [key, val] of Object.entries(value)) {
334
+ if (val !== undefined) {
335
+ const baggageKey = `${prefix}${key}`;
336
+ baggage = baggage.setEntry(baggageKey, { value: String(val) });
337
+ }
338
+ }
339
+
340
+ const newContext = propagation.setBaggage(currentContext, baggage);
341
+ updateActiveContext(newContext);
342
+ }) as TBaggage extends Record<string, unknown>
343
+ ? <T extends TBaggage>(
344
+ namespace: string | undefined,
345
+ value: Partial<T>,
346
+ ) => void
347
+ : never,
348
+ };
349
+
350
+ return {
351
+ traceId: spanContext.traceId,
352
+ spanId: spanContext.spanId,
353
+ correlationId: spanContext.traceId.slice(0, 16),
354
+ setAttribute: span.setAttribute.bind(span),
355
+ setAttributes: span.setAttributes.bind(span),
356
+ setStatus: span.setStatus.bind(span),
357
+ recordException: span.recordException.bind(span),
358
+ ...baggageHelpers,
359
+ };
360
+ }
361
+
362
+ /**
363
+ * Define a typed baggage schema for type-safe baggage operations
364
+ *
365
+ * This helper provides a type-safe API for working with baggage entries.
366
+ * The namespace parameter is optional and prefixes all keys to avoid collisions.
367
+ *
368
+ * @template T - The baggage schema type (all fields are treated as optional)
369
+ * @param namespace - Optional namespace to prefix baggage keys
370
+ *
371
+ * @example Basic usage
372
+ * ```typescript
373
+ * type TenantBaggage = { tenantId: string; region?: string };
374
+ * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
375
+ *
376
+ * export const handler = trace<TenantBaggage>((ctx) => async () => {
377
+ * // Get typed baggage
378
+ * const tenant = tenantBaggage.get(ctx);
379
+ * if (tenant?.tenantId) {
380
+ * console.log('Tenant:', tenant.tenantId);
381
+ * }
382
+ *
383
+ * // Set typed baggage
384
+ * tenantBaggage.set(ctx, { tenantId: 't1', region: 'us-east-1' });
385
+ * });
386
+ * ```
387
+ *
388
+ * @example With withBaggage helper
389
+ * ```typescript
390
+ * const tenantBaggage = defineBaggageSchema<TenantBaggage>('tenant');
391
+ *
392
+ * export const handler = trace<TenantBaggage>((ctx) => async () => {
393
+ * return await tenantBaggage.with(ctx, { tenantId: 't1' }, async () => {
394
+ * // Baggage is available here and in child spans
395
+ * const tenant = tenantBaggage.get(ctx);
396
+ * });
397
+ * });
398
+ * ```
399
+ */
400
+ export function defineBaggageSchema<T extends Record<string, unknown>>(
401
+ namespace?: string,
402
+ ) {
403
+ return {
404
+ /**
405
+ * Get typed baggage from context
406
+ * @param ctx - Trace context
407
+ * @returns Partial baggage object or undefined if no baggage is set
408
+ */
409
+ get: (ctx: TraceContext<T>): Partial<T> | undefined => {
410
+ if (!ctx.getTypedBaggage) return undefined;
411
+ return ctx.getTypedBaggage<T>(namespace);
412
+ },
413
+
414
+ /**
415
+ * Set typed baggage in context
416
+ *
417
+ * Note: For proper scoping across async boundaries, use the `with` method instead
418
+ *
419
+ * @param ctx - Trace context
420
+ * @param value - Partial baggage object to set
421
+ */
422
+ set: (ctx: TraceContext<T>, value: Partial<T>): void => {
423
+ if (!ctx.setTypedBaggage) return;
424
+ ctx.setTypedBaggage<T>(namespace, value);
425
+ },
426
+
427
+ /**
428
+ * Run a function with typed baggage properly scoped
429
+ *
430
+ * This is the recommended way to set baggage as it ensures proper
431
+ * scoping across async boundaries.
432
+ *
433
+ * @param ctx - Trace context (can be omitted, will use active context)
434
+ * @param value - Partial baggage object to set
435
+ * @param fn - Function to execute with the baggage
436
+ */
437
+ with: <R>(
438
+ ctxOrValue: TraceContext<T> | Partial<T>,
439
+ valueOrFn: Partial<T> | (() => R | Promise<R>),
440
+ maybeFn?: () => R | Promise<R>,
441
+ ): R | Promise<R> => {
442
+ // Support both with(ctx, value, fn) and with(value, fn)
443
+ const value = maybeFn
444
+ ? (valueOrFn as Partial<T>)
445
+ : (ctxOrValue as Partial<T>);
446
+ const fn = maybeFn || (valueOrFn as () => R | Promise<R>);
447
+
448
+ // Serialize typed baggage to flat key-value pairs
449
+ const prefix = namespace ? `${namespace}.` : '';
450
+ const flatBaggage: Record<string, string> = {};
451
+ for (const [key, val] of Object.entries(value)) {
452
+ if (val !== undefined) {
453
+ flatBaggage[`${prefix}${key}`] = String(val);
454
+ }
455
+ }
456
+
457
+ // Use the existing withBaggage helper
458
+ const currentContext = context.active();
459
+ let baggage =
460
+ propagation.getBaggage(currentContext) ?? propagation.createBaggage();
461
+
462
+ for (const [key, val] of Object.entries(flatBaggage)) {
463
+ baggage = baggage.setEntry(key, { value: val });
464
+ }
465
+
466
+ const newContext = propagation.setBaggage(currentContext, baggage);
467
+ return context.with(newContext, fn);
468
+ },
469
+ };
470
+ }