# Changelog

## 6.4.1

### Bug Fix

- Updated colorize.ts so values now follow the color of their associated key, using a slightly different shade instead of the exact same color to make key/value pairs easier to visually distinguish while still clearly belonging together.

## 6.4.0

### Breaking Changes
- **`IColorConfiguration` key slots removed.** The interface no longer includes `key`, `levelKey`, `messageKey`, `fileNameKey`, `logCallStackKey`, `packageNameKey`, `timestampKey`, or `errCallStackKey`. These slots were used to assign a single fixed color to all keys of each type. They are replaced by hash-based coloring (see below). If you were reading or writing these slots on a custom `IColorConfiguration`, remove those references. Value-coloring slots (`errorLevel`, `warnLevel`, `nonErrorMessage`, `fileName`, `timestamp`, `errCallStack`, etc.) are unchanged.

### New Features
- **Unique per-property key colors derived from property name.** Every JSON key now gets its own distinct ANSI truecolor (24-bit RGB) derived from a djb2 hash of the key name. The same key name always produces the same color across all log lines, regardless of call site, log level, or log order. This makes it easy to visually track specific fields like `userId` or `requestId` across many log entries — each field consistently appears in its own color.
- **Terminal background auto-detection.** When `CONSOLE_LOG_COLORIZE=true`, the colorizer now detects whether the terminal background is dark or light and adjusts key colors accordingly. Dark backgrounds (the most common developer setup) get bright, high-lightness colors. Light backgrounds get darker, more readable tones. Detection checks, in order: `CONSOLE_LOG_COLORIZE_BACKGROUND` env var override, `COLORFGBG` (xterm/rxvt/Konsole), `TERM_PROGRAM` (`Apple_Terminal` → light, `vscode` → dark), `WT_SESSION` (Windows Terminal → dark), `VTE_VERSION` (GNOME Terminal → dark). Falls back to dark-background behavior when no signal is found.
- **`CONSOLE_LOG_COLORIZE_BACKGROUND` override.** Set to `dark` or `light` to force a specific color palette regardless of terminal detection. Useful in CI environments, scripts, or when auto-detection is wrong.

### Security Fixes
- Replaced the regex-based `colorJson(...)` token matcher with a linear JSON scanner, removing the polynomial-time escaped-string path flagged by CodeQL while preserving existing ANSI color behavior.

### Improvements
- Unified the logger configuration model so settings can be supplied either as direct `LoggerAdaptToConsole({...})` options or as environment variables. This adds top-level programmatic aliases for the existing env-backed flags and adds env-var forms for log level, debug-string capture, static custom fields, redaction, hook timeout, and advanced hook references.
- Key colors are cached per name and theme across log calls, so repeated keys (e.g. `level`, `message`, `userId`) pay the hash cost only once per process lifetime.

### Tests
- Added regression coverage for long escaped-quote payloads in `colorJson(...)`, ensuring colorized output still round-trips without content changes.
- Added regression coverage for the unified configuration surface, including top-level flag aliases, env-driven log level/debug/custom-options/redaction behavior, and env-resolved hook callbacks.
- Added end-to-end regression coverage for colorized logger output through the real `LoggerAdaptToConsole(...)` path, including direct top-level `colorize` usage and the `transformOutput + colorize` and `redact + colorize` combinations. The new tests assert both ANSI emission and that the JSON payload remains correct after stripping ANSI codes.
- Added hash-based key color tests: same key name produces same color across calls, different key names produce different colors, truecolor codes are emitted, light and dark themes produce visually distinct colors (verified by RGB sum thresholds).

## 6.3.2

### Bug Fixes
- Hardened browser-like host detection so the logger treats `globalThis.document` and `window.document` as DOM signals when deciding whether `process.stdout.write(...)` is trustworthy. This closes another `esm.sh`-style recursion path where a browser host exposes a fake Node `stdout` shim through `tty.mjs`.

### Tests
- Added regression coverage for browser-like hosts that expose DOM only through `window.document`, ensuring the logger still avoids fake `stdout` writes in that shape.

## 6.3.1

### Bug Fixes
- Added a second defensive safeguard for browser-style hosts where even the saved original `console.log(...)` feeds back into the patched console path. Re-entrant feedback during the logger's own write/fallback emission is now dropped instead of recursively re-logging logger output.


## 6.3.0

### Security Fixes
- Upgraded dev-dependency np package version to 11.1.0
- Upgraded dev-dependency jest package version to 30.3.0

