speexjs-core 0.7.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 (78) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/CONTRIBUTING.md +55 -0
  3. package/PUBLISH.md +45 -0
  4. package/README.md +174 -0
  5. package/ROADMAP.md +72 -0
  6. package/SECURITY.md +35 -0
  7. package/SUMMARY.md +321 -0
  8. package/dist/async/index.d.ts +232 -0
  9. package/dist/async/index.js +366 -0
  10. package/dist/async/index.js.map +1 -0
  11. package/dist/collection/index.d.ts +230 -0
  12. package/dist/collection/index.js +375 -0
  13. package/dist/collection/index.js.map +1 -0
  14. package/dist/color/index.d.ts +128 -0
  15. package/dist/color/index.js +167 -0
  16. package/dist/color/index.js.map +1 -0
  17. package/dist/core/index.d.ts +119 -0
  18. package/dist/core/index.js +324 -0
  19. package/dist/core/index.js.map +1 -0
  20. package/dist/crypto/index.d.ts +84 -0
  21. package/dist/crypto/index.js +144 -0
  22. package/dist/crypto/index.js.map +1 -0
  23. package/dist/date/index.d.ts +588 -0
  24. package/dist/date/index.js +737 -0
  25. package/dist/date/index.js.map +1 -0
  26. package/dist/dep-exray/analyzer/index.d.ts +7 -0
  27. package/dist/dep-exray/analyzer/index.js +68 -0
  28. package/dist/dep-exray/analyzer/index.js.map +1 -0
  29. package/dist/dep-exray/cli.d.ts +1 -0
  30. package/dist/dep-exray/cli.js +441 -0
  31. package/dist/dep-exray/cli.js.map +1 -0
  32. package/dist/dep-exray/index.d.ts +5 -0
  33. package/dist/dep-exray/index.js +454 -0
  34. package/dist/dep-exray/index.js.map +1 -0
  35. package/dist/dep-exray/known-mappings.d.ts +17 -0
  36. package/dist/dep-exray/known-mappings.js +122 -0
  37. package/dist/dep-exray/known-mappings.js.map +1 -0
  38. package/dist/dep-exray/reporter/index.d.ts +5 -0
  39. package/dist/dep-exray/reporter/index.js +89 -0
  40. package/dist/dep-exray/reporter/index.js.map +1 -0
  41. package/dist/dep-exray/scanner/index.d.ts +5 -0
  42. package/dist/dep-exray/scanner/index.js +299 -0
  43. package/dist/dep-exray/scanner/index.js.map +1 -0
  44. package/dist/dep-exray/types.d.ts +38 -0
  45. package/dist/dep-exray/types.js +1 -0
  46. package/dist/dep-exray/types.js.map +1 -0
  47. package/dist/error/index.d.ts +148 -0
  48. package/dist/error/index.js +115 -0
  49. package/dist/error/index.js.map +1 -0
  50. package/dist/index-BgG21uJC.d.ts +166 -0
  51. package/dist/index.d.ts +19 -0
  52. package/dist/index.js +4378 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/io/index.d.ts +39 -0
  55. package/dist/io/index.js +111 -0
  56. package/dist/io/index.js.map +1 -0
  57. package/dist/logger/index.d.ts +1 -0
  58. package/dist/logger/index.js +214 -0
  59. package/dist/logger/index.js.map +1 -0
  60. package/dist/logger/transports.d.ts +1 -0
  61. package/dist/logger/transports.js +122 -0
  62. package/dist/logger/transports.js.map +1 -0
  63. package/dist/math/index.d.ts +362 -0
  64. package/dist/math/index.js +372 -0
  65. package/dist/math/index.js.map +1 -0
  66. package/dist/path/index.d.ts +81 -0
  67. package/dist/path/index.js +134 -0
  68. package/dist/path/index.js.map +1 -0
  69. package/dist/string/index.d.ts +234 -0
  70. package/dist/string/index.js +411 -0
  71. package/dist/string/index.js.map +1 -0
  72. package/dist/type/index.d.ts +85 -0
  73. package/dist/type/index.js +107 -0
  74. package/dist/type/index.js.map +1 -0
  75. package/dist/validation/index.d.ts +203 -0
  76. package/dist/validation/index.js +402 -0
  77. package/dist/validation/index.js.map +1 -0
  78. package/package.json +172 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Options for CSV parsing.
