@dynamic-labs/logger 5.9.2 → 5.9.4

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/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
1
 
2
+ ### [5.9.4](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.3...v5.9.4) (2026-10-02)
3
+
4
+ ### [5.9.3](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.2...v5.9.3) (2026-10-02)
5
+
6
+ ### Bug Fixes
7
+
8
+ * **deps:** patch undici/joi/webpack-dev-middleware highs (main) ([#12452](https://github.com/dynamic-labs/dynamic-auth/issues/12452)) ([3b2ac12](https://github.com/dynamic-labs/dynamic-auth/commit/3b2ac126153bec03c0f296353a71a97bb61974d9)), closes [#1030-1048](https://github.com/dynamic-labs/dynamic-auth/issues/1030-1048) [#1036](https://github.com/dynamic-labs/dynamic-auth/issues/1036) [#1035](https://github.com/dynamic-labs/dynamic-auth/issues/1035)
9
+
2
10
  ### [5.9.2](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.1...v5.9.2) (2026-09-28)
3
11
 
4
12
 
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@dynamic-labs/logger",
3
- "version": "5.9.2",
3
+ "version": "5.9.4",
4
4
  "description": "A simple client side logging library used in Dynamic SDK",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
7
+ "dependencies": {
8
+ "@dynamic-labs/redaction": "1.1.0",
9
+ "eventemitter3": "5.0.1"
10
+ },
7
11
  "main": "./src/index.cjs",
8
12
  "module": "./src/index.js",
9
13
  "types": "./src/index.d.ts",
@@ -17,8 +21,5 @@
17
21
  },
18
22
  "./package.json": "./package.json"
19
23
  },
20
- "dependencies": {
21
- "eventemitter3": "5.0.1"
22
- },
23
24
  "peerDependencies": {}
24
25
  }
package/src/index.cjs CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var _tslib = require('../_virtual/_tslib.cjs');
6
6
  var EventEmitter = require('eventemitter3');
7
+ var redaction = require('@dynamic-labs/redaction');
7
8
  var MetaData = require('./MetaData/MetaData.cjs');
8
9
  var types = require('./types.cjs');
9
10
  var createCircularReferenceReplacer = require('./utils/createCircularReferenceReplacer.cjs');
@@ -149,16 +150,25 @@ class Logger {
149
150
  }
150
151
  captureAndSend(level, message, ...args) {
151
152
  return _tslib.__awaiter(this, void 0, void 0, function* () {
153
+ // `fetch` (not `window`) is the actual requirement: this also lets Node
154
+ // (which has had a global `fetch` since v18) forward logs, not just browsers.
152
155
  if (globalState.keys.emitErrors &&
153
156
  !IGNORE_MESSAGES.includes(message === null || message === void 0 ? void 0 : message.toString()) &&
154
- typeof window !== 'undefined') {
157
+ typeof fetch !== 'undefined') {
155
158
  this.emitHttpLogs(level, message, { args });
156
159
  }
157
160
  });
158
161
  }
