logixia 1.12.4 → 1.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +80 -27
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/async-context-CSHWoHMB.js +88 -0
  4. package/dist/async-context-CSHWoHMB.js.map +1 -0
  5. package/dist/async-context-CwBNMm2E.mjs +68 -0
  6. package/dist/async-context-CwBNMm2E.mjs.map +1 -0
  7. package/dist/azure-monitor.transport-CG7ClkYj.d.ts +62 -0
  8. package/dist/azure-monitor.transport-CG7ClkYj.d.ts.map +1 -0
  9. package/dist/azure-monitor.transport-CHnjVRF-.mjs +152 -0
  10. package/dist/azure-monitor.transport-CHnjVRF-.mjs.map +1 -0
  11. package/dist/azure-monitor.transport-Cm74kXZS.d.mts +62 -0
  12. package/dist/azure-monitor.transport-Cm74kXZS.d.mts.map +1 -0
  13. package/dist/azure-monitor.transport-CrvfHd9C.js +157 -0
  14. package/dist/azure-monitor.transport-CrvfHd9C.js.map +1 -0
  15. package/dist/azure.d.mts +3 -0
  16. package/dist/azure.d.ts +3 -0
  17. package/dist/azure.js +6 -0
  18. package/dist/azure.mjs +6 -0
  19. package/dist/batch-buffer-BY-mRWIK.js +170 -0
  20. package/dist/batch-buffer-BY-mRWIK.js.map +1 -0
  21. package/dist/batch-buffer-PGvSgbmd.mjs +132 -0
  22. package/dist/batch-buffer-PGvSgbmd.mjs.map +1 -0
  23. package/dist/browser.d.mts +427 -0
  24. package/dist/browser.d.mts.map +1 -0
  25. package/dist/browser.d.ts +427 -0
  26. package/dist/browser.d.ts.map +1 -0
  27. package/dist/browser.js +590 -0
  28. package/dist/browser.js.map +1 -0
  29. package/dist/browser.mjs +586 -0
  30. package/dist/browser.mjs.map +1 -0
  31. package/dist/chunk-DLSkYcPk.mjs +7 -0
  32. package/dist/chunk-nOFOJqeH.js +30 -0
  33. package/dist/cloudwatch.d.mts +3 -0
  34. package/dist/cloudwatch.d.ts +3 -0
  35. package/dist/cloudwatch.js +6 -0
  36. package/dist/cloudwatch.mjs +6 -0
  37. package/dist/cloudwatch.transport-CGHY4buE.d.mts +81 -0
  38. package/dist/cloudwatch.transport-CGHY4buE.d.mts.map +1 -0
  39. package/dist/cloudwatch.transport-DK_8cKd3.d.ts +81 -0
  40. package/dist/cloudwatch.transport-DK_8cKd3.d.ts.map +1 -0
  41. package/dist/cloudwatch.transport-pNBNWJLt.js +370 -0
  42. package/dist/cloudwatch.transport-pNBNWJLt.js.map +1 -0
  43. package/dist/cloudwatch.transport-yBwm4OeO.mjs +360 -0
  44. package/dist/cloudwatch.transport-yBwm4OeO.mjs.map +1 -0
  45. package/dist/coerce.utils-BN980Y9V.js +44 -0
  46. package/dist/coerce.utils-BN980Y9V.js.map +1 -0
  47. package/dist/coerce.utils-Dxv4_ikC.mjs +38 -0
  48. package/dist/coerce.utils-Dxv4_ikC.mjs.map +1 -0
  49. package/dist/correlation.d.mts +238 -0
  50. package/dist/correlation.d.mts.map +1 -0
  51. package/dist/correlation.d.ts +238 -0
  52. package/dist/correlation.d.ts.map +1 -0
  53. package/dist/correlation.js +272 -0
  54. package/dist/correlation.js.map +1 -0
  55. package/dist/correlation.mjs +261 -0
  56. package/dist/correlation.mjs.map +1 -0
  57. package/dist/gcp.d.mts +3 -0
  58. package/dist/gcp.d.ts +3 -0
  59. package/dist/gcp.js +6 -0
  60. package/dist/gcp.mjs +6 -0
  61. package/dist/gcp.transport-BJuNRFe_.mjs +192 -0
  62. package/dist/gcp.transport-BJuNRFe_.mjs.map +1 -0
  63. package/dist/gcp.transport-BOhkVKlI.d.ts +71 -0
  64. package/dist/gcp.transport-BOhkVKlI.d.ts.map +1 -0
  65. package/dist/gcp.transport-Bi6CUqZR.d.mts +71 -0
  66. package/dist/gcp.transport-Bi6CUqZR.d.mts.map +1 -0
  67. package/dist/gcp.transport-SHdtc1n0.js +198 -0
  68. package/dist/gcp.transport-SHdtc1n0.js.map +1 -0
  69. package/dist/{index-CwFww7VC.d.ts → index-BPKwwERo.d.mts} +18 -174
  70. package/dist/index-BPKwwERo.d.mts.map +1 -0
  71. package/dist/{index-DnyeaoZU.d.mts → index-C1X-TE5I.d.ts} +18 -174
  72. package/dist/index-C1X-TE5I.d.ts.map +1 -0
  73. package/dist/index.d.mts +41 -11
  74. package/dist/index.d.mts.map +1 -1
  75. package/dist/index.d.ts +40 -10
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +87 -147
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +62 -132
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/internal-log-BUJYMZbE.js +70 -0
  82. package/dist/internal-log-BUJYMZbE.js.map +1 -0
  83. package/dist/internal-log-Cm8SOWSV.mjs +52 -0
  84. package/dist/internal-log-Cm8SOWSV.mjs.map +1 -0
  85. package/dist/{logitron-logger.module-BIGTm2V6.mjs → logitron-logger.module-Bs3XYZgF.mjs} +266 -166
  86. package/dist/logitron-logger.module-Bs3XYZgF.mjs.map +1 -0
  87. package/dist/{logitron-logger.module-BTxDpK6u.js → logitron-logger.module-BsDZR5BH.js} +297 -203
  88. package/dist/logitron-logger.module-BsDZR5BH.js.map +1 -0
  89. package/dist/{logitron-logger.module-BmT-ewin.d.ts → logitron-logger.module-CxT1F6Cm.d.ts} +23 -10
  90. package/dist/logitron-logger.module-CxT1F6Cm.d.ts.map +1 -0
  91. package/dist/{logitron-logger.module-BCq3sF27.d.mts → logitron-logger.module-zDKVd_o0.d.mts} +23 -10
  92. package/dist/logitron-logger.module-zDKVd_o0.d.mts.map +1 -0
  93. package/dist/middleware.d.mts +5 -2
  94. package/dist/middleware.d.mts.map +1 -1
  95. package/dist/middleware.d.ts +5 -2
  96. package/dist/middleware.d.ts.map +1 -1
  97. package/dist/middleware.js +13 -4
  98. package/dist/middleware.js.map +1 -1
  99. package/dist/middleware.mjs +14 -4
  100. package/dist/middleware.mjs.map +1 -1
  101. package/dist/nest.d.mts +3 -2
  102. package/dist/nest.d.mts.map +1 -1
  103. package/dist/nest.d.ts +3 -2
  104. package/dist/nest.d.ts.map +1 -1
  105. package/dist/nest.js +6 -2
  106. package/dist/nest.mjs +6 -2
  107. package/dist/safe-stringify-DJ66tW5I.mjs +118 -0
  108. package/dist/safe-stringify-DJ66tW5I.mjs.map +1 -0
  109. package/dist/safe-stringify-DWo3aZp_.js +142 -0
  110. package/dist/safe-stringify-DWo3aZp_.js.map +1 -0
  111. package/dist/search-CFQRISUv.mjs +1596 -0
  112. package/dist/search-CFQRISUv.mjs.map +1 -0
  113. package/dist/search-CQOo-Iq6.d.mts +816 -0
  114. package/dist/search-CQOo-Iq6.d.mts.map +1 -0
  115. package/dist/search-DujhR94O.d.ts +816 -0
  116. package/dist/search-DujhR94O.d.ts.map +1 -0
  117. package/dist/search-njTI2hdo.js +1631 -0
  118. package/dist/search-njTI2hdo.js.map +1 -0
  119. package/dist/search.d.mts +4 -1
  120. package/dist/search.d.ts +4 -1
  121. package/dist/search.js +9 -1
  122. package/dist/search.mjs +3 -2
  123. package/dist/testing.d.mts +2 -1
  124. package/dist/testing.d.mts.map +1 -1
  125. package/dist/testing.d.ts +2 -1
  126. package/dist/testing.d.ts.map +1 -1
  127. package/dist/{transport.manager-ciG4r5uz.js → transport.manager-BivyUTtU.js} +497 -437
  128. package/dist/transport.manager-BivyUTtU.js.map +1 -0
  129. package/dist/{transport.manager-DETpXuaY.mjs → transport.manager-D6KL3t9V.mjs} +473 -364
  130. package/dist/transport.manager-D6KL3t9V.mjs.map +1 -0
  131. package/dist/transport.types-B5vcyv2k.d.mts +187 -0
  132. package/dist/transport.types-B5vcyv2k.d.mts.map +1 -0
  133. package/dist/transport.types-BuY84TwO.d.ts +187 -0
  134. package/dist/transport.types-BuY84TwO.d.ts.map +1 -0
  135. package/dist/transports.d.mts +90 -29
  136. package/dist/transports.d.mts.map +1 -1
  137. package/dist/transports.d.ts +90 -29
  138. package/dist/transports.d.ts.map +1 -1
  139. package/dist/transports.js +14 -2
  140. package/dist/transports.mjs +10 -2
  141. package/dist/worker-entry.js +1241 -0
  142. package/dist/worker.d.mts +3 -0
  143. package/dist/worker.d.ts +3 -0
  144. package/dist/worker.js +4 -0
  145. package/dist/worker.mjs +4 -0
  146. package/dist/worker.transport-BP8Q28Z2.d.mts +76 -0
  147. package/dist/worker.transport-BP8Q28Z2.d.mts.map +1 -0
  148. package/dist/worker.transport-BhMyvqQ2.mjs +167 -0
  149. package/dist/worker.transport-BhMyvqQ2.mjs.map +1 -0
  150. package/dist/worker.transport-CfH6z37Z.js +168 -0
  151. package/dist/worker.transport-CfH6z37Z.js.map +1 -0
  152. package/dist/worker.transport-mKXgNK0L.d.ts +76 -0
  153. package/dist/worker.transport-mKXgNK0L.d.ts.map +1 -0
  154. package/package.json +23 -18
  155. package/dist/index-CwFww7VC.d.ts.map +0 -1
  156. package/dist/index-DnyeaoZU.d.mts.map +0 -1
  157. package/dist/logitron-logger.module-BCq3sF27.d.mts.map +0 -1
  158. package/dist/logitron-logger.module-BIGTm2V6.mjs.map +0 -1
  159. package/dist/logitron-logger.module-BTxDpK6u.js.map +0 -1
  160. package/dist/logitron-logger.module-BmT-ewin.d.ts.map +0 -1
  161. package/dist/search-Cg_OasF-.d.ts +0 -1
  162. package/dist/search-DN676Dnz.d.mts +0 -1
  163. package/dist/search-DOvSI-mb.mjs +0 -1
  164. package/dist/search-DoZF3RZj.js +0 -0
  165. package/dist/transport.manager-DETpXuaY.mjs.map +0 -1
  166. package/dist/transport.manager-ciG4r5uz.js.map +0 -1
