@safaricom-mxl/log 0.0.4 → 0.0.5

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.
Files changed (137) hide show
  1. package/README.md +121 -40
  2. package/dist/{_http-CTtzGDc6.mjs → _http-BpkAshj6.mjs} +2 -2
  3. package/dist/_http-BpkAshj6.mjs.map +1 -0
  4. package/dist/{_severity-CLNgC2HU.mjs → _severity-Q1BuITU_.mjs} +1 -1
  5. package/dist/{_severity-CLNgC2HU.mjs.map → _severity-Q1BuITU_.mjs.map} +1 -1
  6. package/dist/adapters/axiom.d.mts +3 -3
  7. package/dist/adapters/axiom.mjs +6 -6
  8. package/dist/adapters/axiom.mjs.map +1 -1
  9. package/dist/adapters/better-stack.d.mts +4 -4
  10. package/dist/adapters/better-stack.mjs +5 -5
  11. package/dist/adapters/better-stack.mjs.map +1 -1
  12. package/dist/adapters/otlp.d.mts +4 -4
  13. package/dist/adapters/otlp.mjs +17 -13
  14. package/dist/adapters/otlp.mjs.map +1 -1
  15. package/dist/adapters/posthog.d.mts +5 -5
  16. package/dist/adapters/posthog.mjs +7 -7
  17. package/dist/adapters/posthog.mjs.map +1 -1
  18. package/dist/adapters/sentry.d.mts +3 -3
  19. package/dist/adapters/sentry.mjs +7 -7
  20. package/dist/adapters/sentry.mjs.map +1 -1
  21. package/dist/browser.d.mts +1 -1
  22. package/dist/browser.mjs +2 -2
  23. package/dist/browser.mjs.map +1 -1
  24. package/dist/{dist-Dalk68oO.mjs → dist-BsWcv7B8.mjs} +1 -1
  25. package/dist/{dist-Dalk68oO.mjs.map → dist-BsWcv7B8.mjs.map} +1 -1
  26. package/dist/elysia/index.d.mts +2 -2
  27. package/dist/elysia/index.mjs +2 -2
  28. package/dist/elysia/index.mjs.map +1 -1
  29. package/dist/enrichers.d.mts +1 -1
  30. package/dist/{error-IMQ3w1i0.d.mts → error-D4JQHcSq.d.mts} +2 -2
  31. package/dist/{error-IMQ3w1i0.d.mts.map → error-D4JQHcSq.d.mts.map} +1 -1
  32. package/dist/error.d.mts +1 -1
  33. package/dist/errors-BP9QdDrY.mjs +18 -0
  34. package/dist/errors-BP9QdDrY.mjs.map +1 -0
  35. package/dist/errors-DL0gLqac.d.mts +39 -0
  36. package/dist/errors-DL0gLqac.d.mts.map +1 -0
  37. package/dist/express/index.d.mts +4 -4
  38. package/dist/express/index.mjs +4 -4
  39. package/dist/express/index.mjs.map +1 -1
  40. package/dist/fastify/index.d.mts +5 -5
  41. package/dist/fastify/index.mjs +6 -6
  42. package/dist/fastify/index.mjs.map +1 -1
  43. package/dist/{headers-BnDMFr6p.mjs → headers-Crw-o-No.mjs} +7 -5
  44. package/dist/headers-Crw-o-No.mjs.map +1 -0
  45. package/dist/hono/index.d.mts +4 -4
  46. package/dist/hono/index.mjs +3 -3
  47. package/dist/hono/index.mjs.map +1 -1
  48. package/dist/index.d.mts +5 -5
  49. package/dist/{logger-B6moO_0c.d.mts → logger-Dwb7G3sg.d.mts} +2 -2
  50. package/dist/{logger-B6moO_0c.d.mts.map → logger-Dwb7G3sg.d.mts.map} +1 -1
  51. package/dist/logger.d.mts +1 -1
  52. package/dist/logger.mjs +45 -2
  53. package/dist/logger.mjs.map +1 -1
  54. package/dist/middleware-Cbh6eBkJ.d.mts +75 -0
  55. package/dist/middleware-Cbh6eBkJ.d.mts.map +1 -0
  56. package/dist/nestjs/index.d.mts +6 -6
  57. package/dist/nestjs/index.mjs +5 -5
  58. package/dist/nestjs/index.mjs.map +1 -1
  59. package/dist/next/client.d.mts +2 -2
  60. package/dist/next/client.mjs +1 -1
  61. package/dist/next/client.mjs.map +1 -1
  62. package/dist/next/index.d.mts +9 -9
  63. package/dist/next/index.d.mts.map +1 -1
  64. package/dist/next/index.mjs +12 -12
  65. package/dist/next/index.mjs.map +1 -1
  66. package/dist/nitro/errorHandler.mjs +2 -1
  67. package/dist/nitro/errorHandler.mjs.map +1 -1
  68. package/dist/nitro/module.d.mts +2 -2
  69. package/dist/nitro/module.mjs.map +1 -1
  70. package/dist/nitro/plugin.mjs +8 -8
  71. package/dist/nitro/plugin.mjs.map +1 -1
  72. package/dist/nitro/v3/errorHandler.mjs +3 -2
  73. package/dist/nitro/v3/errorHandler.mjs.map +1 -1
  74. package/dist/nitro/v3/middleware.d.mts +1 -1
  75. package/dist/nitro/v3/middleware.mjs +1 -1
  76. package/dist/nitro/v3/middleware.mjs.map +1 -1
  77. package/dist/nitro/v3/module.d.mts +1 -1
  78. package/dist/nitro/v3/module.mjs +3 -1
  79. package/dist/nitro/v3/module.mjs.map +1 -1
  80. package/dist/nitro/v3/plugin.d.mts +4 -2
  81. package/dist/nitro/v3/plugin.mjs +11 -11
  82. package/dist/nitro/v3/plugin.mjs.map +1 -1
  83. package/dist/nitro/v3/useLogger.d.mts +1 -1
  84. package/dist/nitro/v3/useLogger.mjs +1 -1
  85. package/dist/nitro/v3/useLogger.mjs.map +1 -1
  86. package/dist/{nitro-BsDTWASN.mjs → nitro-BYA2IdQR.mjs} +4 -9
  87. package/dist/nitro-BYA2IdQR.mjs.map +1 -0
  88. package/dist/{nitro-iuEZtGVq.d.mts → nitro-Bqj5GhQh.d.mts} +2 -2
  89. package/dist/nitro-Bqj5GhQh.d.mts.map +1 -0
  90. package/dist/nuxt/module.d.mts +3 -3
  91. package/dist/nuxt/module.mjs +4 -4
  92. package/dist/nuxt/module.mjs.map +1 -1
  93. package/dist/{parseError-DGjBRrb3.d.mts → parseError-Ljsd4G0m.d.mts} +2 -2
  94. package/dist/parseError-Ljsd4G0m.d.mts.map +1 -0
  95. package/dist/pipeline.d.mts +1 -1
  96. package/dist/pipeline.mjs +7 -7
  97. package/dist/pipeline.mjs.map +1 -1
  98. package/dist/{routes-DdmLpEnG.mjs → routes-CE3_c-iZ.mjs} +1 -1
  99. package/dist/{routes-DdmLpEnG.mjs.map → routes-CE3_c-iZ.mjs.map} +1 -1
  100. package/dist/runtime/client/log.d.mts +1 -1
  101. package/dist/runtime/client/log.d.mts.map +1 -1
  102. package/dist/runtime/client/log.mjs +5 -11
  103. package/dist/runtime/client/log.mjs.map +1 -1
  104. package/dist/runtime/server/useLogger.d.mts +1 -1
  105. package/dist/runtime/server/useLogger.mjs +1 -1
  106. package/dist/runtime/server/useLogger.mjs.map +1 -1
  107. package/dist/runtime/utils/parseError.d.mts +2 -2
  108. package/dist/{storage-CZLHKrbu.mjs → storage-CxDBSIoI.mjs} +6 -4
  109. package/dist/storage-CxDBSIoI.mjs.map +1 -0
  110. package/dist/sveltekit/index.d.mts +11 -11
  111. package/dist/sveltekit/index.mjs +13 -12
  112. package/dist/sveltekit/index.mjs.map +1 -1
  113. package/dist/toolkit.d.mts +38 -0
  114. package/dist/toolkit.d.mts.map +1 -0
  115. package/dist/toolkit.mjs +5 -0
  116. package/dist/{types-abpnM9XB.d.mts → types-B82IuY7M.d.mts} +18 -18
  117. package/dist/types-B82IuY7M.d.mts.map +1 -0
  118. package/dist/types.d.mts +1 -1
  119. package/dist/{useLogger-DW6-kpBP.d.mts → useLogger-B4LUeTYl.d.mts} +2 -2
  120. package/dist/{useLogger-DW6-kpBP.d.mts.map → useLogger-B4LUeTYl.d.mts.map} +1 -1
  121. package/dist/utils.d.mts +18 -2
  122. package/dist/utils.d.mts.map +1 -1
  123. package/dist/utils.mjs +27 -1
  124. package/dist/utils.mjs.map +1 -1
  125. package/dist/workers.d.mts +2 -2
  126. package/dist/workers.mjs +1 -1
  127. package/dist/workers.mjs.map +1 -1
  128. package/package.json +76 -34
  129. package/dist/_http-CTtzGDc6.mjs.map +0 -1
  130. package/dist/headers-BnDMFr6p.mjs.map +0 -1
  131. package/dist/middleware-CVOU14aj.d.mts +0 -36
  132. package/dist/middleware-CVOU14aj.d.mts.map +0 -1
  133. package/dist/nitro-BsDTWASN.mjs.map +0 -1
  134. package/dist/nitro-iuEZtGVq.d.mts.map +0 -1
  135. package/dist/parseError-DGjBRrb3.d.mts.map +0 -1
  136. package/dist/storage-CZLHKrbu.mjs.map +0 -1
  137. package/dist/types-abpnM9XB.d.mts.map +0 -1
