Skip to content

Architecture

User code
┌────────────────────────────────────────────────────┐
│ Wiz instance │
│ │
│ ① Level filter severity check -> skip or continue│
│ ② PII masking deep-clone + redact meta │
│ ③ Error parsing Error -> StackFrame[] │
│ ④ Entry assembly readonly LogEntry object │
└────────────────────────┬───────────────────────────┘
│ LogEntry (immutable)
┌───────────────┼───────────────┐
▼ ▼ ▼
ConsolePretty ConsoleJson FileTransport
(ANSI colours) (NDJSON) (daily rotation)
+ ConsoleBrowser
(DevTools groups)

if (LOG_LEVEL_SEVERITY[level] < LOG_LEVEL_SEVERITY[config.level]) return;

If the entry is below the configured threshold it returns immediately. In level: 'none' mode this is the only work done per call — zero allocations.

const maskedMeta = maskSensitiveData(options.meta, this.maskedKeys);

Deep-clones the metadata object, replacing sensitive keys with '[MASKED]'. A WeakSet tracks visited objects to handle circular references without throwing.

const parsedErr = options.error ? parseError(options.error) : undefined;

Converts an Error instance into a structured ParsedError with a StackFrame[] array — function name, file, line, and column per frame.

const entry: LogEntry = {
timestamp, level, env, message,
scope?, correlationId?, meta?, error?
};

The LogEntry is a plain readonly object. Once assembled it is never mutated.

for (const transport of this.transports) {
transport.write(entry);
}

Every registered transport receives the same immutable entry.


ModulePathResponsibility
Typessrc/types/index.tsAll public interfaces and level constants
Wizsrc/core/wiz.tsPipeline, level filter, transport factory
Maskersrc/utils/masker.tsRecursive PII masking + circular-ref guard
ErrorParsersrc/utils/error-parser.tsErrorParsedError + StackFrame[]
Timestampsrc/utils/timestamp.tsISO-8601 via Date.toISOString()
Envsrc/utils/env.tsNode / browser / production detection
PrettyTransportsrc/transports/console-pretty.tsANSI-coloured dev output
JsonTransportsrc/transports/console-json.tsSingle-line JSON
BrowserTransportsrc/transports/console-browser.tsGrouped DevTools output
FileTransportsrc/transports/file.tsDaily rotation + async buffer

TargetConfigOutputConsumers
ESMtsconfig.esm.jsondist/esm/Vite, Rollup, esbuild
CJStsconfig.cjs.jsondist/cjs/Node.js require(), Jest
Browsertsconfig.browser.jsondist/browser/Browser bundles — no fs
Typestsconfig.types.jsondist/types/TypeScript declarations

The exports field in package.json routes each consumer to the correct target automatically.


"sideEffects": false in package.json tells every bundler the package is side-effect-free. The FileTransport is lazily imported inside Wiz so it is completely absent from browser bundles.