3
+ */
4
+ interface CsvOptions {
5
+ delimiter?: string;
6
+ header?: boolean;
7
+ skipEmptyLines?: boolean;
8
+ }
9
+ /**
10
+ * Parses a CSV string into an array of records (objects).
11
+ *
12
+ * @param input - CSV string
13
+ * @param options - Optional parsing options
14
+ */
15
+ declare function parseCsv(input: string, options?: CsvOptions): Record<string, string>[];
16
+ /**
17
+ * Converts an array of records to a CSV string.
18
+ */
19
+ declare function stringifyCsv(data: Record<string, unknown>[], options?: {
20
+ delimiter?: string;
21
+ }): string;
22
+ /**
23
+ * Safely parses a JSON string, returning the default value or null on failure.
24
+ */
25
+ declare function safeJsonParse<T>(input: string, default_?: T): T | null;
26
+ /**
27
+ * Reads an environment variable with optional default.
28
+ */
29
+ declare function env(name: string, default_?: string): string;
30
+ /**
31
+ * Reads an environment variable as an integer.
32
+ */
33
+ declare function envInt(name: string, default_?: number): number;
34
+ /**
35
+ * Reads an environment variable as a boolean.
36
+ */
37
+ declare function envBool(name: string, default_?: boolean): boolean;
38
+
39
+ export { type CsvOptions, env, envBool, envInt, parseCsv, safeJsonParse, stringifyCsv };
@@ -0,0 +1,111 @@
1
+ // src/io/index.ts
2
+ function parseCsv(input, options) {
3
+ const { delimiter = ",", header = true, skipEmptyLines = true } = options ?? {};
4
+ const lines = input.split(/\r?\n/);
5
+ const rows = [];
6
+ for (const line of lines) {
7
+ const trimmed = line.trim();
8
+ if (skipEmptyLines && trimmed.length === 0) continue;
9
+ const values = parseCsvLine(trimmed, delimiter);
10
+ rows.push(values);
11
+ }
12
+ if (rows.length === 0) return [];
13
+ if (header) {
14
+ const [head, ...body] = rows;
15
+ if (head === void 0) return [];
16
+ return body.map((row) => {
17
+ const record = {};
18
+ for (let i = 0; i < head.length; i++) {
19
+ if (head[i] === "__proto__" || head[i] === "constructor" || head[i] === "prototype") continue;
20
+ record[head[i]] = row[i] ?? "";
21
+ }
22
+ return record;
23
+ });
24
+ }
25
+ return rows.map((row) => {
26
+ const record = {};
27
+ for (let i = 0; i < row.length; i++) {
28
+ record[String(i)] = row[i];
29
+ }
30
+ return record;
31
+ });
32
+ }
33
+ function parseCsvLine(line, delimiter) {
34
+ const result = [];
35
+ let current = "";
36
+ let inQuotes = false;
37
+ for (let i = 0; i < line.length; i++) {
38
+ const ch = line[i];
39
+ if (inQuotes) {
40
+ if (ch === '"') {
41
+ if (line[i + 1] === '"') {
42
+ current += '"';
43
+ i++;
44
+ } else {
45
+ inQuotes = false;
46
+ }
47
+ } else {
48
+ current += ch;
49
+ }
50
+ } else {
51
+ if (ch === '"') {
52
+ inQuotes = true;
53
+ } else if (ch === delimiter) {
54
+ result.push(current);
55
+ current = "";
56
+ } else {
57
+ current += ch;
58
+ }
59
+ }
60
+ }
61
+ result.push(current);
62
+ return result;
63
+ }
64
+ function stringifyCsv(data, options) {
65
+ const { delimiter = "," } = options ?? {};
66
+ if (data.length === 0) return "";
67
+ const headers = Object.keys(data[0]);
68
+ const lines = [headers.map((v) => escapeCsvField(v, delimiter)).join(delimiter)];
69
+ for (const record of data) {
70
+ const row = headers.map((h) => escapeCsvField(String(record[h] ?? ""), delimiter));
71
+ lines.push(row.join(delimiter));
72
+ }
73
+ return lines.join("\n");
74
+ }
75
+ function escapeCsvField(value, delimiter) {
76
+ if (value.includes('"') || value.includes(delimiter) || value.includes("\n") || value.includes("\r")) {
77
+ return '"' + value.replace(/"/g, '""') + '"';
78
+ }
79
+ return value;
80
+ }
81
+ function safeJsonParse(input, default_) {
82
+ try {
83
+ return JSON.parse(input);
84
+ } catch {
85
+ return default_ ?? null;
86
+ }
87
+ }
88
+ function env(name, default_) {
89
+ const value = process.env[name];
90
+ return value ?? default_ ?? "";
91
+ }
92
+ function envInt(name, default_) {
93
+ const value = process.env[name];
94
+ if (value === void 0 || value === "") return default_ ?? 0;
95
+ const parsed = Number.parseInt(value, 10);
96
+ return Number.isNaN(parsed) ? default_ ?? 0 : parsed;
97
+ }
98
+ function envBool(name, default_) {
99
+ const value = process.env[name];
100
+ if (value === void 0 || value === "") return default_ ?? false;
101
+ return value === "true" || value === "1" || value === "yes";
102
+ }
103
+ export {
104
+ env,
105
+ envBool,
106
+ envInt,
107
+ parseCsv,
108
+ safeJsonParse,
109
+ stringifyCsv
110
+ };
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/io/index.ts"],"sourcesContent":["/**\r\n * Options for CSV parsing.\r\n */\r\nexport interface CsvOptions {\r\n delimiter?: string\r\n header?: boolean\r\n skipEmptyLines?: boolean\r\n}\r\n\r\n/**\r\n * Parses a CSV string into an array of records (objects).\r\n *\r\n * @param input - CSV string\r\n * @param options - Optional parsing options\r\n */\r\nexport function parseCsv(input: string, options?: CsvOptions): Record<string, string>[] {\r\n const { delimiter = ',', header = true, skipEmptyLines = true } = options ?? {}\r\n\r\n const lines = input.split(/\\r?\\n/)\r\n const rows: string[][] = []\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim()\r\n if (skipEmptyLines && trimmed.length === 0) continue\r\n const values = parseCsvLine(trimmed, delimiter)\r\n rows.push(values)\r\n }\r\n\r\n if (rows.length === 0) return []\r\n\r\n if (header) {\r\n const [head, ...body] = rows\r\n if (head === undefined) return []\r\n return body.map(row => {\r\n const record: Record<string, string> = {}\r\n for (let i = 0; i < head.length; i++) {\r\n if (head[i] === '__proto__' || head[i] === 'constructor' || head[i] === 'prototype') continue\r\n record[head[i]!] = row[i] ?? ''\r\n }\r\n return record\r\n })\r\n }\r\n\r\n return rows.map(row => {\r\n const record: Record<string, string> = {}\r\n for (let i = 0; i < row.length; i++) {\r\n record[String(i)] = row[i]!\r\n }\r\n return record\r\n })\r\n}\r\n\r\nfunction parseCsvLine(line: string, delimiter: string): string[] {\r\n const result: string[] = []\r\n let current = ''\r\n let inQuotes = false\r\n\r\n for (let i = 0; i < line.length; i++) {\r\n const ch = line[i]!\r\n if (inQuotes) {\r\n if (ch === '\"') {\r\n if (line[i + 1] === '\"') {\r\n current += '\"'\r\n i++\r\n } else {\r\n inQuotes = false\r\n }\r\n } else {\r\n current += ch\r\n }\r\n } else {\r\n if (ch === '\"') {\r\n inQuotes = true\r\n } else if (ch === delimiter) {\r\n result.push(current)\r\n current = ''\r\n } else {\r\n current += ch\r\n }\r\n }\r\n }\r\n result.push(current)\r\n return result\r\n}\r\n\r\n/**\r\n * Converts an array of records to a CSV string.\r\n */\r\nexport function stringifyCsv(data: Record<string, unknown>[], options?: { delimiter?: string }): string {\r\n const { delimiter = ',' } = options ?? {}\r\n if (data.length === 0) return ''\r\n\r\n const headers = Object.keys(data[0]!)\r\n const lines: string[] = [headers.map(v => escapeCsvField(v, delimiter)).join(delimiter)]\r\n\r\n for (const record of data) {\r\n const row = headers.map(h => escapeCsvField(String(record[h] ?? ''), delimiter))\r\n lines.push(row.join(delimiter))\r\n }\r\n\r\n return lines.join('\\n')\r\n}\r\n\r\nfunction escapeCsvField(value: string, delimiter: string): string {\r\n if (value.includes('\"') || value.includes(delimiter) || value.includes('\\n') || value.includes('\\r')) {\r\n return '\"' + value.replace(/\"/g, '\"\"') + '\"'\r\n }\r\n return value\r\n}\r\n\r\n/**\r\n * Safely parses a JSON string, returning the default value or null on failure.\r\n */\r\nexport function safeJsonParse<T>(input: string, default_?: T): T | null {\r\n try {\r\n return JSON.parse(input) as T\r\n } catch {\r\n return default_ ?? null\r\n }\r\n}\r\n\r\n/**\r\n * Reads an environment variable with optional default.\r\n */\r\nexport function env(name: string, default_?: string): string {\r\n const value = process.env[name]\r\n return value ?? default_ ?? ''\r\n}\r\n\r\n/**\r\n * Reads an environment variable as an integer.\r\n */\r\nexport function envInt(name: string, default_?: number): number {\r\n const value = process.env[name]\r\n if (value === undefined || value === '') return default_ ?? 0\r\n const parsed = Number.parseInt(value, 10)\r\n return Number.isNaN(parsed) ? (default_ ?? 0) : parsed\r\n}\r\n\r\n/**\r\n * Reads an environment variable as a boolean.\r\n */\r\nexport function envBool(name: string, default_?: boolean): boolean {\r\n const value = process.env[name]\r\n if (value === undefined || value === '') return default_ ?? false\r\n return value === 'true' || value === '1' || value === 'yes'\r\n}\r\n"],"mappings":";AAeO,SAAS,SAAS,OAAe,SAAgD;AACtF,QAAM,EAAE,YAAY,KAAK,SAAS,MAAM,iBAAiB,KAAK,IAAI,WAAW,CAAC;AAE9E,QAAM,QAAQ,MAAM,MAAM,OAAO;AACjC,QAAM,OAAmB,CAAC;AAE1B,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,kBAAkB,QAAQ,WAAW,EAAG;AAC5C,UAAM,SAAS,aAAa,SAAS,SAAS;AAC9C,SAAK,KAAK,MAAM;AAAA,EAClB;AAEA,MAAI,KAAK,WAAW,EAAG,QAAO,CAAC;AAE/B,MAAI,QAAQ;AACV,UAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,QAAI,SAAS,OAAW,QAAO,CAAC;AAChC,WAAO,KAAK,IAAI,SAAO;AACrB,YAAM,SAAiC,CAAC;AACxC,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAI,KAAK,CAAC,MAAM,eAAe,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,YAAa;AACrF,eAAO,KAAK,CAAC,CAAE,IAAI,IAAI,CAAC,KAAK;AAAA,MAC/B;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,KAAK,IAAI,SAAO;AACrB,UAAM,SAAiC,CAAC;AACxC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,aAAO,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,aAAa,MAAc,WAA6B;AAC/D,QAAM,SAAmB,CAAC;AAC1B,MAAI,UAAU;AACd,MAAI,WAAW;AAEf,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,KAAK,KAAK,CAAC;AACjB,QAAI,UAAU;AACZ,UAAI,OAAO,KAAK;AACd,YAAI,KAAK,IAAI,CAAC,MAAM,KAAK;AACvB,qBAAW;AACX;AAAA,QACF,OAAO;AACL,qBAAW;AAAA,QACb;AAAA,MACF,OAAO;AACL,mBAAW;AAAA,MACb;AAAA,IACF,OAAO;AACL,UAAI,OAAO,KAAK;AACd,mBAAW;AAAA,MACb,WAAW,OAAO,WAAW;AAC3B,eAAO,KAAK,OAAO;AACnB,kBAAU;AAAA,MACZ,OAAO;AACL,mBAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACA,SAAO,KAAK,OAAO;AACnB,SAAO;AACT;AAKO,SAAS,aAAa,MAAiC,SAA0C;AACtG,QAAM,EAAE,YAAY,IAAI,IAAI,WAAW,CAAC;AACxC,MAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,QAAM,UAAU,OAAO,KAAK,KAAK,CAAC,CAAE;AACpC,QAAM,QAAkB,CAAC,QAAQ,IAAI,OAAK,eAAe,GAAG,SAAS,CAAC,EAAE,KAAK,SAAS,CAAC;AAEvF,aAAW,UAAU,MAAM;AACzB,UAAM,MAAM,QAAQ,IAAI,OAAK,eAAe,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,SAAS,CAAC;AAC/E,UAAM,KAAK,IAAI,KAAK,SAAS,CAAC;AAAA,EAChC;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,eAAe,OAAe,WAA2B;AAChE,MAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,IAAI,GAAG;AACpG,WAAO,MAAM,MAAM,QAAQ,MAAM,IAAI,IAAI;AAAA,EAC3C;AACA,SAAO;AACT;AAKO,SAAS,cAAiB,OAAe,UAAwB;AACtE,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB,QAAQ;AACN,WAAO,YAAY;AAAA,EACrB;AACF;AAKO,SAAS,IAAI,MAAc,UAA2B;AAC3D,QAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,SAAO,SAAS,YAAY;AAC9B;AAKO,SAAS,OAAO,MAAc,UAA2B;AAC9D,QAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,MAAI,UAAU,UAAa,UAAU,GAAI,QAAO,YAAY;AAC5D,QAAM,SAAS,OAAO,SAAS,OAAO,EAAE;AACxC,SAAO,OAAO,MAAM,MAAM,IAAK,YAAY,IAAK;AAClD;AAKO,SAAS,QAAQ,MAAc,UAA6B;AACjE,QAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,MAAI,UAAU,UAAa,UAAU,GAAI,QAAO,YAAY;AAC5D,SAAO,UAAU,UAAU,UAAU,OAAO,UAAU;AACxD;","names":[]}
@@ -0,0 +1 @@
1
+ export { h as LogFn, L as LogLevel, a as Logger, i as LoggerOptions, T as Transport, c as consoleTransport, b as createBufferedTransport, d as createConsoleTransport, e as createFileTransport, f as createJsonTransport, l as logger } from '../index-BgG21uJC.js';
@@ -0,0 +1,214 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/logger/logger.ts
9
+ var LEVEL_ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
10
+ var Logger = class _Logger {
11
+ _level;
12
+ _name;
13
+ _transport;
14
+ _extraMeta;
15
+ constructor(options) {
16
+ this._level = options?.level ?? "info";
17
+ this._name = options?.name;
18
+ this._transport = options?.transport ?? consoleTransport;
19
+ this._extraMeta = /* @__PURE__ */ Object.create(null);
20
+ }
21
+ _shouldLog(target) {
22
+ return LEVEL_ORDER[this._level] <= LEVEL_ORDER[target];
23
+ }
24
+ _log(level, message, meta) {
25
+ if (level !== "error" && !this._shouldLog(level)) return;
26
+ const merged = /* @__PURE__ */ Object.create(null);
27
+ for (const key of Object.keys(this._extraMeta)) {
28
+ merged[key] = this._extraMeta[key];
29
+ }
30
+ if (meta !== void 0) {
31
+ for (const key of Object.keys(meta)) {
32
+ merged[key] = meta[key];
33
+ }
34
+ }
35
+ const label = this._name !== void 0 ? `[${this._name}] ${message}` : message;
36
+ const finalMeta = Object.keys(merged).length > 0 ? merged : void 0;
37
+ this._transport.log(level, label, finalMeta);
38
+ }
39
+ /** Log at `debug` level. Only emitted when the current level is `'debug'`. */
40
+ debug = (message, meta) => this._log("debug", message, meta);
41
+ /** Log at `info` level. Emitted when level is `'debug'` or `'info'`. */
42
+ info = (message, meta) => this._log("info", message, meta);
43
+ /** Log at `warn` level. Emitted when level is `'debug'`, `'info'`, or `'warn'`. */
44
+ warn = (message, meta) => this._log("warn", message, meta);
45
+ /** Log at `error` level. Always emitted regardless of current level. */
46
+ error = (message, meta) => this._log("error", message, meta);
47
+ /**
48
+ * Creates a child logger that inherits the parent's level, name, and transport,
49
+ * but merges `extraMeta` into every log call. Child metadata is shallow-merged
50
+ * on top of the parent's inherited metadata.
51
+ *
52
+ * @param extraMeta - Additional context to include in every log entry.
53
+ */
54
+ child(extraMeta) {
55
+ const child = new _Logger({
56
+ level: this._level,
57
+ name: this._name,
58
+ transport: this._transport
59
+ });
60
+ const inherited = /* @__PURE__ */ Object.create(null);
61
+ for (const key of Object.keys(this._extraMeta)) {
62
+ inherited[key] = this._extraMeta[key];
63
+ }
64
+ for (const key of Object.keys(extraMeta)) {
65
+ inherited[key] = extraMeta[key];
66
+ }
67
+ child._extraMeta = inherited;
68
+ return child;
69
+ }
70
+ /** Updates the minimum log level for this instance. */
71
+ setLevel(level) {
72
+ this._level = level;
73
+ }
74
+ /** Returns the current minimum log level. */
75
+ getLevel() {
76
+ return this._level;
77
+ }
78
+ /**
79
+ * Creates a new named Logger.
80
+ * Convenience shorthand for `new Logger({ ...options, name })`.
81
+ *
82
+ * @param name - The name tag shown in log output.
83
+ * @param options - Additional configuration.
84
+ */
85
+ static create(name, options) {
86
+ return new _Logger({ ...options, name });
87
+ }
88
+ };
89
+ var consoleTransport = {
90
+ log(level, message, meta) {
91
+ const metaStr = meta !== void 0 && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : "";
92
+ console.log(`[${level.toUpperCase()}] ${message}${metaStr}`);
93
+ }
94
+ };
95
+ var logger = new Logger();
96
+
97
+ // src/logger/transports.ts
98
+ var LEVEL_COLORS = {
99
+ debug: "\x1B[90m",
100
+ info: "\x1B[34m",
101
+ warn: "\x1B[33m",
102
+ error: "\x1B[31m"
103
+ };
104
+ var RESET = "\x1B[0m";
105
+ function createConsoleTransport(options) {
106
+ const useColors = options?.colors !== false;
107
+ const showTimestamp = options?.timestamp ?? false;
108
+ return {
109
+ log(level, message, meta) {
110
+ const parts = [];
111
+ if (showTimestamp) {
112
+ parts.push((/* @__PURE__ */ new Date()).toISOString());
113
+ }
114
+ if (useColors) {
115
+ const color = LEVEL_COLORS[level];
116
+ parts.push(`${color}[${level.toUpperCase()}]${RESET}`);
117
+ } else {
118
+ parts.push(`[${level.toUpperCase()}]`);
119
+ }
120
+ parts.push(message);
121
+ if (meta !== void 0 && Object.keys(meta).length > 0) {
122
+ parts.push(JSON.stringify(meta));
123
+ }
124
+ console.log(parts.join(" "));
125
+ }
126
+ };
127
+ }
128
+ function createJsonTransport(options) {
129
+ const writeStream = options?.stream ?? (typeof process !== "undefined" && typeof process.stdout !== "undefined" && typeof process.stdout.write === "function" ? process.stdout : void 0);
130
+ return {
131
+ log(level, message, meta) {
132
+ const entry = {
133
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
134
+ level,
135
+ message
136
+ };
137
+ if (meta !== void 0 && Object.keys(meta).length > 0) {
138
+ entry.meta = meta;
139
+ }
140
+ const line = JSON.stringify(entry);
141
+ if (writeStream !== void 0) {
142
+ writeStream.write(line + "\n");
143
+ } else {
144
+ console.log(line);
145
+ }
146
+ }
147
+ };
148
+ }
149
+ function createFileTransport(filename, _options) {
150
+ let fs = null;
151
+ try {
152
+ if (typeof process !== "undefined" && process.versions?.node) {
153
+ const m = __require("fs");
154
+ fs = m;
155
+ }
156
+ } catch {
157
+ }
158
+ return {
159
+ log(level, message, meta) {
160
+ if (fs === null) return;
161
+ const metaStr = meta !== void 0 && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : "";
162
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level.toUpperCase()}] ${message}${metaStr}
163
+ `;
164
+ try {
165
+ fs.appendFileSync(filename, line);
166
+ } catch {
167
+ }
168
+ }
169
+ };
170
+ }
171
+ function createBufferedTransport(transport, options) {
172
+ const maxSize = options?.maxSize ?? 100;
173
+ const flushIntervalMs = options?.flushIntervalMs ?? 5e3;
174
+ const buffer = [];
175
+ let timer;
176
+ function flush() {
177
+ if (timer !== void 0) {
178
+ clearTimeout(timer);
179
+ timer = void 0;
180
+ }
181
+ for (let i = 0; i < buffer.length; i++) {
182
+ const entry = buffer[i];
183
+ transport.log(entry.level, entry.message, entry.meta);
184
+ }
185
+ buffer.length = 0;
186
+ }
187
+ function scheduleFlush() {
188
+ if (timer !== void 0 || flushIntervalMs <= 0) return;
189
+ timer = setTimeout(() => {
190
+ timer = void 0;
191
+ flush();
192
+ }, flushIntervalMs);
193
+ }
194
+ return {
195
+ log(level, message, meta) {
196
+ buffer.push({ level, message, meta });
197
+ if (buffer.length >= maxSize) {
198
+ flush();
199
+ } else {
200
+ scheduleFlush();
201
+ }
202
+ }
203
+ };
204
+ }
205
+ export {
206
+ Logger,
207
+ consoleTransport,
208
+ createBufferedTransport,
209
+ createConsoleTransport,
210
+ createFileTransport,
211
+ createJsonTransport,
212
+ logger
213
+ };
214
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/logger/logger.ts","../../src/logger/transports.ts"],"sourcesContent":["/**\n * Represents the severity level of a log entry.\n * Ordered from least to most severe: debug < info < warn < error.\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error'\n\n/**\n * Log function signature bound to a specific severity level.\n */\nexport type LogFn = (message: string, meta?: Record<string, unknown>) => void\n\n/**\n * Configuration options for creating a Logger instance.\n */\nexport interface LoggerOptions {\n /** Minimum log level to output (default: 'info'). */\n level?: LogLevel\n /** Optional name tag prepended to every message as `[name]`. */\n name?: string\n /** Custom transport; defaults to {@link consoleTransport}. */\n transport?: Transport\n}\n\n/**\n * A transport handles the formatted output of log entries.\n * Implementations write to stdout, files, buffers, or remote services.\n */\nexport interface Transport {\n log(level: LogLevel, message: string, meta?: Record<string, unknown>): void\n}\n\nconst LEVEL_ORDER: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 }\n\n/**\n * Structured logger with level filtering, child loggers, and pluggable transport.\n *\n * @example\n * ```ts\n * const log = new Logger({ level: 'debug', name: 'app' })\n * log.info('server started', { port: 3000 })\n *\n * const child = log.child({ requestId: 'abc-123' })\n * child.warn('slow query', { durationMs: 450 })\n * ```\n */\nexport class Logger {\n private _level: LogLevel\n private _name?: string\n private _transport: Transport\n private _extraMeta: Record<string, unknown>\n\n constructor(options?: LoggerOptions) {\n this._level = options?.level ?? 'info'\n this._name = options?.name\n this._transport = options?.transport ?? consoleTransport\n this._extraMeta = Object.create(null)\n }\n\n private _shouldLog(target: LogLevel): boolean {\n return LEVEL_ORDER[this._level] <= LEVEL_ORDER[target]\n }\n\n private _log(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n if (level !== 'error' && !this._shouldLog(level)) return\n\n const merged: Record<string, unknown> = Object.create(null)\n for (const key of Object.keys(this._extraMeta)) {\n merged[key] = (this._extraMeta as Record<string, unknown>)[key]!\n }\n if (meta !== undefined) {\n for (const key of Object.keys(meta)) {\n merged[key] = meta[key]!\n }\n }\n\n const label = this._name !== undefined ? `[${this._name}] ${message}` : message\n const finalMeta = Object.keys(merged).length > 0 ? merged : undefined\n this._transport.log(level, label, finalMeta)\n }\n\n /** Log at `debug` level. Only emitted when the current level is `'debug'`. */\n debug: LogFn = (message, meta?) => this._log('debug', message, meta)\n\n /** Log at `info` level. Emitted when level is `'debug'` or `'info'`. */\n info: LogFn = (message, meta?) => this._log('info', message, meta)\n\n /** Log at `warn` level. Emitted when level is `'debug'`, `'info'`, or `'warn'`. */\n warn: LogFn = (message, meta?) => this._log('warn', message, meta)\n\n /** Log at `error` level. Always emitted regardless of current level. */\n error: LogFn = (message, meta?) => this._log('error', message, meta)\n\n /**\n * Creates a child logger that inherits the parent's level, name, and transport,\n * but merges `extraMeta` into every log call. Child metadata is shallow-merged\n * on top of the parent's inherited metadata.\n *\n * @param extraMeta - Additional context to include in every log entry.\n */\n child(extraMeta: Record<string, unknown>): Logger {\n const child = new Logger({\n level: this._level,\n name: this._name,\n transport: this._transport,\n })\n const inherited: Record<string, unknown> = Object.create(null)\n for (const key of Object.keys(this._extraMeta)) {\n inherited[key] = (this._extraMeta as Record<string, unknown>)[key]!\n }\n for (const key of Object.keys(extraMeta)) {\n inherited[key] = extraMeta[key]!\n }\n child._extraMeta = inherited\n return child\n }\n\n /** Updates the minimum log level for this instance. */\n setLevel(level: LogLevel): void {\n this._level = level\n }\n\n /** Returns the current minimum log level. */\n getLevel(): LogLevel {\n return this._level\n }\n\n /**\n * Creates a new named Logger.\n * Convenience shorthand for `new Logger({ ...options, name })`.\n *\n * @param name - The name tag shown in log output.\n * @param options - Additional configuration.\n */\n static create(name: string, options?: LoggerOptions): Logger {\n return new Logger({ ...options, name })\n }\n}\n\n/**\n * Default transport that writes formatted log lines to `console.log`.\n *\n * Output format: `[LEVEL] message {meta}`\n *\n * When a logger has a name, the format becomes: `[LEVEL] [name] message {meta}`\n */\nexport const consoleTransport: Transport = {\n log(level, message, meta) {\n const metaStr =\n meta !== undefined && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : ''\n console.log(`[${level.toUpperCase()}] ${message}${metaStr}`)\n },\n}\n\n/**\n * Default logger instance at `'info'` level with no name.\n */\nexport const logger: Logger = new Logger()\n","import type { LogLevel } from './logger.js'\n\n/**\n * A transport handles the formatted output of log entries.\n */\nexport interface Transport {\n log(level: LogLevel, message: string, meta?: Record<string, unknown>): void\n}\n\nconst LEVEL_COLORS: Record<LogLevel, string> = {\n debug: '\\x1b[90m',\n info: '\\x1b[34m',\n warn: '\\x1b[33m',\n error: '\\x1b[31m',\n}\n\nconst RESET = '\\x1b[0m'\n\n/**\n * Creates a console transport that writes formatted log lines to `console.log`.\n *\n * The level prefix is optionally colored using ANSI escape codes:\n * - `debug` → gray\n * - `info` → blue\n * - `warn` → yellow\n * - `error` → red\n *\n * @param options - Configuration for the console transport.\n * @param options.colors - Enable ANSI color output (default: `true`).\n * @param options.timestamp - Prepend an ISO-8601 timestamp (default: `false`).\n */\nexport function createConsoleTransport(options?: {\n colors?: boolean\n timestamp?: boolean\n}): Transport {\n const useColors = options?.colors !== false\n const showTimestamp = options?.timestamp ?? false\n\n return {\n log(level, message, meta) {\n const parts: string[] = []\n\n if (showTimestamp) {\n parts.push(new Date().toISOString())\n }\n\n if (useColors) {\n const color = LEVEL_COLORS[level]\n parts.push(`${color}[${level.toUpperCase()}]${RESET}`)\n } else {\n parts.push(`[${level.toUpperCase()}]`)\n }\n\n parts.push(message)\n\n if (meta !== undefined && Object.keys(meta).length > 0) {\n parts.push(JSON.stringify(meta))\n }\n\n console.log(parts.join(' '))\n },\n }\n}\n\n/**\n * Creates a transport that outputs structured JSON lines.\n *\n * Each log entry is serialized as a single JSON object with\n * `timestamp`, `level`, `message`, and optional `meta` fields.\n *\n * @param options - Configuration for the JSON transport.\n * @param options.stream - A writable stream (e.g. `process.stdout`).\n * Defaults to `process.stdout` in Node.js, falls\n * back to `console.log` in browsers.\n */\nexport function createJsonTransport(options?: {\n stream?: { write(data: string): void }\n}): Transport {\n const writeStream =\n options?.stream ??\n (typeof process !== 'undefined' &&\n typeof process.stdout !== 'undefined' &&\n typeof process.stdout.write === 'function'\n ? (process.stdout as { write(data: string): void })\n : undefined)\n\n return {\n log(level, message, meta) {\n const entry: Record<string, unknown> = {\n timestamp: new Date().toISOString(),\n level,\n message,\n }\n if (meta !== undefined && Object.keys(meta).length > 0) {\n entry.meta = meta\n }\n const line = JSON.stringify(entry)\n if (writeStream !== undefined) {\n writeStream.write(line + '\\n')\n } else {\n console.log(line)\n }\n },\n }\n}\n\n/**\n * Creates a transport that appends log entries to a file.\n *\n * Each line is formatted as: `[timestamp] [LEVEL] message {meta}`\n *\n * ⚠️ Node.js only. Silently discards log entries when `fs` is unavailable\n * (browsers, Deno, Bun — though Bun supports `fs`).\n *\n * @param filename - Path to the log file.\n * @param options - Configuration for the file transport.\n * @param options.maxSize - Maximum file size in bytes before rotation\n * (default: 10 MB). **Note:** rotation is not\n * yet implemented; this is reserved for future use.\n */\nexport function createFileTransport(\n filename: string,\n _options?: { maxSize?: number },\n): Transport {\n // Try to resolve fs synchronously at construction time\n // Uses process.versions.node as a heuristic for Node.js environment\n let fs: { appendFileSync: (path: string, data: string) => void } | null = null\n try {\n if (typeof process !== 'undefined' && process.versions?.node) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const m = require('fs') as { appendFileSync: (path: string, data: string) => void }\n fs = m\n }\n } catch {\n // fs unavailable (browser, edge runtime)\n }\n\n return {\n log(level, message, meta) {\n if (fs === null) return\n\n const metaStr =\n meta !== undefined && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : ''\n const line = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}${metaStr}\\n`\n\n try {\n fs.appendFileSync(filename, line)\n } catch {\n // Silently drop if write fails (disk full, permissions, etc.)\n }\n },\n }\n}\n\n/**\n * Creates a buffered transport that batches log entries and flushes them\n * to the underlying transport when either the buffer size or flush interval\n * is reached (whichever comes first).\n *\n * Useful for reducing I/O pressure in high-throughput scenarios.\n *\n * @param transport - The underlying transport to flush to.\n * @param options - Configuration for the buffer.\n * @param options.maxSize - Maximum number of entries before forced flush\n * (default: 100).\n * @param options.flushIntervalMs - How often to auto-flush in milliseconds\n * (default: 5000). Set to `0` to disable\n * interval flushing.\n */\nexport function createBufferedTransport(\n transport: Transport,\n options?: { maxSize?: number; flushIntervalMs?: number },\n): Transport {\n const maxSize = options?.maxSize ?? 100\n const flushIntervalMs = options?.flushIntervalMs ?? 5000\n\n const buffer: Array<{\n level: LogLevel\n message: string\n meta?: Record<string, unknown>\n }> = []\n\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function flush(): void {\n if (timer !== undefined) {\n clearTimeout(timer)\n timer = undefined\n }\n for (let i = 0; i < buffer.length; i++) {\n const entry = buffer[i]!\n transport.log(entry.level, entry.message, entry.meta)\n }\n buffer.length = 0\n }\n\n function scheduleFlush(): void {\n if (timer !== undefined || flushIntervalMs <= 0) return\n timer = setTimeout((): void => {\n timer = undefined\n flush()\n }, flushIntervalMs)\n }\n\n return {\n log(level, message, meta) {\n buffer.push({ level, message, meta })\n if (buffer.length >= maxSize) {\n flush()\n } else {\n scheduleFlush()\n }\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ export { g as Transport, b as createBufferedTransport, d as createConsoleTransport, e as createFileTransport, f as createJsonTransport } from '../index-BgG21uJC.js';
@@ -0,0 +1,122 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/logger/transports.ts
9
+ var LEVEL_COLORS = {
10
+ debug: "\x1B[90m",
11
+ info: "\x1B[34m",
12
+ warn: "\x1B[33m",
13
+ error: "\x1B[31m"
14
+ };
15
+ var RESET = "\x1B[0m";
16
+ function createConsoleTransport(options) {
17
+ const useColors = options?.colors !== false;
18
+ const showTimestamp = options?.timestamp ?? false;
19
+ return {
20
+ log(level, message, meta) {
21
+ const parts = [];
22
+ if (showTimestamp) {
23
+ parts.push((/* @__PURE__ */ new Date()).toISOString());
24
+ }
25
+ if (useColors) {
26
+ const color = LEVEL_COLORS[level];
27
+ parts.push(`${color}[${level.toUpperCase()}]${RESET}`);
28
+ } else {
29
+ parts.push(`[${level.toUpperCase()}]`);
30
+ }
31
+ parts.push(message);
32
+ if (meta !== void 0 && Object.keys(meta).length > 0) {
33
+ parts.push(JSON.stringify(meta));
34
+ }
35
+ console.log(parts.join(" "));
36
+ }
37
+ };
38
+ }
39
+ function createJsonTransport(options) {
40
+ const writeStream = options?.stream ?? (typeof process !== "undefined" && typeof process.stdout !== "undefined" && typeof process.stdout.write === "function" ? process.stdout : void 0);
41
+ return {
42
+ log(level, message, meta) {
43
+ const entry = {
44
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
45
+ level,
46
+ message
47
+ };
48
+ if (meta !== void 0 && Object.keys(meta).length > 0) {
49
+ entry.meta = meta;
50
+ }
51
+ const line = JSON.stringify(entry);
52
+ if (writeStream !== void 0) {
53
+ writeStream.write(line + "\n");
54
+ } else {
55
+ console.log(line);
56
+ }
57
+ }
58
+ };
59
+ }
60
+ function createFileTransport(filename, _options) {
61
+ let fs = null;
62
+ try {
63
+ if (typeof process !== "undefined" && process.versions?.node) {
64
+ const m = __require("fs");
65
+ fs = m;
66
+ }
67
+ } catch {
68
+ }
69
+ return {
70
+ log(level, message, meta) {
71
+ if (fs === null) return;
72
+ const metaStr = meta !== void 0 && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : "";
73
+ const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${level.toUpperCase()}] ${message}${metaStr}
74
+ `;
75
+ try {
76
+ fs.appendFileSync(filename, line);
77
+ } catch {
78
+ }
79
+ }
80
+ };
81
+ }
82
+ function createBufferedTransport(transport, options) {
83
+ const maxSize = options?.maxSize ?? 100;
84
+ const flushIntervalMs = options?.flushIntervalMs ?? 5e3;
85
+ const buffer = [];
86
+ let timer;
87
+ function flush() {
88
+ if (timer !== void 0) {
89
+ clearTimeout(timer);
90
+ timer = void 0;
91
+ }
92
+ for (let i = 0; i < buffer.length; i++) {
93
+ const entry = buffer[i];
94
+ transport.log(entry.level, entry.message, entry.meta);
95
+ }
96
+ buffer.length = 0;
97
+ }
98
+ function scheduleFlush() {
99
+ if (timer !== void 0 || flushIntervalMs <= 0) return;
100
+ timer = setTimeout(() => {
101
+ timer = void 0;
102
+ flush();
103
+ }, flushIntervalMs);
104
+ }
105
+ return {
106
+ log(level, message, meta) {
107
+ buffer.push({ level, message, meta });
108
+ if (buffer.length >= maxSize) {
109
+ flush();
110
+ } else {
111
+ scheduleFlush();
112
+ }
113
+ }
114
+ };
115
+ }
116
+ export {
117
+ createBufferedTransport,
118
+ createConsoleTransport,
119
+ createFileTransport,
120
+ createJsonTransport
121
+ };
122
+ //# sourceMappingURL=transports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/logger/transports.ts"],"sourcesContent":["import type { LogLevel } from './logger.js'\n\n/**\n * A transport handles the formatted output of log entries.\n */\nexport interface Transport {\n log(level: LogLevel, message: string, meta?: Record<string, unknown>): void\n}\n\nconst LEVEL_COLORS: Record<LogLevel, string> = {\n debug: '\\x1b[90m',\n info: '\\x1b[34m',\n warn: '\\x1b[33m',\n error: '\\x1b[31m',\n}\n\nconst RESET = '\\x1b[0m'\n\n/**\n * Creates a console transport that writes formatted log lines to `console.log`.\n *\n * The level prefix is optionally colored using ANSI escape codes:\n * - `debug` → gray\n * - `info` → blue\n * - `warn` → yellow\n * - `error` → red\n *\n * @param options - Configuration for the console transport.\n * @param options.colors - Enable ANSI color output (default: `true`).\n * @param options.timestamp - Prepend an ISO-8601 timestamp (default: `false`).\n */\nexport function createConsoleTransport(options?: {\n colors?: boolean\n timestamp?: boolean\n}): Transport {\n const useColors = options?.colors !== false\n const showTimestamp = options?.timestamp ?? false\n\n return {\n log(level, message, meta) {\n const parts: string[] = []\n\n if (showTimestamp) {\n parts.push(new Date().toISOString())\n }\n\n if (useColors) {\n const color = LEVEL_COLORS[level]\n parts.push(`${color}[${level.toUpperCase()}]${RESET}`)\n } else {\n parts.push(`[${level.toUpperCase()}]`)\n }\n\n parts.push(message)\n\n if (meta !== undefined && Object.keys(meta).length > 0) {\n parts.push(JSON.stringify(meta))\n }\n\n console.log(parts.join(' '))\n },\n }\n}\n\n/**\n * Creates a transport that outputs structured JSON lines.\n *\n * Each log entry is serialized as a single JSON object with\n * `timestamp`, `level`, `message`, and optional `meta` fields.\n *\n * @param options - Configuration for the JSON transport.\n * @param options.stream - A writable stream (e.g. `process.stdout`).\n * Defaults to `process.stdout` in Node.js, falls\n * back to `console.log` in browsers.\n */\nexport function createJsonTransport(options?: {\n stream?: { write(data: string): void }\n}): Transport {\n const writeStream =\n options?.stream ??\n (typeof process !== 'undefined' &&\n typeof process.stdout !== 'undefined' &&\n typeof process.stdout.write === 'function'\n ? (process.stdout as { write(data: string): void })\n : undefined)\n\n return {\n log(level, message, meta) {\n const entry: Record<string, unknown> = {\n timestamp: new Date().toISOString(),\n level,\n message,\n }\n if (meta !== undefined && Object.keys(meta).length > 0) {\n entry.meta = meta\n }\n const line = JSON.stringify(entry)\n if (writeStream !== undefined) {\n writeStream.write(line + '\\n')\n } else {\n console.log(line)\n }\n },\n }\n}\n\n/**\n * Creates a transport that appends log entries to a file.\n *\n * Each line is formatted as: `[timestamp] [LEVEL] message {meta}`\n *\n * ⚠️ Node.js only. Silently discards log entries when `fs` is unavailable\n * (browsers, Deno, Bun — though Bun supports `fs`).\n *\n * @param filename - Path to the log file.\n * @param options - Configuration for the file transport.\n * @param options.maxSize - Maximum file size in bytes before rotation\n * (default: 10 MB). **Note:** rotation is not\n * yet implemented; this is reserved for future use.\n */\nexport function createFileTransport(\n filename: string,\n _options?: { maxSize?: number },\n): Transport {\n // Try to resolve fs synchronously at construction time\n // Uses process.versions.node as a heuristic for Node.js environment\n let fs: { appendFileSync: (path: string, data: string) => void } | null = null\n try {\n if (typeof process !== 'undefined' && process.versions?.node) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const m = require('fs') as { appendFileSync: (path: string, data: string) => void }\n fs = m\n }\n } catch {\n // fs unavailable (browser, edge runtime)\n }\n\n return {\n log(level, message, meta) {\n if (fs === null) return\n\n const metaStr =\n meta !== undefined && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : ''\n const line = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}${metaStr}\\n`\n\n try {\n fs.appendFileSync(filename, line)\n } catch {\n // Silently drop if write fails (disk full, permissions, etc.)\n }\n },\n }\n}\n\n/**\n * Creates a buffered transport that batches log entries and flushes them\n * to the underlying transport when either the buffer size or flush interval\n * is reached (whichever comes first).\n *\n * Useful for reducing I/O pressure in high-throughput scenarios.\n *\n * @param transport - The underlying transport to flush to.\n * @param options - Configuration for the buffer.\n * @param options.maxSize - Maximum number of entries before forced flush\n * (default: 100).\n * @param options.flushIntervalMs - How often to auto-flush in milliseconds\n * (default: 5000). Set to `0` to disable\n * interval flushing.\n */\nexport function createBufferedTransport(\n transport: Transport,\n options?: { maxSize?: number; flushIntervalMs?: number },\n): Transport {\n const maxSize = options?.maxSize ?? 100\n const flushIntervalMs = options?.flushIntervalMs ?? 5000\n\n const buffer: Array<{\n level: LogLevel\n message: string\n meta?: Record<string, unknown>\n }> = []\n\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function flush(): void {\n if (timer !== undefined) {\n clearTimeout(timer)\n timer = undefined\n }\n for (let i = 0; i < buffer.length; i++) {\n const entry = buffer[i]!\n transport.log(entry.level, entry.message, entry.meta)\n }\n buffer.length = 0\n }\n\n function scheduleFlush(): void {\n if (timer !== undefined || flushIntervalMs <= 0) return\n timer = setTimeout((): void => {\n timer = undefined\n flush()\n }, flushIntervalMs)\n }\n\n return {\n log(level, message, meta) {\n buffer.push({ level, message, meta })\n if (buffer.length >= maxSize) {\n flush()\n } else {\n scheduleFlush()\n }\n },\n }\n}\n"],"mappings":"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","names":[]}