@logbrew/sdk 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/trace-context.cjs CHANGED
@@ -1,217 +1,414 @@
1
+ const { SdkError } = require("./sdk-error.cjs");
2
+ const {
3
+ ZERO_SPAN_ID,
4
+ ZERO_TRACE_ID,
5
+ isRecord,
6
+ requireSpanId,
7
+ requireTraceFlags,
8
+ requireTraceId
9
+ } = require("./validation.cjs");
10
+
11
+ /**
12
+ * @import { BaggageEntry, TraceparentContext, TracestateEntry } from "./index.cjs"
13
+ * @typedef {{ traceparent: string, tracestate?: string, baggage?: string }} TraceContextHeaders
14
+ * @typedef {{ readonly key: string, readonly value: string, readonly properties?: readonly string[] }} ReadonlyBaggageEntry
15
+ */
16
+
1
17
  const MAX_TRACESTATE_ENTRIES = 32;
2
18
  const MAX_TRACESTATE_LENGTH = 512;
19
+ const MAX_TRACESTATE_VALUE_LENGTH = 256;
3
20
  const MAX_BAGGAGE_ENTRIES = 64;
4
21
  const MAX_BAGGAGE_LENGTH = 8192;
22
+ const DEFAULT_TRACE_FLAGS = "01";
23
+ const HEX_RADIX = 16;
24
+ const SAMPLED_FLAG_DIVISOR = 2;
25
+ const SAMPLED_FLAG_REMAINDER = 1;
26
+ const KEY_START = 0;
27
+ const SEPARATOR_WIDTH = 1;
28
+ const NO_PROPERTIES = 0;
29
+ const TRACEPARENT_PATTERN =
30
+ /^(?<version>[0-9a-fA-F]{2})-(?<traceId>[0-9a-fA-F]{32})-(?<parentSpanId>[0-9a-fA-F]{16})-(?<traceFlags>[0-9a-fA-F]{2})$/u;
5
31
  const TRACESTATE_SIMPLE_KEY_PATTERN = /^[a-z0-9][a-z0-9_\-*/]{0,255}$/u;
6
32
  const TRACESTATE_TENANT_KEY_PATTERN = /^[a-z0-9][a-z0-9_\-*/]{0,240}@[a-z][a-z0-9_\-*/]{0,13}$/u;
7
- const TRACESTATE_VALUE_PATTERN = /^[\x20-\x2B\x2D-\x3C\x3E-\x7E]*[\x21-\x2B\x2D-\x3C\x3E-\x7E]$/u;
33
+ const TRACESTATE_VALUE_PATTERN = /^[ -+--<>-~]*[!-+--<>-~]$/u;
8
34
  const BAGGAGE_KEY_PATTERN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/u;