159
162
  emitHttpLogs(level, message, { args = [], transformMeta = (meta) => meta }) {
160
163
  const stack = getStack.getStack(this.emitHttpLogs);
161
- messageQueue.push({ args, level, message, stack });
164
+ // Captured now, not at flush time — see MessageQueueMessage.environmentId.
165
+ messageQueue.push({
166
+ args,
167
+ environmentId: globalState.keys.environmentId,
168
+ level,
169
+ message,
170
+ stack,
171
+ });
162
172
  if (messageQueue.length === 1) {
163
173
  /**
164
174
  * Batching the logs to send them in a single request
@@ -173,43 +183,70 @@ class Logger {
173
183
  try {
174
184
  // Grab all pending messages immediately and clear the queue
175
185
  const currentBatch = messageQueue.splice(0, messageQueue.length);
176
- const messages = [];
186
+ // Group by the environmentId each message was queued under (not
187
+ // whatever is globally current now) and send one request per
188
+ // group, so a concurrent Logger.setEnvironmentId() call — a
189
+ // different tenant/request in the same Node process — can't
190
+ // redirect an already-queued message to the wrong destination.
191
+ const batchesByEnvironmentId = new Map();
177
192
  currentBatch.forEach((msg) => {
178
- var _a, _b, _c, _d, _e, _f;
179
- const body = {};
180
- const { objectArgs, remainingArgs } = processArgs.processArgs(msg);
181
- Object.assign(body, ...objectArgs);
182
- Object.assign(body, {
183
- level: types.LogLevel[msg.level],
184
- message: [msg.message, ...remainingArgs].join(' '),
185
- meta: transformMeta(globalState.metaData.merge(this.metaData).get()),
186
- stack: msg.stack,
187
- url: {
188
- hostname: (_a = window.location) === null || _a === void 0 ? void 0 : _a.hostname,
189
- origin: (_b = window.location) === null || _b === void 0 ? void 0 : _b.origin,
190
- pathname: (_c = window.location) === null || _c === void 0 ? void 0 : _c.pathname,
191
- port: (_d = window.location) === null || _d === void 0 ? void 0 : _d.port,
192
- protocol: (_e = window.location) === null || _e === void 0 ? void 0 : _e.protocol,
193
+ const existing = batchesByEnvironmentId.get(msg.environmentId);
194
+ if (existing) {
195
+ existing.push(msg);
196
+ }
197
+ else {
198
+ batchesByEnvironmentId.set(msg.environmentId, [msg]);
199
+ }
200
+ });
201
+ yield Promise.all(Array.from(batchesByEnvironmentId.entries()).map((_a) => _tslib.__awaiter(this, [_a], void 0, function* ([environmentId, msgs]) {
202
+ if (!environmentId) {
203
+ throw new Error('Environment ID not set');
204
+ }
205
+ const messages = [];
206
+ msgs.forEach((msg) => {
207
+ var _a, _b, _c, _d, _e, _f;
208
+ const body = {};
209
+ const { objectArgs, remainingArgs } = processArgs.processArgs(msg);
210
+ Object.assign(body, ...objectArgs);
211
+ const hasWindow = typeof window !== 'undefined';
212
+ Object.assign(body, {
213
+ level: types.LogLevel[msg.level],
214
+ message: [msg.message, ...remainingArgs].join(' '),
215
+ meta: transformMeta(globalState.metaData.merge(this.metaData).get()),
216
+ stack: msg.stack,
217
+ // Node/server environments have no window/location/navigator.
218
+ url: hasWindow
219
+ ? {
220
+ hostname: (_a = window.location) === null || _a === void 0 ? void 0 : _a.hostname,
221
+ origin: (_b = window.location) === null || _b === void 0 ? void 0 : _b.origin,
222
+ pathname: (_c = window.location) === null || _c === void 0 ? void 0 : _c.pathname,
223
+ port: (_d = window.location) === null || _d === void 0 ? void 0 : _d.port,
224
+ protocol: (_e = window.location) === null || _e === void 0 ? void 0 : _e.protocol,
225
+ }
226
+ : undefined,
227
+ userAgent: hasWindow
228
+ ? (_f = window.navigator) === null || _f === void 0 ? void 0 : _f.userAgent
229
+ : undefined,
230
+ });
231
+ // Credential/key-material redaction (@dynamic-labs/redaction) —
232
+ // scrubs both denylisted keys and credential-shaped free text
233
+ // (JWTs, Bearer/Basic, dyn_* keys) anywhere in the payload,
234
+ // including inside `message`/`stack`/caller-supplied context.
235
+ messages.push(redaction.redact(body, redaction.DEFAULT_REDACT_KEYS));
236
+ });
237
+ yield fetch(`https://logs.dynamicauth.com/api/v1/${environmentId}`, {
238
+ body: JSON.stringify(messages, createLogPayloadReplacer.createLogPayloadReplacer()),
239
+ headers: {
240
+ 'Content-Type': 'application/json',
193
241
  },
194
- userAgent: (_f = window.navigator) === null || _f === void 0 ? void 0 : _f.userAgent,
242
+ // keepalive lets queued logs (e.g. wallet-creation timeout /
243
+ // abandonment events) flush even as the tab is unloading.
244
+ keepalive: true,
245
+ method: 'POST',
246
+ mode: 'cors',
247
+ referrerPolicy: 'origin-when-cross-origin',
195
248
  });
196
- messages.push(body);
197
- });
198
- if (!globalState.keys.environmentId) {
199
- throw new Error('Environment ID not set');
200
- }
201
- yield fetch(`https://logs.dynamicauth.com/api/v1/${globalState.keys.environmentId}`, {
202
- body: JSON.stringify(messages, createLogPayloadReplacer.createLogPayloadReplacer()),
203
- headers: {
204
- 'Content-Type': 'application/json',
205
- },
206
- // keepalive lets queued logs (e.g. wallet-creation timeout /
207
- // abandonment events) flush even as the tab is unloading.
208
- keepalive: true,
209
- method: 'POST',
210
- mode: 'cors',
211
- referrerPolicy: 'origin-when-cross-origin',
212
- });
249
+ })));
213
250
  }
214
251
  catch (error) {
215
252
  this.debug('Failed to send logs to server', error);
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __awaiter } from '../_virtual/_tslib.js';
2
2
  import EventEmitter from 'eventemitter3';
3
+ import { redact, DEFAULT_REDACT_KEYS } from '@dynamic-labs/redaction';
3
4
  import { MetaData } from './MetaData/MetaData.js';
4
5
  import { LogLevel } from './types.js';
5
6
  export { LogLevel } from './types.js';
@@ -142,16 +143,25 @@ class Logger {
142
143
  }
143
144
  captureAndSend(level, message, ...args) {
144
145
  return __awaiter(this, void 0, void 0, function* () {
146
+ // `fetch` (not `window`) is the actual requirement: this also lets Node
147
+ // (which has had a global `fetch` since v18) forward logs, not just browsers.
145
148
  if (globalState.keys.emitErrors &&
146
149
  !IGNORE_MESSAGES.includes(message === null || message === void 0 ? void 0 : message.toString()) &&
147
- typeof window !== 'undefined') {
150
+ typeof fetch !== 'undefined') {
148
151
  this.emitHttpLogs(level, message, { args });
149
152
  }
150
153
  });
151
154
  }
152
155
  emitHttpLogs(level, message, { args = [], transformMeta = (meta) => meta }) {
153
156
  const stack = getStack(this.emitHttpLogs);
154
- messageQueue.push({ args, level, message, stack });
157
+ // Captured now, not at flush time — see MessageQueueMessage.environmentId.
158
+ messageQueue.push({
159
+ args,
160
+ environmentId: globalState.keys.environmentId,
161
+ level,
162
+ message,
163
+ stack,
164
+ });
155
165
  if (messageQueue.length === 1) {
156
166
  /**
157
167
  * Batching the logs to send them in a single request
@@ -166,43 +176,70 @@ class Logger {
166
176
  try {
167
177
  // Grab all pending messages immediately and clear the queue
168
178
  const currentBatch = messageQueue.splice(0, messageQueue.length);
169
- const messages = [];
179
+ // Group by the environmentId each message was queued under (not
180
+ // whatever is globally current now) and send one request per
181
+ // group, so a concurrent Logger.setEnvironmentId() call — a
182
+ // different tenant/request in the same Node process — can't
183
+ // redirect an already-queued message to the wrong destination.
184
+ const batchesByEnvironmentId = new Map();
170
185
  currentBatch.forEach((msg) => {
171
- var _a, _b, _c, _d, _e, _f;
172
- const body = {};
173
- const { objectArgs, remainingArgs } = processArgs(msg);
174
- Object.assign(body, ...objectArgs);
175
- Object.assign(body, {
176
- level: LogLevel[msg.level],
177
- message: [msg.message, ...remainingArgs].join(' '),
178
- meta: transformMeta(globalState.metaData.merge(this.metaData).get()),
179
- stack: msg.stack,
180
- url: {
181
- hostname: (_a = window.location) === null || _a === void 0 ? void 0 : _a.hostname,
182
- origin: (_b = window.location) === null || _b === void 0 ? void 0 : _b.origin,
183
- pathname: (_c = window.location) === null || _c === void 0 ? void 0 : _c.pathname,
184
- port: (_d = window.location) === null || _d === void 0 ? void 0 : _d.port,
185
- protocol: (_e = window.location) === null || _e === void 0 ? void 0 : _e.protocol,
186
+ const existing = batchesByEnvironmentId.get(msg.environmentId);
187
+ if (existing) {
188
+ existing.push(msg);
189
+ }
190
+ else {
191
+ batchesByEnvironmentId.set(msg.environmentId, [msg]);
192
+ }
193
+ });
194
+ yield Promise.all(Array.from(batchesByEnvironmentId.entries()).map((_a) => __awaiter(this, [_a], void 0, function* ([environmentId, msgs]) {
195
+ if (!environmentId) {
196
+ throw new Error('Environment ID not set');
197
+ }
198
+ const messages = [];
199
+ msgs.forEach((msg) => {
200
+ var _a, _b, _c, _d, _e, _f;
201
+ const body = {};
202
+ const { objectArgs, remainingArgs } = processArgs(msg);
203
+ Object.assign(body, ...objectArgs);
204
+ const hasWindow = typeof window !== 'undefined';
205
+ Object.assign(body, {
206
+ level: LogLevel[msg.level],
207
+ message: [msg.message, ...remainingArgs].join(' '),
208
+ meta: transformMeta(globalState.metaData.merge(this.metaData).get()),
209
+ stack: msg.stack,
210
+ // Node/server environments have no window/location/navigator.
211
+ url: hasWindow
212
+ ? {
213
+ hostname: (_a = window.location) === null || _a === void 0 ? void 0 : _a.hostname,
214
+ origin: (_b = window.location) === null || _b === void 0 ? void 0 : _b.origin,
215
+ pathname: (_c = window.location) === null || _c === void 0 ? void 0 : _c.pathname,
216
+ port: (_d = window.location) === null || _d === void 0 ? void 0 : _d.port,
217
+ protocol: (_e = window.location) === null || _e === void 0 ? void 0 : _e.protocol,
218
+ }
219
+ : undefined,
220
+ userAgent: hasWindow
221
+ ? (_f = window.navigator) === null || _f === void 0 ? void 0 : _f.userAgent
222
+ : undefined,
223
+ });
224
+ // Credential/key-material redaction (@dynamic-labs/redaction) —
225
+ // scrubs both denylisted keys and credential-shaped free text
226
+ // (JWTs, Bearer/Basic, dyn_* keys) anywhere in the payload,
227
+ // including inside `message`/`stack`/caller-supplied context.
228
+ messages.push(redact(body, DEFAULT_REDACT_KEYS));
229
+ });
230
+ yield fetch(`https://logs.dynamicauth.com/api/v1/${environmentId}`, {
231
+ body: JSON.stringify(messages, createLogPayloadReplacer()),
232
+ headers: {
233
+ 'Content-Type': 'application/json',
186
234
  },
187
- userAgent: (_f = window.navigator) === null || _f === void 0 ? void 0 : _f.userAgent,
235
+ // keepalive lets queued logs (e.g. wallet-creation timeout /
236
+ // abandonment events) flush even as the tab is unloading.
237
+ keepalive: true,
238
+ method: 'POST',
239
+ mode: 'cors',
240
+ referrerPolicy: 'origin-when-cross-origin',
188
241
  });
189
- messages.push(body);
190
- });
191
- if (!globalState.keys.environmentId) {
192
- throw new Error('Environment ID not set');
193
- }
194
- yield fetch(`https://logs.dynamicauth.com/api/v1/${globalState.keys.environmentId}`, {
195
- body: JSON.stringify(messages, createLogPayloadReplacer()),
196
- headers: {
197
- 'Content-Type': 'application/json',
198
- },
199
- // keepalive lets queued logs (e.g. wallet-creation timeout /
200
- // abandonment events) flush even as the tab is unloading.
201
- keepalive: true,
202
- method: 'POST',
203
- mode: 'cors',
204
- referrerPolicy: 'origin-when-cross-origin',
205
- });
242
+ })));
206
243
  }
207
244
  catch (error) {
208
245
  this.debug('Failed to send logs to server', error);
package/src/types.d.ts CHANGED
@@ -17,4 +17,5 @@ export type MessageQueueMessage = {
17
17
  message: Message;
18
18
  args: any[];
19
19
  stack?: string;
20
+ environmentId?: string;
20
21
  };