logixia 1.12.5 → 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 +65 -14
  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-DvqtI43C.d.ts → logitron-logger.module-CxT1F6Cm.d.ts} +25 -12
  90. package/dist/logitron-logger.module-CxT1F6Cm.d.ts.map +1 -0
  91. package/dist/{logitron-logger.module-CpffEHec.d.mts → logitron-logger.module-zDKVd_o0.d.mts} +25 -12
  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-BIGTm2V6.mjs.map +0 -1
  158. package/dist/logitron-logger.module-BTxDpK6u.js.map +0 -1
  159. package/dist/logitron-logger.module-CpffEHec.d.mts.map +0 -1
  160. package/dist/logitron-logger.module-DvqtI43C.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
@@ -1,102 +1,14 @@
1
- import { createRequire } from "node:module";
2
- import { EventEmitter } from "node:events";
3
- import * as readline from "node:readline";
1
+ import { t as __require } from "./chunk-DLSkYcPk.mjs";
2
+ import { n as internalLog, r as internalWarn, t as internalError } from "./internal-log-Cm8SOWSV.mjs";
3
+ import { i as stringifyForLog } from "./safe-stringify-DJ66tW5I.mjs";
4
+ import { t as safeToString } from "./coerce.utils-Dxv4_ikC.mjs";
4
5
  import * as fs from "node:fs";
5
- import * as path from "node:path";
6
+ import * as path$1 from "node:path";
7
+ import { EventEmitter } from "node:events";
6
8
  import { pipeline } from "node:stream/promises";
7
9
  import { promisify } from "node:util";
8
10
  import { createGzip } from "node:zlib";
9
11
 
10
- //#region rolldown:runtime
11
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
12
-
13
- //#endregion
14
- //#region src/utils/internal-log.ts
15
- /**
16
- * Internal logging helpers for use within the logixia library itself.
17
- *
18
- * These functions write directly to stderr/stdout without going through
19
- * LogixiaLogger — this avoids circular dependencies and ensures internal
20
- * diagnostics still surface even when the logger is misconfigured.
21
- *
22
- * Library code must NEVER call console.log/warn/error directly. Use these
23
- * helpers instead so that internal output can be silenced in tests by setting
24
- * the LOGIXIA_SILENT_INTERNAL=1 environment variable.
25
- */
26
- /**
27
- * Read the silence flag on each call rather than caching it at import time, so
28
- * setting LOGIXIA_SILENT_INTERNAL=1 AFTER the module is first imported (e.g. in
29
- * a test setup file) still takes effect — the documented test-silencing
30
- * behavior was previously unreliable because the value was frozen at load.
31
- */
32
- function isSilent() {
33
- return process.env.LOGIXIA_SILENT_INTERNAL === "1";
34
- }
35
- /**
36
- * Emit an internal debug/info message to stderr.
37
- * Use for field-enable/disable notifications that a developer might want to see
38
- * during development but should not appear in production log streams.
39
- */
40
- function internalLog(message) {
41
- if (!isSilent()) process.stderr.write(`[logixia] ${message}\n`);
42
- }
43
- /**
44
- * Emit an internal warning to stderr.
45
- * Use when something is misconfigured but logixia can continue operating.
46
- */
47
- function internalWarn(message) {
48
- if (!isSilent()) process.stderr.write(`[logixia:warn] ${message}\n`);
49
- }
50
- /**
51
- * Emit an internal error to stderr.
52
- * Use when a transport write fails or a serious internal error occurs.
53
- */
54
- function internalError(message, error) {
55
- if (!isSilent()) {
56
- let errStr = "";
57
- if (error instanceof Error) errStr = ` — ${error.message}`;
58
- else if (error != null) errStr = ` — ${String(error)}`;
59
- process.stderr.write(`[logixia:error] ${message}${errStr}\n`);
60
- }
61
- }
62
-
63
- //#endregion
64
- //#region src/utils/coerce.utils.ts
65
- /**
66
- * Defensive value coercion helpers for Logixia.
67
- *
68
- * Logger inputs come from third-party code (NestJS framework internals,
69
- * user payloads, error objects) where the runtime type is not always what
70
- * the TypeScript signature promises. The formatter / transport hot paths
71
- * call `.replace()` on string fields and crash if the field is anything
72
- * else. Use these helpers anywhere a downstream consumer assumes a string.
73
- */
74
- /**
75
- * Coerce any value to a string without throwing.
76
- *
77
- * - `undefined` / `null` → `''` (so the field is rendered as empty rather
78
- * than the literal string "undefined")
79
- * - strings → returned as-is (zero allocation on the hot path)
80
- * - Errors → `error.message` (matches what users would expect to see)
81
- * - everything else → `JSON.stringify` if possible, falling back to
82
- * `String(value)` for circular refs / values without a stringifier.
83
- */
84
- function safeToString(value) {
85
- var _constructor;
86
- if (typeof value === "string") return value;
87
- if (value === void 0 || value === null) return "";
88
- if (value instanceof Error) return value.message;
89
- if (typeof value === "number" || typeof value === "bigint" || typeof value === "boolean") return String(value);
90
- if (typeof value === "symbol") return value.toString();
91
- if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
92
- try {
93
- const json = JSON.stringify(value);
94
- if (json !== void 0) return json;
95
- } catch {}
96
- return `[${((_constructor = value.constructor) === null || _constructor === void 0 ? void 0 : _constructor.name) ?? "object"}]`;
97
- }
98
-
99
- //#endregion
100
12
  //#region src/transports/console.transport.ts
101
13
  /**
102
14
  * Writes log entries to stdout (info/debug/verbose) and stderr (error/warn).
@@ -142,7 +54,7 @@ var ConsoleTransport = class ConsoleTransport {
142
54
  (lvl === "error" || lvl === "warn" ? process.stderr : process.stdout).write(formatted);
143
55
  }
144
56
  formatEntry(entry) {
145
- if (this.config.format === "json") return JSON.stringify({
57
+ if (this.config.format === "json") return stringifyForLog({
146
58
  timestamp: this.config.timestamp !== false ? entry.timestamp.toISOString() : void 0,
147
59
  level: entry.level,
148
60
  message: entry.message,
@@ -170,7 +82,7 @@ var ConsoleTransport = class ConsoleTransport {
170
82
  }
171
83
  parts.push(ConsoleTransport.sanitize(entry.message));
172
84
  if (entry.data && Object.keys(entry.data).length > 0) {
173
- const data = JSON.stringify(entry.data);
85
+ const data = stringifyForLog(entry.data);
174
86
  parts.push(this.colorize(data, "blue"));
175
87
  }
176
88
  return parts.join(" ");
@@ -205,6 +117,15 @@ var ConsoleTransport = class ConsoleTransport {
205
117
  * Validates that a SQL identifier (table/index name) contains only safe characters.
206
118
  * Prevents SQL injection via user-supplied table names.
207
119
  */
120
+ const POSTGRES_MAX_PARAMS = 65535;
121
+ const POSTGRES_COLUMNS = 8;
122
+ const POSTGRES_ROWS_PER_INSERT = Math.floor(POSTGRES_MAX_PARAMS / POSTGRES_COLUMNS);
123
+ const MYSQL_ROWS_PER_INSERT = 5e3;
124
+ function chunk(items, size) {
125
+ const chunks = [];
126
+ for (let i = 0; i < items.length; i += size) chunks.push(items.slice(i, i + size));
127
+ return chunks;
128
+ }
208
129
  function validateSqlIdentifier(name, label = "table") {
209
130
  if (!/^[a-zA-Z_]\w*$/.test(name)) throw new Error(`Invalid ${label} name "${name}". Only letters, digits, and underscores are allowed, and the name must start with a letter or underscore.`);
210
131
  }
@@ -406,22 +327,38 @@ var DatabaseTransport = class {
406
327
  }
