logixia 2.0.11 → 2.1.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.
- package/README.md +2 -1
- package/dist/{async-context-D8um9I5V.js → async-context-Dgl3ZLyb.js} +3 -3
- package/dist/{async-context-D8um9I5V.js.map → async-context-Dgl3ZLyb.js.map} +1 -1
- package/dist/{async-context-BGUCdYAa.mjs → async-context-fBqC5lNc.mjs} +2 -2
- package/dist/{async-context-BGUCdYAa.mjs.map → async-context-fBqC5lNc.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts → azure-monitor.transport-C5VjvREZ.d.mts} +2 -2
- package/dist/{azure-monitor.transport-CbSHOnNX.d.mts.map → azure-monitor.transport-C5VjvREZ.d.mts.map} +1 -1
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts → azure-monitor.transport-CyHDjHS-.d.ts} +2 -2
- package/dist/{azure-monitor.transport-Bvf7Xegt.d.ts.map → azure-monitor.transport-CyHDjHS-.d.ts.map} +1 -1
- package/dist/{azure-monitor.transport-CTnfwA0F.mjs → azure-monitor.transport-DGiacfvT.mjs} +4 -4
- package/dist/{azure-monitor.transport-CTnfwA0F.mjs.map → azure-monitor.transport-DGiacfvT.mjs.map} +1 -1
- package/dist/{azure-monitor.transport-C8KdmsSw.js → azure-monitor.transport-DX3fuK2t.js} +4 -4
- package/dist/{azure-monitor.transport-C8KdmsSw.js.map → azure-monitor.transport-DX3fuK2t.js.map} +1 -1
- package/dist/azure.d.mts +1 -1
- package/dist/azure.d.ts +1 -1
- package/dist/azure.js +1 -1
- package/dist/azure.mjs +1 -1
- package/dist/{batch-buffer-BTQdAXwC.js → batch-buffer-BLmVvJAZ.js} +2 -2
- package/dist/{batch-buffer-BTQdAXwC.js.map → batch-buffer-BLmVvJAZ.js.map} +1 -1
- package/dist/{batch-buffer-BJqzpfpT.mjs → batch-buffer-CM-lK_Qy.mjs} +2 -2
- package/dist/{batch-buffer-BJqzpfpT.mjs.map → batch-buffer-CM-lK_Qy.mjs.map} +1 -1
- package/dist/browser.d.mts +2 -0
- package/dist/browser.d.mts.map +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +18 -4
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +18 -4
- package/dist/browser.mjs.map +1 -1
- package/dist/{builder-C6kKEVrU.mjs → builder-CA_dokb4.mjs} +108 -61
- package/dist/builder-CA_dokb4.mjs.map +1 -0
- package/dist/{builder-Up4YxX7l.js → builder-jMlVYaQa.js} +114 -67
- package/dist/builder-jMlVYaQa.js.map +1 -0
- package/dist/cloudwatch.d.mts +1 -1
- package/dist/cloudwatch.d.ts +1 -1
- package/dist/cloudwatch.js +1 -1
- package/dist/cloudwatch.mjs +1 -1
- package/dist/{cloudwatch.transport-Bl1qzdBx.mjs → cloudwatch.transport-Cr0fEpko.mjs} +5 -5
- package/dist/{cloudwatch.transport-Bl1qzdBx.mjs.map → cloudwatch.transport-Cr0fEpko.mjs.map} +1 -1
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts → cloudwatch.transport-DdSjUWvu.d.ts} +2 -2
- package/dist/{cloudwatch.transport-CQyT6U91.d.ts.map → cloudwatch.transport-DdSjUWvu.d.ts.map} +1 -1
- package/dist/{cloudwatch.transport-BoCyxNKO.js → cloudwatch.transport-Lst1Bbmr.js} +5 -5
- package/dist/{cloudwatch.transport-BoCyxNKO.js.map → cloudwatch.transport-Lst1Bbmr.js.map} +1 -1
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts → cloudwatch.transport-_hS7Mcc5.d.mts} +2 -2
- package/dist/{cloudwatch.transport-CjVrI6S4.d.mts.map → cloudwatch.transport-_hS7Mcc5.d.mts.map} +1 -1
- package/dist/correlation.js +2 -2
- package/dist/correlation.mjs +2 -2
- package/dist/{entry-fields-CJbeaoBs.js → entry-fields-BSLkzw18.js} +3 -3
- package/dist/{entry-fields-CJbeaoBs.js.map → entry-fields-BSLkzw18.js.map} +1 -1
- package/dist/{entry-fields-D_aNnjg0.mjs → entry-fields-J1OBi24o.mjs} +2 -2
- package/dist/{entry-fields-D_aNnjg0.mjs.map → entry-fields-J1OBi24o.mjs.map} +1 -1
- package/dist/gcp.d.mts +1 -1
- package/dist/gcp.d.ts +1 -1
- package/dist/gcp.js +1 -1
- package/dist/gcp.mjs +1 -1
- package/dist/{gcp.transport-D_NHVZrw.js → gcp.transport-5-ZIjN8r.js} +5 -5
- package/dist/{gcp.transport-D_NHVZrw.js.map → gcp.transport-5-ZIjN8r.js.map} +1 -1
- package/dist/{gcp.transport-D9SdLPwP.d.mts → gcp.transport-C8VJiEM7.d.mts} +2 -2
- package/dist/{gcp.transport-D9SdLPwP.d.mts.map → gcp.transport-C8VJiEM7.d.mts.map} +1 -1
- package/dist/{gcp.transport-BCIvdFV-.d.ts → gcp.transport-Ct0BtKFo.d.ts} +2 -2
- package/dist/{gcp.transport-BCIvdFV-.d.ts.map → gcp.transport-Ct0BtKFo.d.ts.map} +1 -1
- package/dist/{gcp.transport-DOH4bpWM.mjs → gcp.transport-Cw3Qke85.mjs} +5 -5
- package/dist/{gcp.transport-DOH4bpWM.mjs.map → gcp.transport-Cw3Qke85.mjs.map} +1 -1
- package/dist/{index-BAkPHp5D.d.mts → index-B3ajtXJd.d.mts} +2 -2
- package/dist/{index-BAkPHp5D.d.mts.map → index-B3ajtXJd.d.mts.map} +1 -1
- package/dist/{index-e7LowmAu.d.ts → index-oqD3WNxf.d.ts} +2 -2
- package/dist/{index-e7LowmAu.d.ts.map → index-oqD3WNxf.d.ts.map} +1 -1
- package/dist/index.d.mts +8 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -8
- package/dist/index.mjs.map +1 -1
- package/dist/{logitron-logger-DVUdgmBY.d.ts → logitron-logger-Csn3e6Qu.d.ts} +2 -2
- package/dist/{logitron-logger-DVUdgmBY.d.ts.map → logitron-logger-Csn3e6Qu.d.ts.map} +1 -1
- package/dist/{logitron-logger-DoWmMjYB.d.mts → logitron-logger-fMOkXr8H.d.mts} +2 -2
- package/dist/{logitron-logger-DoWmMjYB.d.mts.map → logitron-logger-fMOkXr8H.d.mts.map} +1 -1
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.js +5 -4
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +3 -2
- package/dist/middleware.mjs.map +1 -1
- package/dist/nest.d.mts +47 -15
- package/dist/nest.d.mts.map +1 -1
- package/dist/nest.d.ts +47 -15
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +169 -48
- package/dist/nest.js.map +1 -1
- package/dist/nest.mjs +166 -45
- package/dist/nest.mjs.map +1 -1
- package/dist/{otel-DH6-G6DR.js → otel-8ypFGG19.js} +319 -66
- package/dist/otel-8ypFGG19.js.map +1 -0
- package/dist/{otel-DAVxpArV.mjs → otel-b-s2QbY4.mjs} +319 -66
- package/dist/otel-b-s2QbY4.mjs.map +1 -0
- package/dist/own-property-BWkibepN.js +40 -0
- package/dist/own-property-BWkibepN.js.map +1 -0
- package/dist/own-property-CjFw9qwZ.mjs +29 -0
- package/dist/own-property-CjFw9qwZ.mjs.map +1 -0
- package/dist/{safe-stringify-pZOnzGRJ.mjs → safe-stringify-B5p5ktFe.mjs} +2 -2
- package/dist/{safe-stringify-pZOnzGRJ.mjs.map → safe-stringify-B5p5ktFe.mjs.map} +1 -1
- package/dist/{safe-stringify-CJisLyZ3.js → safe-stringify-J3sh-7YM.js} +5 -5
- package/dist/{safe-stringify-CJisLyZ3.js.map → safe-stringify-J3sh-7YM.js.map} +1 -1
- package/dist/{search-Crf2IEoA.d.mts → search-B-hJe2N-.d.mts} +7 -3
- package/dist/{search-Crf2IEoA.d.mts.map → search-B-hJe2N-.d.mts.map} +1 -1
- package/dist/{search-B4eEzrhM.d.ts → search-BlKBLm5D.d.ts} +7 -3
- package/dist/{search-B4eEzrhM.d.ts.map → search-BlKBLm5D.d.ts.map} +1 -1
- package/dist/{search-CjYl-mo5.mjs → search-CTR4XNHq.mjs} +52 -14
- package/dist/search-CTR4XNHq.mjs.map +1 -0
- package/dist/{search-CJw_xoQl.js → search-_qx4YzRP.js} +52 -14
- package/dist/search-_qx4YzRP.js.map +1 -0
- package/dist/search.d.mts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.js +1 -1
- package/dist/search.mjs +1 -1
- package/dist/{secret-config-6hdODxBb.js → secret-config--cVTOWwp.js} +6 -5
- package/dist/{secret-config-6hdODxBb.js.map → secret-config--cVTOWwp.js.map} +1 -1
- package/dist/{secret-config-D1F4MW69.mjs → secret-config-GKmb15Me.mjs} +3 -2
- package/dist/{secret-config-D1F4MW69.mjs.map → secret-config-GKmb15Me.mjs.map} +1 -1
- package/dist/{sensitive-names-wv27qBQC.mjs → sensitive-names-BiBM6R1X.mjs} +2 -28
- package/dist/sensitive-names-BiBM6R1X.mjs.map +1 -0
- package/dist/{sensitive-names-CNgHaqv9.js → sensitive-names-NiKIRhp5.js} +1 -39
- package/dist/sensitive-names-NiKIRhp5.js.map +1 -0
- package/dist/{slack.transport-C6E0l4kw.d.ts → slack.transport-5OPL7H3u.d.mts} +76 -3
- package/dist/slack.transport-5OPL7H3u.d.mts.map +1 -0
- package/dist/{slack.transport-BDyENuR0.d.mts → slack.transport-BFpBD_Ri.d.ts} +76 -3
- package/dist/slack.transport-BFpBD_Ri.d.ts.map +1 -0
- package/dist/{slack.transport-CEYBVzUj.js → slack.transport-Cpx5fKga.js} +231 -8
- package/dist/slack.transport-Cpx5fKga.js.map +1 -0
- package/dist/{slack.transport-YvaLJxNv.mjs → slack.transport-Qwj9WkrJ.mjs} +226 -9
- package/dist/slack.transport-Qwj9WkrJ.mjs.map +1 -0
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/{transport.types-CzJq4IrF.d.ts → transport.types-B1ejJJP6.d.mts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.mts.map +1 -0
- package/dist/{transport.types-CzJq4IrF.d.mts → transport.types-B1ejJJP6.d.ts} +6 -1
- package/dist/transport.types-B1ejJJP6.d.ts.map +1 -0
- package/dist/transports.d.mts +61 -11
- package/dist/transports.d.mts.map +1 -1
- package/dist/transports.d.ts +61 -11
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +7 -6
- package/dist/transports.mjs +7 -7
- package/dist/worker-entry.js +91 -11
- package/dist/worker.d.mts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.mjs +1 -1
- package/dist/{worker.transport-B9mCQSM1.d.ts → worker.transport-B7olL1Uh.d.ts} +12 -2
- package/dist/worker.transport-B7olL1Uh.d.ts.map +1 -0
- package/dist/{worker.transport-DgK_ZXlB.mjs → worker.transport-BHnWDXPH.mjs} +40 -2
- package/dist/worker.transport-BHnWDXPH.mjs.map +1 -0
- package/dist/{worker.transport-CwNpH98o.js → worker.transport-C7jNGhev.js} +40 -2
- package/dist/worker.transport-C7jNGhev.js.map +1 -0
- package/dist/{worker.transport-Bl8lFRck.d.mts → worker.transport-DnU0_9Bd.d.mts} +12 -2
- package/dist/worker.transport-DnU0_9Bd.d.mts.map +1 -0
- package/package.json +1 -1
- package/dist/builder-C6kKEVrU.mjs.map +0 -1
- package/dist/builder-Up4YxX7l.js.map +0 -1
- package/dist/otel-DAVxpArV.mjs.map +0 -1
- package/dist/otel-DH6-G6DR.js.map +0 -1
- package/dist/search-CJw_xoQl.js.map +0 -1
- package/dist/search-CjYl-mo5.mjs.map +0 -1
- package/dist/sensitive-names-CNgHaqv9.js.map +0 -1
- package/dist/sensitive-names-wv27qBQC.mjs.map +0 -1
- package/dist/slack.transport-BDyENuR0.d.mts.map +0 -1
- package/dist/slack.transport-C6E0l4kw.d.ts.map +0 -1
- package/dist/slack.transport-CEYBVzUj.js.map +0 -1
- package/dist/slack.transport-YvaLJxNv.mjs.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.mts.map +0 -1
- package/dist/transport.types-CzJq4IrF.d.ts.map +0 -1
- package/dist/worker.transport-B9mCQSM1.d.ts.map +0 -1
- package/dist/worker.transport-Bl8lFRck.d.mts.map +0 -1
- package/dist/worker.transport-CwNpH98o.js.map +0 -1
- package/dist/worker.transport-DgK_ZXlB.mjs.map +0 -1
package/dist/transports.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_otel = require("./otel-
|
|
3
|
-
const require_slack_transport = require("./slack.transport-
|
|
4
|
-
const require_azure_monitor_transport = require("./azure-monitor.transport-
|
|
5
|
-
const require_cloudwatch_transport = require("./cloudwatch.transport-
|
|
6
|
-
const require_gcp_transport = require("./gcp.transport-
|
|
7
|
-
const require_worker_transport = require("./worker.transport-
|
|
2
|
+
const require_otel = require("./otel-8ypFGG19.js");
|
|
3
|
+
const require_slack_transport = require("./slack.transport-Cpx5fKga.js");
|
|
4
|
+
const require_azure_monitor_transport = require("./azure-monitor.transport-DX3fuK2t.js");
|
|
5
|
+
const require_cloudwatch_transport = require("./cloudwatch.transport-Lst1Bbmr.js");
|
|
6
|
+
const require_gcp_transport = require("./gcp.transport-5-ZIjN8r.js");
|
|
7
|
+
const require_worker_transport = require("./worker.transport-C7jNGhev.js");
|
|
8
8
|
exports.AnalyticsTransport = require_otel.AnalyticsTransport;
|
|
9
9
|
exports.AzureMonitorTransport = require_azure_monitor_transport.AzureMonitorTransport;
|
|
10
10
|
exports.CloudWatchTransport = require_cloudwatch_transport.CloudWatchTransport;
|
|
@@ -18,6 +18,7 @@ exports.GoogleAnalyticsTransport = require_otel.GoogleAnalyticsTransport;
|
|
|
18
18
|
exports.MixpanelTransport = require_otel.MixpanelTransport;
|
|
19
19
|
exports.OtlpLogTransport = require_slack_transport.OtlpLogTransport;
|
|
20
20
|
exports.SegmentTransport = require_otel.SegmentTransport;
|
|
21
|
+
exports.SentryTransport = require_slack_transport.SentryTransport;
|
|
21
22
|
exports.SlackTransport = require_slack_transport.SlackTransport;
|
|
22
23
|
exports.TransportManager = require_otel.TransportManager;
|
|
23
24
|
exports.WorkerTransport = require_worker_transport.WorkerTransport;
|
package/dist/transports.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as ConsoleTransport, c as TransportManager, d as GoogleAnalyticsTransport, f as FileTransport, h as DatabaseTransport, l as SegmentTransport, m as AnalyticsTransport, p as DataDogTransport, u as MixpanelTransport } from "./otel-
|
|
2
|
-
import {
|
|
3
|
-
import { t as AzureMonitorTransport } from "./azure-monitor.transport-
|
|
4
|
-
import { t as CloudWatchTransport } from "./cloudwatch.transport-
|
|
5
|
-
import { t as GCPTransport } from "./gcp.transport-
|
|
6
|
-
import { t as WorkerTransport } from "./worker.transport-
|
|
7
|
-
export { AnalyticsTransport, AzureMonitorTransport, CloudWatchTransport, ConsoleTransport, DataDogTransport, DatabaseTransport, DiscordTransport, FileTransport, GCPTransport, GoogleAnalyticsTransport, MixpanelTransport, OtlpLogTransport, SegmentTransport, SlackTransport, TransportManager, WorkerTransport, toOtelSeverity };
|
|
1
|
+
import { _ as ConsoleTransport, c as TransportManager, d as GoogleAnalyticsTransport, f as FileTransport, h as DatabaseTransport, l as SegmentTransport, m as AnalyticsTransport, p as DataDogTransport, u as MixpanelTransport } from "./otel-b-s2QbY4.mjs";
|
|
2
|
+
import { a as toOtelSeverity, i as OtlpLogTransport, n as SentryTransport, r as DiscordTransport, t as SlackTransport } from "./slack.transport-Qwj9WkrJ.mjs";
|
|
3
|
+
import { t as AzureMonitorTransport } from "./azure-monitor.transport-DGiacfvT.mjs";
|
|
4
|
+
import { t as CloudWatchTransport } from "./cloudwatch.transport-Cr0fEpko.mjs";
|
|
5
|
+
import { t as GCPTransport } from "./gcp.transport-Cw3Qke85.mjs";
|
|
6
|
+
import { t as WorkerTransport } from "./worker.transport-BHnWDXPH.mjs";
|
|
7
|
+
export { AnalyticsTransport, AzureMonitorTransport, CloudWatchTransport, ConsoleTransport, DataDogTransport, DatabaseTransport, DiscordTransport, FileTransport, GCPTransport, GoogleAnalyticsTransport, MixpanelTransport, OtlpLogTransport, SegmentTransport, SentryTransport, SlackTransport, TransportManager, WorkerTransport, toOtelSeverity };
|
package/dist/worker-entry.js
CHANGED
|
@@ -781,6 +781,7 @@ function isDataError(type, error) {
|
|
|
781
781
|
return false;
|
|
782
782
|
}
|
|
783
783
|
/** A write that stored part of a batch: only `remaining` still needs to be written. */
|
|
784
|
+
var DatabaseUnavailableError = class extends Error {};
|
|
784
785
|
var PartialWriteError = class extends Error {
|
|
785
786
|
remaining;
|
|
786
787
|
constructor(message, remaining, cause) {
|
|
@@ -828,6 +829,8 @@ var DatabaseTransport = class {
|
|
|
828
829
|
connection;
|
|
829
830
|
isConnected = false;
|
|
830
831
|
connectionPromise;
|
|
832
|
+
connectFailures = 0;
|
|
833
|
+
nextConnectAt = 0;
|
|
831
834
|
cap;
|
|
832
835
|
constructor(config) {
|
|
833
836
|
this.config = config;
|
|
@@ -849,9 +852,12 @@ var DatabaseTransport = class {
|
|
|
849
852
|
];
|
|
850
853
|
}
|
|
851
854
|
async write(entry) {
|
|
852
|
-
if (!this.isConnected) await this.connect();
|
|
853
855
|
this.addToBatch(entry);
|
|
854
|
-
if (this.batch.length >= this.batchSize)
|
|
856
|
+
if (this.batch.length >= this.batchSize) try {
|
|
857
|
+
await this.flush();
|
|
858
|
+
} catch (error) {
|
|
859
|
+
if (!(error instanceof DatabaseUnavailableError)) throw error;
|
|
860
|
+
}
|
|
855
861
|
}
|
|
856
862
|
addToBatch(entry) {
|
|
857
863
|
this.batch.push(entry);
|
|
@@ -876,6 +882,7 @@ var DatabaseTransport = class {
|
|
|
876
882
|
*/
|
|
877
883
|
async drain() {
|
|
878
884
|
while (this.batch.length > 0) {
|
|
885
|
+
await this.ensureConnected();
|
|
879
886
|
const entries = this.batch.splice(0, this.batchSize);
|
|
880
887
|
try {
|
|
881
888
|
await this.writeEntries(entries);
|
|
@@ -973,6 +980,38 @@ var DatabaseTransport = class {
|
|
|
973
980
|
return false;
|
|
974
981
|
}
|
|
975
982
|
}
|
|
983
|
+
async ensureConnected() {
|
|
984
|
+
if (this.isConnected) return;
|
|
985
|
+
const wait = this.nextConnectAt - Date.now();
|
|
986
|
+
if (wait > 0) throw new DatabaseUnavailableError(`Database unavailable; next connect attempt in ${wait}ms`);
|
|
987
|
+
try {
|
|
988
|
+
await this.connect();
|
|
989
|
+
this.connectFailures = 0;
|
|
990
|
+
} catch (error) {
|
|
991
|
+
this.connectFailures += 1;
|
|
992
|
+
this.nextConnectAt = Date.now() + Math.min(3e4, 1e3 * 2 ** (this.connectFailures - 1));
|
|
993
|
+
internalError("Database connection error", error);
|
|
994
|
+
throw new DatabaseUnavailableError("Database unavailable", { cause: error });
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* The driver reported the connection gone (idle timeout, server restart,
|
|
999
|
+
* network drop). Forget it so the next flush reconnects; without an 'error'
|
|
1000
|
+
* listener the driver's emitter would crash the process.
|
|
1001
|
+
*/
|
|
1002
|
+
onConnectionLost(connection, error) {
|
|
1003
|
+
if (this.connection !== connection) return;
|
|
1004
|
+
if (error) internalError("Database connection lost", error);
|
|
1005
|
+
this.isConnected = false;
|
|
1006
|
+
this.connectionPromise = void 0;
|
|
1007
|
+
this.connection = void 0;
|
|
1008
|
+
}
|
|
1009
|
+
watchConnection(connection) {
|
|
1010
|
+
var _connection$on, _connection$on2;
|
|
1011
|
+
const lost = (error) => this.onConnectionLost(connection, error);
|
|
1012
|
+
(_connection$on = connection.on) === null || _connection$on === void 0 || _connection$on.call(connection, "error", lost);
|
|
1013
|
+
(_connection$on2 = connection.on) === null || _connection$on2 === void 0 || _connection$on2.call(connection, "end", () => lost());
|
|
1014
|
+
}
|
|
976
1015
|
async connect() {
|
|
977
1016
|
if (this.connectionPromise) return this.connectionPromise;
|
|
978
1017
|
this.connectionPromise = this.establishConnection().catch((error) => {
|
|
@@ -1009,6 +1048,7 @@ var DatabaseTransport = class {
|
|
|
1009
1048
|
});
|
|
1010
1049
|
const connectionString = this.config.connectionString || `mongodb://${this.config.host}:${this.config.port}/${this.config.database}`;
|
|
1011
1050
|
this.connection = new MongoClient(connectionString);
|
|
1051
|
+
this.watchConnection(this.connection);
|
|
1012
1052
|
await this.connection.connect();
|
|
1013
1053
|
await this.connection.db(this.config.database).admin().ping();
|
|
1014
1054
|
} catch (error) {
|
|
@@ -1030,6 +1070,7 @@ var DatabaseTransport = class {
|
|
|
1030
1070
|
if (this.config.password) config.password = this.config.password;
|
|
1031
1071
|
if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
|
|
1032
1072
|
this.connection = new Client(config);
|
|
1073
|
+
this.watchConnection(this.connection);
|
|
1033
1074
|
await this.connection.connect();
|
|
1034
1075
|
await this.createPostgreSQLTable();
|
|
1035
1076
|
} catch (error) {
|
|
@@ -1050,6 +1091,7 @@ var DatabaseTransport = class {
|
|
|
1050
1091
|
if (this.config.password) config.password = this.config.password;
|
|
1051
1092
|
if (this.config.ssl) config.ssl = typeof this.config.ssl === "boolean" ? {} : this.config.ssl;
|
|
1052
1093
|
this.connection = await mysql.createConnection(config);
|
|
1094
|
+
this.watchConnection(this.connection);
|
|
1053
1095
|
await this.createMySQLTable();
|
|
1054
1096
|
} catch (error) {
|
|
1055
1097
|
throw new Error(`MySQL connection failed: ${error}`, { cause: error });
|
|
@@ -1272,6 +1314,7 @@ var DatabaseTransport = class {
|
|
|
1272
1314
|
this.flushTimer = void 0;
|
|
1273
1315
|
}
|
|
1274
1316
|
const MAX_CLOSE_FLUSH_ATTEMPTS = 3;
|
|
1317
|
+
this.nextConnectAt = 0;
|
|
1275
1318
|
if (this.flushPromise) await this.flushPromise.catch(() => {});
|
|
1276
1319
|
for (let attempt = 0; attempt < MAX_CLOSE_FLUSH_ATTEMPTS && this.batch.length > 0; attempt += 1) try {
|
|
1277
1320
|
await this.flush();
|
|
@@ -1280,17 +1323,19 @@ var DatabaseTransport = class {
|
|
|
1280
1323
|
}
|
|
1281
1324
|
if (this.batch.length > 0) internalError(`Database transport closing with ${this.batch.length} unflushed log entr${this.batch.length === 1 ? "y" : "ies"} after ${MAX_CLOSE_FLUSH_ATTEMPTS} attempts`);
|
|
1282
1325
|
this.cap.report(0);
|
|
1283
|
-
|
|
1326
|
+
const connection = this.connection;
|
|
1327
|
+
this.connection = void 0;
|
|
1328
|
+
if (connection) switch (this.config.type) {
|
|
1284
1329
|
case "mongodb":
|
|
1285
|
-
await
|
|
1330
|
+
await connection.close();
|
|
1286
1331
|
break;
|
|
1287
1332
|
case "postgresql":
|
|
1288
|
-
await
|
|
1333
|
+
await connection.end();
|
|
1289
1334
|
break;
|
|
1290
1335
|
case "mysql":
|
|
1291
|
-
await
|
|
1336
|
+
await connection.end();
|
|
1292
1337
|
break;
|
|
1293
|
-
case "sqlite": await
|
|
1338
|
+
case "sqlite": await connection.close();
|
|
1294
1339
|
}
|
|
1295
1340
|
this.isConnected = false;
|
|
1296
1341
|
}
|
|
@@ -1446,6 +1491,8 @@ var FileTransport = class {
|
|
|
1446
1491
|
lastDropWarning = 0;
|
|
1447
1492
|
/** Gzip and pruning of rotated files run off the write path, one at a time. */
|
|
1448
1493
|
housekeeping = Promise.resolve();
|
|
1494
|
+
exitListenerAttached = false;
|
|
1495
|
+
onExit = () => this.flushSyncOnExit();
|
|
1449
1496
|
constructor(config) {
|
|
1450
1497
|
this.config = {
|
|
1451
1498
|
format: "json",
|
|
@@ -1534,6 +1581,7 @@ var FileTransport = class {
|
|
|
1534
1581
|
await done;
|
|
1535
1582
|
}
|
|
1536
1583
|
enqueue(entry) {
|
|
1584
|
+
this.attachExitListener();
|
|
1537
1585
|
if (this.queueFull()) {
|
|
1538
1586
|
if (this.queuePolicy === "drop-oldest" && this.batch.length > 0) {
|
|
1539
1587
|
this.batch.shift();
|
|
@@ -1545,6 +1593,30 @@ var FileTransport = class {
|
|
|
1545
1593
|
this.batch.push(entry);
|
|
1546
1594
|
this.enqueued += 1;
|
|
1547
1595
|
}
|
|
1596
|
+
attachExitListener() {
|
|
1597
|
+
if (this.exitListenerAttached) return;
|
|
1598
|
+
this.exitListenerAttached = true;
|
|
1599
|
+
process.on("exit", this.onExit);
|
|
1600
|
+
}
|
|
1601
|
+
detachExitListener() {
|
|
1602
|
+
if (!this.exitListenerAttached) return;
|
|
1603
|
+
this.exitListenerAttached = false;
|
|
1604
|
+
process.removeListener("exit", this.onExit);
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* Last chance on process exit: async writes cannot finish, so whatever is still
|
|
1608
|
+
* batched is appended synchronously to the current file.
|
|
1609
|
+
*/
|
|
1610
|
+
flushSyncOnExit() {
|
|
1611
|
+
if (this.batch.length === 0) return;
|
|
1612
|
+
const pending = this.batch;
|
|
1613
|
+
this.batch = [];
|
|
1614
|
+
this.enqueued -= pending.length;
|
|
1615
|
+
try {
|
|
1616
|
+
const content = pending.map((entry) => this.formatEntry(entry)).join("\n") + "\n";
|
|
1617
|
+
node_fs.appendFileSync(this.currentFilePath, content, { mode: this.fileMode });
|
|
1618
|
+
} catch {}
|
|
1619
|
+
}
|
|
1548
1620
|
queueFull() {
|
|
1549
1621
|
return this.batch.length + this.inFlight >= this.maxQueue;
|
|
1550
1622
|
}
|
|
@@ -1629,7 +1701,11 @@ var FileTransport = class {
|
|
|
1629
1701
|
case "json": return stringifyForLog(mergeCoreFields({
|
|
1630
1702
|
timestamp: entry.timestamp.toISOString(),
|
|
1631
1703
|
level: entry.level,
|
|
1632
|
-
message: entry.message
|
|
1704
|
+
message: entry.message,
|
|
1705
|
+
context: entry.context,
|
|
1706
|
+
traceId: entry.traceId,
|
|
1707
|
+
appName: entry.appName,
|
|
1708
|
+
environment: entry.environment
|
|
1633
1709
|
}, entry.data));
|
|
1634
1710
|
case "csv": return [
|
|
1635
1711
|
entry.timestamp.toISOString(),
|
|
@@ -1651,9 +1727,12 @@ var FileTransport = class {
|
|
|
1651
1727
|
this.batchTimer = void 0;
|
|
1652
1728
|
}
|
|
1653
1729
|
this.startDrain();
|
|
1654
|
-
} else if (!this.batchTimer && this.config.flushInterval)
|
|
1655
|
-
this.
|
|
1656
|
-
|
|
1730
|
+
} else if (!this.batchTimer && this.config.flushInterval) {
|
|
1731
|
+
this.batchTimer = setTimeout(() => {
|
|
1732
|
+
this.flush().catch((err) => internalError("FileTransport interval flush failed", err));
|
|
1733
|
+
}, this.config.flushInterval);
|
|
1734
|
+
this.batchTimer.unref();
|
|
1735
|
+
}
|
|
1657
1736
|
}
|
|
1658
1737
|
/** Only ever called from drain(), so writes and rotations never overlap. */
|
|
1659
1738
|
async writeBatch(entries) {
|
|
@@ -1819,6 +1898,7 @@ var FileTransport = class {
|
|
|
1819
1898
|
this.batchTimer = void 0;
|
|
1820
1899
|
}
|
|
1821
1900
|
await this.flush();
|
|
1901
|
+
this.detachExitListener();
|
|
1822
1902
|
await this.housekeeping;
|
|
1823
1903
|
this.reportDropped(0);
|
|
1824
1904
|
}
|
package/dist/worker.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-
|
|
1
|
+
import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-DnU0_9Bd.mjs";
|
|
2
2
|
export { WorkerTransport, WorkerTransportConfig };
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-
|
|
1
|
+
import { n as WorkerTransportConfig, t as WorkerTransport } from "./worker.transport-B7olL1Uh.js";
|
|
2
2
|
export { WorkerTransport, WorkerTransportConfig };
|
package/dist/worker.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_worker_transport = require("./worker.transport-
|
|
2
|
+
const require_worker_transport = require("./worker.transport-C7jNGhev.js");
|
|
3
3
|
exports.WorkerTransport = require_worker_transport.WorkerTransport;
|
package/dist/worker.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as WorkerTransport } from "./worker.transport-
|
|
1
|
+
export { t as WorkerTransport } from "./worker.transport-BHnWDXPH.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as TransportLogEntry, d as ITransport } from "./transport.types-
|
|
1
|
+
import { _ as TransportLogEntry, d as ITransport } from "./transport.types-B1ejJJP6.js";
|
|
2
2
|
interface WorkerTransportConfig {
|
|
3
3
|
/**
|
|
4
4
|
* Which built-in logixia transport to run inside the worker thread.
|
|
@@ -49,11 +49,21 @@ declare class WorkerTransport implements ITransport {
|
|
|
49
49
|
private restartTimer;
|
|
50
50
|
/** Set once close() begins, so a worker 'exit' no longer triggers a restart. */
|
|
51
51
|
private closing;
|
|
52
|
+
/** Writes have been posted since the last flush; keeps the beforeExit flush from looping. */
|
|
53
|
+
private dirty;
|
|
54
|
+
/** Run once the worker reports ready, used when the process wants to exit before that. */
|
|
55
|
+
private onReady;
|
|
52
56
|
/** Max time to wait for the worker's 'flushed' ack before giving up. */
|
|
53
57
|
private readonly FLUSH_TIMEOUT_MS;
|
|
54
58
|
/** Max time to wait for a graceful worker exit before force-terminating. */
|
|
55
59
|
private readonly SHUTDOWN_TIMEOUT_MS;
|
|
56
60
|
constructor(config: WorkerTransportConfig);
|
|
61
|
+
/**
|
|
62
|
+
* The worker is unref'd so it never keeps the process alive on its own; the
|
|
63
|
+
* trade-off is that lines still queued on it would be lost when the event loop
|
|
64
|
+
* drains. On beforeExit, re-ref the worker until it acknowledges a flush.
|
|
65
|
+
*/
|
|
66
|
+
private readonly flushForExit;
|
|
57
67
|
private startWorker;
|
|
58
68
|
/** The worker entry is always built as CommonJS, next to this module's output. */
|
|
59
69
|
protected workerFile(): string;
|
|
@@ -74,4 +84,4 @@ declare class WorkerTransport implements ITransport {
|
|
|
74
84
|
private drainBufferTo;
|
|
75
85
|
}
|
|
76
86
|
export { WorkerTransportConfig as n, WorkerTransport as t };
|
|
77
|
-
//# sourceMappingURL=worker.transport-
|
|
87
|
+
//# sourceMappingURL=worker.transport-B7olL1Uh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.transport-B7olL1Uh.d.ts","names":[],"sources":["../src/transports/worker.transport.ts"],"mappings":";UA0CiB;;;;;EAKf;;EAEA,iBAAiB;;;;;;EAMjB;;;;;EAKA;;;;;EAKA,SAAS;;;;;EAKT;;;;;;cAOW,2BAA2B;WACtB;WACA;WACA;WACA;UAER;UACA;mBACS;mBACA;UACT;mBACS;mBACA;;UAET;;UAEA;;UAEA;;UAEA;;mBAES;;mBAEA;EAEL,YAAA,QAAQ;;;;;;mBAeH;UAgBT;;YA4CE;UAIF;UAuBA;EASR,MAAM,OAAO;EAaP,SAAS;;;;;;;;EAsCT,SAAS;;EAqCT,YAAY;UAIV"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as protectSecrets } from "./secret-config-
|
|
1
|
+
import { n as protectSecrets } from "./secret-config-GKmb15Me.mjs";
|
|
2
2
|
import { r as internalWarn, t as internalError } from "./internal-log-Cy5nF1ZL.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -62,6 +62,10 @@ var WorkerTransport = class {
|
|
|
62
62
|
restartTimer = null;
|
|
63
63
|
/** Set once close() begins, so a worker 'exit' no longer triggers a restart. */
|
|
64
64
|
closing = false;
|
|
65
|
+
/** Writes have been posted since the last flush; keeps the beforeExit flush from looping. */
|
|
66
|
+
dirty = false;
|
|
67
|
+
/** Run once the worker reports ready, used when the process wants to exit before that. */
|
|
68
|
+
onReady;
|
|
65
69
|
/** Max time to wait for the worker's 'flushed' ack before giving up. */
|
|
66
70
|
FLUSH_TIMEOUT_MS = 5e3;
|
|
67
71
|
/** Max time to wait for a graceful worker exit before force-terminating. */
|
|
@@ -73,7 +77,26 @@ var WorkerTransport = class {
|
|
|
73
77
|
this.level = config.level;
|
|
74
78
|
protectSecrets(this, ["config"]);
|
|
75
79
|
this.startWorker();
|
|
80
|
+
process.on("beforeExit", this.flushForExit);
|
|
76
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* The worker is unref'd so it never keeps the process alive on its own; the
|
|
84
|
+
* trade-off is that lines still queued on it would be lost when the event loop
|
|
85
|
+
* drains. On beforeExit, re-ref the worker until it acknowledges a flush.
|
|
86
|
+
*/
|
|
87
|
+
flushForExit = () => {
|
|
88
|
+
var _worker$ref;
|
|
89
|
+
const worker = this.worker;
|
|
90
|
+
if (!worker || this.closing || !this.dirty) return;
|
|
91
|
+
(_worker$ref = worker.ref) === null || _worker$ref === void 0 || _worker$ref.call(worker);
|
|
92
|
+
const timer = setTimeout(() => worker.unref(), this.FLUSH_TIMEOUT_MS);
|
|
93
|
+
const done = () => {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
worker.unref();
|
|
96
|
+
};
|
|
97
|
+
if (this.ready) this.flush().finally(done);
|
|
98
|
+
else this.onReady = () => void this.flush().finally(done);
|
|
99
|
+
};
|
|
77
100
|
startWorker() {
|
|
78
101
|
try {
|
|
79
102
|
this.worker = new Worker(this.workerFile(), { workerData: {
|
|
@@ -85,6 +108,9 @@ var WorkerTransport = class {
|
|
|
85
108
|
if (msg.type === "ready") {
|
|
86
109
|
this.ready = true;
|
|
87
110
|
this.drainBuffer();
|
|
111
|
+
const onReady = this.onReady;
|
|
112
|
+
this.onReady = void 0;
|
|
113
|
+
onReady === null || onReady === void 0 || onReady();
|
|
88
114
|
} else if (msg.type === "error" || msg.type === "write-error") internalError(`WorkerTransport [${this.config.transportType}]: ${msg.error ?? "unknown"}`);
|
|
89
115
|
});
|
|
90
116
|
this.worker.on("error", (err) => {
|
|
@@ -97,6 +123,7 @@ var WorkerTransport = class {
|
|
|
97
123
|
this.handleWorkerExit();
|
|
98
124
|
}
|
|
99
125
|
});
|
|
126
|
+
this.worker.unref();
|
|
100
127
|
} catch (err) {
|
|
101
128
|
internalError("WorkerTransport failed to start", err);
|
|
102
129
|
}
|
|
@@ -128,6 +155,7 @@ var WorkerTransport = class {
|
|
|
128
155
|
}
|
|
129
156
|
}
|
|
130
157
|
write(entry) {
|
|
158
|
+
this.dirty = true;
|
|
131
159
|
if (this.ready && this.worker) this.worker.postMessage({
|
|
132
160
|
type: "write",
|
|
133
161
|
entry
|
|
@@ -141,18 +169,25 @@ var WorkerTransport = class {
|
|
|
141
169
|
}
|
|
142
170
|
}
|
|
143
171
|
async flush() {
|
|
172
|
+
var _worker$ref2;
|
|
144
173
|
if (!this.ready || !this.worker) return;
|
|
145
174
|
const worker = this.worker;
|
|
175
|
+
this.dirty = false;
|
|
176
|
+
(_worker$ref2 = worker.ref) === null || _worker$ref2 === void 0 || _worker$ref2.call(worker);
|
|
146
177
|
return new Promise((resolve) => {
|
|
147
178
|
const timer = setTimeout(() => {
|
|
179
|
+
var _worker$unref;
|
|
148
180
|
worker.off("message", handler);
|
|
181
|
+
(_worker$unref = worker.unref) === null || _worker$unref === void 0 || _worker$unref.call(worker);
|
|
149
182
|
resolve();
|
|
150
183
|
}, this.FLUSH_TIMEOUT_MS);
|
|
151
184
|
if (timer.unref) timer.unref();
|
|
152
185
|
const handler = (msg) => {
|
|
153
186
|
if (msg.type === "flushed") {
|
|
187
|
+
var _worker$unref2;
|
|
154
188
|
clearTimeout(timer);
|
|
155
189
|
worker.off("message", handler);
|
|
190
|
+
(_worker$unref2 = worker.unref) === null || _worker$unref2 === void 0 || _worker$unref2.call(worker);
|
|
156
191
|
resolve();
|
|
157
192
|
}
|
|
158
193
|
};
|
|
@@ -168,7 +203,9 @@ var WorkerTransport = class {
|
|
|
168
203
|
* graceful exit, leaking the worker thread and dropping its buffered logs.
|
|
169
204
|
*/
|
|
170
205
|
async close() {
|
|
206
|
+
var _worker$ref3;
|
|
171
207
|
this.closing = true;
|
|
208
|
+
process.removeListener("beforeExit", this.flushForExit);
|
|
172
209
|
if (this.restartTimer) {
|
|
173
210
|
clearTimeout(this.restartTimer);
|
|
174
211
|
this.restartTimer = null;
|
|
@@ -178,6 +215,7 @@ var WorkerTransport = class {
|
|
|
178
215
|
this.worker = null;
|
|
179
216
|
this.drainBufferTo(worker);
|
|
180
217
|
worker.postMessage({ type: "shutdown" });
|
|
218
|
+
(_worker$ref3 = worker.ref) === null || _worker$ref3 === void 0 || _worker$ref3.call(worker);
|
|
181
219
|
await new Promise((resolve) => {
|
|
182
220
|
const timer = setTimeout(() => {
|
|
183
221
|
worker.terminate().finally(() => resolve());
|
|
@@ -205,4 +243,4 @@ var WorkerTransport = class {
|
|
|
205
243
|
};
|
|
206
244
|
export { WorkerTransport as t };
|
|
207
245
|
|
|
208
|
-
//# sourceMappingURL=worker.transport-
|
|
246
|
+
//# sourceMappingURL=worker.transport-BHnWDXPH.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.transport-BHnWDXPH.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 * custom: [\n * new WorkerTransport({\n * transportType: 'file',\n * transportConfig: { filename: 'app.log', dirname: './logs' },\n * bufferSize: 500,\n * maxRestarts: 3,\n * }),\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';\nimport { protectSecrets } from './secret-config';\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 * Custom level severities (`levelOptions.levels`) the wrapped transport's own\n * `level` is compared against inside the worker. Built-in levels need no entry.\n */\n levels?: Record<string, 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 /** Writes have been posted since the last flush; keeps the beforeExit flush from looping. */\n private dirty = false;\n /** Run once the worker reports ready, used when the process wants to exit before that. */\n private onReady: (() => void) | undefined;\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 protectSecrets(this, ['config']);\n this.startWorker();\n process.on('beforeExit', this.flushForExit);\n }\n\n /**\n * The worker is unref'd so it never keeps the process alive on its own; the\n * trade-off is that lines still queued on it would be lost when the event loop\n * drains. On beforeExit, re-ref the worker until it acknowledges a flush.\n */\n private readonly flushForExit = (): void => {\n const worker = this.worker;\n if (!worker || this.closing || !this.dirty) return;\n worker.ref?.();\n const timer = setTimeout(() => worker.unref(), this.FLUSH_TIMEOUT_MS);\n const done = (): void => {\n clearTimeout(timer);\n worker.unref();\n };\n if (this.ready) {\n void this.flush().finally(done);\n } else {\n this.onReady = () => void this.flush().finally(done);\n }\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 levels: this.config.levels,\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 const onReady = this.onReady;\n this.onReady = undefined;\n onReady?.();\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\n // After the listeners: adding a 'message' listener re-refs the worker's port.\n this.worker.unref();\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 this.dirty = true;\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 this.dirty = false;\n // Unref'd between flushes; ref'd here so an awaited flush() keeps the process alive.\n worker.ref?.();\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 worker.unref?.();\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 worker.unref?.();\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 process.removeListener('beforeExit', this.flushForExit);\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 // The worker is unref'd, so hold the process open until it has drained and exited.\n worker.ref?.();\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"],"ignoreList":[0],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_secret_config = require("./secret-config
|
|
1
|
+
const require_secret_config = require("./secret-config--cVTOWwp.js");
|
|
2
2
|
const require_internal_log = require("./internal-log-DwqTjhpb.js");
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
node_path = require_secret_config.__toESM(node_path);
|
|
@@ -58,6 +58,10 @@ var WorkerTransport = class {
|
|
|
58
58
|
restartTimer = null;
|
|
59
59
|
/** Set once close() begins, so a worker 'exit' no longer triggers a restart. */
|
|
60
60
|
closing = false;
|
|
61
|
+
/** Writes have been posted since the last flush; keeps the beforeExit flush from looping. */
|
|
62
|
+
dirty = false;
|
|
63
|
+
/** Run once the worker reports ready, used when the process wants to exit before that. */
|
|
64
|
+
onReady;
|
|
61
65
|
/** Max time to wait for the worker's 'flushed' ack before giving up. */
|
|
62
66
|
FLUSH_TIMEOUT_MS = 5e3;
|
|
63
67
|
/** Max time to wait for a graceful worker exit before force-terminating. */
|
|
@@ -69,7 +73,26 @@ var WorkerTransport = class {
|
|
|
69
73
|
this.level = config.level;
|
|
70
74
|
require_secret_config.protectSecrets(this, ["config"]);
|
|
71
75
|
this.startWorker();
|
|
76
|
+
process.on("beforeExit", this.flushForExit);
|
|
72
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The worker is unref'd so it never keeps the process alive on its own; the
|
|
80
|
+
* trade-off is that lines still queued on it would be lost when the event loop
|
|
81
|
+
* drains. On beforeExit, re-ref the worker until it acknowledges a flush.
|
|
82
|
+
*/
|
|
83
|
+
flushForExit = () => {
|
|
84
|
+
var _worker$ref;
|
|
85
|
+
const worker = this.worker;
|
|
86
|
+
if (!worker || this.closing || !this.dirty) return;
|
|
87
|
+
(_worker$ref = worker.ref) === null || _worker$ref === void 0 || _worker$ref.call(worker);
|
|
88
|
+
const timer = setTimeout(() => worker.unref(), this.FLUSH_TIMEOUT_MS);
|
|
89
|
+
const done = () => {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
worker.unref();
|
|
92
|
+
};
|
|
93
|
+
if (this.ready) this.flush().finally(done);
|
|
94
|
+
else this.onReady = () => void this.flush().finally(done);
|
|
95
|
+
};
|
|
73
96
|
startWorker() {
|
|
74
97
|
try {
|
|
75
98
|
this.worker = new node_worker_threads.Worker(this.workerFile(), { workerData: {
|
|
@@ -81,6 +104,9 @@ var WorkerTransport = class {
|
|
|
81
104
|
if (msg.type === "ready") {
|
|
82
105
|
this.ready = true;
|
|
83
106
|
this.drainBuffer();
|
|
107
|
+
const onReady = this.onReady;
|
|
108
|
+
this.onReady = void 0;
|
|
109
|
+
onReady === null || onReady === void 0 || onReady();
|
|
84
110
|
} else if (msg.type === "error" || msg.type === "write-error") require_internal_log.internalError(`WorkerTransport [${this.config.transportType}]: ${msg.error ?? "unknown"}`);
|
|
85
111
|
});
|
|
86
112
|
this.worker.on("error", (err) => {
|
|
@@ -93,6 +119,7 @@ var WorkerTransport = class {
|
|
|
93
119
|
this.handleWorkerExit();
|
|
94
120
|
}
|
|
95
121
|
});
|
|
122
|
+
this.worker.unref();
|
|
96
123
|
} catch (err) {
|
|
97
124
|
require_internal_log.internalError("WorkerTransport failed to start", err);
|
|
98
125
|
}
|
|
@@ -124,6 +151,7 @@ var WorkerTransport = class {
|
|
|
124
151
|
}
|
|
125
152
|
}
|
|
126
153
|
write(entry) {
|
|
154
|
+
this.dirty = true;
|
|
127
155
|
if (this.ready && this.worker) this.worker.postMessage({
|
|
128
156
|
type: "write",
|
|
129
157
|
entry
|
|
@@ -137,18 +165,25 @@ var WorkerTransport = class {
|
|
|
137
165
|
}
|
|
138
166
|
}
|
|
139
167
|
async flush() {
|
|
168
|
+
var _worker$ref2;
|
|
140
169
|
if (!this.ready || !this.worker) return;
|
|
141
170
|
const worker = this.worker;
|
|
171
|
+
this.dirty = false;
|
|
172
|
+
(_worker$ref2 = worker.ref) === null || _worker$ref2 === void 0 || _worker$ref2.call(worker);
|
|
142
173
|
return new Promise((resolve) => {
|
|
143
174
|
const timer = setTimeout(() => {
|
|
175
|
+
var _worker$unref;
|
|
144
176
|
worker.off("message", handler);
|
|
177
|
+
(_worker$unref = worker.unref) === null || _worker$unref === void 0 || _worker$unref.call(worker);
|
|
145
178
|
resolve();
|
|
146
179
|
}, this.FLUSH_TIMEOUT_MS);
|
|
147
180
|
if (timer.unref) timer.unref();
|
|
148
181
|
const handler = (msg) => {
|
|
149
182
|
if (msg.type === "flushed") {
|
|
183
|
+
var _worker$unref2;
|
|
150
184
|
clearTimeout(timer);
|
|
151
185
|
worker.off("message", handler);
|
|
186
|
+
(_worker$unref2 = worker.unref) === null || _worker$unref2 === void 0 || _worker$unref2.call(worker);
|
|
152
187
|
resolve();
|
|
153
188
|
}
|
|
154
189
|
};
|
|
@@ -164,7 +199,9 @@ var WorkerTransport = class {
|
|
|
164
199
|
* graceful exit, leaking the worker thread and dropping its buffered logs.
|
|
165
200
|
*/
|
|
166
201
|
async close() {
|
|
202
|
+
var _worker$ref3;
|
|
167
203
|
this.closing = true;
|
|
204
|
+
process.removeListener("beforeExit", this.flushForExit);
|
|
168
205
|
if (this.restartTimer) {
|
|
169
206
|
clearTimeout(this.restartTimer);
|
|
170
207
|
this.restartTimer = null;
|
|
@@ -174,6 +211,7 @@ var WorkerTransport = class {
|
|
|
174
211
|
this.worker = null;
|
|
175
212
|
this.drainBufferTo(worker);
|
|
176
213
|
worker.postMessage({ type: "shutdown" });
|
|
214
|
+
(_worker$ref3 = worker.ref) === null || _worker$ref3 === void 0 || _worker$ref3.call(worker);
|
|
177
215
|
await new Promise((resolve) => {
|
|
178
216
|
const timer = setTimeout(() => {
|
|
179
217
|
worker.terminate().finally(() => resolve());
|
|
@@ -206,4 +244,4 @@ Object.defineProperty(exports, "WorkerTransport", {
|
|
|
206
244
|
}
|
|
207
245
|
});
|
|
208
246
|
|
|
209
|
-
//# sourceMappingURL=worker.transport-
|
|
247
|
+
//# sourceMappingURL=worker.transport-C7jNGhev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.transport-C7jNGhev.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 * custom: [\n * new WorkerTransport({\n * transportType: 'file',\n * transportConfig: { filename: 'app.log', dirname: './logs' },\n * bufferSize: 500,\n * maxRestarts: 3,\n * }),\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';\nimport { protectSecrets } from './secret-config';\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 * Custom level severities (`levelOptions.levels`) the wrapped transport's own\n * `level` is compared against inside the worker. Built-in levels need no entry.\n */\n levels?: Record<string, 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 /** Writes have been posted since the last flush; keeps the beforeExit flush from looping. */\n private dirty = false;\n /** Run once the worker reports ready, used when the process wants to exit before that. */\n private onReady: (() => void) | undefined;\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 protectSecrets(this, ['config']);\n this.startWorker();\n process.on('beforeExit', this.flushForExit);\n }\n\n /**\n * The worker is unref'd so it never keeps the process alive on its own; the\n * trade-off is that lines still queued on it would be lost when the event loop\n * drains. On beforeExit, re-ref the worker until it acknowledges a flush.\n */\n private readonly flushForExit = (): void => {\n const worker = this.worker;\n if (!worker || this.closing || !this.dirty) return;\n worker.ref?.();\n const timer = setTimeout(() => worker.unref(), this.FLUSH_TIMEOUT_MS);\n const done = (): void => {\n clearTimeout(timer);\n worker.unref();\n };\n if (this.ready) {\n void this.flush().finally(done);\n } else {\n this.onReady = () => void this.flush().finally(done);\n }\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 levels: this.config.levels,\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 const onReady = this.onReady;\n this.onReady = undefined;\n onReady?.();\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\n // After the listeners: adding a 'message' listener re-refs the worker's port.\n this.worker.unref();\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 this.dirty = true;\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 this.dirty = false;\n // Unref'd between flushes; ref'd here so an awaited flush() keeps the process alive.\n worker.ref?.();\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 worker.unref?.();\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 worker.unref?.();\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 process.removeListener('beforeExit', this.flushForExit);\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 // The worker is unref'd, so hold the process open until it has drained and exited.\n worker.ref?.();\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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"}
|