package/README.md CHANGED
@@ -203,7 +203,7 @@ export default defineNitroConfig({
203
203
  })
204
204
  ```
205
205
 
206
- Then use `useLogger` in any route. Import from `mxllog/nitro/v3` (v3) or `mxllog/nitro` (v2):
206
+ Then use `useLogger` in any route. Import from `@safaricom-mxl/log/nitro/v3` (v3) or `@safaricom-mxl/log/nitro` (v2):
207
207
 
208
208
  ```typescript
209
209
  // routes/api/documents/[id]/export.post.ts
@@ -375,43 +375,116 @@ Notes:
375
375
 
376
376
  ## Hono
377
377
 
378
- Use the standalone API to create one wide event per request from a Hono middleware.
379
-
380
378
  ```typescript
381
379
  // src/index.ts
382
- import { serve } from '@hono/node-server'
383
380
  import { Hono } from 'hono'
384
- import { createRequestLogger, initLogger } from '@safaricom-mxl/log'
381
+ import { initLogger } from '@safaricom-mxl/log'
382
+ import { mxllog, type MxllogVariables } from '@safaricom-mxl/log/hono'
385
383
 
386
- initLogger({
387
- env: { service: 'hono-api' },
384
+ initLogger({ env: { service: 'hono-api' } })
385
+
386
+ const app = new Hono<MxllogVariables>()
387
+ app.use(mxllog())
388
+
389
+ app.get('/api/users', (c) => {
390
+ const log = c.get('log')
391
+ log.set({ users: { count: 42 } })
392
+ return c.json({ users: [] })
388
393
  })
394
+ ```
389
395
 