407
328
  async flushToPostgreSQL(entries) {
408
329
  const tableName = this.config.table || "logs";
409
- const values = entries.map((entry) => [
330
+ const chunks = chunk(entries.map((entry) => [
410
331
  entry.timestamp,
411
332
  entry.level,
412
333
  entry.message,
413
- JSON.stringify(entry.data || {}),
334
+ stringifyForLog(entry.data || {}),
414
335
  entry.context,
415
336
  entry.traceId,
416
337
  entry.appName,
417
338
  entry.environment
418
- ]);
419
- const query = `
339
+ ]), POSTGRES_ROWS_PER_INSERT);
340
+ const insertChunk = async (rows) => {
341
+ const query = `
420
342
  INSERT INTO ${tableName}
421
343
  (timestamp, level, message, payload, context, trace_id, app_name, environment)
422
- VALUES ${values.map((_, i) => `($${i * 8 + 1}, $${i * 8 + 2}, $${i * 8 + 3}, $${i * 8 + 4}, $${i * 8 + 5}, $${i * 8 + 6}, $${i * 8 + 7}, $${i * 8 + 8})`).join(", ")}
344
+ VALUES ${rows.map((_, i) => {
345
+ return `(${Array.from({ length: POSTGRES_COLUMNS }, (_unused, c) => `$${i * POSTGRES_COLUMNS + c + 1}`).join(", ")})`;
346
+ }).join(", ")}
423
347
  `;
424
- await this.connection.query(query, values.flat());
348
+ await this.connection.query(query, rows.flat());
349
+ };
350
+ if (chunks.length === 1) {
351
+ await insertChunk(chunks[0]);
352
+ return;
353
+ }
354
+ await this.connection.query("BEGIN");
355
+ try {
356
+ for (const rows of chunks) await insertChunk(rows);
357
+ await this.connection.query("COMMIT");
358
+ } catch (error) {
359
+ await this.connection.query("ROLLBACK").catch(() => {});
360
+ throw error;
361
+ }
425
362
  }
426
363
  async flushToMySQL(entries) {
427
364
  const tableName = this.config.table || "logs";
@@ -429,7 +366,7 @@ var DatabaseTransport = class {
429
366
  entry.timestamp,
430
367
  entry.level,
431
368
  entry.message,
432
- JSON.stringify(entry.data || {}),
369
+ stringifyForLog(entry.data || {}),
433
370
  entry.context,
434
371
  entry.traceId,
435
372
  entry.appName,
@@ -440,7 +377,19 @@ var DatabaseTransport = class {
440
377
  (timestamp, level, message, payload, context, trace_id, app_name, environment)
441
378
  VALUES ?
442
379
  `;
443
- await this.connection.query(query, [values]);
380
+ const chunks = chunk(values, MYSQL_ROWS_PER_INSERT);
381
+ if (chunks.length === 1) {
382
+ await this.connection.query(query, [values]);
383
+ return;
384
+ }
385
+ await this.connection.beginTransaction();
386
+ try {
387
+ for (const rows of chunks) await this.connection.query(query, [rows]);
388
+ await this.connection.commit();
389
+ } catch (error) {
390
+ await this.connection.rollback().catch(() => {});
391
+ throw error;
392
+ }
444
393
  }
445
394
  async flushToSQLite(entries) {
446
395
  const tableName = this.config.table || "logs";
@@ -449,8 +398,16 @@ var DatabaseTransport = class {
449
398
  (timestamp, level, message, payload, context, trace_id, app_name, environment)
450
399
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
451
400
  `);
452
- for (const entry of entries) await stmt.run(entry.timestamp instanceof Date ? entry.timestamp.toISOString() : entry.timestamp, entry.level, entry.message, JSON.stringify(entry.data || {}), entry.context, entry.traceId, entry.appName, entry.environment);
453
- await stmt.finalize();
401
+ await this.connection.exec("BEGIN");
402
+ try {
403
+ for (const entry of entries) await stmt.run(entry.timestamp instanceof Date ? entry.timestamp.toISOString() : entry.timestamp, entry.level, entry.message, stringifyForLog(entry.data || {}), entry.context, entry.traceId, entry.appName, entry.environment);
404
+ await this.connection.exec("COMMIT");
405
+ } catch (error) {
406
+ await this.connection.exec("ROLLBACK").catch(() => {});
407
+ throw error;
408
+ } finally {
409
+ await stmt.finalize().catch(() => {});
410
+ }
454
411
  }
455
412
  async createPostgreSQLTable() {
456
413
  const tableName = this.config.table || "logs";
@@ -518,11 +475,13 @@ var DatabaseTransport = class {
518
475
  await this.connection.exec(`CREATE INDEX IF NOT EXISTS idx_${tableName}_trace_id ON ${tableName} (trace_id)`);
519
476
  }
520
477
  setupFlushTimer() {
478
+ var _this$flushTimer$unre, _this$flushTimer;
521
479
  this.flushTimer = setInterval(() => {
522
480
  this.flush().catch((error) => {
523
481
  internalError("Scheduled database flush error", error);
524
482
  });
525
483
  }, this.flushInterval);
484
+ (_this$flushTimer$unre = (_this$flushTimer = this.flushTimer).unref) === null || _this$flushTimer$unre === void 0 || _this$flushTimer$unre.call(_this$flushTimer);
526
485
  }
527
486
  async close() {
528
487
  if (this.flushTimer) {
@@ -530,6 +489,7 @@ var DatabaseTransport = class {
530
489
  this.flushTimer = void 0;
531
490
  }
532
491
  const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
492
+ if (this.flushPromise) await this.flushPromise.catch(() => {});
533
493
  for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) try {
534
494
  await this.flush();
535
495
  } catch (error) {
@@ -565,14 +525,22 @@ var DatabaseTransport = class {
565
525
  try {
566
526
  switch (this.config.type) {
567
527
  case "mongodb": return await this.connection.db(this.config.database).collection(this.config.collection || "logs").countDocuments();
568
- case "postgresql":
569
- case "mysql":
570
- case "sqlite": {
571
- var _result$rows, _result$;
528
+ case "postgresql": {
529
+ var _result$rows;
572
530
  const tableName = this.config.table || "logs";
573
531
  const result = await this.connection.query(`SELECT COUNT(*) as count FROM ${tableName}`);
574
- const rawCount = ((_result$rows = result.rows) === null || _result$rows === void 0 || (_result$rows = _result$rows[0]) === null || _result$rows === void 0 ? void 0 : _result$rows.count) ?? ((_result$ = result[0]) === null || _result$ === void 0 ? void 0 : _result$.count) ?? 0;
575
- return Number(rawCount) || 0;
532
+ return Number((_result$rows = result.rows) === null || _result$rows === void 0 || (_result$rows = _result$rows[0]) === null || _result$rows === void 0 ? void 0 : _result$rows.count) || 0;
533
+ }
534
+ case "mysql": {
535
+ var _rows$;
536
+ const tableName = this.config.table || "logs";
537
+ const [rows] = await this.connection.query(`SELECT COUNT(*) as count FROM ${tableName}`);
538
+ return Number(rows === null || rows === void 0 || (_rows$ = rows[0]) === null || _rows$ === void 0 ? void 0 : _rows$.count) || 0;
539
+ }
540
+ case "sqlite": {
541
+ const tableName = this.config.table || "logs";
542
+ const row = await this.connection.get(`SELECT COUNT(*) as count FROM ${tableName}`);
543
+ return Number(row === null || row === void 0 ? void 0 : row.count) || 0;
576
544
  }
577
545
  default: return 0;
578
546
  }
@@ -599,10 +567,9 @@ var AnalyticsTransport = class {
599
567
  this.level = config.level;
600
568
  this.batchSize = this.config.batchSize || 50;
601
569
  this.flushInterval = this.config.flushInterval || 1e4;
602
- this.initialize();
603
570
  }
604
571
  async write(entry) {
605
- if (!this.isReady) await this.waitForReady();
572
+ if (!this.isReady) await this.ensureReady();
606
573
  if (this.shouldSkipEntry(entry)) return;
607
574
  if (this.config.batchSize && this.config.batchSize > 1) this.addToBatch(entry);
608
575
  else await this.sendEntry(entry);
@@ -610,9 +577,13 @@ var AnalyticsTransport = class {
610
577
  addToBatch(entry) {
611
578
  this.batch.push(entry);
612
579
  if (this.batch.length >= (this.config.batchSize || 50)) this.flush().catch((err) => internalError(`${this.name} batch flush failed`, err));
613
- else if (!this.batchTimer && this.config.flushInterval) this.batchTimer = setTimeout(() => {
614
- this.flush().catch((err) => internalError(`${this.name} interval flush failed`, err));
615
- }, this.config.flushInterval);
580
+ else if (!this.batchTimer && this.config.flushInterval) {
581
+ var _this$batchTimer$unre, _this$batchTimer;
582
+ this.batchTimer = setTimeout(() => {
583
+ this.flush().catch((err) => internalError(`${this.name} interval flush failed`, err));
584
+ }, this.config.flushInterval);
585
+ (_this$batchTimer$unre = (_this$batchTimer = this.batchTimer).unref) === null || _this$batchTimer$unre === void 0 || _this$batchTimer$unre.call(_this$batchTimer);
586
+ }
616
587
  }
617
588
  async flush() {
618
589
  if (this.batchTimer) {
@@ -671,10 +642,20 @@ var AnalyticsTransport = class {
671
642
  if (this.config.customProperties) Object.assign(transformed, this.config.customProperties);
672
643
  return transformed;
673
644
  }
674
- async waitForReady(timeout = 5e3) {
675
- const startTime = Date.now();
676
- while (!this.isReady && Date.now() - startTime < timeout) await new Promise((resolve) => setTimeout(resolve, 100));
677
- if (!this.isReady) throw new Error(`Analytics transport ${this.name} failed to initialize within ${timeout}ms`);
645
+ /**
646
+ * Runs initialize() once. A bad config (say, a missing API key) fails every
647
+ * write with the same error instead of an unhandled rejection at startup.
648
+ */
649
+ ensureReady() {
650
+ this.initPromise ??= (async () => {
651
+ await this.initialize();
652
+ this.isReady = true;
653
+ })();
654
+ return this.initPromise;
655
+ }
656
+ /** @deprecated Use ensureReady(); kept for subclasses that call it. */
657
+ async waitForReady() {
658
+ await this.ensureReady();
678
659
  }
679
660
  };
680
661
 
@@ -700,7 +681,6 @@ var DataDogTransport = class extends AnalyticsTransport {
700
681
  async initialize() {
701
682
  try {
702
683
  if (!this.datadogConfig.apiKey) throw new Error("DataDog API key is required");
703
- await this.testConnection();
704
684
  this.isReady = true;
705
685
  } catch (error) {
706
686
  internalError("DataDog transport initialization failed", error);
@@ -751,11 +731,11 @@ var DataDogTransport = class extends AnalyticsTransport {
751
731
  timestamp: entry.timestamp.toISOString(),
752
732
  level: this.mapLogLevel(entry.level),
753
733
  message: entry.message,
754
- service: this.datadogConfig.service || "logitron",
734
+ service: this.datadogConfig.service || "logixia",
755
735
  version: this.datadogConfig.version,
756
736
  env: this.datadogConfig.env || "production",
757
737
  logger: {
758
- name: "logitron",
738
+ name: "logixia",
759
739
  thread_name: "main"
760
740
  },
761
741
  ...transformed,
@@ -773,7 +753,7 @@ var DataDogTransport = class extends AnalyticsTransport {
773
753
  host: this.getHostname(),
774
754
  tags: [
775
755
  `level:${entry.level}`,
776
- `service:${this.datadogConfig.service || "logitron"}`,
756
+ `service:${this.datadogConfig.service || "logixia"}`,
777
757
  `env:${this.datadogConfig.env || "production"}`,
778
758
  ...entry.context ? [`context:${entry.context}`] : [],
779
759
  ...entry.appName ? [`app:${entry.appName}`] : []
@@ -786,7 +766,7 @@ var DataDogTransport = class extends AnalyticsTransport {
786
766
  span_id: this.generateSpanId(),
787
767
  parent_id: null,
788
768
  name: "log.entry",
789
- service: this.datadogConfig.service || "logitron",
769
+ service: this.datadogConfig.service || "logixia",
790
770
  resource: entry.message,
791
771
  type: "log",
792
772
  start: entry.timestamp.getTime() * 1e6,
@@ -823,7 +803,7 @@ var DataDogTransport = class extends AnalyticsTransport {
823
803
  "Content-Type": "application/json",
824
804
  "DD-API-KEY": this.datadogConfig.apiKey
825
805
  },
826
- body: JSON.stringify(data)
806
+ body: stringifyForLog(data)
827
807
  });
828
808
  if (!response.ok) throw new Error(`DataDog Logs API error: ${response.status} ${response.statusText}`);
829
809
  } catch (error) {
@@ -839,23 +819,13 @@ var DataDogTransport = class extends AnalyticsTransport {
839
819
  "Content-Type": "application/json",
840
820
  "DD-API-KEY": this.datadogConfig.apiKey
841
821
  },
842
- body: JSON.stringify(data)
822
+ body: stringifyForLog(data)
843
823
  });
844
824
  if (!response.ok) throw new Error(`DataDog Metrics API error: ${response.status} ${response.statusText}`);
845
825
  } catch (error) {
846
826
  throw new Error(`Failed to send metrics to DataDog: ${error.message}`, { cause: error });
847
827
  }
848
828
  }
849
- async testConnection() {
850
- const testMetric = { series: [{
851
- metric: "logitron.test",
852
- points: [[Math.floor(Date.now() / 1e3), 1]],
853
- type: "count",
854
- host: this.getHostname(),
855
- tags: ["test:true"]
856
- }] };
857
- await this.makeMetricsRequest("/api/v1/series", testMetric);
858
- }
859
829
  generateSpanId() {
860
830
  return Math.floor(Math.random() * 0xffffffffffff).toString(16);
861
831
  }
@@ -883,11 +853,11 @@ var DataDogTransport = class extends AnalyticsTransport {
883
853
  date_happened: Math.floor(Date.now() / 1e3),
884
854
  priority: "normal",
885
855
  tags: [
886
- `service:${this.datadogConfig.service || "logitron"}`,
856
+ `service:${this.datadogConfig.service || "logixia"}`,
887
857
  `env:${this.datadogConfig.env || "production"}`,
888
858
  ...tags
889
859
  ],
890
- source_type_name: "logitron"
860
+ source_type_name: "logixia"
891
861
  };
892
862
  const url = `${this.baseUrl}/api/v1/events`;
893
863
  try {
@@ -897,7 +867,7 @@ var DataDogTransport = class extends AnalyticsTransport {
897
867
  "Content-Type": "application/json",
898
868
  "DD-API-KEY": this.datadogConfig.apiKey
899
869
  },
900
- body: JSON.stringify(payload)
870
+ body: stringifyForLog(payload)
901
871
  });
902
872
  if (!response.ok) throw new Error(`DataDog Events API error: ${response.status} ${response.statusText}`);
903
873
  } catch (error) {
@@ -908,16 +878,46 @@ var DataDogTransport = class extends AnalyticsTransport {
908
878
 
909
879
  //#endregion
910
880
  //#region src/transports/file.transport.ts
911
- const writeFile = promisify(fs.writeFile);
912
- const mkdir = promisify(fs.mkdir);
881
+ const appendFile = promisify(fs.appendFile);
882
+ const rename = promisify(fs.rename);
913
883
  const unlink = promisify(fs.unlink);
914
884
  const readdir = promisify(fs.readdir);
915
885
  const stat = promisify(fs.stat);
886
+ const DROP_WARN_INTERVAL_MS = 5e3;
887
+ const SIZE_UNITS = {
888
+ "": 1,
889
+ k: 1024,
890
+ m: 1024 ** 2,
891
+ g: 1024 ** 3,
892
+ t: 1024 ** 4
893
+ };
894
+ /**
895
+ * Parses a size like `50MB`, `1.5g`, `512 KiB` or a plain byte count.
896
+ * Units are binary (1KB = 1024 bytes). Returns undefined for anything else.
897
+ */
898
+ function parseSize(value) {
899
+ if (value === void 0) return void 0;
900
+ if (typeof value === "number") return Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
901
+ const match = /^(\d+(?:\.\d+)?) ?([kmgt]?)(?:i?b)?$/i.exec(value.trim());
902
+ if (!match) return void 0;
903
+ const bytes = Math.floor(Number(match[1]) * (SIZE_UNITS[(match[2] ?? "").toLowerCase()] ?? 1));
904
+ return bytes > 0 ? bytes : void 0;
905
+ }
906
+ /** Formats a date with the YYYY, MM, DD, HH, mm and ss tokens, in local time. */
907
+ function formatDatePattern(date, pattern) {
908
+ const pad = (n) => String(n).padStart(2, "0");
909
+ return pattern.replace(/YYYY/g, String(date.getFullYear())).replace(/MM/g, pad(date.getMonth() + 1)).replace(/DD/g, pad(date.getDate())).replace(/HH/g, pad(date.getHours())).replace(/mm/g, pad(date.getMinutes())).replace(/ss/g, pad(date.getSeconds()));
910
+ }
916
911
  /**
917
912
  * Appends log entries to a local file with automatic rotation.
918
913
  *
919
- * Supports batched writes, size-based and date-based rotation, and optional
920
- * gzip compression of rotated files.
914
+ * Rotates by size (`maxSize`), by date (`datePattern`), by interval
915
+ * (`rotation.interval`) or by a custom `rotation.shouldRotate` check. Rotated
916
+ * files can be gzipped (`zippedArchive`) and pruned to the newest `maxFiles`.
917
+ *
918
+ * Without a `rotation` block the live file keeps its name (`app.log`) and
919
+ * rotated files are renamed beside it (`app-2026-10-22T09-30-00-000.log`).
920
+ * With a `rotation` block every file, the live one included, is timestamped.
921
921
  *
922
922
  * @example
923
923
  * transports: { file: { filename: 'app.log', dirname: './logs', maxSize: '50MB' } }
@@ -927,7 +927,17 @@ var FileTransport = class {
927
927
  this.name = "file";
928
928
  this.batch = [];
929
929
  this.lastRotation = /* @__PURE__ */ new Date();
930
- this.isRotating = false;
930
+ this.bytesWritten = 0;
931
+ this.rotateRequested = false;
932
+ this.rotationWaiters = [];
933
+ this.enqueued = 0;
934
+ this.settled = 0;
935
+ this.flushWaiters = [];
936
+ this.spaceWaiters = [];
937
+ this.inFlight = 0;
938
+ this.dropped = 0;
939
+ this.lastDropWarning = 0;
940
+ this.housekeeping = Promise.resolve();
931
941
  this.config = {
932
942
  format: "json",
933
943
  batchSize: 100,
@@ -938,50 +948,171 @@ var FileTransport = class {
938
948
  this.batchSize = this.config.batchSize || 100;
939
949
  this.flushInterval = this.config.flushInterval || 5e3;
940
950
  if (config.filter) this.filter = config.filter;
941
- this.currentFilePath = this.generateFilePath();
942
- this.ensureDirectoryExists();
951
+ const rotation = config.rotation;
952
+ const rawMaxSize = (rotation === null || rotation === void 0 ? void 0 : rotation.maxSize) ?? config.maxSize;
953
+ this.maxBytes = parseSize(rawMaxSize);
954
+ if (rawMaxSize !== void 0 && this.maxBytes === void 0) internalWarn(`FileTransport: maxSize ${JSON.stringify(rawMaxSize)} is not a valid size (try '50MB'); size rotation is off`);
955
+ const maxQueue = config.maxQueue;
956
+ if (maxQueue !== void 0 && !(Number.isInteger(maxQueue) && maxQueue > 0)) internalWarn(`FileTransport: maxQueue ${String(maxQueue)} is not a positive integer; ignored`);
957
+ else this.maxQueue = maxQueue;
958
+ this.queuePolicy = config.queuePolicy ?? "drop-oldest";
959
+ this.maxFiles = (rotation === null || rotation === void 0 ? void 0 : rotation.maxFiles) ?? config.maxFiles;
960
+ this.compress = (rotation === null || rotation === void 0 ? void 0 : rotation.compress) ?? config.zippedArchive ?? false;
961
+ this.intervalMs = (rotation === null || rotation === void 0 ? void 0 : rotation.interval) ? this.parseInterval(rotation.interval) : void 0;
962
+ this.timestampedActive = rotation !== void 0;
963
+ this.dir = this.resolveDir();
964
+ this.ext = path$1.extname(config.filename);
965
+ this.base = path$1.basename(config.filename, this.ext);
966
+ try {
967
+ fs.mkdirSync(this.dir, { recursive: true });
968
+ } catch (error) {
969
+ internalError(`FileTransport could not create ${this.dir}`, error);
970
+ }
971
+ this.currentFilePath = this.timestampedActive ? this.uniquePath(this.timestamp(/* @__PURE__ */ new Date())) : path$1.join(this.dir, `${this.base}${this.ext}`);
972
+ let existing;
973
+ try {
974
+ existing = fs.statSync(this.currentFilePath);
975
+ } catch {
976
+ existing = void 0;
977
+ }
978
+ this.bytesWritten = (existing === null || existing === void 0 ? void 0 : existing.size) ?? 0;
979
+ if (config.datePattern) this.period = formatDatePattern((existing === null || existing === void 0 ? void 0 : existing.mtime) ?? /* @__PURE__ */ new Date(), config.datePattern);
943
980
  }
944
981
  async write(entry) {
945
982
  try {
946
- if (this.shouldRotateNow() && !this.isRotating) {
947
- this.isRotating = true;
948
- try {
949
- await this.rotate();
950
- } finally {
951
- this.isRotating = false;
952
- }
953
- }
983
+ while (this.queuePolicy === "block" && this.queueFull()) await this.roomAvailable();
954
984
  if (this.config.batchSize && this.config.batchSize > 1) this.addToBatch(entry);
955
- else await this.writeBatch([entry]);
985
+ else {
986
+ this.enqueue(entry);
987
+ await this.flush();
988
+ }
956
989
  } catch (error) {
957
990
  throw new Error(`File transport write failed: ${error.message}`, { cause: error });
958
991
  }
959
992
  }
993
+ /**
994
+ * Resolves once every entry queued before the call is on disk. It does not
995
+ * wait for entries queued afterwards, so under steady traffic it still returns
996
+ * instead of waiting for a quiet moment that never comes.
997
+ */
960
998
  async flush() {
961
999
  if (this.batchTimer) {
962
1000
  clearTimeout(this.batchTimer);
963
1001
  this.batchTimer = void 0;
964
1002
  }
965
- if (!this.flushPromise) this.flushPromise = this.drain().finally(() => {
966
- this.flushPromise = void 0;
1003
+ if (this.settled >= this.enqueued) return;
1004
+ const done = new Promise((resolve, reject) => {
1005
+ this.flushWaiters.push({
1006
+ upTo: this.enqueued,
1007
+ resolve,
1008
+ reject
1009
+ });
1010
+ });
1011
+ this.startDrain();
1012
+ await done;
1013
+ }
1014
+ /** Writes out anything pending, then starts a new file. */
1015
+ async rotate() {
1016
+ await this.flush();
1017
+ const done = new Promise((resolve) => this.rotationWaiters.push(resolve));
1018
+ this.rotateRequested = true;
1019
+ this.startDrain();
1020
+ await done;
1021
+ }
1022
+ enqueue(entry) {
1023
+ if (this.queueFull()) {
1024
+ if (this.queuePolicy === "drop-oldest" && this.batch.length > 0) {
1025
+ this.batch.shift();
1026
+ this.batch.push(entry);
1027
+ }
1028
+ this.noteDropped();
1029
+ return;
1030
+ }
1031
+ this.batch.push(entry);
1032
+ this.enqueued += 1;
1033
+ }
1034
+ queueFull() {
1035
+ return this.maxQueue !== void 0 && this.batch.length + this.inFlight >= this.maxQueue;
1036
+ }
1037
+ roomAvailable() {
1038
+ const room = new Promise((resolve) => this.spaceWaiters.push(resolve));
1039
+ this.startDrain();
1040
+ return room;
1041
+ }
1042
+ releaseWaiters() {
1043
+ const waiting = this.spaceWaiters;
1044
+ this.spaceWaiters = [];
1045
+ for (const resolve of waiting) resolve();
1046
+ }
1047
+ noteDropped() {
1048
+ this.dropped += 1;
1049
+ this.reportDropped(DROP_WARN_INTERVAL_MS);
1050
+ }
1051
+ reportDropped(minGapMs) {
1052
+ const now = Date.now();
1053
+ if (this.dropped === 0 || now - this.lastDropWarning < minGapMs) return;
1054
+ internalWarn(`FileTransport: dropped ${this.dropped} log line${this.dropped === 1 ? "" : "s"} (queue full at maxQueue ${this.maxQueue}, policy ${this.queuePolicy})`);
1055
+ this.dropped = 0;
1056
+ this.lastDropWarning = now;
1057
+ }
1058
+ startDrain() {
1059
+ if (this.draining) return;
1060
+ this.draining = this.drain().finally(() => {
1061
+ this.draining = void 0;
967
1062
  });
968
- await this.flushPromise;
969
1063
  }
970
1064
  /**
971
- * Drains the batch to disk one snapshot at a time. Entries appended while a
972
- * write is in flight are picked up by the next loop iteration, so a single
973
- * drain() empties the batch completely regardless of concurrent writes.
1065
+ * Writes the batch one snapshot at a time. Entries queued while a write is in
1066
+ * flight are picked up by the next iteration, so one drain empties the batch
1067
+ * however much is logged meanwhile.
974
1068
  */
975
1069
  async drain() {
976
- while (this.batch.length > 0) {
1070
+ while (this.batch.length > 0 || this.rotateRequested) {
1071
+ if (this.rotateRequested) {
1072
+ this.rotateRequested = false;
1073
+ const waiting = this.rotationWaiters;
1074
+ this.rotationWaiters = [];
1075
+ try {
1076
+ await this.rotateFile();
1077
+ } catch (error) {
1078
+ internalError("FileTransport rotation failed", error);
1079
+ }
1080
+ for (const resolve of waiting) resolve();
1081
+ continue;
1082
+ }
977
1083
  const pending = this.batch;
978
1084
  this.batch = [];
979
- await this.writeBatch(pending);
1085
+ this.inFlight = pending.length;
1086
+ let failure;
1087
+ try {
1088
+ await this.writeBatch(pending);
1089
+ } catch (error) {
1090
+ failure = error;
1091
+ }
1092
+ this.inFlight = 0;
1093
+ this.settled += pending.length;
1094
+ this.settle(failure);
1095
+ this.releaseWaiters();
1096
+ }
1097
+ }
1098
+ /**
1099
+ * Resolves the flush() calls whose entries are now written. A failed batch
1100
+ * fails every flush still waiting, since each one covers that batch.
1101
+ */
1102
+ settle(failure) {
1103
+ if (failure !== void 0) {
1104
+ if (this.flushWaiters.length === 0) internalError("FileTransport write failed", failure);
1105
+ for (const waiter of this.flushWaiters) waiter.error ??= failure;
980
1106
  }
1107
+ const waiting = [];
1108
+ for (const waiter of this.flushWaiters) if (waiter.upTo > this.settled) waiting.push(waiter);
1109
+ else if (waiter.error === void 0) waiter.resolve();
1110
+ else waiter.reject(waiter.error);
1111
+ this.flushWaiters = waiting;
981
1112
  }
982
1113
  formatEntry(entry) {
983
1114
  switch (this.config.format) {
984
- case "json": return JSON.stringify({
1115
+ case "json": return stringifyForLog({
985
1116
  timestamp: entry.timestamp.toISOString(),
986
1117
  level: entry.level,
987
1118
  message: entry.message,
@@ -995,43 +1126,79 @@ var FileTransport = class {
995
1126
  `"${safeMessage.replace(/"/g, "\"\"")}"`,
996
1127
  safeToString(entry.context),
997
1128
  safeToString(entry.traceId),
998
- JSON.stringify(entry.data || {})
1129
+ stringifyForLog(entry.data || {})
999
1130
  ].join(",");
1000
1131
  }
1001
1132
  case "text":
1002
- default: return `${entry.timestamp.toISOString()} [${entry.level.toUpperCase()}] ${safeToString(entry.message)}${entry.data ? " " + JSON.stringify(entry.data) : ""}`;
1133
+ default: return `${entry.timestamp.toISOString()} [${entry.level.toUpperCase()}] ${safeToString(entry.message)}${entry.data ? " " + stringifyForLog(entry.data) : ""}`;
1003
1134
  }