9
35
  const BAGGAGE_PROPERTY_PATTERN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+(?:=[!#$%&'*+\-.^_`|~0-9A-Za-z]*)?$/u;
10
36
 
11
- function buildTraceContextHelpers({ SdkError, createTraceparent }) {
12
- function parseTracestate(tracestate) {
13
- if (typeof tracestate !== "string" || tracestate.trim() === "") {
14
- throw new SdkError("validation_error", "tracestate must be non-empty");
15
- }
16
- return normalizeTracestateEntries(
17
- tracestate.split(",")
18
- .map((entry) => entry.trim())
19
- .filter((entry) => entry !== "")
20
- .map((entry) => {
21
- const separator = entry.indexOf("=");
22
- if (separator <= 0) {
23
- throw new SdkError("validation_error", "tracestate entries must use key=value");
24
- }
25
- return {
26
- key: entry.slice(0, separator).trim(),
27
- value: entry.slice(separator + 1).trim()
28
- };
29
- })
30
- );
31
- }
32
-
33
- function createTracestate(entries) {
34
- return serializeTracestate(normalizeTracestateEntries(entries));
35
- }
36
-
37
- function parseBaggage(baggage) {
38
- if (typeof baggage !== "string" || baggage.trim() === "") {
39
- throw new SdkError("validation_error", "baggage must be non-empty");
40
- }
41
- return normalizeBaggageEntries(
42
- baggage.split(",")
43
- .map((entry) => entry.trim())
44
- .filter((entry) => entry !== "")
45
- .map((entry) => {
46
- const [pair, ...rawProperties] = entry.split(";");
47
- const separator = pair.indexOf("=");
48
- if (separator <= 0) {
49
- throw new SdkError("validation_error", "baggage entries must use key=value");
50
- }
51
- return {
52
- key: pair.slice(0, separator).trim(),
53
- value: decodeBaggageValue(pair.slice(separator + 1).trim()),
54
- properties: rawProperties.map((property) => property.trim()).filter((property) => property !== "")
55
- };
56
- })
57
- );
58
- }
59
-
60
- function createBaggage(entries) {
61
- return serializeBaggage(normalizeBaggageEntries(entries));
62
- }
63
-
64
- function createTraceContextHeaders(input) {
65
- if (!input || Array.isArray(input) || typeof input !== "object") {
66
- throw new SdkError("validation_error", "trace context input must be an object");
67
- }
68
- const headers = { traceparent: createTraceparent(input) };
69
- if (input.tracestate !== undefined) {
70
- const tracestate = typeof input.tracestate === "string"
71
- ? createTracestate(parseTracestate(input.tracestate))
72
- : createTracestate(input.tracestate);
73
- if (tracestate !== "") {
74
- headers.tracestate = tracestate;
75
- }
76
- }
77
- if (input.baggage !== undefined) {
78
- const baggage = typeof input.baggage === "string"
79
- ? createBaggage(parseBaggage(input.baggage))
80
- : createBaggage(input.baggage);
81
- if (baggage !== "") {
82
- headers.baggage = baggage;
83
- }
84
- }
85
- return headers;
37
+ /**
38
+ * @param {unknown} traceparent
39
+ * @returns {Readonly<Record<string, string>>}
40
+ */
41
+ function traceparentParts(traceparent) {
42
+ if (typeof traceparent !== "string" || traceparent.trim() === "") {
43
+ throw new SdkError("validation_error", "traceparent must be non-empty");
86
44
  }
45
+ const parts = TRACEPARENT_PATTERN.exec(traceparent.trim())?.groups;
46
+ if (parts === undefined) {
47
+ throw new SdkError("validation_error", "traceparent must use W3C version-traceId-parentSpanId-traceFlags format");
48
+ }
49
+ return parts;
50
+ }
87
51
 
88
- function normalizeTracestateEntries(entries) {
89
- if (!Array.isArray(entries)) {
90
- throw new SdkError("validation_error", "tracestate entries must be an array");
91
- }
92
- if (entries.length > MAX_TRACESTATE_ENTRIES) {
93
- throw new SdkError("validation_error", `tracestate must contain at most ${MAX_TRACESTATE_ENTRIES} entries`);
94
- }
95
- const seenKeys = new Set();
96
- const normalized = entries.map((entry) => {
97
- if (!entry || Array.isArray(entry) || typeof entry !== "object") {
98
- throw new SdkError("validation_error", "tracestate entry must be an object");
99
- }
100
- const key = validateTracestateKey(entry.key);
101
- if (seenKeys.has(key)) {
102
- throw new SdkError("validation_error", "tracestate keys must be unique");
103
- }
104
- seenKeys.add(key);
105
- return {
106
- key,
107
- value: validateTracestateValue(entry.value)
108
- };
109
- });
110
- const serialized = serializeTracestate(normalized);
111
- if (serialized.length > MAX_TRACESTATE_LENGTH) {
112
- throw new SdkError("validation_error", `tracestate must be at most ${MAX_TRACESTATE_LENGTH} characters`);
113
- }
114
- return normalized;
52
+ /**
53
+ * @param {string} version
54
+ * @param {string} traceId
55
+ * @param {string} parentSpanId
56
+ * @returns {void}
57
+ */
58
+ function rejectInvalidTraceparent(version, traceId, parentSpanId) {
59
+ if (version === "ff") {
60
+ throw new SdkError("validation_error", "traceparent version ff is not allowed");
115
61
  }
62
+ if (traceId === ZERO_TRACE_ID) {
63
+ throw new SdkError("validation_error", "traceparent traceId must not be all zeros");
64
+ }
65
+ if (parentSpanId === ZERO_SPAN_ID) {
66
+ throw new SdkError("validation_error", "traceparent parentSpanId must not be all zeros");
67
+ }
68
+ }
116
69
 
117
- function normalizeBaggageEntries(entries) {
118
- if (!Array.isArray(entries)) {
119
- throw new SdkError("validation_error", "baggage entries must be an array");
120
- }
121
- if (entries.length > MAX_BAGGAGE_ENTRIES) {
122
- throw new SdkError("validation_error", `baggage must contain at most ${MAX_BAGGAGE_ENTRIES} entries`);
123
- }
124
- const normalized = entries.map((entry) => {
125
- if (!entry || Array.isArray(entry) || typeof entry !== "object") {
126
- throw new SdkError("validation_error", "baggage entry must be an object");
127
- }
128
- return {
129
- key: validateBaggageKey(entry.key),
130
- value: validateBaggageValue(entry.value),
131
- ...normalizeBaggageProperties(entry.properties)
132
- };
133
- });
134
- const serialized = serializeBaggage(normalized);
135
- if (serialized.length > MAX_BAGGAGE_LENGTH) {
136
- throw new SdkError("validation_error", `baggage must be at most ${MAX_BAGGAGE_LENGTH} characters`);
137
- }
138
- return normalized;
70
+ /**
71
+ * @param {unknown} traceparent
72
+ * @returns {TraceparentContext}
73
+ */
74
+ function parseTraceparent(traceparent) {
75
+ const parts = traceparentParts(traceparent);
76
+ const version = String(parts["version"]).toLowerCase();
77
+ const traceId = String(parts["traceId"]).toLowerCase();
78
+ const parentSpanId = String(parts["parentSpanId"]).toLowerCase();
79
+ const traceFlags = String(parts["traceFlags"]).toLowerCase();
80
+ rejectInvalidTraceparent(version, traceId, parentSpanId);
81
+ const sampled = Number.parseInt(traceFlags, HEX_RADIX) % SAMPLED_FLAG_DIVISOR === SAMPLED_FLAG_REMAINDER;
82
+ return {
83
+ version,
84
+
85
+ traceId,
86
+
87
+ parentSpanId,
88
+ traceFlags,
89
+
90
+ sampled
91
+ };
92
+ }
93
+
94
+ /**
95
+ * @param {Readonly<{ traceId?: unknown, spanId?: unknown, traceFlags?: unknown }>} input
96
+ * @returns {string}
97
+ */
98
+ function createTraceparent({ traceId, spanId, traceFlags = DEFAULT_TRACE_FLAGS }) {
99
+ const validTraceId = requireTraceId(traceId);
100
+ const validSpanId = requireSpanId("spanId", spanId);
101
+ const validTraceFlags = requireTraceFlags(traceFlags);
102
+ return `00-${validTraceId.toLowerCase()}-${validSpanId.toLowerCase()}-${validTraceFlags.toLowerCase()}`;
103
+ }
104
+
105
+ /**
106
+ * @param {Readonly<{ traceId?: unknown, spanId?: unknown, traceFlags?: unknown }>} input
107
+ * @returns {{ traceparent: string }}
108
+ */
109
+ function createTraceparentHeaders(input) {
110
+ return { traceparent: createTraceparent(input) };
111
+ }
112
+
113
+ /**
114
+ * @param {readonly Readonly<TracestateEntry>[]} entries
115
+ * @returns {string}
116
+ */
117
+ function serializeTracestate(entries) {
118
+ return entries.map((entry) => `${entry.key}=${entry.value}`).join(",");
119
+ }
120
+
121
+ /**
122
+ * @param {readonly ReadonlyBaggageEntry[]} entries
123
+ * @returns {string}
124
+ */
125
+ function serializeBaggage(entries) {
126
+ return entries
127
+ .map((entry) => {
128
+ const properties = entry.properties === undefined ? "" : `;${entry.properties.join(";")}`;
129
+ return `${entry.key}=${encodeURIComponent(entry.value)}${properties}`;
130
+ })
131
+ .join(",");
132
+ }
133
+
134
+ /**
135
+ * @param {unknown} key
136
+ * @returns {string}
137
+ */
138
+ function validateTracestateKey(key) {
139
+ if (typeof key !== "string" || key.trim() === "") {
140
+ throw new SdkError("validation_error", "tracestate key must be non-empty");
139
141
  }
142
+ const normalized = key.trim();
143
+ if (!TRACESTATE_SIMPLE_KEY_PATTERN.test(normalized) && !TRACESTATE_TENANT_KEY_PATTERN.test(normalized)) {
144
+ throw new SdkError("validation_error", "tracestate key must be lowercase W3C tracestate key");
145
+ }
146
+ return normalized;
147
+ }
140
148
 
141
- function validateTracestateKey(key) {
142
- if (typeof key !== "string" || key.trim() === "") {
143
- throw new SdkError("validation_error", "tracestate key must be non-empty");
144
- }
145
- const normalized = key.trim();
146
- if (!TRACESTATE_SIMPLE_KEY_PATTERN.test(normalized) && !TRACESTATE_TENANT_KEY_PATTERN.test(normalized)) {
147
- throw new SdkError("validation_error", "tracestate key must be lowercase W3C tracestate key");
148
- }
149
- return normalized;
149
+ /**
150
+ * @param {unknown} value
151
+ * @returns {string}
152
+ */
153
+ function validateTracestateValue(value) {
154
+ if (
155
+ typeof value !== "string"
156
+ || value === ""
157
+ || value.length > MAX_TRACESTATE_VALUE_LENGTH
158
+ || !TRACESTATE_VALUE_PATTERN.test(value)
159
+ ) {
160
+ throw new SdkError("validation_error", "tracestate value must be printable ASCII without comma or equals");
150
161
  }
162
+ return value;
163
+ }
151
164
 
152
- function validateTracestateValue(value) {
153
- if (typeof value !== "string" || value === "" || value.length > 256 || !TRACESTATE_VALUE_PATTERN.test(value)) {
154
- throw new SdkError("validation_error", "tracestate value must be printable ASCII without comma or equals");
155
- }
156
- return value;
165
+ /**
166
+ * @param {unknown} key
167
+ * @returns {string}
168
+ */
169
+ function validateBaggageKey(key) {
170
+ if (typeof key !== "string" || !BAGGAGE_KEY_PATTERN.test(key)) {
171
+ throw new SdkError("validation_error", "baggage key must use RFC header-name characters");
157
172
  }
173
+ return key;
174
+ }
158
175
 
159
- function validateBaggageKey(key) {
160
- if (typeof key !== "string" || !BAGGAGE_KEY_PATTERN.test(key)) {
161
- throw new SdkError("validation_error", "baggage key must use RFC header-name characters");
162
- }
163
- return key;
176
+ /**
177
+ * @param {unknown} value
178
+ * @returns {string}
179
+ */
180
+ function validateBaggageValue(value) {
181
+ if (typeof value !== "string") {
182
+ throw new SdkError("validation_error", "baggage value must be a string");
164
183
  }
184
+ return value;
185
+ }
165
186
 
166
- function validateBaggageValue(value) {
167
- if (typeof value !== "string") {
168
- throw new SdkError("validation_error", "baggage value must be a string");
187
+ /**
188
+ * @param {unknown} properties
189
+ * @returns {string[] | undefined}
190
+ */
191
+ function normalizeBaggageProperties(properties) {
192
+ if (properties === undefined) {
193
+ return undefined;
194
+ }
195
+ if (!Array.isArray(properties)) {
196
+ throw new SdkError("validation_error", "baggage properties must be an array");
197
+ }
198
+ /** @type {readonly unknown[]} */
199
+ const candidates = properties;
200
+ const safeProperties = candidates.map((property) => {
201
+ if (typeof property !== "string" || !BAGGAGE_PROPERTY_PATTERN.test(property)) {
202
+ throw new SdkError("validation_error", "baggage property must use RFC header-name characters");
169
203
  }
170
- return value;
204
+ return property;
205
+ });
206
+ return safeProperties.length > NO_PROPERTIES ? safeProperties : undefined;
207
+ }
208
+
209
+ /**
210
+ * @param {string} value
211
+ * @returns {string}
212
+ */
213
+ function decodeBaggageValue(value) {
214
+ try {
215
+ return decodeURIComponent(value);
216
+ } catch {
217
+ throw new SdkError("validation_error", "baggage value must use valid percent encoding");
218
+ }
219
+ }
220
+
221
+ /**
222
+ * @param {unknown} entries
223
+ * @param {string} label
224
+ * @param {number} maxEntries
225
+ * @returns {readonly unknown[]}
226
+ */
227
+ function requireEntryList(entries, label, maxEntries) {
228
+ if (!Array.isArray(entries)) {
229
+ throw new SdkError("validation_error", `${label} entries must be an array`);
230
+ }
231
+ if (entries.length > maxEntries) {
232
+ throw new SdkError("validation_error", `${label} must contain at most ${maxEntries} entries`);
171
233
  }
234
+ return entries;
235
+ }
172
236
 
173
- function normalizeBaggageProperties(properties) {
174
- if (properties === undefined) {
175
- return {};
237
+ /**
238
+ * @param {unknown} entries
239
+ * @returns {TracestateEntry[]}
240
+ */
241
+ function normalizeTracestateEntries(entries) {
242
+ const list = requireEntryList(entries, "tracestate", MAX_TRACESTATE_ENTRIES);
243
+ const seenKeys = new Set();
244
+ const normalized = list.map((entry) => {
245
+ if (!isRecord(entry)) {
246
+ throw new SdkError("validation_error", "tracestate entry must be an object");
176
247
  }
177
- if (!Array.isArray(properties)) {
178
- throw new SdkError("validation_error", "baggage properties must be an array");
248
+ const key = validateTracestateKey(entry["key"]);
249
+ if (seenKeys.has(key)) {
250
+ throw new SdkError("validation_error", "tracestate keys must be unique");
179
251
  }
180
- const safeProperties = properties.map((property) => {
181
- if (typeof property !== "string" || !BAGGAGE_PROPERTY_PATTERN.test(property)) {
182
- throw new SdkError("validation_error", "baggage property must use RFC header-name characters");
183
- }
184
- return property;
185
- });
186
- return safeProperties.length > 0 ? { properties: safeProperties } : {};
252
+ seenKeys.add(key);
253
+ return { key, value: validateTracestateValue(entry["value"]) };
254
+ });
255
+ if (serializeTracestate(normalized).length > MAX_TRACESTATE_LENGTH) {
256
+ throw new SdkError("validation_error", `tracestate must be at most ${MAX_TRACESTATE_LENGTH} characters`);
187
257
  }
258
+ return normalized;
259
+ }
188
260
 
189
- function decodeBaggageValue(value) {
190
- try {
191
- return decodeURIComponent(value);
192
- } catch {
193
- throw new SdkError("validation_error", "baggage value must use valid percent encoding");
194
- }
261
+ /**
262
+ * @param {unknown} entry
263
+ * @returns {BaggageEntry}
264
+ */
265
+ function normalizeBaggageEntry(entry) {
266
+ if (!isRecord(entry)) {
267
+ throw new SdkError("validation_error", "baggage entry must be an object");
195
268
  }
269
+ const key = validateBaggageKey(entry["key"]);
270
+ const value = validateBaggageValue(entry["value"]);
271
+ const properties = normalizeBaggageProperties(entry["properties"]);
272
+ return { key, value, ...(properties === undefined ? {} : { properties }) };
273
+ }
274
+
275
+ /**
276
+ * @param {unknown} entries
277
+ * @returns {BaggageEntry[]}
278
+ */
279
+ function normalizeBaggageEntries(entries) {
280
+ const list = requireEntryList(entries, "baggage", MAX_BAGGAGE_ENTRIES);
281
+ const normalized = list.map((entry) => normalizeBaggageEntry(entry));
282
+ if (serializeBaggage(normalized).length > MAX_BAGGAGE_LENGTH) {
283
+ throw new SdkError("validation_error", `baggage must be at most ${MAX_BAGGAGE_LENGTH} characters`);
284
+ }
285
+ return normalized;
286
+ }
287
+
288
+ /**
289
+ * @param {string} header
290
+ * @returns {string[]}
291
+ */
292
+ function headerEntries(header) {
293
+ return header
294
+ .split(",")
295
+ .map((entry) => entry.trim())
296
+ .filter((entry) => entry !== "");
297
+ }
196
298
 
299
+ /**
300
+ * @param {unknown} tracestate
301
+ * @returns {TracestateEntry[]}
302
+ */
303
+ function parseTracestate(tracestate) {
304
+ if (typeof tracestate !== "string" || tracestate.trim() === "") {
305
+ throw new SdkError("validation_error", "tracestate must be non-empty");
306
+ }
307
+ return normalizeTracestateEntries(
308
+ headerEntries(tracestate).map((entry) => {
309
+ const separator = entry.indexOf("=");
310
+ if (separator <= KEY_START) {
311
+ throw new SdkError("validation_error", "tracestate entries must use key=value");
312
+ }
313
+ return {
314
+ key: entry.slice(KEY_START, separator).trim(),
315
+ value: entry.slice(separator + SEPARATOR_WIDTH).trim()
316
+ };
317
+ })
318
+ );
319
+ }
320
+
321
+ /**
322
+ * @param {string} entry
323
+ * @returns {ReadonlyBaggageEntry}
324
+ */
325
+ function parseBaggageEntry(entry) {
326
+ const [pair = "", ...rawProperties] = entry.split(";");
327
+ const separator = pair.indexOf("=");
328
+ if (separator <= KEY_START) {
329
+ throw new SdkError("validation_error", "baggage entries must use key=value");
330
+ }
331
+ const key = pair.slice(KEY_START, separator).trim();
332
+ const value = decodeBaggageValue(pair.slice(separator + SEPARATOR_WIDTH).trim());
333
+ const properties = rawProperties.map((property) => property.trim()).filter((property) => property !== "");
197
334
  return {
198
- createBaggage,
199
- createTraceContextHeaders,
200
- createTracestate,
201
- parseBaggage,
202
- parseTracestate
335
+ key,
336
+ value,
337
+
338
+ properties
203
339
  };
204
340
  }
205
341
 
206
- function serializeTracestate(entries) {
207
- return entries.map((entry) => `${entry.key}=${entry.value}`).join(",");
342
+ /**
343
+ * @param {unknown} baggage
344
+ * @returns {BaggageEntry[]}
345
+ */
346
+ function parseBaggage(baggage) {
347
+ if (typeof baggage !== "string" || baggage.trim() === "") {
348
+ throw new SdkError("validation_error", "baggage must be non-empty");
349
+ }
350
+ return normalizeBaggageEntries(headerEntries(baggage).map((entry) => parseBaggageEntry(entry)));
208
351
  }
209
352
 
210
- function serializeBaggage(entries) {
211
- return entries.map((entry) => {
212
- const properties = entry.properties ? `;${entry.properties.join(";")}` : "";
213
- return `${entry.key}=${encodeURIComponent(entry.value)}${properties}`;
214
- }).join(",");
353
+ /**
354
+ * @param {unknown} entries
355
+ * @returns {string}
356
+ */
357
+ function createTracestate(entries) {
358
+ return serializeTracestate(normalizeTracestateEntries(entries));
359
+ }
360
+
361
+ /**
362
+ * @param {unknown} entries
363
+ * @returns {string}
364
+ */
365
+ function createBaggage(entries) {
366
+ return serializeBaggage(normalizeBaggageEntries(entries));
367
+ }
368
+
369
+ /**
370
+ * @param {unknown} tracestate
371
+ * @returns {{ tracestate?: string }}
372
+ */
373
+ function tracestateHeader(tracestate) {
374
+ if (tracestate === undefined) {
375
+ return {};
376
+ }
377
+ const value = typeof tracestate === "string" ? createTracestate(parseTracestate(tracestate)) : createTracestate(tracestate);
378
+ return value === "" ? {} : { tracestate: value };
379
+ }
380
+
381
+ /**
382
+ * @param {unknown} baggage
383
+ * @returns {{ baggage?: string }}
384
+ */
385
+ function baggageHeader(baggage) {
386
+ if (baggage === undefined) {
387
+ return {};
388
+ }
389
+ const value = typeof baggage === "string" ? createBaggage(parseBaggage(baggage)) : createBaggage(baggage);
390
+ return value === "" ? {} : { baggage: value };
391
+ }
392
+
393
+ /**
394
+ * @param {unknown} input
395
+ * @returns {TraceContextHeaders}
396
+ */
397
+ function createTraceContextHeaders(input) {
398
+ if (!isRecord(input)) {
399
+ throw new SdkError("validation_error", "trace context input must be an object");
400
+ }
401
+ const traceparent = createTraceparent(input);
402
+ return { traceparent, ...tracestateHeader(input["tracestate"]), ...baggageHeader(input["baggage"]) };
215
403
  }
216
404
 
217
- module.exports = { buildTraceContextHelpers };
405
+ module.exports = {
406
+ createBaggage,
407
+ createTraceContextHeaders,
408
+ createTraceparent,
409
+ createTraceparentHeaders,
410
+ createTracestate,
411
+ parseBaggage,
412
+ parseTraceparent,
413
+ parseTracestate
414
+ };
@@ -0,0 +1,23 @@
1
+ class TransportError extends Error {
2
+ /**
3
+ * @param {string} code
4
+ * @param {string} message
5
+ * @param {boolean} [retryable]
6
+ */
7
+ constructor(code, message, retryable = false) {
8
+ super(message);
9
+ this.name = "TransportError";
10
+ this.code = code;
11
+ this.retryable = retryable;
12
+ }
13
+
14
+ /**
15
+ * @param {string} message
16
+ * @returns {TransportError}
17
+ */
18
+ static network(message) {
19
+ return new TransportError("network_failure", message, true);
20
+ }
21
+ }
22
+
23
+ module.exports = { TransportError };