{"_id":"@carvis_ai/sanitize-log","name":"@carvis_ai/sanitize-log","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@carvis_ai/sanitize-log","version":"0.1.0","description":"Production-grade log sanitization with two-layer secret redaction. Detect and mask tokens, API keys, JWTs, and sensitive fields before they hit your logs.","keywords":["logging","sanitize","redact","security","secrets","pii","tokens","api-keys","jwt","pino","winston"],"license":"MIT","author":{"name":"Carvis AI","email":"oss@carvis.ai"},"repository":{"type":"git","url":"git+https://github.com/Carvis-AI/sanitize-log.git"},"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"scripts":{"build":"tsup","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"pnpm run build"},"devDependencies":{"tsup":"^8.0.0","typescript":"^5.4.0","vitest":"^2.0.0"},"engines":{"node":">=18"},"sideEffects":false,"_id":"@carvis_ai/sanitize-log@0.1.0","gitHead":"4b0476deb285104bf1783aae85f0f18db9a1db8d","bugs":{"url":"https://github.com/Carvis-AI/sanitize-log/issues"},"homepage":"https://github.com/Carvis-AI/sanitize-log#readme","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-9KasA1HGiNT4q3sowXFrD2K8LH2sn1Wi/920d4FaUWB5OmioklbQ6rAPF7+FHGox9o5UQ76yGPb0F3KneZdk4A==","shasum":"d4a35763c2362d168b3351be5a7de09584c2a209","tarball":"https://registry.npmjs.org/@carvis_ai/sanitize-log/-/sanitize-log-0.1.0.tgz","fileCount":9,"unpackedSize":77892,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEUlPeq6FCBI2+AfHoQkRc3C19WeScydQiXO3F+ahFTjAiBLUDCCmPI1YpDvxBKfRionvfEmalIf2xi4oMPmPeTlKw=="}]},"_npmUser":{"name":"cjna","email":"cj@carvis.ai"},"directories":{},"maintainers":[{"name":"cjna","email":"cj@carvis.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sanitize-log_0.1.0_1775410187719_0.7891402672042767"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-05T17:29:47.617Z","0.1.0":"2026-04-05T17:29:47.877Z","modified":"2026-04-05T17:29:48.170Z"},"maintainers":[{"name":"cjna","email":"cj@carvis.ai"}],"description":"Production-grade log sanitization with two-layer secret redaction. Detect and mask tokens, API keys, JWTs, and sensitive fields before they hit your logs.","homepage":"https://github.com/Carvis-AI/sanitize-log#readme","keywords":["logging","sanitize","redact","security","secrets","pii","tokens","api-keys","jwt","pino","winston"],"repository":{"type":"git","url":"git+https://github.com/Carvis-AI/sanitize-log.git"},"author":{"name":"Carvis AI","email":"oss@carvis.ai"},"bugs":{"url":"https://github.com/Carvis-AI/sanitize-log/issues"},"license":"MIT","readme":"# @carvis_ai/sanitize-log\n\nProduction-grade log sanitization with two-layer secret redaction.\n\nPrevents tokens, API keys, JWTs, passwords, and other sensitive data from leaking into your logs. Works with any logging backend (pino, winston, console).\n\n## Why This Exists\n\nMost sanitization libraries either redact everything (killing debuggability) or miss embedded secrets in string values. This library does both:\n\n1. **Key-based redaction** — fields named `password`, `token`, `apiKey`, etc. are fully redacted\n2. **Value-based detection** — strings are scanned for Bearer tokens, JWTs, API key patterns (`sk-`, `pk-`), and basic auth in URLs\n\nURL query parameters are selectively redacted: `?token=secret&page=2` becomes `?token=[REDACTED]&page=2`. You keep your debugging params.\n\n## Install\n\n```bash\nnpm install @carvis_ai/sanitize-log\n```\n\n## Quick Start\n\n```ts\nimport { sanitizeForLogging } from \"@carvis_ai/sanitize-log\";\n\nconst data = {\n  user: \"john\",\n  password: \"secret123\",\n  headers: { Authorization: \"Bearer eyJhbG...\" },\n  url: \"https://api.com?token=abc&page=1\",\n};\n\nconsole.log(sanitizeForLogging(data));\n// {\n//   user: \"john\",\n//   password: \"[REDACTED]\",\n//   headers: { Authorization: \"[REDACTED]\" },\n//   url: \"https://api.com?token=[REDACTED]&page=1\"\n// }\n```\n\n## API\n\n### `sanitizeForLogging(obj, maxDepth?)`\n\nDeep-sanitize an object. Handles circular references, arrays, nested objects.\n\n```ts\nsanitizeForLogging({ password: \"secret\" });\n// => { password: \"[REDACTED]\" }\n\nsanitizeForLogging(\"Bearer eyJhbGci...\");\n// => \"Bearer [REDACTED]\"\n```\n\n### `sanitizeStringValue(value)`\n\nScan a string for embedded secrets and mask them.\n\n```ts\nsanitizeStringValue(\"sk-1234567890abcdef\");\n// => \"sk-[REDACTED]\"\n\nsanitizeStringValue(\"https://user:pass@host.com\");\n// => \"https://user:[REDACTED]@host.com\"\n```\n\n### `createSanitizer(options?)`\n\nCreate a customized sanitizer instance.\n\n```ts\nimport { createSanitizer } from \"@carvis_ai/sanitize-log\";\n\nconst { sanitizeForLogging } = createSanitizer({\n  extraFields: [\"x-custom-secret\", \"internalToken\"],\n  extraPatterns: [\n    {\n      pattern: /MYAPP-[A-Z0-9]{20,}/g,\n      replace: () => \"MYAPP-[REDACTED]\",\n    },\n  ],\n  maxDepth: 5,\n});\n```\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `extraFields` | `string[]` | Additional field names to redact (merged with defaults) |\n| `extraPatterns` | `ValuePattern[]` | Additional regex patterns for string value detection |\n| `maxDepth` | `number` | Max recursion depth (default: 10) |\n\n### Logger Utilities\n\nMinimal pino-compatible logger interface with automatic sanitization.\n\n```ts\nimport { consoleLogger, createPrefixedLogger } from \"@carvis_ai/sanitize-log\";\n\n// Auto-sanitizing console logger\nconsoleLogger.error({ err: new Error(\"fail\"), token: \"secret\" }, \"Request failed\");\n// console: \"Request failed\" { err: { name: \"Error\", message: \"fail\", stack: \"...\" }, token: \"[REDACTED]\" }\n\n// Prefixed logger (cached, no GC pressure)\nconst log = createPrefixedLogger(\"[auth]\");\nlog.info({ userId: \"123\" }, \"Login successful\");\n// console: \"[auth] Login successful\" { userId: \"123\" }\n\n// Wrap any pino/winston logger\nconst log = createPrefixedLogger(\"[api]\", pinoInstance);\n```\n\n### `tryCatch(promise)`\n\nType-safe async error handling with discriminated unions.\n\n```ts\nimport { tryCatch } from \"@carvis_ai/sanitize-log\";\n\nconst { data, error } = await tryCatch(fetchUser(id));\nif (error) {\n  log.error({ err: error }, \"Failed to fetch user\");\n  return;\n}\n// data is typed correctly, error is null\nconsole.log(data.name);\n```\n\n## What Gets Redacted\n\n### Key-based (full redaction)\n\nAny field whose name contains: `password`, `token`, `secret`, `apikey`, `authorization`, `creditcard`, `cvv`, `ssn`, `pin`, `sessionid`, `cookie`, `bearer`, `private_key`, `client_secret`, `id_token`, `code_verifier`, `code_challenge`.\n\nDetection works across naming conventions:\n- `accessToken` (camelCase)\n- `access_token` (snake_case)\n- `x-auth-token` (hyphenated)\n\n### Value-based (pattern detection)\n\n| Pattern | Example | Result |\n|---------|---------|--------|\n| Bearer tokens | `Bearer eyJhbG...` | `Bearer [REDACTED]` |\n| API keys | `sk-1234567890abcdef` | `sk-[REDACTED]` |\n| JWTs | `eyJhbG.eyJzd.dozjg` | `[JWT-REDACTED]` |\n| Basic auth URLs | `://user:pass@host` | `://user:[REDACTED]@host` |\n| Sensitive URL params | `?token=abc&page=1` | `?token=[REDACTED]&page=1` |\n\n## Used at Carvis\n\nThis library is extracted from [Carvis](https://carvis.ai), where it runs in production across our backend API, Chrome extension, and AI agent orchestration layer.\n\n**The problem:** Our platform integrates with dozens of third-party APIs — shop management systems, parts distributors, vehicle data providers. Every integration exchanges OAuth tokens, API keys, and customer data. Before this library, secrets leaked into logs through:\n\n- Error messages containing request URLs with tokens in query strings\n- Stringified API responses with embedded JWTs\n- OAuth callback parameters logged during debugging\n- Nested objects from third-party SDKs with credentials in unexpected fields\n\n**How we use it:** Every logger instance is wrapped with `sanitizeForLogging`. All log output — including error-level logs forwarded to Sentry — is auto-sanitized. Engineers don't think about it; the default is safe.\n\nWe run ~50 prefixed logger modules, each processing requests carrying OAuth tokens and customer data. The FIFO cache and WeakMap caching were added after profiling showed naive sanitization added measurable overhead at our log volume.\n\nWe use `createSanitizer` to extend the defaults with domain-specific fields and patterns for partner APIs that use non-standard key formats — without polluting the library defaults.\n\nIf you're building integrations that touch customer data — especially in automotive, healthcare, fintech, or any multi-vendor SaaS — this is the same protection we rely on daily.\n\n## Design Decisions\n\n- **FIFO cache** for field name parsing — bounded at 1000 entries, no LRU complexity. Field names are a fixed set in practice; cache misses are cheap.\n- **WeakMap cache** for prefixed loggers — GC'd when the base logger is collected. No memory leaks from temporary logger instances.\n- **Selective URL param redaction** — non-sensitive params (`page`, `limit`, `shopId`) are preserved for debugging. Most libraries redact everything.\n- **Error serialization** — `Error.message` and `Error.stack` are non-enumerable. The logger serializes them before sanitization so they appear in logs.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-f148e56a1e1e7a349af1f8a1d8f69977"}