logixia 1.12.4 → 1.12.6

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 (166) hide show
  1. package/README.md +80 -27
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/async-context-CSHWoHMB.js +88 -0
  4. package/dist/async-context-CSHWoHMB.js.map +1 -0
  5. package/dist/async-context-CwBNMm2E.mjs +68 -0
  6. package/dist/async-context-CwBNMm2E.mjs.map +1 -0
  7. package/dist/azure-monitor.transport-CG7ClkYj.d.ts +62 -0
  8. package/dist/azure-monitor.transport-CG7ClkYj.d.ts.map +1 -0
  9. package/dist/azure-monitor.transport-CHnjVRF-.mjs +152 -0
  10. package/dist/azure-monitor.transport-CHnjVRF-.mjs.map +1 -0
  11. package/dist/azure-monitor.transport-Cm74kXZS.d.mts +62 -0
  12. package/dist/azure-monitor.transport-Cm74kXZS.d.mts.map +1 -0
  13. package/dist/azure-monitor.transport-CrvfHd9C.js +157 -0
  14. package/dist/azure-monitor.transport-CrvfHd9C.js.map +1 -0
  15. package/dist/azure.d.mts +3 -0
  16. package/dist/azure.d.ts +3 -0
  17. package/dist/azure.js +6 -0
  18. package/dist/azure.mjs +6 -0
  19. package/dist/batch-buffer-BY-mRWIK.js +170 -0
  20. package/dist/batch-buffer-BY-mRWIK.js.map +1 -0
  21. package/dist/batch-buffer-PGvSgbmd.mjs +132 -0
  22. package/dist/batch-buffer-PGvSgbmd.mjs.map +1 -0
  23. package/dist/browser.d.mts +427 -0
  24. package/dist/browser.d.mts.map +1 -0
  25. package/dist/browser.d.ts +427 -0
  26. package/dist/browser.d.ts.map +1 -0
  27. package/dist/browser.js +590 -0
  28. package/dist/browser.js.map +1 -0
  29. package/dist/browser.mjs +586 -0
  30. package/dist/browser.mjs.map +1 -0
  31. package/dist/chunk-DLSkYcPk.mjs +7 -0
  32. package/dist/chunk-nOFOJqeH.js +30 -0
  33. package/dist/cloudwatch.d.mts +3 -0
  34. package/dist/cloudwatch.d.ts +3 -0
  35. package/dist/cloudwatch.js +6 -0
  36. package/dist/cloudwatch.mjs +6 -0
  37. package/dist/cloudwatch.transport-CGHY4buE.d.mts +81 -0
  38. package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +1 -0
  39. package/dist/cloudwatch.transport-DK_8cKd3.d.ts +81 -0
  40. package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +1 -0
  41. package/dist/cloudwatch.transport-pNBNWJLt.js +370 -0
  42. package/dist/cloudwatch.transport-pNBNWJLt.js.map +1 -0
  43. package/dist/cloudwatch.transport-yBwm4OeO.mjs +360 -0
  44. package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +1 -0
  45. package/dist/coerce.utils-BN980Y9V.js +44 -0
  46. package/dist/coerce.utils-BN980Y9V.js.map +1 -0
  47. package/dist/coerce.utils-Dxv4_ikC.mjs +38 -0
  48. package/dist/coerce.utils-Dxv4_ikC.mjs.map +1 -0
  49. package/dist/correlation.d.mts +238 -0
  50. package/dist/correlation.d.mts.map +1 -0
  51. package/dist/correlation.d.ts +238 -0
  52. package/dist/correlation.d.ts.map +1 -0
  53. package/dist/correlation.js +272 -0
  54. package/dist/correlation.js.map +1 -0
  55. package/dist/correlation.mjs +261 -0
  56. package/dist/correlation.mjs.map +1 -0
  57. package/dist/gcp.d.mts +3 -0
  58. package/dist/gcp.d.ts +3 -0
  59. package/dist/gcp.js +6 -0
  60. package/dist/gcp.mjs +6 -0
  61. package/dist/gcp.transport-BJuNRFe_.mjs +192 -0
  62. package/dist/gcp.transport-BJuNRFe_.mjs.map +1 -0
  63. package/dist/gcp.transport-BOhkVKlI.d.ts +71 -0
  64. package/dist/gcp.transport-BOhkVKlI.d.ts.map +1 -0
  65. package/dist/gcp.transport-Bi6CUqZR.d.mts +71 -0
  66. package/dist/gcp.transport-Bi6CUqZR.d.mts.map +1 -0
  67. package/dist/gcp.transport-SHdtc1n0.js +198 -0
  68. package/dist/gcp.transport-SHdtc1n0.js.map +1 -0
  69. package/dist/{index-CwFww7VC.d.ts → index-BPKwwERo.d.mts} +18 -174
  70. package/dist/index-BPKwwERo.d.mts.map +1 -0
  71. package/dist/{index-DnyeaoZU.d.mts → index-C1X-TE5I.d.ts} +18 -174
  72. package/dist/index-C1X-TE5I.d.ts.map +1 -0
  73. package/dist/index.d.mts +41 -11
  74. package/dist/index.d.mts.map +1 -1
  75. package/dist/index.d.ts +40 -10
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +87 -147
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +62 -132
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/internal-log-BUJYMZbE.js +70 -0
  82. package/dist/internal-log-BUJYMZbE.js.map +1 -0
  83. package/dist/internal-log-Cm8SOWSV.mjs +52 -0
  84. package/dist/internal-log-Cm8SOWSV.mjs.map +1 -0
  85. package/dist/{logitron-logger.module-BIGTm2V6.mjs → logitron-logger.module-Bs3XYZgF.mjs} +266 -166
  86. package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +1 -0
  87. package/dist/{logitron-logger.module-BTxDpK6u.js → logitron-logger.module-BsDZR5BH.js} +297 -203
  88. package/dist/logitron-logger.module-BsDZR5BH.js.map +1 -0
  89. package/dist/{logitron-logger.module-BmT-ewin.d.ts → logitron-logger.module-CxT1F6Cm.d.ts} +23 -10
  90. package/dist/logitron-logger.module-CxT1F6Cm.d.ts.map +1 -0
  91. package/dist/{logitron-logger.module-BCq3sF27.d.mts → logitron-logger.module-zDKVd_o0.d.mts} +23 -10
  92. package/dist/logitron-logger.module-zDKVd_o0.d.mts.map +1 -0
  93. package/dist/middleware.d.mts +5 -2
  94. package/dist/middleware.d.mts.map +1 -1
  95. package/dist/middleware.d.ts +5 -2
  96. package/dist/middleware.d.ts.map +1 -1
  97. package/dist/middleware.js +13 -4
  98. package/dist/middleware.js.map +1 -1
  99. package/dist/middleware.mjs +14 -4
  100. package/dist/middleware.mjs.map +1 -1
  101. package/dist/nest.d.mts +3 -2
  102. package/dist/nest.d.mts.map +1 -1
  103. package/dist/nest.d.ts +3 -2
  104. package/dist/nest.d.ts.map +1 -1
  105. package/dist/nest.js +6 -2
  106. package/dist/nest.mjs +6 -2
  107. package/dist/safe-stringify-DJ66tW5I.mjs +118 -0
  108. package/dist/safe-stringify-DJ66tW5I.mjs.map +1 -0
  109. package/dist/safe-stringify-DWo3aZp_.js +142 -0
  110. package/dist/safe-stringify-DWo3aZp_.js.map +1 -0
  111. package/dist/search-CFQRISUv.mjs +1596 -0
  112. package/dist/search-CFQRISUv.mjs.map +1 -0
  113. package/dist/search-CQOo-Iq6.d.mts +816 -0
  114. package/dist/search-CQOo-Iq6.d.mts.map +1 -0
  115. package/dist/search-DujhR94O.d.ts +816 -0
  116. package/dist/search-DujhR94O.d.ts.map +1 -0
  117. package/dist/search-njTI2hdo.js +1631 -0
  118. package/dist/search-njTI2hdo.js.map +1 -0
  119. package/dist/search.d.mts +4 -1
  120. package/dist/search.d.ts +4 -1
  121. package/dist/search.js +9 -1
  122. package/dist/search.mjs +3 -2
  123. package/dist/testing.d.mts +2 -1
  124. package/dist/testing.d.mts.map +1 -1
  125. package/dist/testing.d.ts +2 -1
  126. package/dist/testing.d.ts.map +1 -1
  127. package/dist/{transport.manager-ciG4r5uz.js → transport.manager-BivyUTtU.js} +497 -437
  128. package/dist/transport.manager-BivyUTtU.js.map +1 -0
  129. package/dist/{transport.manager-DETpXuaY.mjs → transport.manager-D6KL3t9V.mjs} +473 -364
  130. package/dist/transport.manager-D6KL3t9V.mjs.map +1 -0
  131. package/dist/transport.types-B5vcyv2k.d.mts +187 -0
  132. package/dist/transport.types-B5vcyv2k.d.mts.map +1 -0
  133. package/dist/transport.types-BuY84TwO.d.ts +187 -0
  134. package/dist/transport.types-BuY84TwO.d.ts.map +1 -0
  135. package/dist/transports.d.mts +90 -29
  136. package/dist/transports.d.mts.map +1 -1
  137. package/dist/transports.d.ts +90 -29
  138. package/dist/transports.d.ts.map +1 -1
  139. package/dist/transports.js +14 -2
  140. package/dist/transports.mjs +10 -2
  141. package/dist/worker-entry.js +1241 -0
  142. package/dist/worker.d.mts +3 -0
  143. package/dist/worker.d.ts +3 -0
  144. package/dist/worker.js +4 -0
  145. package/dist/worker.mjs +4 -0
  146. package/dist/worker.transport-BP8Q28Z2.d.mts +76 -0
  147. package/dist/worker.transport-BP8Q28Z2.d.mts.map +1 -0
  148. package/dist/worker.transport-BhMyvqQ2.mjs +167 -0
  149. package/dist/worker.transport-BhMyvqQ2.mjs.map +1 -0
  150. package/dist/worker.transport-CfH6z37Z.js +168 -0
  151. package/dist/worker.transport-CfH6z37Z.js.map +1 -0
  152. package/dist/worker.transport-mKXgNK0L.d.ts +76 -0
  153. package/dist/worker.transport-mKXgNK0L.d.ts.map +1 -0
  154. package/package.json +23 -18
  155. package/dist/index-CwFww7VC.d.ts.map +0 -1
  156. package/dist/index-DnyeaoZU.d.mts.map +0 -1
  157. package/dist/logitron-logger.module-BCq3sF27.d.mts.map +0 -1
  158. package/dist/logitron-logger.module-BIGTm2V6.mjs.map +0 -1
  159. package/dist/logitron-logger.module-BTxDpK6u.js.map +0 -1
  160. package/dist/logitron-logger.module-BmT-ewin.d.ts.map +0 -1
  161. package/dist/search-Cg_OasF-.d.ts +0 -1
  162. package/dist/search-DN676Dnz.d.mts +0 -1
  163. package/dist/search-DOvSI-mb.mjs +0 -1
  164. package/dist/search-DoZF3RZj.js +0 -0
  165. package/dist/transport.manager-DETpXuaY.mjs.map +0 -1
  166. package/dist/transport.manager-ciG4r5uz.js.map +0 -1
