unnbound-logger-sdk 3.0.35 → 3.0.37

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/dist/axios.d.ts CHANGED
@@ -10,8 +10,14 @@ interface HttpClientOptions extends HttpOptions<GetPayload> {
10
10
  redact?: RedactOptions | boolean;
11
11
  }
12
12
  /**
13
- * Wraps an axios instance to add tracing and span tracking
14
- * @param axios - The axios instance to wrap
13
+ * Wraps an axios instance to add tracing and span tracking.
14
+ *
15
+ * Idempotent: wrapping an already-wrapped instance returns it unchanged (the second
16
+ * call's options are ignored). Wrapping mutates the instance in place, so without the
17
+ * guard each call nests another span layer around the previous wrapper — long-lived
18
+ * processes that construct clients repeatedly accumulate layers until a single request
19
+ * overflows the stack (T-3235).
20
+ * @param client - The axios instance to wrap
15
21
  * @param options - Configuration options for HTTP tracing
16
22
  * @returns The wrapped axios instance with span tracking
17
23
  */
package/dist/axios.js CHANGED
@@ -37,9 +37,18 @@ const buildOutgoingHttpPayload = (config, res, redact) => ({
37
37
  });
38
38
  const getNoopPayload = () => ({});
39
39
  const onNoopRequest = (config, callback) => callback(config);
40
+ // Global-registry symbol so the guard holds even when several copies of this SDK
41
+ // coexist in one process (e.g. a workflow's own copy plus one nested under another SDK).
42
+ const tracedMarker = Symbol.for('unnbound-logger-sdk.traceAxios.traced');
40
43
  /**
41
- * Wraps an axios instance to add tracing and span tracking
42
- * @param axios - The axios instance to wrap
44
+ * Wraps an axios instance to add tracing and span tracking.
45
+ *
46
+ * Idempotent: wrapping an already-wrapped instance returns it unchanged (the second
47
+ * call's options are ignored). Wrapping mutates the instance in place, so without the
48
+ * guard each call nests another span layer around the previous wrapper — long-lived
49
+ * processes that construct clients repeatedly accumulate layers until a single request
50
+ * overflows the stack (T-3235).
51
+ * @param client - The axios instance to wrap
43
52
  * @param options - Configuration options for HTTP tracing
44
53
  * @returns The wrapped axios instance with span tracking
45
54
  */
