logixia 2.0.6 → 2.0.8
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/README.md +9 -0
- package/dist/{async-context-2mbUKhcl.mjs → async-context-COuvmwsS.mjs} +2 -2
- package/dist/{async-context-2mbUKhcl.mjs.map → async-context-COuvmwsS.mjs.map} +1 -1
- package/dist/{async-context-DUFMDYAr.js → async-context-Dv0bmPC-.js} +3 -3
- package/dist/{async-context-DUFMDYAr.js.map → async-context-Dv0bmPC-.js.map} +1 -1
- package/dist/{azure-monitor.transport-C1RWAumT.mjs → azure-monitor.transport-Coz5Gesu.mjs} +5 -5
- package/dist/{azure-monitor.transport-C1RWAumT.mjs.map → azure-monitor.transport-Coz5Gesu.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-Bu4S2I2q.js → azure-monitor.transport-D6ryi8rA.js} +5 -5
- package/dist/{azure-monitor.transport-Bu4S2I2q.js.map → azure-monitor.transport-D6ryi8rA.js.map} +1 -1
- package/dist/azure.js +1 -1
- package/dist/azure.mjs +1 -1
- package/dist/{batch-buffer-C7Am4Mw-.js → batch-buffer-CFzKnuNZ.js} +3 -3
- package/dist/{batch-buffer-C7Am4Mw-.js.map → batch-buffer-CFzKnuNZ.js.map} +1 -1
- package/dist/{batch-buffer-BvXLDPlV.mjs → batch-buffer-CQUWDMYq.mjs} +3 -3
- package/dist/{batch-buffer-BvXLDPlV.mjs.map → batch-buffer-CQUWDMYq.mjs.map} +1 -1
- package/dist/browser.js +25 -1
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +25 -1
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-yFvJrz7o.js → builder-BTzvPGHN.js} +82 -15
- package/dist/builder-BTzvPGHN.js.map +1 -0
- package/dist/{builder-DhNhvOkt.mjs → builder-DKL7WcIN.mjs} +71 -10
- package/dist/builder-DKL7WcIN.mjs.map +1 -0
- package/dist/cloudwatch.js +1 -1
- package/dist/cloudwatch.mjs +1 -1
- package/dist/{cloudwatch.transport-DZqF2xZO.mjs → cloudwatch.transport-Cr1aeTGj.mjs} +6 -6
- package/dist/{cloudwatch.transport-DZqF2xZO.mjs.map → cloudwatch.transport-Cr1aeTGj.mjs.map} +1 -1
- package/dist/{cloudwatch.transport-Ch1Uae-0.js → cloudwatch.transport-D4G5xYfG.js} +6 -6
- package/dist/{cloudwatch.transport-Ch1Uae-0.js.map → cloudwatch.transport-D4G5xYfG.js.map} +1 -1
- package/dist/correlation.d.mts +6 -0
- package/dist/correlation.d.mts.map +1 -1
- package/dist/correlation.d.ts +6 -0
- package/dist/correlation.d.ts.map +1 -1
- package/dist/correlation.js +4 -2
- package/dist/correlation.js.map +1 -1
- package/dist/correlation.mjs +4 -2
- package/dist/correlation.mjs.map +1 -1
- package/dist/{entry-fields-BSLkzw18.js → entry-fields-CVwoQplO.js} +3 -3
- package/dist/{entry-fields-BSLkzw18.js.map → entry-fields-CVwoQplO.js.map} +1 -1
- package/dist/{entry-fields-J1OBi24o.mjs → entry-fields-DNTKQxoU.mjs} +2 -2
- package/dist/{entry-fields-J1OBi24o.mjs.map → entry-fields-DNTKQxoU.mjs.map} +1 -1
- package/dist/gcp.js +1 -1
- package/dist/gcp.mjs +1 -1
- package/dist/{gcp.transport-Dy2Lf8FI.js → gcp.transport-CVuRpchl.js} +6 -6
- package/dist/{gcp.transport-Dy2Lf8FI.js.map → gcp.transport-CVuRpchl.js.map} +1 -1
- package/dist/{gcp.transport-DVCmnA3b.mjs → gcp.transport-LLK2bw2-.mjs} +6 -6
- package/dist/{gcp.transport-DVCmnA3b.mjs.map → gcp.transport-LLK2bw2-.mjs.map} +1 -1
- package/dist/{index-BSTtFcQ6.d.mts → index-BAkPHp5D.d.mts} +9 -1
- package/dist/index-BAkPHp5D.d.mts.map +1 -0
- package/dist/{index-CFDGkI8n.d.ts → index-e7LowmAu.d.ts} +9 -1
- package/dist/index-e7LowmAu.d.ts.map +1 -0
- package/dist/index.d.mts +11 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -8
- package/dist/internal-log-Cy5nF1ZL.mjs +63 -0
- package/dist/internal-log-Cy5nF1ZL.mjs.map +1 -0
- package/dist/internal-log-DwqTjhpb.js +80 -0
- package/dist/internal-log-DwqTjhpb.js.map +1 -0
- package/dist/{logitron-logger-D_MYYrQt.d.ts → logitron-logger-Qh3y9-WH.d.ts} +2 -2
- package/dist/{logitron-logger-D_MYYrQt.d.ts.map → logitron-logger-Qh3y9-WH.d.ts.map} +1 -1
- package/dist/{logitron-logger-D22Yb61K.d.mts → logitron-logger-sYuk8fOb.d.mts} +2 -2
- package/dist/{logitron-logger-D22Yb61K.d.mts.map → logitron-logger-sYuk8fOb.d.mts.map} +1 -1
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +8 -8
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +3 -3
- package/dist/nest.d.mts +12 -3
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +12 -3
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +128 -20
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +128 -20
- package/dist/nest.mjs.map +1 -1
- package/dist/{otel-DyeH6DVR.js → otel-ChnVYRLA.js} +5 -5
- package/dist/{otel-DyeH6DVR.js.map → otel-ChnVYRLA.js.map} +1 -1
- package/dist/{otel-Dt5riXuE.mjs → otel-DOuwGPCd.mjs} +5 -5
- package/dist/{otel-Dt5riXuE.mjs.map → otel-DOuwGPCd.mjs.map} +1 -1
- package/dist/{safe-stringify-B5p5ktFe.mjs → safe-stringify--7gbe95n.mjs} +2 -2
- package/dist/{safe-stringify-B5p5ktFe.mjs.map → safe-stringify--7gbe95n.mjs.map} +1 -1
- package/dist/{safe-stringify-J3sh-7YM.js → safe-stringify-CN7icp8S.js} +5 -5
- package/dist/{safe-stringify-J3sh-7YM.js.map → safe-stringify-CN7icp8S.js.map} +1 -1
- package/dist/{search-DA3ft3X5.d.mts → search-D-8HJADE.d.mts} +2 -2
- package/dist/{search-DA3ft3X5.d.mts.map → search-D-8HJADE.d.mts.map} +1 -1
- package/dist/{search-DEl3Pe47.d.ts → search-DPwTKPve.d.ts} +2 -2
- package/dist/{search-DEl3Pe47.d.ts.map → search-DPwTKPve.d.ts.map} +1 -1
- package/dist/search.d.mts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/{secret-config-CmK2wVkr.js → secret-config-BvFl2dC8.js} +7 -8
- package/dist/{secret-config-CmK2wVkr.js.map → secret-config-BvFl2dC8.js.map} +1 -1
- package/dist/{secret-config-Dhb6pqTU.mjs → secret-config-ByGq7kJd.mjs} +2 -3
- package/dist/{secret-config-Dhb6pqTU.mjs.map → secret-config-ByGq7kJd.mjs.map} +1 -1
- package/dist/sensitive-names-CHMowujD.js +276 -0
- package/dist/sensitive-names-CHMowujD.js.map +1 -0
- package/dist/sensitive-names-o__1PUUR.mjs +217 -0
- package/dist/sensitive-names-o__1PUUR.mjs.map +1 -0
- package/dist/{slack.transport-BTEwsREY.mjs → slack.transport-CSj1j0_X.mjs} +6 -6
- package/dist/{slack.transport-BTEwsREY.mjs.map → slack.transport-CSj1j0_X.mjs.map} +1 -1
- package/dist/{slack.transport-UbYvOdKx.js → slack.transport-zLQ9MGxS.js} +6 -6
- package/dist/{slack.transport-UbYvOdKx.js.map → slack.transport-zLQ9MGxS.js.map} +1 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/transports.d.mts +1 -1
- package/dist/transports.d.ts +1 -1
- package/dist/transports.js +6 -6
- package/dist/transports.mjs +6 -6
- package/dist/worker-entry.js +25 -1
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-BmmOKb1-.mjs → worker.transport-D78xhNhB.mjs} +3 -3
- package/dist/{worker.transport-BmmOKb1-.mjs.map → worker.transport-D78xhNhB.mjs.map} +1 -1
- package/dist/{worker.transport-DxxbqQCG.js → worker.transport-DQDv1nAJ.js} +3 -3
- package/dist/{worker.transport-DxxbqQCG.js.map → worker.transport-DQDv1nAJ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/builder-DhNhvOkt.mjs.map +0 -1
- package/dist/builder-yFvJrz7o.js.map +0 -1
- package/dist/index-BSTtFcQ6.d.mts.map +0 -1
- package/dist/index-CFDGkI8n.d.ts.map +0 -1
- package/dist/internal-log-Bg4V1cPg.mjs +0 -170
- package/dist/internal-log-Bg4V1cPg.mjs.map +0 -1
- package/dist/internal-log-By4Govmu.js +0 -223
- package/dist/internal-log-By4Govmu.js.map +0 -1
- package/dist/own-property-BWkibepN.js +0 -40
- package/dist/own-property-BWkibepN.js.map +0 -1
- package/dist/own-property-CjFw9qwZ.mjs +0 -29
- package/dist/own-property-CjFw9qwZ.mjs.map +0 -1
package/dist/correlation.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"correlation.mjs","names":[],"sources":["../src/correlation.ts"],"sourcesContent":["/**\n * logixia — Microservices Correlation ID Propagation\n *\n * Provides zero-boilerplate correlation ID generation and propagation for\n * distributed systems. A single correlation ID travels through every service\n * in a request fan-out, making it trivial to join logs across services.\n *\n * Features:\n * - UUID v4 correlation ID generation (via `crypto.randomUUID()`)\n * - Express / Fastify / NestJS incoming-request middleware\n * - `correlationFetch()` — wraps global `fetch`, auto-injects `X-Correlation-ID`\n * - `createCorrelationAxiosInterceptor()` — axios request interceptor\n * - `childFromRequest(req, logger)` — child logger with all request identifiers\n * - Kafka / SQS / RabbitMQ message context helpers\n * - Integration with `LogixiaContext` (AsyncLocalStorage) so every `logger.info()`\n * call automatically includes the correlationId without per-call passing.\n *\n * @example Express middleware\n * ```ts\n * import { correlationMiddleware } from 'logixia/correlation';\n * import { logger } from 'logixia';\n *\n * app.use(correlationMiddleware());\n *\n * app.get('/orders', (req, res) => {\n * // correlationId is automatically in every log inside this request\n * logger.info('Listing orders');\n * res.json({ ok: true });\n * });\n * ```\n *\n * @example Outbound fetch with correlation\n * ```ts\n * import { correlationFetch } from 'logixia/correlation';\n *\n * // Reads correlationId from current LogixiaContext and injects it as header\n * const data = await correlationFetch('https://payments.internal/charge', {\n * method: 'POST',\n * body: JSON.stringify({ amount: 100 }),\n * });\n * ```\n *\n * @example Manual correlation context\n * ```ts\n * import { withCorrelationId } from 'logixia/correlation';\n *\n * await withCorrelationId('trace-abc-123', async () => {\n * // All logs and outbound fetch calls in here carry 'trace-abc-123'\n * await processOrder();\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { LogixiaContext } from './context/async-context';\nimport type { HttpRequestShape, HttpResponseShape } from './types/http-shapes';\nimport { sanitizeIncomingId } from './utils/trace.utils';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/** Fields injected into the log context by the correlation middleware. */\nexport interface CorrelationContext {\n correlationId: string;\n traceId?: string;\n /** Service that originated the request (from `X-Origin-Service` header). */\n originService?: string;\n /** Index signature so CorrelationContext is assignable to LogContext. */\n [key: string]: unknown;\n}\n\nexport interface CorrelationMiddlewareOptions {\n /**\n * HTTP header to read/write the correlation ID from/to.\n * @default 'x-correlation-id'\n */\n header?: string;\n /**\n * HTTP header for the originating service name.\n * @default 'x-origin-service'\n */\n originServiceHeader?: string;\n /**\n * Function to generate a new correlation ID when none is present in the request.\n * @default () => crypto.randomUUID()\n */\n generate?: () => string;\n /**\n * When `false`, the incoming correlation header is ignored and a new ID is\n * always generated. Use this at the edge when client-supplied IDs should not\n * be trusted.\n * @default true\n */\n trustIncoming?: boolean;\n /**\n * When `true`, the response will include the correlation ID header so\n * clients can log it client-side.\n * @default true\n */\n setResponseHeader?: boolean;\n}\n\n// ── ID generation ─────────────────────────────────────────────────────────────\n\n/**\n * Generate a new correlation ID using `crypto.randomUUID()` (available in\n * Node.js 14.17+, all modern browsers, and Edge runtimes).\n *\n * When the Web Crypto global is unavailable (e.g. Node 18 without\n * `--experimental-global-webcrypto`), fall back to `node:crypto`'s\n * `randomUUID`, which returns a proper UUID v4 — matching the shape this\n * function's JSDoc and README promise. `logixia/correlation` is Node-only\n * (it builds on `AsyncLocalStorage`), so importing `node:crypto` is safe here.\n */\nexport function generateCorrelationId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return randomUUID();\n}\n\n/**\n * Return an incoming correlation ID only if it is short and made of safe\n * characters. Anything else (over-long, empty, or containing newlines or other\n * control characters) is dropped so the caller generates a fresh ID instead of\n * writing client-supplied text into every log line.\n */\nfunction validIncomingId(value: unknown): string | undefined {\n if (typeof value === 'string' && value.trim() !== value) return undefined;\n return sanitizeIncomingId(value);\n}\n\n// ── Context helpers ───────────────────────────────────────────────────────────\n\n/**\n * Return the correlation ID from the current `LogixiaContext`, or `undefined`\n * when called outside any context scope.\n */\nexport function getCurrentCorrelationId(): string | undefined {\n const ctx = LogixiaContext.get();\n return ctx?.correlationId as string | undefined;\n}\n\n/**\n * Run `callback` inside a correlation context scope.\n *\n * If a correlation ID is not provided, a new UUID is generated.\n *\n * @example\n * ```ts\n * await withCorrelationId('cid-abc', async () => {\n * logger.info('Processing message'); // → { correlationId: 'cid-abc', ... }\n * await callDownstream(); // correlationFetch() picks up cid-abc\n * });\n * ```\n */\nexport function withCorrelationId<T>(correlationId: string | undefined, callback: () => T): T {\n const id = correlationId ?? generateCorrelationId();\n return LogixiaContext.run({ correlationId: id }, callback);\n}\n\n// ── Express / Connect middleware ──────────────────────────────────────────────\n\n/**\n * Express-compatible middleware that:\n * 1. Reads `X-Correlation-ID` from the incoming request (or generates a new one)\n * 2. Wraps the request in a `LogixiaContext` so all loggers in the handler\n * automatically include `correlationId`\n * 3. Writes the correlation ID back to the response header (opt-out via options)\n *\n * @example\n * ```ts\n * import { correlationMiddleware } from 'logixia/correlation';\n * app.use(correlationMiddleware());\n * ```\n */\nexport function correlationMiddleware(options: CorrelationMiddlewareOptions = {}) {\n const {\n header = 'x-correlation-id',\n originServiceHeader = 'x-origin-service',\n generate = generateCorrelationId,\n trustIncoming = true,\n setResponseHeader = true,\n } = options;\n\n return function logixiaCorrelationMiddleware(\n req: HttpRequestShape,\n res: HttpResponseShape,\n next: () => void\n ): void {\n const headers = req.headers ?? {};\n\n // Node lower-cases incoming header names, so look up with lower-cased keys.\n const incomingId = trustIncoming ? validIncomingId(headers[header.toLowerCase()]) : undefined;\n const correlationId = incomingId ?? generate();\n const originService = validIncomingId(headers[originServiceHeader.toLowerCase()]);\n\n if (setResponseHeader) {\n res.setHeader?.(header, correlationId);\n }\n\n const ctx: CorrelationContext = {\n correlationId,\n ...(originService !== undefined ? { originService } : {}),\n };\n\n LogixiaContext.run(ctx, next);\n };\n}\n\n// ── Fastify hook ──────────────────────────────────────────────────────────────\n\n/**\n * Fastify `onRequest` lifecycle hook — same functionality as `correlationMiddleware`\n * but adapted to Fastify's hook API.\n *\n * @example\n * ```ts\n * import { correlationFastifyHook } from 'logixia/correlation';\n * fastify.addHook('onRequest', correlationFastifyHook());\n * ```\n */\nexport function correlationFastifyHook(options: CorrelationMiddlewareOptions = {}) {\n const {\n header = 'x-correlation-id',\n originServiceHeader = 'x-origin-service',\n generate = generateCorrelationId,\n trustIncoming = true,\n setResponseHeader = true,\n } = options;\n\n return function logixiaCorrelationFastifyHook(\n request: HttpRequestShape,\n reply: HttpResponseShape,\n done: () => void\n ): void {\n const headers = request.headers ?? {};\n\n // Node lower-cases incoming header names, so look up with lower-cased keys.\n const incomingId = trustIncoming ? validIncomingId(headers[header.toLowerCase()]) : undefined;\n const correlationId = incomingId ?? generate();\n const originService = validIncomingId(headers[originServiceHeader.toLowerCase()]);\n\n if (setResponseHeader) {\n reply.header?.(header, correlationId);\n }\n\n const ctx: CorrelationContext = {\n correlationId,\n ...(originService !== undefined ? { originService } : {}),\n };\n\n LogixiaContext.run(ctx, done);\n };\n}\n\n// ── Outbound fetch wrapper ────────────────────────────────────────────────────\n\n/**\n * A drop-in replacement for `fetch` that automatically injects the current\n * `correlationId` from `LogixiaContext` as an `X-Correlation-ID` request header.\n *\n * Falls back to the global `fetch` when no correlation context is active.\n *\n * @example\n * ```ts\n * import { correlationFetch } from 'logixia/correlation';\n *\n * // Inside a request handler with correlationMiddleware active:\n * const response = await correlationFetch('https://payments.internal/v1/charge', {\n * method: 'POST',\n * body: JSON.stringify({ amount: 100 }),\n * });\n * ```\n */\nexport async function correlationFetch(\n input: string | URL | Request,\n init: RequestInit = {},\n options: { header?: string } = {}\n): Promise<Response> {\n const header = options.header ?? 'x-correlation-id';\n const correlationId = getCurrentCorrelationId();\n\n // `init.headers` can be a plain object, a `Headers` instance, or an array of\n // `[name, value]` tuples. Spreading it into a plain object loses everything\n // but the object form: a `Headers` instance has no own enumerable properties,\n // and an array spread yields numeric indices. `Headers` accepts all three, is\n // case-insensitive, and is the shape `fetch` expects back.\n //\n // A `Request` carries headers of its own, and `fetch(request, { headers })`\n // replaces them rather than merging them, so they are seeded first and the\n // caller's `init.headers` is applied on top. Without this, accepting a\n // `Request` here would drop its headers, which is the same defect one input\n // shape over.\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n for (const [name, value] of new Headers(init.headers)) {\n headers.set(name, value);\n }\n if (correlationId && !headers.has(header)) {\n headers.set(header, correlationId);\n }\n\n return globalThis.fetch(input, { ...init, headers });\n}\n\n// ── Axios interceptor factory ─────────────────────────────────────────────────\n\n/**\n * Returns an axios request interceptor that automatically injects the current\n * correlation ID into outgoing axios requests.\n *\n * @example\n * ```ts\n * import axios from 'axios';\n * import { createCorrelationAxiosInterceptor } from 'logixia/correlation';\n *\n * axios.interceptors.request.use(createCorrelationAxiosInterceptor());\n * ```\n */\nexport function createCorrelationAxiosInterceptor(\n options: { header?: string } = {}\n): (config: Record<string, unknown>) => Record<string, unknown> {\n const header = options.header ?? 'x-correlation-id';\n\n return function correlationAxiosInterceptor(\n config: Record<string, unknown>\n ): Record<string, unknown> {\n const correlationId = getCurrentCorrelationId();\n if (!correlationId) return config;\n\n const headers = (config['headers'] ?? {}) as Record<string, unknown>;\n if (!headers[header]) {\n headers[header] = correlationId;\n }\n\n return { ...config, headers };\n };\n}\n\n// ── Child logger from request ─────────────────────────────────────────────────\n\nconst MAX_USER_AGENT_LENGTH = 512;\nconst MAX_IP_LENGTH = 64;\n\nexport interface ChildFromRequestOptions {\n /** Header to read the correlation ID from. @default 'x-correlation-id' */\n correlationHeader?: string;\n /**\n * Take the client IP from the first `X-Forwarded-For` entry. Only enable this\n * when the app sits behind a proxy that overwrites the header; otherwise any\n * client can choose the logged IP.\n * @default false\n */\n trustProxy?: boolean;\n /**\n * Context name passed as the first argument to `logger.child(context, data)`.\n * When omitted, logixia loggers (detected by their `getContext` /\n * `getAvailableTransports` methods) get `child('request', fields)` and any other\n * logger gets `child(fields)`.\n */\n childContext?: string;\n}\n\n/**\n * Create a child logger enriched with all correlation-relevant identifiers\n * extracted from the incoming HTTP request.\n *\n * The child logger's every call automatically includes:\n * `correlationId`, `method`, `url`, `userAgent`, `ip`\n *\n * The IP comes from `req.ip` / the socket address unless `trustProxy` is set.\n *\n * @example\n * ```ts\n * import { childFromRequest } from 'logixia/correlation';\n * import { logger } from 'logixia';\n *\n * app.use((req, res, next) => {\n * req.logger = childFromRequest(req, logger);\n * next();\n * });\n *\n * app.get('/orders', (req, res) => {\n * req.logger.info('Listing orders'); // → correlationId, requestId, method, url ...\n * });\n * ```\n */\nexport function childFromRequest<TLogger extends { child(...args: never[]): TLogger }>(\n req: HttpRequestShape,\n logger: TLogger,\n options: ChildFromRequestOptions = {}\n): TLogger {\n const correlationHeader = options.correlationHeader ?? 'x-correlation-id';\n\n const headers = req.headers ?? {};\n // Node lower-cases incoming header names, so look up with a lower-cased key.\n const correlationId =\n validIncomingId(headers[correlationHeader.toLowerCase()]) ??\n getCurrentCorrelationId() ??\n generateCorrelationId();\n\n const method = req.method;\n const url = req.url ?? req.originalUrl;\n const rawUserAgent = headers['user-agent'];\n const userAgent =\n typeof rawUserAgent === 'string' ? rawUserAgent.slice(0, MAX_USER_AGENT_LENGTH) : undefined;\n const ip = resolveClientIp(req, headers, options.trustProxy === true);\n\n const fields = {\n correlationId,\n ...(method !== undefined ? { method } : {}),\n ...(url !== undefined ? { url } : {}),\n ...(userAgent !== undefined ? { userAgent } : {}),\n ...(ip !== undefined ? { ip } : {}),\n };\n\n const child = logger.child as (...args: unknown[]) => TLogger;\n if (options.childContext !== undefined) {\n return child.call(logger, options.childContext, fields);\n }\n // logixia's ILogger.child(context: string, data?) takes a string namespace;\n // pino/winston-style loggers take a bindings object.\n if (usesStringContext(logger)) {\n return child.call(logger, 'request', fields);\n }\n return child.call(logger, fields);\n}\n\n/** ILogger implementations (LogixiaLogger, LogixiaLoggerService, mock logger) expose these methods. */\nfunction usesStringContext(logger: object): boolean {\n const l = logger as Record<string, unknown>;\n return typeof l['getContext'] === 'function' || typeof l['getAvailableTransports'] === 'function';\n}\n\nfunction resolveClientIp(\n req: HttpRequestShape,\n headers: Record<string, string | string[] | undefined>,\n trustProxy: boolean\n): string | undefined {\n if (trustProxy) {\n const forwarded = headers['x-forwarded-for'];\n const first = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : undefined;\n if (first) return first.slice(0, MAX_IP_LENGTH);\n }\n const fromReq = req.ip;\n if (typeof fromReq === 'string' && fromReq) return fromReq.slice(0, MAX_IP_LENGTH);\n const remote = req.socket?.remoteAddress;\n return typeof remote === 'string' ? remote.slice(0, MAX_IP_LENGTH) : undefined;\n}\n\n// ── Message queue helpers ─────────────────────────────────────────────────────\n\n/**\n * Extract a correlation context from a Kafka / RabbitMQ / SQS message object.\n *\n * Looks for `correlationId`, `correlation_id`, or `x-correlation-id` in\n * `message.headers` (Kafka) or `message.MessageAttributes` (SQS).\n *\n * @example Kafka consumer\n * ```ts\n * import { extractMessageCorrelationId, withCorrelationId } from 'logixia/correlation';\n *\n * consumer.run({\n * eachMessage: async ({ message }) => {\n * const correlationId = extractMessageCorrelationId(message);\n * await withCorrelationId(correlationId, () => processMessage(message));\n * },\n * });\n * ```\n */\nexport function extractMessageCorrelationId(message: Record<string, unknown>): string | undefined {\n // Kafka: message.headers is Record<string, Buffer | string>\n const kafkaHeaders = message['headers'] as Record<string, Buffer | string> | undefined;\n if (kafkaHeaders) {\n const raw =\n kafkaHeaders['x-correlation-id'] ??\n kafkaHeaders['correlationId'] ??\n kafkaHeaders['correlation_id'];\n if (raw !== undefined) {\n return validIncomingId(Buffer.isBuffer(raw) ? raw.toString('utf8', 0, 512) : String(raw));\n }\n }\n\n // SQS: message.MessageAttributes\n const sqsAttrs = message['MessageAttributes'] as\n Record<string, { StringValue?: string }> | undefined;\n if (sqsAttrs) {\n return validIncomingId(\n sqsAttrs['x-correlation-id']?.StringValue ??\n sqsAttrs['correlationId']?.StringValue ??\n sqsAttrs['correlation_id']?.StringValue\n );\n }\n\n // AMQP / generic envelope\n return validIncomingId(message['correlationId'] ?? message['correlation_id']);\n}\n\n/**\n * Build Kafka message headers containing the current correlation context.\n *\n * @example\n * ```ts\n * import { buildKafkaCorrelationHeaders } from 'logixia/correlation';\n *\n * await producer.send({\n * topic: 'orders',\n * messages: [{ value: JSON.stringify(order), headers: buildKafkaCorrelationHeaders() }],\n * });\n * ```\n */\nexport function buildKafkaCorrelationHeaders(): Record<string, string> {\n const ctx = LogixiaContext.get();\n const headers: Record<string, string> = {};\n\n const correlationId = ctx?.correlationId as string | undefined;\n if (correlationId) headers['x-correlation-id'] = correlationId;\n\n const traceId = ctx?.traceId as string | undefined;\n if (traceId) headers['x-trace-id'] = traceId;\n\n return headers;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"correlation.mjs","names":[],"sources":["../src/correlation.ts"],"sourcesContent":["/**\n * logixia — Microservices Correlation ID Propagation\n *\n * Provides zero-boilerplate correlation ID generation and propagation for\n * distributed systems. A single correlation ID travels through every service\n * in a request fan-out, making it trivial to join logs across services.\n *\n * Features:\n * - UUID v4 correlation ID generation (via `crypto.randomUUID()`)\n * - Express / Fastify / NestJS incoming-request middleware\n * - `correlationFetch()` — wraps global `fetch`, auto-injects `X-Correlation-ID`\n * - `createCorrelationAxiosInterceptor()` — axios request interceptor\n * - `childFromRequest(req, logger)` — child logger with all request identifiers\n * - Kafka / SQS / RabbitMQ message context helpers\n * - Integration with `LogixiaContext` (AsyncLocalStorage) so every `logger.info()`\n * call automatically includes the correlationId without per-call passing.\n *\n * @example Express middleware\n * ```ts\n * import { correlationMiddleware } from 'logixia/correlation';\n * import { logger } from 'logixia';\n *\n * app.use(correlationMiddleware());\n *\n * app.get('/orders', (req, res) => {\n * // correlationId is automatically in every log inside this request\n * logger.info('Listing orders');\n * res.json({ ok: true });\n * });\n * ```\n *\n * @example Outbound fetch with correlation\n * ```ts\n * import { correlationFetch } from 'logixia/correlation';\n *\n * // Reads correlationId from current LogixiaContext and injects it as header\n * const data = await correlationFetch('https://payments.internal/charge', {\n * method: 'POST',\n * body: JSON.stringify({ amount: 100 }),\n * });\n * ```\n *\n * @example Manual correlation context\n * ```ts\n * import { withCorrelationId } from 'logixia/correlation';\n *\n * await withCorrelationId('trace-abc-123', async () => {\n * // All logs and outbound fetch calls in here carry 'trace-abc-123'\n * await processOrder();\n * });\n * ```\n */\n\nimport { randomUUID } from 'node:crypto';\n\nimport { LogixiaContext } from './context/async-context';\nimport type { HttpRequestShape, HttpResponseShape } from './types/http-shapes';\nimport { buildNameSet, DEFAULT_REDACT_QUERY_PARAMS, redactUrlQuery } from './utils/sensitive-names';\nimport { sanitizeIncomingId } from './utils/trace.utils';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/** Fields injected into the log context by the correlation middleware. */\nexport interface CorrelationContext {\n correlationId: string;\n traceId?: string;\n /** Service that originated the request (from `X-Origin-Service` header). */\n originService?: string;\n /** Index signature so CorrelationContext is assignable to LogContext. */\n [key: string]: unknown;\n}\n\nexport interface CorrelationMiddlewareOptions {\n /**\n * HTTP header to read/write the correlation ID from/to.\n * @default 'x-correlation-id'\n */\n header?: string;\n /**\n * HTTP header for the originating service name.\n * @default 'x-origin-service'\n */\n originServiceHeader?: string;\n /**\n * Function to generate a new correlation ID when none is present in the request.\n * @default () => crypto.randomUUID()\n */\n generate?: () => string;\n /**\n * When `false`, the incoming correlation header is ignored and a new ID is\n * always generated. Use this at the edge when client-supplied IDs should not\n * be trusted.\n * @default true\n */\n trustIncoming?: boolean;\n /**\n * When `true`, the response will include the correlation ID header so\n * clients can log it client-side.\n * @default true\n */\n setResponseHeader?: boolean;\n}\n\n// ── ID generation ─────────────────────────────────────────────────────────────\n\n/**\n * Generate a new correlation ID using `crypto.randomUUID()` (available in\n * Node.js 14.17+, all modern browsers, and Edge runtimes).\n *\n * When the Web Crypto global is unavailable (e.g. Node 18 without\n * `--experimental-global-webcrypto`), fall back to `node:crypto`'s\n * `randomUUID`, which returns a proper UUID v4 — matching the shape this\n * function's JSDoc and README promise. `logixia/correlation` is Node-only\n * (it builds on `AsyncLocalStorage`), so importing `node:crypto` is safe here.\n */\nexport function generateCorrelationId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return randomUUID();\n}\n\n/**\n * Return an incoming correlation ID only if it is short and made of safe\n * characters. Anything else (over-long, empty, or containing newlines or other\n * control characters) is dropped so the caller generates a fresh ID instead of\n * writing client-supplied text into every log line.\n */\nfunction validIncomingId(value: unknown): string | undefined {\n if (typeof value === 'string' && value.trim() !== value) return undefined;\n return sanitizeIncomingId(value);\n}\n\n// ── Context helpers ───────────────────────────────────────────────────────────\n\n/**\n * Return the correlation ID from the current `LogixiaContext`, or `undefined`\n * when called outside any context scope.\n */\nexport function getCurrentCorrelationId(): string | undefined {\n const ctx = LogixiaContext.get();\n return ctx?.correlationId as string | undefined;\n}\n\n/**\n * Run `callback` inside a correlation context scope.\n *\n * If a correlation ID is not provided, a new UUID is generated.\n *\n * @example\n * ```ts\n * await withCorrelationId('cid-abc', async () => {\n * logger.info('Processing message'); // → { correlationId: 'cid-abc', ... }\n * await callDownstream(); // correlationFetch() picks up cid-abc\n * });\n * ```\n */\nexport function withCorrelationId<T>(correlationId: string | undefined, callback: () => T): T {\n const id = correlationId ?? generateCorrelationId();\n return LogixiaContext.run({ correlationId: id }, callback);\n}\n\n// ── Express / Connect middleware ──────────────────────────────────────────────\n\n/**\n * Express-compatible middleware that:\n * 1. Reads `X-Correlation-ID` from the incoming request (or generates a new one)\n * 2. Wraps the request in a `LogixiaContext` so all loggers in the handler\n * automatically include `correlationId`\n * 3. Writes the correlation ID back to the response header (opt-out via options)\n *\n * @example\n * ```ts\n * import { correlationMiddleware } from 'logixia/correlation';\n * app.use(correlationMiddleware());\n * ```\n */\nexport function correlationMiddleware(options: CorrelationMiddlewareOptions = {}) {\n const {\n header = 'x-correlation-id',\n originServiceHeader = 'x-origin-service',\n generate = generateCorrelationId,\n trustIncoming = true,\n setResponseHeader = true,\n } = options;\n\n return function logixiaCorrelationMiddleware(\n req: HttpRequestShape,\n res: HttpResponseShape,\n next: () => void\n ): void {\n const headers = req.headers ?? {};\n\n // Node lower-cases incoming header names, so look up with lower-cased keys.\n const incomingId = trustIncoming ? validIncomingId(headers[header.toLowerCase()]) : undefined;\n const correlationId = incomingId ?? generate();\n const originService = validIncomingId(headers[originServiceHeader.toLowerCase()]);\n\n if (setResponseHeader) {\n res.setHeader?.(header, correlationId);\n }\n\n const ctx: CorrelationContext = {\n correlationId,\n ...(originService !== undefined ? { originService } : {}),\n };\n\n LogixiaContext.run(ctx, next);\n };\n}\n\n// ── Fastify hook ──────────────────────────────────────────────────────────────\n\n/**\n * Fastify `onRequest` lifecycle hook — same functionality as `correlationMiddleware`\n * but adapted to Fastify's hook API.\n *\n * @example\n * ```ts\n * import { correlationFastifyHook } from 'logixia/correlation';\n * fastify.addHook('onRequest', correlationFastifyHook());\n * ```\n */\nexport function correlationFastifyHook(options: CorrelationMiddlewareOptions = {}) {\n const {\n header = 'x-correlation-id',\n originServiceHeader = 'x-origin-service',\n generate = generateCorrelationId,\n trustIncoming = true,\n setResponseHeader = true,\n } = options;\n\n return function logixiaCorrelationFastifyHook(\n request: HttpRequestShape,\n reply: HttpResponseShape,\n done: () => void\n ): void {\n const headers = request.headers ?? {};\n\n // Node lower-cases incoming header names, so look up with lower-cased keys.\n const incomingId = trustIncoming ? validIncomingId(headers[header.toLowerCase()]) : undefined;\n const correlationId = incomingId ?? generate();\n const originService = validIncomingId(headers[originServiceHeader.toLowerCase()]);\n\n if (setResponseHeader) {\n reply.header?.(header, correlationId);\n }\n\n const ctx: CorrelationContext = {\n correlationId,\n ...(originService !== undefined ? { originService } : {}),\n };\n\n LogixiaContext.run(ctx, done);\n };\n}\n\n// ── Outbound fetch wrapper ────────────────────────────────────────────────────\n\n/**\n * A drop-in replacement for `fetch` that automatically injects the current\n * `correlationId` from `LogixiaContext` as an `X-Correlation-ID` request header.\n *\n * Falls back to the global `fetch` when no correlation context is active.\n *\n * @example\n * ```ts\n * import { correlationFetch } from 'logixia/correlation';\n *\n * // Inside a request handler with correlationMiddleware active:\n * const response = await correlationFetch('https://payments.internal/v1/charge', {\n * method: 'POST',\n * body: JSON.stringify({ amount: 100 }),\n * });\n * ```\n */\nexport async function correlationFetch(\n input: string | URL | Request,\n init: RequestInit = {},\n options: { header?: string } = {}\n): Promise<Response> {\n const header = options.header ?? 'x-correlation-id';\n const correlationId = getCurrentCorrelationId();\n\n // `init.headers` can be a plain object, a `Headers` instance, or an array of\n // `[name, value]` tuples. Spreading it into a plain object loses everything\n // but the object form: a `Headers` instance has no own enumerable properties,\n // and an array spread yields numeric indices. `Headers` accepts all three, is\n // case-insensitive, and is the shape `fetch` expects back.\n //\n // A `Request` carries headers of its own, and `fetch(request, { headers })`\n // replaces them rather than merging them, so they are seeded first and the\n // caller's `init.headers` is applied on top. Without this, accepting a\n // `Request` here would drop its headers, which is the same defect one input\n // shape over.\n const headers = new Headers(input instanceof Request ? input.headers : undefined);\n for (const [name, value] of new Headers(init.headers)) {\n headers.set(name, value);\n }\n if (correlationId && !headers.has(header)) {\n headers.set(header, correlationId);\n }\n\n return globalThis.fetch(input, { ...init, headers });\n}\n\n// ── Axios interceptor factory ─────────────────────────────────────────────────\n\n/**\n * Returns an axios request interceptor that automatically injects the current\n * correlation ID into outgoing axios requests.\n *\n * @example\n * ```ts\n * import axios from 'axios';\n * import { createCorrelationAxiosInterceptor } from 'logixia/correlation';\n *\n * axios.interceptors.request.use(createCorrelationAxiosInterceptor());\n * ```\n */\nexport function createCorrelationAxiosInterceptor(\n options: { header?: string } = {}\n): (config: Record<string, unknown>) => Record<string, unknown> {\n const header = options.header ?? 'x-correlation-id';\n\n return function correlationAxiosInterceptor(\n config: Record<string, unknown>\n ): Record<string, unknown> {\n const correlationId = getCurrentCorrelationId();\n if (!correlationId) return config;\n\n const headers = (config['headers'] ?? {}) as Record<string, unknown>;\n if (!headers[header]) {\n headers[header] = correlationId;\n }\n\n return { ...config, headers };\n };\n}\n\n// ── Child logger from request ─────────────────────────────────────────────────\n\nconst MAX_USER_AGENT_LENGTH = 512;\nconst MAX_IP_LENGTH = 64;\n\nexport interface ChildFromRequestOptions {\n /** Header to read the correlation ID from. @default 'x-correlation-id' */\n correlationHeader?: string;\n /**\n * Take the client IP from the first `X-Forwarded-For` entry. Only enable this\n * when the app sits behind a proxy that overwrites the header; otherwise any\n * client can choose the logged IP.\n * @default false\n */\n trustProxy?: boolean;\n /**\n * Context name passed as the first argument to `logger.child(context, data)`.\n * When omitted, logixia loggers (detected by their `getContext` /\n * `getAvailableTransports` methods) get `child('request', fields)` and any other\n * logger gets `child(fields)`.\n */\n childContext?: string;\n /**\n * Extra query parameter names redacted in the bound `url` field, on top of the\n * defaults (`token`, `code`, `password`, `api_key`, …). A bare logger exposes no\n * `redact.queryParams`, so pass the same list you gave `LoggerConfig.redact`.\n */\n redactQueryParams?: readonly string[];\n}\n\n/**\n * Create a child logger enriched with all correlation-relevant identifiers\n * extracted from the incoming HTTP request.\n *\n * The child logger's every call automatically includes:\n * `correlationId`, `method`, `url`, `userAgent`, `ip`\n *\n * The IP comes from `req.ip` / the socket address unless `trustProxy` is set.\n *\n * @example\n * ```ts\n * import { childFromRequest } from 'logixia/correlation';\n * import { logger } from 'logixia';\n *\n * app.use((req, res, next) => {\n * req.logger = childFromRequest(req, logger);\n * next();\n * });\n *\n * app.get('/orders', (req, res) => {\n * req.logger.info('Listing orders'); // → correlationId, requestId, method, url ...\n * });\n * ```\n */\nexport function childFromRequest<TLogger extends { child(...args: never[]): TLogger }>(\n req: HttpRequestShape,\n logger: TLogger,\n options: ChildFromRequestOptions = {}\n): TLogger {\n const correlationHeader = options.correlationHeader ?? 'x-correlation-id';\n\n const headers = req.headers ?? {};\n // Node lower-cases incoming header names, so look up with a lower-cased key.\n const correlationId =\n validIncomingId(headers[correlationHeader.toLowerCase()]) ??\n getCurrentCorrelationId() ??\n generateCorrelationId();\n\n const method = req.method;\n const rawUrl = req.originalUrl ?? req.url;\n const url =\n rawUrl === undefined\n ? undefined\n : redactUrlQuery(\n rawUrl,\n buildNameSet(DEFAULT_REDACT_QUERY_PARAMS, options.redactQueryParams)\n );\n const rawUserAgent = headers['user-agent'];\n const userAgent =\n typeof rawUserAgent === 'string' ? rawUserAgent.slice(0, MAX_USER_AGENT_LENGTH) : undefined;\n const ip = resolveClientIp(req, headers, options.trustProxy === true);\n\n const fields = {\n correlationId,\n ...(method !== undefined ? { method } : {}),\n ...(url !== undefined ? { url } : {}),\n ...(userAgent !== undefined ? { userAgent } : {}),\n ...(ip !== undefined ? { ip } : {}),\n };\n\n const child = logger.child as (...args: unknown[]) => TLogger;\n if (options.childContext !== undefined) {\n return child.call(logger, options.childContext, fields);\n }\n // logixia's ILogger.child(context: string, data?) takes a string namespace;\n // pino/winston-style loggers take a bindings object.\n if (usesStringContext(logger)) {\n return child.call(logger, 'request', fields);\n }\n return child.call(logger, fields);\n}\n\n/** ILogger implementations (LogixiaLogger, LogixiaLoggerService, mock logger) expose these methods. */\nfunction usesStringContext(logger: object): boolean {\n const l = logger as Record<string, unknown>;\n return typeof l['getContext'] === 'function' || typeof l['getAvailableTransports'] === 'function';\n}\n\nfunction resolveClientIp(\n req: HttpRequestShape,\n headers: Record<string, string | string[] | undefined>,\n trustProxy: boolean\n): string | undefined {\n if (trustProxy) {\n const forwarded = headers['x-forwarded-for'];\n const first = typeof forwarded === 'string' ? forwarded.split(',')[0]?.trim() : undefined;\n if (first) return first.slice(0, MAX_IP_LENGTH);\n }\n const fromReq = req.ip;\n if (typeof fromReq === 'string' && fromReq) return fromReq.slice(0, MAX_IP_LENGTH);\n const remote = req.socket?.remoteAddress;\n return typeof remote === 'string' ? remote.slice(0, MAX_IP_LENGTH) : undefined;\n}\n\n// ── Message queue helpers ─────────────────────────────────────────────────────\n\n/**\n * Extract a correlation context from a Kafka / RabbitMQ / SQS message object.\n *\n * Looks for `correlationId`, `correlation_id`, or `x-correlation-id` in\n * `message.headers` (Kafka) or `message.MessageAttributes` (SQS).\n *\n * @example Kafka consumer\n * ```ts\n * import { extractMessageCorrelationId, withCorrelationId } from 'logixia/correlation';\n *\n * consumer.run({\n * eachMessage: async ({ message }) => {\n * const correlationId = extractMessageCorrelationId(message);\n * await withCorrelationId(correlationId, () => processMessage(message));\n * },\n * });\n * ```\n */\nexport function extractMessageCorrelationId(message: Record<string, unknown>): string | undefined {\n // Kafka: message.headers is Record<string, Buffer | string>\n const kafkaHeaders = message['headers'] as Record<string, Buffer | string> | undefined;\n if (kafkaHeaders) {\n const raw =\n kafkaHeaders['x-correlation-id'] ??\n kafkaHeaders['correlationId'] ??\n kafkaHeaders['correlation_id'];\n if (raw !== undefined) {\n return validIncomingId(Buffer.isBuffer(raw) ? raw.toString('utf8', 0, 512) : String(raw));\n }\n }\n\n // SQS: message.MessageAttributes\n const sqsAttrs = message['MessageAttributes'] as\n Record<string, { StringValue?: string }> | undefined;\n if (sqsAttrs) {\n return validIncomingId(\n sqsAttrs['x-correlation-id']?.StringValue ??\n sqsAttrs['correlationId']?.StringValue ??\n sqsAttrs['correlation_id']?.StringValue\n );\n }\n\n // AMQP / generic envelope\n return validIncomingId(message['correlationId'] ?? message['correlation_id']);\n}\n\n/**\n * Build Kafka message headers containing the current correlation context.\n *\n * @example\n * ```ts\n * import { buildKafkaCorrelationHeaders } from 'logixia/correlation';\n *\n * await producer.send({\n * topic: 'orders',\n * messages: [{ value: JSON.stringify(order), headers: buildKafkaCorrelationHeaders() }],\n * });\n * ```\n */\nexport function buildKafkaCorrelationHeaders(): Record<string, string> {\n const ctx = LogixiaContext.get();\n const headers: Record<string, string> = {};\n\n const correlationId = ctx?.correlationId as string | undefined;\n if (correlationId) headers['x-correlation-id'] = correlationId;\n\n const traceId = ctx?.traceId as string | undefined;\n if (traceId) headers['x-trace-id'] = traceId;\n\n return headers;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_sensitive_names = require("./sensitive-names-CHMowujD.js");
|
|
2
2
|
// src/transports/entry-fields.ts
|
|
3
3
|
const PAYLOAD_PREFIX = "data_";
|
|
4
4
|
/**
|
|
@@ -19,7 +19,7 @@ function mergeCoreFields(core, data, extraReserved = []) {
|
|
|
19
19
|
const reserved = /* @__PURE__ */ new Set([...Object.keys(core), ...extraReserved]);
|
|
20
20
|
const payloadKeys = new Set(Object.keys(data));
|
|
21
21
|
for (const key of payloadKeys) {
|
|
22
|
-
if (
|
|
22
|
+
if (require_sensitive_names.isProtoKey(key)) continue;
|
|
23
23
|
if (key === "traceId" && core["traceId"] !== void 0 && data[key] === core["traceId"]) continue;
|
|
24
24
|
let target = key;
|
|
25
25
|
if (reserved.has(target)) do
|
|
@@ -36,4 +36,4 @@ Object.defineProperty(exports, "mergeCoreFields", {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
//# sourceMappingURL=entry-fields-
|
|
39
|
+
//# sourceMappingURL=entry-fields-CVwoQplO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-fields-
|
|
1
|
+
{"version":3,"file":"entry-fields-CVwoQplO.js","names":["isProtoKey"],"sources":["../src/transports/entry-fields.ts"],"sourcesContent":["import { isProtoKey } from '../utils/own-property';\n\nconst PAYLOAD_PREFIX = 'data_';\n\n/**\n * Copies `core` and then the user payload into one object. The core fields stay\n * authoritative: a payload key that matches a core key (even one whose value is\n * undefined) or a reserved name is kept under a `data_` prefix instead. The\n * prefix is repeated until the name is free of core keys and of every other\n * payload key, so the result does not depend on key order and a payload's own\n * `data_level` stays where it is.\n *\n * Exception: a payload `traceId` equal to the core `traceId` is a duplicate (the\n * context middleware copies the trace id into the payload) and is dropped rather\n * than emitted again as `data_traceId`. A different value is still kept.\n */\nexport function mergeCoreFields(\n core: Record<string, unknown>,\n data: Record<string, unknown> | undefined,\n extraReserved: readonly string[] = []\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...core };\n if (!data) return merged;\n const reserved = new Set([...Object.keys(core), ...extraReserved]);\n const payloadKeys = new Set(Object.keys(data));\n for (const key of payloadKeys) {\n if (isProtoKey(key)) continue;\n if (key === 'traceId' && core['traceId'] !== undefined && data[key] === core['traceId'])\n continue;\n let target = key;\n if (reserved.has(target)) {\n do {\n target = `${PAYLOAD_PREFIX}${target}`;\n } while (reserved.has(target) || payloadKeys.has(target));\n }\n merged[target] = data[key];\n }\n return merged;\n}\n"],"mappings":";;AAEA,MAAM,iBAAiB;;;;;;;;;;;;;AAcvB,SAAgB,gBACd,MACA,MACA,gBAAmC,CAAC,GACX;CACzB,MAAM,SAAkC,EAAE,GAAG,KAAK;CAClD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,2BAAW,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,aAAa,CAAC;CACjE,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;CAC7C,KAAK,MAAM,OAAO,aAAa;EAC7B,IAAIA,wBAAAA,WAAW,GAAG,GAAG;EACrB,IAAI,QAAQ,aAAa,KAAK,eAAe,KAAA,KAAa,KAAK,SAAS,KAAK,YAC3E;EACF,IAAI,SAAS;EACb,IAAI,SAAS,IAAI,MAAM,GACrB;GACE,SAAS,GAAG,iBAAiB;SACtB,SAAS,IAAI,MAAM,KAAK,YAAY,IAAI,MAAM;EAEzD,OAAO,UAAU,KAAK;CACxB;CACA,OAAO;AACT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { u as isProtoKey } from "./sensitive-names-o__1PUUR.mjs";
|
|
2
2
|
// src/transports/entry-fields.ts
|
|
3
3
|
const PAYLOAD_PREFIX = "data_";
|
|
4
4
|
/**
|
|
@@ -31,4 +31,4 @@ function mergeCoreFields(core, data, extraReserved = []) {
|
|
|
31
31
|
}
|
|
32
32
|
export { mergeCoreFields as t };
|
|
33
33
|
|
|
34
|
-
//# sourceMappingURL=entry-fields-
|
|
34
|
+
//# sourceMappingURL=entry-fields-DNTKQxoU.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-fields-
|
|
1
|
+
{"version":3,"file":"entry-fields-DNTKQxoU.mjs","names":[],"sources":["../src/transports/entry-fields.ts"],"sourcesContent":["import { isProtoKey } from '../utils/own-property';\n\nconst PAYLOAD_PREFIX = 'data_';\n\n/**\n * Copies `core` and then the user payload into one object. The core fields stay\n * authoritative: a payload key that matches a core key (even one whose value is\n * undefined) or a reserved name is kept under a `data_` prefix instead. The\n * prefix is repeated until the name is free of core keys and of every other\n * payload key, so the result does not depend on key order and a payload's own\n * `data_level` stays where it is.\n *\n * Exception: a payload `traceId` equal to the core `traceId` is a duplicate (the\n * context middleware copies the trace id into the payload) and is dropped rather\n * than emitted again as `data_traceId`. A different value is still kept.\n */\nexport function mergeCoreFields(\n core: Record<string, unknown>,\n data: Record<string, unknown> | undefined,\n extraReserved: readonly string[] = []\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...core };\n if (!data) return merged;\n const reserved = new Set([...Object.keys(core), ...extraReserved]);\n const payloadKeys = new Set(Object.keys(data));\n for (const key of payloadKeys) {\n if (isProtoKey(key)) continue;\n if (key === 'traceId' && core['traceId'] !== undefined && data[key] === core['traceId'])\n continue;\n let target = key;\n if (reserved.has(target)) {\n do {\n target = `${PAYLOAD_PREFIX}${target}`;\n } while (reserved.has(target) || payloadKeys.has(target));\n }\n merged[target] = data[key];\n }\n return merged;\n}\n"],"mappings":";;AAEA,MAAM,iBAAiB;;;;;;;;;;;;;AAcvB,SAAgB,gBACd,MACA,MACA,gBAAmC,CAAC,GACX;CACzB,MAAM,SAAkC,EAAE,GAAG,KAAK;CAClD,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,2BAAW,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,aAAa,CAAC;CACjE,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;CAC7C,KAAK,MAAM,OAAO,aAAa;EAC7B,IAAI,WAAW,GAAG,GAAG;EACrB,IAAI,QAAQ,aAAa,KAAK,eAAe,KAAA,KAAa,KAAK,SAAS,KAAK,YAC3E;EACF,IAAI,SAAS;EACb,IAAI,SAAS,IAAI,MAAM,GACrB;GACE,SAAS,GAAG,iBAAiB;SACtB,SAAS,IAAI,MAAM,KAAK,YAAY,IAAI,MAAM;EAEzD,OAAO,UAAU,KAAK;CACxB;CACA,OAAO;AACT"}
|
package/dist/gcp.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_gcp_transport = require("./gcp.transport-
|
|
2
|
+
const require_gcp_transport = require("./gcp.transport-CVuRpchl.js");
|
|
3
3
|
exports.GCPTransport = require_gcp_transport.GCPTransport;
|
package/dist/gcp.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as GCPTransport } from "./gcp.transport-
|
|
1
|
+
export { t as GCPTransport } from "./gcp.transport-LLK2bw2-.mjs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const require_secret_config = require("./secret-config-
|
|
2
|
-
const require_internal_log = require("./internal-log-
|
|
3
|
-
const require_safe_stringify = require("./safe-stringify-
|
|
4
|
-
const require_entry_fields = require("./entry-fields-
|
|
5
|
-
const require_batch_buffer = require("./batch-buffer-
|
|
1
|
+
const require_secret_config = require("./secret-config-BvFl2dC8.js");
|
|
2
|
+
const require_internal_log = require("./internal-log-DwqTjhpb.js");
|
|
3
|
+
const require_safe_stringify = require("./safe-stringify-CN7icp8S.js");
|
|
4
|
+
const require_entry_fields = require("./entry-fields-CVwoQplO.js");
|
|
5
|
+
const require_batch_buffer = require("./batch-buffer-CFzKnuNZ.js");
|
|
6
6
|
let node_https = require("node:https");
|
|
7
7
|
node_https = require_secret_config.__toESM(node_https);
|
|
8
8
|
// src/transports/gcp.transport.ts
|
|
@@ -237,4 +237,4 @@ Object.defineProperty(exports, "GCPTransport", {
|
|
|
237
237
|
}
|
|
238
238
|
});
|
|
239
239
|
|
|
240
|
-
//# sourceMappingURL=gcp.transport-
|
|
240
|
+
//# sourceMappingURL=gcp.transport-CVuRpchl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcp.transport-Dy2Lf8FI.js","names":["BatchBuffer","mergeCoreFields","https","httpRequest","stringifyForLog"],"sources":["../src/transports/gcp.transport.ts"],"sourcesContent":["/**\n * logixia — Google Cloud Logging (Stackdriver) transport\n *\n * Maps logixia log entries to the GCP Logging REST API format:\n * - Maps `level` → `severity` (INFO, WARNING, ERROR, CRITICAL…)\n * - Injects `logging.googleapis.com/trace` for Cloud Trace correlation\n * - Sets `traceSampled: true` whenever a trace id is present\n * (`logging.googleapis.com/spanId` and `sourceLocation` are not populated)\n * - Supports structured `jsonPayload` and plain `textPayload`\n *\n * Auth: the metadata server on GCE/GKE/Cloud Run, or a service-account key passed\n * as `credentials`. The `GOOGLE_APPLICATION_CREDENTIALS` key-file variable is not\n * read; full ADC is not supported.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { GCPTransport } from 'logixia/gcp';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new GCPTransport({\n * projectId: process.env.GOOGLE_CLOUD_PROJECT,\n * logName: 'projects/my-project/logs/api',\n * resource: { type: 'gce_instance', labels: { instance_id: '123' } },\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport * as https from 'node:https';\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n httpRequest,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets } from './secret-config';\n\nexport interface GCPMonitoredResource {\n type: string;\n labels?: Record<string, string>;\n}\n\nexport interface GCPTransportConfig {\n /** GCP project ID. Falls back to `GOOGLE_CLOUD_PROJECT` or `GCLOUD_PROJECT` env vars. */\n projectId?: string;\n /**\n * Full log name, e.g. `'projects/my-project/logs/api'`.\n * If omitted, defaults to `projects/{projectId}/logs/logixia`.\n */\n logName?: string;\n /** Monitored resource descriptor. Defaults to `global`. */\n resource?: GCPMonitoredResource;\n /**\n * Service account key JSON (parsed). If omitted, only the metadata server\n * (GCE/GKE/Cloud Run) is tried; the key-file env var is not read.\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n /** Number of entries to batch. @default 200 */\n batchSize?: number;\n /** Flush interval in ms. @default 5000 */\n flushIntervalMs?: number;\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered entries; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n level?: string;\n}\n\ntype GcpSeverity =\n | 'DEFAULT'\n | 'DEBUG'\n | 'INFO'\n | 'NOTICE'\n | 'WARNING'\n | 'ERROR'\n | 'CRITICAL'\n | 'ALERT'\n | 'EMERGENCY';\n\nfunction toGcpSeverity(level: string): GcpSeverity {\n switch (level.toLowerCase()) {\n case 'trace':\n case 'verbose':\n case 'debug':\n return 'DEBUG';\n case 'info':\n case 'log':\n return 'INFO';\n case 'warn':\n case 'warning':\n return 'WARNING';\n case 'error':\n return 'ERROR';\n case 'critical':\n case 'fatal':\n return 'CRITICAL';\n default:\n return 'DEFAULT';\n }\n}\n\n/**\n * Google Cloud Logging transport with trace correlation and GCP severity mapping.\n */\nexport class GCPTransport implements IAsyncTransport {\n public readonly name = 'gcp';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<TransportLogEntry>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private accessToken: string | null = null;\n private tokenExpiry = 0;\n\n private readonly projectId: string;\n private readonly logName: string;\n private readonly resource: GCPMonitoredResource;\n private readonly credentials: { client_email: string; private_key: string } | undefined;\n\n constructor(config: GCPTransportConfig) {\n protectSecrets(this, ['credentials', 'accessToken']);\n this.projectId =\n config.projectId ??\n process.env['GOOGLE_CLOUD_PROJECT'] ??\n process.env['GCLOUD_PROJECT'] ??\n 'unknown-project';\n this.logName = config.logName ?? `projects/${this.projectId}/logs/logixia`;\n this.resource = config.resource ?? { type: 'global' };\n this.credentials = config.credentials;\n this.batchSize = config.batchSize ?? 200;\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<TransportLogEntry>({\n name: 'GCPTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (entries) => this.writeEntries(entries),\n secrets: () => this.secretValues(),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n }\n\n write(entry: TransportLogEntry): void {\n this.buffer.push(entry);\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining entries and stop the interval timer on shutdown. Without\n * this the manager's close() skipped the transport (close was undefined) and\n * buffered entries were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private buildLogEntry(entry: TransportLogEntry): Record<string, unknown> {\n const gcpEntry: Record<string, unknown> = {\n logName: this.logName,\n resource: this.resource,\n severity: toGcpSeverity(entry.level),\n timestamp: entry.timestamp ?? new Date().toISOString(),\n jsonPayload: mergeCoreFields(\n { message: entry.message, appName: entry.appName, context: entry.context },\n entry.data\n ),\n };\n\n // GCP Cloud Trace correlation\n if (entry.traceId) {\n gcpEntry['trace'] = `projects/${this.projectId}/traces/${entry.traceId}`;\n gcpEntry['traceSampled'] = true;\n }\n\n return gcpEntry;\n }\n\n private async getAccessToken(): Promise<string | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;\n\n // Try ADC metadata server (GCE/GKE/Cloud Run)\n try {\n const token = await this.fetchFromMetadataServer();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000; // 55 minutes\n return this.accessToken;\n }\n } catch {\n /* fall through to service account */\n }\n\n // Try service account key\n if (this.credentials) {\n try {\n const token = await this.fetchServiceAccountToken();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n return this.accessToken;\n }\n } catch (err) {\n internalError('GCPTransport service account token error', err);\n }\n }\n\n return null;\n }\n\n private fetchFromMetadataServer(): Promise<string | null> {\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n hostname: 'metadata.google.internal',\n path: '/computeMetadata/v1/instance/service-accounts/default/token',\n headers: { 'Metadata-Flavor': 'Google' },\n timeout: 3000,\n },\n (res) => {\n let raw = '';\n res.on('data', (c: Buffer) => (raw += c.toString()));\n res.on('end', () => {\n if (res.statusCode === 200) {\n try {\n const parsed = JSON.parse(raw) as { access_token?: string };\n resolve(parsed.access_token ?? null);\n } catch {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n });\n }\n );\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('metadata timeout'));\n });\n req.end();\n });\n }\n\n private fetchServiceAccountToken(): Promise<string | null> {\n // Minimal JWT creation for service account — only for environments without\n // the full Google Auth Library. For production workloads, prefer ADC.\n if (!this.credentials) return Promise.resolve(null);\n\n const iat = Math.floor(Date.now() / 1000);\n const exp = iat + 3600;\n const scope = 'https://www.googleapis.com/auth/logging.write';\n\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');\n const payload = Buffer.from(\n JSON.stringify({\n iss: this.credentials.client_email,\n scope,\n aud: 'https://oauth2.googleapis.com/token',\n exp,\n iat,\n })\n ).toString('base64url');\n\n const signingInput = `${header}.${payload}`;\n\n let signature: string;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const sign = require('node:crypto').createSign('RSA-SHA256');\n sign.update(signingInput);\n signature = sign.sign(this.credentials.private_key, 'base64url') as string;\n } catch {\n return Promise.resolve(null);\n }\n\n const jwt = `${signingInput}.${signature}`;\n const body = `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`;\n\n return httpRequest({\n url: new URL('https://oauth2.googleapis.com/token'),\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP token request',\n }).then(\n (res) => (JSON.parse(res.body) as { access_token?: string }).access_token ?? null,\n () => null\n );\n }\n\n private secretValues(token?: string): (string | undefined)[] {\n return [\n ...(this.credentials?.private_key.split('\\n') ?? []),\n this.credentials?.private_key,\n this.accessToken ?? undefined,\n token,\n ];\n }\n\n private async writeEntries(entries: TransportLogEntry[]): Promise<void> {\n const token = await this.getAccessToken();\n if (!token) {\n throw new Error('GCPTransport: no access token available');\n }\n\n const body = stringifyForLog({\n logName: this.logName,\n resource: this.resource,\n entries: entries.map((e) => this.buildLogEntry(e)),\n });\n\n await httpRequest({\n url: new URL('https://logging.googleapis.com/v2/entries:write'),\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP Logging API',\n secrets: () => this.secretValues(token),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gcp.transport-CVuRpchl.js","names":["BatchBuffer","mergeCoreFields","https","httpRequest","stringifyForLog"],"sources":["../src/transports/gcp.transport.ts"],"sourcesContent":["/**\n * logixia — Google Cloud Logging (Stackdriver) transport\n *\n * Maps logixia log entries to the GCP Logging REST API format:\n * - Maps `level` → `severity` (INFO, WARNING, ERROR, CRITICAL…)\n * - Injects `logging.googleapis.com/trace` for Cloud Trace correlation\n * - Sets `traceSampled: true` whenever a trace id is present\n * (`logging.googleapis.com/spanId` and `sourceLocation` are not populated)\n * - Supports structured `jsonPayload` and plain `textPayload`\n *\n * Auth: the metadata server on GCE/GKE/Cloud Run, or a service-account key passed\n * as `credentials`. The `GOOGLE_APPLICATION_CREDENTIALS` key-file variable is not\n * read; full ADC is not supported.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { GCPTransport } from 'logixia/gcp';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new GCPTransport({\n * projectId: process.env.GOOGLE_CLOUD_PROJECT,\n * logName: 'projects/my-project/logs/api',\n * resource: { type: 'gce_instance', labels: { instance_id: '123' } },\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport * as https from 'node:https';\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n httpRequest,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets } from './secret-config';\n\nexport interface GCPMonitoredResource {\n type: string;\n labels?: Record<string, string>;\n}\n\nexport interface GCPTransportConfig {\n /** GCP project ID. Falls back to `GOOGLE_CLOUD_PROJECT` or `GCLOUD_PROJECT` env vars. */\n projectId?: string;\n /**\n * Full log name, e.g. `'projects/my-project/logs/api'`.\n * If omitted, defaults to `projects/{projectId}/logs/logixia`.\n */\n logName?: string;\n /** Monitored resource descriptor. Defaults to `global`. */\n resource?: GCPMonitoredResource;\n /**\n * Service account key JSON (parsed). If omitted, only the metadata server\n * (GCE/GKE/Cloud Run) is tried; the key-file env var is not read.\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n /** Number of entries to batch. @default 200 */\n batchSize?: number;\n /** Flush interval in ms. @default 5000 */\n flushIntervalMs?: number;\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered entries; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n level?: string;\n}\n\ntype GcpSeverity =\n | 'DEFAULT'\n | 'DEBUG'\n | 'INFO'\n | 'NOTICE'\n | 'WARNING'\n | 'ERROR'\n | 'CRITICAL'\n | 'ALERT'\n | 'EMERGENCY';\n\nfunction toGcpSeverity(level: string): GcpSeverity {\n switch (level.toLowerCase()) {\n case 'trace':\n case 'verbose':\n case 'debug':\n return 'DEBUG';\n case 'info':\n case 'log':\n return 'INFO';\n case 'warn':\n case 'warning':\n return 'WARNING';\n case 'error':\n return 'ERROR';\n case 'critical':\n case 'fatal':\n return 'CRITICAL';\n default:\n return 'DEFAULT';\n }\n}\n\n/**\n * Google Cloud Logging transport with trace correlation and GCP severity mapping.\n */\nexport class GCPTransport implements IAsyncTransport {\n public readonly name = 'gcp';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<TransportLogEntry>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private accessToken: string | null = null;\n private tokenExpiry = 0;\n\n private readonly projectId: string;\n private readonly logName: string;\n private readonly resource: GCPMonitoredResource;\n private readonly credentials: { client_email: string; private_key: string } | undefined;\n\n constructor(config: GCPTransportConfig) {\n protectSecrets(this, ['credentials', 'accessToken']);\n this.projectId =\n config.projectId ??\n process.env['GOOGLE_CLOUD_PROJECT'] ??\n process.env['GCLOUD_PROJECT'] ??\n 'unknown-project';\n this.logName = config.logName ?? `projects/${this.projectId}/logs/logixia`;\n this.resource = config.resource ?? { type: 'global' };\n this.credentials = config.credentials;\n this.batchSize = config.batchSize ?? 200;\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<TransportLogEntry>({\n name: 'GCPTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (entries) => this.writeEntries(entries),\n secrets: () => this.secretValues(),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n }\n\n write(entry: TransportLogEntry): void {\n this.buffer.push(entry);\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining entries and stop the interval timer on shutdown. Without\n * this the manager's close() skipped the transport (close was undefined) and\n * buffered entries were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private buildLogEntry(entry: TransportLogEntry): Record<string, unknown> {\n const gcpEntry: Record<string, unknown> = {\n logName: this.logName,\n resource: this.resource,\n severity: toGcpSeverity(entry.level),\n timestamp: entry.timestamp ?? new Date().toISOString(),\n jsonPayload: mergeCoreFields(\n { message: entry.message, appName: entry.appName, context: entry.context },\n entry.data\n ),\n };\n\n // GCP Cloud Trace correlation\n if (entry.traceId) {\n gcpEntry['trace'] = `projects/${this.projectId}/traces/${entry.traceId}`;\n gcpEntry['traceSampled'] = true;\n }\n\n return gcpEntry;\n }\n\n private async getAccessToken(): Promise<string | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;\n\n // Try ADC metadata server (GCE/GKE/Cloud Run)\n try {\n const token = await this.fetchFromMetadataServer();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000; // 55 minutes\n return this.accessToken;\n }\n } catch {\n /* fall through to service account */\n }\n\n // Try service account key\n if (this.credentials) {\n try {\n const token = await this.fetchServiceAccountToken();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n return this.accessToken;\n }\n } catch (err) {\n internalError('GCPTransport service account token error', err);\n }\n }\n\n return null;\n }\n\n private fetchFromMetadataServer(): Promise<string | null> {\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n hostname: 'metadata.google.internal',\n path: '/computeMetadata/v1/instance/service-accounts/default/token',\n headers: { 'Metadata-Flavor': 'Google' },\n timeout: 3000,\n },\n (res) => {\n let raw = '';\n res.on('data', (c: Buffer) => (raw += c.toString()));\n res.on('end', () => {\n if (res.statusCode === 200) {\n try {\n const parsed = JSON.parse(raw) as { access_token?: string };\n resolve(parsed.access_token ?? null);\n } catch {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n });\n }\n );\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('metadata timeout'));\n });\n req.end();\n });\n }\n\n private fetchServiceAccountToken(): Promise<string | null> {\n // Minimal JWT creation for service account — only for environments without\n // the full Google Auth Library. For production workloads, prefer ADC.\n if (!this.credentials) return Promise.resolve(null);\n\n const iat = Math.floor(Date.now() / 1000);\n const exp = iat + 3600;\n const scope = 'https://www.googleapis.com/auth/logging.write';\n\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');\n const payload = Buffer.from(\n JSON.stringify({\n iss: this.credentials.client_email,\n scope,\n aud: 'https://oauth2.googleapis.com/token',\n exp,\n iat,\n })\n ).toString('base64url');\n\n const signingInput = `${header}.${payload}`;\n\n let signature: string;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const sign = require('node:crypto').createSign('RSA-SHA256');\n sign.update(signingInput);\n signature = sign.sign(this.credentials.private_key, 'base64url') as string;\n } catch {\n return Promise.resolve(null);\n }\n\n const jwt = `${signingInput}.${signature}`;\n const body = `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`;\n\n return httpRequest({\n url: new URL('https://oauth2.googleapis.com/token'),\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP token request',\n }).then(\n (res) => (JSON.parse(res.body) as { access_token?: string }).access_token ?? null,\n () => null\n );\n }\n\n private secretValues(token?: string): (string | undefined)[] {\n return [\n ...(this.credentials?.private_key.split('\\n') ?? []),\n this.credentials?.private_key,\n this.accessToken ?? undefined,\n token,\n ];\n }\n\n private async writeEntries(entries: TransportLogEntry[]): Promise<void> {\n const token = await this.getAccessToken();\n if (!token) {\n throw new Error('GCPTransport: no access token available');\n }\n\n const body = stringifyForLog({\n logName: this.logName,\n resource: this.resource,\n entries: entries.map((e) => this.buildLogEntry(e)),\n });\n\n await httpRequest({\n url: new URL('https://logging.googleapis.com/v2/entries:write'),\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP Logging API',\n secrets: () => this.secretValues(token),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __require } from "./rolldown-runtime-D3PmRqjj.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as stringifyForLog } from "./safe-stringify
|
|
5
|
-
import { t as mergeCoreFields } from "./entry-fields-
|
|
6
|
-
import { a as httpRequest, t as BatchBuffer } from "./batch-buffer-
|
|
2
|
+
import { n as protectSecrets } from "./secret-config-ByGq7kJd.mjs";
|
|
3
|
+
import { t as internalError } from "./internal-log-Cy5nF1ZL.mjs";
|
|
4
|
+
import { i as stringifyForLog } from "./safe-stringify--7gbe95n.mjs";
|
|
5
|
+
import { t as mergeCoreFields } from "./entry-fields-DNTKQxoU.mjs";
|
|
6
|
+
import { a as httpRequest, t as BatchBuffer } from "./batch-buffer-CQUWDMYq.mjs";
|
|
7
7
|
import * as https from "node:https";
|
|
8
8
|
// src/transports/gcp.transport.ts
|
|
9
9
|
/**
|
|
@@ -232,4 +232,4 @@ var GCPTransport = class {
|
|
|
232
232
|
};
|
|
233
233
|
export { GCPTransport as t };
|
|
234
234
|
|
|
235
|
-
//# sourceMappingURL=gcp.transport-
|
|
235
|
+
//# sourceMappingURL=gcp.transport-LLK2bw2-.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcp.transport-DVCmnA3b.mjs","names":[],"sources":["../src/transports/gcp.transport.ts"],"sourcesContent":["/**\n * logixia — Google Cloud Logging (Stackdriver) transport\n *\n * Maps logixia log entries to the GCP Logging REST API format:\n * - Maps `level` → `severity` (INFO, WARNING, ERROR, CRITICAL…)\n * - Injects `logging.googleapis.com/trace` for Cloud Trace correlation\n * - Sets `traceSampled: true` whenever a trace id is present\n * (`logging.googleapis.com/spanId` and `sourceLocation` are not populated)\n * - Supports structured `jsonPayload` and plain `textPayload`\n *\n * Auth: the metadata server on GCE/GKE/Cloud Run, or a service-account key passed\n * as `credentials`. The `GOOGLE_APPLICATION_CREDENTIALS` key-file variable is not\n * read; full ADC is not supported.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { GCPTransport } from 'logixia/gcp';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new GCPTransport({\n * projectId: process.env.GOOGLE_CLOUD_PROJECT,\n * logName: 'projects/my-project/logs/api',\n * resource: { type: 'gce_instance', labels: { instance_id: '123' } },\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport * as https from 'node:https';\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n httpRequest,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets } from './secret-config';\n\nexport interface GCPMonitoredResource {\n type: string;\n labels?: Record<string, string>;\n}\n\nexport interface GCPTransportConfig {\n /** GCP project ID. Falls back to `GOOGLE_CLOUD_PROJECT` or `GCLOUD_PROJECT` env vars. */\n projectId?: string;\n /**\n * Full log name, e.g. `'projects/my-project/logs/api'`.\n * If omitted, defaults to `projects/{projectId}/logs/logixia`.\n */\n logName?: string;\n /** Monitored resource descriptor. Defaults to `global`. */\n resource?: GCPMonitoredResource;\n /**\n * Service account key JSON (parsed). If omitted, only the metadata server\n * (GCE/GKE/Cloud Run) is tried; the key-file env var is not read.\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n /** Number of entries to batch. @default 200 */\n batchSize?: number;\n /** Flush interval in ms. @default 5000 */\n flushIntervalMs?: number;\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered entries; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n level?: string;\n}\n\ntype GcpSeverity =\n | 'DEFAULT'\n | 'DEBUG'\n | 'INFO'\n | 'NOTICE'\n | 'WARNING'\n | 'ERROR'\n | 'CRITICAL'\n | 'ALERT'\n | 'EMERGENCY';\n\nfunction toGcpSeverity(level: string): GcpSeverity {\n switch (level.toLowerCase()) {\n case 'trace':\n case 'verbose':\n case 'debug':\n return 'DEBUG';\n case 'info':\n case 'log':\n return 'INFO';\n case 'warn':\n case 'warning':\n return 'WARNING';\n case 'error':\n return 'ERROR';\n case 'critical':\n case 'fatal':\n return 'CRITICAL';\n default:\n return 'DEFAULT';\n }\n}\n\n/**\n * Google Cloud Logging transport with trace correlation and GCP severity mapping.\n */\nexport class GCPTransport implements IAsyncTransport {\n public readonly name = 'gcp';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<TransportLogEntry>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private accessToken: string | null = null;\n private tokenExpiry = 0;\n\n private readonly projectId: string;\n private readonly logName: string;\n private readonly resource: GCPMonitoredResource;\n private readonly credentials: { client_email: string; private_key: string } | undefined;\n\n constructor(config: GCPTransportConfig) {\n protectSecrets(this, ['credentials', 'accessToken']);\n this.projectId =\n config.projectId ??\n process.env['GOOGLE_CLOUD_PROJECT'] ??\n process.env['GCLOUD_PROJECT'] ??\n 'unknown-project';\n this.logName = config.logName ?? `projects/${this.projectId}/logs/logixia`;\n this.resource = config.resource ?? { type: 'global' };\n this.credentials = config.credentials;\n this.batchSize = config.batchSize ?? 200;\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<TransportLogEntry>({\n name: 'GCPTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (entries) => this.writeEntries(entries),\n secrets: () => this.secretValues(),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n }\n\n write(entry: TransportLogEntry): void {\n this.buffer.push(entry);\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining entries and stop the interval timer on shutdown. Without\n * this the manager's close() skipped the transport (close was undefined) and\n * buffered entries were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private buildLogEntry(entry: TransportLogEntry): Record<string, unknown> {\n const gcpEntry: Record<string, unknown> = {\n logName: this.logName,\n resource: this.resource,\n severity: toGcpSeverity(entry.level),\n timestamp: entry.timestamp ?? new Date().toISOString(),\n jsonPayload: mergeCoreFields(\n { message: entry.message, appName: entry.appName, context: entry.context },\n entry.data\n ),\n };\n\n // GCP Cloud Trace correlation\n if (entry.traceId) {\n gcpEntry['trace'] = `projects/${this.projectId}/traces/${entry.traceId}`;\n gcpEntry['traceSampled'] = true;\n }\n\n return gcpEntry;\n }\n\n private async getAccessToken(): Promise<string | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;\n\n // Try ADC metadata server (GCE/GKE/Cloud Run)\n try {\n const token = await this.fetchFromMetadataServer();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000; // 55 minutes\n return this.accessToken;\n }\n } catch {\n /* fall through to service account */\n }\n\n // Try service account key\n if (this.credentials) {\n try {\n const token = await this.fetchServiceAccountToken();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n return this.accessToken;\n }\n } catch (err) {\n internalError('GCPTransport service account token error', err);\n }\n }\n\n return null;\n }\n\n private fetchFromMetadataServer(): Promise<string | null> {\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n hostname: 'metadata.google.internal',\n path: '/computeMetadata/v1/instance/service-accounts/default/token',\n headers: { 'Metadata-Flavor': 'Google' },\n timeout: 3000,\n },\n (res) => {\n let raw = '';\n res.on('data', (c: Buffer) => (raw += c.toString()));\n res.on('end', () => {\n if (res.statusCode === 200) {\n try {\n const parsed = JSON.parse(raw) as { access_token?: string };\n resolve(parsed.access_token ?? null);\n } catch {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n });\n }\n );\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('metadata timeout'));\n });\n req.end();\n });\n }\n\n private fetchServiceAccountToken(): Promise<string | null> {\n // Minimal JWT creation for service account — only for environments without\n // the full Google Auth Library. For production workloads, prefer ADC.\n if (!this.credentials) return Promise.resolve(null);\n\n const iat = Math.floor(Date.now() / 1000);\n const exp = iat + 3600;\n const scope = 'https://www.googleapis.com/auth/logging.write';\n\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');\n const payload = Buffer.from(\n JSON.stringify({\n iss: this.credentials.client_email,\n scope,\n aud: 'https://oauth2.googleapis.com/token',\n exp,\n iat,\n })\n ).toString('base64url');\n\n const signingInput = `${header}.${payload}`;\n\n let signature: string;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const sign = require('node:crypto').createSign('RSA-SHA256');\n sign.update(signingInput);\n signature = sign.sign(this.credentials.private_key, 'base64url') as string;\n } catch {\n return Promise.resolve(null);\n }\n\n const jwt = `${signingInput}.${signature}`;\n const body = `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`;\n\n return httpRequest({\n url: new URL('https://oauth2.googleapis.com/token'),\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP token request',\n }).then(\n (res) => (JSON.parse(res.body) as { access_token?: string }).access_token ?? null,\n () => null\n );\n }\n\n private secretValues(token?: string): (string | undefined)[] {\n return [\n ...(this.credentials?.private_key.split('\\n') ?? []),\n this.credentials?.private_key,\n this.accessToken ?? undefined,\n token,\n ];\n }\n\n private async writeEntries(entries: TransportLogEntry[]): Promise<void> {\n const token = await this.getAccessToken();\n if (!token) {\n throw new Error('GCPTransport: no access token available');\n }\n\n const body = stringifyForLog({\n logName: this.logName,\n resource: this.resource,\n entries: entries.map((e) => this.buildLogEntry(e)),\n });\n\n await httpRequest({\n url: new URL('https://logging.googleapis.com/v2/entries:write'),\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP Logging API',\n secrets: () => this.secretValues(token),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gcp.transport-LLK2bw2-.mjs","names":[],"sources":["../src/transports/gcp.transport.ts"],"sourcesContent":["/**\n * logixia — Google Cloud Logging (Stackdriver) transport\n *\n * Maps logixia log entries to the GCP Logging REST API format:\n * - Maps `level` → `severity` (INFO, WARNING, ERROR, CRITICAL…)\n * - Injects `logging.googleapis.com/trace` for Cloud Trace correlation\n * - Sets `traceSampled: true` whenever a trace id is present\n * (`logging.googleapis.com/spanId` and `sourceLocation` are not populated)\n * - Supports structured `jsonPayload` and plain `textPayload`\n *\n * Auth: the metadata server on GCE/GKE/Cloud Run, or a service-account key passed\n * as `credentials`. The `GOOGLE_APPLICATION_CREDENTIALS` key-file variable is not\n * read; full ADC is not supported.\n *\n * @example\n * ```ts\n * import { createLogger } from 'logixia';\n * import { GCPTransport } from 'logixia/gcp';\n *\n * const logger = createLogger({\n * transports: {\n * custom: [\n * new GCPTransport({\n * projectId: process.env.GOOGLE_CLOUD_PROJECT,\n * logName: 'projects/my-project/logs/api',\n * resource: { type: 'gce_instance', labels: { instance_id: '123' } },\n * }),\n * ],\n * },\n * });\n * ```\n */\n\nimport * as https from 'node:https';\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError } from '../utils/internal-log';\nimport { stringifyForLog } from '../utils/safe-stringify';\nimport {\n BatchBuffer,\n DEFAULT_MAX_BUFFER_SIZE,\n DEFAULT_REQUEST_TIMEOUT_MS,\n httpRequest,\n} from './batch-buffer';\nimport { mergeCoreFields } from './entry-fields';\nimport { protectSecrets } from './secret-config';\n\nexport interface GCPMonitoredResource {\n type: string;\n labels?: Record<string, string>;\n}\n\nexport interface GCPTransportConfig {\n /** GCP project ID. Falls back to `GOOGLE_CLOUD_PROJECT` or `GCLOUD_PROJECT` env vars. */\n projectId?: string;\n /**\n * Full log name, e.g. `'projects/my-project/logs/api'`.\n * If omitted, defaults to `projects/{projectId}/logs/logixia`.\n */\n logName?: string;\n /** Monitored resource descriptor. Defaults to `global`. */\n resource?: GCPMonitoredResource;\n /**\n * Service account key JSON (parsed). If omitted, only the metadata server\n * (GCE/GKE/Cloud Run) is tried; the key-file env var is not read.\n */\n credentials?: {\n client_email: string;\n private_key: string;\n };\n /** Number of entries to batch. @default 200 */\n batchSize?: number;\n /** Flush interval in ms. @default 5000 */\n flushIntervalMs?: number;\n /** Abort a request that has not finished after this many ms. @default 10000 */\n requestTimeoutMs?: number;\n /** Max buffered entries; the oldest are dropped past this. @default 10000 */\n maxBufferSize?: number;\n level?: string;\n}\n\ntype GcpSeverity =\n | 'DEFAULT'\n | 'DEBUG'\n | 'INFO'\n | 'NOTICE'\n | 'WARNING'\n | 'ERROR'\n | 'CRITICAL'\n | 'ALERT'\n | 'EMERGENCY';\n\nfunction toGcpSeverity(level: string): GcpSeverity {\n switch (level.toLowerCase()) {\n case 'trace':\n case 'verbose':\n case 'debug':\n return 'DEBUG';\n case 'info':\n case 'log':\n return 'INFO';\n case 'warn':\n case 'warning':\n return 'WARNING';\n case 'error':\n return 'ERROR';\n case 'critical':\n case 'fatal':\n return 'CRITICAL';\n default:\n return 'DEFAULT';\n }\n}\n\n/**\n * Google Cloud Logging transport with trace correlation and GCP severity mapping.\n */\nexport class GCPTransport implements IAsyncTransport {\n public readonly name = 'gcp';\n public readonly batchSize: number;\n public readonly flushInterval: number;\n public readonly level: string | undefined;\n\n private readonly buffer: BatchBuffer<TransportLogEntry>;\n private readonly requestTimeoutMs: number;\n private flushTimer: NodeJS.Timeout | null = null;\n private accessToken: string | null = null;\n private tokenExpiry = 0;\n\n private readonly projectId: string;\n private readonly logName: string;\n private readonly resource: GCPMonitoredResource;\n private readonly credentials: { client_email: string; private_key: string } | undefined;\n\n constructor(config: GCPTransportConfig) {\n protectSecrets(this, ['credentials', 'accessToken']);\n this.projectId =\n config.projectId ??\n process.env['GOOGLE_CLOUD_PROJECT'] ??\n process.env['GCLOUD_PROJECT'] ??\n 'unknown-project';\n this.logName = config.logName ?? `projects/${this.projectId}/logs/logixia`;\n this.resource = config.resource ?? { type: 'global' };\n this.credentials = config.credentials;\n this.batchSize = config.batchSize ?? 200;\n this.flushInterval = config.flushIntervalMs ?? 5000;\n this.level = config.level;\n this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n this.buffer = new BatchBuffer<TransportLogEntry>({\n name: 'GCPTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (entries) => this.writeEntries(entries),\n secrets: () => this.secretValues(),\n });\n\n this.flushTimer = setInterval(() => {\n this.flush().catch(() => {});\n }, this.flushInterval);\n if (this.flushTimer.unref) this.flushTimer.unref();\n }\n\n write(entry: TransportLogEntry): void {\n this.buffer.push(entry);\n this.buffer.flushIfFull();\n }\n\n flush(): Promise<void> {\n return this.buffer.flush();\n }\n\n /**\n * Flush remaining entries and stop the interval timer on shutdown. Without\n * this the manager's close() skipped the transport (close was undefined) and\n * buffered entries were lost on deploy. Waits for any in-flight send first.\n */\n async close(): Promise<void> {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n await this.buffer.close();\n }\n\n private buildLogEntry(entry: TransportLogEntry): Record<string, unknown> {\n const gcpEntry: Record<string, unknown> = {\n logName: this.logName,\n resource: this.resource,\n severity: toGcpSeverity(entry.level),\n timestamp: entry.timestamp ?? new Date().toISOString(),\n jsonPayload: mergeCoreFields(\n { message: entry.message, appName: entry.appName, context: entry.context },\n entry.data\n ),\n };\n\n // GCP Cloud Trace correlation\n if (entry.traceId) {\n gcpEntry['trace'] = `projects/${this.projectId}/traces/${entry.traceId}`;\n gcpEntry['traceSampled'] = true;\n }\n\n return gcpEntry;\n }\n\n private async getAccessToken(): Promise<string | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;\n\n // Try ADC metadata server (GCE/GKE/Cloud Run)\n try {\n const token = await this.fetchFromMetadataServer();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000; // 55 minutes\n return this.accessToken;\n }\n } catch {\n /* fall through to service account */\n }\n\n // Try service account key\n if (this.credentials) {\n try {\n const token = await this.fetchServiceAccountToken();\n if (token) {\n this.accessToken = token;\n this.tokenExpiry = Date.now() + 55 * 60 * 1000;\n return this.accessToken;\n }\n } catch (err) {\n internalError('GCPTransport service account token error', err);\n }\n }\n\n return null;\n }\n\n private fetchFromMetadataServer(): Promise<string | null> {\n return new Promise((resolve, reject) => {\n const req = https.request(\n {\n hostname: 'metadata.google.internal',\n path: '/computeMetadata/v1/instance/service-accounts/default/token',\n headers: { 'Metadata-Flavor': 'Google' },\n timeout: 3000,\n },\n (res) => {\n let raw = '';\n res.on('data', (c: Buffer) => (raw += c.toString()));\n res.on('end', () => {\n if (res.statusCode === 200) {\n try {\n const parsed = JSON.parse(raw) as { access_token?: string };\n resolve(parsed.access_token ?? null);\n } catch {\n resolve(null);\n }\n } else {\n resolve(null);\n }\n });\n }\n );\n req.on('error', reject);\n req.on('timeout', () => {\n req.destroy();\n reject(new Error('metadata timeout'));\n });\n req.end();\n });\n }\n\n private fetchServiceAccountToken(): Promise<string | null> {\n // Minimal JWT creation for service account — only for environments without\n // the full Google Auth Library. For production workloads, prefer ADC.\n if (!this.credentials) return Promise.resolve(null);\n\n const iat = Math.floor(Date.now() / 1000);\n const exp = iat + 3600;\n const scope = 'https://www.googleapis.com/auth/logging.write';\n\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url');\n const payload = Buffer.from(\n JSON.stringify({\n iss: this.credentials.client_email,\n scope,\n aud: 'https://oauth2.googleapis.com/token',\n exp,\n iat,\n })\n ).toString('base64url');\n\n const signingInput = `${header}.${payload}`;\n\n let signature: string;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const sign = require('node:crypto').createSign('RSA-SHA256');\n sign.update(signingInput);\n signature = sign.sign(this.credentials.private_key, 'base64url') as string;\n } catch {\n return Promise.resolve(null);\n }\n\n const jwt = `${signingInput}.${signature}`;\n const body = `grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${jwt}`;\n\n return httpRequest({\n url: new URL('https://oauth2.googleapis.com/token'),\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP token request',\n }).then(\n (res) => (JSON.parse(res.body) as { access_token?: string }).access_token ?? null,\n () => null\n );\n }\n\n private secretValues(token?: string): (string | undefined)[] {\n return [\n ...(this.credentials?.private_key.split('\\n') ?? []),\n this.credentials?.private_key,\n this.accessToken ?? undefined,\n token,\n ];\n }\n\n private async writeEntries(entries: TransportLogEntry[]): Promise<void> {\n const token = await this.getAccessToken();\n if (!token) {\n throw new Error('GCPTransport: no access token available');\n }\n\n const body = stringifyForLog({\n logName: this.logName,\n resource: this.resource,\n entries: entries.map((e) => this.buildLogEntry(e)),\n });\n\n await httpRequest({\n url: new URL('https://logging.googleapis.com/v2/entries:write'),\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'GCP Logging API',\n secrets: () => this.secretValues(token),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -186,6 +186,14 @@ interface RedactConfig {
|
|
|
186
186
|
* @example `['req.headers.authorization', '*.password', 'user.creditCard']`
|
|
187
187
|
*/
|
|
188
188
|
paths?: string[];
|
|
189
|
+
/**
|
|
190
|
+
* Extra URL query parameter names whose values are replaced with `[REDACTED]`
|
|
191
|
+
* wherever logixia logs a request URL (exception filter, trace context, and the
|
|
192
|
+
* NestJS trace middleware). Merged with the defaults (`token`, `code`, `password`,
|
|
193
|
+
* `api_key`, `x-amz-signature`, …). Names are matched case-insensitively.
|
|
194
|
+
* @example `['invite', 'magic']`
|
|
195
|
+
*/
|
|
196
|
+
queryParams?: string[];
|
|
189
197
|
/**
|
|
190
198
|
* Dot-notation field paths exempt from `patterns` / `autoDetect` value-pattern
|
|
191
199
|
* scanning. Use this for internal identifiers whose *value* happens to look
|
|
@@ -515,4 +523,4 @@ declare const DEFAULT_LOG_COLORS: {
|
|
|
515
523
|
verbose: string;
|
|
516
524
|
};
|
|
517
525
|
export { TraceIdConfig as A, usePlugin as B, LogixiaLoggerInstance as C, ReservedLevelName as D, RequestContext as E, RequestMetrics as F, RequestTiming as I, LogixiaPlugin as L, HttpError as M, HttpRequest as N, SamplingConfig as O, HttpResponse as P, PluginRegistry as R, LogixiaLoggerDefault as S, RedactConfig as T, LogFieldKey as _, DEFAULT_LOG_LEVELS as a, LoggerConfig as b, ExtractLevels as c, ILogFormatter as d, ILogger as f, LogEntry as g, LogColor as h, DEFAULT_LOG_COLORS as i, TraceIdExtractorConfig as j, TimingEntry as k, GracefulShutdownConfig as l, ILoggerRuntimeControls as m, ContextData as n, Environment as o, ILoggerDefault as p, CustomLevelMethods as r, ErrorSerializationOptions as s, AdaptiveSamplingConfig as t, IBaseLogger as u, LogLevel as v, NamespaceLevels as w, LoggerWithLevels as x, LogLevelString as y, globalPluginRegistry as z };
|
|
518
|
-
//# sourceMappingURL=index-
|
|
526
|
+
//# sourceMappingURL=index-BAkPHp5D.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BAkPHp5D.d.mts","names":[],"sources":["../src/plugin.ts","../src/types/http.types.ts","../src/types/index.ts"],"mappings":"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"}
|
|
@@ -186,6 +186,14 @@ interface RedactConfig {
|
|
|
186
186
|
* @example `['req.headers.authorization', '*.password', 'user.creditCard']`
|
|
187
187
|
*/
|
|
188
188
|
paths?: string[];
|
|
189
|
+
/**
|
|
190
|
+
* Extra URL query parameter names whose values are replaced with `[REDACTED]`
|
|
191
|
+
* wherever logixia logs a request URL (exception filter, trace context, and the
|
|
192
|
+
* NestJS trace middleware). Merged with the defaults (`token`, `code`, `password`,
|
|
193
|
+
* `api_key`, `x-amz-signature`, …). Names are matched case-insensitively.
|
|
194
|
+
* @example `['invite', 'magic']`
|
|
195
|
+
*/
|
|
196
|
+
queryParams?: string[];
|
|
189
197
|
/**
|
|
190
198
|
* Dot-notation field paths exempt from `patterns` / `autoDetect` value-pattern
|
|
191
199
|
* scanning. Use this for internal identifiers whose *value* happens to look
|
|
@@ -515,4 +523,4 @@ declare const DEFAULT_LOG_COLORS: {
|
|
|
515
523
|
verbose: string;
|
|
516
524
|
};
|
|
517
525
|
export { TraceIdConfig as A, usePlugin as B, LogixiaLoggerInstance as C, ReservedLevelName as D, RequestContext as E, RequestMetrics as F, RequestTiming as I, LogixiaPlugin as L, HttpError as M, HttpRequest as N, SamplingConfig as O, HttpResponse as P, PluginRegistry as R, LogixiaLoggerDefault as S, RedactConfig as T, LogFieldKey as _, DEFAULT_LOG_LEVELS as a, LoggerConfig as b, ExtractLevels as c, ILogFormatter as d, ILogger as f, LogEntry as g, LogColor as h, DEFAULT_LOG_COLORS as i, TraceIdExtractorConfig as j, TimingEntry as k, GracefulShutdownConfig as l, ILoggerRuntimeControls as m, ContextData as n, Environment as o, ILoggerDefault as p, CustomLevelMethods as r, ErrorSerializationOptions as s, AdaptiveSamplingConfig as t, IBaseLogger as u, LogLevel as v, NamespaceLevels as w, LoggerWithLevels as x, LogLevelString as y, globalPluginRegistry as z };
|
|
518
|
-
//# sourceMappingURL=index-
|
|
526
|
+
//# sourceMappingURL=index-e7LowmAu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-e7LowmAu.d.ts","names":[],"sources":["../src/plugin.ts","../src/types/http.types.ts","../src/types/index.ts"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { _ as TransportLogEntry, d as ITransport, h as TransportConfig } from "./transport.types-CzJq4IrF.mjs";
|
|
2
2
|
import { n as HttpResponseShape, t as HttpRequestShape } from "./http-shapes-BnBkJcid.mjs";
|
|
3
|
-
import { A as TraceIdConfig, B as usePlugin, C as LogixiaLoggerInstance, D as ReservedLevelName, E as RequestContext, F as RequestMetrics, I as RequestTiming, L as LogixiaPlugin, M as HttpError, N as HttpRequest, O as SamplingConfig, P as HttpResponse, R as PluginRegistry, S as LogixiaLoggerDefault, T as RedactConfig, _ as LogFieldKey, a as DEFAULT_LOG_LEVELS, b as LoggerConfig, c as ExtractLevels, d as ILogFormatter, f as ILogger, g as LogEntry, h as LogColor, i as DEFAULT_LOG_COLORS, j as TraceIdExtractorConfig, k as TimingEntry, l as GracefulShutdownConfig, m as ILoggerRuntimeControls, n as ContextData, o as Environment, p as ILoggerDefault, r as CustomLevelMethods, s as ErrorSerializationOptions, t as AdaptiveSamplingConfig, u as IBaseLogger, v as LogLevel, w as NamespaceLevels, x as LoggerWithLevels, y as LogLevelString, z as globalPluginRegistry } from "./index-
|
|
4
|
-
import { n as createLogger$1, t as LogixiaLogger } from "./logitron-logger-
|
|
3
|
+
import { A as TraceIdConfig, B as usePlugin, C as LogixiaLoggerInstance, D as ReservedLevelName, E as RequestContext, F as RequestMetrics, I as RequestTiming, L as LogixiaPlugin, M as HttpError, N as HttpRequest, O as SamplingConfig, P as HttpResponse, R as PluginRegistry, S as LogixiaLoggerDefault, T as RedactConfig, _ as LogFieldKey, a as DEFAULT_LOG_LEVELS, b as LoggerConfig, c as ExtractLevels, d as ILogFormatter, f as ILogger, g as LogEntry, h as LogColor, i as DEFAULT_LOG_COLORS, j as TraceIdExtractorConfig, k as TimingEntry, l as GracefulShutdownConfig, m as ILoggerRuntimeControls, n as ContextData, o as Environment, p as ILoggerDefault, r as CustomLevelMethods, s as ErrorSerializationOptions, t as AdaptiveSamplingConfig, u as IBaseLogger, v as LogLevel, w as NamespaceLevels, x as LoggerWithLevels, y as LogLevelString, z as globalPluginRegistry } from "./index-BAkPHp5D.mjs";
|
|
4
|
+
import { n as createLogger$1, t as LogixiaLogger } from "./logitron-logger-sYuk8fOb.mjs";
|
|
5
5
|
import { a as DiscordTransport, c as OtlpLogTransportConfig, i as DiscordEmbed, l as toOtelSeverity, n as SlackTransport, o as DiscordTransportConfig, r as SlackTransportConfig, s as OtlpLogTransport, t as SlackMessage } from "./slack.transport-BDyENuR0.mjs";
|
|
6
|
-
import { A as SearchStats, C as SearchFilters, D as SearchPreset, E as SearchOptions, F as SuggestionType, I as TimeRange, L as TimelineEvent, M as SemanticIndex, N as SimilarLog, O as SearchQuery, P as SortField, S as RelativeTime, T as SearchMatch, _ as ParsedNLQuery, a as ILogSearchEngine, b as RelatedLog, c as SearchManager, d as CorrelatedLogs, f as EntityType, g as LogPattern, h as LogCorrelationSummary, i as BasicSearchEngine, j as SearchSuggestion, k as SearchResult, l as SearchManagerConfig, m as LogCluster, n as NLPSearchEngine, o as BasicLogIndexer, p as ExportOptions, r as CorrelationEngine, s as ILogIndexer, t as PatternRecognitionEngine, u as AnomalyDetection, v as QueryEntity, w as SearchHighlight, x as RelationshipType, y as QueryIntent } from "./search-
|
|
6
|
+
import { A as SearchStats, C as SearchFilters, D as SearchPreset, E as SearchOptions, F as SuggestionType, I as TimeRange, L as TimelineEvent, M as SemanticIndex, N as SimilarLog, O as SearchQuery, P as SortField, S as RelativeTime, T as SearchMatch, _ as ParsedNLQuery, a as ILogSearchEngine, b as RelatedLog, c as SearchManager, d as CorrelatedLogs, f as EntityType, g as LogPattern, h as LogCorrelationSummary, i as BasicSearchEngine, j as SearchSuggestion, k as SearchResult, l as SearchManagerConfig, m as LogCluster, n as NLPSearchEngine, o as BasicLogIndexer, p as ExportOptions, r as CorrelationEngine, s as ILogIndexer, t as PatternRecognitionEngine, u as AnomalyDetection, v as QueryEntity, w as SearchHighlight, x as RelationshipType, y as QueryIntent } from "./search-D-8HJADE.mjs";
|
|
7
7
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
8
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
9
9
|
/**
|
|
@@ -100,6 +100,14 @@ export declare function serializeError(error: Error, options?: ErrorSerializatio
|
|
|
100
100
|
* Type guard: returns true if the value looks like an Error object.
|
|
101
101
|
*/
|
|
102
102
|
export declare function isError(value: unknown): value is Error;
|
|
103
|
+
/**
|
|
104
|
+
* Replaces real Error instances inside a log payload with their serialized form,
|
|
105
|
+
* because JSON output drops an Error's non-enumerable `message` and `stack`. Runs on
|
|
106
|
+
* every log call, so its work is capped and it copies nothing until it finds one.
|
|
107
|
+
* Duck-typed objects are data, and an Error with its own toJSON has already chosen
|
|
108
|
+
* what to show. The caller's objects are never mutated.
|
|
109
|
+
*/
|
|
110
|
+
export declare function serializeNestedErrors(data: Record<string, unknown>): Record<string, unknown>;
|
|
103
111
|
/**
|
|
104
112
|
* Coerce any thrown value into a proper Error instance.
|
|
105
113
|
*/
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":["createLoggerFromCore","_$__types0.Environment","_$__types0.LogColor"],"sources":["../src/core/default-config.ts","../src/formatters/json.formatter.ts","../src/formatters/text.formatter.ts","../src/utils/error.utils.ts","../src/utils/otel.ts","../src/utils/redact.utils.ts","../src/utils/runtime-control.ts","../src/utils/safe-stringify.ts","../src/utils/shutdown.utils.ts","../src/utils/trace.utils.ts","../src/utils/typed-logger.ts","../src/wide-events.ts","../src/utils/request-trace.ts","../src/context/async-context.ts","../src/utils/sampling.utils.ts","../src/exceptions/types.ts","../src/exceptions/builder.ts","../src/exceptions/exception.ts","../src/metrics.ts","../src/index.ts"],"mappings":";;;;;;;;;;;qBAMa;;EAEmB,aAAA;;;;;;;;;;;;;;;;;;IAyBvB,QAAA,eAAe;;;;;;;;;;;;;qBCTX,yBAAyB;UAC5B;UACA;UACA;UACA;UACA;UACA;EAGN,YAAA;IACE;IACA;IACA;IACA;IACA;IACA;;EAWJ,OAAO,OAAO;UA0DN;;qBC/FG,yBAAyB;UAC5B;UACA;UACA;UACA;UACA;UACA;UACA;EAGN,YAAA;IACE;IACA;IACA;IACA;IACA;IACA;IACA,SAAS;;EAuBb,OAAO,OAAO;UA+DN;UAcA;;;;SAqDD,gBAAgB;SAWhB,kBAAkB;SAWlB,iBAAiB;;;;;;;;;;wBC3KV,eACd,OAAO,OACP,UAAS,4BACR;;;;wBA6Ia,QAAQ,iBAAiB,SAAS;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["createLoggerFromCore","_$__types0.Environment","_$__types0.LogColor"],"sources":["../src/core/default-config.ts","../src/formatters/json.formatter.ts","../src/formatters/text.formatter.ts","../src/utils/error.utils.ts","../src/utils/otel.ts","../src/utils/redact.utils.ts","../src/utils/runtime-control.ts","../src/utils/safe-stringify.ts","../src/utils/shutdown.utils.ts","../src/utils/trace.utils.ts","../src/utils/typed-logger.ts","../src/wide-events.ts","../src/utils/request-trace.ts","../src/context/async-context.ts","../src/utils/sampling.utils.ts","../src/exceptions/types.ts","../src/exceptions/builder.ts","../src/exceptions/exception.ts","../src/metrics.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { _ as TransportLogEntry, d as ITransport, h as TransportConfig } from "./transport.types-CzJq4IrF.js";
|
|
2
2
|
import { n as HttpResponseShape, t as HttpRequestShape } from "./http-shapes-BnBkJcid.js";
|
|
3
|
-
import { A as TraceIdConfig, B as usePlugin, C as LogixiaLoggerInstance, D as ReservedLevelName, E as RequestContext, F as RequestMetrics, I as RequestTiming, L as LogixiaPlugin, M as HttpError, N as HttpRequest, O as SamplingConfig, P as HttpResponse, R as PluginRegistry, S as LogixiaLoggerDefault, T as RedactConfig, _ as LogFieldKey, a as DEFAULT_LOG_LEVELS, b as LoggerConfig, c as ExtractLevels, d as ILogFormatter, f as ILogger, g as LogEntry, h as LogColor, i as DEFAULT_LOG_COLORS, j as TraceIdExtractorConfig, k as TimingEntry, l as GracefulShutdownConfig, m as ILoggerRuntimeControls, n as ContextData, o as Environment, p as ILoggerDefault, r as CustomLevelMethods, s as ErrorSerializationOptions, t as AdaptiveSamplingConfig, u as IBaseLogger, v as LogLevel, w as NamespaceLevels, x as LoggerWithLevels, y as LogLevelString, z as globalPluginRegistry } from "./index-
|
|
4
|
-
import { n as createLogger$1, t as LogixiaLogger } from "./logitron-logger-
|
|
3
|
+
import { A as TraceIdConfig, B as usePlugin, C as LogixiaLoggerInstance, D as ReservedLevelName, E as RequestContext, F as RequestMetrics, I as RequestTiming, L as LogixiaPlugin, M as HttpError, N as HttpRequest, O as SamplingConfig, P as HttpResponse, R as PluginRegistry, S as LogixiaLoggerDefault, T as RedactConfig, _ as LogFieldKey, a as DEFAULT_LOG_LEVELS, b as LoggerConfig, c as ExtractLevels, d as ILogFormatter, f as ILogger, g as LogEntry, h as LogColor, i as DEFAULT_LOG_COLORS, j as TraceIdExtractorConfig, k as TimingEntry, l as GracefulShutdownConfig, m as ILoggerRuntimeControls, n as ContextData, o as Environment, p as ILoggerDefault, r as CustomLevelMethods, s as ErrorSerializationOptions, t as AdaptiveSamplingConfig, u as IBaseLogger, v as LogLevel, w as NamespaceLevels, x as LoggerWithLevels, y as LogLevelString, z as globalPluginRegistry } from "./index-e7LowmAu.js";
|
|
4
|
+
import { n as createLogger$1, t as LogixiaLogger } from "./logitron-logger-Qh3y9-WH.js";
|
|
5
5
|
import { a as DiscordTransport, c as OtlpLogTransportConfig, i as DiscordEmbed, l as toOtelSeverity, n as SlackTransport, o as DiscordTransportConfig, r as SlackTransportConfig, s as OtlpLogTransport, t as SlackMessage } from "./slack.transport-C6E0l4kw.js";
|
|
6
|
-
import { A as SearchStats, C as SearchFilters, D as SearchPreset, E as SearchOptions, F as SuggestionType, I as TimeRange, L as TimelineEvent, M as SemanticIndex, N as SimilarLog, O as SearchQuery, P as SortField, S as RelativeTime, T as SearchMatch, _ as ParsedNLQuery, a as ILogSearchEngine, b as RelatedLog, c as SearchManager, d as CorrelatedLogs, f as EntityType, g as LogPattern, h as LogCorrelationSummary, i as BasicSearchEngine, j as SearchSuggestion, k as SearchResult, l as SearchManagerConfig, m as LogCluster, n as NLPSearchEngine, o as BasicLogIndexer, p as ExportOptions, r as CorrelationEngine, s as ILogIndexer, t as PatternRecognitionEngine, u as AnomalyDetection, v as QueryEntity, w as SearchHighlight, x as RelationshipType, y as QueryIntent } from "./search-
|
|
6
|
+
import { A as SearchStats, C as SearchFilters, D as SearchPreset, E as SearchOptions, F as SuggestionType, I as TimeRange, L as TimelineEvent, M as SemanticIndex, N as SimilarLog, O as SearchQuery, P as SortField, S as RelativeTime, T as SearchMatch, _ as ParsedNLQuery, a as ILogSearchEngine, b as RelatedLog, c as SearchManager, d as CorrelatedLogs, f as EntityType, g as LogPattern, h as LogCorrelationSummary, i as BasicSearchEngine, j as SearchSuggestion, k as SearchResult, l as SearchManagerConfig, m as LogCluster, n as NLPSearchEngine, o as BasicLogIndexer, p as ExportOptions, r as CorrelationEngine, s as ILogIndexer, t as PatternRecognitionEngine, u as AnomalyDetection, v as QueryEntity, w as SearchHighlight, x as RelationshipType, y as QueryIntent } from "./search-DPwTKPve.js";
|
|
7
7
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
8
8
|
import { IncomingMessage, ServerResponse } from "node:http";
|
|
9
9
|
/**
|
|
@@ -100,6 +100,14 @@ export declare function serializeError(error: Error, options?: ErrorSerializatio
|
|
|
100
100
|
* Type guard: returns true if the value looks like an Error object.
|
|
101
101
|
*/
|
|
102
102
|
export declare function isError(value: unknown): value is Error;
|
|
103
|
+
/**
|
|
104
|
+
* Replaces real Error instances inside a log payload with their serialized form,
|
|
105
|
+
* because JSON output drops an Error's non-enumerable `message` and `stack`. Runs on
|
|
106
|
+
* every log call, so its work is capped and it copies nothing until it finds one.
|
|
107
|
+
* Duck-typed objects are data, and an Error with its own toJSON has already chosen
|
|
108
|
+
* what to show. The caller's objects are never mutated.
|
|
109
|
+
*/
|
|
110
|
+
export declare function serializeNestedErrors(data: Record<string, unknown>): Record<string, unknown>;
|
|
103
111
|
/**
|
|
104
112
|
* Coerce any thrown value into a proper Error instance.
|
|
105
113
|
*/
|