### Bug Fixes
- Narrowed browser-like output handling to ignore fake `process.stdout.write(...)` shims in hosts like `code.esm.sh`, preventing recursive `console.log(...)` loops and `Maximum call stack size exceeded` while preserving direct stdout writes in real Node.js. See details in [docs/code-esm-sh-stdout-recursion.md](docs/code-esm-sh-stdout-recursion.md)

### Improvements
- Made the Jest contributor/test stack ESM-aware without changing library runtime behavior. Jest now transpiles the ESM-only `chai` package via `ts-jest`, uses a dedicated `tsconfig.jest.json`, and keeps the test environment on the existing CommonJS semantics so logger startup behavior stays stable under test.
- Refreshed the contributor toolchain around the Jest migration by upgrading `ts-jest`, `chai`, `@types/jest`, `@types/chai`, `sinon`, `@types/sinon`, `@types/node`, `prettier`, and `typescript`, while pruning stale unused test/dev dependencies from `package.json`.
- Added TypeScript 6 build compatibility by setting `ignoreDeprecations: "6.0"` in `tsconfig.json`, keeping the existing emit target and broader library compatibility intact.

### Tests
- Added regression coverage for the browser-like fake-stdout recursion case in both the Node-simulated compatibility tests and the real browser bundle tests.
- Added regression coverage for browser-style saved-console feedback loops, both in the Node-simulated compatibility tests and in the real browser bundle tests.
- Updated the Jest test suite to use ESM-safe imports where needed so the upgraded Jest/Chai toolchain runs cleanly end to end.

## 6.2.1

### Bug Fixes

- **Logging a bare `Error` no longer prefixes the message with a dangling hyphen.** Calls like `console.error(new Error('bang'))` and `console.log(new Error('bang'))` now emit `message: "bang"` instead of `message: "  - bang"`.

### Tests

- **Added regression coverage for bare-error logging without extra context.** Updated error-only expectations and added an explicit end-to-end console-path test to ensure the emitted `message` stays clean when no leading string message is provided.

## 6.2.0

### Bug Fixes

- **Buffered startup logs now preserve original caller metadata.** When an early log is held briefly for async package-name lookup, its `@filename` and `@logCallStack` are captured at the original call site instead of being recomputed later during flush.
- **Node ESM caller detection now skips packaged library frames more reliably.** `@filename` no longer falls back to `node_modules/console-log-json/dist/esm/index.mjs` in the reported startup case when the first real external caller is the consumer's app entry file.
- **Bare `Error` stack headers are now stripped from non-error call stacks.** `@logCallStack` no longer degrades to a useless literal `"Error"` when the runtime emits a header line without a trailing colon.
- **Internal helper frames are omitted from `@logCallStack`.** Non-error call stacks now start at the consumer-visible caller instead of internal helpers like `captureFileInfo(...)`, `emitConsoleJsonLog(...)`, or `logUsingConsoleJson(...)`.

### Tests

- **Added end-to-end regression coverage for the reported Node ESM startup case.** The test suite now verifies `@packageName`, `@filename`, and `@logCallStack` behavior with a temporary ESM consumer setup that mirrors the installed package layout under `node_modules/console-log-json/dist/esm/index.mjs`.
- **Added stack-parser regressions for packaged ESM frames and internal helper trimming.** Browser/stack compatibility tests now cover installed-package frame skipping, bare `Error` headers, and removal of leading internal logger helper frames from `@logCallStack`.

## 6.0.0

### Breaking Changes

- **Automatic `.env` loading has been removed.** The library no longer reads `.env` files or depends on `dotenv`, even optionally. Configuration now comes only from existing `process.env` values or `LoggerAdaptToConsole({ envOptions })`.
- **`logUsingWinston` has been renamed to `logUsingConsoleJson`.** If you were importing or referencing the old helper directly, update to the new name.

### New Features

- **Built-in structured redaction.** `LoggerAdaptToConsole()` now accepts a Pino-style `redact` option:
  - shorthand array form: `redact: ['password', 'headers.authorization', 'items[*].token']`
  - object form with custom censor: `redact: { paths: [...], censor: 'MASKED' }`
- **Redaction runs on the final output object.** It applies after `transformOutput`, before serialization/write, and `onLog` receives the redacted result.
- **Minification-resistant caller detection.** `@filename` now prefers V8 callsites, skips internal logger frames by function identity where possible, and falls back to stack parsing only when needed.

