{"version":3,"file":"index.mjs","names":[],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks'\nimport { Elysia } from 'elysia'\nimport type { RequestLogger } from '../types'\nimport { createMiddlewareLogger, type BaseMxllogOptions } from '../shared/middleware'\nimport { extractSafeHeaders } from '../shared/headers'\n\nconst storage = new AsyncLocalStorage<RequestLogger>()\n\n// Tracks loggers that are currently active (within a live request).\n// Elysia uses storage.enterWith() which persists in the async context\n// even after the request ends, so we use this set to distinguish\n// an in-flight logger from a stale one.\nconst activeLoggers = new WeakSet<RequestLogger>()\n\nexport type MxllogElysiaOptions = BaseMxllogOptions\n\n/**\n * Get the request-scoped logger from anywhere in the call stack.\n * Must be called inside a request handled by the `mxllog()` plugin.\n *\n * Unlike other frameworks, Elysia uses `storage.enterWith()` which persists\n * beyond the request lifecycle. This accessor additionally checks `activeLoggers`\n * to ensure the logger belongs to an in-flight request.\n *\n * @example\n * ```ts\n * import { useLogger } from '@safaricom-mxl/log/elysia'\n *\n * function findUser(id: string) {\n *   const log = useLogger()\n *   log.set({ user: { id } })\n * }\n * ```\n */\nexport function useLogger<T extends object = Record<string, unknown>>(): RequestLogger<T> {\n  const logger = storage.getStore()\n  if (!logger || !activeLoggers.has(logger)) {\n    throw new Error(\n      '[mxllog] useLogger() was called outside of an mxllog plugin context. '\n      + 'Make sure app.use(mxllog()) is registered before your routes.',\n    )\n  }\n  return logger as RequestLogger<T>\n}\n\n/**\n * Create an mxllog plugin for Elysia.\n *\n * @example\n * ```ts\n * import { Elysia } from 'elysia'\n * import { mxllog } from '@safaricom-mxl/log/elysia'\n * import { createAxiomDrain } from '@safaricom-mxl/log/axiom'\n *\n * const app = new Elysia()\n *   .use(mxllog({\n *     drain: createAxiomDrain(),\n *     enrich: (ctx) => {\n *       ctx.event.region = process.env.FLY_REGION\n *     },\n *   }))\n *   .get('/health', ({ log }) => {\n *     log.set({ route: 'health' })\n *     return { ok: true }\n *   })\n *   .listen(3000)\n * ```\n */\ninterface RequestState {\n  finish: (opts?: { status?: number; error?: Error }) => Promise<unknown>\n  skipped: boolean\n  logger: RequestLogger\n}\n\nexport function mxllog(options: MxllogElysiaOptions = {}) {\n  const emitted = new WeakSet<Request>()\n  const requestState = new WeakMap<Request, RequestState>()\n\n  return new Elysia({ name: '@safaricom-mxl/log' })\n    .derive({ as: 'global' }, ({ request }) => {\n      const url = new URL(request.url)\n\n      const { logger, finish, skipped } = createMiddlewareLogger({\n        method: request.method,\n        path: url.pathname,\n        requestId: request.headers.get('x-request-id') || crypto.randomUUID(),\n        headers: extractSafeHeaders(request.headers),\n        ...options,\n      })\n\n      if (!skipped) activeLoggers.add(logger)\n      storage.enterWith(logger)\n      requestState.set(request, { finish, skipped, logger })\n\n      return { log: logger }\n    })\n    .onAfterHandle({ as: 'global' }, async ({ request, set }) => {\n      const state = requestState.get(request)\n      if (!state || state.skipped || emitted.has(request)) return\n      emitted.add(request)\n      await state.finish({ status: set.status as number || 200 })\n      activeLoggers.delete(state.logger)\n      storage.enterWith(undefined as unknown as RequestLogger)\n    })\n    .onError({ as: 'global' }, async ({ request, error }) => {\n      const state = requestState.get(request)\n      if (!state || state.skipped || emitted.has(request)) return\n      emitted.add(request)\n      const err = error instanceof Error ? error : new Error(String(error))\n      state.logger.error(err)\n      await state.finish({ error: err })\n      activeLoggers.delete(state.logger)\n      storage.enterWith(undefined as unknown as RequestLogger)\n    })\n}\n"],"mappings":";;;;AAMA,MAAM,UAAU,IAAI,mBAAkC;AAMtD,MAAM,gCAAgB,IAAI,SAAwB;;;;;;;;;;;;;;;;;;;AAsBlD,SAAgB,YAA0E;CACxF,MAAM,SAAS,QAAQ,UAAU;AACjC,KAAI,CAAC,UAAU,CAAC,cAAc,IAAI,OAAO,CACvC,OAAM,IAAI,MACR,qIAED;AAEH,QAAO;;AAgCT,SAAgB,OAAO,UAA+B,EAAE,EAAE;CACxD,MAAM,0BAAU,IAAI,SAAkB;CACtC,MAAM,+BAAe,IAAI,SAAgC;AAEzD,QAAO,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAC,CAC9C,OAAO,EAAE,IAAI,UAAU,GAAG,EAAE,cAAc;EACzC,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;EAEhC,MAAM,EAAE,QAAQ,QAAQ,YAAY,uBAAuB;GACzD,QAAQ,QAAQ;GAChB,MAAM,IAAI;GACV,WAAW,QAAQ,QAAQ,IAAI,eAAe,IAAI,OAAO,YAAY;GACrE,SAAS,mBAAmB,QAAQ,QAAQ;GAC5C,GAAG;GACJ,CAAC;AAEF,MAAI,CAAC,QAAS,eAAc,IAAI,OAAO;AACvC,UAAQ,UAAU,OAAO;AACzB,eAAa,IAAI,SAAS;GAAE;GAAQ;GAAS;GAAQ,CAAC;AAEtD,SAAO,EAAE,KAAK,QAAQ;GACtB,CACD,cAAc,EAAE,IAAI,UAAU,EAAE,OAAO,EAAE,SAAS,UAAU;EAC3D,MAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,MAAI,CAAC,SAAS,MAAM,WAAW,QAAQ,IAAI,QAAQ,CAAE;AACrD,UAAQ,IAAI,QAAQ;AACpB,QAAM,MAAM,OAAO,EAAE,QAAQ,IAAI,UAAoB,KAAK,CAAC;AAC3D,gBAAc,OAAO,MAAM,OAAO;AAClC,UAAQ,UAAU,KAAA,EAAsC;GACxD,CACD,QAAQ,EAAE,IAAI,UAAU,EAAE,OAAO,EAAE,SAAS,YAAY;EACvD,MAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,MAAI,CAAC,SAAS,MAAM,WAAW,QAAQ,IAAI,QAAQ,CAAE;AACrD,UAAQ,IAAI,QAAQ;EACpB,MAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AACrE,QAAM,OAAO,MAAM,IAAI;AACvB,QAAM,MAAM,OAAO,EAAE,OAAO,KAAK,CAAC;AAClC,gBAAc,OAAO,MAAM,OAAO;AAClC,UAAQ,UAAU,KAAA,EAAsC;GACxD"}