@@ -0,0 +1,3 @@
1
+ import "./transport.types-B5vcyv2k.mjs";
2
+ import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-BP8Q28Z2.mjs";
3
+ export { WorkerTransport, WorkerTransportConfig };
@@ -0,0 +1,3 @@
1
+ import "./transport.types-BuY84TwO.js";
2
+ import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-mKXgNK0L.js";
3
+ export { WorkerTransport, WorkerTransportConfig };
package/dist/worker.js ADDED
@@ -0,0 +1,4 @@
1
+ require('./internal-log-BUJYMZbE.js');
2
+ const require_worker_transport = require('./worker.transport-CfH6z37Z.js');
3
+
4
+ exports.WorkerTransport = require_worker_transport.WorkerTransport;
@@ -0,0 +1,4 @@
1
+ import "./internal-log-Cm8SOWSV.mjs";
2
+ import { t as WorkerTransport } from "./worker.transport-BhMyvqQ2.mjs";
3
+
4
+ export { WorkerTransport };
@@ -0,0 +1,76 @@
1
+ import { l as ITransport, p as TransportLogEntry } from "./transport.types-B5vcyv2k.mjs";
2
+
3
+ //#region src/transports/worker.transport.d.ts
4
+
5
+ interface WorkerTransportConfig {
6
+ /**
7
+ * Which built-in logixia transport to run inside the worker thread.
8
+ * The worker resolves the correct module automatically.
9
+ */
10
+ transportType: 'file' | 'database' | 'console';
11
+ /** Config forwarded verbatim to the wrapped transport constructor. */
12
+ transportConfig: Record<string, unknown>;
13
+ /**
14
+ * Max log entries to buffer in the main thread while the worker is starting
15
+ * or restarting. Entries beyond this limit are dropped with a warning.
16
+ * @default 1000
17
+ */
18
+ bufferSize?: number;
19
+ /**
20
+ * How many times to restart the worker if it crashes unexpectedly.
21
+ * @default 3
22
+ */
23
+ maxRestarts?: number;
24
+ /**
25
+ * Log level filter — only entries at or above this level are forwarded.
26
+ * Useful for routing only errors to an expensive transport in a worker.
27
+ */
28
+ level?: string;
29
+ }
30
+ /**
31
+ * Transport that runs a wrapped transport inside a dedicated Node.js worker
32
+ * thread, completely removing JSON serialization and I/O from the main event loop.
33
+ */
34
+ declare class WorkerTransport implements ITransport {
35
+ readonly name = "worker";
36
+ readonly level: string | undefined;
37
+ readonly batchSize = 1;
38
+ readonly flushInterval = 0;
39
+ private worker;
40
+ private ready;
41
+ private readonly buffer;
42
+ private readonly bufferSize;
43
+ private restarts;
44
+ private readonly maxRestarts;
45
+ private readonly config;
46
+ /** Pending restart-backoff timer, so close() can cancel a queued restart. */
47
+ private restartTimer;
48
+ /** Set once close() begins, so a worker 'exit' no longer triggers a restart. */
49
+ private closing;
50
+ /** Max time to wait for the worker's 'flushed' ack before giving up. */
51
+ private readonly FLUSH_TIMEOUT_MS;
52
+ /** Max time to wait for a graceful worker exit before force-terminating. */
53
+ private readonly SHUTDOWN_TIMEOUT_MS;
54
+ constructor(config: WorkerTransportConfig);
55
+ private startWorker;
56
+ /** The worker entry is always built as CommonJS, next to this module's output. */
57
+ protected workerFile(): string;
58
+ private handleWorkerExit;
59
+ private drainBuffer;
60
+ write(entry: TransportLogEntry): void;
61
+ flush(): Promise<void>;
62
+ /**
63
+ * Flush the worker's buffer and terminate the thread on shutdown.
64
+ *
65
+ * This MUST be named close() — TransportManager.close() invokes
66
+ * transport.close(), so a method named only shutdown() was never called on
67
+ * graceful exit, leaking the worker thread and dropping its buffered logs.
68
+ */
69
+ close(): Promise<void>;
70
+ /** Back-compat alias — prefer close(). */
71
+ shutdown(): Promise<void>;
72
+ private drainBufferTo;
73
+ }
74
+ //#endregion
75
+ export { WorkerTransportConfig as n, WorkerTransport as t };
76
+ //# sourceMappingURL=worker.transport-BP8Q28Z2.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.transport-BP8Q28Z2.d.mts","names":[],"sources":["../src/transports/worker.transport.ts"],"sourcesContent":[],"mappings":";;;;UAuCiB,qBAAA;;;;;;;mBAOE;;;;;;;;;;;;;;;;;;;;;;cAuBN,eAAA,YAA2B;;;;;;;;;;;;;;;;;;;;sBAsBlB;;;;;;eAiFP;WAYE;;;;;;;;WAiCA;;cAkCG"}
@@ -0,0 +1,167 @@
1
+ import { r as internalWarn, t as internalError } from "./internal-log-Cm8SOWSV.mjs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { Worker } from "node:worker_threads";
5
+
6
+ //#region node_modules/tsdown/esm-shims.js
7
+ const getFilename = () => fileURLToPath(import.meta.url);
8
+ const getDirname = () => path.dirname(getFilename());
9
+ const __dirname = /* @__PURE__ */ getDirname();
10
+
11
+ //#endregion
12
+ //#region src/transports/worker.transport.ts
13
+ /**
14
+ * Transport that runs a wrapped transport inside a dedicated Node.js worker
15
+ * thread, completely removing JSON serialization and I/O from the main event loop.
16
+ */
17
+ var WorkerTransport = class {
18
+ constructor(config) {
19
+ this.name = "worker";
20
+ this.batchSize = 1;
21
+ this.flushInterval = 0;
22
+ this.worker = null;
23
+ this.ready = false;
24
+ this.buffer = [];
25
+ this.restarts = 0;
26
+ this.restartTimer = null;
27
+ this.closing = false;
28
+ this.FLUSH_TIMEOUT_MS = 5e3;
29
+ this.SHUTDOWN_TIMEOUT_MS = 5e3;
30
+ this.config = config;
31
+ this.bufferSize = config.bufferSize ?? 1e3;
32
+ this.maxRestarts = config.maxRestarts ?? 3;
33
+ this.level = config.level;
34
+ this.startWorker();
35
+ }
36
+ startWorker() {
37
+ try {
38
+ this.worker = new Worker(this.workerFile(), { workerData: {
39
+ transportType: this.config.transportType,
40
+ transportConfig: this.config.transportConfig
41
+ } });
42
+ this.worker.on("message", (msg) => {
43
+ if (msg.type === "ready") {
44
+ this.ready = true;
45
+ this.drainBuffer();
46
+ } else if (msg.type === "error" || msg.type === "write-error") internalError(`WorkerTransport [${this.config.transportType}]: ${msg.error ?? "unknown"}`);
47
+ });
48
+ this.worker.on("error", (err) => {
49
+ internalError("WorkerTransport worker error", err);
50
+ this.handleWorkerExit();
51
+ });
52
+ this.worker.on("exit", (code) => {
53
+ if (code !== 0) {
54
+ internalWarn(`WorkerTransport worker exited with code ${code}`);
55
+ this.handleWorkerExit();
56
+ }
57
+ });
58
+ } catch (err) {
59
+ internalError("WorkerTransport failed to start", err);
60
+ }
61
+ }
62
+ /** The worker entry is always built as CommonJS, next to this module's output. */
63
+ workerFile() {
64
+ return path.join(__dirname, "worker-entry.js");
65
+ }
66
+ handleWorkerExit() {
67
+ this.ready = false;
68
+ if (this.closing) return;
69
+ if (this.restarts < this.maxRestarts) {
70
+ this.restarts++;
71
+ internalWarn(`WorkerTransport restarting (attempt ${this.restarts}/${this.maxRestarts})`);
72
+ this.restartTimer = setTimeout(() => {
73
+ this.restartTimer = null;
74
+ this.startWorker();
75
+ }, 500 * this.restarts);
76
+ if (this.restartTimer.unref) this.restartTimer.unref();
77
+ } else internalError(`WorkerTransport exhausted ${this.maxRestarts} restart attempts — transport disabled`);
78
+ }
79
+ drainBuffer() {
80
+ while (this.buffer.length > 0 && this.ready && this.worker) {
81
+ const entry = this.buffer.shift();
82
+ if (entry) this.worker.postMessage({
83
+ type: "write",
84
+ entry
85
+ });
86
+ }
87
+ }
88
+ write(entry) {
89
+ if (this.ready && this.worker) this.worker.postMessage({
90
+ type: "write",
91
+ entry
92
+ });
93
+ else {
94
+ if (this.buffer.length >= this.bufferSize) {
95
+ internalWarn("WorkerTransport buffer full — dropping oldest entry");
96
+ this.buffer.shift();
97
+ }
98
+ this.buffer.push(entry);
99
+ }
100
+ }
101
+ async flush() {
102
+ if (!this.ready || !this.worker) return;
103
+ const worker = this.worker;
104
+ return new Promise((resolve) => {
105
+ const timer = setTimeout(() => {
106
+ worker.off("message", handler);
107
+ resolve();
108
+ }, this.FLUSH_TIMEOUT_MS);
109
+ if (timer.unref) timer.unref();
110
+ const handler = (msg) => {
111
+ if (msg.type === "flushed") {
112
+ clearTimeout(timer);
113
+ worker.off("message", handler);
114
+ resolve();
115
+ }
116
+ };
117
+ worker.on("message", handler);
118
+ worker.postMessage({ type: "flush" });
119
+ });
120
+ }
121
+ /**
122
+ * Flush the worker's buffer and terminate the thread on shutdown.
123
+ *
124
+ * This MUST be named close() — TransportManager.close() invokes
125
+ * transport.close(), so a method named only shutdown() was never called on
126
+ * graceful exit, leaking the worker thread and dropping its buffered logs.
127
+ */
128
+ async close() {
129
+ this.closing = true;
130
+ if (this.restartTimer) {
131
+ clearTimeout(this.restartTimer);
132
+ this.restartTimer = null;
133
+ }
134
+ if (!this.worker) return;
135
+ const worker = this.worker;
136
+ this.worker = null;
137
+ this.drainBufferTo(worker);
138
+ worker.postMessage({ type: "shutdown" });
139
+ await new Promise((resolve) => {
140
+ const timer = setTimeout(() => {
141
+ worker.terminate().finally(() => resolve());
142
+ }, this.SHUTDOWN_TIMEOUT_MS);
143
+ if (timer.unref) timer.unref();
144
+ worker.once("exit", () => {
145
+ clearTimeout(timer);
146
+ resolve();
147
+ });
148
+ });
149
+ }
150
+ /** Back-compat alias — prefer close(). */
151
+ async shutdown() {
152
+ await this.close();
153
+ }
154
+ drainBufferTo(worker) {
155
+ while (this.buffer.length > 0) {
156
+ const entry = this.buffer.shift();
157
+ if (entry) worker.postMessage({
158
+ type: "write",
159
+ entry
160
+ });
161
+ }
162
+ }
163
+ };
164
+
165
+ //#endregion
166
+ export { WorkerTransport as t };
167
+ //# sourceMappingURL=worker.transport-BhMyvqQ2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.transport-BhMyvqQ2.mjs","names":[],"sources":["../node_modules/tsdown/esm-shims.js","../src/transports/worker.transport.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * logixia — Worker Thread Transport\n *\n * Offloads JSON serialization and all I/O to a Node.js worker thread,\n * completely eliminating any event-loop impact from logging. The main thread\n * only posts a raw message to the worker — it never calls JSON.stringify or\n * any I/O syscalls on the hot path.\n *\n * Architecture:\n * Main thread → MessageChannel → Worker thread → Wrapped transport\n *\n * The worker runs an ordinary logixia transport (file, database, console…)\n * inside its own event loop. If the worker crashes it is restarted automatically\n * (up to `maxRestarts` times) and buffered messages are replayed.\n *\n * @example\n * ```ts\n * import { WorkerTransport } from 'logixia/worker';\n *\n * const logger = createLogger({\n * transports: {\n * // Run file transport inside a worker thread — zero event-loop impact\n * worker: new WorkerTransport({\n * transportType: 'file',\n * transportConfig: { filename: 'app.log', dirname: './logs' },\n * bufferSize: 500,\n * maxRestarts: 3,\n * }),\n * },\n * });\n * ```\n */\n\nimport path from 'node:path';\nimport { Worker } from 'node:worker_threads';\n\nimport type { ITransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError, internalWarn } from '../utils/internal-log';\n\nexport interface WorkerTransportConfig {\n /**\n * Which built-in logixia transport to run inside the worker thread.\n * The worker resolves the correct module automatically.\n */\n transportType: 'file' | 'database' | 'console';\n /** Config forwarded verbatim to the wrapped transport constructor. */\n transportConfig: Record<string, unknown>;\n /**\n * Max log entries to buffer in the main thread while the worker is starting\n * or restarting. Entries beyond this limit are dropped with a warning.\n * @default 1000\n */\n bufferSize?: number;\n /**\n * How many times to restart the worker if it crashes unexpectedly.\n * @default 3\n */\n maxRestarts?: number;\n /**\n * Log level filter — only entries at or above this level are forwarded.\n * Useful for routing only errors to an expensive transport in a worker.\n */\n level?: string;\n}\n\n/**\n * Transport that runs a wrapped transport inside a dedicated Node.js worker\n * thread, completely removing JSON serialization and I/O from the main event loop.\n */\nexport class WorkerTransport implements ITransport {\n public readonly name = 'worker';\n public readonly level: string | undefined;\n public readonly batchSize = 1;\n public readonly flushInterval = 0;\n\n private worker: Worker | null = null;\n private ready = false;\n private readonly buffer: TransportLogEntry[] = [];\n private readonly bufferSize: number;\n private restarts = 0;\n private readonly maxRestarts: number;\n private readonly config: WorkerTransportConfig;\n /** Pending restart-backoff timer, so close() can cancel a queued restart. */\n private restartTimer: NodeJS.Timeout | null = null;\n /** Set once close() begins, so a worker 'exit' no longer triggers a restart. */\n private closing = false;\n /** Max time to wait for the worker's 'flushed' ack before giving up. */\n private readonly FLUSH_TIMEOUT_MS = 5000;\n /** Max time to wait for a graceful worker exit before force-terminating. */\n private readonly SHUTDOWN_TIMEOUT_MS = 5000;\n\n constructor(config: WorkerTransportConfig) {\n this.config = config;\n this.bufferSize = config.bufferSize ?? 1000;\n this.maxRestarts = config.maxRestarts ?? 3;\n this.level = config.level;\n this.startWorker();\n }\n\n private startWorker(): void {\n try {\n this.worker = new Worker(this.workerFile(), {\n workerData: {\n transportType: this.config.transportType,\n transportConfig: this.config.transportConfig,\n },\n });\n\n this.worker.on('message', (msg: { type: string; error?: string }) => {\n if (msg.type === 'ready') {\n this.ready = true;\n this.drainBuffer();\n } else if (msg.type === 'error' || msg.type === 'write-error') {\n internalError(\n `WorkerTransport [${this.config.transportType}]: ${msg.error ?? 'unknown'}`\n );\n }\n });\n\n this.worker.on('error', (err) => {\n internalError('WorkerTransport worker error', err);\n this.handleWorkerExit();\n });\n\n this.worker.on('exit', (code) => {\n if (code !== 0) {\n internalWarn(`WorkerTransport worker exited with code ${code}`);\n this.handleWorkerExit();\n }\n });\n } catch (err) {\n internalError('WorkerTransport failed to start', err);\n }\n }\n\n /** The worker entry is always built as CommonJS, next to this module's output. */\n protected workerFile(): string {\n return path.join(__dirname, 'worker-entry.js');\n }\n\n private handleWorkerExit(): void {\n this.ready = false;\n // Don't resurrect a worker we're intentionally shutting down — close() sets\n // `closing` and nulls the worker, so a late 'exit'/'error' event must not\n // queue a restart (which would spawn a fresh leaked thread post-shutdown).\n if (this.closing) return;\n if (this.restarts < this.maxRestarts) {\n this.restarts++;\n internalWarn(`WorkerTransport restarting (attempt ${this.restarts}/${this.maxRestarts})`);\n // Small backoff before restart. unref() so a perpetually-failing worker's\n // pending restart never keeps the process alive on its own.\n this.restartTimer = setTimeout(() => {\n this.restartTimer = null;\n this.startWorker();\n }, 500 * this.restarts);\n if (this.restartTimer.unref) this.restartTimer.unref();\n } else {\n internalError(\n `WorkerTransport exhausted ${this.maxRestarts} restart attempts — transport disabled`\n );\n }\n }\n\n private drainBuffer(): void {\n while (this.buffer.length > 0 && this.ready && this.worker) {\n const entry = this.buffer.shift();\n if (entry) {\n this.worker.postMessage({ type: 'write', entry });\n }\n }\n }\n\n write(entry: TransportLogEntry): void {\n if (this.ready && this.worker) {\n this.worker.postMessage({ type: 'write', entry });\n } else {\n if (this.buffer.length >= this.bufferSize) {\n internalWarn('WorkerTransport buffer full — dropping oldest entry');\n this.buffer.shift();\n }\n this.buffer.push(entry);\n }\n }\n\n async flush(): Promise<void> {\n if (!this.ready || !this.worker) return;\n const worker = this.worker;\n return new Promise<void>((resolve) => {\n // Time-box the flush: if the worker dies or restarts before answering,\n // the 'flushed' message would never arrive and this promise would hang\n // forever, blocking shutdown until the force-exit timer kills the process\n // (losing everything). Resolve on timeout so close() can still terminate.\n const timer = setTimeout(() => {\n worker.off('message', handler);\n resolve();\n }, this.FLUSH_TIMEOUT_MS);\n if (timer.unref) timer.unref();\n\n const handler = (msg: { type: string }) => {\n if (msg.type === 'flushed') {\n clearTimeout(timer);\n worker.off('message', handler);\n resolve();\n }\n };\n worker.on('message', handler);\n worker.postMessage({ type: 'flush' });\n });\n }\n\n /**\n * Flush the worker's buffer and terminate the thread on shutdown.\n *\n * This MUST be named close() — TransportManager.close() invokes\n * transport.close(), so a method named only shutdown() was never called on\n * graceful exit, leaking the worker thread and dropping its buffered logs.\n */\n async close(): Promise<void> {\n // Stop the restart loop first: cancel any queued backoff restart and flag\n // that further worker exits are expected (so handleWorkerExit no-ops).\n this.closing = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n\n if (!this.worker) return;\n const worker = this.worker;\n this.worker = null;\n\n // Push any locally-buffered (pre-ready) entries first: the worker's port\n // queues them until its listener attaches, so they are handled before the\n // shutdown message, which flushes the wrapped transport and exits.\n this.drainBufferTo(worker);\n worker.postMessage({ type: 'shutdown' });\n\n await new Promise<void>((resolve) => {\n // Don't wait forever for a wedged worker — terminate() it after a timeout.\n const timer = setTimeout(() => {\n worker.terminate().finally(() => resolve());\n }, this.SHUTDOWN_TIMEOUT_MS);\n if (timer.unref) timer.unref();\n\n worker.once('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n /** Back-compat alias — prefer close(). */\n async shutdown(): Promise<void> {\n await this.close();\n }\n\n private drainBufferTo(worker: Worker): void {\n while (this.buffer.length > 0) {\n const entry = this.buffer.shift();\n if (entry) worker.postMessage({ type: 'write', entry });\n }\n }\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ const require_chunk = require('./chunk-nOFOJqeH.js');
2
+ const require_internal_log = require('./internal-log-BUJYMZbE.js');
3
+ let node_path = require("node:path");
4
+ node_path = require_chunk.__toESM(node_path);
5
+ let node_worker_threads = require("node:worker_threads");
6
+ node_worker_threads = require_chunk.__toESM(node_worker_threads);
7
+
8
+ //#region src/transports/worker.transport.ts
9
+ /**
10
+ * Transport that runs a wrapped transport inside a dedicated Node.js worker
11
+ * thread, completely removing JSON serialization and I/O from the main event loop.
12
+ */
13
+ var WorkerTransport = class {
14
+ constructor(config) {
15
+ this.name = "worker";
16
+ this.batchSize = 1;
17
+ this.flushInterval = 0;
18
+ this.worker = null;
19
+ this.ready = false;
20
+ this.buffer = [];
21
+ this.restarts = 0;
22
+ this.restartTimer = null;
23
+ this.closing = false;
24
+ this.FLUSH_TIMEOUT_MS = 5e3;
25
+ this.SHUTDOWN_TIMEOUT_MS = 5e3;
26
+ this.config = config;
27
+ this.bufferSize = config.bufferSize ?? 1e3;
28
+ this.maxRestarts = config.maxRestarts ?? 3;
29
+ this.level = config.level;
30
+ this.startWorker();
31
+ }
32
+ startWorker() {
33
+ try {
34
+ this.worker = new node_worker_threads.Worker(this.workerFile(), { workerData: {
35
+ transportType: this.config.transportType,
36
+ transportConfig: this.config.transportConfig
37
+ } });
38
+ this.worker.on("message", (msg) => {
39
+ if (msg.type === "ready") {
40
+ this.ready = true;
41
+ this.drainBuffer();
42
+ } else if (msg.type === "error" || msg.type === "write-error") require_internal_log.internalError(`WorkerTransport [${this.config.transportType}]: ${msg.error ?? "unknown"}`);
43
+ });
44
+ this.worker.on("error", (err) => {
45
+ require_internal_log.internalError("WorkerTransport worker error", err);
46
+ this.handleWorkerExit();
47
+ });
48
+ this.worker.on("exit", (code) => {
49
+ if (code !== 0) {
50
+ require_internal_log.internalWarn(`WorkerTransport worker exited with code ${code}`);
51
+ this.handleWorkerExit();
52
+ }
53
+ });
54
+ } catch (err) {
55
+ require_internal_log.internalError("WorkerTransport failed to start", err);
56
+ }
57
+ }
58
+ /** The worker entry is always built as CommonJS, next to this module's output. */
59
+ workerFile() {
60
+ return node_path.default.join(__dirname, "worker-entry.js");
61
+ }
62
+ handleWorkerExit() {
63
+ this.ready = false;
64
+ if (this.closing) return;
65
+ if (this.restarts < this.maxRestarts) {
66
+ this.restarts++;
67
+ require_internal_log.internalWarn(`WorkerTransport restarting (attempt ${this.restarts}/${this.maxRestarts})`);
68
+ this.restartTimer = setTimeout(() => {
69
+ this.restartTimer = null;
70
+ this.startWorker();
71
+ }, 500 * this.restarts);
72
+ if (this.restartTimer.unref) this.restartTimer.unref();
73
+ } else require_internal_log.internalError(`WorkerTransport exhausted ${this.maxRestarts} restart attempts — transport disabled`);
74
+ }
75
+ drainBuffer() {
76
+ while (this.buffer.length > 0 && this.ready && this.worker) {
77
+ const entry = this.buffer.shift();
78
+ if (entry) this.worker.postMessage({
79
+ type: "write",
80
+ entry
81
+ });
82
+ }
83
+ }
84
+ write(entry) {
85
+ if (this.ready && this.worker) this.worker.postMessage({
86
+ type: "write",
87
+ entry
88
+ });
89
+ else {
90
+ if (this.buffer.length >= this.bufferSize) {
91
+ require_internal_log.internalWarn("WorkerTransport buffer full — dropping oldest entry");
92
+ this.buffer.shift();
93
+ }
94
+ this.buffer.push(entry);
95
+ }
96
+ }
97
+ async flush() {
98
+ if (!this.ready || !this.worker) return;
99
+ const worker = this.worker;
100
+ return new Promise((resolve) => {
101
+ const timer = setTimeout(() => {
102
+ worker.off("message", handler);
103
+ resolve();
104
+ }, this.FLUSH_TIMEOUT_MS);
105
+ if (timer.unref) timer.unref();
106
+ const handler = (msg) => {
107
+ if (msg.type === "flushed") {
108
+ clearTimeout(timer);
109
+ worker.off("message", handler);
110
+ resolve();
111
+ }
112
+ };
113
+ worker.on("message", handler);
114
+ worker.postMessage({ type: "flush" });
115
+ });
116
+ }
117
+ /**
118
+ * Flush the worker's buffer and terminate the thread on shutdown.
119
+ *
120
+ * This MUST be named close() — TransportManager.close() invokes
121
+ * transport.close(), so a method named only shutdown() was never called on
122
+ * graceful exit, leaking the worker thread and dropping its buffered logs.
123
+ */
124
+ async close() {
125
+ this.closing = true;
126
+ if (this.restartTimer) {
127
+ clearTimeout(this.restartTimer);
128
+ this.restartTimer = null;
129
+ }
130
+ if (!this.worker) return;
131
+ const worker = this.worker;
132
+ this.worker = null;
133
+ this.drainBufferTo(worker);
134
+ worker.postMessage({ type: "shutdown" });
135
+ await new Promise((resolve) => {
136
+ const timer = setTimeout(() => {
137
+ worker.terminate().finally(() => resolve());
138
+ }, this.SHUTDOWN_TIMEOUT_MS);
139
+ if (timer.unref) timer.unref();
140
+ worker.once("exit", () => {
141
+ clearTimeout(timer);
142
+ resolve();
143
+ });
144
+ });
145
+ }
146
+ /** Back-compat alias — prefer close(). */
147
+ async shutdown() {
148
+ await this.close();
149
+ }
150
+ drainBufferTo(worker) {
151
+ while (this.buffer.length > 0) {
152
+ const entry = this.buffer.shift();
153
+ if (entry) worker.postMessage({
154
+ type: "write",
155
+ entry
156
+ });
157
+ }
158
+ }
159
+ };
160
+
161
+ //#endregion
162
+ Object.defineProperty(exports, 'WorkerTransport', {
163
+ enumerable: true,
164
+ get: function () {
165
+ return WorkerTransport;
166
+ }
167
+ });
168
+ //# sourceMappingURL=worker.transport-CfH6z37Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.transport-CfH6z37Z.js","names":["Worker","path"],"sources":["../src/transports/worker.transport.ts"],"sourcesContent":["/**\n * logixia — Worker Thread Transport\n *\n * Offloads JSON serialization and all I/O to a Node.js worker thread,\n * completely eliminating any event-loop impact from logging. The main thread\n * only posts a raw message to the worker — it never calls JSON.stringify or\n * any I/O syscalls on the hot path.\n *\n * Architecture:\n * Main thread → MessageChannel → Worker thread → Wrapped transport\n *\n * The worker runs an ordinary logixia transport (file, database, console…)\n * inside its own event loop. If the worker crashes it is restarted automatically\n * (up to `maxRestarts` times) and buffered messages are replayed.\n *\n * @example\n * ```ts\n * import { WorkerTransport } from 'logixia/worker';\n *\n * const logger = createLogger({\n * transports: {\n * // Run file transport inside a worker thread — zero event-loop impact\n * worker: new WorkerTransport({\n * transportType: 'file',\n * transportConfig: { filename: 'app.log', dirname: './logs' },\n * bufferSize: 500,\n * maxRestarts: 3,\n * }),\n * },\n * });\n * ```\n */\n\nimport path from 'node:path';\nimport { Worker } from 'node:worker_threads';\n\nimport type { ITransport, TransportLogEntry } from '../types/transport.types';\nimport { internalError, internalWarn } from '../utils/internal-log';\n\nexport interface WorkerTransportConfig {\n /**\n * Which built-in logixia transport to run inside the worker thread.\n * The worker resolves the correct module automatically.\n */\n transportType: 'file' | 'database' | 'console';\n /** Config forwarded verbatim to the wrapped transport constructor. */\n transportConfig: Record<string, unknown>;\n /**\n * Max log entries to buffer in the main thread while the worker is starting\n * or restarting. Entries beyond this limit are dropped with a warning.\n * @default 1000\n */\n bufferSize?: number;\n /**\n * How many times to restart the worker if it crashes unexpectedly.\n * @default 3\n */\n maxRestarts?: number;\n /**\n * Log level filter — only entries at or above this level are forwarded.\n * Useful for routing only errors to an expensive transport in a worker.\n */\n level?: string;\n}\n\n/**\n * Transport that runs a wrapped transport inside a dedicated Node.js worker\n * thread, completely removing JSON serialization and I/O from the main event loop.\n */\nexport class WorkerTransport implements ITransport {\n public readonly name = 'worker';\n public readonly level: string | undefined;\n public readonly batchSize = 1;\n public readonly flushInterval = 0;\n\n private worker: Worker | null = null;\n private ready = false;\n private readonly buffer: TransportLogEntry[] = [];\n private readonly bufferSize: number;\n private restarts = 0;\n private readonly maxRestarts: number;\n private readonly config: WorkerTransportConfig;\n /** Pending restart-backoff timer, so close() can cancel a queued restart. */\n private restartTimer: NodeJS.Timeout | null = null;\n /** Set once close() begins, so a worker 'exit' no longer triggers a restart. */\n private closing = false;\n /** Max time to wait for the worker's 'flushed' ack before giving up. */\n private readonly FLUSH_TIMEOUT_MS = 5000;\n /** Max time to wait for a graceful worker exit before force-terminating. */\n private readonly SHUTDOWN_TIMEOUT_MS = 5000;\n\n constructor(config: WorkerTransportConfig) {\n this.config = config;\n this.bufferSize = config.bufferSize ?? 1000;\n this.maxRestarts = config.maxRestarts ?? 3;\n this.level = config.level;\n this.startWorker();\n }\n\n private startWorker(): void {\n try {\n this.worker = new Worker(this.workerFile(), {\n workerData: {\n transportType: this.config.transportType,\n transportConfig: this.config.transportConfig,\n },\n });\n\n this.worker.on('message', (msg: { type: string; error?: string }) => {\n if (msg.type === 'ready') {\n this.ready = true;\n this.drainBuffer();\n } else if (msg.type === 'error' || msg.type === 'write-error') {\n internalError(\n `WorkerTransport [${this.config.transportType}]: ${msg.error ?? 'unknown'}`\n );\n }\n });\n\n this.worker.on('error', (err) => {\n internalError('WorkerTransport worker error', err);\n this.handleWorkerExit();\n });\n\n this.worker.on('exit', (code) => {\n if (code !== 0) {\n internalWarn(`WorkerTransport worker exited with code ${code}`);\n this.handleWorkerExit();\n }\n });\n } catch (err) {\n internalError('WorkerTransport failed to start', err);\n }\n }\n\n /** The worker entry is always built as CommonJS, next to this module's output. */\n protected workerFile(): string {\n return path.join(__dirname, 'worker-entry.js');\n }\n\n private handleWorkerExit(): void {\n this.ready = false;\n // Don't resurrect a worker we're intentionally shutting down — close() sets\n // `closing` and nulls the worker, so a late 'exit'/'error' event must not\n // queue a restart (which would spawn a fresh leaked thread post-shutdown).\n if (this.closing) return;\n if (this.restarts < this.maxRestarts) {\n this.restarts++;\n internalWarn(`WorkerTransport restarting (attempt ${this.restarts}/${this.maxRestarts})`);\n // Small backoff before restart. unref() so a perpetually-failing worker's\n // pending restart never keeps the process alive on its own.\n this.restartTimer = setTimeout(() => {\n this.restartTimer = null;\n this.startWorker();\n }, 500 * this.restarts);\n if (this.restartTimer.unref) this.restartTimer.unref();\n } else {\n internalError(\n `WorkerTransport exhausted ${this.maxRestarts} restart attempts — transport disabled`\n );\n }\n }\n\n private drainBuffer(): void {\n while (this.buffer.length > 0 && this.ready && this.worker) {\n const entry = this.buffer.shift();\n if (entry) {\n this.worker.postMessage({ type: 'write', entry });\n }\n }\n }\n\n write(entry: TransportLogEntry): void {\n if (this.ready && this.worker) {\n this.worker.postMessage({ type: 'write', entry });\n } else {\n if (this.buffer.length >= this.bufferSize) {\n internalWarn('WorkerTransport buffer full — dropping oldest entry');\n this.buffer.shift();\n }\n this.buffer.push(entry);\n }\n }\n\n async flush(): Promise<void> {\n if (!this.ready || !this.worker) return;\n const worker = this.worker;\n return new Promise<void>((resolve) => {\n // Time-box the flush: if the worker dies or restarts before answering,\n // the 'flushed' message would never arrive and this promise would hang\n // forever, blocking shutdown until the force-exit timer kills the process\n // (losing everything). Resolve on timeout so close() can still terminate.\n const timer = setTimeout(() => {\n worker.off('message', handler);\n resolve();\n }, this.FLUSH_TIMEOUT_MS);\n if (timer.unref) timer.unref();\n\n const handler = (msg: { type: string }) => {\n if (msg.type === 'flushed') {\n clearTimeout(timer);\n worker.off('message', handler);\n resolve();\n }\n };\n worker.on('message', handler);\n worker.postMessage({ type: 'flush' });\n });\n }\n\n /**\n * Flush the worker's buffer and terminate the thread on shutdown.\n *\n * This MUST be named close() — TransportManager.close() invokes\n * transport.close(), so a method named only shutdown() was never called on\n * graceful exit, leaking the worker thread and dropping its buffered logs.\n */\n async close(): Promise<void> {\n // Stop the restart loop first: cancel any queued backoff restart and flag\n // that further worker exits are expected (so handleWorkerExit no-ops).\n this.closing = true;\n if (this.restartTimer) {\n clearTimeout(this.restartTimer);\n this.restartTimer = null;\n }\n\n if (!this.worker) return;\n const worker = this.worker;\n this.worker = null;\n\n // Push any locally-buffered (pre-ready) entries first: the worker's port\n // queues them until its listener attaches, so they are handled before the\n // shutdown message, which flushes the wrapped transport and exits.\n this.drainBufferTo(worker);\n worker.postMessage({ type: 'shutdown' });\n\n await new Promise<void>((resolve) => {\n // Don't wait forever for a wedged worker — terminate() it after a timeout.\n const timer = setTimeout(() => {\n worker.terminate().finally(() => resolve());\n }, this.SHUTDOWN_TIMEOUT_MS);\n if (timer.unref) timer.unref();\n\n worker.once('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n /** Back-compat alias — prefer close(). */\n async shutdown(): Promise<void> {\n await this.close();\n }\n\n private drainBufferTo(worker: Worker): void {\n while (this.buffer.length > 0) {\n const entry = this.buffer.shift();\n if (entry) worker.postMessage({ type: 'write', entry });\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { l as ITransport, p as TransportLogEntry } from "./transport.types-BuY84TwO.js";
2
+
3
+ //#region src/transports/worker.transport.d.ts
4
+
5
+ interface WorkerTransportConfig {
6
+ /**
7
+ * Which built-in logixia transport to run inside the worker thread.
8
+ * The worker resolves the correct module automatically.
9
+ */
10
+ transportType: 'file' | 'database' | 'console';
11
+ /** Config forwarded verbatim to the wrapped transport constructor. */
12
+ transportConfig: Record<string, unknown>;
13
+ /**
14
+ * Max log entries to buffer in the main thread while the worker is starting
15
+ * or restarting. Entries beyond this limit are dropped with a warning.
16
+ * @default 1000
17
+ */
18
+ bufferSize?: number;
19
+ /**
20
+ * How many times to restart the worker if it crashes unexpectedly.
21
+ * @default 3
22
+ */
23
+ maxRestarts?: number;
24
+ /**
25
+ * Log level filter — only entries at or above this level are forwarded.
26
+ * Useful for routing only errors to an expensive transport in a worker.
27
+ */
28
+ level?: string;
29
+ }
30
+ /**
31
+ * Transport that runs a wrapped transport inside a dedicated Node.js worker
32
+ * thread, completely removing JSON serialization and I/O from the main event loop.
33
+ */
34
+ declare class WorkerTransport implements ITransport {
35
+ readonly name = "worker";
36
+ readonly level: string | undefined;
37
+ readonly batchSize = 1;
38
+ readonly flushInterval = 0;
39
+ private worker;
40
+ private ready;
41
+ private readonly buffer;
42
+ private readonly bufferSize;
43
+ private restarts;
44
+ private readonly maxRestarts;
45
+ private readonly config;
46
+ /** Pending restart-backoff timer, so close() can cancel a queued restart. */
47
+ private restartTimer;
48
+ /** Set once close() begins, so a worker 'exit' no longer triggers a restart. */
49
+ private closing;
50
+ /** Max time to wait for the worker's 'flushed' ack before giving up. */
51
+ private readonly FLUSH_TIMEOUT_MS;
52
+ /** Max time to wait for a graceful worker exit before force-terminating. */
53
+ private readonly SHUTDOWN_TIMEOUT_MS;
54
+ constructor(config: WorkerTransportConfig);
55
+ private startWorker;
56
+ /** The worker entry is always built as CommonJS, next to this module's output. */
57
+ protected workerFile(): string;
58
+ private handleWorkerExit;
59
+ private drainBuffer;
60
+ write(entry: TransportLogEntry): void;
61
+ flush(): Promise<void>;
62
+ /**
63
+ * Flush the worker's buffer and terminate the thread on shutdown.
64
+ *
65
+ * This MUST be named close() — TransportManager.close() invokes
66
+ * transport.close(), so a method named only shutdown() was never called on
67
+ * graceful exit, leaking the worker thread and dropping its buffered logs.
68
+ */
69
+ close(): Promise<void>;
70
+ /** Back-compat alias — prefer close(). */
71
+ shutdown(): Promise<void>;
72
+ private drainBufferTo;
73
+ }
74
+ //#endregion
75
+ export { WorkerTransportConfig as n, WorkerTransport as t };
76
+ //# sourceMappingURL=worker.transport-mKXgNK0L.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.transport-mKXgNK0L.d.ts","names":[],"sources":["../src/transports/worker.transport.ts"],"sourcesContent":[],"mappings":";;;;UAuCiB,qBAAA;;;;;;;mBAOE;;;;;;;;;;;;;;;;;;;;;;cAuBN,eAAA,YAA2B;;;;;;;;;;;;;;;;;;;;sBAsBlB;;;;;;eAiFP;WAYE;;;;;;;;WAiCA;;cAkCG"}