1004
1135
  }
1005
1136
  addToBatch(entry) {
1006
- this.batch.push(entry);
1007
- if (this.batch.length >= (this.config.batchSize || 100)) {
1137
+ this.enqueue(entry);
1138
+ const threshold = Math.min(this.config.batchSize || 100, this.maxQueue ?? Infinity);
1139
+ if (this.batch.length >= threshold && !this.draining) {
1008
1140
  if (this.batchTimer) {
1009
1141
  clearTimeout(this.batchTimer);
1010
1142
  this.batchTimer = void 0;
1011
1143
  }
1012
- this.flush().catch((err) => internalError("FileTransport batch flush failed", err));
1144
+ this.startDrain();
1013
1145
  } else if (!this.batchTimer && this.config.flushInterval) this.batchTimer = setTimeout(() => {
1014
1146
  this.flush().catch((err) => internalError("FileTransport interval flush failed", err));
1015
1147
  }, this.config.flushInterval);
1016
1148
  }
1149
+ /** Only ever called from drain(), so writes and rotations never overlap. */
1017
1150
  async writeBatch(entries) {
1018
1151
  if (entries.length === 0) return;
1019
- const content = entries.map((entry) => this.formatEntry(entry)).join("\n") + "\n";
1020
- if (this.writeStream) return new Promise((resolve, reject) => {
1021
- this.writeStream.write(content, (error) => {
1022
- if (error) reject(error);
1023
- else resolve();
1024
- });
1025
- });
1026
- else await writeFile(this.currentFilePath, content, { flag: "a" });
1152
+ if (this.timeToRotate()) await this.rotateFile();
1153
+ if (this.maxBytes === void 0) {
1154
+ const content = entries.map((entry) => this.formatEntry(entry)).join("\n") + "\n";
1155
+ await this.append(content);
1156
+ return;
1157
+ }
1158
+ let chunk$1 = "";
1159
+ let chunkBytes = 0;
1160
+ for (const entry of entries) {
1161
+ const line = this.formatEntry(entry) + "\n";
1162
+ const lineBytes = Buffer.byteLength(line);
1163
+ const used = this.bytesWritten + chunkBytes;
1164
+ if (used > 0 && used + lineBytes > this.maxBytes) {
1165
+ if (chunk$1) await this.append(chunk$1, chunkBytes);
1166
+ chunk$1 = "";
1167
+ chunkBytes = 0;
1168
+ await this.rotateFile();
1169
+ }
1170
+ chunk$1 += line;
1171
+ chunkBytes += lineBytes;
1172
+ }
1173
+ if (chunk$1) await this.append(chunk$1, chunkBytes);
1174
+ }
1175
+ async append(content, bytes = Buffer.byteLength(content)) {
1176
+ await appendFile(this.currentFilePath, content);
1177
+ this.bytesWritten += bytes;
1027
1178
  }
1028
- shouldRotateNow() {
1179
+ timeToRotate() {
1029
1180
  var _this$config$rotation;
1030
- if (!((_this$config$rotation = this.config.rotation) === null || _this$config$rotation === void 0 ? void 0 : _this$config$rotation.interval)) return false;
1031
- return (/* @__PURE__ */ new Date()).getTime() - this.lastRotation.getTime() >= this.parseInterval(this.config.rotation.interval);
1181
+ if (this.intervalMs !== void 0 && Date.now() - this.lastRotation.getTime() >= this.intervalMs) return true;
1182
+ if (this.config.datePattern && this.period !== void 0) {
1183
+ if (formatDatePattern(/* @__PURE__ */ new Date(), this.config.datePattern) !== this.period) return true;
1184
+ }
1185
+ const shouldRotate = (_this$config$rotation = this.config.rotation) === null || _this$config$rotation === void 0 ? void 0 : _this$config$rotation.shouldRotate;
1186
+ if (shouldRotate) {
1187
+ const stats = {
1188
+ size: this.bytesWritten,
1189
+ created: this.lastRotation,
1190
+ modified: /* @__PURE__ */ new Date()
1191
+ };
1192
+ try {
1193
+ return shouldRotate(this.currentFilePath, stats);
1194
+ } catch (error) {
1195
+ internalError("FileTransport rotation.shouldRotate threw", error);
1196
+ }
1197
+ }
1198
+ return false;
1032
1199
  }
1033
1200
  parseInterval(interval) {
1034
- const match = (/* @__PURE__ */ new RegExp(/(\d+)([hdwmy])/i)).exec(interval);
1201
+ const match = /^(\d{1,6})([hdwmy])$/i.exec(interval.trim());
1035
1202
  if (!match) return 1440 * 60 * 1e3;
1036
1203
  const value = Number.parseInt(match[1] || "1", 10);
1037
1204
  switch ((match[2] || "h").toLowerCase()) {
@@ -1043,40 +1210,54 @@ var FileTransport = class {
1043
1210
  default: return value * 60 * 60 * 1e3;
1044
1211
  }
1045
1212
  }
1046
- async rotate() {
1047
- var _this$config$rotation2, _this$config$rotation3;
1048
- await this.flush();
1049
- if (this.writeStream) {
1050
- await new Promise((resolve) => {
1051
- this.writeStream.end(() => resolve());
1052
- });
1053
- this.writeStream = void 0;
1213
+ async rotateFile() {
1214
+ const now = /* @__PURE__ */ new Date();
1215
+ let archived;
1216
+ if (this.timestampedActive) {
1217
+ archived = this.currentFilePath;
1218
+ this.currentFilePath = this.uniquePath(this.timestamp(now));
1219
+ } else {
1220
+ archived = this.uniquePath(this.period ?? this.timestamp(now));
1221
+ try {
1222
+ await rename(this.currentFilePath, archived);
1223
+ } catch (error) {
1224
+ if (error.code !== "ENOENT") {
1225
+ internalError(`FileTransport could not rotate ${this.currentFilePath}`, error);
1226
+ this.bytesWritten = 0;
1227
+ return;
1228
+ }
1229
+ archived = void 0;
1230
+ }
1054
1231
  }
1055
- const oldPath = this.currentFilePath;
1056
- this.currentFilePath = this.generateFilePath();
1057
- this.lastRotation = /* @__PURE__ */ new Date();
1058
- if ((_this$config$rotation2 = this.config.rotation) === null || _this$config$rotation2 === void 0 ? void 0 : _this$config$rotation2.compress) await this.compressFile(oldPath);
1059
- if ((_this$config$rotation3 = this.config.rotation) === null || _this$config$rotation3 === void 0 ? void 0 : _this$config$rotation3.maxFiles) await this.cleanupOldFiles();
1232
+ this.bytesWritten = 0;
1233
+ this.lastRotation = now;
1234
+ if (this.config.datePattern) this.period = formatDatePattern(now, this.config.datePattern);
1235
+ if (archived === void 0 || !fs.existsSync(archived)) return;
1236
+ const file = archived;
1237
+ this.housekeeping = this.housekeeping.then(async () => {
1238
+ if (this.compress) await this.compressFile(file);
1239
+ if (this.maxFiles) await this.cleanupOldFiles();
1240
+ });
1241
+ }
1242
+ timestamp(date) {
1243
+ return date.toISOString().replace(/[:.]/g, "-").slice(0, 23);
1244
+ }
1245
+ /** `<base>-<stamp><ext>`, with `.1`, `.2`… added if that name (or its .gz) is taken. */
1246
+ uniquePath(stamp) {
1247
+ const taken = (p) => fs.existsSync(p) || fs.existsSync(`${p}.gz`);
1248
+ let candidate = path$1.join(this.dir, `${this.base}-${stamp}${this.ext}`);
1249
+ let n = 0;
1250
+ while (taken(candidate) || candidate === this.currentFilePath) {
1251
+ n += 1;
1252
+ candidate = path$1.join(this.dir, `${this.base}-${stamp}.${n}${this.ext}`);
1253
+ }
1254
+ return candidate;
1060
1255
  }
1061
1256
  resolveDir() {
1062
1257
  if (this.config.dirname) return this.config.dirname;
1063
- const fromFilename = path.dirname(this.config.filename);
1258
+ const fromFilename = path$1.dirname(this.config.filename);
1064
1259
  return fromFilename === "." ? process.cwd() : fromFilename;
1065
1260
  }
1066
- generateFilePath() {
1067
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
1068
- const dir = this.resolveDir();
1069
- const ext = path.extname(this.config.filename);
1070
- const base = path.basename(this.config.filename, ext);
1071
- if (this.config.rotation) return path.join(dir, `${base}-${timestamp}${ext}`);
1072
- return path.join(dir, `${base}${ext}`);
1073
- }
1074
- async ensureDirectoryExists() {
1075
- const dir = this.resolveDir();
1076
- try {
1077
- await mkdir(dir, { recursive: true });
1078
- } catch {}
1079
- }
1080
1261
  /**
1081
1262
  * Gzip the rotated file to `<file>.gz` and remove the original. Streams the
1082
1263
  * data so large log files don't have to be buffered in memory. Best-effort:
@@ -1095,33 +1276,42 @@ var FileTransport = class {
1095
1276
  } catch {}
1096
1277
  }
1097
1278
  }
1279
+ /**
1280
+ * True for this transport's rotated files only: `<base>-<stamp><ext>` where the
1281
+ * stamp is digits and separators, optionally `.gz`. Another transport's
1282
+ * `app-error.log` must not count as one of `app.log`'s rotations.
1283
+ */
1284
+ isOwnRotatedFile(file) {
1285
+ const name = file.endsWith(".gz") ? file.slice(0, -3) : file;
1286
+ if (!name.startsWith(`${this.base}-`) || !name.endsWith(this.ext)) return false;
1287
+ const stamp = name.slice(this.base.length + 1, name.length - this.ext.length);
1288
+ return /^\d[\d\-_.T]*$/.test(stamp);
1289
+ }
1098
1290
  async cleanupOldFiles() {
1099
- var _this$config$rotation4;
1100
- if (!((_this$config$rotation4 = this.config.rotation) === null || _this$config$rotation4 === void 0 ? void 0 : _this$config$rotation4.maxFiles)) return;
1291
+ if (!this.maxFiles) return;
1101
1292
  try {
1102
- const dir = this.resolveDir();
1103
- const files = await readdir(dir);
1104
- const ext = path.extname(this.config.filename);
1105
- const base = path.basename(this.config.filename, ext);
1106
- const isOwnRotatedFile = (file) => file.startsWith(`${base}-`) && (file.endsWith(ext) || file.endsWith(`${ext}.gz`));
1107
- const logFiles = files.filter(isOwnRotatedFile).map(async (file) => {
1108
- const filePath = path.join(dir, file);
1293
+ const files = await readdir(this.dir);
1294
+ const active = path$1.basename(this.currentFilePath);
1295
+ const newestFirst = (await Promise.all(files.filter((file) => file !== active && this.isOwnRotatedFile(file)).map(async (file) => {
1296
+ const filePath = path$1.join(this.dir, file);
1109
1297
  return {
1110
1298
  path: filePath,
1111
- mtime: (await stat(filePath)).mtime
1299
+ mtime: (await stat(filePath)).mtimeMs
1112
1300
  };
1113
- });
1114
- const filesToDelete = (await Promise.all(logFiles)).sort((a, b) => b.mtime.getTime() - a.mtime.getTime()).slice(this.config.rotation.maxFiles);
1115
- for (const file of filesToDelete) await unlink(file.path);
1301
+ }))).sort((a, b) => b.mtime - a.mtime || b.path.localeCompare(a.path));
1302
+ for (const file of newestFirst.slice(this.maxFiles)) await unlink(file.path);
1116
1303
  } catch (error) {
1117
1304
  internalError("Failed to cleanup old log files", error);
1118
1305
  }
1119
1306
  }
1120
1307
  async close() {
1308
+ if (this.batchTimer) {
1309
+ clearTimeout(this.batchTimer);
1310
+ this.batchTimer = void 0;
1311
+ }
1121
1312
  await this.flush();
1122
- if (this.writeStream) return new Promise((resolve) => {
1123
- this.writeStream.end(() => resolve());
1124
- });
1313
+ await this.housekeeping;
1314
+ this.reportDropped(0);
1125
1315
  }
1126
1316
  };
1127
1317
 
@@ -1146,7 +1336,6 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
1146
1336
  try {
1147
1337
  if (!this.gaConfig.measurementId) throw new Error("Google Analytics Measurement ID is required");
1148
1338
  if (!this.gaConfig.apiSecret) throw new Error("Google Analytics API Secret is required");
1149
- await this.testConnection();
1150
1339
  this.isReady = true;
1151
1340
  } catch (error) {
1152
1341
  internalError("Google Analytics transport initialization failed", error);
@@ -1215,10 +1404,10 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
1215
1404
  }
1216
1405
  async sendEvents(events) {
1217
1406
  const chunks = this.chunkArray(events, 25);
1218
- for (const chunk of chunks) {
1407
+ for (const chunk$1 of chunks) {
1219
1408
  const payload = {
1220
1409
  client_id: this.gaConfig.clientId || this.generateClientId(),
1221
- events: chunk
1410
+ events: chunk$1
1222
1411
  };
1223
1412
  await this.makeRequest(payload);
1224
1413
  }
@@ -1233,7 +1422,7 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
1233
1422
  const response = await fetch(`${url}?${params}`, {
1234
1423
  method: "POST",
1235
1424
  headers: { "Content-Type": "application/json" },
1236
- body: JSON.stringify(payload)
1425
+ body: stringifyForLog(payload)
1237
1426
  });
1238
1427
  if (!response.ok) {
1239
1428
  const errorText = await response.text();
@@ -1247,22 +1436,6 @@ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
1247
1436
  throw new Error(`Failed to send data to Google Analytics: ${error.message}`, { cause: error });
1248
1437
  }
1249
1438
  }
1250
- async testConnection() {
1251
- const testEvent = {
1252
- name: "logitron_test",
1253
- params: {
1254
- event_category: "Test",
1255
- event_label: "Connection Test",
1256
- test: true,
1257
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1258
- }
1259
- };
1260
- const payload = {
1261
- client_id: this.gaConfig.clientId || this.generateClientId(),
1262
- events: [testEvent]
1263
- };
1264
- await this.makeRequest(payload, true);
1265
- }
1266
1439
  generateClientId() {
1267
1440
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1268
1441
  const r = Math.random() * 16 | 0;
@@ -1373,7 +1546,6 @@ var MixpanelTransport = class extends AnalyticsTransport {
1373
1546
  async initialize() {
1374
1547
  try {
1375
1548
  if (!this.mixpanelConfig.token) throw new Error("Mixpanel token is required");
1376
- await this.testConnection();
1377
1549
  this.isReady = true;
1378
1550
  } catch (error) {
1379
1551
  internalError("Mixpanel transport initialization failed", error);
@@ -1432,7 +1604,7 @@ var MixpanelTransport = class extends AnalyticsTransport {
1432
1604
  "Content-Type": "application/json",
1433
1605
  Accept: "text/plain"
1434
1606
  },
1435
- body: JSON.stringify(data)
1607
+ body: stringifyForLog(data)
1436
1608
  });
1437
1609
  if (!response.ok) throw new Error(`Mixpanel API error: ${response.status} ${response.statusText}`);
1438
1610
  const result = await response.text();
@@ -1441,18 +1613,6 @@ var MixpanelTransport = class extends AnalyticsTransport {
1441
1613
  throw new Error(`Failed to send data to Mixpanel: ${error.message}`, { cause: error });
1442
1614
  }
1443
1615
  }
1444
- async testConnection() {
1445
- const testEvent = {
1446
- event: "logitron_test",
1447
- properties: {
1448
- token: this.mixpanelConfig.token,
1449
- distinct_id: "test_user",
1450
- test: true,
1451
- time: Date.now()
1452
- }
1453
- };
1454
- await this.makeRequest("/track", [testEvent]);
1455
- }
1456
1616
  generateInsertId(entry) {
1457
1617
  return `${entry.timestamp.getTime()}_${this.simpleHash(entry.message + (entry.traceId || ""))}`;
1458
1618
  }
@@ -1499,6 +1659,17 @@ var MixpanelTransport = class extends AnalyticsTransport {
1499
1659
  }
1500
1660
  };
1501
1661
 
1662
+ //#endregion
1663
+ //#region src/version.ts
1664
+ /**
1665
+ * The published version of this package.
1666
+ *
1667
+ * Kept in sync with `version` in package.json by the release process. Importing
1668
+ * from here (instead of reading package.json at runtime) keeps the built `dist`
1669
+ * free of a JSON import that bundlers and consumers would have to resolve.
1670
+ */
1671
+ const LOGIXIA_VERSION = "1.12.0";
1672
+
1502
1673
  //#endregion
1503
1674
  //#region src/transports/segment.transport.ts
1504
1675
  /**
@@ -1522,7 +1693,6 @@ var SegmentTransport = class extends AnalyticsTransport {
1522
1693
  async initialize() {
1523
1694
  try {
1524
1695
  if (!this.segmentConfig.writeKey) throw new Error("Segment Write Key is required");
1525
- await this.testConnection();
1526
1696
  this.isReady = true;
1527
1697
  } catch (error) {
1528
1698
  internalError("Segment transport initialization failed", error);
@@ -1563,7 +1733,7 @@ var SegmentTransport = class extends AnalyticsTransport {
1563
1733
  context: {
1564
1734
  library: {
1565
1735
  name: "logixia",
1566
- version: "1.0.0"
1736
+ version: LOGIXIA_VERSION
1567
1737
  },
1568
1738
  app: {
1569
1739
  name: entry.appName || "unknown",
@@ -1583,8 +1753,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1583
1753
  }
1584
1754
  async batchTrack(events) {
1585
1755
  const chunks = this.chunkArray(events, this.segmentConfig.maxBatchSize || 100);
1586
- for (const chunk of chunks) {
1587
- const payload = { batch: chunk };
1756
+ for (const chunk$1 of chunks) {
1757
+ const payload = { batch: chunk$1 };
1588
1758
  await this.makeRequest("/v1/batch", payload);
1589
1759
  }
1590
1760
  }
@@ -1597,9 +1767,9 @@ var SegmentTransport = class extends AnalyticsTransport {
1597
1767
  headers: {
1598
1768
  "Content-Type": "application/json",
1599
1769
  Authorization: `Basic ${auth}`,
1600
- "User-Agent": "logixia/1.0.0"
1770
+ "User-Agent": `logixia/${LOGIXIA_VERSION}`
1601
1771
  },
1602
- body: JSON.stringify(data)
1772
+ body: stringifyForLog(data)
1603
1773
  });
1604
1774
  if (!response.ok) {
1605
1775
  const errorText = await response.text();
@@ -1609,24 +1779,6 @@ var SegmentTransport = class extends AnalyticsTransport {
1609
1779
  throw new Error(`Failed to send data to Segment: ${error.message}`, { cause: error });
1610
1780
  }
1611
1781
  }
1612
- async testConnection() {
1613
- const testEvent = {
1614
- type: "track",
1615
- event: "Logixia Test",
1616
- userId: "test-user",
1617
- anonymousId: this.generateAnonymousId(),
1618
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1619
- properties: {
1620
- test: true,
1621
- source: "logixia"
1622
- },
1623
- context: { library: {
1624
- name: "logixia",
1625
- version: "1.0.0"
1626
- } }
1627
- };
1628
- await this.makeRequest("/v1/track", testEvent);
1629
- }
1630
1782
  extractUserId(entry) {
1631
1783
  if (entry.data) {
1632
1784
  const d = entry.data;
@@ -1656,8 +1808,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1656
1808
  ...user.traits
1657
1809
  },
1658
1810
  context: { library: {
1659
- name: "logitron",
1660
- version: "1.0.0"
1811
+ name: "logixia",
1812
+ version: LOGIXIA_VERSION
1661
1813
  } }
1662
1814
  };
1663
1815
  await this.makeRequest("/v1/identify", payload);
@@ -1675,8 +1827,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1675
1827
  },
1676
1828
  context: {
1677
1829
  library: {
1678
- name: "logitron",
1679
- version: "1.0.0"
1830
+ name: "logixia",
1831
+ version: LOGIXIA_VERSION
1680
1832
  },
1681
1833
  page: {
1682
1834
  url: properties.url || `/${name.toLowerCase().replace(/\s+/g, "-")}`,
@@ -1695,8 +1847,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1695
1847
  properties: { ...properties },
1696
1848
  context: {
1697
1849
  library: {
1698
- name: "logitron",
1699
- version: "1.0.0"
1850
+ name: "logixia",
1851
+ version: LOGIXIA_VERSION
1700
1852
  },
1701
1853
  screen: { name }
1702
1854
  }
@@ -1712,8 +1864,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1712
1864
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1713
1865
  traits,
1714
1866
  context: { library: {
1715
- name: "logitron",
1716
- version: "1.0.0"
1867
+ name: "logixia",
1868
+ version: LOGIXIA_VERSION
1717
1869
  } }
1718
1870
  };
1719
1871
  await this.makeRequest("/v1/group", payload);
@@ -1725,8 +1877,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1725
1877
  previousId,
1726
1878
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1727
1879
  context: { library: {
1728
- name: "logitron",
1729
- version: "1.0.0"
1880
+ name: "logixia",
1881
+ version: LOGIXIA_VERSION
1730
1882
  } }
1731
1883
  };
1732
1884
  await this.makeRequest("/v1/alias", payload);
@@ -1740,8 +1892,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1740
1892
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1741
1893
  properties,
1742
1894
  context: { library: {
1743
- name: "logitron",
1744
- version: "1.0.0"
1895
+ name: "logixia",
1896
+ version: LOGIXIA_VERSION
1745
1897
  } }
1746
1898
  };
1747
1899
  await this.makeRequest("/v1/track", payload);
@@ -1759,8 +1911,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1759
1911
  products
1760
1912
  },
1761
1913
  context: { library: {
1762
- name: "logitron",
1763
- version: "1.0.0"
1914
+ name: "logixia",
1915
+ version: LOGIXIA_VERSION
1764
1916
  } }
1765
1917
  };
1766
1918
  await this.makeRequest("/v1/track", payload);
@@ -1773,8 +1925,8 @@ var SegmentTransport = class extends AnalyticsTransport {
1773
1925
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1774
1926
  properties: product,
1775
1927
  context: { library: {
1776
- name: "logitron",
1777
- version: "1.0.0"
1928
+ name: "logixia",
1929
+ version: LOGIXIA_VERSION
1778
1930
  } }
1779
1931
  };
1780
1932
  await this.makeRequest("/v1/track", payload);
@@ -1793,7 +1945,7 @@ var TransportManager = class extends EventEmitter {
1793
1945
  this.metrics = /* @__PURE__ */ new Map();
1794
1946
  this.isShuttingDown = false;
1795
1947
  this.transportLevelPreferences = /* @__PURE__ */ new Map();
1796
- this.promptForLevels = false;
1948
+ this.warnedPromptDeprecated = false;
1797
1949
  this.setupTransports(config);
1798
1950
  }
1799
1951
  setupTransports(config) {
@@ -1893,17 +2045,24 @@ var TransportManager = class extends EventEmitter {
1893
2045
  if (entry.context !== void 0) transportEntry.context = entry.context;
1894
2046
  if (entry.traceId !== void 0) transportEntry.traceId = entry.traceId;
1895
2047
  if (entry.environment !== void 0) transportEntry.environment = entry.environment;
1896
- if (this.promptForLevels) return this._writeAsyncWithPrompt(transportEntry);
1897
2048
  let pending;
2049
+ let syncFailure;
1898
2050
  for (const [id, transport] of this.transports) {
1899
2051
  if (!this.shouldTransportHandle(transport, transportEntry.level, id)) continue;
1900
2052
  if (transport.filter && !transport.filter(transportEntry)) continue;
1901
- const result = this.writeToTransport(id, transport, transportEntry);
2053
+ let result;
2054
+ try {
2055
+ result = this.writeToTransport(id, transport, transportEntry);
2056
+ } catch (error) {
2057
+ syncFailure ??= { error };
2058
+ continue;
2059
+ }
1902
2060
  if (result && typeof result.then === "function") {
1903
2061
  if (pending === void 0) pending = [];
1904
2062
  pending.push(result);
1905
2063
  }
1906
2064
  }
2065
+ if (syncFailure) throw syncFailure.error;
1907
2066
  if (pending === void 0) return;
1908
2067
  return Promise.allSettled(pending).then((results) => {
1909
2068
  const failures = results.filter((r) => r.status === "rejected");
@@ -1913,22 +2072,6 @@ var TransportManager = class extends EventEmitter {
1913
2072
  }
1914
2073
  });
1915
2074
  }
1916
- /** Slow path used only when interactive level-prompting is enabled. */
1917
- async _writeAsyncWithPrompt(transportEntry) {
1918
- const writePromises = [];
1919
- for (const [id, transport] of this.transports) {
1920
- if (!this.transportLevelPreferences.has(id)) await this.configureTransportLevels(id);
1921
- if (!this.shouldTransportHandle(transport, transportEntry.level, id)) continue;
1922
- if (transport.filter && !transport.filter(transportEntry)) continue;
1923
- const result = this.writeToTransport(id, transport, transportEntry);
1924
- if (result && typeof result.then === "function") writePromises.push(result);
1925
- }
1926
- const failures = (await Promise.allSettled(writePromises)).filter((r) => r.status === "rejected");
1927
- if (failures.length > 0) {
1928
- const errors = failures.map((f) => f.reason);
1929
- this.emit("error", /* @__PURE__ */ new Error(`Transport write failures: ${errors.join(", ")}`), "multiple");
1930
- }
1931
- }
1932
2075
  writeToTransport(id, transport, entry) {
1933
2076
  const startTime = Date.now();
1934
2077
  const metrics = this.metrics.get(id);
@@ -2115,52 +2258,18 @@ var TransportManager = class extends EventEmitter {
2115
2258
  details
2116
2259
  };
2117
2260
  }
2261
+ /** @deprecated Library code never prompts on stdin. Use setTransportLevels(). No-op. */
2118
2262
  enableLevelPrompting() {
2119
- this.promptForLevels = true;
2120
- internalLog("Transport level prompting enabled");
2263
+ this.warnPromptingRemoved();
2121
2264
  }
2265
+ /** @deprecated Library code never prompts on stdin. No-op. */
2122
2266
  disableLevelPrompting() {
2123
- this.promptForLevels = false;
2124
- internalLog("Transport level prompting disabled");
2267
+ this.warnPromptingRemoved();
2125
2268
  }
2126
- async promptUserForTransportLevels(transportId) {
2127
- const availableLevels = [
2128
- "error",
2129
- "warn",
2130
- "info",
2131
- "debug",
2132
- "trace",
2133
- "verbose"
2134
- ];
2135
- return new Promise((resolve) => {
2136
- const rl = readline.createInterface({
2137
- input: process.stdin,
2138
- output: process.stdout
2139
- });
2140
- process.stdout.write(`\nConfigure log levels for transport '${transportId}'\n`);
2141
- process.stdout.write(`Available levels: ${availableLevels.join(", ")}\n`);
2142
- process.stdout.write("Enter levels separated by commas (e.g., error,warn,info) or \"all\" for all levels:\n");
2143
- rl.question("> ", (answer) => {
2144
- rl.close();
2145
- if (answer.toLowerCase().trim() === "all") resolve(availableLevels);
2146
- else {
2147
- const selectedLevels = answer.split(",").map((level) => level.trim().toLowerCase()).filter((level) => availableLevels.includes(level));
2148
- if (selectedLevels.length === 0) {
2149
- internalWarn("No valid levels selected, using all levels");
2150
- resolve(availableLevels);
2151
- } else {
2152
- internalLog(`Selected levels for ${transportId}: ${selectedLevels.join(", ")}`);
2153
- resolve(selectedLevels);
2154
- }
2155
- }
2156
- });
2157
- });
2158
- }
2159
- async configureTransportLevels(transportId) {
2160
- if (this.promptForLevels && !this.transportLevelPreferences.has(transportId)) {
2161
- const selectedLevels = await this.promptUserForTransportLevels(transportId);
2162
- this.transportLevelPreferences.set(transportId, selectedLevels);
2163
- }
2269
+ warnPromptingRemoved() {
2270
+ if (this.warnedPromptDeprecated) return;
2271
+ this.warnedPromptDeprecated = true;
2272
+ internalWarn("Transport level prompting was removed: logixia never reads stdin. Use setTransportLevels(id, levels) instead.");
2164
2273
  }
2165
2274
  setTransportLevels(transportId, levels) {
2166
2275
  this.transportLevelPreferences.set(transportId, levels);
@@ -2176,5 +2285,5 @@ var TransportManager = class extends EventEmitter {
2176
2285
  };
2177
2286
 
2178
2287
  //#endregion
2179
- export { FileTransport as a, DatabaseTransport as c, internalError as d, internalLog as f, GoogleAnalyticsTransport as i, ConsoleTransport as l, __require as m, SegmentTransport as n, DataDogTransport as o, internalWarn as p, MixpanelTransport as r, AnalyticsTransport as s, TransportManager as t, safeToString as u };
2180
- //# sourceMappingURL=transport.manager-DETpXuaY.mjs.map
2288
+ export { FileTransport as a, DatabaseTransport as c, GoogleAnalyticsTransport as i, ConsoleTransport as l, SegmentTransport as n, DataDogTransport as o, MixpanelTransport as r, AnalyticsTransport as s, TransportManager as t };
2289
+ //# sourceMappingURL=transport.manager-D6KL3t9V.mjs.map