### Improvements

- **Jest replaced Mocha.** The test runner is now Jest via `ts-jest`, with a new `jest.config.cjs` and TypeScript configured for Jest globals.
- **Safer browser/bundled filename behavior.** Documentation now explicitly treats `@filename` as best-effort when a consumer bundles the library and their app into a single browser file.
- **No more manual `.env` scanning logic.** The legacy `Env.loadDotEnv()` implementation is now a no-op compatibility shim instead of touching the filesystem.
- **Logging pipeline cleanup.** Internal naming and structure were updated to match the current architecture:
  - `logUsingConsoleJson` replaces stale Winston naming
  - final output shaping, transform hooks, redaction, and serialization are now separated more clearly
- **Test suite cleanup.** Removed confusing no-op `await console.*(...)` usage, converted the helper stack-format test to assertions instead of console output, and added targeted coverage for:
  - reserved `message` handling through the real `console.log(...)` path
  - fallback-pattern skipping in browser-style stack parsing
  - callsite-based filename detection
  - structured redaction behavior
- **Stronger configuration coverage.** Added an audit test to ensure every documented `CONSOLE_LOG_*` setting in `README.md` is referenced by the test suite.
- **More deterministic permutation coverage.** Added a table-driven test that exercises permutations of string messages, errors, one or more context objects, and explicit `{ level: ... }` overrides and asserts a normalized final payload.

### Follow-up Behavior Changes

- **Reserved `message` handling is now consistent.**
  - `console.log('dude', { message: 'hi there' })` now produces `message: "dude - hi there"`
  - object-valued `message` is preserved under `@messageObject` instead of being flattened into top-level keys
  - when only `message: { ... }` is provided, the canonical `message` field remains present with the usual placeholder text

### Bug Fixes

- **`@packageName` now works in Node ESM startup paths.** The logger no longer relies solely on `require(...)` to discover `package.json`, so `LoggerAdaptToConsole()` in `"type": "module"` projects no longer emits the misleading `"<not-yet-set> Please await..."` placeholder.
- **Early logs are buffered while async package-name lookup completes.** Startup logs emitted immediately after `LoggerAdaptToConsole()` are now replayed once package-name resolution finishes, instead of racing initialization.
- **Redaction no longer mutates caller-owned input objects.** Sensitive fields are still redacted in the final emitted log object, but the original application objects passed to `console.log(...)` remain unchanged.

### Documentation

- **`ARCHITECTURE.md` was rewritten and updated** to reflect the real implementation instead of the older Winston-based design.
- **`README.md` now documents**:
  - Jest-based contributor/test setup
  - no automatic `.env` loading
  - best-effort `@filename` semantics in bundled browsers
  - the new `redact` API with examples and guidance

## 4.0.0

### Breaking Changes

- **Removed `winston` dependency.** The logging engine is now a lightweight native implementation. If you were importing Winston-specific types or relying on Winston transport behavior, this will affect you. The public API (`LoggerAdaptToConsole`, `console.log`, etc.) is unchanged.
- **Removed `app-root-path` dependency.** Replaced with a built-in project root detector. The `@filename` and stack trace path stripping behavior is identical.
- **`dotenv` and `source-map-support` are now optional dependencies.** They will still be installed by default, but if installation fails (e.g. in restricted environments), the library works without them.
- **Compilation target lowered from `es2019` to `es2017`.** This broadens browser and Node.js compatibility but should not affect consumers.
- **Barrel exports restricted to public API only.** Internal helpers like `getAppRoot`, `getEnv`, `sortObject`, `ToOneLine`, `safeObjectAssign`, `FormatStackTrace`, `NewLineCharacter`, `jsonStringifySafe`, `colorJson`, `CaptureNestedStackTrace`, and `callsites` are no longer exported from the package root. If you were importing these directly from `console-log-json`, import them from their specific file paths instead (e.g. `console-log-json/dist/src/safe-object-assign`).

### New Features

- **Zero required runtime dependencies.** The library is fully self-contained.
- **Browser compatible.** Works in Chrome, Firefox, Safari, and Edge via webpack, vite, esbuild, or any modern bundler. Node-specific features (`@filename`, `.env` loading) degrade gracefully.
- **`envOptions` parameter.** Configure the logger programmatically without `process.env`. Accepts the same variable names as the environment variables. Ideal for browser environments.
  ```js
  LoggerAdaptToConsole({
    envOptions: {
      CONSOLE_LOG_JSON_NO_FILE_NAME: 'true',
      CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR: 'true',
    }
  });
  ```