@@ -49,6 +58,8 @@ const traceAxios = (client, { ignoreTraceRoutes = types_1.defaultIgnoreTraceRout
49
58
  getPayload: getNoopPayload,
50
59
  onRequest: onNoopRequest,
51
60
  }) => {
61
+ if (tracedMarker in client)
62
+ return client;
52
63
  const redact = typeof redactOptions === 'boolean' ? { response: redactOptions } : redactOptions;
53
64
  const createSpanWrappedRequest = (originalMethod, method) => {
54
65
  const { headers: defaultHeaders, ...partialDefaultConfig } = client.defaults;
@@ -91,6 +102,7 @@ const traceAxios = (client, { ignoreTraceRoutes = types_1.defaultIgnoreTraceRout
91
102
  const func = createSpanWrappedRequest(request, method);
92
103
  client[method] = (url, config) => func({ ...config, method, url });
93
104
  });
105
+ Object.defineProperty(client, tracedMarker, { value: true });
94
106
  return client;
95
107
  };
96
108
  exports.traceAxios = traceAxios;
package/dist/index.d.ts CHANGED
@@ -4,16 +4,16 @@
4
4
  * A structured logging library built on Pino with TypeScript support.
5
5
  * Provides consistent, well-typed logging across different operational contexts.
6
6
  */
7
- export type { LogLevel, LogType, HttpMethod, Maybe, EventSource, Log, HttpPayload, SftpPayload, EdiPayload, EdiOperation, EdiFormat, EdiX12Payload, EdiX12Operation, } from './types';
8
- export { defaultTraceHeaderKey, defaultMessageHeaderKey } from './types';
7
+ export { type OnRequest, traceAxios } from './axios';
8
+ export type { EmitMetricOptions, MetricDefinition, MetricUnit } from './emf';
9
+ export { emitMetric, emitMetrics } from './emf';
10
+ export { decode, encode } from './encode';
9
11
  export type { ILogger, UnnboundLogger } from './logger';
10
12
  export { logger } from './logger';
11
- export { encode, decode } from './encode';
12
- export { withTrace, getTraceId } from './trace';
13
- export { startSpan } from './span';
14
- export { traceAxios, type OnRequest } from './axios';
15
13
  export { traceMiddleware } from './middleware';
16
- export { storage, withStorage } from './storage';
14
+ export { startSpan } from './span';
17
15
  export type { UnnboundContext } from './storage';
18
- export type { MetricUnit, MetricDefinition, EmitMetricOptions } from './emf';
19
- export { emitMetric, emitMetrics } from './emf';
16
+ export { storage, withStorage } from './storage';
17
+ export { getTraceId, withTrace } from './trace';
18
+ export type { EdiFormat, EdiOperation, EdiPayload, EdiX12Operation, EdiX12Payload, EventSource, HttpMethod, HttpPayload, Log, LogLevel, LogType, Maybe, SftpPayload, } from './types';
19
+ export { defaultMessageHeaderKey, defaultTraceHeaderKey } from './types';
package/dist/index.js CHANGED
@@ -1,26 +1,32 @@
1
1
  "use strict";
2
+ /**
3
+ * unnbound-logger
4
+ *
5
+ * A structured logging library built on Pino with TypeScript support.
6
+ * Provides consistent, well-typed logging across different operational contexts.
7
+ */
2
8
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.emitMetrics = exports.emitMetric = exports.withStorage = exports.storage = exports.traceMiddleware = exports.traceAxios = exports.startSpan = exports.getTraceId = exports.withTrace = exports.decode = exports.encode = exports.logger = exports.defaultMessageHeaderKey = exports.defaultTraceHeaderKey = void 0;
4
- var types_1 = require("./types");
5
- Object.defineProperty(exports, "defaultTraceHeaderKey", { enumerable: true, get: function () { return types_1.defaultTraceHeaderKey; } });
6
- Object.defineProperty(exports, "defaultMessageHeaderKey", { enumerable: true, get: function () { return types_1.defaultMessageHeaderKey; } });
7
- var logger_1 = require("./logger");
8
- Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
9
- var encode_1 = require("./encode");
10
- Object.defineProperty(exports, "encode", { enumerable: true, get: function () { return encode_1.encode; } });
11
- Object.defineProperty(exports, "decode", { enumerable: true, get: function () { return encode_1.decode; } });
12
- var trace_1 = require("./trace");
13
- Object.defineProperty(exports, "withTrace", { enumerable: true, get: function () { return trace_1.withTrace; } });
14
- Object.defineProperty(exports, "getTraceId", { enumerable: true, get: function () { return trace_1.getTraceId; } });
15
- var span_1 = require("./span");
16
- Object.defineProperty(exports, "startSpan", { enumerable: true, get: function () { return span_1.startSpan; } });
9
+ exports.defaultTraceHeaderKey = exports.defaultMessageHeaderKey = exports.withTrace = exports.getTraceId = exports.withStorage = exports.storage = exports.startSpan = exports.traceMiddleware = exports.logger = exports.encode = exports.decode = exports.emitMetrics = exports.emitMetric = exports.traceAxios = void 0;
17
10
  var axios_1 = require("./axios");
18
11
  Object.defineProperty(exports, "traceAxios", { enumerable: true, get: function () { return axios_1.traceAxios; } });
12
+ var emf_1 = require("./emf");
13
+ Object.defineProperty(exports, "emitMetric", { enumerable: true, get: function () { return emf_1.emitMetric; } });
14
+ Object.defineProperty(exports, "emitMetrics", { enumerable: true, get: function () { return emf_1.emitMetrics; } });
15
+ var encode_1 = require("./encode");
16
+ Object.defineProperty(exports, "decode", { enumerable: true, get: function () { return encode_1.decode; } });
17
+ Object.defineProperty(exports, "encode", { enumerable: true, get: function () { return encode_1.encode; } });
18
+ var logger_1 = require("./logger");
19
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
19
20
  var middleware_1 = require("./middleware");
20
21
  Object.defineProperty(exports, "traceMiddleware", { enumerable: true, get: function () { return middleware_1.traceMiddleware; } });
22
+ var span_1 = require("./span");
23
+ Object.defineProperty(exports, "startSpan", { enumerable: true, get: function () { return span_1.startSpan; } });
21
24
  var storage_1 = require("./storage");
22
25
  Object.defineProperty(exports, "storage", { enumerable: true, get: function () { return storage_1.storage; } });
23
26
  Object.defineProperty(exports, "withStorage", { enumerable: true, get: function () { return storage_1.withStorage; } });
24
- var emf_1 = require("./emf");
25
- Object.defineProperty(exports, "emitMetric", { enumerable: true, get: function () { return emf_1.emitMetric; } });
26
- Object.defineProperty(exports, "emitMetrics", { enumerable: true, get: function () { return emf_1.emitMetrics; } });
27
+ var trace_1 = require("./trace");
28
+ Object.defineProperty(exports, "getTraceId", { enumerable: true, get: function () { return trace_1.getTraceId; } });
29
+ Object.defineProperty(exports, "withTrace", { enumerable: true, get: function () { return trace_1.withTrace; } });
30
+ var types_1 = require("./types");
31
+ Object.defineProperty(exports, "defaultMessageHeaderKey", { enumerable: true, get: function () { return types_1.defaultMessageHeaderKey; } });
32
+ Object.defineProperty(exports, "defaultTraceHeaderKey", { enumerable: true, get: function () { return types_1.defaultTraceHeaderKey; } });
package/dist/internal.js CHANGED
@@ -2,8 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.internal = exports.hidden = void 0;
4
4
  const o = { _internal: true };
5
- // Internal logs should be hidden in sandbox
6
- // TODO: Find a better way to detect sandbox
5
+ // Sandbox-internal logs are hidden from customer-visible streams.
7
6
  if (process.env.UNNBOUND_IDLE_TIMEOUT)
8
7
  o._hide = true;
9
8
  const hidden = (data) => '_hide' in data && data._hide;
package/dist/logger.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import pino from 'pino';
2
+ import type { DestinationStream } from 'pino';
2
3
  export interface ILogger {
3
- trace(object: {}, message: string): void;
4
+ trace(object: object, message: string): void;
4
5
  trace(message: string): void;
5
- debug(object: {}, message: string): void;
6
+ debug(object: object, message: string): void;
6
7
  debug(message: string): void;
7
- info(object: {}, message: string): void;
8
+ info(object: object, message: string): void;
8
9
  info(message: string): void;
9
- warn(object: {}, message: string): void;
10
+ warn(object: object, message: string): void;
10
11
  warn(message: string): void;
11
12
  error<O extends {
12
13
  err: unknown;
@@ -14,4 +15,5 @@ export interface ILogger {
14
15
  }
15
16
  export interface UnnboundLogger extends ILogger, Omit<pino.Logger, keyof ILogger> {
16
17
  }
18
+ export declare const createLogger: (destination?: DestinationStream) => UnnboundLogger;
17
19
  export declare const logger: UnnboundLogger;
package/dist/logger.js CHANGED
@@ -3,15 +3,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.logger = void 0;
6
+ exports.logger = exports.createLogger = void 0;
7
7
  const pino_1 = __importDefault(require("pino"));
8
8
  const uuid_1 = require("uuid");
9
9
  const encode_1 = require("./encode");
10
10
  const internal_1 = require("./internal");
11
11
  const storage_1 = require("./storage");
12
12
  const levels = new Set(['debug', 'info', 'warn', 'error']);
13
+ const workflowEnvironment = process.env.WORKFLOW_ENV ?? process.env.UNNBOUND_ENVIRONMENT ?? process.env.ENVIRONMENT;
13
14
  const formatLevel = (level) => ({ level });
14
- // TODO: Check if there is a better way to encode the log object.
15
15
  const formatLog = (log, visited = new WeakSet()) => {
16
16
  // Prevent infinite loops from circular references
17
17
  if (visited.has(log))
@@ -22,6 +22,12 @@ const formatLog = (log, visited = new WeakSet()) => {
22
22
  return log;
23
23
  // We don't use Object.entries() for performance reasons
24
24
  for (const key in log) {
25
+ if (!Object.hasOwn(log, key))
26
+ continue;
27
+ // JSON.parse produces own '__proto__'/'constructor' keys; assigning to them
28
+ // routes through Object.prototype setters and pollutes the prototype chain.
29
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype')
30
+ continue;
25
31
  const value = log[key];
26
32
  // We don't want to encode undefined values.
27
33
  if (value === undefined)
@@ -39,16 +45,19 @@ const formatLog = (log, visited = new WeakSet()) => {
39
45
  ? formatLog(item, visited)
40
46
  : item);
41
47
  }
42
- else if (typeof value === 'object') {
48
+ else if (value !== null && typeof value === 'object') {
43
49
  log[key] = formatLog(value, visited);
44
50
  }
45
51
  }
46
52
  return log;
47
53
  };
48
- exports.logger = (0, pino_1.default)({
54
+ const loggerOptions = {
49
55
  level: process.env.LOG_LEVEL ?? 'debug',
50
56
  base: {
51
- environment: process.env.ENVIRONMENT,
57
+ // The Pulumi stack name is internal platform vocabulary — never stamp it into
58
+ // the customer-visible envelope (T-3235). Platform stack attribution flows via
59
+ // OTel resource attributes into the ClickHouse `stack` column instead (T-2236).
60
+ environment: workflowEnvironment,
52
61
  workflowId: process.env.UNNBOUND_WORKFLOW_ID,
53
62
  serviceId: process.env.UNNBOUND_SERVICE_ID,
54
63
  deploymentId: process.env.UNNBOUND_DEPLOYMENT_ID,
@@ -69,17 +78,18 @@ exports.logger = (0, pino_1.default)({
69
78
  hooks: {
70
79
  logMethod(args, method) {
71
80
  const firstArg = args[0];
81
+ let activeMethod = method;
72
82
  if (!!firstArg && typeof firstArg === 'object') {
73
83
  // If the log entry is considered hidden, don't log it
74
84
  if ((0, internal_1.hidden)(firstArg))
75
85
  return;
76
86
  // Dynamic log level by allowing overwriting the log level
77
87
  if ('level' in firstArg && typeof firstArg.level === 'string' && levels.has(firstArg.level)) {
78
- method = this[firstArg.level];
88
+ activeMethod = this[firstArg.level];
79
89
  firstArg.level = undefined;
80
90
  }
81
91
  }
82
- method.apply(this, args);
92
+ activeMethod.apply(this, args);
83
93
  },
84
94
  },
85
95
  redact: {
@@ -92,7 +102,10 @@ exports.logger = (0, pino_1.default)({
92
102
  ],
93
103
  remove: true,
94
104
  },
95
- });
105
+ };
106
+ const createLogger = (destination) => destination ? (0, pino_1.default)(loggerOptions, destination) : (0, pino_1.default)(loggerOptions);
107
+ exports.createLogger = createLogger;
108
+ exports.logger = (0, exports.createLogger)();
96
109
  process.on('uncaughtException', (err, origin) => {
97
110
  try {
98
111
  exports.logger.error({ err, origin }, 'Uncaught exception.');
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.traceMiddleware = void 0;
4
4
  const span_1 = require("./span");
5
- const types_1 = require("./types");
6
5
  const trace_1 = require("./trace");
6
+ const types_1 = require("./types");
7
7
  const utils_1 = require("./utils");
8
8
  const extractQueryParams = (url) => {
9
9
  const object = new URL(url);
package/package.json CHANGED
@@ -1,24 +1,11 @@
1
1
  {
2
2
  "name": "unnbound-logger-sdk",
3
3
  "description": "A structured logging library with TypeScript support using Pino. Provides consistent, well-typed logging with automatic logId, workflowId, traceId, and deploymentId tracking across operational contexts.",
4
- "version": "3.0.35",
4
+ "version": "3.0.37",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "scripts": {
8
- "build": "bun x tsc",
9
- "test": "echo 'No tests'",
10
- "typecheck": "tsc -noEmit",
11
- "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
12
- "lint:fix": "bun run lint --fix",
13
- "format": "biome format --write .",
14
- "format:check": "biome format .",
15
- "prepublishOnly": "bun run build",
16
- "start:example": "bun --watch examples/node-express.ts",
17
- "version:bump": "npm version patch"
18
- },
19
7
  "keywords": [
20
8
  "logging",
21
- "typescript",
22
9
  "structured-logging",
23
10
  "pino",
24
11
  "tracing",
@@ -38,19 +25,19 @@
38
25
  "url": "https://github.com/unnbounddev/unnbound-sdks/issues"
39
26
  },
40
27
  "dependencies": {
41
- "axios": "^1.12.2",
28
+ "axios": "1.16.0",
42
29
  "express": "^4.0.0 || ^5.0.0",
43
- "pino": "^8.17.2",
44
- "uuid": "^11.1.0"
30
+ "pino": "^10.3.1",
31
+ "uuid": "^11.1.1"
45
32
  },
46
33
  "devDependencies": {
47
34
  "@types/express": "^4.17.21",
48
- "@types/node": "^22",
35
+ "@types/node": "^24.12.2",
49
36
  "@types/uuid": "^9.0.8",
50
- "typescript": "^5.9.3"
37
+ "vitest": "^4.0.15"
51
38
  },
52
39
  "peerDependencies": {
53
- "axios": "^1.12.2",
40
+ "axios": "^1.15.1",
54
41
  "express": "^4.0.0 || ^5.0.0"
55
42
  },
56
43
  "peerDependenciesMeta": {
@@ -69,5 +56,14 @@
69
56
  "engines": {
70
57
  "node": ">=22"
71
58
  },
72
- "sideEffects": false
73
- }
59
+ "sideEffects": false,
60
+ "scripts": {
61
+ "build": "tsc",
62
+ "test": "vitest run src",
63
+ "typecheck": "tsc --noEmit",
64
+ "format": "biome format --write .",
65
+ "format:check": "biome format .",
66
+ "start:example": "tsx watch examples/node-express.ts",
67
+ "version:bump": "npm version patch"
68
+ }
69
+ }