390
- const app = new Hono()
396
+ See the full [hono example](https://github.com/HugoRCD/mxllog/tree/main/examples/hono) for a complete working project.
391
397
 
392
- app.use('*', async (c, next) => {
393
- const startedAt = Date.now()
394
- const log = createRequestLogger({ method: c.req.method, path: c.req.path })
398
+ ## Express
395
399
 
396
- try {
397
- await next()
398
- } catch (error) {
399
- log.error(error as Error)
400
- throw error
401
- } finally {
402
- log.emit({
403
- status: c.res.status,
404
- duration: Date.now() - startedAt,
405
- })
406
- }
400
+ ```typescript
401
+ // src/index.ts
402
+ import express from 'express'
403
+ import { initLogger } from '@safaricom-mxl/log'
404
+ import { mxllog, useLogger } from '@safaricom-mxl/log/express'
405
+
406
+ initLogger({ env: { service: 'express-api' } })
407
+
408
+ const app = express()
409
+ app.use(mxllog())
410
+
411
+ app.get('/api/users', (req, res) => {
412
+ req.log.set({ users: { count: 42 } })
413
+ res.json({ users: [] })
407
414
  })
415
+ ```
416
+
417
+ Use `useLogger()` to access the logger from anywhere in the call stack without passing `req`.
418
+
419
+ See the full [express example](https://github.com/HugoRCD/mxllog/tree/main/examples/express) for a complete working project.
420
+
421
+ ## Fastify
422
+
423
+ ```typescript
424
+ // src/index.ts
425
+ import Fastify from 'fastify'
426
+ import { initLogger } from '@safaricom-mxl/log'
427
+ import { mxllog, useLogger } from '@safaricom-mxl/log/fastify'
428
+
429
+ initLogger({ env: { service: 'fastify-api' } })
408
430
 
409
- app.get('/health', (c) => c.json({ ok: true }))
431
+ const app = Fastify({ logger: false })
432
+ await app.register(mxllog)
410
433
 
411
- serve({ fetch: app.fetch, port: 3000 })
434
+ app.get('/api/users', async (request) => {
435
+ request.log.set({ users: { count: 42 } })
436
+ return { users: [] }
437
+ })
412
438
  ```
413
439
 
414
- See the full [hono example](https://github.com/HugoRCD/mxllog/tree/main/examples/hono) for a complete working project.
440
+ `request.log` is the mxllog wide-event logger (shadows Fastify's built-in pino logger on the request). Use `useLogger()` to access the logger from anywhere in the call stack.
441
+
442
+ See the full [fastify example](https://github.com/HugoRCD/mxllog/tree/main/examples/fastify) for a complete working project.
443
+
444
+ ## Elysia
445
+
446
+ ```typescript
447
+ // src/index.ts
448
+ import { Elysia } from 'elysia'
449
+ import { initLogger } from '@safaricom-mxl/log'
450
+ import { mxllog, useLogger } from '@safaricom-mxl/log/elysia'
451
+
452
+ initLogger({ env: { service: 'elysia-api' } })
453
+
454
+ const app = new Elysia()
455
+ .use(mxllog())
456
+ .get('/api/users', ({ log }) => {
457
+ log.set({ users: { count: 42 } })
458
+ return { users: [] }
459
+ })
460
+ .listen(3000)
461
+ ```
462
+
463
+ Use `useLogger()` to access the logger from anywhere in the call stack.
464
+
465
+ See the full [elysia example](https://github.com/HugoRCD/mxllog/tree/main/examples/elysia) for a complete working project.
466
+
467
+ ## NestJS
468
+
469
+ ```typescript
470
+ // src/app.module.ts
471
+ import { Module } from '@nestjs/common'
472
+ import { MxllogModule } from '@safaricom-mxl/log/nestjs'
473
+
474
+ @Module({
475
+ imports: [MxllogModule.forRoot()],
476
+ })
477
+ export class AppModule {}
478
+
479
+ // In any controller or service:
480
+ import { useLogger } from '@safaricom-mxl/log/nestjs'
481
+ const log = useLogger()
482
+ log.set({ users: { count: 42 } })
483
+ ```
484
+
485
+ `MxllogModule.forRoot()` registers a global middleware that creates a request-scoped logger for every request. Use `useLogger()` to access it anywhere in the call stack, or `req.log` directly. Supports `forRootAsync()` for async configuration.
486
+
487
+ See the full [nestjs example](https://github.com/HugoRCD/mxllog/tree/main/examples/nestjs) for a complete working project.
415
488
 
416
489
  ## Browser
417
490
 
@@ -504,7 +577,7 @@ Use the `mxllog:enrich` hook to add derived context after emit, before drain.
504
577
  ```typescript
505
578
  // server/plugins/mxllog-enrich.ts
506
579
  export default defineNitroPlugin((nitroApp) => {
507
- nitroApp.hooks.hook('@safaricom-mxl/log:enrich', (ctx) => {
580
+ nitroApp.hooks.hook('mxllog:enrich', (ctx) => {
508
581
  ctx.event.deploymentId = process.env.DEPLOYMENT_ID
509
582
  })
510
583
  })
@@ -529,7 +602,7 @@ export default defineNitroPlugin((nitroApp) => {
529
602
  createTraceContextEnricher(),
530
603
  ]
531
604
 
532
- nitroApp.hooks.hook('@safaricom-mxl/log:enrich', (ctx) => {
605
+ nitroApp.hooks.hook('mxllog:enrich', (ctx) => {
533
606
  for (const enricher of enrich) enricher(ctx)
534
607
  })
535
608
  })
@@ -573,7 +646,7 @@ Example custom enricher:
573
646
  ```typescript
574
647
  // server/plugins/mxllog-enrich.ts
575
648
  export default defineNitroPlugin((nitroApp) => {
576
- nitroApp.hooks.hook('@safaricom-mxl/log:enrich', (ctx) => {
649
+ nitroApp.hooks.hook('mxllog:enrich', (ctx) => {
577
650
  // Add deployment metadata
578
651
  ctx.event.deploymentId = process.env.DEPLOYMENT_ID
579
652
  ctx.event.region = process.env.FLY_REGION
@@ -598,7 +671,7 @@ Send your logs to external observability platforms with built-in adapters.
598
671
  import { createAxiomDrain } from '@safaricom-mxl/log/axiom'
599
672
 
600
673
  export default defineNitroPlugin((nitroApp) => {
601
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain())
674
+ nitroApp.hooks.hook('mxllog:drain', createAxiomDrain())
602
675
  })
603
676
  ```
604
677
 
@@ -618,7 +691,7 @@ Works with Grafana, Datadog, Honeycomb, and any OTLP-compatible backend.
618
691
  import { createOTLPDrain } from '@safaricom-mxl/log/otlp'
619
692
 
620
693
  export default defineNitroPlugin((nitroApp) => {
621
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', createOTLPDrain())
694
+ nitroApp.hooks.hook('mxllog:drain', createOTLPDrain())
622
695
  })
623
696
  ```
624
697
 
@@ -635,7 +708,7 @@ NUXT_OTLP_ENDPOINT=http://localhost:4318
635
708
  import { createPostHogDrain } from '@safaricom-mxl/log/posthog'
636
709
 
637
710
  export default defineNitroPlugin((nitroApp) => {
638
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', createPostHogDrain())
711
+ nitroApp.hooks.hook('mxllog:drain', createPostHogDrain())
639
712
  })
640
713
  ```
641
714
 
@@ -653,7 +726,7 @@ NUXT_POSTHOG_HOST=https://us.i.posthog.com # Optional: for EU or self-hosted
653
726
  import { createSentryDrain } from '@safaricom-mxl/log/sentry'
654
727
 
655
728
  export default defineNitroPlugin((nitroApp) => {
656
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', createSentryDrain())
729
+ nitroApp.hooks.hook('mxllog:drain', createSentryDrain())
657
730
  })
658
731
  ```
659
732
 
@@ -670,7 +743,7 @@ NUXT_SENTRY_DSN=https://public@o0.ingest.sentry.io/123
670
743
  import { createBetterStackDrain } from '@safaricom-mxl/log/better-stack'
671
744
 
672
745
  export default defineNitroPlugin((nitroApp) => {
673
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain())
746
+ nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain())
674
747
  })
675
748
  ```
676
749
 
@@ -693,7 +766,7 @@ export default defineNitroPlugin((nitroApp) => {
693
766
  const axiom = createAxiomDrain()
694
767
  const otlp = createOTLPDrain()
695
768
 
696
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', async (ctx) => {
769
+ nitroApp.hooks.hook('mxllog:drain', async (ctx) => {
697
770
  await Promise.allSettled([axiom(ctx), otlp(ctx)])
698
771
  })
699
772
  })
@@ -706,7 +779,7 @@ Build your own adapter for any destination:
706
779
  ```typescript
707
780
  // server/plugins/mxllog-drain.ts
708
781
  export default defineNitroPlugin((nitroApp) => {
709
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', async (ctx) => {
782
+ nitroApp.hooks.hook('mxllog:drain', async (ctx) => {
710
783
  await fetch('https://your-service.com/logs', {
711
784
  method: 'POST',
712
785
  headers: { 'Content-Type': 'application/json' },
@@ -741,7 +814,7 @@ export default defineNitroPlugin((nitroApp) => {
741
814
 
742
815
  const drain = pipeline(createAxiomDrain())
743
816
 
744
- nitroApp.hooks.hook('@safaricom-mxl/log:drain', drain)
817
+ nitroApp.hooks.hook('mxllog:drain', drain)
745
818
  nitroApp.hooks.hook('close', () => drain.flush())
746
819
  })
747
820
  ```
@@ -859,7 +932,7 @@ For business-specific conditions (premium users, feature flags), use the `mxllog
859
932
  ```typescript
860
933
  // server/plugins/mxllog-custom.ts
861
934
  export default defineNitroPlugin((nitroApp) => {
862
- nitroApp.hooks.hook('@safaricom-mxl/log:emit:keep', (ctx) => {
935
+ nitroApp.hooks.hook('mxllog:emit:keep', (ctx) => {
863
936
  // Always keep logs for premium users
864
937
  if (ctx.context.user?.premium) {
865
938
  ctx.shouldKeep = true
@@ -940,7 +1013,7 @@ log.emit({ status: 200 })
940
1013
 
941
1014
  ### `createError(options)`
942
1015
 
943
- Create a structured error with HTTP status support. Import from `mxllog` directly to avoid conflicts with Nuxt/Nitro's `createError`.
1016
+ Create a structured error with HTTP status support. Import from `@safaricom-mxl/log` directly to avoid conflicts with Nuxt/Nitro's `createError`.
944
1017
 
945
1018
  > **Note**: `createMxllogError` is also available as an auto-imported alias in Nuxt/Nitro to avoid conflicts.
946
1019
 
@@ -991,16 +1064,24 @@ try {
991
1064
  |-----------|-------------|
992
1065
  | **Nuxt** | `modules: ['@safaricom-mxl/log/nuxt']` |
993
1066
  | **Next.js** | `createMxllog()` factory with `import { createMxllog } from '@safaricom-mxl/log/next'` ([example](./examples/nextjs)) |
1067
+ | **SvelteKit** | `export const { handle, handleError } = createMxllogHooks()` with `import { createMxllogHooks } from '@safaricom-mxl/log/sveltekit'` ([example](./examples/sveltekit)) |
994
1068
  | **Nitro v3** | `modules: [mxllog()]` with `import mxllog from '@safaricom-mxl/log/nitro/v3'` |
995
1069
  | **Nitro v2** | `modules: [mxllog()]` with `import mxllog from '@safaricom-mxl/log/nitro'` |
1070
+ | **TanStack Start** | Nitro v3 module setup ([example](./examples/tanstack-start)) |
1071
+ | **NestJS** | `MxllogModule.forRoot()` with `import { MxllogModule } from '@safaricom-mxl/log/nestjs'` ([example](./examples/nestjs)) |
1072
+ | **Express** | `app.use(mxllog())` with `import { mxllog } from '@safaricom-mxl/log/express'` ([example](./examples/express)) |
1073
+ | **Hono** | `app.use(mxllog())` with `import { mxllog } from '@safaricom-mxl/log/hono'` ([example](./examples/hono)) |
1074
+ | **Fastify** | `app.register(mxllog)` with `import { mxllog } from '@safaricom-mxl/log/fastify'` ([example](./examples/fastify)) |
1075
+ | **Elysia** | `.use(mxllog())` with `import { mxllog } from '@safaricom-mxl/log/elysia'` ([example](./examples/elysia)) |
1076
+ | **Cloudflare Workers** | Manual setup with `import { initLogger, createRequestLogger } from '@safaricom-mxl/log'` ([example](./examples/workers)) |
1077
+ | **Custom** | Build your own with `import { createMiddlewareLogger } from '@safaricom-mxl/log/toolkit'` ([guide](https://mxllog.dev/frameworks/custom-integration)) |
996
1078
  | **Analog** | Nitro v2 module setup |
997
1079
  | **Vinxi** | Nitro v2 module setup |
998
1080
  | **SolidStart** | Nitro v2 module setup ([example](./examples/solidstart)) |
999
- | **TanStack Start** | Nitro v3 module setup ([example](./examples/tanstack-start)) |
1000
1081
 
1001
1082
  ## Agent Skills
1002
1083
 
1003
- mxllog provides [Agent Skills](https://github.com/boristane/agent-skills) to help AI coding assistants understand and implement proper logging patterns in your codebase.
1084
+ mxllog provides [Agent Skills](https://www.mxllog.dev/getting-started/agent-skills) to help AI coding assistants understand and implement proper logging patterns in your codebase.
1004
1085
 
1005
1086
  ### Installation
1006
1087
 
@@ -41,7 +41,7 @@ function defineDrain(options) {
41
41
  try {
42
42
  await options.send(contexts.map((c) => c.event), config);
43
43
  } catch (error) {
44
- console.error(`[@safaricom-mxl/log/${options.name}] Failed to send events:`, error);
44
+ console.error(`[mxllog/${options.name}] Failed to send events:`, error);
45
45
  }
46
46
  };
47
47
  }
@@ -69,4 +69,4 @@ async function httpPost({ url, headers, body, timeout, label }) {
69
69
  //#endregion
70
70
  export { defineDrain as n, resolveAdapterConfig as r, httpPost as t };
71
71
 
72
- //# sourceMappingURL=_http-CTtzGDc6.mjs.map
72
+ //# sourceMappingURL=_http-BpkAshj6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_http-BpkAshj6.mjs","names":[],"sources":["../src/adapters/_config.ts","../src/adapters/_drain.ts","../src/adapters/_http.ts"],"sourcesContent":["/**\n * Try to get runtime config from Nitro/Nuxt environment.\n * Returns undefined if not in a Nitro context.\n */\nexport function getRuntimeConfig(): Record<string, any> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { useRuntimeConfig } = require('nitropack/runtime')\n return useRuntimeConfig()\n } catch {\n return undefined\n }\n}\n\nexport interface ConfigField<T> {\n key: keyof T & string\n env?: string[]\n}\n\nexport function resolveAdapterConfig<T>(\n namespace: string,\n fields: ConfigField<T>[],\n overrides?: Partial<T>,\n): Partial<T> {\n const runtimeConfig = getRuntimeConfig()\n const mxllogNs = runtimeConfig?.mxllog?.[namespace]\n const rootNs = runtimeConfig?.[namespace]\n\n const config: Record<string, unknown> = {}\n\n for (const { key, env } of fields) {\n config[key] =\n overrides?.[key]\n ?? mxllogNs?.[key]\n ?? rootNs?.[key]\n ?? resolveEnv(env)\n }\n\n return config as Partial<T>\n}\n\nfunction resolveEnv(envKeys?: string[]): string | undefined {\n if (!envKeys) return undefined\n for (const key of envKeys) {\n const val = process.env[key]\n if (val) return val\n }\n return undefined\n}\n","import type { DrainContext, WideEvent } from '../types'\n\nexport interface DrainOptions<TConfig> {\n name: string\n resolve: () => TConfig | null\n send: (events: WideEvent[], config: TConfig) => Promise<void>\n}\n\nexport function defineDrain<TConfig>(options: DrainOptions<TConfig>): (ctx: DrainContext | DrainContext[]) => Promise<void> {\n return async (ctx: DrainContext | DrainContext[]) => {\n const contexts = Array.isArray(ctx) ? ctx : [ctx]\n if (contexts.length === 0) return\n\n const config = options.resolve()\n if (!config) return\n\n try {\n await options.send(contexts.map(c => c.event), config)\n } catch (error) {\n console.error(`[mxllog/${options.name}] Failed to send events:`, error)\n }\n }\n}\n","export interface HttpPostOptions {\n url: string\n headers: Record<string, string>\n body: string\n timeout: number\n label: string\n}\n\nexport async function httpPost({ url, headers, body, timeout, label }: HttpPostOptions): Promise<void> {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body,\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => 'Unknown error')\n const safeText = text.length > 200 ? `${text.slice(0, 200)}...[truncated]` : text\n throw new Error(`${label} API error: ${response.status} ${response.statusText} - ${safeText}`)\n }\n } finally {\n clearTimeout(timeoutId)\n }\n}\n"],"mappings":";;;;;;;;;AAIA,SAAgB,mBAAoD;AAClE,KAAI;EAEF,MAAM,EAAE,qBAAA,UAA6B,oBAAoB;AACzD,SAAO,kBAAkB;SACnB;AACN;;;AASJ,SAAgB,qBACd,WACA,QACA,WACY;CACZ,MAAM,gBAAgB,kBAAkB;CACxC,MAAM,WAAW,eAAe,SAAS;CACzC,MAAM,SAAS,gBAAgB;CAE/B,MAAM,SAAkC,EAAE;AAE1C,MAAK,MAAM,EAAE,KAAK,SAAS,OACzB,QAAO,OACL,YAAY,QACT,WAAW,QACX,SAAS,QACT,WAAW,IAAI;AAGtB,QAAO;;AAGT,SAAS,WAAW,SAAwC;AAC1D,KAAI,CAAC,QAAS,QAAO,KAAA;AACrB,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,IAAK,QAAO;;;;;ACrCpB,SAAgB,YAAqB,SAAuF;AAC1H,QAAO,OAAO,QAAuC;EACnD,MAAM,WAAW,MAAM,QAAQ,IAAI,GAAG,MAAM,CAAC,IAAI;AACjD,MAAI,SAAS,WAAW,EAAG;EAE3B,MAAM,SAAS,QAAQ,SAAS;AAChC,MAAI,CAAC,OAAQ;AAEb,MAAI;AACF,SAAM,QAAQ,KAAK,SAAS,KAAI,MAAK,EAAE,MAAM,EAAE,OAAO;WAC/C,OAAO;AACd,WAAQ,MAAM,WAAW,QAAQ,KAAK,2BAA2B,MAAM;;;;;;ACX7E,eAAsB,SAAS,EAAE,KAAK,SAAS,MAAM,SAAS,SAAyC;CACrG,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,QAAQ;AAE/D,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR;GACA;GACA,QAAQ,WAAW;GACpB,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,gBAAgB;GAC/D,MAAM,WAAW,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC,kBAAkB;AAC7E,SAAM,IAAI,MAAM,GAAG,MAAM,cAAc,SAAS,OAAO,GAAG,SAAS,WAAW,KAAK,WAAW;;WAExF;AACR,eAAa,UAAU"}
@@ -14,4 +14,4 @@ const OTEL_SEVERITY_TEXT = {
14
14
  //#endregion
15
15
  export { OTEL_SEVERITY_TEXT as n, OTEL_SEVERITY_NUMBER as t };
16
16
 
17
- //# sourceMappingURL=_severity-CLNgC2HU.mjs.map
17
+ //# sourceMappingURL=_severity-Q1BuITU_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_severity-CLNgC2HU.mjs","names":[],"sources":["../src/adapters/_severity.ts"],"sourcesContent":["import type { LogLevel } from '../types'\n\nexport const OTEL_SEVERITY_NUMBER: Record<LogLevel, number> = {\n debug: 5,\n info: 9,\n warn: 13,\n error: 17,\n}\n\nexport const OTEL_SEVERITY_TEXT: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n}\n"],"mappings":";AAEA,MAAa,uBAAiD;CAC5D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;AAED,MAAa,qBAA+C;CAC1D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR"}
1
+ {"version":3,"file":"_severity-Q1BuITU_.mjs","names":[],"sources":["../src/adapters/_severity.ts"],"sourcesContent":["import type { LogLevel } from '../types'\n\nexport const OTEL_SEVERITY_NUMBER: Record<LogLevel, number> = {\n debug: 5,\n info: 9,\n warn: 13,\n error: 17,\n}\n\nexport const OTEL_SEVERITY_TEXT: Record<LogLevel, string> = {\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n}\n"],"mappings":";AAEA,MAAa,uBAAiD;CAC5D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;AAED,MAAa,qBAA+C;CAC1D,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR"}
@@ -1,4 +1,4 @@
1
- import { T as WideEvent, r as DrainContext } from "../types-abpnM9XB.mjs";
1
+ import { T as WideEvent, r as DrainContext } from "../types-B82IuY7M.mjs";
2
2
  //#region src/adapters/axiom.d.ts
3
3
  interface BaseAxiomConfig {
4
4
  /** Axiom dataset name */
@@ -39,10 +39,10 @@ type AxiomConfig = BaseAxiomConfig & (EdgeAxiomConfig | EndpointAxiomConfig);
39
39
  * @example
40
40
  * ```ts
41
41
  * // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars
42
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain())
42
+ * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain())
43
43
  *
44
44
  * // With overrides
45
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain({
45
+ * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain({
46
46
  * dataset: 'my-dataset',
47
47
  * }))
48
48
  * ```
@@ -1,4 +1,4 @@
1
- import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-CTtzGDc6.mjs";
1
+ import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-BpkAshj6.mjs";
2
2
  //#region src/adapters/axiom.ts
3
3
  const AXIOM_FIELDS = [
4
4
  {
@@ -35,10 +35,10 @@ const AXIOM_FIELDS = [
35
35
  * @example
36
36
  * ```ts
37
37
  * // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars
38
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain())
38
+ * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain())
39
39
  *
40
40
  * // With overrides
41
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain({
41
+ * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain({
42
42
  * dataset: 'my-dataset',
43
43
  * }))
44
44
  * ```
@@ -49,11 +49,11 @@ function createAxiomDrain(overrides) {
49
49
  resolve: () => {
50
50
  const config = resolveAdapterConfig("axiom", AXIOM_FIELDS, overrides);
51
51
  if (!config.dataset || !config.token) {
52
- console.error("[@safaricom-mxl/log/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()");
52
+ console.error("[mxllog/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()");
53
53
  return null;
54
54
  }
55
55
  if (config.edgeUrl && config.baseUrl) {
56
- console.warn("[@safaricom-mxl/log/axiom] Both edgeUrl and baseUrl are set. edgeUrl takes precedence for ingest.");
56
+ console.warn("[mxllog/axiom] Both edgeUrl and baseUrl are set. edgeUrl takes precedence for ingest.");
57
57
  delete config.baseUrl;
58
58
  }
59
59
  return config;
@@ -113,7 +113,7 @@ function resolveIngestUrl(config) {
113
113
  parsed.pathname = parsed.pathname.replace(/\/+$/, "");
114
114
  return parsed.toString();
115
115
  } catch {
116
- console.warn(`[@safaricom-mxl/log/axiom] edgeUrl "${config.edgeUrl}" is not a valid URL, falling back to string concatenation.`);
116
+ console.warn(`[mxllog/axiom] edgeUrl "${config.edgeUrl}" is not a valid URL, falling back to string concatenation.`);
117
117
  return `${config.edgeUrl.replace(/\/+$/, "")}/v1/ingest/${encodedDataset}`;
118
118
  }
119
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"axiom.mjs","names":[],"sources":["../../src/adapters/axiom.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\n\ninterface BaseAxiomConfig {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\ninterface EdgeAxiomConfig {\n /**\n * Edge URL for Axiom ingest/query endpoints.\n * If no path is provided, uses /v1/ingest/{dataset}.\n * If a custom path is provided, it is used as-is (trailing slash trimmed).\n */\n edgeUrl: string\n /** Mutually exclusive with edgeUrl. */\n baseUrl?: never\n}\n\ninterface EndpointAxiomConfig {\n /** Base URL for Axiom API. Uses /v1/datasets/{dataset}/ingest. */\n baseUrl?: string\n /** Mutually exclusive with baseUrl. */\n edgeUrl?: never\n}\n\nexport type AxiomConfig = BaseAxiomConfig & (EdgeAxiomConfig | EndpointAxiomConfig)\n\ntype ResolvedAxiomConfig = BaseAxiomConfig & {\n edgeUrl?: string\n baseUrl?: string\n}\n\nconst AXIOM_FIELDS: ConfigField<ResolvedAxiomConfig>[] = [\n { key: 'dataset', env: ['NUXT_AXIOM_DATASET', 'AXIOM_DATASET'] },\n { key: 'token', env: ['NUXT_AXIOM_TOKEN', 'AXIOM_TOKEN'] },\n { key: 'orgId', env: ['NUXT_AXIOM_ORG_ID', 'AXIOM_ORG_ID'] },\n { key: 'edgeUrl', env: ['NUXT_AXIOM_EDGE_URL', 'AXIOM_EDGE_URL'] },\n { key: 'baseUrl', env: ['NUXT_AXIOM_URL', 'AXIOM_URL'] },\n { key: 'timeout' },\n]\n\n/**\n * Create a drain function for sending logs to Axiom.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createAxiomDrain()\n * 2. runtimeConfig.mxllog.axiom\n * 3. runtimeConfig.axiom\n * 4. Environment variables: NUXT_AXIOM_*, AXIOM_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars\n * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createAxiomDrain({\n * dataset: 'my-dataset',\n * }))\n * ```\n */\nexport function createAxiomDrain(overrides?: Partial<AxiomConfig>) {\n return defineDrain<AxiomConfig>({\n name: 'axiom',\n resolve: () => {\n const config = resolveAdapterConfig<ResolvedAxiomConfig>(\n 'axiom',\n AXIOM_FIELDS,\n overrides as Partial<ResolvedAxiomConfig>,\n )\n if (!config.dataset || !config.token) {\n console.error('[@safaricom-mxl/log/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()')\n return null\n }\n\n if (config.edgeUrl && config.baseUrl) {\n console.warn('[@safaricom-mxl/log/axiom] Both edgeUrl and baseUrl are set. edgeUrl takes precedence for ingest.')\n delete config.baseUrl\n }\n\n return config as AxiomConfig\n },\n send: sendBatchToAxiom,\n })\n}\n\n/**\n * Send a single event to Axiom.\n *\n * @example\n * ```ts\n * await sendToAxiom(event, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendToAxiom(event: WideEvent, config: AxiomConfig): Promise<void> {\n await sendBatchToAxiom([event], config)\n}\n\n/**\n * Send a batch of events to Axiom.\n *\n * @example\n * ```ts\n * await sendBatchToAxiom(events, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToAxiom(events: WideEvent[], config: AxiomConfig): Promise<void> {\n const url = resolveIngestUrl(config)\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.token}`,\n }\n\n if (config.orgId) {\n headers['X-Axiom-Org-Id'] = config.orgId\n }\n\n await httpPost({\n url,\n headers,\n body: JSON.stringify(events),\n timeout: config.timeout ?? 5000,\n label: 'Axiom',\n })\n}\n\nfunction resolveIngestUrl(config: AxiomConfig): string {\n const encodedDataset = encodeURIComponent(config.dataset)\n\n if (!config.edgeUrl) {\n const baseUrl = config.baseUrl ?? 'https://api.axiom.co'\n return `${baseUrl}/v1/datasets/${encodedDataset}/ingest`\n }\n\n try {\n const parsed = new URL(config.edgeUrl)\n\n if (parsed.pathname === '' || parsed.pathname === '/') {\n parsed.pathname = `/v1/ingest/${encodedDataset}`\n return parsed.toString()\n }\n\n parsed.pathname = parsed.pathname.replace(/\\/+$/, '')\n return parsed.toString()\n } catch {\n console.warn(`[@safaricom-mxl/log/axiom] edgeUrl \"${config.edgeUrl}\" is not a valid URL, falling back to string concatenation.`)\n const trimmed = config.edgeUrl.replace(/\\/+$/, '')\n return `${trimmed}/v1/ingest/${encodedDataset}`\n }\n}\n"],"mappings":";;AA0CA,MAAM,eAAmD;CACvD;EAAE,KAAK;EAAW,KAAK,CAAC,sBAAsB,gBAAgB;EAAE;CAChE;EAAE,KAAK;EAAS,KAAK,CAAC,oBAAoB,cAAc;EAAE;CAC1D;EAAE,KAAK;EAAS,KAAK,CAAC,qBAAqB,eAAe;EAAE;CAC5D;EAAE,KAAK;EAAW,KAAK,CAAC,uBAAuB,iBAAiB;EAAE;CAClE;EAAE,KAAK;EAAW,KAAK,CAAC,kBAAkB,YAAY;EAAE;CACxD,EAAE,KAAK,WAAW;CACnB;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,iBAAiB,WAAkC;AACjE,QAAO,YAAyB;EAC9B,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBACb,SACA,cACA,UACD;AACD,OAAI,CAAC,OAAO,WAAW,CAAC,OAAO,OAAO;AACpC,YAAQ,MAAM,sIAAsI;AACpJ,WAAO;;AAGT,OAAI,OAAO,WAAW,OAAO,SAAS;AACpC,YAAQ,KAAK,oGAAoG;AACjH,WAAO,OAAO;;AAGhB,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;;AAcJ,eAAsB,YAAY,OAAkB,QAAoC;AACtF,OAAM,iBAAiB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;;AAczC,eAAsB,iBAAiB,QAAqB,QAAoC;CAC9F,MAAM,MAAM,iBAAiB,OAAO;CAEpC,MAAM,UAAkC;EACtC,gBAAgB;EAChB,iBAAiB,UAAU,OAAO;EACnC;AAED,KAAI,OAAO,MACT,SAAQ,oBAAoB,OAAO;AAGrC,OAAM,SAAS;EACb;EACA;EACA,MAAM,KAAK,UAAU,OAAO;EAC5B,SAAS,OAAO,WAAW;EAC3B,OAAO;EACR,CAAC;;AAGJ,SAAS,iBAAiB,QAA6B;CACrD,MAAM,iBAAiB,mBAAmB,OAAO,QAAQ;AAEzD,KAAI,CAAC,OAAO,QAEV,QAAO,GADS,OAAO,WAAW,uBAChB,eAAe,eAAe;AAGlD,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,OAAO,QAAQ;AAEtC,MAAI,OAAO,aAAa,MAAM,OAAO,aAAa,KAAK;AACrD,UAAO,WAAW,cAAc;AAChC,UAAO,OAAO,UAAU;;AAG1B,SAAO,WAAW,OAAO,SAAS,QAAQ,QAAQ,GAAG;AACrD,SAAO,OAAO,UAAU;SAClB;AACN,UAAQ,KAAK,uCAAuC,OAAO,QAAQ,6DAA6D;AAEhI,SAAO,GADS,OAAO,QAAQ,QAAQ,QAAQ,GAAG,CAChC,aAAa"}
1
+ {"version":3,"file":"axiom.mjs","names":[],"sources":["../../src/adapters/axiom.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\n\ninterface BaseAxiomConfig {\n /** Axiom dataset name */\n dataset: string\n /** Axiom API token */\n token: string\n /** Organization ID (required for Personal Access Tokens) */\n orgId?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\ninterface EdgeAxiomConfig {\n /**\n * Edge URL for Axiom ingest/query endpoints.\n * If no path is provided, uses /v1/ingest/{dataset}.\n * If a custom path is provided, it is used as-is (trailing slash trimmed).\n */\n edgeUrl: string\n /** Mutually exclusive with edgeUrl. */\n baseUrl?: never\n}\n\ninterface EndpointAxiomConfig {\n /** Base URL for Axiom API. Uses /v1/datasets/{dataset}/ingest. */\n baseUrl?: string\n /** Mutually exclusive with baseUrl. */\n edgeUrl?: never\n}\n\nexport type AxiomConfig = BaseAxiomConfig & (EdgeAxiomConfig | EndpointAxiomConfig)\n\ntype ResolvedAxiomConfig = BaseAxiomConfig & {\n edgeUrl?: string\n baseUrl?: string\n}\n\nconst AXIOM_FIELDS: ConfigField<ResolvedAxiomConfig>[] = [\n { key: 'dataset', env: ['NUXT_AXIOM_DATASET', 'AXIOM_DATASET'] },\n { key: 'token', env: ['NUXT_AXIOM_TOKEN', 'AXIOM_TOKEN'] },\n { key: 'orgId', env: ['NUXT_AXIOM_ORG_ID', 'AXIOM_ORG_ID'] },\n { key: 'edgeUrl', env: ['NUXT_AXIOM_EDGE_URL', 'AXIOM_EDGE_URL'] },\n { key: 'baseUrl', env: ['NUXT_AXIOM_URL', 'AXIOM_URL'] },\n { key: 'timeout' },\n]\n\n/**\n * Create a drain function for sending logs to Axiom.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createAxiomDrain()\n * 2. runtimeConfig.mxllog.axiom\n * 3. runtimeConfig.axiom\n * 4. Environment variables: NUXT_AXIOM_*, AXIOM_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_AXIOM_TOKEN and NUXT_AXIOM_DATASET env vars\n * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('mxllog:drain', createAxiomDrain({\n * dataset: 'my-dataset',\n * }))\n * ```\n */\nexport function createAxiomDrain(overrides?: Partial<AxiomConfig>) {\n return defineDrain<AxiomConfig>({\n name: 'axiom',\n resolve: () => {\n const config = resolveAdapterConfig<ResolvedAxiomConfig>(\n 'axiom',\n AXIOM_FIELDS,\n overrides as Partial<ResolvedAxiomConfig>,\n )\n if (!config.dataset || !config.token) {\n console.error('[mxllog/axiom] Missing dataset or token. Set NUXT_AXIOM_TOKEN/NUXT_AXIOM_DATASET env vars or pass to createAxiomDrain()')\n return null\n }\n\n if (config.edgeUrl && config.baseUrl) {\n console.warn('[mxllog/axiom] Both edgeUrl and baseUrl are set. edgeUrl takes precedence for ingest.')\n delete config.baseUrl\n }\n\n return config as AxiomConfig\n },\n send: sendBatchToAxiom,\n })\n}\n\n/**\n * Send a single event to Axiom.\n *\n * @example\n * ```ts\n * await sendToAxiom(event, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendToAxiom(event: WideEvent, config: AxiomConfig): Promise<void> {\n await sendBatchToAxiom([event], config)\n}\n\n/**\n * Send a batch of events to Axiom.\n *\n * @example\n * ```ts\n * await sendBatchToAxiom(events, {\n * dataset: 'my-logs',\n * token: process.env.AXIOM_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToAxiom(events: WideEvent[], config: AxiomConfig): Promise<void> {\n const url = resolveIngestUrl(config)\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.token}`,\n }\n\n if (config.orgId) {\n headers['X-Axiom-Org-Id'] = config.orgId\n }\n\n await httpPost({\n url,\n headers,\n body: JSON.stringify(events),\n timeout: config.timeout ?? 5000,\n label: 'Axiom',\n })\n}\n\nfunction resolveIngestUrl(config: AxiomConfig): string {\n const encodedDataset = encodeURIComponent(config.dataset)\n\n if (!config.edgeUrl) {\n const baseUrl = config.baseUrl ?? 'https://api.axiom.co'\n return `${baseUrl}/v1/datasets/${encodedDataset}/ingest`\n }\n\n try {\n const parsed = new URL(config.edgeUrl)\n\n if (parsed.pathname === '' || parsed.pathname === '/') {\n parsed.pathname = `/v1/ingest/${encodedDataset}`\n return parsed.toString()\n }\n\n parsed.pathname = parsed.pathname.replace(/\\/+$/, '')\n return parsed.toString()\n } catch {\n console.warn(`[mxllog/axiom] edgeUrl \"${config.edgeUrl}\" is not a valid URL, falling back to string concatenation.`)\n const trimmed = config.edgeUrl.replace(/\\/+$/, '')\n return `${trimmed}/v1/ingest/${encodedDataset}`\n }\n}\n"],"mappings":";;AA0CA,MAAM,eAAmD;CACvD;EAAE,KAAK;EAAW,KAAK,CAAC,sBAAsB,gBAAgB;EAAE;CAChE;EAAE,KAAK;EAAS,KAAK,CAAC,oBAAoB,cAAc;EAAE;CAC1D;EAAE,KAAK;EAAS,KAAK,CAAC,qBAAqB,eAAe;EAAE;CAC5D;EAAE,KAAK;EAAW,KAAK,CAAC,uBAAuB,iBAAiB;EAAE;CAClE;EAAE,KAAK;EAAW,KAAK,CAAC,kBAAkB,YAAY;EAAE;CACxD,EAAE,KAAK,WAAW;CACnB;;;;;;;;;;;;;;;;;;;;;AAsBD,SAAgB,iBAAiB,WAAkC;AACjE,QAAO,YAAyB;EAC9B,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBACb,SACA,cACA,UACD;AACD,OAAI,CAAC,OAAO,WAAW,CAAC,OAAO,OAAO;AACpC,YAAQ,MAAM,0HAA0H;AACxI,WAAO;;AAGT,OAAI,OAAO,WAAW,OAAO,SAAS;AACpC,YAAQ,KAAK,wFAAwF;AACrG,WAAO,OAAO;;AAGhB,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;;AAcJ,eAAsB,YAAY,OAAkB,QAAoC;AACtF,OAAM,iBAAiB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;;AAczC,eAAsB,iBAAiB,QAAqB,QAAoC;CAC9F,MAAM,MAAM,iBAAiB,OAAO;CAEpC,MAAM,UAAkC;EACtC,gBAAgB;EAChB,iBAAiB,UAAU,OAAO;EACnC;AAED,KAAI,OAAO,MACT,SAAQ,oBAAoB,OAAO;AAGrC,OAAM,SAAS;EACb;EACA;EACA,MAAM,KAAK,UAAU,OAAO;EAC5B,SAAS,OAAO,WAAW;EAC3B,OAAO;EACR,CAAC;;AAGJ,SAAS,iBAAiB,QAA6B;CACrD,MAAM,iBAAiB,mBAAmB,OAAO,QAAQ;AAEzD,KAAI,CAAC,OAAO,QAEV,QAAO,GADS,OAAO,WAAW,uBAChB,eAAe,eAAe;AAGlD,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,OAAO,QAAQ;AAEtC,MAAI,OAAO,aAAa,MAAM,OAAO,aAAa,KAAK;AACrD,UAAO,WAAW,cAAc;AAChC,UAAO,OAAO,UAAU;;AAG1B,SAAO,WAAW,OAAO,SAAS,QAAQ,QAAQ,GAAG;AACrD,SAAO,OAAO,UAAU;SAClB;AACN,UAAQ,KAAK,2BAA2B,OAAO,QAAQ,6DAA6D;AAEpH,SAAO,GADS,OAAO,QAAQ,QAAQ,QAAQ,GAAG,CAChC,aAAa"}
@@ -1,4 +1,4 @@
1
- import { T as WideEvent, r as DrainContext } from "../types-abpnM9XB.mjs";
1
+ import { T as WideEvent, r as DrainContext } from "../types-B82IuY7M.mjs";
2
2
  //#region src/adapters/better-stack.d.ts
3
3
  interface BetterStackConfig {
4
4
  /** Better Stack source token */
@@ -9,7 +9,7 @@ interface BetterStackConfig {
9
9
  timeout?: number;
10
10
  }
11
11
  /**
12
- * Transform an @safaricom-mxl/log wide event into a Better Stack event.
12
+ * Transform an mxllog wide event into a Better Stack event.
13
13
  * Maps `timestamp` to `dt` (Better Stack's expected field).
14
14
  */
15
15
  declare function toBetterStackEvent(event: WideEvent): Record<string, unknown>;
@@ -25,10 +25,10 @@ declare function toBetterStackEvent(event: WideEvent): Record<string, unknown>;
25
25
  * @example
26
26
  * ```ts
27
27
  * // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var
28
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain())
28
+ * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain())
29
29
  *
30
30
  * // With overrides
31
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain({
31
+ * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain({
32
32
  * sourceToken: 'my-token',
33
33
  * }))
34
34
  * ```
@@ -1,4 +1,4 @@
1
- import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-CTtzGDc6.mjs";
1
+ import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-BpkAshj6.mjs";
2
2
  //#region src/adapters/better-stack.ts
3
3
  const BETTER_STACK_FIELDS = [
4
4
  {
@@ -12,7 +12,7 @@ const BETTER_STACK_FIELDS = [
12
12
  { key: "timeout" }
13
13
  ];
14
14
  /**
15
- * Transform an @safaricom-mxl/log wide event into a Better Stack event.
15
+ * Transform an mxllog wide event into a Better Stack event.
16
16
  * Maps `timestamp` to `dt` (Better Stack's expected field).
17
17
  */
18
18
  function toBetterStackEvent(event) {
@@ -34,10 +34,10 @@ function toBetterStackEvent(event) {
34
34
  * @example
35
35
  * ```ts
36
36
  * // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var
37
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain())
37
+ * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain())
38
38
  *
39
39
  * // With overrides
40
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain({
40
+ * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain({
41
41
  * sourceToken: 'my-token',
42
42
  * }))
43
43
  * ```
@@ -48,7 +48,7 @@ function createBetterStackDrain(overrides) {
48
48
  resolve: () => {
49
49
  const config = resolveAdapterConfig("betterStack", BETTER_STACK_FIELDS, overrides);
50
50
  if (!config.sourceToken) {
51
- console.error("[@safaricom-mxl/log/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()");
51
+ console.error("[mxllog/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()");
52
52
  return null;
53
53
  }
54
54
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"better-stack.mjs","names":[],"sources":["../../src/adapters/better-stack.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\n\nexport interface BetterStackConfig {\n /** Better Stack source token */\n sourceToken: string\n /** Logtail ingestion endpoint. Default: https://in.logs.betterstack.com */\n endpoint?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\nconst BETTER_STACK_FIELDS: ConfigField<BetterStackConfig>[] = [\n { key: 'sourceToken', env: ['NUXT_BETTER_STACK_SOURCE_TOKEN', 'BETTER_STACK_SOURCE_TOKEN'] },\n { key: 'endpoint', env: ['NUXT_BETTER_STACK_ENDPOINT', 'BETTER_STACK_ENDPOINT'] },\n { key: 'timeout' },\n]\n\n/**\n * Transform an @safaricom-mxl/log wide event into a Better Stack event.\n * Maps `timestamp` to `dt` (Better Stack's expected field).\n */\nexport function toBetterStackEvent(event: WideEvent): Record<string, unknown> {\n const { timestamp, ...rest } = event\n return { ...rest, dt: timestamp }\n}\n\n/**\n * Create a drain function for sending logs to Better Stack.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createBetterStackDrain()\n * 2. runtimeConfig.mxllog.betterStack\n * 3. runtimeConfig.betterStack\n * 4. Environment variables: NUXT_BETTER_STACK_*, BETTER_STACK_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var\n * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createBetterStackDrain({\n * sourceToken: 'my-token',\n * }))\n * ```\n */\nexport function createBetterStackDrain(overrides?: Partial<BetterStackConfig>) {\n return defineDrain<BetterStackConfig>({\n name: 'better-stack',\n resolve: () => {\n const config = resolveAdapterConfig<BetterStackConfig>('betterStack', BETTER_STACK_FIELDS, overrides)\n if (!config.sourceToken) {\n console.error('[@safaricom-mxl/log/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()')\n return null\n }\n return config as BetterStackConfig\n },\n send: sendBatchToBetterStack,\n })\n}\n\n/**\n * Send a single event to Better Stack.\n *\n * @example\n * ```ts\n * await sendToBetterStack(event, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendToBetterStack(event: WideEvent, config: BetterStackConfig): Promise<void> {\n await sendBatchToBetterStack([event], config)\n}\n\n/**\n * Send a batch of events to Better Stack.\n *\n * @example\n * ```ts\n * await sendBatchToBetterStack(events, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToBetterStack(events: WideEvent[], config: BetterStackConfig): Promise<void> {\n const endpoint = (config.endpoint ?? 'https://in.logs.betterstack.com').replace(/\\/+$/, '')\n\n await httpPost({\n url: endpoint,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.sourceToken}`,\n },\n body: JSON.stringify(events.map(toBetterStackEvent)),\n timeout: config.timeout ?? 5000,\n label: 'Better Stack',\n })\n}\n"],"mappings":";;AAeA,MAAM,sBAAwD;CAC5D;EAAE,KAAK;EAAe,KAAK,CAAC,kCAAkC,4BAA4B;EAAE;CAC5F;EAAE,KAAK;EAAY,KAAK,CAAC,8BAA8B,wBAAwB;EAAE;CACjF,EAAE,KAAK,WAAW;CACnB;;;;;AAMD,SAAgB,mBAAmB,OAA2C;CAC5E,MAAM,EAAE,WAAW,GAAG,SAAS;AAC/B,QAAO;EAAE,GAAG;EAAM,IAAI;EAAW;;;;;;;;;;;;;;;;;;;;;;AAuBnC,SAAgB,uBAAuB,WAAwC;AAC7E,QAAO,YAA+B;EACpC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAAwC,eAAe,qBAAqB,UAAU;AACrG,OAAI,CAAC,OAAO,aAAa;AACvB,YAAQ,MAAM,yIAAyI;AACvJ,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,kBAAkB,OAAkB,QAA0C;AAClG,OAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa/C,eAAsB,uBAAuB,QAAqB,QAA0C;AAG1G,OAAM,SAAS;EACb,MAHgB,OAAO,YAAY,mCAAmC,QAAQ,QAAQ,GAAG;EAIzF,SAAS;GACP,gBAAgB;GAChB,iBAAiB,UAAU,OAAO;GACnC;EACD,MAAM,KAAK,UAAU,OAAO,IAAI,mBAAmB,CAAC;EACpD,SAAS,OAAO,WAAW;EAC3B,OAAO;EACR,CAAC"}
1
+ {"version":3,"file":"better-stack.mjs","names":[],"sources":["../../src/adapters/better-stack.ts"],"sourcesContent":["import type { WideEvent } from '../types'\nimport type { ConfigField } from './_config'\nimport { resolveAdapterConfig } from './_config'\nimport { defineDrain } from './_drain'\nimport { httpPost } from './_http'\n\nexport interface BetterStackConfig {\n /** Better Stack source token */\n sourceToken: string\n /** Logtail ingestion endpoint. Default: https://in.logs.betterstack.com */\n endpoint?: string\n /** Request timeout in milliseconds. Default: 5000 */\n timeout?: number\n}\n\nconst BETTER_STACK_FIELDS: ConfigField<BetterStackConfig>[] = [\n { key: 'sourceToken', env: ['NUXT_BETTER_STACK_SOURCE_TOKEN', 'BETTER_STACK_SOURCE_TOKEN'] },\n { key: 'endpoint', env: ['NUXT_BETTER_STACK_ENDPOINT', 'BETTER_STACK_ENDPOINT'] },\n { key: 'timeout' },\n]\n\n/**\n * Transform an mxllog wide event into a Better Stack event.\n * Maps `timestamp` to `dt` (Better Stack's expected field).\n */\nexport function toBetterStackEvent(event: WideEvent): Record<string, unknown> {\n const { timestamp, ...rest } = event\n return { ...rest, dt: timestamp }\n}\n\n/**\n * Create a drain function for sending logs to Better Stack.\n *\n * Configuration priority (highest to lowest):\n * 1. Overrides passed to createBetterStackDrain()\n * 2. runtimeConfig.mxllog.betterStack\n * 3. runtimeConfig.betterStack\n * 4. Environment variables: NUXT_BETTER_STACK_*, BETTER_STACK_*\n *\n * @example\n * ```ts\n * // Zero config - just set NUXT_BETTER_STACK_SOURCE_TOKEN env var\n * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain())\n *\n * // With overrides\n * nitroApp.hooks.hook('mxllog:drain', createBetterStackDrain({\n * sourceToken: 'my-token',\n * }))\n * ```\n */\nexport function createBetterStackDrain(overrides?: Partial<BetterStackConfig>) {\n return defineDrain<BetterStackConfig>({\n name: 'better-stack',\n resolve: () => {\n const config = resolveAdapterConfig<BetterStackConfig>('betterStack', BETTER_STACK_FIELDS, overrides)\n if (!config.sourceToken) {\n console.error('[mxllog/better-stack] Missing source token. Set NUXT_BETTER_STACK_SOURCE_TOKEN env var or pass to createBetterStackDrain()')\n return null\n }\n return config as BetterStackConfig\n },\n send: sendBatchToBetterStack,\n })\n}\n\n/**\n * Send a single event to Better Stack.\n *\n * @example\n * ```ts\n * await sendToBetterStack(event, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendToBetterStack(event: WideEvent, config: BetterStackConfig): Promise<void> {\n await sendBatchToBetterStack([event], config)\n}\n\n/**\n * Send a batch of events to Better Stack.\n *\n * @example\n * ```ts\n * await sendBatchToBetterStack(events, {\n * sourceToken: process.env.BETTER_STACK_SOURCE_TOKEN!,\n * })\n * ```\n */\nexport async function sendBatchToBetterStack(events: WideEvent[], config: BetterStackConfig): Promise<void> {\n const endpoint = (config.endpoint ?? 'https://in.logs.betterstack.com').replace(/\\/+$/, '')\n\n await httpPost({\n url: endpoint,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.sourceToken}`,\n },\n body: JSON.stringify(events.map(toBetterStackEvent)),\n timeout: config.timeout ?? 5000,\n label: 'Better Stack',\n })\n}\n"],"mappings":";;AAeA,MAAM,sBAAwD;CAC5D;EAAE,KAAK;EAAe,KAAK,CAAC,kCAAkC,4BAA4B;EAAE;CAC5F;EAAE,KAAK;EAAY,KAAK,CAAC,8BAA8B,wBAAwB;EAAE;CACjF,EAAE,KAAK,WAAW;CACnB;;;;;AAMD,SAAgB,mBAAmB,OAA2C;CAC5E,MAAM,EAAE,WAAW,GAAG,SAAS;AAC/B,QAAO;EAAE,GAAG;EAAM,IAAI;EAAW;;;;;;;;;;;;;;;;;;;;;;AAuBnC,SAAgB,uBAAuB,WAAwC;AAC7E,QAAO,YAA+B;EACpC,MAAM;EACN,eAAe;GACb,MAAM,SAAS,qBAAwC,eAAe,qBAAqB,UAAU;AACrG,OAAI,CAAC,OAAO,aAAa;AACvB,YAAQ,MAAM,6HAA6H;AAC3I,WAAO;;AAET,UAAO;;EAET,MAAM;EACP,CAAC;;;;;;;;;;;;AAaJ,eAAsB,kBAAkB,OAAkB,QAA0C;AAClG,OAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO;;;;;;;;;;;;AAa/C,eAAsB,uBAAuB,QAAqB,QAA0C;AAG1G,OAAM,SAAS;EACb,MAHgB,OAAO,YAAY,mCAAmC,QAAQ,QAAQ,GAAG;EAIzF,SAAS;GACP,gBAAgB;GAChB,iBAAiB,UAAU,OAAO;GACnC;EACD,MAAM,KAAK,UAAU,OAAO,IAAI,mBAAmB,CAAC;EACpD,SAAS,OAAO,WAAW;EAC3B,OAAO;EACR,CAAC"}
@@ -1,4 +1,4 @@
1
- import { T as WideEvent, r as DrainContext } from "../types-abpnM9XB.mjs";
1
+ import { T as WideEvent, r as DrainContext } from "../types-B82IuY7M.mjs";
2
2
  //#region src/adapters/otlp.d.ts
3
3
  interface OTLPConfig {
4
4
  /** OTLP HTTP endpoint (e.g., http://localhost:4318) */
@@ -32,7 +32,7 @@ interface OTLPLogRecord {
32
32
  spanId?: string;
33
33
  }
34
34
  /**
35
- * Convert an @safaricom-mxl/log WideEvent to an OTLP LogRecord.
35
+ * Convert an mxllog WideEvent to an OTLP LogRecord.
36
36
  */
37
37
  declare function toOTLPLogRecord(event: WideEvent): OTLPLogRecord;
38
38
  /**
@@ -47,10 +47,10 @@ declare function toOTLPLogRecord(event: WideEvent): OTLPLogRecord;
47
47
  * @example
48
48
  * ```ts
49
49
  * // Zero config - reads from runtimeConfig or env vars
50
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createOTLPDrain())
50
+ * nitroApp.hooks.hook('mxllog:drain', createOTLPDrain())
51
51
  *
52
52
  * // With overrides
53
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createOTLPDrain({
53
+ * nitroApp.hooks.hook('mxllog:drain', createOTLPDrain({
54
54
  * endpoint: 'http://localhost:4318',
55
55
  * }))
56
56
  * ```
@@ -1,5 +1,5 @@
1
- import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-CTtzGDc6.mjs";
2
- import { n as OTEL_SEVERITY_TEXT, t as OTEL_SEVERITY_NUMBER } from "../_severity-CLNgC2HU.mjs";
1
+ import { n as defineDrain, r as resolveAdapterConfig, t as httpPost } from "../_http-BpkAshj6.mjs";
2
+ import { n as OTEL_SEVERITY_TEXT, t as OTEL_SEVERITY_NUMBER } from "../_severity-Q1BuITU_.mjs";
3
3
  //#region src/adapters/otlp.ts
4
4
  const OTLP_FIELDS = [
5
5
  {
@@ -24,7 +24,7 @@ function toAttributeValue(value) {
24
24
  return { stringValue: JSON.stringify(value) };
25
25
  }
26
26
  /**
27
- * Convert an @safaricom-mxl/log WideEvent to an OTLP LogRecord.
27
+ * Convert an mxllog WideEvent to an OTLP LogRecord.
28
28
  */
29
29
  function toOTLPLogRecord(event) {
30
30
  const timestamp = new Date(event.timestamp).getTime() * 1e6;
@@ -116,10 +116,10 @@ function getHeadersFromEnv() {
116
116
  * @example
117
117
  * ```ts
118
118
  * // Zero config - reads from runtimeConfig or env vars
119
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createOTLPDrain())
119
+ * nitroApp.hooks.hook('mxllog:drain', createOTLPDrain())
120
120
  *
121
121
  * // With overrides
122
- * nitroApp.hooks.hook('@safaricom-mxl/log:drain', createOTLPDrain({
122
+ * nitroApp.hooks.hook('mxllog:drain', createOTLPDrain({
123
123
  * endpoint: 'http://localhost:4318',
124
124
  * }))
125
125
  * ```
@@ -131,7 +131,7 @@ function createOTLPDrain(overrides) {
131
131
  const config = resolveAdapterConfig("otlp", OTLP_FIELDS, overrides);
132
132
  if (!config.headers) config.headers = getHeadersFromEnv();
133
133
  if (!config.endpoint) {
134
- console.error("[@safaricom-mxl/log/otlp] Missing endpoint. Set NUXT_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT env var, or pass to createOTLPDrain()");
134
+ console.error("[mxllog/otlp] Missing endpoint. Set NUXT_OTLP_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT env var, or pass to createOTLPDrain()");
135
135
  return null;
136
136
  }
137
137
  return config;
@@ -165,19 +165,23 @@ async function sendToOTLP(event, config) {
165
165
  async function sendBatchToOTLP(events, config) {
166
166
  if (events.length === 0) return;
167
167
  const url = `${config.endpoint.replace(/\/$/, "")}/v1/logs`;
168
- const [firstEvent] = events;
169
- const resourceAttributes = buildResourceAttributes(firstEvent, config);
170
- const logRecords = events.map(toOTLPLogRecord);
171
- const payload = { resourceLogs: [{
172
- resource: { attributes: resourceAttributes },
168
+ const grouped = /* @__PURE__ */ new Map();
169
+ for (const event of events) {
170
+ const key = `${event.service}::${event.environment}`;
171
+ const group = grouped.get(key);
172
+ if (group) group.push(event);
173
+ else grouped.set(key, [event]);
174
+ }
175
+ const payload = { resourceLogs: Array.from(grouped.values()).map((groupEvents) => ({
176
+ resource: { attributes: buildResourceAttributes(groupEvents[0], config) },
173
177
  scopeLogs: [{
174
178
  scope: {
175
179
  name: "@safaricom-mxl/log",
176
180
  version: "1.0.0"
177
181
  },
178
- logRecords
182
+ logRecords: groupEvents.map(toOTLPLogRecord)
179
183
  }]
180
- }] };
184
+ })) };
181
185
  await httpPost({
182
186
  url,
183
187
  headers: {