logixia 1.1.4 → 1.2.0

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 (68) hide show
  1. package/README.md +8 -0
  2. package/dist/{build-DIEB3doa.js → build-DOx-YxF1.js} +1 -1
  3. package/dist/{build-DIEB3doa.js.map → build-DOx-YxF1.js.map} +1 -1
  4. package/dist/{build-MmD3T4bV.mjs → build-DWmxA6A2.mjs} +1 -1
  5. package/dist/{build-MmD3T4bV.mjs.map → build-DWmxA6A2.mjs.map} +1 -1
  6. package/dist/{esm-BRY8ugtK.mjs → esm-1Ra90uql.mjs} +1 -1
  7. package/dist/{esm-BRY8ugtK.mjs.map → esm-1Ra90uql.mjs.map} +1 -1
  8. package/dist/{esm-CzjF801-.js → esm-FNhqFIqG.js} +1 -1
  9. package/dist/{esm-CzjF801-.js.map → esm-FNhqFIqG.js.map} +1 -1
  10. package/dist/index-BDRSTjUt.d.ts +247 -0
  11. package/dist/index-BDRSTjUt.d.ts.map +1 -0
  12. package/dist/index-Drrzn-Yg.d.mts +247 -0
  13. package/dist/index-Drrzn-Yg.d.mts.map +1 -0
  14. package/dist/index.d.mts +4 -1311
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.d.ts +4 -1311
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +177 -13898
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +135 -13841
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{lib-BNWFXK2z.mjs → lib-8XKCHDOH.mjs} +1 -1
  23. package/dist/{lib-BNWFXK2z.mjs.map → lib-8XKCHDOH.mjs.map} +1 -1
  24. package/dist/{lib-Bb_wxP5g.js → lib-BNEYXXTQ.js} +1 -1
  25. package/dist/{lib-Bb_wxP5g.js.map → lib-BNEYXXTQ.js.map} +1 -1
  26. package/dist/logitron-logger.module-CY3t8yK6.d.mts +279 -0
  27. package/dist/logitron-logger.module-CY3t8yK6.d.mts.map +1 -0
  28. package/dist/logitron-logger.module-DgEldK9V.d.ts +279 -0
  29. package/dist/logitron-logger.module-DgEldK9V.d.ts.map +1 -0
  30. package/dist/logitron-logger.module-X6nGDVGC.js +10484 -0
  31. package/dist/logitron-logger.module-X6nGDVGC.js.map +1 -0
  32. package/dist/logitron-logger.module-iO8DPE7_.mjs +10307 -0
  33. package/dist/logitron-logger.module-iO8DPE7_.mjs.map +1 -0
  34. package/dist/nest.d.mts +63 -0
  35. package/dist/nest.d.mts.map +1 -0
  36. package/dist/nest.d.ts +63 -0
  37. package/dist/nest.d.ts.map +1 -0
  38. package/dist/nest.js +127 -0
  39. package/dist/nest.js.map +1 -0
  40. package/dist/nest.mjs +95 -0
  41. package/dist/nest.mjs.map +1 -0
  42. package/dist/{promise-O6_ARWpI.mjs → promise-C4pQPcK4.mjs} +1 -1
  43. package/dist/{promise-O6_ARWpI.mjs.map → promise-C4pQPcK4.mjs.map} +1 -1
  44. package/dist/{promise-DWsrbKAX.js → promise-DaiZ2BaH.js} +1 -1
  45. package/dist/{promise-DWsrbKAX.js.map → promise-DaiZ2BaH.js.map} +1 -1
  46. package/dist/search-1txemGPh.mjs +1 -0
  47. package/dist/search-Cg_OasF-.d.ts +1 -0
  48. package/dist/search-DanSf_yc.d.mts +1 -0
  49. package/dist/search-DeZHhWxB.js +0 -0
  50. package/dist/search.d.mts +1 -0
  51. package/dist/search.d.ts +1 -0
  52. package/dist/search.js +1 -0
  53. package/dist/search.mjs +3 -0
  54. package/dist/{sqlite3-DWYzFy5X.js → sqlite3-CSkpjC90.js} +1 -1
  55. package/dist/{sqlite3-DWYzFy5X.js.map → sqlite3-CSkpjC90.js.map} +1 -1
  56. package/dist/{sqlite3-BUpkBlte.mjs → sqlite3-DD2_nRRH.mjs} +1 -1
  57. package/dist/{sqlite3-BUpkBlte.mjs.map → sqlite3-DD2_nRRH.mjs.map} +1 -1
  58. package/dist/transport.manager-C3Xr7Tvi.js +1925 -0
  59. package/dist/transport.manager-C3Xr7Tvi.js.map +1 -0
  60. package/dist/transport.manager-Vi__pagn.mjs +1849 -0
  61. package/dist/transport.manager-Vi__pagn.mjs.map +1 -0
  62. package/dist/transports.d.mts +409 -0
  63. package/dist/transports.d.mts.map +1 -0
  64. package/dist/transports.d.ts +409 -0
  65. package/dist/transports.d.ts.map +1 -0
  66. package/dist/transports.js +11 -0
  67. package/dist/transports.mjs +3 -0
  68. package/package.json +19 -3