@@ -0,0 +1,88 @@
1
+ const require_chunk = require('./chunk-nOFOJqeH.js');
2
+ let node_crypto = require("node:crypto");
3
+ node_crypto = require_chunk.__toESM(node_crypto);
4
+ let node_async_hooks = require("node:async_hooks");
5
+ node_async_hooks = require_chunk.__toESM(node_async_hooks);
6
+
7
+ //#region src/context/async-context.ts
8
+ /** Generates an 8-character random ID using Node's crypto module. */
9
+ function randomShortId() {
10
+ return (0, node_crypto.randomUUID)().slice(0, 8);
11
+ }
12
+ const _storage = new node_async_hooks.AsyncLocalStorage();
13
+ const LogixiaContext = {
14
+ run(store, callback) {
15
+ const parent = _storage.getStore() ?? {};
16
+ return _storage.run({
17
+ ...parent,
18
+ ...store
19
+ }, callback);
20
+ },
21
+ get() {
22
+ return _storage.getStore();
23
+ },
24
+ set(fields) {
25
+ const store = _storage.getStore();
26
+ if (!store) return;
27
+ Object.assign(store, fields);
28
+ },
29
+ getStorage() {
30
+ return _storage;
31
+ }
32
+ };
33
+ /**
34
+ * Create an Express/Connect-compatible middleware that wraps each request in
35
+ * a `LogixiaContext.run()` scope populated with common request fields.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * import { createExpressContextMiddleware } from 'logixia';
40
+ * app.use(createExpressContextMiddleware());
41
+ * ```
42
+ */
43
+ function createExpressContextMiddleware(options = {}) {
44
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
45
+ return function logixiaContextMiddleware(req, _res, next) {
46
+ const base = { traceId: (req["headers"] ?? {})[traceIdHeader] ?? randomShortId() };
47
+ LogixiaContext.run({
48
+ ...base,
49
+ ...enrich ? enrich(req) : {}
50
+ }, next);
51
+ };
52
+ }
53
+ /**
54
+ * Create a Fastify lifecycle hook that wraps each request in a context scope.
55
+ *
56
+ * Register with `fastify.addHook('onRequest', createFastifyContextHook())`.
57
+ */
58
+ function createFastifyContextHook(options = {}) {
59
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
60
+ return function logixiaFastifyHook(request, _reply, done) {
61
+ const base = { traceId: (request["headers"] ?? {})[traceIdHeader] ?? request["id"] ?? randomShortId() };
62
+ LogixiaContext.run({
63
+ ...base,
64
+ ...enrich ? enrich(request) : {}
65
+ }, done);
66
+ };
67
+ }
68
+
69
+ //#endregion
70
+ Object.defineProperty(exports, 'LogixiaContext', {
71
+ enumerable: true,
72
+ get: function () {
73
+ return LogixiaContext;
74
+ }
75
+ });
76
+ Object.defineProperty(exports, 'createExpressContextMiddleware', {
77
+ enumerable: true,
78
+ get: function () {
79
+ return createExpressContextMiddleware;
80
+ }
81
+ });
82
+ Object.defineProperty(exports, 'createFastifyContextHook', {
83
+ enumerable: true,
84
+ get: function () {
85
+ return createFastifyContextHook;
86
+ }
87
+ });
88
+ //# sourceMappingURL=async-context-CSHWoHMB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-context-CSHWoHMB.js","names":["AsyncLocalStorage","base: LogContext"],"sources":["../src/context/async-context.ts"],"sourcesContent":["/**\n * LogixiaContext — Zero-boilerplate AsyncLocalStorage context propagation.\n *\n * Lets every `logger.info()` call inside a context automatically pick up stored\n * fields (requestId, userId, tenantId, …) without passing them through every function.\n *\n * Works across `Promise.all`, `setTimeout`, and event emitters — anything that\n * inherits the async execution context.\n *\n * @example\n * ```ts\n * import { LogixiaContext } from 'logixia';\n *\n * // Wrap a request handler:\n * app.use((req, res, next) => {\n * LogixiaContext.run({ requestId: req.id, userId: req.user?.id }, next);\n * });\n *\n * // Anywhere deeper in the call tree:\n * async function processOrder(orderId: string) {\n * const ctx = LogixiaContext.get(); // { requestId, userId, orderId }\n * logger.info('Processing order', { orderId, ...ctx });\n * }\n * ```\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\n\n/** Generates an 8-character random ID using Node's crypto module. */\nfunction randomShortId(): string {\n return randomUUID().slice(0, 8);\n}\n\nexport interface LogContext {\n traceId?: string;\n spanId?: string;\n userId?: string;\n tenantId?: string;\n sessionId?: string;\n [key: string]: unknown;\n}\n\n// Module-level singleton so all loggers share the same ALS store.\nconst _storage = new AsyncLocalStorage<LogContext>();\n\nexport const LogixiaContext = {\n /**\n * Run `callback` inside an async context that carries `store` fields.\n * All loggers queried within `callback` (and its async descendants) will\n * automatically see these fields.\n *\n * @example\n * ```ts\n * LogixiaContext.run({ requestId: 'abc', userId: '42' }, async () => {\n * await processOrder(); // sees requestId + userId in every log\n * });\n * ```\n */\n run<T>(store: LogContext, callback: () => T): T {\n const parent = _storage.getStore() ?? {};\n return _storage.run({ ...parent, ...store }, callback);\n },\n\n /**\n * Return the context fields active in the current async scope.\n * Returns `undefined` when called outside any `LogixiaContext.run()`.\n */\n get(): LogContext | undefined {\n return _storage.getStore();\n },\n\n /**\n * Merge `fields` into the **existing** context for the current scope.\n * If called outside a `run()` context this is a no-op (logs a dev warning).\n */\n set(fields: Partial<LogContext>): void {\n const store = _storage.getStore();\n if (!store) {\n // Silently ignore — avoids crashing in code that may call setContext\n // before a request context is established (e.g. background jobs).\n return;\n }\n Object.assign(store, fields);\n },\n\n /**\n * Retrieve the underlying `AsyncLocalStorage` instance.\n * Useful for advanced use-cases like custom middleware.\n */\n getStorage(): AsyncLocalStorage<LogContext> {\n return _storage;\n },\n};\n\n/**\n * Create an Express/Connect-compatible middleware that wraps each request in\n * a `LogixiaContext.run()` scope populated with common request fields.\n *\n * @example\n * ```ts\n * import { createExpressContextMiddleware } from 'logixia';\n * app.use(createExpressContextMiddleware());\n * ```\n */\nexport function createExpressContextMiddleware(\n options: {\n /** Extract additional fields from the request. */\n enrich?: (req: Record<string, unknown>) => Partial<LogContext>;\n /** Header to read the traceId from. Default: 'x-trace-id'. */\n traceIdHeader?: string;\n } = {}\n) {\n const { enrich, traceIdHeader = 'x-trace-id' } = options;\n\n return function logixiaContextMiddleware(\n req: Record<string, unknown>,\n _res: unknown,\n next: () => void\n ): void {\n const headers = (req['headers'] ?? {}) as Record<string, string | undefined>;\n const traceId = headers[traceIdHeader] ?? randomShortId();\n const base: LogContext = { traceId };\n LogixiaContext.run({ ...base, ...(enrich ? enrich(req) : {}) }, next);\n };\n}\n\n/**\n * Create a Fastify lifecycle hook that wraps each request in a context scope.\n *\n * Register with `fastify.addHook('onRequest', createFastifyContextHook())`.\n */\nexport function createFastifyContextHook(\n options: {\n enrich?: (request: Record<string, unknown>) => Partial<LogContext>;\n traceIdHeader?: string;\n } = {}\n) {\n const { enrich, traceIdHeader = 'x-trace-id' } = options;\n\n return function logixiaFastifyHook(\n request: Record<string, unknown>,\n _reply: unknown,\n done: () => void\n ): void {\n const headers = (request['headers'] ?? {}) as Record<string, string | undefined>;\n const traceId =\n headers[traceIdHeader] ?? (request['id'] as string | undefined) ?? randomShortId();\n const base: LogContext = { traceId };\n LogixiaContext.run({ ...base, ...(enrich ? enrich(request) : {}) }, done);\n };\n}\n"],"mappings":";;;;;;;;AA8BA,SAAS,gBAAwB;AAC/B,qCAAmB,CAAC,MAAM,GAAG,EAAE;;AAajC,MAAM,WAAW,IAAIA,oCAA+B;AAEpD,MAAa,iBAAiB;CAa5B,IAAO,OAAmB,UAAsB;EAC9C,MAAM,SAAS,SAAS,UAAU,IAAI,EAAE;AACxC,SAAO,SAAS,IAAI;GAAE,GAAG;GAAQ,GAAG;GAAO,EAAE,SAAS;;CAOxD,MAA8B;AAC5B,SAAO,SAAS,UAAU;;CAO5B,IAAI,QAAmC;EACrC,MAAM,QAAQ,SAAS,UAAU;AACjC,MAAI,CAAC,MAGH;AAEF,SAAO,OAAO,OAAO,OAAO;;CAO9B,aAA4C;AAC1C,SAAO;;CAEV;;;;;;;;;;;AAYD,SAAgB,+BACd,UAKI,EAAE,EACN;CACA,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB;AAEjD,QAAO,SAAS,yBACd,KACA,MACA,MACM;EAGN,MAAMC,OAAmB,EAAE,UAFV,IAAI,cAAc,EAAE,EACb,kBAAkB,eAAe,EACrB;AACpC,iBAAe,IAAI;GAAE,GAAG;GAAM,GAAI,SAAS,OAAO,IAAI,GAAG,EAAE;GAAG,EAAE,KAAK;;;;;;;;AASzE,SAAgB,yBACd,UAGI,EAAE,EACN;CACA,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB;AAEjD,QAAO,SAAS,mBACd,SACA,QACA,MACM;EAIN,MAAMA,OAAmB,EAAE,UAHV,QAAQ,cAAc,EAAE,EAE/B,kBAAmB,QAAQ,SAAgC,eAAe,EAChD;AACpC,iBAAe,IAAI;GAAE,GAAG;GAAM,GAAI,SAAS,OAAO,QAAQ,GAAG,EAAE;GAAG,EAAE,KAAK"}
@@ -0,0 +1,68 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+
4
+ //#region src/context/async-context.ts
5
+ /** Generates an 8-character random ID using Node's crypto module. */
6
+ function randomShortId() {
7
+ return randomUUID().slice(0, 8);
8
+ }
9
+ const _storage = new AsyncLocalStorage();
10
+ const LogixiaContext = {
11
+ run(store, callback) {
12
+ const parent = _storage.getStore() ?? {};
13
+ return _storage.run({
14
+ ...parent,
15
+ ...store
16
+ }, callback);
17
+ },
18
+ get() {
19
+ return _storage.getStore();
20
+ },
21
+ set(fields) {
22
+ const store = _storage.getStore();
23
+ if (!store) return;
24
+ Object.assign(store, fields);
25
+ },
26
+ getStorage() {
27
+ return _storage;
28
+ }
29
+ };
30
+ /**
31
+ * Create an Express/Connect-compatible middleware that wraps each request in
32
+ * a `LogixiaContext.run()` scope populated with common request fields.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createExpressContextMiddleware } from 'logixia';
37
+ * app.use(createExpressContextMiddleware());
38
+ * ```
39
+ */
40
+ function createExpressContextMiddleware(options = {}) {
41
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
42
+ return function logixiaContextMiddleware(req, _res, next) {
43
+ const base = { traceId: (req["headers"] ?? {})[traceIdHeader] ?? randomShortId() };
44
+ LogixiaContext.run({
45
+ ...base,
46
+ ...enrich ? enrich(req) : {}
47
+ }, next);
48
+ };
49
+ }
50
+ /**
51
+ * Create a Fastify lifecycle hook that wraps each request in a context scope.
52
+ *
53
+ * Register with `fastify.addHook('onRequest', createFastifyContextHook())`.
54
+ */
55
+ function createFastifyContextHook(options = {}) {
56
+ const { enrich, traceIdHeader = "x-trace-id" } = options;
57
+ return function logixiaFastifyHook(request, _reply, done) {
58
+ const base = { traceId: (request["headers"] ?? {})[traceIdHeader] ?? request["id"] ?? randomShortId() };
59
+ LogixiaContext.run({
60
+ ...base,
61
+ ...enrich ? enrich(request) : {}
62
+ }, done);
63
+ };
64
+ }
65
+
66
+ //#endregion
67
+ export { createExpressContextMiddleware as n, createFastifyContextHook as r, LogixiaContext as t };
68
+ //# sourceMappingURL=async-context-CwBNMm2E.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-context-CwBNMm2E.mjs","names":["base: LogContext"],"sources":["../src/context/async-context.ts"],"sourcesContent":["/**\n * LogixiaContext — Zero-boilerplate AsyncLocalStorage context propagation.\n *\n * Lets every `logger.info()` call inside a context automatically pick up stored\n * fields (requestId, userId, tenantId, …) without passing them through every function.\n *\n * Works across `Promise.all`, `setTimeout`, and event emitters — anything that\n * inherits the async execution context.\n *\n * @example\n * ```ts\n * import { LogixiaContext } from 'logixia';\n *\n * // Wrap a request handler:\n * app.use((req, res, next) => {\n * LogixiaContext.run({ requestId: req.id, userId: req.user?.id }, next);\n * });\n *\n * // Anywhere deeper in the call tree:\n * async function processOrder(orderId: string) {\n * const ctx = LogixiaContext.get(); // { requestId, userId, orderId }\n * logger.info('Processing order', { orderId, ...ctx });\n * }\n * ```\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\n\n/** Generates an 8-character random ID using Node's crypto module. */\nfunction randomShortId(): string {\n return randomUUID().slice(0, 8);\n}\n\nexport interface LogContext {\n traceId?: string;\n spanId?: string;\n userId?: string;\n tenantId?: string;\n sessionId?: string;\n [key: string]: unknown;\n}\n\n// Module-level singleton so all loggers share the same ALS store.\nconst _storage = new AsyncLocalStorage<LogContext>();\n\nexport const LogixiaContext = {\n /**\n * Run `callback` inside an async context that carries `store` fields.\n * All loggers queried within `callback` (and its async descendants) will\n * automatically see these fields.\n *\n * @example\n * ```ts\n * LogixiaContext.run({ requestId: 'abc', userId: '42' }, async () => {\n * await processOrder(); // sees requestId + userId in every log\n * });\n * ```\n */\n run<T>(store: LogContext, callback: () => T): T {\n const parent = _storage.getStore() ?? {};\n return _storage.run({ ...parent, ...store }, callback);\n },\n\n /**\n * Return the context fields active in the current async scope.\n * Returns `undefined` when called outside any `LogixiaContext.run()`.\n */\n get(): LogContext | undefined {\n return _storage.getStore();\n },\n\n /**\n * Merge `fields` into the **existing** context for the current scope.\n * If called outside a `run()` context this is a no-op (logs a dev warning).\n */\n set(fields: Partial<LogContext>): void {\n const store = _storage.getStore();\n if (!store) {\n // Silently ignore — avoids crashing in code that may call setContext\n // before a request context is established (e.g. background jobs).\n return;\n }\n Object.assign(store, fields);\n },\n\n /**\n * Retrieve the underlying `AsyncLocalStorage` instance.\n * Useful for advanced use-cases like custom middleware.\n */\n getStorage(): AsyncLocalStorage<LogContext> {\n return _storage;\n },\n};\n\n/**\n * Create an Express/Connect-compatible middleware that wraps each request in\n * a `LogixiaContext.run()` scope populated with common request fields.\n *\n * @example\n * ```ts\n * import { createExpressContextMiddleware } from 'logixia';\n * app.use(createExpressContextMiddleware());\n * ```\n */\nexport function createExpressContextMiddleware(\n options: {\n /** Extract additional fields from the request. */\n enrich?: (req: Record<string, unknown>) => Partial<LogContext>;\n /** Header to read the traceId from. Default: 'x-trace-id'. */\n traceIdHeader?: string;\n } = {}\n) {\n const { enrich, traceIdHeader = 'x-trace-id' } = options;\n\n return function logixiaContextMiddleware(\n req: Record<string, unknown>,\n _res: unknown,\n next: () => void\n ): void {\n const headers = (req['headers'] ?? {}) as Record<string, string | undefined>;\n const traceId = headers[traceIdHeader] ?? randomShortId();\n const base: LogContext = { traceId };\n LogixiaContext.run({ ...base, ...(enrich ? enrich(req) : {}) }, next);\n };\n}\n\n/**\n * Create a Fastify lifecycle hook that wraps each request in a context scope.\n *\n * Register with `fastify.addHook('onRequest', createFastifyContextHook())`.\n */\nexport function createFastifyContextHook(\n options: {\n enrich?: (request: Record<string, unknown>) => Partial<LogContext>;\n traceIdHeader?: string;\n } = {}\n) {\n const { enrich, traceIdHeader = 'x-trace-id' } = options;\n\n return function logixiaFastifyHook(\n request: Record<string, unknown>,\n _reply: unknown,\n done: () => void\n ): void {\n const headers = (request['headers'] ?? {}) as Record<string, string | undefined>;\n const traceId =\n headers[traceIdHeader] ?? (request['id'] as string | undefined) ?? randomShortId();\n const base: LogContext = { traceId };\n LogixiaContext.run({ ...base, ...(enrich ? enrich(request) : {}) }, done);\n };\n}\n"],"mappings":";;;;;AA8BA,SAAS,gBAAwB;AAC/B,QAAO,YAAY,CAAC,MAAM,GAAG,EAAE;;AAajC,MAAM,WAAW,IAAI,mBAA+B;AAEpD,MAAa,iBAAiB;CAa5B,IAAO,OAAmB,UAAsB;EAC9C,MAAM,SAAS,SAAS,UAAU,IAAI,EAAE;AACxC,SAAO,SAAS,IAAI;GAAE,GAAG;GAAQ,GAAG;GAAO,EAAE,SAAS;;CAOxD,MAA8B;AAC5B,SAAO,SAAS,UAAU;;CAO5B,IAAI,QAAmC;EACrC,MAAM,QAAQ,SAAS,UAAU;AACjC,MAAI,CAAC,MAGH;AAEF,SAAO,OAAO,OAAO,OAAO;;CAO9B,aAA4C;AAC1C,SAAO;;CAEV;;;;;;;;;;;AAYD,SAAgB,+BACd,UAKI,EAAE,EACN;CACA,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB;AAEjD,QAAO,SAAS,yBACd,KACA,MACA,MACM;EAGN,MAAMA,OAAmB,EAAE,UAFV,IAAI,cAAc,EAAE,EACb,kBAAkB,eAAe,EACrB;AACpC,iBAAe,IAAI;GAAE,GAAG;GAAM,GAAI,SAAS,OAAO,IAAI,GAAG,EAAE;GAAG,EAAE,KAAK;;;;;;;;AASzE,SAAgB,yBACd,UAGI,EAAE,EACN;CACA,MAAM,EAAE,QAAQ,gBAAgB,iBAAiB;AAEjD,QAAO,SAAS,mBACd,SACA,QACA,MACM;EAIN,MAAMA,OAAmB,EAAE,UAHV,QAAQ,cAAc,EAAE,EAE/B,kBAAmB,QAAQ,SAAgC,eAAe,EAChD;AACpC,iBAAe,IAAI;GAAE,GAAG;GAAM,GAAI,SAAS,OAAO,QAAQ,GAAG,EAAE;GAAG,EAAE,KAAK"}
@@ -0,0 +1,62 @@
1
+ import { p as TransportLogEntry, s as IAsyncTransport } from "./transport.types-BuY84TwO.js";
2
+
3
+ //#region src/transports/azure-monitor.transport.d.ts
4
+
5
+ interface AzureMonitorTransportConfig {
6
+ /** DCE (Data Collection Endpoint) URL, e.g. `https://<name>.ingest.monitor.azure.com`. */
7
+ endpoint: string;
8
+ /** Data Collection Rule immutable ID (from Azure portal). */
9
+ ruleId: string;
10
+ /** Stream name defined in the DCR, e.g. `'Custom-LogixiaLogs_CL'`. */
11
+ streamName: string;
12
+ /** Azure AD tenant ID for OAuth2 client-credentials flow. */
13
+ tenantId?: string;
14
+ /** Azure AD app (service principal) client ID. */
15
+ clientId?: string;
16
+ /** Azure AD app client secret. */
17
+ clientSecret?: string;
18
+ /** Number of entries to batch. @default 200 */
19
+ batchSize?: number;
20
+ /** Flush interval in ms. @default 5000 */
21
+ flushIntervalMs?: number;
22
+ /** Abort a request that has not finished after this many ms. @default 10000 */
23
+ requestTimeoutMs?: number;
24
+ /** Max buffered entries; the oldest are dropped past this. @default 10000 */
25
+ maxBufferSize?: number;
26
+ level?: string;
27
+ }
28
+ /**
29
+ * Azure Monitor Logs Ingestion transport.
30
+ */
31
+ declare class AzureMonitorTransport implements IAsyncTransport {
32
+ readonly name = "azure-monitor";
33
+ readonly batchSize: number;
34
+ readonly flushInterval: number;
35
+ readonly level: string | undefined;
36
+ private readonly buffer;
37
+ private readonly requestTimeoutMs;
38
+ private flushTimer;
39
+ private accessToken;
40
+ private tokenExpiry;
41
+ private readonly endpoint;
42
+ private readonly ruleId;
43
+ private readonly streamName;
44
+ private readonly tenantId;
45
+ private readonly clientId;
46
+ private readonly clientSecret;
47
+ constructor(config: AzureMonitorTransportConfig);
48
+ write(entry: TransportLogEntry): void;
49
+ flush(): Promise<void>;
50
+ /**
51
+ * Flush remaining entries and stop the interval timer on shutdown. Without
52
+ * this the manager's close() skipped the transport (close was undefined) and
53
+ * buffered entries were lost on deploy. Waits for any in-flight send first.
54
+ */
55
+ close(): Promise<void>;
56
+ private toAzureRecord;
57
+ private getAccessToken;
58
+ private sendEntries;
59
+ }
60
+ //#endregion
61
+ export { AzureMonitorTransportConfig as n, AzureMonitorTransport as t };
62
+ //# sourceMappingURL=azure-monitor.transport-CG7ClkYj.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure-monitor.transport-CG7ClkYj.d.ts","names":[],"sources":["../src/transports/azure-monitor.transport.ts"],"sourcesContent":[],"mappings":";;;;UAkDiB,2BAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCJ,qBAAA,YAAiC;;;;;;;;;;;;;;;;sBAmBxB;eAwBP;WAKJ;;;;;;WASM"}
@@ -0,0 +1,152 @@
1
+ import { r as internalWarn, t as internalError } from "./internal-log-Cm8SOWSV.mjs";
2
+ import { i as stringifyForLog } from "./safe-stringify-DJ66tW5I.mjs";
3
+ import { a as httpRequest, n as DEFAULT_MAX_BUFFER_SIZE, r as DEFAULT_REQUEST_TIMEOUT_MS, t as BatchBuffer } from "./batch-buffer-PGvSgbmd.mjs";
4
+
5
+ //#region src/transports/azure-monitor.transport.ts
6
+ /**
7
+ * Azure AD tenant IDs are either a GUID or a verified domain (e.g. `contoso.onmicrosoft.com`).
8
+ * This pattern is deliberately permissive on structure but strict on character
9
+ * set — it rejects the breakout characters (`/`, `@`, `:`, `?`, `#`, whitespace)
10
+ * that would let a hostile config smuggle a different host, path, or query into
11
+ * the OAuth token URL.
12
+ */
13
+ const AZURE_TENANT_RE = /^[a-z0-9][a-z0-9.-]{1,253}$/i;
14
+ const SEVERITY_MAP = {
15
+ verbose: 0,
16
+ trace: 0,
17
+ debug: 1,
18
+ info: 1,
19
+ log: 1,
20
+ warn: 2,
21
+ warning: 2,
22
+ error: 3,
23
+ critical: 4,
24
+ fatal: 4
25
+ };
26
+ /**
27
+ * Azure Monitor Logs Ingestion transport.
28
+ */
29
+ var AzureMonitorTransport = class {
30
+ constructor(config) {
31
+ this.name = "azure-monitor";
32
+ this.flushTimer = null;
33
+ this.accessToken = null;
34
+ this.tokenExpiry = 0;
35
+ this.endpoint = config.endpoint.replace(/\/$/, "");
36
+ this.ruleId = config.ruleId;
37
+ this.streamName = config.streamName;
38
+ this.tenantId = config.tenantId ?? process.env["AZURE_TENANT_ID"];
39
+ this.clientId = config.clientId ?? process.env["AZURE_CLIENT_ID"];
40
+ this.clientSecret = config.clientSecret ?? process.env["AZURE_CLIENT_SECRET"];
41
+ this.batchSize = config.batchSize ?? 200;
42
+ this.flushInterval = config.flushIntervalMs ?? 5e3;
43
+ this.level = config.level;
44
+ this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
45
+ this.buffer = new BatchBuffer({
46
+ name: "AzureMonitorTransport",
47
+ batchSize: this.batchSize,
48
+ maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,
49
+ send: (entries) => this.sendEntries(entries)
50
+ });
51
+ this.flushTimer = setInterval(() => {
52
+ this.flush().catch(() => {});
53
+ }, this.flushInterval);
54
+ if (this.flushTimer.unref) this.flushTimer.unref();
55
+ }
56
+ write(entry) {
57
+ this.buffer.push(entry);
58
+ this.buffer.flushIfFull();
59
+ }
60
+ flush() {
61
+ return this.buffer.flush();
62
+ }
63
+ /**
64
+ * Flush remaining entries and stop the interval timer on shutdown. Without
65
+ * this the manager's close() skipped the transport (close was undefined) and
66
+ * buffered entries were lost on deploy. Waits for any in-flight send first.
67
+ */
68
+ async close() {
69
+ if (this.flushTimer) {
70
+ clearInterval(this.flushTimer);
71
+ this.flushTimer = null;
72
+ }
73
+ await this.buffer.close();
74
+ }
75
+ toAzureRecord(entry) {
76
+ return {
77
+ TimeGenerated: entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
78
+ SeverityLevel: SEVERITY_MAP[entry.level.toLowerCase()] ?? 1,
79
+ Message: entry.message,
80
+ AppName: entry.appName,
81
+ Context: entry.context ?? "",
82
+ TraceId: entry.traceId ?? "",
83
+ Properties: stringifyForLog(entry.data ?? {})
84
+ };
85
+ }
86
+ async getAccessToken() {
87
+ if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;
88
+ if (!this.tenantId || !this.clientId || !this.clientSecret) {
89
+ internalWarn("AzureMonitorTransport: missing credentials — set tenantId, clientId, clientSecret");
90
+ return null;
91
+ }
92
+ const body = new URLSearchParams({
93
+ grant_type: "client_credentials",
94
+ client_id: this.clientId,
95
+ client_secret: this.clientSecret,
96
+ scope: "https://monitor.azure.com/.default"
97
+ }).toString();
98
+ const tenantId = this.tenantId;
99
+ if (!AZURE_TENANT_RE.test(tenantId)) {
100
+ internalWarn(`AzureMonitorTransport: refusing to request token — tenantId "${tenantId}" is not a valid GUID or domain`);
101
+ return null;
102
+ }
103
+ const reqUrl = new URL(`https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`);
104
+ try {
105
+ const res = await httpRequest({
106
+ url: reqUrl,
107
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
108
+ body,
109
+ timeoutMs: this.requestTimeoutMs,
110
+ label: "Azure token request"
111
+ });
112
+ const parsed = JSON.parse(res.body);
113
+ if (!parsed.access_token) return null;
114
+ this.accessToken = parsed.access_token;
115
+ this.tokenExpiry = Date.now() + (parsed.expires_in ?? 3600) * 1e3 - 6e4;
116
+ return this.accessToken;
117
+ } catch (err) {
118
+ internalError("AzureMonitorTransport token request failed", err);
119
+ return null;
120
+ }
121
+ }
122
+ async sendEntries(entries) {
123
+ const token = await this.getAccessToken();
124
+ if (!token) throw new Error("AzureMonitorTransport: no access token available");
125
+ const body = stringifyForLog(entries.map((e) => this.toAzureRecord(e)));
126
+ let reqUrl;
127
+ try {
128
+ reqUrl = new URL(`dataCollectionRules/${encodeURIComponent(this.ruleId)}/streams/${encodeURIComponent(this.streamName)}?api-version=2023-01-01`, this.endpoint.endsWith("/") ? this.endpoint : `${this.endpoint}/`);
129
+ } catch (error) {
130
+ internalError(`AzureMonitorTransport: invalid endpoint "${this.endpoint}"`, error);
131
+ return;
132
+ }
133
+ if (reqUrl.protocol !== "https:") {
134
+ internalError(`AzureMonitorTransport: endpoint must use https (got ${reqUrl.protocol})`);
135
+ return;
136
+ }
137
+ await httpRequest({
138
+ url: reqUrl,
139
+ headers: {
140
+ Authorization: `Bearer ${token}`,
141
+ "Content-Type": "application/json"
142
+ },
143
+ body,
144
+ timeoutMs: this.requestTimeoutMs,
145
+ label: "Azure Monitor API"
146
+ });
147
+ }
148
+ };
149
+
150
+ //#endregion
151
+ export { AzureMonitorTransport as t };
152
+ //# sourceMappingURL=azure-monitor.transport-CHnjVRF-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure-monitor.transport-CHnjVRF-.mjs","names":["SEVERITY_MAP: Record<string, number>","reqUrl: URL"],"sources":["../src/transports/azure-monitor.transport.ts"],"sourcesContent":["/**\n * logixia — Azure Monitor / Application Insights transport\n *\n * Sends log entries to Azure Monitor via the Data Collection Rules (DCR) API\n * using the Logs Ingestion API (the modern replacement for the legacy HTTP\n * Data Collector API).\n *\n * Maps logixia levels to Application Insights severity levels:\n * verbose → 0, debug → 1, info → 1, warn → 2, error → 3, critical → 4\n *\n * @example\n * ```ts\n * import { AzureMonitorTransport } from 'logixia';\n *\n * const logger = createLogger({\n * transports: {\n * azure: new AzureMonitorTransport({\n * // Logs Ingestion API endpoint (from your DCR)\n * endpoint: 'https://<dce>.ingest.monitor.azure.com',\n * ruleId: 'dcr-xxxxxxxxxxxxxxxx',\n * streamName: 'Custom-LogixiaLogs',\n * // Client credentials (or managed identity via no-credential mode)\n * tenantId: process.env.AZURE_TENANT_ID,\n * clientId: process.env.AZURE_CLIENT_ID,\n * clientSecret: process.env.AZURE_CLIENT_SECRET,\n * }),\n * },\n * });\n * ```\n */\n\nimport type { IAsyncTransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError, internalWarn } 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';\n\n/**\n * Azure AD tenant IDs are either a GUID or a verified domain (e.g. `contoso.onmicrosoft.com`).\n * This pattern is deliberately permissive on structure but strict on character\n * set — it rejects the breakout characters (`/`, `@`, `:`, `?`, `#`, whitespace)\n * that would let a hostile config smuggle a different host, path, or query into\n * the OAuth token URL.\n */\nconst AZURE_TENANT_RE = /^[a-z0-9][a-z0-9.-]{1,253}$/i;\n\nexport interface AzureMonitorTransportConfig {\n /** DCE (Data Collection Endpoint) URL, e.g. `https://<name>.ingest.monitor.azure.com`. */\n endpoint: string;\n /** Data Collection Rule immutable ID (from Azure portal). */\n ruleId: string;\n /** Stream name defined in the DCR, e.g. `'Custom-LogixiaLogs_CL'`. */\n streamName: string;\n /** Azure AD tenant ID for OAuth2 client-credentials flow. */\n tenantId?: string;\n /** Azure AD app (service principal) client ID. */\n clientId?: string;\n /** Azure AD app client secret. */\n clientSecret?: string;\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\nconst SEVERITY_MAP: Record<string, number> = {\n verbose: 0,\n trace: 0,\n debug: 1,\n info: 1,\n log: 1,\n warn: 2,\n warning: 2,\n error: 3,\n critical: 4,\n fatal: 4,\n};\n\n/**\n * Azure Monitor Logs Ingestion transport.\n */\nexport class AzureMonitorTransport implements IAsyncTransport {\n public readonly name = 'azure-monitor';\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 endpoint: string;\n private readonly ruleId: string;\n private readonly streamName: string;\n private readonly tenantId: string | undefined;\n private readonly clientId: string | undefined;\n private readonly clientSecret: string | undefined;\n\n constructor(config: AzureMonitorTransportConfig) {\n this.endpoint = config.endpoint.replace(/\\/$/, '');\n this.ruleId = config.ruleId;\n this.streamName = config.streamName;\n this.tenantId = config.tenantId ?? process.env['AZURE_TENANT_ID'];\n this.clientId = config.clientId ?? process.env['AZURE_CLIENT_ID'];\n this.clientSecret = config.clientSecret ?? process.env['AZURE_CLIENT_SECRET'];\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: 'AzureMonitorTransport',\n batchSize: this.batchSize,\n maxBufferSize: config.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE,\n send: (entries) => this.sendEntries(entries),\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 toAzureRecord(entry: TransportLogEntry): Record<string, unknown> {\n return {\n TimeGenerated: entry.timestamp ?? new Date().toISOString(),\n SeverityLevel: SEVERITY_MAP[entry.level.toLowerCase()] ?? 1,\n Message: entry.message,\n AppName: entry.appName,\n Context: entry.context ?? '',\n TraceId: entry.traceId ?? '',\n Properties: stringifyForLog(entry.data ?? {}),\n };\n }\n\n private async getAccessToken(): Promise<string | null> {\n if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;\n\n if (!this.tenantId || !this.clientId || !this.clientSecret) {\n internalWarn(\n 'AzureMonitorTransport: missing credentials — set tenantId, clientId, clientSecret'\n );\n return null;\n }\n\n const body = new URLSearchParams({\n grant_type: 'client_credentials',\n client_id: this.clientId,\n client_secret: this.clientSecret,\n scope: 'https://monitor.azure.com/.default',\n }).toString();\n\n const tenantId = this.tenantId;\n if (!AZURE_TENANT_RE.test(tenantId)) {\n internalWarn(\n `AzureMonitorTransport: refusing to request token — tenantId \"${tenantId}\" is not a valid GUID or domain`\n );\n return null;\n }\n\n const reqUrl = new URL(\n `https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`\n );\n try {\n const res = await httpRequest({\n url: reqUrl,\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'Azure token request',\n });\n const parsed = JSON.parse(res.body) as { access_token?: string; expires_in?: number };\n if (!parsed.access_token) return null;\n this.accessToken = parsed.access_token;\n this.tokenExpiry = Date.now() + (parsed.expires_in ?? 3600) * 1000 - 60_000;\n return this.accessToken;\n } catch (err) {\n internalError('AzureMonitorTransport token request failed', err);\n return null;\n }\n }\n\n private async sendEntries(entries: TransportLogEntry[]): Promise<void> {\n const token = await this.getAccessToken();\n if (!token) throw new Error('AzureMonitorTransport: no access token available');\n\n const records = entries.map((e) => this.toAzureRecord(e));\n const body = stringifyForLog(records);\n let reqUrl: URL;\n try {\n // Build from the user-configured DCE endpoint; encodeURIComponent-ing the\n // ruleId/streamName stops a hostile config from smuggling extra path\n // segments or query params into the request.\n reqUrl = new URL(\n `dataCollectionRules/${encodeURIComponent(this.ruleId)}/streams/${encodeURIComponent(this.streamName)}?api-version=2023-01-01`,\n this.endpoint.endsWith('/') ? this.endpoint : `${this.endpoint}/`\n );\n } catch (error) {\n internalError(`AzureMonitorTransport: invalid endpoint \"${this.endpoint}\"`, error);\n return;\n }\n if (reqUrl.protocol !== 'https:') {\n internalError(`AzureMonitorTransport: endpoint must use https (got ${reqUrl.protocol})`);\n return;\n }\n\n await httpRequest({\n url: reqUrl,\n headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n body,\n timeoutMs: this.requestTimeoutMs,\n label: 'Azure Monitor API',\n });\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import { p as TransportLogEntry, s as IAsyncTransport } from "./transport.types-B5vcyv2k.mjs";
2
+
3
+ //#region src/transports/azure-monitor.transport.d.ts
4
+
5
+ interface AzureMonitorTransportConfig {
6
+ /** DCE (Data Collection Endpoint) URL, e.g. `https://<name>.ingest.monitor.azure.com`. */
7
+ endpoint: string;
8
+ /** Data Collection Rule immutable ID (from Azure portal). */
9
+ ruleId: string;
10
+ /** Stream name defined in the DCR, e.g. `'Custom-LogixiaLogs_CL'`. */
11
+ streamName: string;
12
+ /** Azure AD tenant ID for OAuth2 client-credentials flow. */
13
+ tenantId?: string;
14
+ /** Azure AD app (service principal) client ID. */
15
+ clientId?: string;
16
+ /** Azure AD app client secret. */
17
+ clientSecret?: string;
18
+ /** Number of entries to batch. @default 200 */
19
+ batchSize?: number;
20
+ /** Flush interval in ms. @default 5000 */
21
+ flushIntervalMs?: number;
22
+ /** Abort a request that has not finished after this many ms. @default 10000 */
23
+ requestTimeoutMs?: number;
24
+ /** Max buffered entries; the oldest are dropped past this. @default 10000 */
25
+ maxBufferSize?: number;
26
+ level?: string;
27
+ }
28
+ /**
29
+ * Azure Monitor Logs Ingestion transport.
30
+ */
31
+ declare class AzureMonitorTransport implements IAsyncTransport {
32
+ readonly name = "azure-monitor";
33
+ readonly batchSize: number;
34
+ readonly flushInterval: number;
35
+ readonly level: string | undefined;
36
+ private readonly buffer;
37
+ private readonly requestTimeoutMs;
38
+ private flushTimer;
39
+ private accessToken;
40
+ private tokenExpiry;
41
+ private readonly endpoint;
42
+ private readonly ruleId;
43
+ private readonly streamName;
44
+ private readonly tenantId;
45
+ private readonly clientId;
46
+ private readonly clientSecret;
47
+ constructor(config: AzureMonitorTransportConfig);
48
+ write(entry: TransportLogEntry): void;
49
+ flush(): Promise<void>;
50
+ /**
51
+ * Flush remaining entries and stop the interval timer on shutdown. Without
52
+ * this the manager's close() skipped the transport (close was undefined) and
53
+ * buffered entries were lost on deploy. Waits for any in-flight send first.
54
+ */
55
+ close(): Promise<void>;
56
+ private toAzureRecord;
57
+ private getAccessToken;
58
+ private sendEntries;
59
+ }
60
+ //#endregion
61
+ export { AzureMonitorTransportConfig as n, AzureMonitorTransport as t };
62
+ //# sourceMappingURL=azure-monitor.transport-Cm74kXZS.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure-monitor.transport-Cm74kXZS.d.mts","names":[],"sources":["../src/transports/azure-monitor.transport.ts"],"sourcesContent":[],"mappings":";;;;UAkDiB,2BAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAwCJ,qBAAA,YAAiC;;;;;;;;;;;;;;;;sBAmBxB;eAwBP;WAKJ;;;;;;WASM"}
@@ -0,0 +1,157 @@
1
+ const require_internal_log = require('./internal-log-BUJYMZbE.js');
2
+ const require_safe_stringify = require('./safe-stringify-DWo3aZp_.js');
3
+ const require_batch_buffer = require('./batch-buffer-BY-mRWIK.js');
4
+
5
+ //#region src/transports/azure-monitor.transport.ts
6
+ /**
7
+ * Azure AD tenant IDs are either a GUID or a verified domain (e.g. `contoso.onmicrosoft.com`).
8
+ * This pattern is deliberately permissive on structure but strict on character
9
+ * set — it rejects the breakout characters (`/`, `@`, `:`, `?`, `#`, whitespace)
10
+ * that would let a hostile config smuggle a different host, path, or query into
11
+ * the OAuth token URL.
12
+ */
13
+ const AZURE_TENANT_RE = /^[a-z0-9][a-z0-9.-]{1,253}$/i;
14
+ const SEVERITY_MAP = {
15
+ verbose: 0,
16
+ trace: 0,
17
+ debug: 1,
18
+ info: 1,
19
+ log: 1,
20
+ warn: 2,
21
+ warning: 2,
22
+ error: 3,
23
+ critical: 4,
24
+ fatal: 4
25
+ };
26
+ /**
27
+ * Azure Monitor Logs Ingestion transport.
28
+ */
29
+ var AzureMonitorTransport = class {
30
+ constructor(config) {
31
+ this.name = "azure-monitor";
32
+ this.flushTimer = null;
33
+ this.accessToken = null;
34
+ this.tokenExpiry = 0;
35
+ this.endpoint = config.endpoint.replace(/\/$/, "");
36
+ this.ruleId = config.ruleId;
37
+ this.streamName = config.streamName;
38
+ this.tenantId = config.tenantId ?? process.env["AZURE_TENANT_ID"];
39
+ this.clientId = config.clientId ?? process.env["AZURE_CLIENT_ID"];
40
+ this.clientSecret = config.clientSecret ?? process.env["AZURE_CLIENT_SECRET"];
41
+ this.batchSize = config.batchSize ?? 200;
42
+ this.flushInterval = config.flushIntervalMs ?? 5e3;
43
+ this.level = config.level;
44
+ this.requestTimeoutMs = config.requestTimeoutMs ?? require_batch_buffer.DEFAULT_REQUEST_TIMEOUT_MS;
45
+ this.buffer = new require_batch_buffer.BatchBuffer({
46
+ name: "AzureMonitorTransport",
47
+ batchSize: this.batchSize,
48
+ maxBufferSize: config.maxBufferSize ?? require_batch_buffer.DEFAULT_MAX_BUFFER_SIZE,
49
+ send: (entries) => this.sendEntries(entries)
50
+ });
51
+ this.flushTimer = setInterval(() => {
52
+ this.flush().catch(() => {});
53
+ }, this.flushInterval);
54
+ if (this.flushTimer.unref) this.flushTimer.unref();
55
+ }
56
+ write(entry) {
57
+ this.buffer.push(entry);
58
+ this.buffer.flushIfFull();
59
+ }
60
+ flush() {
61
+ return this.buffer.flush();
62
+ }
63
+ /**
64
+ * Flush remaining entries and stop the interval timer on shutdown. Without
65
+ * this the manager's close() skipped the transport (close was undefined) and
66
+ * buffered entries were lost on deploy. Waits for any in-flight send first.
67
+ */
68
+ async close() {
69
+ if (this.flushTimer) {
70
+ clearInterval(this.flushTimer);
71
+ this.flushTimer = null;
72
+ }
73
+ await this.buffer.close();
74
+ }
75
+ toAzureRecord(entry) {
76
+ return {
77
+ TimeGenerated: entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
78
+ SeverityLevel: SEVERITY_MAP[entry.level.toLowerCase()] ?? 1,
79
+ Message: entry.message,
80
+ AppName: entry.appName,
81
+ Context: entry.context ?? "",
82
+ TraceId: entry.traceId ?? "",
83
+ Properties: require_safe_stringify.stringifyForLog(entry.data ?? {})
84
+ };
85
+ }
86
+ async getAccessToken() {
87
+ if (this.accessToken && Date.now() < this.tokenExpiry) return this.accessToken;
88
+ if (!this.tenantId || !this.clientId || !this.clientSecret) {
89
+ require_internal_log.internalWarn("AzureMonitorTransport: missing credentials — set tenantId, clientId, clientSecret");
90
+ return null;
91
+ }
92
+ const body = new URLSearchParams({
93
+ grant_type: "client_credentials",
94
+ client_id: this.clientId,
95
+ client_secret: this.clientSecret,
96
+ scope: "https://monitor.azure.com/.default"
97
+ }).toString();
98
+ const tenantId = this.tenantId;
99
+ if (!AZURE_TENANT_RE.test(tenantId)) {
100
+ require_internal_log.internalWarn(`AzureMonitorTransport: refusing to request token — tenantId "${tenantId}" is not a valid GUID or domain`);
101
+ return null;
102
+ }
103
+ const reqUrl = new URL(`https://login.microsoftonline.com/${encodeURIComponent(tenantId)}/oauth2/v2.0/token`);
104
+ try {
105
+ const res = await require_batch_buffer.httpRequest({
106
+ url: reqUrl,
107
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
108
+ body,
109
+ timeoutMs: this.requestTimeoutMs,
110
+ label: "Azure token request"
111
+ });
112
+ const parsed = JSON.parse(res.body);
113
+ if (!parsed.access_token) return null;
114
+ this.accessToken = parsed.access_token;
115
+ this.tokenExpiry = Date.now() + (parsed.expires_in ?? 3600) * 1e3 - 6e4;
116
+ return this.accessToken;
117
+ } catch (err) {
118
+ require_internal_log.internalError("AzureMonitorTransport token request failed", err);
119
+ return null;
120
+ }
121
+ }
122
+ async sendEntries(entries) {
123
+ const token = await this.getAccessToken();
124
+ if (!token) throw new Error("AzureMonitorTransport: no access token available");
125
+ const body = require_safe_stringify.stringifyForLog(entries.map((e) => this.toAzureRecord(e)));
126
+ let reqUrl;
127
+ try {
128
+ reqUrl = new URL(`dataCollectionRules/${encodeURIComponent(this.ruleId)}/streams/${encodeURIComponent(this.streamName)}?api-version=2023-01-01`, this.endpoint.endsWith("/") ? this.endpoint : `${this.endpoint}/`);
129
+ } catch (error) {
130
+ require_internal_log.internalError(`AzureMonitorTransport: invalid endpoint "${this.endpoint}"`, error);
131
+ return;
132
+ }
133
+ if (reqUrl.protocol !== "https:") {
134
+ require_internal_log.internalError(`AzureMonitorTransport: endpoint must use https (got ${reqUrl.protocol})`);
135
+ return;
136
+ }
137
+ await require_batch_buffer.httpRequest({
138
+ url: reqUrl,
139
+ headers: {
140
+ Authorization: `Bearer ${token}`,
141
+ "Content-Type": "application/json"
142
+ },
143
+ body,
144
+ timeoutMs: this.requestTimeoutMs,
145
+ label: "Azure Monitor API"
146
+ });
147
+ }
148
+ };
149
+
150
+ //#endregion
151
+ Object.defineProperty(exports, 'AzureMonitorTransport', {
152
+ enumerable: true,
153
+ get: function () {
154
+ return AzureMonitorTransport;
155
+ }
156
+ });
157
+ //# sourceMappingURL=azure-monitor.transport-CrvfHd9C.js.map