- **`onLog` interceptor.** Receive every log entry asynchronously after it's written. Useful for forwarding logs to a backend, analytics service, or error tracker. Crash-safe and non-blocking.
  ```js
  LoggerAdaptToConsole({
    onLog: (jsonString, parsedObject) => {
      navigator.sendBeacon('/api/logs', jsonString);
    }
  });
  ```
- **`transformOutput` hook.** Modify the log object before it's written. Rename fields, add properties, or reshape the output to match your log aggregator's schema. Falls back to original output if the callback throws.
  ```js
  LoggerAdaptToConsole({
    transformOutput: (obj) => {
      obj.status = obj.level;
      delete obj.level;
      return obj;
    }
  });
  ```
- **`CONSOLE_LOG_JSON_CONTEXT_KEY` option.** Nest all user-provided context properties under a single key instead of flattening them to the top level. Keeps the top-level JSON schema predictable for DataDog filters, OpenSearch index mappings, etc.
  ```js
  LoggerAdaptToConsole({
    envOptions: { CONSOLE_LOG_JSON_CONTEXT_KEY: 'context' }
  });
  ```
- **ESM build.** Ships both CommonJS (`dist/index.js`) and ESM (`dist/esm/index.mjs`) entry points. Modern bundlers automatically pick the ESM version for tree-shaking.
- **Boolean parameter support.** `console.log('active', false)` now correctly includes `false` in the message instead of silently dropping it.

### Bug Fixes

- **`filterNullOrUndefinedParameters` skipped adjacent nulls.** `forEach` + `splice` shifted indices; fixed by iterating backwards.
- **`FormatErrorObject` crashed when `message` was an object.** Fixed by deleting `message` before merge and adding `typeof` guards.
- **`ErrorWithContext(null, 'string')` crashed.** `typeof null === 'object'` caused `null.message` access; fixed by adding null guard.
- **`Env.loadDotEnv()` had a dead branch.** `.length < 0` is always false; fixed to `.length > 0`.
- **`ifEverythingFailsLogger` could throw into the caller's code.** Now silently catches all errors so logging failures never crash the application.

### Performance Improvements

- **Single Error object per log call** (down from two). `getCallingFilename` now parses the filename from the shared stack string instead of creating a separate Error via the V8 callsites API.
- **No more `Error.prepareStackTrace` global mutation.** Eliminated the race condition hazard in the logging hot path.
- **Environment variables cached at init time.** Reduces ~10 `getEnv()` calls per log to zero.
- **Pre-compiled regex** for stack message extraction.
- **`safeObjectAssign` uses `deepClone` with a visited-object Map** instead of `JSON.parse(jsonStringifySafe(...))`. Eliminates double serialization.
- **`sortObject` optimized** to sort keys directly without intermediate arrays.
- **JSON auto-parse skipped for non-JSON messages.** A quick first-character check avoids the `try { JSON.parse() } catch` overhead on every log.
- **`NewLineCharacter` cached** after first call.
- **Stack trace capture skipped entirely** when both `CONSOLE_LOG_JSON_NO_FILE_NAME` and `CONSOLE_LOG_JSON_NO_STACK_FOR_NON_ERROR` are enabled. Eliminates the most expensive operation for high-throughput logging.
- **Depth limits** added to `safeObjectAssign` (50 levels) and `findNonConflictingKeyInTarget` (20 iterations) to prevent stack overflow on deeply nested objects.

### Migration from v3

1. **Install the new version:**
   ```bash
   npm install console-log-json@4
   ```

2. **No code changes needed** if you only use the public API (`LoggerAdaptToConsole`, `console.log`, `ErrorWithContext`, etc.). The drop-in behavior is identical.

3. **If you imported internal helpers** from `console-log-json` (e.g. `safeObjectAssign`, `sortObject`, `FormatStackTrace`), update your imports to use the deep path:
   ```js
   // Before (v3)
   import { safeObjectAssign } from 'console-log-json';

   // After (v4)
   import { safeObjectAssign } from 'console-log-json/dist/src/safe-object-assign';
   ```

4. **If you depended on Winston types or transports**, those are gone. The library no longer uses Winston internally.

5. **`dotenv` and `source-map-support`** are now optional. If you need `.env` file loading, ensure `dotenv` is installed in your project. If you need TypeScript source map support in stack traces, ensure `source-map-support` is installed.
