@logbrew/sdk 0.1.14 → 0.1.16

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/core.cjs CHANGED
@@ -75,6 +75,7 @@ const PINO_SENSITIVE_CONTEXT_FIELDS = new Set([
75
75
  const TRACEPARENT_PATTERN = /^([0-9a-fA-F]{2})-([0-9a-fA-F]{32})-([0-9a-fA-F]{16})-([0-9a-fA-F]{2})$/u;
76
76
  const ZERO_TRACE_ID = "00000000000000000000000000000000";
77
77
  const ZERO_SPAN_ID = "0000000000000000";
78
+ const RFC3339_TIMESTAMP_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d{1,9})?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/u;
78
79
  const DEFAULT_MAX_QUEUE_SIZE = 1000;
79
80
  const DEFAULT_MAX_QUEUE_BYTES = 4 * 1024 * 1024;
80
81
  const DEFAULT_MAX_BATCH_EVENTS = 100;
@@ -84,6 +85,7 @@ const MAX_DELIVERY_INTERVAL_MS = 60 * 1000;
84
85
  const DEFAULT_DELIVERY_QUEUE_THRESHOLD = 50;
85
86
  const DELIVERY_HEALTH_SCHEMA_VERSION = 1;
86
87
  const EVENT_QUEUE_FACTORY = Symbol.for("@logbrew/sdk.eventQueueFactory");
88
+ const CONTEXT_PROVIDER = Symbol.for("@logbrew/sdk.contextProvider");
87
89
  const MAX_ERROR_CAUSES = 5;
88
90
  const BUILTIN_ERROR_NAMES = new Set([
89
91
  "AggregateError",
@@ -199,6 +201,7 @@ class LogBrewClient {
199
201
  sdkName,
200
202
  sdkVersion,
201
203
  context,
204
+ [CONTEXT_PROVIDER]: contextProvider,
202
205
  maxRetries = 2,
203
206
  eventFilter,
204
207
  maxQueueSize = DEFAULT_MAX_QUEUE_SIZE,
@@ -217,6 +220,9 @@ class LogBrewClient {
217
220
  requireNonEmpty("sdkName", sdkName);
218
221
  requireNonEmpty("sdkVersion", sdkVersion);
219
222
  const clientContext = validateTelemetryContext(context, "client telemetry context");
223
+ if (contextProvider !== undefined && typeof contextProvider !== "function") {
224
+ throw new SdkError("validation_error", "context provider must be a function");
225
+ }
220
226
  requireNonNegativeInteger("maxRetries", maxRetries);
221
227
  if (eventFilter !== undefined && typeof eventFilter !== "function") {
222
228
  throw new SdkError("validation_error", "eventFilter must be a function");
@@ -265,6 +271,7 @@ class LogBrewClient {
265
271
  maxQueueSize,
266
272
  onEventDropped,
267
273
  context: clientContext,
274
+ contextProvider,
268
275
  sdk: {
269
276
  name: sdkName,
270
277
  language: "javascript",
@@ -286,6 +293,7 @@ class LogBrewClient {
286
293
  maxQueueSize,
287
294
  onEventDropped,
288
295
  context,
296
+ contextProvider,
289
297
  eventStore,
290
298
  eventQueueFactory,
291
299
  transport,
@@ -304,6 +312,7 @@ class LogBrewClient {
304
312
  this.maxQueueSize = maxQueueSize;
305
313
  this.onEventDropped = onEventDropped;
306
314
  this.context = cloneTelemetryContext(context);
315
+ this.contextProvider = contextProvider;
307
316
  this.transport = transport;
308
317
  this.sdk = sdk;
309
318
  this.maxRetries = maxRetries;
@@ -623,7 +632,10 @@ class LogBrewClient {
623
632
  }
624
633
  requireNonEmpty("event id", id);
625
634
  requireTimestamp(timestamp);
626
- const context = mergeTelemetryContexts(this.context, attributes.context);
635
+ const context = mergeTelemetryContexts(
636
+ mergeTelemetryContexts(this.context, this.contextProvider?.()),
637
+ attributes.context
638
+ );
627
639
  const eventAttributes = context === undefined
628
640
  ? attributes
629
641
  : { ...attributes, context };
@@ -2199,17 +2211,25 @@ function requireTraceFlags(traceFlags) {
2199
2211
 
2200
2212
  function requireTimestamp(timestamp) {
2201
2213
  requireNonEmpty("timestamp", timestamp);
2202
- if (timestamp.endsWith("Z")) {
2203
- return;
2204
- }
2205
2214
  const timePortion = timestamp.split("T")[1];
2206
- if (timePortion && (timePortion.includes("+") || /.+-.+/.test(timePortion))) {
2207
- return;
2215
+ if (!timestamp.endsWith("Z")
2216
+ && !(timePortion && (timePortion.includes("+") || /.+-.+/.test(timePortion)))) {
2217
+ throw new SdkError(
2218
+ "validation_error",
2219
+ `timestamp must include a timezone offset: ${timestamp}`
2220
+ );
2221
+ }
2222
+ const match = timestamp.match(RFC3339_TIMESTAMP_PATTERN);
2223
+ const calendar = new Date(0);
2224
+ calendar.setUTCHours(0, 0, 0, 0);
2225
+ calendar.setUTCFullYear(Number(match?.[1]), Number(match?.[2]) - 1, Number(match?.[3]));
2226
+ if (!match
2227
+ || Number(match[1]) === 0
2228
+ || calendar.getUTCFullYear() !== Number(match[1])
2229
+ || calendar.getUTCMonth() !== Number(match[2]) - 1
2230
+ || calendar.getUTCDate() !== Number(match[3])) {
2231
+ throw new SdkError("validation_error", `invalid timestamp: ${timestamp}`);
2208
2232
  }
2209
- throw new SdkError(
2210
- "validation_error",
2211
- `timestamp must include a timezone offset: ${timestamp}`
2212
- );
2213
2233
  }
2214
2234
 
2215
2235
  function cloneMetadata(metadata) {
@@ -545,17 +545,18 @@ function buildIssueDiagnosticsHelpers({ SdkError, requireTimestamp, validateIssu
545
545
  }
546
546
 
547
547
  function boundedText(label, value, maxLength, { rejectLocationText = false } = {}) {
548
- if (typeof value !== "string" || value.trim() === "") {
548
+ const normalized = typeof value === "string" ? value.trim() : "";
549
+ if (normalized === "") {
549
550
  throw validationError(`${label} must be non-empty`);
550
551
  }
551
552
  if (
552
- Array.from(value).length > maxLength
553
- || hasControlCharacter(value)
554
- || (rejectLocationText && /[?#]/u.test(value))
553
+ Array.from(normalized).length > maxLength
554
+ || hasControlCharacter(normalized)
555
+ || (rejectLocationText && /[?#]/u.test(normalized))
555
556
  ) {
556
557
  throw validationError(`${label} is invalid or exceeds ${maxLength} characters`);
557
558
  }
558
- return value;
559
+ return normalized;
559
560
  }
560
561
 
561
562
  function requireObject(label, value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logbrew/sdk",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Public LogBrew JavaScript SDK for building, validating, and flushing event batches.",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",