@mks2508/better-logger 0.18.2-alpha.1 → 0.18.2-alpha.2
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 +38 -336
- package/dist/Logger.d.ts +243 -154
- package/dist/Logger.d.ts.map +1 -1
- package/dist/ScopedLogger.d.ts +511 -8
- package/dist/ScopedLogger.d.ts.map +1 -1
- package/dist/chunks/HookBridge-C-AvXmPD.cjs +504 -0
- package/dist/chunks/HookBridge-C-AvXmPD.cjs.map +1 -0
- package/dist/chunks/HookBridge-CI2PH79S.js +487 -0
- package/dist/chunks/HookBridge-CI2PH79S.js.map +1 -0
- package/dist/chunks/{LogContext-L7HzynFw.cjs → LogContext-BaMXleWj.cjs} +19 -4
- package/dist/chunks/LogContext-BaMXleWj.cjs.map +1 -0
- package/dist/chunks/{LogContext-Cwn-1Zzb.js → LogContext-DjlITOzZ.js} +19 -4
- package/dist/chunks/LogContext-DjlITOzZ.js.map +1 -0
- package/dist/chunks/SerializerBridge-Ba43Mk7j.js +393 -0
- package/dist/chunks/SerializerBridge-Ba43Mk7j.js.map +1 -0
- package/dist/chunks/SerializerBridge-C4a9Z37F.cjs +410 -0
- package/dist/chunks/SerializerBridge-C4a9Z37F.cjs.map +1 -0
- package/dist/chunks/{StyleManager-CIpd6wbO.cjs → StyleManager-DQ6UNRB-.cjs} +37 -11
- package/dist/chunks/StyleManager-DQ6UNRB-.cjs.map +1 -0
- package/dist/chunks/StyleManager-DjwAYbxE.js +113 -0
- package/dist/chunks/StyleManager-DjwAYbxE.js.map +1 -0
- package/dist/chunks/{core-PoT7RrTK.js → core-Blfi2klP.js} +1 -4
- package/dist/chunks/core-Blfi2klP.js.map +1 -0
- package/dist/chunks/{core-Dzz7agGa.cjs → core-CqS_UBzJ.cjs} +1 -4
- package/dist/chunks/core-CqS_UBzJ.cjs.map +1 -0
- package/dist/chunks/{environment-detector-CI3TrWK_.js → environment-detector-7NvnYUfr.js} +11 -11
- package/dist/chunks/environment-detector-7NvnYUfr.js.map +1 -0
- package/dist/chunks/{environment-detector-Cnn6wr6O.cjs → environment-detector-D-tHkKWA.cjs} +11 -11
- package/dist/chunks/environment-detector-D-tHkKWA.cjs.map +1 -0
- package/dist/chunks/server-fallback-CaCPjWby.cjs +119 -0
- package/dist/chunks/server-fallback-CaCPjWby.cjs.map +1 -0
- package/dist/chunks/server-fallback-jj0T6XaK.js +114 -0
- package/dist/chunks/server-fallback-jj0T6XaK.js.map +1 -0
- package/dist/chunks/{spinner-DNvxbM9a.cjs → spinner-BHyYEXsM.cjs} +319 -37
- package/dist/chunks/spinner-BHyYEXsM.cjs.map +1 -0
- package/dist/chunks/{spinner-D3FsF78o.js → spinner-BtkwpzYv.js} +319 -37
- package/dist/chunks/spinner-BtkwpzYv.js.map +1 -0
- package/dist/chunks/styling-CRw3KQW4.js +1592 -0
- package/dist/chunks/styling-CRw3KQW4.js.map +1 -0
- package/dist/chunks/styling-Cel2wPRy.cjs +1645 -0
- package/dist/chunks/styling-Cel2wPRy.cjs.map +1 -0
- package/dist/chunks/transports-BGfwwakw.js +1237 -0
- package/dist/chunks/transports-BGfwwakw.js.map +1 -0
- package/dist/chunks/transports-yK6CL0Ml.cjs +1278 -0
- package/dist/chunks/transports-yK6CL0Ml.cjs.map +1 -0
- package/dist/chunks/{utils-BqlFYocD.cjs → utils-W_cxqriN.cjs} +44 -37
- package/dist/chunks/utils-W_cxqriN.cjs.map +1 -0
- package/dist/chunks/{utils-VETbVpkR.js → utils-tKfBAWUM.js} +44 -37
- package/dist/chunks/utils-tKfBAWUM.js.map +1 -0
- package/dist/cli/CommandProcessor.d.ts +166 -19
- package/dist/cli/CommandProcessor.d.ts.map +1 -1
- package/dist/cli/commands/ConfigCommand.d.ts +36 -1
- package/dist/cli/commands/ConfigCommand.d.ts.map +1 -1
- package/dist/cli/commands/ExportCommand.d.ts +49 -3
- package/dist/cli/commands/ExportCommand.d.ts.map +1 -1
- package/dist/cli/commands/ThemeCommand.d.ts +62 -3
- package/dist/cli/commands/ThemeCommand.d.ts.map +1 -1
- package/dist/cli/help.d.ts +30 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.d.ts +29 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.cjs +2 -2
- package/dist/cli.js +2 -2
- package/dist/context/LogContext.d.ts +165 -66
- package/dist/context/LogContext.d.ts.map +1 -1
- package/dist/context.cjs +1 -1
- package/dist/context.js +1 -1
- package/dist/core.cjs +52 -29
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +50 -27
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +52 -29
- package/dist/core.js.map +1 -1
- package/dist/hooks/HookBridge.d.ts +15 -9
- package/dist/hooks/HookBridge.d.ts.map +1 -1
- package/dist/hooks/HookManager.d.ts +295 -2
- package/dist/hooks/HookManager.d.ts.map +1 -1
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.js +1 -1
- package/dist/index.cjs +1092 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1092 -212
- package/dist/index.js.map +1 -1
- package/dist/playground/TerminalBridge.d.ts +23 -16
- package/dist/playground/TerminalBridge.d.ts.map +1 -1
- package/dist/playground/box.d.ts +36 -5
- package/dist/playground/box.d.ts.map +1 -1
- package/dist/playground/cli-table.d.ts +41 -5
- package/dist/playground/cli-table.d.ts.map +1 -1
- package/dist/playground/divider.d.ts +22 -3
- package/dist/playground/divider.d.ts.map +1 -1
- package/dist/playground/header.d.ts +21 -4
- package/dist/playground/header.d.ts.map +1 -1
- package/dist/playground/server-fallback.d.ts +96 -9
- package/dist/playground/server-fallback.d.ts.map +1 -1
- package/dist/playground/spinner.d.ts +159 -10
- package/dist/playground/spinner.d.ts.map +1 -1
- package/dist/playground/step.d.ts +25 -6
- package/dist/playground/step.d.ts.map +1 -1
- package/dist/playground.cjs +1 -1
- package/dist/playground.js +1 -1
- package/dist/serializers/SerializerBridge.d.ts +13 -6
- package/dist/serializers/SerializerBridge.d.ts.map +1 -1
- package/dist/serializers/SerializerRegistry.d.ts +236 -0
- package/dist/serializers/SerializerRegistry.d.ts.map +1 -1
- package/dist/serializers.cjs +1 -1
- package/dist/serializers.js +1 -1
- package/dist/styles/StyleManager.d.ts +138 -31
- package/dist/styles/StyleManager.d.ts.map +1 -1
- package/dist/styles.cjs +2 -2
- package/dist/styles.js +2 -2
- package/dist/styling/SmartPresets.d.ts +100 -6
- package/dist/styling/SmartPresets.d.ts.map +1 -1
- package/dist/styling/StyleBuilder.d.ts +453 -32
- package/dist/styling/StyleBuilder.d.ts.map +1 -1
- package/dist/styling/banners.d.ts +83 -7
- package/dist/styling/banners.d.ts.map +1 -1
- package/dist/styling/themes.d.ts +41 -2
- package/dist/styling/themes.d.ts.map +1 -1
- package/dist/transports/ConsoleTransport.d.ts +95 -0
- package/dist/transports/ConsoleTransport.d.ts.map +1 -1
- package/dist/transports/FileTransport.d.ts +99 -18
- package/dist/transports/FileTransport.d.ts.map +1 -1
- package/dist/transports/HttpTransport.d.ts +135 -22
- package/dist/transports/HttpTransport.d.ts.map +1 -1
- package/dist/transports/OtlpTransport.d.ts +53 -36
- package/dist/transports/OtlpTransport.d.ts.map +1 -1
- package/dist/transports/TransportBridge.d.ts +19 -13
- package/dist/transports/TransportBridge.d.ts.map +1 -1
- package/dist/transports/TransportManager.d.ts +223 -8
- package/dist/transports/TransportManager.d.ts.map +1 -1
- package/dist/transports.cjs +1 -1
- package/dist/transports.js +1 -1
- package/dist/types/core.d.ts +155 -59
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +92 -14
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/serializers.d.ts +72 -0
- package/dist/types/serializers.d.ts.map +1 -1
- package/dist/types/transports.d.ts +42 -37
- package/dist/types/transports.d.ts.map +1 -1
- package/dist/utils/ansi-colors.d.ts +15 -15
- package/dist/utils/environment-detector.d.ts +11 -11
- package/dist/utils/formatting.d.ts +8 -8
- package/dist/utils/output.d.ts +9 -9
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/stackTrace.d.ts +2 -2
- package/package.json +24 -25
- package/dist/chunks/HookBridge-CiRfR67f.cjs +0 -190
- package/dist/chunks/HookBridge-CiRfR67f.cjs.map +0 -1
- package/dist/chunks/HookBridge-SgMmbXZB.js +0 -173
- package/dist/chunks/HookBridge-SgMmbXZB.js.map +0 -1
- package/dist/chunks/LogContext-Cwn-1Zzb.js.map +0 -1
- package/dist/chunks/LogContext-L7HzynFw.cjs.map +0 -1
- package/dist/chunks/SerializerBridge-BaOQOb8q.cjs +0 -166
- package/dist/chunks/SerializerBridge-BaOQOb8q.cjs.map +0 -1
- package/dist/chunks/SerializerBridge-BkpQu5c9.js +0 -149
- package/dist/chunks/SerializerBridge-BkpQu5c9.js.map +0 -1
- package/dist/chunks/StyleManager-CIpd6wbO.cjs.map +0 -1
- package/dist/chunks/StyleManager-LCvVlVdx.js +0 -87
- package/dist/chunks/StyleManager-LCvVlVdx.js.map +0 -1
- package/dist/chunks/core-Dzz7agGa.cjs.map +0 -1
- package/dist/chunks/core-PoT7RrTK.js.map +0 -1
- package/dist/chunks/environment-detector-CI3TrWK_.js.map +0 -1
- package/dist/chunks/environment-detector-Cnn6wr6O.cjs.map +0 -1
- package/dist/chunks/server-fallback-BUKjdLS7.cjs +0 -42
- package/dist/chunks/server-fallback-BUKjdLS7.cjs.map +0 -1
- package/dist/chunks/server-fallback-BsuWH1Dk.js +0 -37
- package/dist/chunks/server-fallback-BsuWH1Dk.js.map +0 -1
- package/dist/chunks/spinner-D3FsF78o.js.map +0 -1
- package/dist/chunks/spinner-DNvxbM9a.cjs.map +0 -1
- package/dist/chunks/styling-84N8T97t.js +0 -941
- package/dist/chunks/styling-84N8T97t.js.map +0 -1
- package/dist/chunks/styling-Cg5saQ46.cjs +0 -994
- package/dist/chunks/styling-Cg5saQ46.cjs.map +0 -1
- package/dist/chunks/transports-BiDk345e.js +0 -715
- package/dist/chunks/transports-BiDk345e.js.map +0 -1
- package/dist/chunks/transports-COPWmlF1.cjs +0 -756
- package/dist/chunks/transports-COPWmlF1.cjs.map +0 -1
- package/dist/chunks/utils-BqlFYocD.cjs.map +0 -1
- package/dist/chunks/utils-VETbVpkR.js.map +0 -1
- package/dist/example.d.ts +0 -18
- package/dist/example.d.ts.map +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.d.ts.map +0 -1
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
//#region src/hooks/HookManager.ts
|
|
2
|
-
const MAX_ONERROR_DEPTH = 5;
|
|
3
|
-
function generateId() {
|
|
4
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
5
|
-
}
|
|
6
|
-
var HookManager = class {
|
|
7
|
-
hooks = /* @__PURE__ */ new Map();
|
|
8
|
-
middlewares = [];
|
|
9
|
-
/**
|
|
10
|
-
* Tracks current recursion depth for each hook event so `onError` chains
|
|
11
|
-
* that throw can't loop forever. Reset when the outer emit returns.
|
|
12
|
-
*/
|
|
13
|
-
_onErrorDepth = /* @__PURE__ */ new Map();
|
|
14
|
-
constructor() {
|
|
15
|
-
this.hooks.set("beforeLog", []);
|
|
16
|
-
this.hooks.set("afterLog", []);
|
|
17
|
-
this.hooks.set("onError", []);
|
|
18
|
-
}
|
|
19
|
-
on(event, callback, priority = 50) {
|
|
20
|
-
const registration = {
|
|
21
|
-
id: generateId(),
|
|
22
|
-
event,
|
|
23
|
-
callback,
|
|
24
|
-
priority,
|
|
25
|
-
once: false
|
|
26
|
-
};
|
|
27
|
-
const hooks = this.hooks.get(event);
|
|
28
|
-
hooks.push(registration);
|
|
29
|
-
hooks.sort((a, b) => b.priority - a.priority);
|
|
30
|
-
return () => this.removeHook(event, registration.id);
|
|
31
|
-
}
|
|
32
|
-
once(event, callback, priority = 50) {
|
|
33
|
-
const registration = {
|
|
34
|
-
id: generateId(),
|
|
35
|
-
event,
|
|
36
|
-
callback,
|
|
37
|
-
priority,
|
|
38
|
-
once: true
|
|
39
|
-
};
|
|
40
|
-
const hooks = this.hooks.get(event);
|
|
41
|
-
hooks.push(registration);
|
|
42
|
-
hooks.sort((a, b) => b.priority - a.priority);
|
|
43
|
-
return () => this.removeHook(event, registration.id);
|
|
44
|
-
}
|
|
45
|
-
off(event, callback) {
|
|
46
|
-
const hooks = this.hooks.get(event);
|
|
47
|
-
if (!hooks) return false;
|
|
48
|
-
const index = hooks.findIndex((h) => h.callback === callback);
|
|
49
|
-
if (index >= 0) {
|
|
50
|
-
hooks.splice(index, 1);
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
removeHook(event, id) {
|
|
56
|
-
const hooks = this.hooks.get(event);
|
|
57
|
-
if (hooks) {
|
|
58
|
-
const index = hooks.findIndex((h) => h.id === id);
|
|
59
|
-
if (index >= 0) hooks.splice(index, 1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
use(middleware, priority = 50) {
|
|
63
|
-
const registration = {
|
|
64
|
-
id: generateId(),
|
|
65
|
-
fn: middleware,
|
|
66
|
-
priority
|
|
67
|
-
};
|
|
68
|
-
this.middlewares.push(registration);
|
|
69
|
-
this.middlewares.sort((a, b) => b.priority - a.priority);
|
|
70
|
-
return () => {
|
|
71
|
-
const index = this.middlewares.findIndex((m) => m.id === registration.id);
|
|
72
|
-
if (index >= 0) this.middlewares.splice(index, 1);
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
async emit(event, entry) {
|
|
76
|
-
const depth = this._onErrorDepth.get(entry.hookEvent ?? event) ?? 0;
|
|
77
|
-
if (event === "onError" && depth >= MAX_ONERROR_DEPTH) {
|
|
78
|
-
console.error("HookManager: onError recursion limit reached, dropping entry:", entry);
|
|
79
|
-
return entry;
|
|
80
|
-
}
|
|
81
|
-
this._onErrorDepth.set(event, depth + 1);
|
|
82
|
-
try {
|
|
83
|
-
const hooks = this.hooks.get(event) || [];
|
|
84
|
-
let currentEntry = { ...entry };
|
|
85
|
-
const toRemove = [];
|
|
86
|
-
for (const hook of hooks) try {
|
|
87
|
-
const result = await hook.callback(currentEntry);
|
|
88
|
-
if (result) currentEntry = {
|
|
89
|
-
...currentEntry,
|
|
90
|
-
...result
|
|
91
|
-
};
|
|
92
|
-
if (hook.once) toRemove.push(hook.id);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
if (event !== "onError") await this.emit("onError", {
|
|
95
|
-
...currentEntry,
|
|
96
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
97
|
-
hookEvent: event
|
|
98
|
-
});
|
|
99
|
-
else console.error("HookManager: onError hook threw, swallowed to break recursion:", error);
|
|
100
|
-
}
|
|
101
|
-
toRemove.forEach((id) => this.removeHook(event, id));
|
|
102
|
-
return currentEntry;
|
|
103
|
-
} finally {
|
|
104
|
-
this._onErrorDepth.set(event, depth);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async process(entry) {
|
|
108
|
-
let currentEntry = { ...entry };
|
|
109
|
-
currentEntry = await this.emit("beforeLog", currentEntry);
|
|
110
|
-
if (this.middlewares.length > 0) {
|
|
111
|
-
let index = 0;
|
|
112
|
-
const executeNext = async () => {
|
|
113
|
-
if (index < this.middlewares.length) {
|
|
114
|
-
const middleware = this.middlewares[index++];
|
|
115
|
-
if (middleware) await middleware.fn(currentEntry, executeNext);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
await executeNext();
|
|
119
|
-
}
|
|
120
|
-
return currentEntry;
|
|
121
|
-
}
|
|
122
|
-
async afterProcess(entry) {
|
|
123
|
-
await this.emit("afterLog", entry);
|
|
124
|
-
}
|
|
125
|
-
clear() {
|
|
126
|
-
this.hooks.forEach((hooks) => hooks.length = 0);
|
|
127
|
-
this.middlewares.length = 0;
|
|
128
|
-
}
|
|
129
|
-
getStats() {
|
|
130
|
-
return {
|
|
131
|
-
hooks: {
|
|
132
|
-
beforeLog: this.hooks.get("beforeLog")?.length || 0,
|
|
133
|
-
afterLog: this.hooks.get("afterLog")?.length || 0,
|
|
134
|
-
onError: this.hooks.get("onError")?.length || 0
|
|
135
|
-
},
|
|
136
|
-
middlewares: this.middlewares.length
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
let _defaultHookManager = null;
|
|
141
|
-
function getDefaultHookManager() {
|
|
142
|
-
if (!_defaultHookManager) _defaultHookManager = new HookManager();
|
|
143
|
-
return _defaultHookManager;
|
|
144
|
-
}
|
|
145
|
-
//#endregion
|
|
146
|
-
//#region src/hooks/HookBridge.ts
|
|
147
|
-
/**
|
|
148
|
-
* Creates a HookBridge instance.
|
|
149
|
-
*/
|
|
150
|
-
function createHookBridge() {
|
|
151
|
-
const hookManager = new HookManager();
|
|
152
|
-
return {
|
|
153
|
-
on(event, callback, priority) {
|
|
154
|
-
return hookManager.on(event, callback, priority);
|
|
155
|
-
},
|
|
156
|
-
once(event, callback, priority) {
|
|
157
|
-
return hookManager.once(event, callback, priority);
|
|
158
|
-
},
|
|
159
|
-
off(event, callback) {
|
|
160
|
-
return hookManager.off(event, callback);
|
|
161
|
-
},
|
|
162
|
-
use(middleware, priority) {
|
|
163
|
-
return hookManager.use(middleware, priority);
|
|
164
|
-
},
|
|
165
|
-
getHookManager() {
|
|
166
|
-
return hookManager;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
//#endregion
|
|
171
|
-
Object.defineProperty(exports, "HookManager", {
|
|
172
|
-
enumerable: true,
|
|
173
|
-
get: function() {
|
|
174
|
-
return HookManager;
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
Object.defineProperty(exports, "createHookBridge", {
|
|
178
|
-
enumerable: true,
|
|
179
|
-
get: function() {
|
|
180
|
-
return createHookBridge;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
Object.defineProperty(exports, "getDefaultHookManager", {
|
|
184
|
-
enumerable: true,
|
|
185
|
-
get: function() {
|
|
186
|
-
return getDefaultHookManager;
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
//# sourceMappingURL=HookBridge-CiRfR67f.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HookBridge-CiRfR67f.cjs","names":[],"sources":["../../src/hooks/HookManager.ts","../../src/hooks/HookBridge.ts"],"sourcesContent":["import type {\n HookLogEntry,\n HookEvent,\n HookCallback,\n MiddlewareFn,\n HookRegistration,\n MiddlewareRegistration,\n IHookManager\n} from '../types/index.js';\n\nconst MAX_ONERROR_DEPTH = 5;\n\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\nexport class HookManager implements IHookManager {\n private hooks: Map<HookEvent, HookRegistration[]> = new Map();\n private middlewares: MiddlewareRegistration[] = [];\n /**\n * Tracks current recursion depth for each hook event so `onError` chains\n * that throw can't loop forever. Reset when the outer emit returns.\n */\n private _onErrorDepth: Map<HookEvent, number> = new Map();\n\n constructor() {\n this.hooks.set('beforeLog', []);\n this.hooks.set('afterLog', []);\n this.hooks.set('onError', []);\n }\n\n on(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {\n const registration: HookRegistration = {\n id: generateId(),\n event,\n callback,\n priority,\n once: false\n };\n\n const hooks = this.hooks.get(event)!;\n hooks.push(registration);\n hooks.sort((a, b) => b.priority - a.priority);\n\n return () => this.removeHook(event, registration.id);\n }\n\n once(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {\n const registration: HookRegistration = {\n id: generateId(),\n event,\n callback,\n priority,\n once: true\n };\n\n const hooks = this.hooks.get(event)!;\n hooks.push(registration);\n hooks.sort((a, b) => b.priority - a.priority);\n\n return () => this.removeHook(event, registration.id);\n }\n\n off(event: HookEvent, callback: HookCallback): boolean {\n const hooks = this.hooks.get(event);\n if (!hooks) return false;\n\n const index = hooks.findIndex(h => h.callback === callback);\n if (index >= 0) {\n hooks.splice(index, 1);\n return true;\n }\n return false;\n }\n\n private removeHook(event: HookEvent, id: string): void {\n const hooks = this.hooks.get(event);\n if (hooks) {\n const index = hooks.findIndex(h => h.id === id);\n if (index >= 0) {\n hooks.splice(index, 1);\n }\n }\n }\n\n use(middleware: MiddlewareFn, priority: number = 50): () => void {\n const registration: MiddlewareRegistration = {\n id: generateId(),\n fn: middleware,\n priority\n };\n\n this.middlewares.push(registration);\n this.middlewares.sort((a, b) => b.priority - a.priority);\n\n return () => {\n const index = this.middlewares.findIndex(m => m.id === registration.id);\n if (index >= 0) {\n this.middlewares.splice(index, 1);\n }\n };\n }\n\n async emit(event: HookEvent, entry: HookLogEntry): Promise<HookLogEntry> {\n // Re-entrancy guard. Without this, an onError hook that itself throws\n // would re-enter emit('onError', ...) and either spin forever or\n // recurse until the stack blows. We allow a small burst (MAX_ONERROR_DEPTH)\n // so legitimate fan-out keeps working, but break the cycle.\n const depth = (this._onErrorDepth.get(entry.hookEvent ?? event) ?? 0);\n if (event === 'onError' && depth >= MAX_ONERROR_DEPTH) {\n // eslint-disable-next-line no-console\n console.error('HookManager: onError recursion limit reached, dropping entry:', entry);\n return entry;\n }\n this._onErrorDepth.set(event, depth + 1);\n\n try {\n const hooks = this.hooks.get(event) || [];\n let currentEntry = { ...entry };\n const toRemove: string[] = [];\n\n for (const hook of hooks) {\n try {\n const result = await hook.callback(currentEntry);\n if (result) {\n currentEntry = { ...currentEntry, ...result };\n }\n if (hook.once) {\n toRemove.push(hook.id);\n }\n } catch (error) {\n if (event !== 'onError') {\n await this.emit('onError', {\n ...currentEntry,\n error: error instanceof Error ? error : new Error(String(error)),\n hookEvent: event\n });\n } else {\n // An onError hook threw — surface to console (single shot)\n // without dispatching another onError (which would recurse).\n // eslint-disable-next-line no-console\n console.error('HookManager: onError hook threw, swallowed to break recursion:', error);\n }\n }\n }\n\n toRemove.forEach(id => this.removeHook(event, id));\n return currentEntry;\n } finally {\n this._onErrorDepth.set(event, depth);\n }\n }\n\n async process(entry: HookLogEntry): Promise<HookLogEntry> {\n let currentEntry = { ...entry };\n\n currentEntry = await this.emit('beforeLog', currentEntry);\n\n if (this.middlewares.length > 0) {\n let index = 0;\n\n const executeNext = async (): Promise<void> => {\n if (index < this.middlewares.length) {\n const middleware = this.middlewares[index++];\n if (middleware) {\n await middleware.fn(currentEntry, executeNext);\n }\n }\n };\n\n await executeNext();\n }\n\n return currentEntry;\n }\n\n async afterProcess(entry: HookLogEntry): Promise<void> {\n await this.emit('afterLog', entry);\n }\n\n clear(): void {\n this.hooks.forEach(hooks => hooks.length = 0);\n this.middlewares.length = 0;\n }\n\n getStats(): { hooks: Record<HookEvent, number>; middlewares: number } {\n return {\n hooks: {\n beforeLog: this.hooks.get('beforeLog')?.length || 0,\n afterLog: this.hooks.get('afterLog')?.length || 0,\n onError: this.hooks.get('onError')?.length || 0\n },\n middlewares: this.middlewares.length\n };\n }\n}\n\nlet _defaultHookManager: HookManager | null = null;\n\nexport function getDefaultHookManager(): HookManager {\n if (!_defaultHookManager) {\n _defaultHookManager = new HookManager();\n }\n return _defaultHookManager;\n}\n","/**\n * @fileoverview HookBridge — HookManager facade.\n * Encapsulates hook registration, middleware pipeline, and event emission.\n */\n\nimport type { HookEvent, HookCallback, MiddlewareFn } from '../types/index.js';\nimport { HookManager } from './index.js';\n\n/**\n * Bridge for hook and middleware management.\n */\nexport interface HookBridge {\n /** Registers a hook for an event. Returns unsubscribe function. */\n on(event: HookEvent, callback: HookCallback, priority?: number): () => void;\n /** Registers a one-time hook. Returns unsubscribe function. */\n once(event: HookEvent, callback: HookCallback, priority?: number): () => void;\n /** Removes a registered hook. Returns true if removed. */\n off(event: HookEvent, callback: HookCallback): boolean;\n /** Adds middleware to the pipeline. Returns unsubscribe function. */\n use(middleware: MiddlewareFn, priority?: number): () => void;\n /** Returns the underlying HookManager. */\n getHookManager(): HookManager;\n}\n\n/**\n * Creates a HookBridge instance.\n */\nexport function createHookBridge(): HookBridge {\n const hookManager = new HookManager();\n\n return {\n on(event: HookEvent, callback: HookCallback, priority?: number): () => void {\n return hookManager.on(event, callback, priority);\n },\n\n once(event: HookEvent, callback: HookCallback, priority?: number): () => void {\n return hookManager.once(event, callback, priority);\n },\n\n off(event: HookEvent, callback: HookCallback): boolean {\n return hookManager.off(event, callback);\n },\n\n use(middleware: MiddlewareFn, priority?: number): () => void {\n return hookManager.use(middleware, priority);\n },\n\n getHookManager(): HookManager {\n return hookManager;\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
//#region src/hooks/HookManager.ts
|
|
2
|
-
const MAX_ONERROR_DEPTH = 5;
|
|
3
|
-
function generateId() {
|
|
4
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
5
|
-
}
|
|
6
|
-
var HookManager = class {
|
|
7
|
-
hooks = /* @__PURE__ */ new Map();
|
|
8
|
-
middlewares = [];
|
|
9
|
-
/**
|
|
10
|
-
* Tracks current recursion depth for each hook event so `onError` chains
|
|
11
|
-
* that throw can't loop forever. Reset when the outer emit returns.
|
|
12
|
-
*/
|
|
13
|
-
_onErrorDepth = /* @__PURE__ */ new Map();
|
|
14
|
-
constructor() {
|
|
15
|
-
this.hooks.set("beforeLog", []);
|
|
16
|
-
this.hooks.set("afterLog", []);
|
|
17
|
-
this.hooks.set("onError", []);
|
|
18
|
-
}
|
|
19
|
-
on(event, callback, priority = 50) {
|
|
20
|
-
const registration = {
|
|
21
|
-
id: generateId(),
|
|
22
|
-
event,
|
|
23
|
-
callback,
|
|
24
|
-
priority,
|
|
25
|
-
once: false
|
|
26
|
-
};
|
|
27
|
-
const hooks = this.hooks.get(event);
|
|
28
|
-
hooks.push(registration);
|
|
29
|
-
hooks.sort((a, b) => b.priority - a.priority);
|
|
30
|
-
return () => this.removeHook(event, registration.id);
|
|
31
|
-
}
|
|
32
|
-
once(event, callback, priority = 50) {
|
|
33
|
-
const registration = {
|
|
34
|
-
id: generateId(),
|
|
35
|
-
event,
|
|
36
|
-
callback,
|
|
37
|
-
priority,
|
|
38
|
-
once: true
|
|
39
|
-
};
|
|
40
|
-
const hooks = this.hooks.get(event);
|
|
41
|
-
hooks.push(registration);
|
|
42
|
-
hooks.sort((a, b) => b.priority - a.priority);
|
|
43
|
-
return () => this.removeHook(event, registration.id);
|
|
44
|
-
}
|
|
45
|
-
off(event, callback) {
|
|
46
|
-
const hooks = this.hooks.get(event);
|
|
47
|
-
if (!hooks) return false;
|
|
48
|
-
const index = hooks.findIndex((h) => h.callback === callback);
|
|
49
|
-
if (index >= 0) {
|
|
50
|
-
hooks.splice(index, 1);
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
removeHook(event, id) {
|
|
56
|
-
const hooks = this.hooks.get(event);
|
|
57
|
-
if (hooks) {
|
|
58
|
-
const index = hooks.findIndex((h) => h.id === id);
|
|
59
|
-
if (index >= 0) hooks.splice(index, 1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
use(middleware, priority = 50) {
|
|
63
|
-
const registration = {
|
|
64
|
-
id: generateId(),
|
|
65
|
-
fn: middleware,
|
|
66
|
-
priority
|
|
67
|
-
};
|
|
68
|
-
this.middlewares.push(registration);
|
|
69
|
-
this.middlewares.sort((a, b) => b.priority - a.priority);
|
|
70
|
-
return () => {
|
|
71
|
-
const index = this.middlewares.findIndex((m) => m.id === registration.id);
|
|
72
|
-
if (index >= 0) this.middlewares.splice(index, 1);
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
async emit(event, entry) {
|
|
76
|
-
const depth = this._onErrorDepth.get(entry.hookEvent ?? event) ?? 0;
|
|
77
|
-
if (event === "onError" && depth >= MAX_ONERROR_DEPTH) {
|
|
78
|
-
console.error("HookManager: onError recursion limit reached, dropping entry:", entry);
|
|
79
|
-
return entry;
|
|
80
|
-
}
|
|
81
|
-
this._onErrorDepth.set(event, depth + 1);
|
|
82
|
-
try {
|
|
83
|
-
const hooks = this.hooks.get(event) || [];
|
|
84
|
-
let currentEntry = { ...entry };
|
|
85
|
-
const toRemove = [];
|
|
86
|
-
for (const hook of hooks) try {
|
|
87
|
-
const result = await hook.callback(currentEntry);
|
|
88
|
-
if (result) currentEntry = {
|
|
89
|
-
...currentEntry,
|
|
90
|
-
...result
|
|
91
|
-
};
|
|
92
|
-
if (hook.once) toRemove.push(hook.id);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
if (event !== "onError") await this.emit("onError", {
|
|
95
|
-
...currentEntry,
|
|
96
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
97
|
-
hookEvent: event
|
|
98
|
-
});
|
|
99
|
-
else console.error("HookManager: onError hook threw, swallowed to break recursion:", error);
|
|
100
|
-
}
|
|
101
|
-
toRemove.forEach((id) => this.removeHook(event, id));
|
|
102
|
-
return currentEntry;
|
|
103
|
-
} finally {
|
|
104
|
-
this._onErrorDepth.set(event, depth);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async process(entry) {
|
|
108
|
-
let currentEntry = { ...entry };
|
|
109
|
-
currentEntry = await this.emit("beforeLog", currentEntry);
|
|
110
|
-
if (this.middlewares.length > 0) {
|
|
111
|
-
let index = 0;
|
|
112
|
-
const executeNext = async () => {
|
|
113
|
-
if (index < this.middlewares.length) {
|
|
114
|
-
const middleware = this.middlewares[index++];
|
|
115
|
-
if (middleware) await middleware.fn(currentEntry, executeNext);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
await executeNext();
|
|
119
|
-
}
|
|
120
|
-
return currentEntry;
|
|
121
|
-
}
|
|
122
|
-
async afterProcess(entry) {
|
|
123
|
-
await this.emit("afterLog", entry);
|
|
124
|
-
}
|
|
125
|
-
clear() {
|
|
126
|
-
this.hooks.forEach((hooks) => hooks.length = 0);
|
|
127
|
-
this.middlewares.length = 0;
|
|
128
|
-
}
|
|
129
|
-
getStats() {
|
|
130
|
-
return {
|
|
131
|
-
hooks: {
|
|
132
|
-
beforeLog: this.hooks.get("beforeLog")?.length || 0,
|
|
133
|
-
afterLog: this.hooks.get("afterLog")?.length || 0,
|
|
134
|
-
onError: this.hooks.get("onError")?.length || 0
|
|
135
|
-
},
|
|
136
|
-
middlewares: this.middlewares.length
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
let _defaultHookManager = null;
|
|
141
|
-
function getDefaultHookManager() {
|
|
142
|
-
if (!_defaultHookManager) _defaultHookManager = new HookManager();
|
|
143
|
-
return _defaultHookManager;
|
|
144
|
-
}
|
|
145
|
-
//#endregion
|
|
146
|
-
//#region src/hooks/HookBridge.ts
|
|
147
|
-
/**
|
|
148
|
-
* Creates a HookBridge instance.
|
|
149
|
-
*/
|
|
150
|
-
function createHookBridge() {
|
|
151
|
-
const hookManager = new HookManager();
|
|
152
|
-
return {
|
|
153
|
-
on(event, callback, priority) {
|
|
154
|
-
return hookManager.on(event, callback, priority);
|
|
155
|
-
},
|
|
156
|
-
once(event, callback, priority) {
|
|
157
|
-
return hookManager.once(event, callback, priority);
|
|
158
|
-
},
|
|
159
|
-
off(event, callback) {
|
|
160
|
-
return hookManager.off(event, callback);
|
|
161
|
-
},
|
|
162
|
-
use(middleware, priority) {
|
|
163
|
-
return hookManager.use(middleware, priority);
|
|
164
|
-
},
|
|
165
|
-
getHookManager() {
|
|
166
|
-
return hookManager;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
//#endregion
|
|
171
|
-
export { HookManager as n, getDefaultHookManager as r, createHookBridge as t };
|
|
172
|
-
|
|
173
|
-
//# sourceMappingURL=HookBridge-SgMmbXZB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HookBridge-SgMmbXZB.js","names":[],"sources":["../../src/hooks/HookManager.ts","../../src/hooks/HookBridge.ts"],"sourcesContent":["import type {\n HookLogEntry,\n HookEvent,\n HookCallback,\n MiddlewareFn,\n HookRegistration,\n MiddlewareRegistration,\n IHookManager\n} from '../types/index.js';\n\nconst MAX_ONERROR_DEPTH = 5;\n\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\nexport class HookManager implements IHookManager {\n private hooks: Map<HookEvent, HookRegistration[]> = new Map();\n private middlewares: MiddlewareRegistration[] = [];\n /**\n * Tracks current recursion depth for each hook event so `onError` chains\n * that throw can't loop forever. Reset when the outer emit returns.\n */\n private _onErrorDepth: Map<HookEvent, number> = new Map();\n\n constructor() {\n this.hooks.set('beforeLog', []);\n this.hooks.set('afterLog', []);\n this.hooks.set('onError', []);\n }\n\n on(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {\n const registration: HookRegistration = {\n id: generateId(),\n event,\n callback,\n priority,\n once: false\n };\n\n const hooks = this.hooks.get(event)!;\n hooks.push(registration);\n hooks.sort((a, b) => b.priority - a.priority);\n\n return () => this.removeHook(event, registration.id);\n }\n\n once(event: HookEvent, callback: HookCallback, priority: number = 50): () => void {\n const registration: HookRegistration = {\n id: generateId(),\n event,\n callback,\n priority,\n once: true\n };\n\n const hooks = this.hooks.get(event)!;\n hooks.push(registration);\n hooks.sort((a, b) => b.priority - a.priority);\n\n return () => this.removeHook(event, registration.id);\n }\n\n off(event: HookEvent, callback: HookCallback): boolean {\n const hooks = this.hooks.get(event);\n if (!hooks) return false;\n\n const index = hooks.findIndex(h => h.callback === callback);\n if (index >= 0) {\n hooks.splice(index, 1);\n return true;\n }\n return false;\n }\n\n private removeHook(event: HookEvent, id: string): void {\n const hooks = this.hooks.get(event);\n if (hooks) {\n const index = hooks.findIndex(h => h.id === id);\n if (index >= 0) {\n hooks.splice(index, 1);\n }\n }\n }\n\n use(middleware: MiddlewareFn, priority: number = 50): () => void {\n const registration: MiddlewareRegistration = {\n id: generateId(),\n fn: middleware,\n priority\n };\n\n this.middlewares.push(registration);\n this.middlewares.sort((a, b) => b.priority - a.priority);\n\n return () => {\n const index = this.middlewares.findIndex(m => m.id === registration.id);\n if (index >= 0) {\n this.middlewares.splice(index, 1);\n }\n };\n }\n\n async emit(event: HookEvent, entry: HookLogEntry): Promise<HookLogEntry> {\n // Re-entrancy guard. Without this, an onError hook that itself throws\n // would re-enter emit('onError', ...) and either spin forever or\n // recurse until the stack blows. We allow a small burst (MAX_ONERROR_DEPTH)\n // so legitimate fan-out keeps working, but break the cycle.\n const depth = (this._onErrorDepth.get(entry.hookEvent ?? event) ?? 0);\n if (event === 'onError' && depth >= MAX_ONERROR_DEPTH) {\n // eslint-disable-next-line no-console\n console.error('HookManager: onError recursion limit reached, dropping entry:', entry);\n return entry;\n }\n this._onErrorDepth.set(event, depth + 1);\n\n try {\n const hooks = this.hooks.get(event) || [];\n let currentEntry = { ...entry };\n const toRemove: string[] = [];\n\n for (const hook of hooks) {\n try {\n const result = await hook.callback(currentEntry);\n if (result) {\n currentEntry = { ...currentEntry, ...result };\n }\n if (hook.once) {\n toRemove.push(hook.id);\n }\n } catch (error) {\n if (event !== 'onError') {\n await this.emit('onError', {\n ...currentEntry,\n error: error instanceof Error ? error : new Error(String(error)),\n hookEvent: event\n });\n } else {\n // An onError hook threw — surface to console (single shot)\n // without dispatching another onError (which would recurse).\n // eslint-disable-next-line no-console\n console.error('HookManager: onError hook threw, swallowed to break recursion:', error);\n }\n }\n }\n\n toRemove.forEach(id => this.removeHook(event, id));\n return currentEntry;\n } finally {\n this._onErrorDepth.set(event, depth);\n }\n }\n\n async process(entry: HookLogEntry): Promise<HookLogEntry> {\n let currentEntry = { ...entry };\n\n currentEntry = await this.emit('beforeLog', currentEntry);\n\n if (this.middlewares.length > 0) {\n let index = 0;\n\n const executeNext = async (): Promise<void> => {\n if (index < this.middlewares.length) {\n const middleware = this.middlewares[index++];\n if (middleware) {\n await middleware.fn(currentEntry, executeNext);\n }\n }\n };\n\n await executeNext();\n }\n\n return currentEntry;\n }\n\n async afterProcess(entry: HookLogEntry): Promise<void> {\n await this.emit('afterLog', entry);\n }\n\n clear(): void {\n this.hooks.forEach(hooks => hooks.length = 0);\n this.middlewares.length = 0;\n }\n\n getStats(): { hooks: Record<HookEvent, number>; middlewares: number } {\n return {\n hooks: {\n beforeLog: this.hooks.get('beforeLog')?.length || 0,\n afterLog: this.hooks.get('afterLog')?.length || 0,\n onError: this.hooks.get('onError')?.length || 0\n },\n middlewares: this.middlewares.length\n };\n }\n}\n\nlet _defaultHookManager: HookManager | null = null;\n\nexport function getDefaultHookManager(): HookManager {\n if (!_defaultHookManager) {\n _defaultHookManager = new HookManager();\n }\n return _defaultHookManager;\n}\n","/**\n * @fileoverview HookBridge — HookManager facade.\n * Encapsulates hook registration, middleware pipeline, and event emission.\n */\n\nimport type { HookEvent, HookCallback, MiddlewareFn } from '../types/index.js';\nimport { HookManager } from './index.js';\n\n/**\n * Bridge for hook and middleware management.\n */\nexport interface HookBridge {\n /** Registers a hook for an event. Returns unsubscribe function. */\n on(event: HookEvent, callback: HookCallback, priority?: number): () => void;\n /** Registers a one-time hook. Returns unsubscribe function. */\n once(event: HookEvent, callback: HookCallback, priority?: number): () => void;\n /** Removes a registered hook. Returns true if removed. */\n off(event: HookEvent, callback: HookCallback): boolean;\n /** Adds middleware to the pipeline. Returns unsubscribe function. */\n use(middleware: MiddlewareFn, priority?: number): () => void;\n /** Returns the underlying HookManager. */\n getHookManager(): HookManager;\n}\n\n/**\n * Creates a HookBridge instance.\n */\nexport function createHookBridge(): HookBridge {\n const hookManager = new HookManager();\n\n return {\n on(event: HookEvent, callback: HookCallback, priority?: number): () => void {\n return hookManager.on(event, callback, priority);\n },\n\n once(event: HookEvent, callback: HookCallback, priority?: number): () => void {\n return hookManager.once(event, callback, priority);\n },\n\n off(event: HookEvent, callback: HookCallback): boolean {\n return hookManager.off(event, callback);\n },\n\n use(middleware: MiddlewareFn, priority?: number): () => void {\n return hookManager.use(middleware, priority);\n },\n\n getHookManager(): HookManager {\n return hookManager;\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LogContext-Cwn-1Zzb.js","names":[],"sources":["../../src/context/LogContext.ts"],"sourcesContent":["/**\n * @fileoverview LogContext bridge — MDC (Mapped Diagnostic Context) management.\n * Encapsulates per-logger structured context, child logger creation, and\n * OTel resource merging.\n *\n * F4 MDC API reset:\n * - `withContext(bindings, fn?)` — if fn provided, run within AsyncLocalStorage.\n * Without fn: no-op (backwards compat shim for the old setter shape).\n * - `withContextAsync(bindings, fn)` — async callback variant.\n * - `child(bindings)` remains immutable (canonical MDC pattern).\n * - Feature-detect AsyncLocalStorage; browser fallback is a no-op.\n */\n\nimport type { ILogResourceRef } from '../types/index.js';\nimport type { LoggerConfig } from '../types/index.js';\n\n/**\n * Snapshot of the bound context. Returned by {@link LogContext.getContext}.\n */\nexport type ContextSnapshot = Readonly<Record<string, unknown>>;\n\n/**\n * Factory function type for creating child Logger instances.\n * Passed to LogContext so `child()` can instantiate new loggers without\n * introducing a circular import. Returns unknown — the actual Logger class\n * is used by the caller and the returned instance has its `context` field\n * written to by LogContext.\n */\nexport type ChildLoggerFactory = (config: Partial<LoggerConfig>) => unknown;\n\n/**\n * Minimal shape of a Logger instance needed by LogContext.\n * Used to avoid circular dependencies between LogContext and Logger.\n * The `_parentContextRecord` field is set by the parent Logger after\n * `LogContext.child()` returns, establishing the context chain.\n */\nexport interface ChildLoggerShape {\n _parentContextRecord?: Record<string, unknown>;\n /** Legacy field — no longer the canonical context source (F4.5.5 fix). */\n context?: Record<string, unknown>;\n}\n\n/**\n * Options passed to {@link createLogContext}.\n */\nexport interface ILogContextOptions {\n /** Initial context key-value pairs. */\n initialContext?: Record<string, unknown>;\n /** Factory for creating child logger instances. */\n childLoggerFactory: ChildLoggerFactory;\n /** Initial OTel resource to merge into every record. */\n initialResource?: Partial<ILogResourceRef>;\n /**\n * Returns the parent logger's merged context record at child-creation time.\n * Used by _getContextRecord() to build the context chain.\n * @internal\n */\n getParentContextRecord?: () => Record<string, unknown>;\n /**\n * The ALS instance to use for withContext scoping.\n * @internal\n */\n alsInstance?: ALS;\n}\n\n/**\n * Result returned by {@link createLogContext}.\n */\nexport interface LogContext {\n /**\n * Current bound context snapshot (shallow copy — mutation does NOT affect\n * what subsequent log calls emit).\n */\n getContext(): ContextSnapshot;\n\n /**\n * Runs `fn` within an AsyncLocalStorage scope where `bindings` are\n * merged into the context for all log calls inside `fn`.\n *\n * If `fn` is not provided (the old setter shape), this is a no-op\n * for backwards compatibility. Prefer `child()` for persistent binding\n * or `withContextAsync()` for async callbacks.\n *\n * @param bindings - Key-value pairs to attach for the duration of `fn`\n * @param fn - Optional synchronous function to run with the scoped bindings\n * @returns The return value of `fn`, or undefined if no fn provided\n */\n withContext<R>(bindings: Record<string, unknown>, fn?: () => R): R | undefined;\n\n /**\n * Async variant of `withContext`. Runs `fn` within an AsyncLocalStorage\n * scope so bindings are available to all async log calls inside `fn`.\n *\n * @param bindings - Key-value pairs to attach for the duration of `fn`\n * @param fn - Async function to run with the scoped bindings\n * @returns The return value of `fn`\n */\n withContextAsync<R>(bindings: Record<string, unknown>, fn: () => Promise<R>): Promise<R>;\n\n /**\n * Drops every key from the bound context. After this call, emitted\n * records no longer carry `attributes` until {@link withContext} or\n * {@link child} re-establishes one.\n *\n * @returns The same LogContext instance, now context-free\n */\n clearContext(): this;\n\n /**\n * Updates the default OTel resource (service.name, version, env).\n * Persisted into every emitted record's `resource` field unless the\n * record itself overrides it.\n *\n * @param resource - Partial OTel resource to merge into the current one\n * @returns The same LogContext instance, for chaining\n */\n setResource(resource: Partial<ILogResourceRef>): this;\n\n /**\n * Returns an immutable copy of this logger with the extra context bound.\n * Future calls on the child emit with the merged context, without\n * mutating the parent — the canonical MDC pattern.\n *\n * @param extra - Key-value pairs to attach (requestId, userId, ...)\n * @returns A new Logger with merged context\n */\n child(extra: Record<string, unknown>): ChildLoggerShape;\n\n /** Internal context record. Exposed for TransportRecord assembly. */\n _getContextRecord(): Record<string, unknown>;\n /**\n * Returns the base context WITHOUT the ALS overlay.\n * Used by Logger.child() to capture the parent context snapshot for\n * child logger creation (F4.5.5 fix).\n * @internal\n */\n _getBaseContextRecord(): Record<string, unknown>;\n /** Internal resource record. Exposed for TransportRecord assembly. */\n _getResource(): Partial<ILogResourceRef> | undefined;\n /**\n * Returns the current AsyncLocalStorage store, if ALS is active.\n * @internal\n */\n _getAlsStore(): Record<string, unknown> | undefined;\n}\n\n// AsyncLocalStorage type (Node 14+, undefined in browser)\ntype ALS = {\n run<R>(store: Record<string, unknown>, fn: () => R): R;\n getStore(): Record<string, unknown> | undefined;\n};\ndeclare const AsyncLocalStorage: new () => ALS;\n\n// Feature-detect AsyncLocalStorage\nconst hasALS = typeof AsyncLocalStorage !== 'undefined';\nconst alsInstance: ALS | undefined = hasALS ? new AsyncLocalStorage() : undefined;\n\n/**\n * Creates a LogContext instance.\n *\n * @param options - Configuration options\n * @returns A LogContext instance\n */\nexport function createLogContext(options: ILogContextOptions): LogContext {\n let context: Record<string, unknown> = { ...options.initialContext };\n let resource: Partial<ILogResourceRef> | undefined = options.initialResource\n ? { ...options.initialResource }\n : undefined;\n\n // Use provided ALS instance or fall back to module-level (browser fallback)\n const als = options.alsInstance ?? alsInstance;\n\n return {\n getContext(): ContextSnapshot {\n return { ...context };\n },\n\n withContext<R>(bindings: Record<string, unknown>, fn?: () => R): R | undefined {\n // No-op without AsyncLocalStorage (browser) — warn once\n if (!als) {\n if (fn) return fn();\n return undefined;\n }\n // No fn: backwards-compat no-op setter shim\n if (!fn) return undefined;\n // Run fn within AsyncLocalStorage scope\n const merged = { ...context, ...bindings };\n return als.run(merged, fn);\n },\n\n async withContextAsync<R>(bindings: Record<string, unknown>, fn: () => Promise<R>): Promise<R> {\n if (!als) return fn();\n const merged = { ...context, ...bindings };\n return als.run(merged, fn);\n },\n\n clearContext(): typeof this {\n context = {};\n return this;\n },\n\n setResource(res: Partial<ILogResourceRef>): typeof this {\n resource = { ...resource, ...res };\n return this;\n },\n\n child(_extra: Record<string, unknown>): ChildLoggerShape {\n // Creates the child logger via factory. Captures the current\n // _getBaseContextRecord() snapshot (parent context WITHOUT ALS) at\n // child-creation time. ALS is transient and should not be baked into\n // the child's _parentContextRecord — it is applied fresh at dispatch time.\n // Note: _extra (bindings) are stored by Logger.child() as _bindings.\n const snapshot = this._getBaseContextRecord();\n const childLogger = options.childLoggerFactory({}) as ChildLoggerShape;\n // Store on childLogger for Logger.child() to pick up\n (childLogger as unknown as Record<string, unknown>)['__parentSnapshot'] = snapshot;\n return childLogger;\n },\n\n _getContextRecord(): Record<string, unknown> {\n // Returns the full merged context for dispatch purposes.\n // Base (parent snapshot + own context) plus ALS overlay if active.\n const base = this._getBaseContextRecord();\n const alsContext = als?.getStore();\n if (alsContext && Object.keys(alsContext).length > 0) {\n return { ...base, ...alsContext };\n }\n return base;\n },\n\n _getBaseContextRecord(): Record<string, unknown> {\n // Returns parent context chain + own context (NO ALS overlay).\n // ALS is applied by _getContextRecord() as a live overlay.\n let base: Record<string, unknown> = {};\n const parentRecord = options.getParentContextRecord?.() ?? null;\n if (parentRecord && Object.keys(parentRecord).length > 0) {\n base = parentRecord;\n } else if (Object.keys(context).length > 0) {\n base = context;\n }\n if (Object.keys(context).length > 0) {\n base = { ...base, ...context };\n }\n return base;\n },\n\n _getResource(): Partial<ILogResourceRef> | undefined {\n return resource;\n },\n\n _getAlsStore(): Record<string, unknown> | undefined {\n return als?.getStore();\n }\n };\n}\n"],"mappings":";AA2JA,MAAM,cADS,OAAO,sBAAsB,cACE,IAAI,kBAAkB,IAAI,KAAA;;;;;;;AAQxE,SAAgB,iBAAiB,SAAyC;CACtE,IAAI,UAAmC,EAAE,GAAG,QAAQ,eAAe;CACnE,IAAI,WAAiD,QAAQ,kBACvD,EAAE,GAAG,QAAQ,gBAAgB,IAC7B,KAAA;CAGN,MAAM,MAAM,QAAQ,eAAe;CAEnC,OAAO;EACH,aAA8B;GAC1B,OAAO,EAAE,GAAG,QAAQ;EACxB;EAEA,YAAe,UAAmC,IAA6B;GAE3E,IAAI,CAAC,KAAK;IACN,IAAI,IAAI,OAAO,GAAG;IAClB;GACJ;GAEA,IAAI,CAAC,IAAI,OAAO,KAAA;GAEhB,MAAM,SAAS;IAAE,GAAG;IAAS,GAAG;GAAS;GACzC,OAAO,IAAI,IAAI,QAAQ,EAAE;EAC7B;EAEA,MAAM,iBAAoB,UAAmC,IAAkC;GAC3F,IAAI,CAAC,KAAK,OAAO,GAAG;GACpB,MAAM,SAAS;IAAE,GAAG;IAAS,GAAG;GAAS;GACzC,OAAO,IAAI,IAAI,QAAQ,EAAE;EAC7B;EAEA,eAA4B;GACxB,UAAU,CAAC;GACX,OAAO;EACX;EAEA,YAAY,KAA4C;GACpD,WAAW;IAAE,GAAG;IAAU,GAAG;GAAI;GACjC,OAAO;EACX;EAEA,MAAM,QAAmD;GAMrD,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,cAAc,QAAQ,mBAAmB,CAAC,CAAC;GAEjD,YAAoD,sBAAsB;GAC1E,OAAO;EACX;EAEA,oBAA6C;GAGzC,MAAM,OAAO,KAAK,sBAAsB;GACxC,MAAM,aAAa,KAAK,SAAS;GACjC,IAAI,cAAc,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GAC/C,OAAO;IAAE,GAAG;IAAM,GAAG;GAAW;GAEpC,OAAO;EACX;EAEA,wBAAiD;GAG7C,IAAI,OAAgC,CAAC;GACrC,MAAM,eAAe,QAAQ,yBAAyB,KAAK;GAC3D,IAAI,gBAAgB,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,GACnD,OAAO;QACJ,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GACrC,OAAO;GAEX,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GAC9B,OAAO;IAAE,GAAG;IAAM,GAAG;GAAQ;GAEjC,OAAO;EACX;EAEA,eAAqD;GACjD,OAAO;EACX;EAEA,eAAoD;GAChD,OAAO,KAAK,SAAS;EACzB;CACJ;AACJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LogContext-L7HzynFw.cjs","names":[],"sources":["../../src/context/LogContext.ts"],"sourcesContent":["/**\n * @fileoverview LogContext bridge — MDC (Mapped Diagnostic Context) management.\n * Encapsulates per-logger structured context, child logger creation, and\n * OTel resource merging.\n *\n * F4 MDC API reset:\n * - `withContext(bindings, fn?)` — if fn provided, run within AsyncLocalStorage.\n * Without fn: no-op (backwards compat shim for the old setter shape).\n * - `withContextAsync(bindings, fn)` — async callback variant.\n * - `child(bindings)` remains immutable (canonical MDC pattern).\n * - Feature-detect AsyncLocalStorage; browser fallback is a no-op.\n */\n\nimport type { ILogResourceRef } from '../types/index.js';\nimport type { LoggerConfig } from '../types/index.js';\n\n/**\n * Snapshot of the bound context. Returned by {@link LogContext.getContext}.\n */\nexport type ContextSnapshot = Readonly<Record<string, unknown>>;\n\n/**\n * Factory function type for creating child Logger instances.\n * Passed to LogContext so `child()` can instantiate new loggers without\n * introducing a circular import. Returns unknown — the actual Logger class\n * is used by the caller and the returned instance has its `context` field\n * written to by LogContext.\n */\nexport type ChildLoggerFactory = (config: Partial<LoggerConfig>) => unknown;\n\n/**\n * Minimal shape of a Logger instance needed by LogContext.\n * Used to avoid circular dependencies between LogContext and Logger.\n * The `_parentContextRecord` field is set by the parent Logger after\n * `LogContext.child()` returns, establishing the context chain.\n */\nexport interface ChildLoggerShape {\n _parentContextRecord?: Record<string, unknown>;\n /** Legacy field — no longer the canonical context source (F4.5.5 fix). */\n context?: Record<string, unknown>;\n}\n\n/**\n * Options passed to {@link createLogContext}.\n */\nexport interface ILogContextOptions {\n /** Initial context key-value pairs. */\n initialContext?: Record<string, unknown>;\n /** Factory for creating child logger instances. */\n childLoggerFactory: ChildLoggerFactory;\n /** Initial OTel resource to merge into every record. */\n initialResource?: Partial<ILogResourceRef>;\n /**\n * Returns the parent logger's merged context record at child-creation time.\n * Used by _getContextRecord() to build the context chain.\n * @internal\n */\n getParentContextRecord?: () => Record<string, unknown>;\n /**\n * The ALS instance to use for withContext scoping.\n * @internal\n */\n alsInstance?: ALS;\n}\n\n/**\n * Result returned by {@link createLogContext}.\n */\nexport interface LogContext {\n /**\n * Current bound context snapshot (shallow copy — mutation does NOT affect\n * what subsequent log calls emit).\n */\n getContext(): ContextSnapshot;\n\n /**\n * Runs `fn` within an AsyncLocalStorage scope where `bindings` are\n * merged into the context for all log calls inside `fn`.\n *\n * If `fn` is not provided (the old setter shape), this is a no-op\n * for backwards compatibility. Prefer `child()` for persistent binding\n * or `withContextAsync()` for async callbacks.\n *\n * @param bindings - Key-value pairs to attach for the duration of `fn`\n * @param fn - Optional synchronous function to run with the scoped bindings\n * @returns The return value of `fn`, or undefined if no fn provided\n */\n withContext<R>(bindings: Record<string, unknown>, fn?: () => R): R | undefined;\n\n /**\n * Async variant of `withContext`. Runs `fn` within an AsyncLocalStorage\n * scope so bindings are available to all async log calls inside `fn`.\n *\n * @param bindings - Key-value pairs to attach for the duration of `fn`\n * @param fn - Async function to run with the scoped bindings\n * @returns The return value of `fn`\n */\n withContextAsync<R>(bindings: Record<string, unknown>, fn: () => Promise<R>): Promise<R>;\n\n /**\n * Drops every key from the bound context. After this call, emitted\n * records no longer carry `attributes` until {@link withContext} or\n * {@link child} re-establishes one.\n *\n * @returns The same LogContext instance, now context-free\n */\n clearContext(): this;\n\n /**\n * Updates the default OTel resource (service.name, version, env).\n * Persisted into every emitted record's `resource` field unless the\n * record itself overrides it.\n *\n * @param resource - Partial OTel resource to merge into the current one\n * @returns The same LogContext instance, for chaining\n */\n setResource(resource: Partial<ILogResourceRef>): this;\n\n /**\n * Returns an immutable copy of this logger with the extra context bound.\n * Future calls on the child emit with the merged context, without\n * mutating the parent — the canonical MDC pattern.\n *\n * @param extra - Key-value pairs to attach (requestId, userId, ...)\n * @returns A new Logger with merged context\n */\n child(extra: Record<string, unknown>): ChildLoggerShape;\n\n /** Internal context record. Exposed for TransportRecord assembly. */\n _getContextRecord(): Record<string, unknown>;\n /**\n * Returns the base context WITHOUT the ALS overlay.\n * Used by Logger.child() to capture the parent context snapshot for\n * child logger creation (F4.5.5 fix).\n * @internal\n */\n _getBaseContextRecord(): Record<string, unknown>;\n /** Internal resource record. Exposed for TransportRecord assembly. */\n _getResource(): Partial<ILogResourceRef> | undefined;\n /**\n * Returns the current AsyncLocalStorage store, if ALS is active.\n * @internal\n */\n _getAlsStore(): Record<string, unknown> | undefined;\n}\n\n// AsyncLocalStorage type (Node 14+, undefined in browser)\ntype ALS = {\n run<R>(store: Record<string, unknown>, fn: () => R): R;\n getStore(): Record<string, unknown> | undefined;\n};\ndeclare const AsyncLocalStorage: new () => ALS;\n\n// Feature-detect AsyncLocalStorage\nconst hasALS = typeof AsyncLocalStorage !== 'undefined';\nconst alsInstance: ALS | undefined = hasALS ? new AsyncLocalStorage() : undefined;\n\n/**\n * Creates a LogContext instance.\n *\n * @param options - Configuration options\n * @returns A LogContext instance\n */\nexport function createLogContext(options: ILogContextOptions): LogContext {\n let context: Record<string, unknown> = { ...options.initialContext };\n let resource: Partial<ILogResourceRef> | undefined = options.initialResource\n ? { ...options.initialResource }\n : undefined;\n\n // Use provided ALS instance or fall back to module-level (browser fallback)\n const als = options.alsInstance ?? alsInstance;\n\n return {\n getContext(): ContextSnapshot {\n return { ...context };\n },\n\n withContext<R>(bindings: Record<string, unknown>, fn?: () => R): R | undefined {\n // No-op without AsyncLocalStorage (browser) — warn once\n if (!als) {\n if (fn) return fn();\n return undefined;\n }\n // No fn: backwards-compat no-op setter shim\n if (!fn) return undefined;\n // Run fn within AsyncLocalStorage scope\n const merged = { ...context, ...bindings };\n return als.run(merged, fn);\n },\n\n async withContextAsync<R>(bindings: Record<string, unknown>, fn: () => Promise<R>): Promise<R> {\n if (!als) return fn();\n const merged = { ...context, ...bindings };\n return als.run(merged, fn);\n },\n\n clearContext(): typeof this {\n context = {};\n return this;\n },\n\n setResource(res: Partial<ILogResourceRef>): typeof this {\n resource = { ...resource, ...res };\n return this;\n },\n\n child(_extra: Record<string, unknown>): ChildLoggerShape {\n // Creates the child logger via factory. Captures the current\n // _getBaseContextRecord() snapshot (parent context WITHOUT ALS) at\n // child-creation time. ALS is transient and should not be baked into\n // the child's _parentContextRecord — it is applied fresh at dispatch time.\n // Note: _extra (bindings) are stored by Logger.child() as _bindings.\n const snapshot = this._getBaseContextRecord();\n const childLogger = options.childLoggerFactory({}) as ChildLoggerShape;\n // Store on childLogger for Logger.child() to pick up\n (childLogger as unknown as Record<string, unknown>)['__parentSnapshot'] = snapshot;\n return childLogger;\n },\n\n _getContextRecord(): Record<string, unknown> {\n // Returns the full merged context for dispatch purposes.\n // Base (parent snapshot + own context) plus ALS overlay if active.\n const base = this._getBaseContextRecord();\n const alsContext = als?.getStore();\n if (alsContext && Object.keys(alsContext).length > 0) {\n return { ...base, ...alsContext };\n }\n return base;\n },\n\n _getBaseContextRecord(): Record<string, unknown> {\n // Returns parent context chain + own context (NO ALS overlay).\n // ALS is applied by _getContextRecord() as a live overlay.\n let base: Record<string, unknown> = {};\n const parentRecord = options.getParentContextRecord?.() ?? null;\n if (parentRecord && Object.keys(parentRecord).length > 0) {\n base = parentRecord;\n } else if (Object.keys(context).length > 0) {\n base = context;\n }\n if (Object.keys(context).length > 0) {\n base = { ...base, ...context };\n }\n return base;\n },\n\n _getResource(): Partial<ILogResourceRef> | undefined {\n return resource;\n },\n\n _getAlsStore(): Record<string, unknown> | undefined {\n return als?.getStore();\n }\n };\n}\n"],"mappings":";AA2JA,MAAM,cADS,OAAO,sBAAsB,cACE,IAAI,kBAAkB,IAAI,KAAA;;;;;;;AAQxE,SAAgB,iBAAiB,SAAyC;CACtE,IAAI,UAAmC,EAAE,GAAG,QAAQ,eAAe;CACnE,IAAI,WAAiD,QAAQ,kBACvD,EAAE,GAAG,QAAQ,gBAAgB,IAC7B,KAAA;CAGN,MAAM,MAAM,QAAQ,eAAe;CAEnC,OAAO;EACH,aAA8B;GAC1B,OAAO,EAAE,GAAG,QAAQ;EACxB;EAEA,YAAe,UAAmC,IAA6B;GAE3E,IAAI,CAAC,KAAK;IACN,IAAI,IAAI,OAAO,GAAG;IAClB;GACJ;GAEA,IAAI,CAAC,IAAI,OAAO,KAAA;GAEhB,MAAM,SAAS;IAAE,GAAG;IAAS,GAAG;GAAS;GACzC,OAAO,IAAI,IAAI,QAAQ,EAAE;EAC7B;EAEA,MAAM,iBAAoB,UAAmC,IAAkC;GAC3F,IAAI,CAAC,KAAK,OAAO,GAAG;GACpB,MAAM,SAAS;IAAE,GAAG;IAAS,GAAG;GAAS;GACzC,OAAO,IAAI,IAAI,QAAQ,EAAE;EAC7B;EAEA,eAA4B;GACxB,UAAU,CAAC;GACX,OAAO;EACX;EAEA,YAAY,KAA4C;GACpD,WAAW;IAAE,GAAG;IAAU,GAAG;GAAI;GACjC,OAAO;EACX;EAEA,MAAM,QAAmD;GAMrD,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,cAAc,QAAQ,mBAAmB,CAAC,CAAC;GAEjD,YAAoD,sBAAsB;GAC1E,OAAO;EACX;EAEA,oBAA6C;GAGzC,MAAM,OAAO,KAAK,sBAAsB;GACxC,MAAM,aAAa,KAAK,SAAS;GACjC,IAAI,cAAc,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GAC/C,OAAO;IAAE,GAAG;IAAM,GAAG;GAAW;GAEpC,OAAO;EACX;EAEA,wBAAiD;GAG7C,IAAI,OAAgC,CAAC;GACrC,MAAM,eAAe,QAAQ,yBAAyB,KAAK;GAC3D,IAAI,gBAAgB,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,GACnD,OAAO;QACJ,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GACrC,OAAO;GAEX,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,SAAS,GAC9B,OAAO;IAAE,GAAG;IAAM,GAAG;GAAQ;GAEjC,OAAO;EACX;EAEA,eAAqD;GACjD,OAAO;EACX;EAEA,eAAoD;GAChD,OAAO,KAAK,SAAS;EACzB;CACJ;AACJ"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
//#region src/serializers/SerializerRegistry.ts
|
|
2
|
-
const DEFAULT_CONFIG = {
|
|
3
|
-
maxDepth: 5,
|
|
4
|
-
circular: "placeholder",
|
|
5
|
-
preserveUndefined: false
|
|
6
|
-
};
|
|
7
|
-
var SerializerRegistry = class {
|
|
8
|
-
serializers = /* @__PURE__ */ new Map();
|
|
9
|
-
config;
|
|
10
|
-
constructor(config = {}) {
|
|
11
|
-
this.config = {
|
|
12
|
-
...DEFAULT_CONFIG,
|
|
13
|
-
...config
|
|
14
|
-
};
|
|
15
|
-
this.registerDefaults();
|
|
16
|
-
}
|
|
17
|
-
registerDefaults() {
|
|
18
|
-
this.add(Error, (err) => ({
|
|
19
|
-
name: err.name,
|
|
20
|
-
message: err.message,
|
|
21
|
-
stack: err.stack?.split("\n").slice(0, 10),
|
|
22
|
-
...err.cause ? { cause: this.serialize(err.cause) } : {}
|
|
23
|
-
}), 100);
|
|
24
|
-
this.add(Date, (date) => ({
|
|
25
|
-
iso: date.toISOString(),
|
|
26
|
-
timestamp: date.getTime()
|
|
27
|
-
}), 90);
|
|
28
|
-
this.add(RegExp, (regex) => ({
|
|
29
|
-
pattern: regex.source,
|
|
30
|
-
flags: regex.flags
|
|
31
|
-
}), 90);
|
|
32
|
-
this.add(Map, (map, ctx) => {
|
|
33
|
-
const obj = {};
|
|
34
|
-
map.forEach((value, key) => {
|
|
35
|
-
const keyStr = typeof key === "object" ? JSON.stringify(key) : String(key);
|
|
36
|
-
obj[keyStr] = this.serializeInternal(value, {
|
|
37
|
-
...ctx,
|
|
38
|
-
depth: ctx.depth + 1,
|
|
39
|
-
path: [...ctx.path, keyStr]
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
return {
|
|
43
|
-
__type: "Map",
|
|
44
|
-
entries: obj
|
|
45
|
-
};
|
|
46
|
-
}, 80);
|
|
47
|
-
this.add(Set, (set, ctx) => ({
|
|
48
|
-
__type: "Set",
|
|
49
|
-
values: Array.from(set).map((v, i) => this.serializeInternal(v, {
|
|
50
|
-
...ctx,
|
|
51
|
-
depth: ctx.depth + 1,
|
|
52
|
-
path: [...ctx.path, `[${i}]`]
|
|
53
|
-
}))
|
|
54
|
-
}), 80);
|
|
55
|
-
if (typeof Buffer !== "undefined") this.add(Buffer, (buf) => ({
|
|
56
|
-
__type: "Buffer",
|
|
57
|
-
length: buf.length,
|
|
58
|
-
preview: buf.slice(0, 50).toString("hex")
|
|
59
|
-
}), 70);
|
|
60
|
-
}
|
|
61
|
-
add(type, serializer, priority = 50) {
|
|
62
|
-
this.serializers.set(type, {
|
|
63
|
-
type,
|
|
64
|
-
serializer,
|
|
65
|
-
priority
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
remove(type) {
|
|
69
|
-
return this.serializers.delete(type);
|
|
70
|
-
}
|
|
71
|
-
has(type) {
|
|
72
|
-
return this.serializers.has(type);
|
|
73
|
-
}
|
|
74
|
-
getAll() {
|
|
75
|
-
return Array.from(this.serializers.values()).sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
|
|
76
|
-
}
|
|
77
|
-
findSerializer(value) {
|
|
78
|
-
const sorted = this.getAll();
|
|
79
|
-
for (const entry of sorted) if (value instanceof entry.type) return entry;
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
serializeInternal(value, context) {
|
|
83
|
-
if (value === null) return null;
|
|
84
|
-
if (value === void 0) return this.config.preserveUndefined ? void 0 : "[undefined]";
|
|
85
|
-
if (typeof value === "function") return `[Function: ${value.name || "anonymous"}]`;
|
|
86
|
-
if (typeof value !== "object") return value;
|
|
87
|
-
if (context.depth >= this.config.maxDepth) return "[Max Depth]";
|
|
88
|
-
if (context.seen.has(value)) switch (this.config.circular) {
|
|
89
|
-
case "error": throw new Error(`Circular reference at ${context.path.join(".")}`);
|
|
90
|
-
case "skip": return;
|
|
91
|
-
default: return "[Circular]";
|
|
92
|
-
}
|
|
93
|
-
context.seen.add(value);
|
|
94
|
-
const serializer = this.findSerializer(value);
|
|
95
|
-
if (serializer) return serializer.serializer(value, context);
|
|
96
|
-
if (Array.isArray(value)) return value.map((item, i) => this.serializeInternal(item, {
|
|
97
|
-
...context,
|
|
98
|
-
depth: context.depth + 1,
|
|
99
|
-
path: [...context.path, `[${i}]`]
|
|
100
|
-
}));
|
|
101
|
-
const result = {};
|
|
102
|
-
for (const [key, val] of Object.entries(value)) result[key] = this.serializeInternal(val, {
|
|
103
|
-
...context,
|
|
104
|
-
depth: context.depth + 1,
|
|
105
|
-
path: [...context.path, key]
|
|
106
|
-
});
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
serialize(value, config) {
|
|
110
|
-
const mergedConfig = {
|
|
111
|
-
...this.config,
|
|
112
|
-
...config
|
|
113
|
-
};
|
|
114
|
-
return this.serializeInternal(value, {
|
|
115
|
-
depth: 0,
|
|
116
|
-
maxDepth: mergedConfig.maxDepth,
|
|
117
|
-
path: [],
|
|
118
|
-
seen: /* @__PURE__ */ new WeakSet()
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
let _defaultRegistry = null;
|
|
123
|
-
function getDefaultSerializerRegistry() {
|
|
124
|
-
if (!_defaultRegistry) _defaultRegistry = new SerializerRegistry();
|
|
125
|
-
return _defaultRegistry;
|
|
126
|
-
}
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/serializers/SerializerBridge.ts
|
|
129
|
-
/**
|
|
130
|
-
* Creates a SerializerBridge instance.
|
|
131
|
-
*/
|
|
132
|
-
function createSerializerBridge() {
|
|
133
|
-
const serializerRegistry = new SerializerRegistry();
|
|
134
|
-
return {
|
|
135
|
-
addSerializer(type, serializer, priority) {
|
|
136
|
-
serializerRegistry.add(type, serializer, priority);
|
|
137
|
-
},
|
|
138
|
-
removeSerializer(type) {
|
|
139
|
-
return serializerRegistry.remove(type);
|
|
140
|
-
},
|
|
141
|
-
getSerializerRegistry() {
|
|
142
|
-
return serializerRegistry;
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
Object.defineProperty(exports, "SerializerRegistry", {
|
|
148
|
-
enumerable: true,
|
|
149
|
-
get: function() {
|
|
150
|
-
return SerializerRegistry;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
Object.defineProperty(exports, "createSerializerBridge", {
|
|
154
|
-
enumerable: true,
|
|
155
|
-
get: function() {
|
|
156
|
-
return createSerializerBridge;
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
Object.defineProperty(exports, "getDefaultSerializerRegistry", {
|
|
160
|
-
enumerable: true,
|
|
161
|
-
get: function() {
|
|
162
|
-
return getDefaultSerializerRegistry;
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
//# sourceMappingURL=SerializerBridge-BaOQOb8q.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SerializerBridge-BaOQOb8q.cjs","names":[],"sources":["../../src/serializers/SerializerRegistry.ts","../../src/serializers/SerializerBridge.ts"],"sourcesContent":["import type {\n SerializerFn,\n SerializerContext,\n SerializerEntry,\n SerializerConfig,\n ISerializerRegistry\n} from '../types/index.js';\n\nconst DEFAULT_CONFIG: Required<SerializerConfig> = {\n maxDepth: 5,\n circular: 'placeholder',\n preserveUndefined: false\n};\n\nexport class SerializerRegistry implements ISerializerRegistry {\n private serializers: Map<Function, SerializerEntry> = new Map();\n private config: Required<SerializerConfig>;\n\n constructor(config: SerializerConfig = {}) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.registerDefaults();\n }\n\n private registerDefaults(): void {\n this.add(Error, (err: Error) => ({\n name: err.name,\n message: err.message,\n stack: err.stack?.split('\\n').slice(0, 10),\n ...(err.cause ? { cause: this.serialize(err.cause) } : {})\n }), 100);\n\n this.add(Date, (date: Date) => ({\n iso: date.toISOString(),\n timestamp: date.getTime()\n }), 90);\n\n this.add(RegExp, (regex: RegExp) => ({\n pattern: regex.source,\n flags: regex.flags\n }), 90);\n\n this.add(Map, (map: Map<any, any>, ctx) => {\n const obj: Record<string, any> = {};\n map.forEach((value, key) => {\n const keyStr = typeof key === 'object' ? JSON.stringify(key) : String(key);\n obj[keyStr] = this.serializeInternal(value, {\n ...ctx,\n depth: ctx.depth + 1,\n path: [...ctx.path, keyStr]\n });\n });\n return { __type: 'Map', entries: obj };\n }, 80);\n\n this.add(Set, (set: Set<any>, ctx) => ({\n __type: 'Set',\n values: Array.from(set).map((v, i) =>\n this.serializeInternal(v, {\n ...ctx,\n depth: ctx.depth + 1,\n path: [...ctx.path, `[${i}]`]\n })\n )\n }), 80);\n\n if (typeof Buffer !== 'undefined') {\n this.add(Buffer as any, (buf: Buffer) => ({\n __type: 'Buffer',\n length: buf.length,\n preview: buf.slice(0, 50).toString('hex')\n }), 70);\n }\n }\n\n add<T>(\n type: new (...args: any[]) => T,\n serializer: SerializerFn<T>,\n priority: number = 50\n ): void {\n this.serializers.set(type, { type, serializer, priority });\n }\n\n remove<T>(type: new (...args: any[]) => T): boolean {\n return this.serializers.delete(type);\n }\n\n has<T>(type: new (...args: any[]) => T): boolean {\n return this.serializers.has(type);\n }\n\n getAll(): SerializerEntry[] {\n return Array.from(this.serializers.values())\n .sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));\n }\n\n private findSerializer(value: any): SerializerEntry | null {\n const sorted = this.getAll();\n for (const entry of sorted) {\n if (value instanceof entry.type) {\n return entry;\n }\n }\n return null;\n }\n\n private serializeInternal(value: any, context: SerializerContext): any {\n if (value === null) return null;\n if (value === undefined) return this.config.preserveUndefined ? undefined : '[undefined]';\n if (typeof value === 'function') return `[Function: ${value.name || 'anonymous'}]`;\n if (typeof value !== 'object') return value;\n\n if (context.depth >= this.config.maxDepth) {\n return '[Max Depth]';\n }\n\n if (context.seen.has(value)) {\n switch (this.config.circular) {\n case 'error':\n throw new Error(`Circular reference at ${context.path.join('.')}`);\n case 'skip':\n return undefined;\n case 'placeholder':\n default:\n return '[Circular]';\n }\n }\n context.seen.add(value);\n\n const serializer = this.findSerializer(value);\n if (serializer) {\n return serializer.serializer(value, context);\n }\n\n if (Array.isArray(value)) {\n return value.map((item, i) =>\n this.serializeInternal(item, {\n ...context,\n depth: context.depth + 1,\n path: [...context.path, `[${i}]`]\n })\n );\n }\n\n const result: Record<string, any> = {};\n for (const [key, val] of Object.entries(value)) {\n result[key] = this.serializeInternal(val, {\n ...context,\n depth: context.depth + 1,\n path: [...context.path, key]\n });\n }\n return result;\n }\n\n serialize(value: any, config?: SerializerConfig): any {\n const mergedConfig = { ...this.config, ...config };\n return this.serializeInternal(value, {\n depth: 0,\n maxDepth: mergedConfig.maxDepth,\n path: [],\n seen: new WeakSet()\n });\n }\n}\n\nlet _defaultRegistry: SerializerRegistry | null = null;\n\nexport function getDefaultSerializerRegistry(): SerializerRegistry {\n if (!_defaultRegistry) {\n _defaultRegistry = new SerializerRegistry();\n }\n return _defaultRegistry;\n}\n","/**\n * @fileoverview SerializerBridge — SerializerRegistry facade.\n * Encapsulates serializer registration, removal, and registry access.\n */\n\nimport type { SerializerFn } from '../types/index.js';\nimport { SerializerRegistry } from './index.js';\n\n/**\n * Bridge for serializer management.\n */\nexport interface SerializerBridge {\n /** Adds a serializer for a type. */\n addSerializer<T>(type: new (...args: unknown[]) => T, serializer: SerializerFn<T>, priority?: number): void;\n removeSerializer<T>(type: new (...args: unknown[]) => T): boolean;\n /** Returns the underlying registry. */\n getSerializerRegistry(): SerializerRegistry;\n}\n\n/**\n * Creates a SerializerBridge instance.\n */\nexport function createSerializerBridge(): SerializerBridge {\n const serializerRegistry = new SerializerRegistry();\n\n return {\n addSerializer<T>(type: new (...args: unknown[]) => T, serializer: SerializerFn<T>, priority?: number): void {\n serializerRegistry.add(type, serializer, priority);\n },\n\n removeSerializer<T>(type: new (...args: unknown[]) => T): boolean {\n return serializerRegistry.remove(type);\n },\n\n getSerializerRegistry(): SerializerRegistry {\n return serializerRegistry;\n }\n };\n}\n"],"mappings":"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"}
|