@@ -0,0 +1,1925 @@
1
+ const require_chunk = require('./chunk-BTgCAUrQ.js');
2
+ let node_events = require("node:events");
3
+ node_events = require_chunk.__toESM(node_events);
4
+ let node_readline = require("node:readline");
5
+ node_readline = require_chunk.__toESM(node_readline);
6
+ let node_fs = require("node:fs");
7
+ node_fs = require_chunk.__toESM(node_fs);
8
+ let node_path = require("node:path");
9
+ node_path = require_chunk.__toESM(node_path);
10
+ let node_util = require("node:util");
11
+ node_util = require_chunk.__toESM(node_util);
12
+
13
+ //#region src/utils/internal-log.ts
14
+ /**
15
+ * Internal logging helpers for use within the logixia library itself.
16
+ *
17
+ * These functions write directly to stderr/stdout without going through
18
+ * LogixiaLogger — this avoids circular dependencies and ensures internal
19
+ * diagnostics still surface even when the logger is misconfigured.
20
+ *
21
+ * Library code must NEVER call console.log/warn/error directly. Use these
22
+ * helpers instead so that internal output can be silenced in tests by setting
23
+ * the LOGIXIA_SILENT_INTERNAL=1 environment variable.
24
+ */
25
+ const silent = process.env.LOGIXIA_SILENT_INTERNAL === "1";
26
+ /**
27
+ * Emit an internal debug/info message to stderr.
28
+ * Use for field-enable/disable notifications that a developer might want to see
29
+ * during development but should not appear in production log streams.
30
+ */
31
+ function internalLog(message) {
32
+ if (!silent) process.stderr.write(`[logixia] ${message}\n`);
33
+ }
34
+ /**
35
+ * Emit an internal warning to stderr.
36
+ * Use when something is misconfigured but logixia can continue operating.
37
+ */
38
+ function internalWarn(message) {
39
+ if (!silent) process.stderr.write(`[logixia:warn] ${message}\n`);
40
+ }
41
+ /**
42
+ * Emit an internal error to stderr.
43
+ * Use when a transport write fails or a serious internal error occurs.
44
+ */
45
+ function internalError(message, error) {
46
+ if (!silent) {
47
+ let errStr = "";
48
+ if (error instanceof Error) errStr = ` — ${error.message}`;
49
+ else if (error != null) errStr = ` — ${String(error)}`;
50
+ process.stderr.write(`[logixia:error] ${message}${errStr}\n`);
51
+ }
52
+ }
53
+
54
+ //#endregion
55
+ //#region src/transports/console.transport.ts
56
+ var ConsoleTransport = class ConsoleTransport {
57
+ static #_ = this.COLORS = new Map([
58
+ ["red", "\x1B[31m"],
59
+ ["green", "\x1B[32m"],
60
+ ["yellow", "\x1B[33m"],
61
+ ["blue", "\x1B[34m"],
62
+ ["magenta", "\x1B[35m"],
63
+ ["cyan", "\x1B[36m"],
64
+ ["white", "\x1B[37m"],
65
+ ["gray", "\x1B[90m"],
66
+ ["reset", "\x1B[0m"]
67
+ ]);
68
+ constructor(config = {}) {
69
+ this.config = config;
70
+ this.name = "console";
71
+ }
72
+ write(entry) {
73
+ const formatted = this.formatEntry(entry) + "\n";
74
+ (entry.level.toLowerCase() === "error" ? process.stderr : process.stdout).write(formatted);
75
+ return Promise.resolve();
76
+ }
77
+ formatEntry(entry) {
78
+ if (this.config.format === "json") return JSON.stringify({
79
+ timestamp: this.config.timestamp !== false ? entry.timestamp.toISOString() : void 0,
80
+ level: entry.level,
81
+ message: entry.message,
82
+ ...entry.data || {},
83
+ context: entry.context,
84
+ traceId: entry.traceId,
85
+ appName: entry.appName,
86
+ environment: entry.environment
87
+ }, null, 2);
88
+ const parts = [];
89
+ if (this.config.timestamp !== false) {
90
+ const timestamp = entry.timestamp.toISOString();
91
+ parts.push(this.colorize(timestamp, "gray"));
92
+ }
93
+ const level = entry.level.toUpperCase().padEnd(5);
94
+ const coloredLevel = this.colorize(level, this.getLevelColor(entry.level));
95
+ parts.push(coloredLevel);
96
+ if (entry.context) {
97
+ const context = `[${entry.context}]`;
98
+ parts.push(this.colorize(context, "cyan"));
99
+ }
100
+ if (entry.traceId) {
101
+ const traceId = `(${entry.traceId})`;
102
+ parts.push(this.colorize(traceId, "magenta"));
103
+ }
104
+ parts.push(entry.message);
105
+ if (entry.data && Object.keys(entry.data).length > 0) {
106
+ const data = JSON.stringify(entry.data);
107
+ parts.push(this.colorize(data, "blue"));
108
+ }
109
+ return parts.join(" ");
110
+ }
111
+ getLevelColor(level) {
112
+ return {
113
+ error: "red",
114
+ warn: "yellow",
115
+ warning: "yellow",
116
+ info: "green",
117
+ debug: "blue",
118
+ trace: "magenta",
119
+ verbose: "cyan"
120
+ }[level.toLowerCase()] || "white";
121
+ }
122
+ colorize(text, color) {
123
+ if (this.config.colorize === false) return text;
124
+ const reset = ConsoleTransport.COLORS.get("reset");
125
+ return `${ConsoleTransport.COLORS.get(color) ?? ConsoleTransport.COLORS.get("white")}${text}${reset}`;
126
+ }
127
+ close() {
128
+ return Promise.resolve();
129
+ }
130
+ };
131
+
132
+ //#endregion
133
+ //#region src/transports/database.transport.ts
134
+ var DatabaseTransport = class {
135
+ constructor(config) {
136
+ this.config = config;
137
+ this.name = "database";
138
+ this.batch = [];
139
+ this.isConnected = false;
140
+ this.batchSize = config.batchSize || 100;
141
+ this.flushInterval = config.flushInterval || 5e3;
142
+ this.setupFlushTimer();
143
+ }
144
+ async write(entry) {
145
+ if (!this.isConnected) await this.connect();
146
+ this.addToBatch(entry);
147
+ if (this.batch.length >= this.batchSize) await this.flush();
148
+ }
149
+ addToBatch(entry) {
150
+ this.batch.push(entry);
151
+ }
152
+ async flush() {
153
+ if (this.batch.length === 0) return;
154
+ const entriesToFlush = [...this.batch];
155
+ this.batch = [];
156
+ try {
157
+ switch (this.config.type) {
158
+ case "mongodb":
159
+ await this.flushToMongoDB(entriesToFlush);
160
+ break;
161
+ case "postgresql":
162
+ await this.flushToPostgreSQL(entriesToFlush);
163
+ break;
164
+ case "mysql":
165
+ await this.flushToMySQL(entriesToFlush);
166
+ break;
167
+ case "sqlite":
168
+ await this.flushToSQLite(entriesToFlush);
169
+ break;
170
+ default: throw new Error(`Unsupported database type: ${this.config.type}`);
171
+ }
172
+ } catch (error) {
173
+ internalError("Database flush error", error);
174
+ this.batch.unshift(...entriesToFlush);
175
+ throw error;
176
+ }
177
+ }
178
+ async isReady() {
179
+ try {
180
+ if (!this.isConnected) await this.connect();
181
+ return this.isConnected;
182
+ } catch {
183
+ return false;
184
+ }
185
+ }
186
+ async connect() {
187
+ if (this.connectionPromise) return this.connectionPromise;
188
+ this.connectionPromise = this.establishConnection();
189
+ return this.connectionPromise;
190
+ }
191
+ async establishConnection() {
192
+ try {
193
+ switch (this.config.type) {
194
+ case "mongodb":
195
+ await this.connectMongoDB();
196
+ break;
197
+ case "postgresql":
198
+ await this.connectPostgreSQL();
199
+ break;
200
+ case "mysql":
201
+ await this.connectMySQL();
202
+ break;
203
+ case "sqlite":
204
+ await this.connectSQLite();
205
+ break;
206
+ }
207
+ this.isConnected = true;
208
+ } catch (error) {
209
+ this.isConnected = false;
210
+ throw new Error(`Database connection failed: ${error}`, { cause: error });
211
+ }
212
+ }
213
+ async connectMongoDB() {
214
+ try {
215
+ const { MongoClient } = await Promise.resolve().then(() => require_chunk.__toDynamicImportESM()(require("./lib-BNEYXXTQ.js"))).catch(() => {
216
+ throw new Error("MongoDB driver not installed. Run: npm install mongodb");
217
+ });
218
+ this.connection = new MongoClient(this.config.connectionString || `mongodb://${this.config.host}:${this.config.port}/${this.config.database}`);
219
+ await this.connection.connect();
220
+ await this.connection.db(this.config.database).admin().ping();
221
+ } catch (error) {
222
+ throw new Error(`MongoDB connection failed: ${error}`, { cause: error });
223
+ }
224
+ }
225
+ async connectPostgreSQL() {
226
+ try {
227
+ const { Client } = await Promise.resolve().then(() => require("./esm-FNhqFIqG.js")).catch(() => {
228
+ throw new Error("PostgreSQL driver not installed. Run: npm install pg @types/pg");
229
+ });
230
+ const config = {
231
+ connectionString: this.config.connectionString,
232
+ host: this.config.host,
233
+ port: this.config.port,
234
+ database: this.config.database
235
+ };
236
+ if (this.config.username) config.user = this.config.username;
237
+ if (this.config.password) config.password = this.config.password;
238
+ if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
239
+ this.connection = new Client(config);
240
+ await this.connection.connect();
241
+ await this.createPostgreSQLTable();
242
+ } catch (error) {
243
+ throw new Error(`PostgreSQL connection failed: ${error}`, { cause: error });
244
+ }
245
+ }
246
+ async connectMySQL() {
247
+ try {
248
+ const mysql = await Promise.resolve().then(() => require_chunk.__toDynamicImportESM()(require("./promise-DaiZ2BaH.js"))).catch(() => {
249
+ throw new Error("MySQL driver not installed. Run: npm install mysql2");
250
+ });
251
+ const config = {
252
+ host: this.config.host,
253
+ port: this.config.port,
254
+ database: this.config.database
255
+ };
256
+ if (this.config.username) config.user = this.config.username;
257
+ if (this.config.password) config.password = this.config.password;
258
+ if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
259
+ this.connection = await mysql.createConnection(config);
260
+ await this.createMySQLTable();
261
+ } catch (error) {
262
+ throw new Error(`MySQL connection failed: ${error}`, { cause: error });
263
+ }
264
+ }
265
+ async connectSQLite() {
266
+ try {
267
+ const sqlite3 = await Promise.resolve().then(() => require_chunk.__toDynamicImportESM()(require("./sqlite3-CSkpjC90.js"))).catch(() => {
268
+ throw new Error("SQLite driver not installed. Run: npm install sqlite3 sqlite");
269
+ });
270
+ const { open } = await Promise.resolve().then(() => require("./build-DOx-YxF1.js")).catch(() => {
271
+ throw new Error("SQLite driver not installed. Run: npm install sqlite3 sqlite");
272
+ });
273
+ this.connection = await open({
274
+ filename: this.config.database,
275
+ driver: sqlite3.Database
276
+ });
277
+ await this.createSQLiteTable();
278
+ } catch (error) {
279
+ throw new Error(`SQLite connection failed: ${error}`, { cause: error });
280
+ }
281
+ }
282
+ async flushToMongoDB(entries) {
283
+ const collection = this.connection.db(this.config.database).collection(this.config.collection || "logs");
284
+ const documents = entries.map((entry) => ({
285
+ timestamp: entry.timestamp,
286
+ level: entry.level,
287
+ message: entry.message,
288
+ payload: entry.data,
289
+ context: entry.context,
290
+ traceId: entry.traceId,
291
+ appName: entry.appName,
292
+ environment: entry.environment
293
+ }));
294
+ await collection.insertMany(documents);
295
+ }
296
+ async flushToPostgreSQL(entries) {
297
+ const tableName = this.config.table || "logs";
298
+ const values = entries.map((entry) => [
299
+ entry.timestamp,
300
+ entry.level,
301
+ entry.message,
302
+ JSON.stringify(entry.data || {}),
303
+ entry.context,
304
+ entry.traceId,
305
+ entry.appName,
306
+ entry.environment
307
+ ]);
308
+ const query = `
309
+ INSERT INTO ${tableName}
310
+ (timestamp, level, message, payload, context, trace_id, app_name, environment)
311
+ VALUES ${values.map((_, i) => `($${i * 9 + 1}, $${i * 9 + 2}, $${i * 9 + 3}, $${i * 9 + 4}, $${i * 9 + 5}, $${i * 9 + 6}, $${i * 9 + 7}, $${i * 9 + 8}, $${i * 9 + 9})`).join(", ")}
312
+ `;
313
+ await this.connection.query(query, values.flat());
314
+ }
315
+ async flushToMySQL(entries) {
316
+ const tableName = this.config.table || "logs";
317
+ const values = entries.map((entry) => [
318
+ entry.timestamp,
319
+ entry.level,
320
+ entry.message,
321
+ JSON.stringify(entry.data || {}),
322
+ entry.context,
323
+ entry.traceId,
324
+ entry.appName,
325
+ entry.environment
326
+ ]);
327
+ const query = `
328
+ INSERT INTO ${tableName}
329
+ (timestamp, level, message, payload, context, trace_id, app_name, environment)
330
+ VALUES ?
331
+ `;
332
+ await this.connection.query(query, [values]);
333
+ }
334
+ async flushToSQLite(entries) {
335
+ const tableName = this.config.table || "logs";
336
+ const stmt = await this.connection.prepare(`
337
+ INSERT INTO ${tableName}
338
+ (timestamp, level, message, payload, context, trace_id, app_name, environment)
339
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
340
+ `);
341
+ 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);
342
+ await stmt.finalize();
343
+ }
344
+ async createPostgreSQLTable() {
345
+ const tableName = this.config.table || "logs";
346
+ const query = `
347
+ CREATE TABLE IF NOT EXISTS ${tableName} (
348
+ id SERIAL PRIMARY KEY,
349
+ timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
350
+ level VARCHAR(20) NOT NULL,
351
+ message TEXT NOT NULL,
352
+ payload JSONB,
353
+ context VARCHAR(255),
354
+ trace_id VARCHAR(255),
355
+ app_name VARCHAR(255),
356
+ environment VARCHAR(50),
357
+ time_taken INTEGER,
358
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
359
+ )
360
+ `;
361
+ await this.connection.query(query);
362
+ await this.connection.query(`CREATE INDEX IF NOT EXISTS idx_${tableName}_timestamp ON ${tableName} (timestamp)`);
363
+ await this.connection.query(`CREATE INDEX IF NOT EXISTS idx_${tableName}_level ON ${tableName} (level)`);
364
+ await this.connection.query(`CREATE INDEX IF NOT EXISTS idx_${tableName}_trace_id ON ${tableName} (trace_id)`);
365
+ }
366
+ async createMySQLTable() {
367
+ const query = `
368
+ CREATE TABLE IF NOT EXISTS ${this.config.table || "logs"} (
369
+ id INT AUTO_INCREMENT PRIMARY KEY,
370
+ timestamp DATETIME NOT NULL,
371
+ level VARCHAR(20) NOT NULL,
372
+ message TEXT NOT NULL,
373
+ payload JSON,
374
+ context VARCHAR(255),
375
+ trace_id VARCHAR(255),
376
+ app_name VARCHAR(255),
377
+ environment VARCHAR(50),
378
+ time_taken INT,
379
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
380
+ INDEX idx_timestamp (timestamp),
381
+ INDEX idx_level (level),
382
+ INDEX idx_trace_id (trace_id)
383
+ )
384
+ `;
385
+ await this.connection.execute(query);
386
+ }
387
+ async createSQLiteTable() {
388
+ const tableName = this.config.table || "logs";
389
+ const query = `
390
+ CREATE TABLE IF NOT EXISTS ${tableName} (
391
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
392
+ timestamp TEXT NOT NULL,
393
+ level TEXT NOT NULL,
394
+ message TEXT NOT NULL,
395
+ payload TEXT,
396
+ context TEXT,
397
+ trace_id TEXT,
398
+ app_name TEXT,
399
+ environment TEXT,
400
+ time_taken INTEGER,
401
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
402
+ )
403
+ `;
404
+ await this.connection.exec(query);
405
+ await this.connection.exec(`CREATE INDEX IF NOT EXISTS idx_${tableName}_timestamp ON ${tableName} (timestamp)`);
406
+ await this.connection.exec(`CREATE INDEX IF NOT EXISTS idx_${tableName}_level ON ${tableName} (level)`);
407
+ await this.connection.exec(`CREATE INDEX IF NOT EXISTS idx_${tableName}_trace_id ON ${tableName} (trace_id)`);
408
+ }
409
+ setupFlushTimer() {
410
+ this.flushTimer = setInterval(() => {
411
+ this.flush().catch((error) => {
412
+ internalError("Scheduled database flush error", error);
413
+ });
414
+ }, this.flushInterval);
415
+ }
416
+ async close() {
417
+ if (this.flushTimer) clearInterval(this.flushTimer);
418
+ await this.flush();
419
+ if (this.connection) switch (this.config.type) {
420
+ case "mongodb":
421
+ await this.connection.close();
422
+ break;
423
+ case "postgresql":
424
+ await this.connection.end();
425
+ break;
426
+ case "mysql":
427
+ await this.connection.end();
428
+ break;
429
+ case "sqlite":
430
+ await this.connection.close();
431
+ break;
432
+ }
433
+ this.isConnected = false;
434
+ }
435
+ getBatchInfo() {
436
+ return {
437
+ batchSize: this.batchSize,
438
+ currentBatchLength: this.batch.length,
439
+ flushInterval: this.flushInterval,
440
+ isConnected: this.isConnected
441
+ };
442
+ }
443
+ async getLogCount() {
444
+ if (!this.isConnected) return 0;
445
+ try {
446
+ switch (this.config.type) {
447
+ case "mongodb": return await this.connection.db(this.config.database).collection(this.config.collection || "logs").countDocuments();
448
+ case "postgresql":
449
+ case "mysql":
450
+ case "sqlite": {
451
+ var _result$rows, _result$;
452
+ const tableName = this.config.table || "logs";
453
+ const result = await this.connection.query(`SELECT COUNT(*) as count FROM ${tableName}`);
454
+ return ((_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;
455
+ }
456
+ default: return 0;
457
+ }
458
+ } catch {
459
+ return 0;
460
+ }
461
+ }
462
+ };
463
+
464
+ //#endregion
465
+ //#region src/transports/analytics.transport.ts
466
+ var AnalyticsTransport = class {
467
+ constructor(name, config) {
468
+ this.batch = [];
469
+ this.isReady = false;
470
+ this.name = name;
471
+ this.config = {
472
+ batchSize: 50,
473
+ flushInterval: 1e4,
474
+ enableUserTracking: true,
475
+ enableEventTracking: true,
476
+ ...config
477
+ };
478
+ this.level = config.level;
479
+ this.batchSize = this.config.batchSize || 50;
480
+ this.flushInterval = this.config.flushInterval || 1e4;
481
+ this.initialize();
482
+ }
483
+ async write(entry) {
484
+ if (!this.isReady) await this.waitForReady();
485
+ if (this.shouldSkipEntry(entry)) return;
486
+ if (this.config.batchSize && this.config.batchSize > 1) this.addToBatch(entry);
487
+ else await this.sendEntry(entry);
488
+ }
489
+ addToBatch(entry) {
490
+ this.batch.push(entry);
491
+ if (this.batch.length >= (this.config.batchSize || 50)) this.flush().catch((err) => internalError(`${this.name} batch flush failed`, err));
492
+ else if (!this.batchTimer && this.config.flushInterval) this.batchTimer = setTimeout(() => {
493
+ this.flush().catch((err) => internalError(`${this.name} interval flush failed`, err));
494
+ }, this.config.flushInterval);
495
+ }
496
+ async flush() {
497
+ if (this.batch.length === 0) return;
498
+ const entriesToSend = [...this.batch];
499
+ this.batch = [];
500
+ if (this.batchTimer) {
501
+ clearTimeout(this.batchTimer);
502
+ delete this.batchTimer;
503
+ }
504
+ try {
505
+ await this.sendBatch(entriesToSend);
506
+ } catch (error) {
507
+ internalError(`Analytics transport ${this.name} flush failed`, error);
508
+ this.batch.unshift(...entriesToSend);
509
+ }
510
+ }
511
+ async close() {
512
+ await this.flush();
513
+ if (this.batchTimer) clearTimeout(this.batchTimer);
514
+ await this.cleanup();
515
+ }
516
+ shouldSkipEntry(entry) {
517
+ return ["debug", "trace"].includes(entry.level.toLowerCase());
518
+ }
519
+ transformEntry(entry) {
520
+ const transformed = {
521
+ timestamp: entry.timestamp.toISOString(),
522
+ level: entry.level,
523
+ message: entry.message,
524
+ ...entry.data
525
+ };
526
+ if (entry.context) transformed.context = entry.context;
527
+ if (entry.traceId) transformed.traceId = entry.traceId;
528
+ if (entry.appName) transformed.appName = entry.appName;
529
+ if (entry.environment) transformed.environment = entry.environment;
530
+ if (this.config.customProperties) Object.assign(transformed, this.config.customProperties);
531
+ return transformed;
532
+ }
533
+ async waitForReady(timeout = 5e3) {
534
+ const startTime = Date.now();
535
+ while (!this.isReady && Date.now() - startTime < timeout) await new Promise((resolve) => setTimeout(resolve, 100));
536
+ if (!this.isReady) throw new Error(`Analytics transport ${this.name} failed to initialize within ${timeout}ms`);
537
+ }
538
+ };
539
+
540
+ //#endregion
541
+ //#region src/transports/datadog.transport.ts
542
+ var DataDogTransport = class extends AnalyticsTransport {
543
+ constructor(config) {
544
+ super("datadog", config);
545
+ this.datadogConfig = config;
546
+ const site = config.site || "datadoghq.com";
547
+ this.baseUrl = `https://api.${site}`;
548
+ this.logsUrl = `https://http-intake.logs.${site}`;
549
+ this.metricsUrl = `https://api.${site}`;
550
+ }
551
+ async initialize() {
552
+ try {
553
+ if (!this.datadogConfig.apiKey) throw new Error("DataDog API key is required");
554
+ await this.testConnection();
555
+ this.isReady = true;
556
+ } catch (error) {
557
+ internalError("DataDog transport initialization failed", error);
558
+ throw error;
559
+ }
560
+ }
561
+ async sendEntry(entry) {
562
+ const promises = [];
563
+ if (this.datadogConfig.enableLogs !== false) promises.push(this.sendLog(entry));
564
+ if (this.datadogConfig.enableMetrics) promises.push(this.sendMetric(entry));
565
+ if (this.datadogConfig.enableTraces && entry.traceId) promises.push(this.sendTrace(entry));
566
+ await Promise.all(promises);
567
+ }
568
+ async sendBatch(entries) {
569
+ const promises = [];
570
+ if (this.datadogConfig.enableLogs !== false) promises.push(this.sendLogBatch(entries));
571
+ if (this.datadogConfig.enableMetrics) promises.push(this.sendMetricBatch(entries));
572
+ if (this.datadogConfig.enableTraces) {
573
+ const entriesWithTraces = entries.filter((e) => e.traceId);
574
+ if (entriesWithTraces.length > 0) promises.push(this.sendTraceBatch(entriesWithTraces));
575
+ }
576
+ await Promise.all(promises);
577
+ }
578
+ async cleanup() {}
579
+ async sendLog(entry) {
580
+ await this.sendLogBatch([entry]);
581
+ }
582
+ async sendLogBatch(entries) {
583
+ const payload = { logs: entries.map((entry) => this.transformToDataDogLog(entry)) };
584
+ await this.makeLogsRequest("/v1/input/" + this.datadogConfig.apiKey, payload);
585
+ }
586
+ async sendMetric(entry) {
587
+ await this.sendMetricBatch([entry]);
588
+ }
589
+ async sendMetricBatch(entries) {
590
+ const payload = { series: entries.map((entry) => this.transformToDataDogMetric(entry)) };
591
+ await this.makeMetricsRequest("/api/v1/series", payload);
592
+ }
593
+ async sendTrace(entry) {
594
+ await this.sendLog(entry);
595
+ }
596
+ async sendTraceBatch(entries) {
597
+ await this.sendLogBatch(entries);
598
+ }
599
+ transformToDataDogLog(entry) {
600
+ const transformed = this.transformEntry(entry);
601
+ return {
602
+ timestamp: entry.timestamp.toISOString(),
603
+ level: this.mapLogLevel(entry.level),
604
+ message: entry.message,
605
+ service: this.datadogConfig.service || "logitron",
606
+ version: this.datadogConfig.version,
607
+ env: this.datadogConfig.env || "production",
608
+ logger: {
609
+ name: "logitron",
610
+ thread_name: "main"
611
+ },
612
+ ...transformed,
613
+ "dd.trace_id": entry.traceId,
614
+ "dd.span_id": this.generateSpanId(),
615
+ host: this.getHostname(),
616
+ source: "nodejs"
617
+ };
618
+ }
619
+ transformToDataDogMetric(entry) {
620
+ return {
621
+ metric: `logitron.logs.${entry.level}`,
622
+ points: [[Math.floor(entry.timestamp.getTime() / 1e3), 1]],
623
+ type: "count",
624
+ host: this.getHostname(),
625
+ tags: [
626
+ `level:${entry.level}`,
627
+ `service:${this.datadogConfig.service || "logitron"}`,
628
+ `env:${this.datadogConfig.env || "production"}`,
629
+ ...entry.context ? [`context:${entry.context}`] : [],
630
+ ...entry.appName ? [`app:${entry.appName}`] : []
631
+ ]
632
+ };
633
+ }
634
+ transformToDataDogTrace(entry) {
635
+ return {
636
+ trace_id: entry.traceId,
637
+ span_id: this.generateSpanId(),
638
+ parent_id: null,
639
+ name: "log.entry",
640
+ service: this.datadogConfig.service || "logitron",
641
+ resource: entry.message,
642
+ type: "log",
643
+ start: entry.timestamp.getTime() * 1e6,
644
+ duration: 1e6,
645
+ meta: {
646
+ "log.level": entry.level,
647
+ "log.message": entry.message,
648
+ ...entry.context && { "log.context": entry.context },
649
+ ...entry.data && Object.keys(entry.data).reduce((acc, key) => {
650
+ acc[`log.${key}`] = String(entry.data[key]);
651
+ return acc;
652
+ }, {})
653
+ },
654
+ metrics: { _sampling_priority_v1: 1 }
655
+ };
656
+ }
657
+ mapLogLevel(level) {
658
+ return {
659
+ error: "error",
660
+ warn: "warn",
661
+ warning: "warn",
662
+ info: "info",
663
+ debug: "debug",
664
+ trace: "trace",
665
+ verbose: "debug"
666
+ }[level.toLowerCase()] || "info";
667
+ }
668
+ async makeLogsRequest(endpoint, data) {
669
+ const url = `${this.logsUrl}${endpoint}`;
670
+ try {
671
+ const response = await fetch(url, {
672
+ method: "POST",
673
+ headers: {
674
+ "Content-Type": "application/json",
675
+ "DD-API-KEY": this.datadogConfig.apiKey
676
+ },
677
+ body: JSON.stringify(data)
678
+ });
679
+ if (!response.ok) throw new Error(`DataDog Logs API error: ${response.status} ${response.statusText}`);
680
+ } catch (error) {
681
+ throw new Error(`Failed to send logs to DataDog: ${error.message}`, { cause: error });
682
+ }
683
+ }
684
+ async makeMetricsRequest(endpoint, data) {
685
+ const url = `${this.metricsUrl}${endpoint}`;
686
+ try {
687
+ const response = await fetch(url, {
688
+ method: "POST",
689
+ headers: {
690
+ "Content-Type": "application/json",
691
+ "DD-API-KEY": this.datadogConfig.apiKey
692
+ },
693
+ body: JSON.stringify(data)
694
+ });
695
+ if (!response.ok) throw new Error(`DataDog Metrics API error: ${response.status} ${response.statusText}`);
696
+ } catch (error) {
697
+ throw new Error(`Failed to send metrics to DataDog: ${error.message}`, { cause: error });
698
+ }
699
+ }
700
+ async testConnection() {
701
+ const testMetric = { series: [{
702
+ metric: "logitron.test",
703
+ points: [[Math.floor(Date.now() / 1e3), 1]],
704
+ type: "count",
705
+ host: this.getHostname(),
706
+ tags: ["test:true"]
707
+ }] };
708
+ await this.makeMetricsRequest("/api/v1/series", testMetric);
709
+ }
710
+ generateSpanId() {
711
+ return Math.floor(Math.random() * 0xffffffffffff).toString(16);
712
+ }
713
+ getHostname() {
714
+ try {
715
+ return require("node:os").hostname();
716
+ } catch {
717
+ return "unknown";
718
+ }
719
+ }
720
+ async sendCustomMetric(metric) {
721
+ const payload = { series: [{
722
+ metric: metric.name,
723
+ points: [[Math.floor((metric.timestamp || /* @__PURE__ */ new Date()).getTime() / 1e3), metric.value]],
724
+ type: "gauge",
725
+ host: this.getHostname(),
726
+ tags: Object.entries(metric.tags || {}).map(([key, value]) => `${key}:${value}`)
727
+ }] };
728
+ await this.makeMetricsRequest("/api/v1/series", payload);
729
+ }
730
+ async sendEvent(title, text, tags = []) {
731
+ const payload = {
732
+ title,
733
+ text,
734
+ date_happened: Math.floor(Date.now() / 1e3),
735
+ priority: "normal",
736
+ tags: [
737
+ `service:${this.datadogConfig.service || "logitron"}`,
738
+ `env:${this.datadogConfig.env || "production"}`,
739
+ ...tags
740
+ ],
741
+ source_type_name: "logitron"
742
+ };
743
+ const url = `${this.baseUrl}/api/v1/events`;
744
+ try {
745
+ const response = await fetch(url, {
746
+ method: "POST",
747
+ headers: {
748
+ "Content-Type": "application/json",
749
+ "DD-API-KEY": this.datadogConfig.apiKey
750
+ },
751
+ body: JSON.stringify(payload)
752
+ });
753
+ if (!response.ok) throw new Error(`DataDog Events API error: ${response.status} ${response.statusText}`);
754
+ } catch (error) {
755
+ throw new Error(`Failed to send event to DataDog: ${error.message}`, { cause: error });
756
+ }
757
+ }
758
+ };
759
+
760
+ //#endregion
761
+ //#region src/transports/file.transport.ts
762
+ const writeFile = (0, node_util.promisify)(node_fs.writeFile);
763
+ const mkdir = (0, node_util.promisify)(node_fs.mkdir);
764
+ const unlink = (0, node_util.promisify)(node_fs.unlink);
765
+ const readdir = (0, node_util.promisify)(node_fs.readdir);
766
+ const stat = (0, node_util.promisify)(node_fs.stat);
767
+ var FileTransport = class {
768
+ constructor(config) {
769
+ this.name = "file";
770
+ this.batch = [];
771
+ this.lastRotation = /* @__PURE__ */ new Date();
772
+ this.config = {
773
+ format: "json",
774
+ batchSize: 100,
775
+ flushInterval: 5e3,
776
+ ...config
777
+ };
778
+ this.level = config.level;
779
+ this.batchSize = this.config.batchSize || 100;
780
+ this.flushInterval = this.config.flushInterval || 5e3;
781
+ this.currentFilePath = this.generateFilePath();
782
+ this.ensureDirectoryExists();
783
+ }
784
+ async write(entry) {
785
+ try {
786
+ if (this.shouldRotateNow()) await this.rotate();
787
+ if (this.config.batchSize && this.config.batchSize > 1) this.addToBatch(entry);
788
+ else await this.writeBatch([entry]);
789
+ } catch (error) {
790
+ throw new Error(`File transport write failed: ${error.message}`, { cause: error });
791
+ }
792
+ }
793
+ async flush() {
794
+ if (this.batch.length > 0) {
795
+ await this.writeBatch([...this.batch]);
796
+ this.batch = [];
797
+ }
798
+ if (this.batchTimer) {
799
+ clearTimeout(this.batchTimer);
800
+ this.batchTimer = void 0;
801
+ }
802
+ }
803
+ formatEntry(entry) {
804
+ switch (this.config.format) {
805
+ case "json": return JSON.stringify({
806
+ timestamp: entry.timestamp.toISOString(),
807
+ level: entry.level,
808
+ message: entry.message,
809
+ ...entry.data || {}
810
+ });
811
+ case "csv": return [
812
+ entry.timestamp.toISOString(),
813
+ entry.level,
814
+ `"${entry.message.replace(/"/g, "\"\"")}"`,
815
+ entry.context || "",
816
+ entry.traceId || "",
817
+ JSON.stringify(entry.data || {})
818
+ ].join(",");
819
+ case "text":
820
+ default: return `${entry.timestamp.toISOString()} [${entry.level.toUpperCase()}] ${entry.message}${entry.data ? " " + JSON.stringify(entry.data) : ""}`;
821
+ }
822
+ }
823
+ addToBatch(entry) {
824
+ this.batch.push(entry);
825
+ if (this.batch.length >= (this.config.batchSize || 100)) this.flush().catch((err) => internalError("FileTransport batch flush failed", err));
826
+ else if (!this.batchTimer && this.config.flushInterval) this.batchTimer = setTimeout(() => {
827
+ this.flush().catch((err) => internalError("FileTransport interval flush failed", err));
828
+ }, this.config.flushInterval);
829
+ }
830
+ async writeBatch(entries) {
831
+ if (entries.length === 0) return;
832
+ const content = entries.map((entry) => this.formatEntry(entry)).join("\n") + "\n";
833
+ if (this.writeStream) return new Promise((resolve, reject) => {
834
+ this.writeStream.write(content, (error) => {
835
+ if (error) reject(error);
836
+ else resolve();
837
+ });
838
+ });
839
+ else await writeFile(this.currentFilePath, content, { flag: "a" });
840
+ }
841
+ shouldRotateNow() {
842
+ if (!this.config.rotation) return false;
843
+ return (/* @__PURE__ */ new Date()).getTime() - this.lastRotation.getTime() >= this.parseInterval(this.config.rotation.interval);
844
+ }
845
+ parseInterval(interval) {
846
+ const match = interval.match(/(\d+)([hdwmy])/i);
847
+ if (!match) return 1440 * 60 * 1e3;
848
+ const value = Number.parseInt(match[1] || "1", 10);
849
+ switch ((match[2] || "h").toLowerCase()) {
850
+ case "h": return value * 60 * 60 * 1e3;
851
+ case "d": return value * 24 * 60 * 60 * 1e3;
852
+ case "w": return value * 7 * 24 * 60 * 60 * 1e3;
853
+ case "m": return value * 30 * 24 * 60 * 60 * 1e3;
854
+ case "y": return value * 365 * 24 * 60 * 60 * 1e3;
855
+ default: return value * 60 * 60 * 1e3;
856
+ }
857
+ }
858
+ async rotate() {
859
+ var _this$config$rotation, _this$config$rotation2;
860
+ await this.flush();
861
+ if (this.writeStream) {
862
+ await new Promise((resolve) => {
863
+ this.writeStream.end(() => resolve());
864
+ });
865
+ this.writeStream = void 0;
866
+ }
867
+ const oldPath = this.currentFilePath;
868
+ this.currentFilePath = this.generateFilePath();
869
+ this.lastRotation = /* @__PURE__ */ new Date();
870
+ if ((_this$config$rotation = this.config.rotation) === null || _this$config$rotation === void 0 ? void 0 : _this$config$rotation.compress) await this.compressFile(oldPath);
871
+ if ((_this$config$rotation2 = this.config.rotation) === null || _this$config$rotation2 === void 0 ? void 0 : _this$config$rotation2.maxFiles) await this.cleanupOldFiles();
872
+ }
873
+ generateFilePath() {
874
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
875
+ const dir = node_path.dirname(this.config.filename);
876
+ const ext = node_path.extname(this.config.filename);
877
+ const base = node_path.basename(this.config.filename, ext);
878
+ if (this.config.rotation) return node_path.join(dir, `${base}-${timestamp}${ext}`);
879
+ return this.config.filename;
880
+ }
881
+ async ensureDirectoryExists() {
882
+ const dir = node_path.dirname(this.currentFilePath);
883
+ try {
884
+ await mkdir(dir, { recursive: true });
885
+ } catch {}
886
+ }
887
+ async compressFile(_filePath) {}
888
+ async cleanupOldFiles() {
889
+ var _this$config$rotation3;
890
+ if (!((_this$config$rotation3 = this.config.rotation) === null || _this$config$rotation3 === void 0 ? void 0 : _this$config$rotation3.maxFiles)) return;
891
+ try {
892
+ const dir = node_path.dirname(this.config.filename);
893
+ const files = await readdir(dir);
894
+ const base = node_path.basename(this.config.filename, node_path.extname(this.config.filename));
895
+ const logFiles = files.filter((file) => file.startsWith(base)).map(async (file) => {
896
+ const filePath = node_path.join(dir, file);
897
+ return {
898
+ path: filePath,
899
+ mtime: (await stat(filePath)).mtime
900
+ };
901
+ });
902
+ const filesToDelete = (await Promise.all(logFiles)).sort((a, b) => b.mtime.getTime() - a.mtime.getTime()).slice(this.config.rotation.maxFiles);
903
+ for (const file of filesToDelete) await unlink(file.path);
904
+ } catch (error) {
905
+ internalError("Failed to cleanup old log files", error);
906
+ }
907
+ }
908
+ async close() {
909
+ await this.flush();
910
+ if (this.writeStream) return new Promise((resolve) => {
911
+ this.writeStream.end(() => resolve());
912
+ });
913
+ }
914
+ };
915
+
916
+ //#endregion
917
+ //#region src/transports/google-analytics.transport.ts
918
+ var GoogleAnalyticsTransport = class extends AnalyticsTransport {
919
+ constructor(config) {
920
+ super("google-analytics", config);
921
+ this.baseUrl = "https://www.google-analytics.com/mp/collect";
922
+ this.debugUrl = "https://www.google-analytics.com/debug/mp/collect";
923
+ this.gaConfig = config;
924
+ }
925
+ async initialize() {
926
+ try {
927
+ if (!this.gaConfig.measurementId) throw new Error("Google Analytics Measurement ID is required");
928
+ if (!this.gaConfig.apiSecret) throw new Error("Google Analytics API Secret is required");
929
+ await this.testConnection();
930
+ this.isReady = true;
931
+ } catch (error) {
932
+ internalError("Google Analytics transport initialization failed", error);
933
+ throw error;
934
+ }
935
+ }
936
+ async sendEntry(entry) {
937
+ const event = this.transformToGAEvent(entry);
938
+ await this.sendEvent(event);
939
+ }
940
+ async sendBatch(entries) {
941
+ const events = entries.map((entry) => this.transformToGAEvent(entry));
942
+ await this.sendEvents(events);
943
+ }
944
+ async cleanup() {}
945
+ transformToGAEvent(entry) {
946
+ const transformed = this.transformEntry(entry);
947
+ return {
948
+ name: "log_event",
949
+ params: {
950
+ event_category: this.mapLogLevelToCategory(entry.level),
951
+ event_label: entry.message,
952
+ log_level: entry.level,
953
+ log_message: entry.message,
954
+ timestamp: entry.timestamp.toISOString(),
955
+ ...entry.context && { context: entry.context },
956
+ ...entry.traceId && { trace_id: entry.traceId },
957
+ ...entry.appName && { app_name: entry.appName },
958
+ ...entry.environment && { environment: entry.environment },
959
+ ...this.flattenData(transformed),
960
+ custom_dimension_1: entry.level,
961
+ custom_dimension_2: entry.context || "default",
962
+ custom_dimension_3: entry.environment || "production"
963
+ }
964
+ };
965
+ }
966
+ mapLogLevelToCategory(level) {
967
+ return {
968
+ error: "Error",
969
+ warn: "Warning",
970
+ warning: "Warning",
971
+ info: "Information",
972
+ debug: "Debug",
973
+ trace: "Trace",
974
+ verbose: "Verbose"
975
+ }[level.toLowerCase()] || "Information";
976
+ }
977
+ flattenData(data, prefix = "") {
978
+ const flattened = {};
979
+ for (const [key, value] of Object.entries(data)) {
980
+ const newKey = prefix ? `${prefix}_${key}` : key;
981
+ if (value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date)) Object.assign(flattened, this.flattenData(value, newKey));
982
+ else {
983
+ const stringValue = String(value);
984
+ flattened[newKey] = stringValue.length > 100 ? stringValue.slice(0, 100) : stringValue;
985
+ }
986
+ }
987
+ return flattened;
988
+ }
989
+ async sendEvent(event) {
990
+ const payload = {
991
+ client_id: this.gaConfig.clientId || this.generateClientId(),
992
+ events: [event]
993
+ };
994
+ await this.makeRequest(payload);
995
+ }
996
+ async sendEvents(events) {
997
+ const chunks = this.chunkArray(events, 25);
998
+ for (const chunk of chunks) {
999
+ const payload = {
1000
+ client_id: this.gaConfig.clientId || this.generateClientId(),
1001
+ events: chunk
1002
+ };
1003
+ await this.makeRequest(payload);
1004
+ }
1005
+ }
1006
+ async makeRequest(payload, debug = false) {
1007
+ const url = debug ? this.debugUrl : this.baseUrl;
1008
+ const params = new URLSearchParams({
1009
+ measurement_id: this.gaConfig.measurementId,
1010
+ api_secret: this.gaConfig.apiSecret
1011
+ });
1012
+ try {
1013
+ const response = await fetch(`${url}?${params}`, {
1014
+ method: "POST",
1015
+ headers: { "Content-Type": "application/json" },
1016
+ body: JSON.stringify(payload)
1017
+ });
1018
+ if (!response.ok) {
1019
+ const errorText = await response.text();
1020
+ throw new Error(`Google Analytics API error: ${response.status} ${response.statusText} - ${errorText}`);
1021
+ }
1022
+ if (debug) {
1023
+ const result = await response.json();
1024
+ internalLog(`GA4 Debug Response: ${JSON.stringify(result)}`);
1025
+ }
1026
+ } catch (error) {
1027
+ throw new Error(`Failed to send data to Google Analytics: ${error.message}`, { cause: error });
1028
+ }
1029
+ }
1030
+ async testConnection() {
1031
+ const testEvent = {
1032
+ name: "logitron_test",
1033
+ params: {
1034
+ event_category: "Test",
1035
+ event_label: "Connection Test",
1036
+ test: true,
1037
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1038
+ }
1039
+ };
1040
+ const payload = {
1041
+ client_id: this.gaConfig.clientId || this.generateClientId(),
1042
+ events: [testEvent]
1043
+ };
1044
+ await this.makeRequest(payload, true);
1045
+ }
1046
+ generateClientId() {
1047
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1048
+ const r = Math.random() * 16 | 0;
1049
+ return (c === "x" ? r : r & 3 | 8).toString(16);
1050
+ });
1051
+ }
1052
+ chunkArray(array, size) {
1053
+ const chunks = [];
1054
+ for (let i = 0; i < array.length; i += size) chunks.push(array.slice(i, i + size));
1055
+ return chunks;
1056
+ }
1057
+ async trackPageView(pagePath, pageTitle) {
1058
+ const event = {
1059
+ name: "page_view",
1060
+ params: {
1061
+ page_location: pagePath,
1062
+ page_title: pageTitle || pagePath,
1063
+ engagement_time_msec: 1
1064
+ }
1065
+ };
1066
+ await this.sendEvent(event);
1067
+ }
1068
+ async trackCustomEvent(eventName, parameters = {}) {
1069
+ const event = {
1070
+ name: eventName.toLowerCase().replace(/[^a-z0-9_]/g, "_"),
1071
+ params: {
1072
+ ...this.flattenData(parameters),
1073
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1074
+ }
1075
+ };
1076
+ await this.sendEvent(event);
1077
+ }
1078
+ async trackConversion(conversionName, value, currency) {
1079
+ const event = {
1080
+ name: conversionName,
1081
+ params: {
1082
+ ...value !== void 0 && { value },
1083
+ ...currency && { currency },
1084
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1085
+ }
1086
+ };
1087
+ await this.sendEvent(event);
1088
+ }
1089
+ async trackError(errorMessage, errorCode, fatal = false) {
1090
+ const event = {
1091
+ name: "exception",
1092
+ params: {
1093
+ description: errorMessage,
1094
+ fatal,
1095
+ ...errorCode && { error_code: errorCode },
1096
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1097
+ }
1098
+ };
1099
+ await this.sendEvent(event);
1100
+ }
1101
+ async setUserProperties(properties) {
1102
+ const event = {
1103
+ name: "user_properties_update",
1104
+ params: {
1105
+ ...this.flattenData(properties),
1106
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1107
+ }
1108
+ };
1109
+ await this.sendEvent(event);
1110
+ }
1111
+ async trackFileDownload(fileName, fileExtension) {
1112
+ if (!this.gaConfig.enableEnhancedMeasurement) return;
1113
+ const event = {
1114
+ name: "file_download",
1115
+ params: {
1116
+ file_name: fileName,
1117
+ file_extension: fileExtension,
1118
+ link_url: fileName,
1119
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1120
+ }
1121
+ };
1122
+ await this.sendEvent(event);
1123
+ }
1124
+ async trackVideoEngagement(videoTitle, videoUrl, progress) {
1125
+ if (!this.gaConfig.enableEnhancedMeasurement) return;
1126
+ const event = {
1127
+ name: "video_progress",
1128
+ params: {
1129
+ video_title: videoTitle,
1130
+ video_url: videoUrl,
1131
+ video_progress: progress,
1132
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1133
+ }
1134
+ };
1135
+ await this.sendEvent(event);
1136
+ }
1137
+ };
1138
+
1139
+ //#endregion
1140
+ //#region src/transports/mixpanel.transport.ts
1141
+ var MixpanelTransport = class extends AnalyticsTransport {
1142
+ constructor(config) {
1143
+ super("mixpanel", config);
1144
+ this.baseUrl = "https://api.mixpanel.com";
1145
+ this.mixpanelConfig = config;
1146
+ }
1147
+ async initialize() {
1148
+ try {
1149
+ if (!this.mixpanelConfig.token) throw new Error("Mixpanel token is required");
1150
+ await this.testConnection();
1151
+ this.isReady = true;
1152
+ } catch (error) {
1153
+ internalError("Mixpanel transport initialization failed", error);
1154
+ throw error;
1155
+ }
1156
+ }
1157
+ async sendEntry(entry) {
1158
+ const event = this.transformToMixpanelEvent(entry);
1159
+ await this.trackEvent(event);
1160
+ }
1161
+ async sendBatch(entries) {
1162
+ const events = entries.map((entry) => this.transformToMixpanelEvent(entry));
1163
+ await this.trackEvents(events);
1164
+ }
1165
+ async cleanup() {}
1166
+ transformToMixpanelEvent(entry) {
1167
+ const transformed = this.transformEntry(entry);
1168
+ return {
1169
+ name: `log_${entry.level}`,
1170
+ properties: {
1171
+ ...transformed,
1172
+ distinct_id: this.mixpanelConfig.distinct_id || "anonymous",
1173
+ time: entry.timestamp.getTime(),
1174
+ $insert_id: this.generateInsertId(entry),
1175
+ ...this.mixpanelConfig.enableSuperProperties ? this.mixpanelConfig.superProperties : {}
1176
+ },
1177
+ timestamp: entry.timestamp
1178
+ };
1179
+ }
1180
+ async trackEvent(event) {
1181
+ const payload = {
1182
+ event: event.name,
1183
+ properties: {
1184
+ token: this.mixpanelConfig.token,
1185
+ ...event.properties
1186
+ }
1187
+ };
1188
+ await this.makeRequest("/track", [payload]);
1189
+ }
1190
+ async trackEvents(events) {
1191
+ const payload = events.map((event) => ({
1192
+ event: event.name,
1193
+ properties: {
1194
+ token: this.mixpanelConfig.token,
1195
+ ...event.properties
1196
+ }
1197
+ }));
1198
+ await this.makeRequest("/track", payload);
1199
+ }
1200
+ async makeRequest(endpoint, data) {
1201
+ const url = `${this.mixpanelConfig.endpoint || this.baseUrl}${endpoint}`;
1202
+ try {
1203
+ const response = await fetch(url, {
1204
+ method: "POST",
1205
+ headers: {
1206
+ "Content-Type": "application/json",
1207
+ Accept: "text/plain"
1208
+ },
1209
+ body: JSON.stringify(data)
1210
+ });
1211
+ if (!response.ok) throw new Error(`Mixpanel API error: ${response.status} ${response.statusText}`);
1212
+ const result = await response.text();
1213
+ if (result !== "1") throw new Error(`Mixpanel API returned error: ${result}`);
1214
+ } catch (error) {
1215
+ throw new Error(`Failed to send data to Mixpanel: ${error.message}`, { cause: error });
1216
+ }
1217
+ }
1218
+ async testConnection() {
1219
+ const testEvent = {
1220
+ event: "logitron_test",
1221
+ properties: {
1222
+ token: this.mixpanelConfig.token,
1223
+ distinct_id: "test_user",
1224
+ test: true,
1225
+ time: Date.now()
1226
+ }
1227
+ };
1228
+ await this.makeRequest("/track", [testEvent]);
1229
+ }
1230
+ generateInsertId(entry) {
1231
+ return `${entry.timestamp.getTime()}_${this.simpleHash(entry.message + (entry.traceId || ""))}`;
1232
+ }
1233
+ simpleHash(str) {
1234
+ let hash = 0;
1235
+ for (let i = 0; i < str.length; i++) {
1236
+ const char = str.charCodeAt(i);
1237
+ hash = (hash << 5) - hash + char;
1238
+ hash = hash & hash;
1239
+ }
1240
+ return Math.abs(hash).toString(36);
1241
+ }
1242
+ async identifyUser(user) {
1243
+ if (!this.mixpanelConfig.enableUserTracking) return;
1244
+ const payload = {
1245
+ $token: this.mixpanelConfig.token,
1246
+ $distinct_id: user.id,
1247
+ $set: user.properties || {}
1248
+ };
1249
+ await this.makeRequest("/engage", [payload]);
1250
+ }
1251
+ async setUserProperties(userId, properties) {
1252
+ if (!this.mixpanelConfig.enableUserTracking) return;
1253
+ const payload = {
1254
+ $token: this.mixpanelConfig.token,
1255
+ $distinct_id: userId,
1256
+ $set: properties
1257
+ };
1258
+ await this.makeRequest("/engage", [payload]);
1259
+ }
1260
+ async trackCustomEvent(eventName, properties = {}) {
1261
+ if (!this.mixpanelConfig.enableEventTracking) return;
1262
+ const payload = {
1263
+ event: eventName,
1264
+ properties: {
1265
+ token: this.mixpanelConfig.token,
1266
+ distinct_id: this.mixpanelConfig.distinct_id || "anonymous",
1267
+ time: Date.now(),
1268
+ ...properties,
1269
+ ...this.mixpanelConfig.enableSuperProperties ? this.mixpanelConfig.superProperties : {}
1270
+ }
1271
+ };
1272
+ await this.makeRequest("/track", [payload]);
1273
+ }
1274
+ };
1275
+
1276
+ //#endregion
1277
+ //#region src/transports/segment.transport.ts
1278
+ var SegmentTransport = class extends AnalyticsTransport {
1279
+ constructor(config) {
1280
+ super("segment", config);
1281
+ this.segmentConfig = {
1282
+ enableBatching: true,
1283
+ maxBatchSize: 100,
1284
+ flushAt: 20,
1285
+ flushInterval: 1e4,
1286
+ ...config
1287
+ };
1288
+ this.baseUrl = config.dataPlaneUrl || "https://api.segment.io";
1289
+ }
1290
+ async initialize() {
1291
+ try {
1292
+ if (!this.segmentConfig.writeKey) throw new Error("Segment Write Key is required");
1293
+ await this.testConnection();
1294
+ this.isReady = true;
1295
+ } catch (error) {
1296
+ internalError("Segment transport initialization failed", error);
1297
+ throw error;
1298
+ }
1299
+ }
1300
+ async sendEntry(entry) {
1301
+ const segmentEvent = this.transformToSegmentEvent(entry);
1302
+ await this.track(segmentEvent);
1303
+ }
1304
+ async sendBatch(entries) {
1305
+ if (!this.segmentConfig.enableBatching) {
1306
+ for (const entry of entries) await this.sendEntry(entry);
1307
+ return;
1308
+ }
1309
+ const segmentEvents = entries.map((entry) => this.transformToSegmentEvent(entry));
1310
+ await this.batchTrack(segmentEvents);
1311
+ }
1312
+ async cleanup() {}
1313
+ transformToSegmentEvent(entry) {
1314
+ const transformed = this.transformEntry(entry);
1315
+ return {
1316
+ type: "track",
1317
+ event: `Log ${entry.level.charAt(0).toUpperCase() + entry.level.slice(1)}`,
1318
+ userId: this.extractUserId(entry),
1319
+ anonymousId: this.generateAnonymousId(),
1320
+ timestamp: entry.timestamp.toISOString(),
1321
+ properties: {
1322
+ level: entry.level,
1323
+ message: entry.message,
1324
+ logger: "logixia",
1325
+ ...transformed,
1326
+ ...entry.context && { context: entry.context },
1327
+ ...entry.traceId && { traceId: entry.traceId },
1328
+ ...entry.appName && { appName: entry.appName },
1329
+ ...entry.environment && { environment: entry.environment }
1330
+ },
1331
+ context: {
1332
+ library: {
1333
+ name: "logixia",
1334
+ version: "1.0.0"
1335
+ },
1336
+ app: {
1337
+ name: entry.appName || "unknown",
1338
+ version: "1.0.0",
1339
+ environment: entry.environment || "production"
1340
+ },
1341
+ ...entry.traceId && { trace: { trace_id: entry.traceId } }
1342
+ },
1343
+ integrations: {
1344
+ All: false,
1345
+ "Segment.io": true
1346
+ }
1347
+ };
1348
+ }
1349
+ async track(event) {
1350
+ await this.makeRequest("/v1/track", event);
1351
+ }
1352
+ async batchTrack(events) {
1353
+ const chunks = this.chunkArray(events, this.segmentConfig.maxBatchSize || 100);
1354
+ for (const chunk of chunks) {
1355
+ const payload = { batch: chunk };
1356
+ await this.makeRequest("/v1/batch", payload);
1357
+ }
1358
+ }
1359
+ async makeRequest(endpoint, data) {
1360
+ const url = `${this.baseUrl}${endpoint}`;
1361
+ const auth = Buffer.from(`${this.segmentConfig.writeKey}:`).toString("base64");
1362
+ try {
1363
+ const response = await fetch(url, {
1364
+ method: "POST",
1365
+ headers: {
1366
+ "Content-Type": "application/json",
1367
+ Authorization: `Basic ${auth}`,
1368
+ "User-Agent": "logixia/1.0.0"
1369
+ },
1370
+ body: JSON.stringify(data)
1371
+ });
1372
+ if (!response.ok) {
1373
+ const errorText = await response.text();
1374
+ throw new Error(`Segment API error: ${response.status} ${response.statusText} - ${errorText}`);
1375
+ }
1376
+ } catch (error) {
1377
+ throw new Error(`Failed to send data to Segment: ${error.message}`, { cause: error });
1378
+ }
1379
+ }
1380
+ async testConnection() {
1381
+ const testEvent = {
1382
+ type: "track",
1383
+ event: "Logixia Test",
1384
+ userId: "test-user",
1385
+ anonymousId: this.generateAnonymousId(),
1386
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1387
+ properties: {
1388
+ test: true,
1389
+ source: "logixia"
1390
+ },
1391
+ context: { library: {
1392
+ name: "logixia",
1393
+ version: "1.0.0"
1394
+ } }
1395
+ };
1396
+ await this.makeRequest("/v1/track", testEvent);
1397
+ }
1398
+ extractUserId(entry) {
1399
+ if (entry.data) {
1400
+ const d = entry.data;
1401
+ const id = d["userId"] ?? d["user_id"] ?? d["id"];
1402
+ return typeof id === "string" ? id : void 0;
1403
+ }
1404
+ }
1405
+ generateAnonymousId() {
1406
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
1407
+ const r = Math.random() * 16 | 0;
1408
+ return (c === "x" ? r : r & 3 | 8).toString(16);
1409
+ });
1410
+ }
1411
+ chunkArray(array, size) {
1412
+ const chunks = [];
1413
+ for (let i = 0; i < array.length; i += size) chunks.push(array.slice(i, i + size));
1414
+ return chunks;
1415
+ }
1416
+ async identify(user) {
1417
+ const payload = {
1418
+ type: "identify",
1419
+ userId: user.id,
1420
+ anonymousId: this.generateAnonymousId(),
1421
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1422
+ traits: {
1423
+ ...user.properties,
1424
+ ...user.traits
1425
+ },
1426
+ context: { library: {
1427
+ name: "logitron",
1428
+ version: "1.0.0"
1429
+ } }
1430
+ };
1431
+ await this.makeRequest("/v1/identify", payload);
1432
+ }
1433
+ async page(name, properties = {}) {
1434
+ const payload = {
1435
+ type: "page",
1436
+ name,
1437
+ anonymousId: this.generateAnonymousId(),
1438
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1439
+ properties: {
1440
+ ...properties,
1441
+ url: properties.url || `/${name.toLowerCase().replace(/\s+/g, "-")}`,
1442
+ title: properties.title || name
1443
+ },
1444
+ context: {
1445
+ library: {
1446
+ name: "logitron",
1447
+ version: "1.0.0"
1448
+ },
1449
+ page: {
1450
+ url: properties.url || `/${name.toLowerCase().replace(/\s+/g, "-")}`,
1451
+ title: properties.title || name
1452
+ }
1453
+ }
1454
+ };
1455
+ await this.makeRequest("/v1/page", payload);
1456
+ }
1457
+ async screen(name, properties = {}) {
1458
+ const payload = {
1459
+ type: "screen",
1460
+ name,
1461
+ anonymousId: this.generateAnonymousId(),
1462
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1463
+ properties: { ...properties },
1464
+ context: {
1465
+ library: {
1466
+ name: "logitron",
1467
+ version: "1.0.0"
1468
+ },
1469
+ screen: { name }
1470
+ }
1471
+ };
1472
+ await this.makeRequest("/v1/screen", payload);
1473
+ }
1474
+ async group(groupId, traits = {}, userId) {
1475
+ const payload = {
1476
+ type: "group",
1477
+ groupId,
1478
+ userId,
1479
+ anonymousId: this.generateAnonymousId(),
1480
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1481
+ traits,
1482
+ context: { library: {
1483
+ name: "logitron",
1484
+ version: "1.0.0"
1485
+ } }
1486
+ };
1487
+ await this.makeRequest("/v1/group", payload);
1488
+ }
1489
+ async alias(userId, previousId) {
1490
+ const payload = {
1491
+ type: "alias",
1492
+ userId,
1493
+ previousId,
1494
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1495
+ context: { library: {
1496
+ name: "logitron",
1497
+ version: "1.0.0"
1498
+ } }
1499
+ };
1500
+ await this.makeRequest("/v1/alias", payload);
1501
+ }
1502
+ async trackCustomEvent(eventName, properties = {}, userId) {
1503
+ const payload = {
1504
+ type: "track",
1505
+ event: eventName,
1506
+ userId,
1507
+ anonymousId: this.generateAnonymousId(),
1508
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1509
+ properties,
1510
+ context: { library: {
1511
+ name: "logitron",
1512
+ version: "1.0.0"
1513
+ } }
1514
+ };
1515
+ await this.makeRequest("/v1/track", payload);
1516
+ }
1517
+ async trackPurchase(orderId, products, revenue, currency = "USD") {
1518
+ const payload = {
1519
+ type: "track",
1520
+ event: "Order Completed",
1521
+ anonymousId: this.generateAnonymousId(),
1522
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1523
+ properties: {
1524
+ orderId,
1525
+ revenue,
1526
+ currency,
1527
+ products
1528
+ },
1529
+ context: { library: {
1530
+ name: "logitron",
1531
+ version: "1.0.0"
1532
+ } }
1533
+ };
1534
+ await this.makeRequest("/v1/track", payload);
1535
+ }
1536
+ async trackProductViewed(product) {
1537
+ const payload = {
1538
+ type: "track",
1539
+ event: "Product Viewed",
1540
+ anonymousId: this.generateAnonymousId(),
1541
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1542
+ properties: product,
1543
+ context: { library: {
1544
+ name: "logitron",
1545
+ version: "1.0.0"
1546
+ } }
1547
+ };
1548
+ await this.makeRequest("/v1/track", payload);
1549
+ }
1550
+ };
1551
+
1552
+ //#endregion
1553
+ //#region src/transports/transport.manager.ts
1554
+ var TransportManager = class extends node_events.EventEmitter {
1555
+ constructor(config = {}) {
1556
+ super();
1557
+ this.transports = /* @__PURE__ */ new Map();
1558
+ this.metrics = /* @__PURE__ */ new Map();
1559
+ this.isShuttingDown = false;
1560
+ this.transportLevelPreferences = /* @__PURE__ */ new Map();
1561
+ this.promptForLevels = false;
1562
+ this.setupTransports(config);
1563
+ }
1564
+ setupTransports(config) {
1565
+ if (config.console) {
1566
+ const consoleTransport = new ConsoleTransport(typeof config.console === "object" ? config.console : {});
1567
+ this.addTransport(consoleTransport, "console");
1568
+ }
1569
+ if (config.file) {
1570
+ const fileConfigs = Array.isArray(config.file) ? config.file : [config.file];
1571
+ for (const [index, fileConfig] of fileConfigs.entries()) {
1572
+ const fileTransport = new FileTransport(fileConfig);
1573
+ this.addTransport(fileTransport, `file-${index}`);
1574
+ }
1575
+ }
1576
+ if (config.database) {
1577
+ const dbConfigs = Array.isArray(config.database) ? config.database : [config.database];
1578
+ for (const [index, dbConfig] of dbConfigs.entries()) {
1579
+ const dbTransport = new DatabaseTransport(dbConfig);
1580
+ this.addTransport(dbTransport, `database-${index}`);
1581
+ }
1582
+ }
1583
+ if (config.analytics) {
1584
+ if (config.analytics.mixpanel) {
1585
+ const mixpanelConfigs = Array.isArray(config.analytics.mixpanel) ? config.analytics.mixpanel : [config.analytics.mixpanel];
1586
+ for (const [index, mixpanelConfig] of mixpanelConfigs.entries()) {
1587
+ const mixpanelTransport = new MixpanelTransport(mixpanelConfig);
1588
+ this.addTransport(mixpanelTransport, `mixpanel-${index}`);
1589
+ }
1590
+ }
1591
+ if (config.analytics.datadog) {
1592
+ const datadogConfigs = Array.isArray(config.analytics.datadog) ? config.analytics.datadog : [config.analytics.datadog];
1593
+ for (const [index, datadogConfig] of datadogConfigs.entries()) {
1594
+ const datadogTransport = new DataDogTransport(datadogConfig);
1595
+ this.addTransport(datadogTransport, `datadog-${index}`);
1596
+ }
1597
+ }
1598
+ if (config.analytics.googleAnalytics) {
1599
+ const gaConfigs = Array.isArray(config.analytics.googleAnalytics) ? config.analytics.googleAnalytics : [config.analytics.googleAnalytics];
1600
+ for (const [index, gaConfig] of gaConfigs.entries()) {
1601
+ const gaTransport = new GoogleAnalyticsTransport(gaConfig);
1602
+ this.addTransport(gaTransport, `google-analytics-${index}`);
1603
+ }
1604
+ }
1605
+ if (config.analytics.segment) {
1606
+ const segmentConfigs = Array.isArray(config.analytics.segment) ? config.analytics.segment : [config.analytics.segment];
1607
+ for (const [index, segmentConfig] of segmentConfigs.entries()) {
1608
+ const segmentTransport = new SegmentTransport(segmentConfig);
1609
+ this.addTransport(segmentTransport, `segment-${index}`);
1610
+ }
1611
+ }
1612
+ }
1613
+ if (config.custom) for (const [index, transport] of config.custom.entries()) this.addTransport(transport, `custom-${index}`);
1614
+ }
1615
+ addTransport(transport, id) {
1616
+ const transportId = id || `${transport.name}-${Date.now()}`;
1617
+ this.transports.set(transportId, transport);
1618
+ this.metrics.set(transportId, {
1619
+ name: transportId,
1620
+ type: this.getTransportType(transport),
1621
+ logsWritten: 0,
1622
+ errors: 0,
1623
+ lastWrite: /* @__PURE__ */ new Date(),
1624
+ averageWriteTime: 0
1625
+ });
1626
+ this.emit("transport:added", transportId, transport);
1627
+ }
1628
+ removeTransport(id) {
1629
+ const transport = this.transports.get(id);
1630
+ if (!transport) return false;
1631
+ this.transports.delete(id);
1632
+ this.metrics.delete(id);
1633
+ if (transport.close) transport.close().catch((error) => {
1634
+ this.emit("error", error, id);
1635
+ });
1636
+ this.emit("transport:removed", id);
1637
+ return true;
1638
+ }
1639
+ async write(entry) {
1640
+ const transportEntry = {
1641
+ timestamp: new Date(entry.timestamp),
1642
+ level: entry.level,
1643
+ message: entry.message,
1644
+ appName: entry.appName
1645
+ };
1646
+ if (entry.payload !== void 0) transportEntry.data = entry.payload;
1647
+ if (entry.context !== void 0) transportEntry.context = entry.context;
1648
+ if (entry.traceId !== void 0) transportEntry.traceId = entry.traceId;
1649
+ if (entry.environment !== void 0) transportEntry.environment = entry.environment;
1650
+ if (this.isShuttingDown) throw new Error("TransportManager is shutting down");
1651
+ const writePromises = [];
1652
+ for (const [id, transport] of this.transports) {
1653
+ if (this.promptForLevels && !this.transportLevelPreferences.has(id)) await this.configureTransportLevels(id);
1654
+ if (!this.shouldTransportHandle(transport, transportEntry.level, id)) continue;
1655
+ const writePromise = this.writeToTransport(id, transport, transportEntry);
1656
+ writePromises.push(writePromise);
1657
+ }
1658
+ const failures = (await Promise.allSettled(writePromises)).filter((result) => result.status === "rejected");
1659
+ if (failures.length > 0) {
1660
+ const errors = failures.map((failure) => failure.reason);
1661
+ this.emit("error", /* @__PURE__ */ new Error(`Transport write failures: ${errors.join(", ")}`), "multiple");
1662
+ }
1663
+ }
1664
+ async writeToTransport(id, transport, entry) {
1665
+ const startTime = Date.now();
1666
+ const metrics = this.metrics.get(id);
1667
+ try {
1668
+ await transport.write(entry);
1669
+ const writeTime = Date.now() - startTime;
1670
+ metrics.logsWritten++;
1671
+ metrics.lastWrite = new Date(startTime);
1672
+ metrics.averageWriteTime = (metrics.averageWriteTime + writeTime) / 2;
1673
+ this.emit("log", entry);
1674
+ } catch (error) {
1675
+ metrics.errors++;
1676
+ this.emit("error", error, id);
1677
+ throw error;
1678
+ }
1679
+ }
1680
+ shouldTransportHandle(transport, level, transportId) {
1681
+ if (transportId && this.transportLevelPreferences.has(transportId)) return this.transportLevelPreferences.get(transportId).includes(level.toLowerCase());
1682
+ if (!transport.level) return true;
1683
+ const levels = [
1684
+ "error",
1685
+ "warn",
1686
+ "info",
1687
+ "debug",
1688
+ "trace",
1689
+ "verbose"
1690
+ ];
1691
+ const transportLevelIndex = levels.indexOf(transport.level.toLowerCase());
1692
+ const entryLevelIndex = levels.indexOf(level.toLowerCase());
1693
+ if (transportLevelIndex === -1 || entryLevelIndex === -1) return true;
1694
+ return entryLevelIndex <= transportLevelIndex;
1695
+ }
1696
+ getTransportType(transport) {
1697
+ if (transport.name === "console") return "console";
1698
+ if (transport.name === "file") return "file";
1699
+ if (transport.name === "database") return "database";
1700
+ if (transport.name === "mixpanel" || transport.name === "datadog" || transport.name === "google-analytics" || transport.name === "segment") return "analytics";
1701
+ return "custom";
1702
+ }
1703
+ async waitForReady() {
1704
+ const readyPromises = [];
1705
+ for (const transport of this.transports.values()) if (this.isAsyncTransport(transport)) readyPromises.push(transport.isReady());
1706
+ if (readyPromises.length > 0) await Promise.all(readyPromises);
1707
+ }
1708
+ async flush() {
1709
+ const flushPromises = [];
1710
+ for (const [id, transport] of this.transports) if (this.isBatchTransport(transport)) {
1711
+ const flushPromise = transport.flush().catch((error) => {
1712
+ this.emit("error", error, id);
1713
+ });
1714
+ flushPromises.push(flushPromise);
1715
+ }
1716
+ await Promise.allSettled(flushPromises);
1717
+ this.emit("flush", "all", this.transports.size);
1718
+ }
1719
+ async close() {
1720
+ this.isShuttingDown = true;
1721
+ await this.flush();
1722
+ const closePromises = [];
1723
+ for (const [id, transport] of this.transports) if (transport.close) {
1724
+ const closePromise = transport.close().catch((error) => {
1725
+ this.emit("error", error, id);
1726
+ });
1727
+ closePromises.push(closePromise);
1728
+ }
1729
+ await Promise.allSettled(closePromises);
1730
+ this.transports.clear();
1731
+ this.metrics.clear();
1732
+ this.removeAllListeners();
1733
+ }
1734
+ getTransports() {
1735
+ return Array.from(this.transports.keys());
1736
+ }
1737
+ getTransport(id) {
1738
+ return this.transports.get(id);
1739
+ }
1740
+ getMetrics() {
1741
+ return Array.from(this.metrics.values());
1742
+ }
1743
+ getMetricsForTransport(id) {
1744
+ return this.metrics.get(id);
1745
+ }
1746
+ isTransportReady(id) {
1747
+ const transport = this.transports.get(id);
1748
+ if (!transport) return Promise.resolve(false);
1749
+ if (this.isAsyncTransport(transport)) return transport.isReady();
1750
+ return Promise.resolve(true);
1751
+ }
1752
+ isAsyncTransport(transport) {
1753
+ return "isReady" in transport && typeof transport.isReady === "function";
1754
+ }
1755
+ isBatchTransport(transport) {
1756
+ return "flush" in transport && typeof transport.flush === "function";
1757
+ }
1758
+ onLog(callback) {
1759
+ this.on("log", callback);
1760
+ }
1761
+ onError(callback) {
1762
+ this.on("error", callback);
1763
+ }
1764
+ onFlush(callback) {
1765
+ this.on("flush", callback);
1766
+ }
1767
+ onTransportAdded(callback) {
1768
+ this.on("transport:added", callback);
1769
+ }
1770
+ onTransportRemoved(callback) {
1771
+ this.on("transport:removed", callback);
1772
+ }
1773
+ async healthCheck() {
1774
+ const details = {};
1775
+ let healthy = true;
1776
+ for (const [id] of this.transports) try {
1777
+ const isReady = await this.isTransportReady(id);
1778
+ details[id] = {
1779
+ ready: isReady,
1780
+ metrics: this.metrics.get(id)
1781
+ };
1782
+ if (!isReady) healthy = false;
1783
+ } catch (error) {
1784
+ details[id] = { error: error instanceof Error ? error.message : "Unknown error" };
1785
+ healthy = false;
1786
+ }
1787
+ return {
1788
+ healthy,
1789
+ details
1790
+ };
1791
+ }
1792
+ enableLevelPrompting() {
1793
+ this.promptForLevels = true;
1794
+ internalLog("Transport level prompting enabled");
1795
+ }
1796
+ disableLevelPrompting() {
1797
+ this.promptForLevels = false;
1798
+ internalLog("Transport level prompting disabled");
1799
+ }
1800
+ async promptUserForTransportLevels(transportId) {
1801
+ const availableLevels = [
1802
+ "error",
1803
+ "warn",
1804
+ "info",
1805
+ "debug",
1806
+ "trace",
1807
+ "verbose"
1808
+ ];
1809
+ return new Promise((resolve) => {
1810
+ const rl = node_readline.createInterface({
1811
+ input: process.stdin,
1812
+ output: process.stdout
1813
+ });
1814
+ process.stdout.write(`\nConfigure log levels for transport '${transportId}'\n`);
1815
+ process.stdout.write(`Available levels: ${availableLevels.join(", ")}\n`);
1816
+ process.stdout.write("Enter levels separated by commas (e.g., error,warn,info) or \"all\" for all levels:\n");
1817
+ rl.question("> ", (answer) => {
1818
+ rl.close();
1819
+ if (answer.toLowerCase().trim() === "all") resolve(availableLevels);
1820
+ else {
1821
+ const selectedLevels = answer.split(",").map((level) => level.trim().toLowerCase()).filter((level) => availableLevels.includes(level));
1822
+ if (selectedLevels.length === 0) {
1823
+ internalWarn("No valid levels selected, using all levels");
1824
+ resolve(availableLevels);
1825
+ } else {
1826
+ internalLog(`Selected levels for ${transportId}: ${selectedLevels.join(", ")}`);
1827
+ resolve(selectedLevels);
1828
+ }
1829
+ }
1830
+ });
1831
+ });
1832
+ }
1833
+ async configureTransportLevels(transportId) {
1834
+ if (this.promptForLevels && !this.transportLevelPreferences.has(transportId)) {
1835
+ const selectedLevels = await this.promptUserForTransportLevels(transportId);
1836
+ this.transportLevelPreferences.set(transportId, selectedLevels);
1837
+ }
1838
+ }
1839
+ setTransportLevels(transportId, levels) {
1840
+ this.transportLevelPreferences.set(transportId, levels);
1841
+ internalLog(`Transport '${transportId}' configured for levels: ${levels.join(", ")}`);
1842
+ }
1843
+ getTransportLevels(transportId) {
1844
+ return this.transportLevelPreferences.get(transportId);
1845
+ }
1846
+ clearTransportLevelPreferences() {
1847
+ this.transportLevelPreferences.clear();
1848
+ internalLog("Transport level preferences cleared");
1849
+ }
1850
+ };
1851
+
1852
+ //#endregion
1853
+ Object.defineProperty(exports, 'AnalyticsTransport', {
1854
+ enumerable: true,
1855
+ get: function () {
1856
+ return AnalyticsTransport;
1857
+ }
1858
+ });
1859
+ Object.defineProperty(exports, 'ConsoleTransport', {
1860
+ enumerable: true,
1861
+ get: function () {
1862
+ return ConsoleTransport;
1863
+ }
1864
+ });
1865
+ Object.defineProperty(exports, 'DataDogTransport', {
1866
+ enumerable: true,
1867
+ get: function () {
1868
+ return DataDogTransport;
1869
+ }
1870
+ });
1871
+ Object.defineProperty(exports, 'DatabaseTransport', {
1872
+ enumerable: true,
1873
+ get: function () {
1874
+ return DatabaseTransport;
1875
+ }
1876
+ });
1877
+ Object.defineProperty(exports, 'FileTransport', {
1878
+ enumerable: true,
1879
+ get: function () {
1880
+ return FileTransport;
1881
+ }
1882
+ });
1883
+ Object.defineProperty(exports, 'GoogleAnalyticsTransport', {
1884
+ enumerable: true,
1885
+ get: function () {
1886
+ return GoogleAnalyticsTransport;
1887
+ }
1888
+ });
1889
+ Object.defineProperty(exports, 'MixpanelTransport', {
1890
+ enumerable: true,
1891
+ get: function () {
1892
+ return MixpanelTransport;
1893
+ }
1894
+ });
1895
+ Object.defineProperty(exports, 'SegmentTransport', {
1896
+ enumerable: true,
1897
+ get: function () {
1898
+ return SegmentTransport;
1899
+ }
1900
+ });
1901
+ Object.defineProperty(exports, 'TransportManager', {
1902
+ enumerable: true,
1903
+ get: function () {
1904
+ return TransportManager;
1905
+ }
1906
+ });
1907
+ Object.defineProperty(exports, 'internalError', {
1908
+ enumerable: true,
1909
+ get: function () {
1910
+ return internalError;
1911
+ }
1912
+ });
1913
+ Object.defineProperty(exports, 'internalLog', {
1914
+ enumerable: true,
1915
+ get: function () {
1916
+ return internalLog;
1917
+ }
1918
+ });
1919
+ Object.defineProperty(exports, 'internalWarn', {
1920
+ enumerable: true,
1921
+ get: function () {
1922
+ return internalWarn;
1923
+ }
1924
+ });
1925
+ //# sourceMappingURL=transport.manager-C3Xr7Tvi.js.map