@blac/logging-plugin 2.0.13 → 2.0.15
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/dist/LoggingPlugin.d.ts +5 -5
- package/dist/LoggingPlugin.d.ts.map +1 -1
- package/dist/formatters/GroupedFormatter.d.ts +1 -1
- package/dist/formatters/GroupedFormatter.d.ts.map +1 -1
- package/dist/formatters/SimpleFormatter.d.ts +1 -1
- package/dist/formatters/SimpleFormatter.d.ts.map +1 -1
- package/dist/index.cjs +42 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +42 -18
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/LoggingPlugin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BlacPlugin,
|
|
1
|
+
import type { BlacPlugin, PathSet, PluginContext } from '@blac/core';
|
|
2
2
|
import type { LoggingPluginConfig } from './types';
|
|
3
3
|
export declare class LoggingPlugin implements BlacPlugin {
|
|
4
4
|
readonly name = "LoggingPlugin";
|
|
@@ -13,11 +13,11 @@ export declare class LoggingPlugin implements BlacPlugin {
|
|
|
13
13
|
private stateChangeWindowStart;
|
|
14
14
|
private stateChangeLoggingDisabled;
|
|
15
15
|
constructor(config?: LoggingPluginConfig);
|
|
16
|
-
onInstall(
|
|
16
|
+
onInstall(ctx: PluginContext): void;
|
|
17
17
|
onUninstall(): void;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
onCreated(ctx: PluginContext): void;
|
|
19
|
+
onStateChange<S extends object>(ctx: PluginContext, previousState: S, currentState: S, paths: PathSet): void;
|
|
20
|
+
onDestroyed(ctx: PluginContext): void;
|
|
21
21
|
logStats(): void;
|
|
22
22
|
private shouldLog;
|
|
23
23
|
private shouldLogLifecycle;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoggingPlugin.d.ts","sourceRoot":"","sources":["../src/LoggingPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"LoggingPlugin.d.ts","sourceRoot":"","sources":["../src/LoggingPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,OAAO,EACP,aAAa,EAEd,MAAM,YAAY,CAAC;AAMpB,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,SAAS,CAAC;AAsBjB,qBAAa,aAAc,YAAW,UAAU;IAC9C,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,OAAO,WAAW;IAE3B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,gBAAgB,CAAmB;IAG3C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,0BAA0B,CAAS;gBAE/B,MAAM,GAAE,mBAAwB;IAmB5C,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAWnC,WAAW,IAAI,IAAI;IAenB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAwBnC,aAAa,CAAC,CAAC,SAAS,MAAM,EAC5B,GAAG,EAAE,aAAa,EAClB,aAAa,EAAE,CAAC,EAChB,YAAY,EAAE,CAAC,EACf,KAAK,EAAE,OAAO,GACb,IAAI;IA8DP,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IA6BrC,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,UAAU;CAOnB"}
|
|
@@ -14,7 +14,7 @@ export declare class GroupedFormatter {
|
|
|
14
14
|
logUninstall(): void;
|
|
15
15
|
logInstanceCreated(metadata: InstanceMetadata, initialState: unknown): void;
|
|
16
16
|
logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number, stateChangeCount: number): void;
|
|
17
|
-
logStateChanged(metadata: InstanceMetadata, previousState: unknown, currentState: unknown, callstack: string | undefined, includeCallstack: boolean): void;
|
|
17
|
+
logStateChanged(metadata: InstanceMetadata, previousState: unknown, currentState: unknown, callstack: string | undefined, includeCallstack: boolean, paths?: string[]): void;
|
|
18
18
|
logWarning(message: string, details?: Record<string, unknown>): void;
|
|
19
19
|
logStats(stats: {
|
|
20
20
|
registeredTypes: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupedFormatter.d.ts","sourceRoot":"","sources":["../../src/formatters/GroupedFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAU,cAAc,EAAE,MAAM,UAAU,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,cAAc;IAKlC,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,QAAQ;IAMhB,UAAU,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAO5E,YAAY,IAAI,IAAI;IAIpB,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"GroupedFormatter.d.ts","sourceRoot":"","sources":["../../src/formatters/GroupedFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAU,cAAc,EAAE,MAAM,UAAU,CAAC;AAEvD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,cAAc;IAKlC,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,QAAQ;IAMhB,UAAU,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAO5E,YAAY,IAAI,IAAI;IAIpB,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,GAAG,IAAI;IAS3E,mBAAmB,CACjB,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,GACvB,IAAI;IASP,eAAe,CACb,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,EACrB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,EAAE,OAAO,EACzB,KAAK,CAAC,EAAE,MAAM,EAAE,GACf,IAAI;IAcP,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYpE,QAAQ,CAAC,KAAK,EAAE;QACd,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,GAAG,IAAI;IAQR,OAAO,CAAC,cAAc;CAKvB"}
|
|
@@ -12,7 +12,7 @@ export declare class SimpleFormatter {
|
|
|
12
12
|
logUninstall(): void;
|
|
13
13
|
logInstanceCreated(metadata: InstanceMetadata): void;
|
|
14
14
|
logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number): void;
|
|
15
|
-
logStateChanged(metadata: InstanceMetadata, previousState: unknown, currentState: unknown, _callstack: string | undefined, includeCallstack: boolean): void;
|
|
15
|
+
logStateChanged(metadata: InstanceMetadata, previousState: unknown, currentState: unknown, _callstack: string | undefined, includeCallstack: boolean, paths?: string[]): void;
|
|
16
16
|
logWarning(message: string): void;
|
|
17
17
|
logStats(stats: {
|
|
18
18
|
registeredTypes: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SimpleFormatter.d.ts","sourceRoot":"","sources":["../../src/formatters/SimpleFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAU,cAAc,EAAE,MAAM,UAAU,CAAC;AAEvD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,cAAc;IAKlC,OAAO,CAAC,gBAAgB;IAKxB,UAAU,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAM5E,YAAY,IAAI,IAAI;IAIpB,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAKpD,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAQzE,eAAe,CACb,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,EACrB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,gBAAgB,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"SimpleFormatter.d.ts","sourceRoot":"","sources":["../../src/formatters/SimpleFormatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAU,cAAc,EAAE,MAAM,UAAU,CAAC;AAEvD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,cAAc;IAKlC,OAAO,CAAC,gBAAgB;IAKxB,UAAU,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAM5E,YAAY,IAAI,IAAI;IAIpB,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAKpD,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAQzE,eAAe,CACb,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,OAAO,EACtB,YAAY,EAAE,OAAO,EACrB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,gBAAgB,EAAE,OAAO,EACzB,KAAK,CAAC,EAAE,MAAM,EAAE,GACf,IAAI;IAeP,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC,QAAQ,CAAC,KAAK,EAAE;QACd,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,GAAG,IAAI;IAMR,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,cAAc;CAKvB"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _blac_core = require("@blac/core");
|
|
2
3
|
//#region src/formatters/SimpleFormatter.ts
|
|
3
4
|
var SimpleFormatter = class {
|
|
4
5
|
constructor(config) {
|
|
@@ -23,11 +24,12 @@ var SimpleFormatter = class {
|
|
|
23
24
|
const lifespan = this.formatDuration(lifespanMs);
|
|
24
25
|
this.logger.log(`${this.prefix} Disposed ${instanceId} (lived ${lifespan})`);
|
|
25
26
|
}
|
|
26
|
-
logStateChanged(metadata, previousState, currentState, _callstack, includeCallstack) {
|
|
27
|
+
logStateChanged(metadata, previousState, currentState, _callstack, includeCallstack, paths) {
|
|
27
28
|
const instanceId = this.formatInstanceId(metadata.className, metadata.id);
|
|
28
29
|
const prev = this.formatState(previousState);
|
|
29
30
|
const curr = this.formatState(currentState);
|
|
30
31
|
this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);
|
|
32
|
+
if (paths !== void 0) this.logger.log(`${this.prefix} Paths: ${paths.join(", ")}`);
|
|
31
33
|
if (includeCallstack && _callstack) this.logger.log(`${this.prefix} Callstack: ${_callstack}`);
|
|
32
34
|
}
|
|
33
35
|
logWarning(message) {
|
|
@@ -86,7 +88,6 @@ var GroupedFormatter = class {
|
|
|
86
88
|
this.logger.log("Class:", metadata.className);
|
|
87
89
|
this.logger.log("Instance ID:", metadata.id);
|
|
88
90
|
this.logger.log("Initial state:", initialState);
|
|
89
|
-
if (metadata.callstack) this.logger.log("Callstack:", metadata.callstack);
|
|
90
91
|
this.groupEnd();
|
|
91
92
|
}
|
|
92
93
|
logInstanceDisposed(metadata, lifespanMs, stateChangeCount) {
|
|
@@ -97,11 +98,12 @@ var GroupedFormatter = class {
|
|
|
97
98
|
this.logger.log("Final state:", metadata.state);
|
|
98
99
|
this.groupEnd();
|
|
99
100
|
}
|
|
100
|
-
logStateChanged(metadata, previousState, currentState, callstack, includeCallstack) {
|
|
101
|
+
logStateChanged(metadata, previousState, currentState, callstack, includeCallstack, paths) {
|
|
101
102
|
const instanceId = this.formatInstanceId(metadata.className, metadata.id);
|
|
102
103
|
this.group(`${this.prefix} ${instanceId} state changed`);
|
|
103
104
|
this.logger.log("Previous:", previousState);
|
|
104
105
|
this.logger.log("Current:", currentState);
|
|
106
|
+
if (paths !== void 0) this.logger.log("Paths:", paths);
|
|
105
107
|
if (includeCallstack && callstack) this.logger.log("Callstack:", callstack);
|
|
106
108
|
this.groupEnd();
|
|
107
109
|
}
|
|
@@ -239,6 +241,7 @@ function resolveConfig(config = {}) {
|
|
|
239
241
|
logLifecycle: config.logLifecycle ?? true,
|
|
240
242
|
logStateChanges: config.logStateChanges ?? true,
|
|
241
243
|
includeCallstack: config.includeCallstack ?? false,
|
|
244
|
+
logPaths: config.logPaths ?? false,
|
|
242
245
|
instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,
|
|
243
246
|
detectRapidLifecycles: config.detectRapidLifecycles ?? true,
|
|
244
247
|
rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1e3,
|
|
@@ -249,6 +252,19 @@ function resolveConfig(config = {}) {
|
|
|
249
252
|
//#endregion
|
|
250
253
|
//#region src/LoggingPlugin.ts
|
|
251
254
|
const STATE_CHANGE_RATE_LIMIT = 1e3;
|
|
255
|
+
/**
|
|
256
|
+
* Decode a `PathSet` to an array of path name strings.
|
|
257
|
+
*
|
|
258
|
+
* Returns `['<all>']` when `paths === ALL_PATHS`.
|
|
259
|
+
* Uses `interner.lookup(id)` for all other IDs.
|
|
260
|
+
*
|
|
261
|
+
* The `interner` is typed structurally to avoid a direct compile-time
|
|
262
|
+
* dependency on `@dirtytalk/structural` from this package.
|
|
263
|
+
*/
|
|
264
|
+
function decodePaths(paths, interner) {
|
|
265
|
+
if (paths === _blac_core.ALL_PATHS) return ["<all>"];
|
|
266
|
+
return Array.from(paths).map((id) => interner.lookup(id));
|
|
267
|
+
}
|
|
252
268
|
var LoggingPlugin = class {
|
|
253
269
|
constructor(config = {}) {
|
|
254
270
|
this.name = "LoggingPlugin";
|
|
@@ -265,9 +281,9 @@ var LoggingPlugin = class {
|
|
|
265
281
|
this.instanceCountMonitor = new InstanceCountMonitor(this.config, warningHandler);
|
|
266
282
|
this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);
|
|
267
283
|
}
|
|
268
|
-
onInstall(
|
|
269
|
-
this.context =
|
|
270
|
-
const stats =
|
|
284
|
+
onInstall(ctx) {
|
|
285
|
+
this.context = ctx;
|
|
286
|
+
const stats = ctx.getStats();
|
|
271
287
|
if (this.config.format === "simple") this.simpleFormatter.logInstall(stats);
|
|
272
288
|
else this.groupedFormatter.logInstall(stats);
|
|
273
289
|
}
|
|
@@ -281,17 +297,21 @@ var LoggingPlugin = class {
|
|
|
281
297
|
this.stateChangeLoggingDisabled = false;
|
|
282
298
|
this.context = void 0;
|
|
283
299
|
}
|
|
284
|
-
|
|
285
|
-
const
|
|
300
|
+
onCreated(ctx) {
|
|
301
|
+
const instance = ctx.container;
|
|
302
|
+
if (!instance) return;
|
|
303
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
286
304
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
287
305
|
this.instanceCountMonitor.onInstanceCreated(metadata.className);
|
|
288
306
|
this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);
|
|
289
307
|
if (!this.shouldLogLifecycle()) return;
|
|
290
308
|
if (this.config.format === "simple") this.simpleFormatter.logInstanceCreated(metadata);
|
|
291
|
-
else this.groupedFormatter.logInstanceCreated(metadata,
|
|
309
|
+
else this.groupedFormatter.logInstanceCreated(metadata, ctx.getState(instance));
|
|
292
310
|
}
|
|
293
|
-
|
|
294
|
-
const
|
|
311
|
+
onStateChange(ctx, previousState, currentState, paths) {
|
|
312
|
+
const instance = ctx.container;
|
|
313
|
+
if (!instance) return;
|
|
314
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
295
315
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
296
316
|
this.lifecycleMonitor.onStateChanged(metadata.id);
|
|
297
317
|
if (!this.shouldLogStateChanges()) return;
|
|
@@ -307,11 +327,15 @@ var LoggingPlugin = class {
|
|
|
307
327
|
this.logWarning(`State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`);
|
|
308
328
|
return;
|
|
309
329
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
330
|
+
const callstack = this.config.includeCallstack ? (/* @__PURE__ */ new Error()).stack : void 0;
|
|
331
|
+
const decodedPaths = this.config.logPaths ? decodePaths(paths, instance.interner) : void 0;
|
|
332
|
+
if (this.config.format === "simple") this.simpleFormatter.logStateChanged(metadata, previousState, currentState, callstack, this.config.includeCallstack, decodedPaths);
|
|
333
|
+
else this.groupedFormatter.logStateChanged(metadata, previousState, currentState, callstack, this.config.includeCallstack, decodedPaths);
|
|
334
|
+
}
|
|
335
|
+
onDestroyed(ctx) {
|
|
336
|
+
const instance = ctx.container;
|
|
337
|
+
if (!instance) return;
|
|
338
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
315
339
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
316
340
|
const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);
|
|
317
341
|
const lifespanMs = info ? Date.now() - info.createdAt : 0;
|
|
@@ -332,12 +356,12 @@ var LoggingPlugin = class {
|
|
|
332
356
|
if (this.config.include && !this.config.include.includes(className)) return false;
|
|
333
357
|
if (this.config.exclude?.includes(className)) return false;
|
|
334
358
|
if (this.config.filter) {
|
|
335
|
-
const
|
|
359
|
+
const filterCtx = {
|
|
336
360
|
instance,
|
|
337
361
|
className,
|
|
338
362
|
instanceId
|
|
339
363
|
};
|
|
340
|
-
return this.config.filter(
|
|
364
|
+
return this.config.filter(filterCtx);
|
|
341
365
|
}
|
|
342
366
|
return true;
|
|
343
367
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/formatters/SimpleFormatter.ts","../src/formatters/GroupedFormatter.ts","../src/monitors/InstanceCountMonitor.ts","../src/monitors/LifecycleMonitor.ts","../src/types.ts","../src/LoggingPlugin.ts"],"sourcesContent":["import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class SimpleFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.logger.log(\n `${this.prefix} Plugin installed (${stats.registeredTypes} types, ${stats.totalInstances} instances)`,\n );\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.logger.log(`${this.prefix} Created ${instanceId}`);\n }\n\n logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const lifespan = this.formatDuration(lifespanMs);\n this.logger.log(\n `${this.prefix} Disposed ${instanceId} (lived ${lifespan})`,\n );\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n _callstack: string | undefined,\n includeCallstack: boolean,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const prev = this.formatState(previousState);\n const curr = this.formatState(currentState);\n this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);\n\n if (includeCallstack && _callstack) {\n this.logger.log(`${this.prefix} Callstack: ${_callstack}`);\n }\n }\n\n logWarning(message: string): void {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.logger.log(\n `${this.prefix} Stats: ${stats.totalInstances} instances across ${stats.registeredTypes} types`,\n );\n }\n\n private formatState(state: unknown): string {\n if (state === null) return 'null';\n if (state === undefined) return 'undefined';\n if (typeof state === 'object') {\n try {\n const str = JSON.stringify(state);\n return str.length > 50 ? str.slice(0, 50) + '...' : str;\n } catch {\n return '[Object]';\n }\n }\n return JSON.stringify(state);\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class GroupedFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n private group(label: string, collapsed = true): void {\n if (collapsed && this.logger.groupCollapsed) {\n this.logger.groupCollapsed(label);\n } else if (this.logger.group) {\n this.logger.group(label);\n } else {\n this.logger.log(label);\n }\n }\n\n private groupEnd(): void {\n if (this.logger.groupEnd) {\n this.logger.groupEnd();\n }\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.group(`${this.prefix} Plugin installed`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.groupEnd();\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata, initialState: unknown): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Created ${instanceId}`);\n this.logger.log('Class:', metadata.className);\n this.logger.log('Instance ID:', metadata.id);\n this.logger.log('Initial state:', initialState);\n if (metadata.callstack) {\n this.logger.log('Callstack:', metadata.callstack);\n }\n this.groupEnd();\n }\n\n logInstanceDisposed(\n metadata: InstanceMetadata,\n lifespanMs: number,\n stateChangeCount: number,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Disposed ${instanceId}`);\n this.logger.log('Lifespan:', this.formatDuration(lifespanMs));\n this.logger.log('State changes:', stateChangeCount);\n this.logger.log('Final state:', metadata.state);\n this.groupEnd();\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n callstack: string | undefined,\n includeCallstack: boolean,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} ${instanceId} state changed`);\n this.logger.log('Previous:', previousState);\n this.logger.log('Current:', currentState);\n if (includeCallstack && callstack) {\n this.logger.log('Callstack:', callstack);\n }\n this.groupEnd();\n }\n\n logWarning(message: string, details?: Record<string, unknown>): void {\n if (details) {\n this.group(`${this.prefix} ⚠️ ${message}`, false);\n for (const [key, value] of Object.entries(details)) {\n this.logger.log(`${key}:`, value);\n }\n this.groupEnd();\n } else {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.group(`${this.prefix} Stats`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.logger.log('Breakdown:', stats.typeBreakdown);\n this.groupEnd();\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { ResolvedConfig } from '../types';\n\nexport class InstanceCountMonitor {\n private instanceCounts = new Map<string, number>();\n private warnedClasses = new Set<string>();\n private threshold: number;\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.threshold = config.instanceCountWarningThreshold;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string): void {\n const count = (this.instanceCounts.get(className) ?? 0) + 1;\n this.instanceCounts.set(className, count);\n\n if (count >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `High instance count: ${className} has ${count} instances`,\n {\n className,\n count,\n threshold: this.threshold,\n },\n );\n }\n }\n\n onInstanceDisposed(className: string): void {\n const count = this.instanceCounts.get(className) ?? 0;\n if (count > 0) {\n this.instanceCounts.set(className, count - 1);\n }\n\n if (count - 1 < this.threshold) {\n this.warnedClasses.delete(className);\n }\n }\n\n getStats(): Map<string, number> {\n return new Map(this.instanceCounts);\n }\n\n reset(): void {\n this.instanceCounts.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { ResolvedConfig } from '../types';\n\ninterface LifecycleEvent {\n timestamp: number;\n type: 'created' | 'disposed';\n}\n\ninterface InstanceInfo {\n createdAt: number;\n stateChangeCount: number;\n}\n\nexport class LifecycleMonitor {\n private lifecycleHistory = new Map<string, LifecycleEvent[]>();\n private instanceInfo = new Map<string, InstanceInfo>();\n private windowMs: number;\n private threshold: number;\n private enabled: boolean;\n private warnedClasses = new Set<string>();\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.windowMs = config.rapidLifecycleWindowMs;\n this.threshold = config.rapidLifecycleThreshold;\n this.enabled = config.detectRapidLifecycles;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.set(instanceId, {\n createdAt: Date.now(),\n stateChangeCount: 0,\n });\n\n this.recordEvent(className, 'created');\n this.checkRapidLifecycle(className);\n }\n\n onInstanceDisposed(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.delete(instanceId);\n this.recordEvent(className, 'disposed');\n this.checkRapidLifecycle(className);\n }\n\n onStateChanged(instanceId: string): void {\n const info = this.instanceInfo.get(instanceId);\n if (info) {\n info.stateChangeCount++;\n }\n }\n\n getInstanceInfo(instanceId: string): InstanceInfo | undefined {\n return this.instanceInfo.get(instanceId);\n }\n\n private recordEvent(className: string, type: 'created' | 'disposed'): void {\n const now = Date.now();\n const events = this.lifecycleHistory.get(className) ?? [];\n\n events.push({ timestamp: now, type });\n\n const cutoff = now - this.windowMs;\n const filtered = events.filter((e) => e.timestamp > cutoff);\n this.lifecycleHistory.set(className, filtered);\n }\n\n private checkRapidLifecycle(className: string): void {\n const events = this.lifecycleHistory.get(className) ?? [];\n const cycleCount = Math.min(\n events.filter((e) => e.type === 'created').length,\n events.filter((e) => e.type === 'disposed').length,\n );\n\n if (cycleCount >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `Rapid lifecycle: ${className} created/disposed ${cycleCount} times in ${this.windowMs}ms`,\n {\n className,\n cycleCount,\n windowMs: this.windowMs,\n threshold: this.threshold,\n },\n );\n\n setTimeout(() => {\n this.warnedClasses.delete(className);\n }, this.windowMs);\n }\n }\n\n reset(): void {\n this.lifecycleHistory.clear();\n this.instanceInfo.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { StateContainer } from '@blac/core';\n\nexport type LogLevel = 'minimal' | 'info' | 'debug' | 'verbose';\n\nexport type LogFormat = 'simple' | 'grouped';\n\nexport interface Logger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n group?(label: string): void;\n groupEnd?(): void;\n groupCollapsed?(label: string): void;\n}\n\nexport interface FilterContext {\n instance: StateContainer<any>;\n className: string;\n instanceId: string;\n}\n\nexport type FilterFn = (ctx: FilterContext) => boolean;\n\nexport interface LoggingPluginConfig {\n /** Log verbosity level (default: 'info') */\n level?: LogLevel;\n\n /** Output format (default: 'grouped') */\n format?: LogFormat;\n\n /** Custom logger implementation (default: console) */\n logger?: Logger;\n\n /** Filter which instances to log */\n filter?: FilterFn;\n\n /** Include class names to log (whitelist) */\n include?: string[];\n\n /** Exclude class names from logging (blacklist) */\n exclude?: string[];\n\n /** Log instance creation/disposal (default: true) */\n logLifecycle?: boolean;\n\n /** Log state changes (default: true) */\n logStateChanges?: boolean;\n\n /** Include callstack in state change logs (default: false) */\n includeCallstack?: boolean;\n\n /** Warn when instance count exceeds threshold (default: 50) */\n instanceCountWarningThreshold?: number;\n\n /** Warn on rapid init/dispose cycles (default: true) */\n detectRapidLifecycles?: boolean;\n\n /** Time window for rapid lifecycle detection in ms (default: 1000) */\n rapidLifecycleWindowMs?: number;\n\n /** Number of cycles in window to trigger warning (default: 5) */\n rapidLifecycleThreshold?: number;\n\n /** Log prefix (default: '[BlaC]') */\n prefix?: string;\n}\n\nexport interface ResolvedConfig {\n level: LogLevel;\n format: LogFormat;\n logger: Logger;\n filter: FilterFn | undefined;\n include: string[] | undefined;\n exclude: string[] | undefined;\n logLifecycle: boolean;\n logStateChanges: boolean;\n includeCallstack: boolean;\n instanceCountWarningThreshold: number;\n detectRapidLifecycles: boolean;\n rapidLifecycleWindowMs: number;\n rapidLifecycleThreshold: number;\n prefix: string;\n}\n\nexport function resolveConfig(\n config: LoggingPluginConfig = {},\n): ResolvedConfig {\n return {\n level: config.level ?? 'info',\n format: config.format ?? 'grouped',\n logger: config.logger ?? console,\n filter: config.filter,\n include: config.include,\n exclude: config.exclude,\n logLifecycle: config.logLifecycle ?? true,\n logStateChanges: config.logStateChanges ?? true,\n includeCallstack: config.includeCallstack ?? false,\n instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,\n detectRapidLifecycles: config.detectRapidLifecycles ?? true,\n rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1000,\n rapidLifecycleThreshold: config.rapidLifecycleThreshold ?? 5,\n prefix: config.prefix ?? '[BlaC]',\n };\n}\n","import type { BlacPlugin, PluginContext, StateContainer } from '@blac/core';\nimport { SimpleFormatter } from './formatters/SimpleFormatter';\nimport { GroupedFormatter } from './formatters/GroupedFormatter';\nimport { InstanceCountMonitor } from './monitors/InstanceCountMonitor';\nimport { LifecycleMonitor } from './monitors/LifecycleMonitor';\nimport type {\n LoggingPluginConfig,\n ResolvedConfig,\n FilterContext,\n} from './types';\nimport { resolveConfig } from './types';\n\nconst STATE_CHANGE_RATE_LIMIT = 1000; // max state changes per second\n\nexport class LoggingPlugin implements BlacPlugin {\n readonly name = 'LoggingPlugin';\n readonly version = '1.0.0';\n\n private config: ResolvedConfig;\n private context?: PluginContext;\n private simpleFormatter: SimpleFormatter;\n private groupedFormatter: GroupedFormatter;\n private instanceCountMonitor: InstanceCountMonitor;\n private lifecycleMonitor: LifecycleMonitor;\n\n // Rate limiting for state changes\n private stateChangeCount = 0;\n private stateChangeWindowStart = Date.now();\n private stateChangeLoggingDisabled = false;\n\n constructor(config: LoggingPluginConfig = {}) {\n this.config = resolveConfig(config);\n\n const warningHandler = (\n message: string,\n details?: Record<string, unknown>,\n ) => {\n this.logWarning(message, details);\n };\n\n this.simpleFormatter = new SimpleFormatter(this.config);\n this.groupedFormatter = new GroupedFormatter(this.config);\n this.instanceCountMonitor = new InstanceCountMonitor(\n this.config,\n warningHandler,\n );\n this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);\n }\n\n onInstall(context: PluginContext): void {\n this.context = context;\n const stats = context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstall(stats);\n } else {\n this.groupedFormatter.logInstall(stats);\n }\n }\n\n onUninstall(): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logUninstall();\n } else {\n this.groupedFormatter.logUninstall();\n }\n\n this.instanceCountMonitor.reset();\n this.lifecycleMonitor.reset();\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = Date.now();\n this.stateChangeLoggingDisabled = false;\n this.context = undefined;\n }\n\n onInstanceCreated(\n instance: StateContainer<any>,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.instanceCountMonitor.onInstanceCreated(metadata.className);\n this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceCreated(metadata);\n } else {\n this.groupedFormatter.logInstanceCreated(\n metadata,\n context.getState(instance),\n );\n }\n }\n\n onStateChanged<S extends object>(\n instance: StateContainer<S>,\n previousState: S,\n currentState: S,\n callstack: string | undefined,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.lifecycleMonitor.onStateChanged(metadata.id);\n\n if (!this.shouldLogStateChanges()) return;\n\n // Check rate limit\n if (this.stateChangeLoggingDisabled) return;\n\n const now = Date.now();\n if (now - this.stateChangeWindowStart >= 1000) {\n // Reset window\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = now;\n }\n\n this.stateChangeCount++;\n\n if (this.stateChangeCount > STATE_CHANGE_RATE_LIMIT) {\n this.stateChangeLoggingDisabled = true;\n this.logWarning(\n `State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`,\n );\n return;\n }\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n );\n } else {\n this.groupedFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n );\n }\n }\n\n onInstanceDisposed(\n instance: StateContainer<any>,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);\n const lifespanMs = info ? Date.now() - info.createdAt : 0;\n const stateChangeCount = info?.stateChangeCount ?? 0;\n\n this.instanceCountMonitor.onInstanceDisposed(metadata.className);\n this.lifecycleMonitor.onInstanceDisposed(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceDisposed(metadata, lifespanMs);\n } else {\n this.groupedFormatter.logInstanceDisposed(\n metadata,\n lifespanMs,\n stateChangeCount,\n );\n }\n }\n\n logStats(): void {\n if (!this.context) return;\n const stats = this.context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStats(stats);\n } else {\n this.groupedFormatter.logStats(stats);\n }\n }\n\n private shouldLog(\n instance: StateContainer<any>,\n className: string,\n instanceId: string,\n ): boolean {\n if (this.config.include && !this.config.include.includes(className)) {\n return false;\n }\n\n if (this.config.exclude?.includes(className)) {\n return false;\n }\n\n if (this.config.filter) {\n const ctx: FilterContext = {\n instance,\n className,\n instanceId,\n };\n return this.config.filter(ctx);\n }\n\n return true;\n }\n\n private shouldLogLifecycle(): boolean {\n if (!this.config.logLifecycle) return false;\n return this.config.level !== 'minimal';\n }\n\n private shouldLogStateChanges(): boolean {\n if (!this.config.logStateChanges) return false;\n return (\n this.config.level === 'info' ||\n this.config.level === 'debug' ||\n this.config.level === 'verbose'\n );\n }\n\n private logWarning(message: string, details?: Record<string, unknown>): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logWarning(message);\n } else {\n this.groupedFormatter.logWarning(message, details);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["ALL_PATHS"],"sources":["../src/formatters/SimpleFormatter.ts","../src/formatters/GroupedFormatter.ts","../src/monitors/InstanceCountMonitor.ts","../src/monitors/LifecycleMonitor.ts","../src/types.ts","../src/LoggingPlugin.ts"],"sourcesContent":["import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class SimpleFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.logger.log(\n `${this.prefix} Plugin installed (${stats.registeredTypes} types, ${stats.totalInstances} instances)`,\n );\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.logger.log(`${this.prefix} Created ${instanceId}`);\n }\n\n logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const lifespan = this.formatDuration(lifespanMs);\n this.logger.log(\n `${this.prefix} Disposed ${instanceId} (lived ${lifespan})`,\n );\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n _callstack: string | undefined,\n includeCallstack: boolean,\n paths?: string[],\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const prev = this.formatState(previousState);\n const curr = this.formatState(currentState);\n this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);\n\n if (paths !== undefined) {\n this.logger.log(`${this.prefix} Paths: ${paths.join(', ')}`);\n }\n\n if (includeCallstack && _callstack) {\n this.logger.log(`${this.prefix} Callstack: ${_callstack}`);\n }\n }\n\n logWarning(message: string): void {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.logger.log(\n `${this.prefix} Stats: ${stats.totalInstances} instances across ${stats.registeredTypes} types`,\n );\n }\n\n private formatState(state: unknown): string {\n if (state === null) return 'null';\n if (state === undefined) return 'undefined';\n if (typeof state === 'object') {\n try {\n const str = JSON.stringify(state);\n return str.length > 50 ? str.slice(0, 50) + '...' : str;\n } catch {\n return '[Object]';\n }\n }\n return JSON.stringify(state);\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class GroupedFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n private group(label: string, collapsed = true): void {\n if (collapsed && this.logger.groupCollapsed) {\n this.logger.groupCollapsed(label);\n } else if (this.logger.group) {\n this.logger.group(label);\n } else {\n this.logger.log(label);\n }\n }\n\n private groupEnd(): void {\n if (this.logger.groupEnd) {\n this.logger.groupEnd();\n }\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.group(`${this.prefix} Plugin installed`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.groupEnd();\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata, initialState: unknown): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Created ${instanceId}`);\n this.logger.log('Class:', metadata.className);\n this.logger.log('Instance ID:', metadata.id);\n this.logger.log('Initial state:', initialState);\n this.groupEnd();\n }\n\n logInstanceDisposed(\n metadata: InstanceMetadata,\n lifespanMs: number,\n stateChangeCount: number,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Disposed ${instanceId}`);\n this.logger.log('Lifespan:', this.formatDuration(lifespanMs));\n this.logger.log('State changes:', stateChangeCount);\n this.logger.log('Final state:', metadata.state);\n this.groupEnd();\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n callstack: string | undefined,\n includeCallstack: boolean,\n paths?: string[],\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} ${instanceId} state changed`);\n this.logger.log('Previous:', previousState);\n this.logger.log('Current:', currentState);\n if (paths !== undefined) {\n this.logger.log('Paths:', paths);\n }\n if (includeCallstack && callstack) {\n this.logger.log('Callstack:', callstack);\n }\n this.groupEnd();\n }\n\n logWarning(message: string, details?: Record<string, unknown>): void {\n if (details) {\n this.group(`${this.prefix} ⚠️ ${message}`, false);\n for (const [key, value] of Object.entries(details)) {\n this.logger.log(`${key}:`, value);\n }\n this.groupEnd();\n } else {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.group(`${this.prefix} Stats`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.logger.log('Breakdown:', stats.typeBreakdown);\n this.groupEnd();\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { ResolvedConfig } from '../types';\n\nexport class InstanceCountMonitor {\n private instanceCounts = new Map<string, number>();\n private warnedClasses = new Set<string>();\n private threshold: number;\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.threshold = config.instanceCountWarningThreshold;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string): void {\n const count = (this.instanceCounts.get(className) ?? 0) + 1;\n this.instanceCounts.set(className, count);\n\n if (count >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `High instance count: ${className} has ${count} instances`,\n {\n className,\n count,\n threshold: this.threshold,\n },\n );\n }\n }\n\n onInstanceDisposed(className: string): void {\n const count = this.instanceCounts.get(className) ?? 0;\n if (count > 0) {\n this.instanceCounts.set(className, count - 1);\n }\n\n if (count - 1 < this.threshold) {\n this.warnedClasses.delete(className);\n }\n }\n\n getStats(): Map<string, number> {\n return new Map(this.instanceCounts);\n }\n\n reset(): void {\n this.instanceCounts.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { ResolvedConfig } from '../types';\n\ninterface LifecycleEvent {\n timestamp: number;\n type: 'created' | 'disposed';\n}\n\ninterface InstanceInfo {\n createdAt: number;\n stateChangeCount: number;\n}\n\nexport class LifecycleMonitor {\n private lifecycleHistory = new Map<string, LifecycleEvent[]>();\n private instanceInfo = new Map<string, InstanceInfo>();\n private windowMs: number;\n private threshold: number;\n private enabled: boolean;\n private warnedClasses = new Set<string>();\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.windowMs = config.rapidLifecycleWindowMs;\n this.threshold = config.rapidLifecycleThreshold;\n this.enabled = config.detectRapidLifecycles;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.set(instanceId, {\n createdAt: Date.now(),\n stateChangeCount: 0,\n });\n\n this.recordEvent(className, 'created');\n this.checkRapidLifecycle(className);\n }\n\n onInstanceDisposed(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.delete(instanceId);\n this.recordEvent(className, 'disposed');\n this.checkRapidLifecycle(className);\n }\n\n onStateChanged(instanceId: string): void {\n const info = this.instanceInfo.get(instanceId);\n if (info) {\n info.stateChangeCount++;\n }\n }\n\n getInstanceInfo(instanceId: string): InstanceInfo | undefined {\n return this.instanceInfo.get(instanceId);\n }\n\n private recordEvent(className: string, type: 'created' | 'disposed'): void {\n const now = Date.now();\n const events = this.lifecycleHistory.get(className) ?? [];\n\n events.push({ timestamp: now, type });\n\n const cutoff = now - this.windowMs;\n const filtered = events.filter((e) => e.timestamp > cutoff);\n this.lifecycleHistory.set(className, filtered);\n }\n\n private checkRapidLifecycle(className: string): void {\n const events = this.lifecycleHistory.get(className) ?? [];\n const cycleCount = Math.min(\n events.filter((e) => e.type === 'created').length,\n events.filter((e) => e.type === 'disposed').length,\n );\n\n if (cycleCount >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `Rapid lifecycle: ${className} created/disposed ${cycleCount} times in ${this.windowMs}ms`,\n {\n className,\n cycleCount,\n windowMs: this.windowMs,\n threshold: this.threshold,\n },\n );\n\n setTimeout(() => {\n this.warnedClasses.delete(className);\n }, this.windowMs);\n }\n }\n\n reset(): void {\n this.lifecycleHistory.clear();\n this.instanceInfo.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { StateContainer } from '@blac/core';\n\nexport type LogLevel = 'minimal' | 'info' | 'debug' | 'verbose';\n\nexport type LogFormat = 'simple' | 'grouped';\n\nexport interface Logger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n group?(label: string): void;\n groupEnd?(): void;\n groupCollapsed?(label: string): void;\n}\n\nexport interface FilterContext {\n instance: StateContainer<any>;\n className: string;\n instanceId: string;\n}\n\nexport type FilterFn = (ctx: FilterContext) => boolean;\n\nexport interface LoggingPluginConfig {\n /** Log verbosity level (default: 'info') */\n level?: LogLevel;\n\n /** Output format (default: 'grouped') */\n format?: LogFormat;\n\n /** Custom logger implementation (default: console) */\n logger?: Logger;\n\n /** Filter which instances to log */\n filter?: FilterFn;\n\n /** Include class names to log (whitelist) */\n include?: string[];\n\n /** Exclude class names from logging (blacklist) */\n exclude?: string[];\n\n /** Log instance creation/disposal (default: true) */\n logLifecycle?: boolean;\n\n /** Log state changes (default: true) */\n logStateChanges?: boolean;\n\n /** Include callstack in state change logs (default: false) */\n includeCallstack?: boolean;\n\n /** Log changed path names in state change output (default: false) */\n logPaths?: boolean;\n\n /** Warn when instance count exceeds threshold (default: 50) */\n instanceCountWarningThreshold?: number;\n\n /** Warn on rapid init/dispose cycles (default: true) */\n detectRapidLifecycles?: boolean;\n\n /** Time window for rapid lifecycle detection in ms (default: 1000) */\n rapidLifecycleWindowMs?: number;\n\n /** Number of cycles in window to trigger warning (default: 5) */\n rapidLifecycleThreshold?: number;\n\n /** Log prefix (default: '[BlaC]') */\n prefix?: string;\n}\n\nexport interface ResolvedConfig {\n level: LogLevel;\n format: LogFormat;\n logger: Logger;\n filter: FilterFn | undefined;\n include: string[] | undefined;\n exclude: string[] | undefined;\n logLifecycle: boolean;\n logStateChanges: boolean;\n includeCallstack: boolean;\n logPaths: boolean;\n instanceCountWarningThreshold: number;\n detectRapidLifecycles: boolean;\n rapidLifecycleWindowMs: number;\n rapidLifecycleThreshold: number;\n prefix: string;\n}\n\nexport function resolveConfig(\n config: LoggingPluginConfig = {},\n): ResolvedConfig {\n return {\n level: config.level ?? 'info',\n format: config.format ?? 'grouped',\n logger: config.logger ?? console,\n filter: config.filter,\n include: config.include,\n exclude: config.exclude,\n logLifecycle: config.logLifecycle ?? true,\n logStateChanges: config.logStateChanges ?? true,\n includeCallstack: config.includeCallstack ?? false,\n logPaths: config.logPaths ?? false,\n instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,\n detectRapidLifecycles: config.detectRapidLifecycles ?? true,\n rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1000,\n rapidLifecycleThreshold: config.rapidLifecycleThreshold ?? 5,\n prefix: config.prefix ?? '[BlaC]',\n };\n}\n","import type {\n BlacPlugin,\n PathSet,\n PluginContext,\n StateContainer,\n} from '@blac/core';\nimport { ALL_PATHS } from '@blac/core';\nimport { SimpleFormatter } from './formatters/SimpleFormatter';\nimport { GroupedFormatter } from './formatters/GroupedFormatter';\nimport { InstanceCountMonitor } from './monitors/InstanceCountMonitor';\nimport { LifecycleMonitor } from './monitors/LifecycleMonitor';\nimport type {\n LoggingPluginConfig,\n ResolvedConfig,\n FilterContext,\n} from './types';\nimport { resolveConfig } from './types';\n\nconst STATE_CHANGE_RATE_LIMIT = 1000; // max state changes per second\n\n/**\n * Decode a `PathSet` to an array of path name strings.\n *\n * Returns `['<all>']` when `paths === ALL_PATHS`.\n * Uses `interner.lookup(id)` for all other IDs.\n *\n * The `interner` is typed structurally to avoid a direct compile-time\n * dependency on `@dirtytalk/structural` from this package.\n */\nfunction decodePaths(\n paths: PathSet,\n interner: { lookup(id: number): string },\n): string[] {\n if (paths === ALL_PATHS) return ['<all>'];\n return Array.from(paths as Set<number>).map((id) => interner.lookup(id));\n}\n\nexport class LoggingPlugin implements BlacPlugin {\n readonly name = 'LoggingPlugin';\n readonly version = '1.0.0';\n\n private config: ResolvedConfig;\n private context?: PluginContext;\n private simpleFormatter: SimpleFormatter;\n private groupedFormatter: GroupedFormatter;\n private instanceCountMonitor: InstanceCountMonitor;\n private lifecycleMonitor: LifecycleMonitor;\n\n // Rate limiting for state changes\n private stateChangeCount = 0;\n private stateChangeWindowStart = Date.now();\n private stateChangeLoggingDisabled = false;\n\n constructor(config: LoggingPluginConfig = {}) {\n this.config = resolveConfig(config);\n\n const warningHandler = (\n message: string,\n details?: Record<string, unknown>,\n ) => {\n this.logWarning(message, details);\n };\n\n this.simpleFormatter = new SimpleFormatter(this.config);\n this.groupedFormatter = new GroupedFormatter(this.config);\n this.instanceCountMonitor = new InstanceCountMonitor(\n this.config,\n warningHandler,\n );\n this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);\n }\n\n onInstall(ctx: PluginContext): void {\n this.context = ctx;\n const stats = ctx.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstall(stats);\n } else {\n this.groupedFormatter.logInstall(stats);\n }\n }\n\n onUninstall(): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logUninstall();\n } else {\n this.groupedFormatter.logUninstall();\n }\n\n this.instanceCountMonitor.reset();\n this.lifecycleMonitor.reset();\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = Date.now();\n this.stateChangeLoggingDisabled = false;\n this.context = undefined;\n }\n\n onCreated(ctx: PluginContext): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.instanceCountMonitor.onInstanceCreated(metadata.className);\n this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceCreated(metadata);\n } else {\n this.groupedFormatter.logInstanceCreated(\n metadata,\n ctx.getState(instance),\n );\n }\n }\n\n onStateChange<S extends object>(\n ctx: PluginContext,\n previousState: S,\n currentState: S,\n paths: PathSet,\n ): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.lifecycleMonitor.onStateChanged(metadata.id);\n\n if (!this.shouldLogStateChanges()) return;\n\n // Check rate limit\n if (this.stateChangeLoggingDisabled) return;\n\n const now = Date.now();\n if (now - this.stateChangeWindowStart >= 1000) {\n // Reset window\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = now;\n }\n\n this.stateChangeCount++;\n\n if (this.stateChangeCount > STATE_CHANGE_RATE_LIMIT) {\n this.stateChangeLoggingDisabled = true;\n this.logWarning(\n `State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`,\n );\n return;\n }\n\n const callstack = this.config.includeCallstack\n ? new Error().stack\n : undefined;\n\n const decodedPaths = this.config.logPaths\n ? decodePaths(paths, instance.interner)\n : undefined;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n decodedPaths,\n );\n } else {\n this.groupedFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n decodedPaths,\n );\n }\n }\n\n onDestroyed(ctx: PluginContext): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);\n const lifespanMs = info ? Date.now() - info.createdAt : 0;\n const stateChangeCount = info?.stateChangeCount ?? 0;\n\n this.instanceCountMonitor.onInstanceDisposed(metadata.className);\n this.lifecycleMonitor.onInstanceDisposed(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceDisposed(metadata, lifespanMs);\n } else {\n this.groupedFormatter.logInstanceDisposed(\n metadata,\n lifespanMs,\n stateChangeCount,\n );\n }\n }\n\n logStats(): void {\n if (!this.context) return;\n const stats = this.context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStats(stats);\n } else {\n this.groupedFormatter.logStats(stats);\n }\n }\n\n private shouldLog(\n instance: StateContainer<any>,\n className: string,\n instanceId: string,\n ): boolean {\n if (this.config.include && !this.config.include.includes(className)) {\n return false;\n }\n\n if (this.config.exclude?.includes(className)) {\n return false;\n }\n\n if (this.config.filter) {\n const filterCtx: FilterContext = {\n instance,\n className,\n instanceId,\n };\n return this.config.filter(filterCtx);\n }\n\n return true;\n }\n\n private shouldLogLifecycle(): boolean {\n if (!this.config.logLifecycle) return false;\n return this.config.level !== 'minimal';\n }\n\n private shouldLogStateChanges(): boolean {\n if (!this.config.logStateChanges) return false;\n return (\n this.config.level === 'info' ||\n this.config.level === 'debug' ||\n this.config.level === 'verbose'\n );\n }\n\n private logWarning(message: string, details?: Record<string, unknown>): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logWarning(message);\n } else {\n this.groupedFormatter.logWarning(message, details);\n }\n }\n}\n"],"mappings":";;;AAGA,IAAa,kBAAb,MAA6B;CAI3B,YAAY,QAAwB;EAClC,KAAK,SAAS,OAAO;EACrB,KAAK,SAAS,OAAO;;CAGvB,iBAAyB,WAAmB,IAAoB;EAE9D,OAAO,GAAG,UAAU,GADJ,GAAG,SAAS,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG;;CAInD,WAAW,OAAkE;EAC3E,KAAK,OAAO,IACV,GAAG,KAAK,OAAO,qBAAqB,MAAM,gBAAgB,UAAU,MAAM,eAAe,aAC1F;;CAGH,eAAqB;EACnB,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,qBAAqB;;CAGtD,mBAAmB,UAAkC;EACnD,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,WAAW,aAAa;;CAGzD,oBAAoB,UAA4B,YAA0B;EACxE,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,MAAM,WAAW,KAAK,eAAe,WAAW;EAChD,KAAK,OAAO,IACV,GAAG,KAAK,OAAO,YAAY,WAAW,UAAU,SAAS,GAC1D;;CAGH,gBACE,UACA,eACA,cACA,YACA,kBACA,OACM;EACN,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,MAAM,OAAO,KAAK,YAAY,cAAc;EAC5C,MAAM,OAAO,KAAK,YAAY,aAAa;EAC3C,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,GAAG,WAAW,UAAU,KAAK,KAAK,OAAO;EAExE,IAAI,UAAU,KAAA,GACZ,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,YAAY,MAAM,KAAK,KAAK,GAAG;EAGhE,IAAI,oBAAoB,YACtB,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,gBAAgB,aAAa;;CAIhE,WAAW,SAAuB;EAChC,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,MAAM,UAAU;;CAGlD,SAAS,OAIA;EACP,KAAK,OAAO,IACV,GAAG,KAAK,OAAO,UAAU,MAAM,eAAe,oBAAoB,MAAM,gBAAgB,QACzF;;CAGH,YAAoB,OAAwB;EAC1C,IAAI,UAAU,MAAM,OAAO;EAC3B,IAAI,UAAU,KAAA,GAAW,OAAO;EAChC,IAAI,OAAO,UAAU,UACnB,IAAI;GACF,MAAM,MAAM,KAAK,UAAU,MAAM;GACjC,OAAO,IAAI,SAAS,KAAK,IAAI,MAAM,GAAG,GAAG,GAAG,QAAQ;UAC9C;GACN,OAAO;;EAGX,OAAO,KAAK,UAAU,MAAM;;CAG9B,eAAuB,IAAoB;EACzC,IAAI,KAAK,KAAM,OAAO,GAAG,GAAG;EAC5B,IAAI,KAAK,KAAO,OAAO,IAAI,KAAK,KAAM,QAAQ,EAAE,CAAC;EACjD,OAAO,IAAI,KAAK,KAAO,QAAQ,EAAE,CAAC;;;;;AC1FtC,IAAa,mBAAb,MAA8B;CAI5B,YAAY,QAAwB;EAClC,KAAK,SAAS,OAAO;EACrB,KAAK,SAAS,OAAO;;CAGvB,iBAAyB,WAAmB,IAAoB;EAE9D,OAAO,GAAG,UAAU,GADJ,GAAG,SAAS,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG;;CAInD,MAAc,OAAe,YAAY,MAAY;EACnD,IAAI,aAAa,KAAK,OAAO,gBAC3B,KAAK,OAAO,eAAe,MAAM;OAC5B,IAAI,KAAK,OAAO,OACrB,KAAK,OAAO,MAAM,MAAM;OAExB,KAAK,OAAO,IAAI,MAAM;;CAI1B,WAAyB;EACvB,IAAI,KAAK,OAAO,UACd,KAAK,OAAO,UAAU;;CAI1B,WAAW,OAAkE;EAC3E,KAAK,MAAM,GAAG,KAAK,OAAO,mBAAmB;EAC7C,KAAK,OAAO,IAAI,qBAAqB,MAAM,gBAAgB;EAC3D,KAAK,OAAO,IAAI,oBAAoB,MAAM,eAAe;EACzD,KAAK,UAAU;;CAGjB,eAAqB;EACnB,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,qBAAqB;;CAGtD,mBAAmB,UAA4B,cAA6B;EAC1E,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,KAAK,MAAM,GAAG,KAAK,OAAO,WAAW,aAAa;EAClD,KAAK,OAAO,IAAI,UAAU,SAAS,UAAU;EAC7C,KAAK,OAAO,IAAI,gBAAgB,SAAS,GAAG;EAC5C,KAAK,OAAO,IAAI,kBAAkB,aAAa;EAC/C,KAAK,UAAU;;CAGjB,oBACE,UACA,YACA,kBACM;EACN,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,KAAK,MAAM,GAAG,KAAK,OAAO,YAAY,aAAa;EACnD,KAAK,OAAO,IAAI,aAAa,KAAK,eAAe,WAAW,CAAC;EAC7D,KAAK,OAAO,IAAI,kBAAkB,iBAAiB;EACnD,KAAK,OAAO,IAAI,gBAAgB,SAAS,MAAM;EAC/C,KAAK,UAAU;;CAGjB,gBACE,UACA,eACA,cACA,WACA,kBACA,OACM;EACN,MAAM,aAAa,KAAK,iBAAiB,SAAS,WAAW,SAAS,GAAG;EACzE,KAAK,MAAM,GAAG,KAAK,OAAO,GAAG,WAAW,gBAAgB;EACxD,KAAK,OAAO,IAAI,aAAa,cAAc;EAC3C,KAAK,OAAO,IAAI,YAAY,aAAa;EACzC,IAAI,UAAU,KAAA,GACZ,KAAK,OAAO,IAAI,UAAU,MAAM;EAElC,IAAI,oBAAoB,WACtB,KAAK,OAAO,IAAI,cAAc,UAAU;EAE1C,KAAK,UAAU;;CAGjB,WAAW,SAAiB,SAAyC;EACnE,IAAI,SAAS;GACX,KAAK,MAAM,GAAG,KAAK,OAAO,MAAM,WAAW,MAAM;GACjD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAChD,KAAK,OAAO,IAAI,GAAG,IAAI,IAAI,MAAM;GAEnC,KAAK,UAAU;SAEf,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,MAAM,UAAU;;CAIpD,SAAS,OAIA;EACP,KAAK,MAAM,GAAG,KAAK,OAAO,QAAQ;EAClC,KAAK,OAAO,IAAI,qBAAqB,MAAM,gBAAgB;EAC3D,KAAK,OAAO,IAAI,oBAAoB,MAAM,eAAe;EACzD,KAAK,OAAO,IAAI,cAAc,MAAM,cAAc;EAClD,KAAK,UAAU;;CAGjB,eAAuB,IAAoB;EACzC,IAAI,KAAK,KAAM,OAAO,GAAG,GAAG;EAC5B,IAAI,KAAK,KAAO,OAAO,IAAI,KAAK,KAAM,QAAQ,EAAE,CAAC;EACjD,OAAO,IAAI,KAAK,KAAO,QAAQ,EAAE,CAAC;;;;;AChHtC,IAAa,uBAAb,MAAkC;CAShC,YACE,QACA,WACA;wCAXuB,IAAI,KAAqB;uCAC1B,IAAI,KAAa;EAWvC,KAAK,YAAY,OAAO;EACxB,KAAK,YAAY;;CAGnB,kBAAkB,WAAyB;EACzC,MAAM,SAAS,KAAK,eAAe,IAAI,UAAU,IAAI,KAAK;EAC1D,KAAK,eAAe,IAAI,WAAW,MAAM;EAEzC,IAAI,SAAS,KAAK,aAAa,CAAC,KAAK,cAAc,IAAI,UAAU,EAAE;GACjE,KAAK,cAAc,IAAI,UAAU;GACjC,KAAK,UACH,wBAAwB,UAAU,OAAO,MAAM,aAC/C;IACE;IACA;IACA,WAAW,KAAK;IACjB,CACF;;;CAIL,mBAAmB,WAAyB;EAC1C,MAAM,QAAQ,KAAK,eAAe,IAAI,UAAU,IAAI;EACpD,IAAI,QAAQ,GACV,KAAK,eAAe,IAAI,WAAW,QAAQ,EAAE;EAG/C,IAAI,QAAQ,IAAI,KAAK,WACnB,KAAK,cAAc,OAAO,UAAU;;CAIxC,WAAgC;EAC9B,OAAO,IAAI,IAAI,KAAK,eAAe;;CAGrC,QAAc;EACZ,KAAK,eAAe,OAAO;EAC3B,KAAK,cAAc,OAAO;;;;;ACzC9B,IAAa,mBAAb,MAA8B;CAY5B,YACE,QACA,WACA;0CAdyB,IAAI,KAA+B;sCACvC,IAAI,KAA2B;uCAI9B,IAAI,KAAa;EAUvC,KAAK,WAAW,OAAO;EACvB,KAAK,YAAY,OAAO;EACxB,KAAK,UAAU,OAAO;EACtB,KAAK,YAAY;;CAGnB,kBAAkB,WAAmB,YAA0B;EAC7D,IAAI,CAAC,KAAK,SAAS;EAEnB,KAAK,aAAa,IAAI,YAAY;GAChC,WAAW,KAAK,KAAK;GACrB,kBAAkB;GACnB,CAAC;EAEF,KAAK,YAAY,WAAW,UAAU;EACtC,KAAK,oBAAoB,UAAU;;CAGrC,mBAAmB,WAAmB,YAA0B;EAC9D,IAAI,CAAC,KAAK,SAAS;EAEnB,KAAK,aAAa,OAAO,WAAW;EACpC,KAAK,YAAY,WAAW,WAAW;EACvC,KAAK,oBAAoB,UAAU;;CAGrC,eAAe,YAA0B;EACvC,MAAM,OAAO,KAAK,aAAa,IAAI,WAAW;EAC9C,IAAI,MACF,KAAK;;CAIT,gBAAgB,YAA8C;EAC5D,OAAO,KAAK,aAAa,IAAI,WAAW;;CAG1C,YAAoB,WAAmB,MAAoC;EACzE,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,SAAS,KAAK,iBAAiB,IAAI,UAAU,IAAI,EAAE;EAEzD,OAAO,KAAK;GAAE,WAAW;GAAK;GAAM,CAAC;EAErC,MAAM,SAAS,MAAM,KAAK;EAC1B,MAAM,WAAW,OAAO,QAAQ,MAAM,EAAE,YAAY,OAAO;EAC3D,KAAK,iBAAiB,IAAI,WAAW,SAAS;;CAGhD,oBAA4B,WAAyB;EACnD,MAAM,SAAS,KAAK,iBAAiB,IAAI,UAAU,IAAI,EAAE;EACzD,MAAM,aAAa,KAAK,IACtB,OAAO,QAAQ,MAAM,EAAE,SAAS,UAAU,CAAC,QAC3C,OAAO,QAAQ,MAAM,EAAE,SAAS,WAAW,CAAC,OAC7C;EAED,IAAI,cAAc,KAAK,aAAa,CAAC,KAAK,cAAc,IAAI,UAAU,EAAE;GACtE,KAAK,cAAc,IAAI,UAAU;GACjC,KAAK,UACH,oBAAoB,UAAU,oBAAoB,WAAW,YAAY,KAAK,SAAS,KACvF;IACE;IACA;IACA,UAAU,KAAK;IACf,WAAW,KAAK;IACjB,CACF;GAED,iBAAiB;IACf,KAAK,cAAc,OAAO,UAAU;MACnC,KAAK,SAAS;;;CAIrB,QAAc;EACZ,KAAK,iBAAiB,OAAO;EAC7B,KAAK,aAAa,OAAO;EACzB,KAAK,cAAc,OAAO;;;;;AChB9B,SAAgB,cACd,SAA8B,EAAE,EAChB;CAChB,OAAO;EACL,OAAO,OAAO,SAAS;EACvB,QAAQ,OAAO,UAAU;EACzB,QAAQ,OAAO,UAAU;EACzB,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,SAAS,OAAO;EAChB,cAAc,OAAO,gBAAgB;EACrC,iBAAiB,OAAO,mBAAmB;EAC3C,kBAAkB,OAAO,oBAAoB;EAC7C,UAAU,OAAO,YAAY;EAC7B,+BAA+B,OAAO,iCAAiC;EACvE,uBAAuB,OAAO,yBAAyB;EACvD,wBAAwB,OAAO,0BAA0B;EACzD,yBAAyB,OAAO,2BAA2B;EAC3D,QAAQ,OAAO,UAAU;EAC1B;;;;ACzFH,MAAM,0BAA0B;;;;;;;;;;AAWhC,SAAS,YACP,OACA,UACU;CACV,IAAI,UAAUA,WAAAA,WAAW,OAAO,CAAC,QAAQ;CACzC,OAAO,MAAM,KAAK,MAAqB,CAAC,KAAK,OAAO,SAAS,OAAO,GAAG,CAAC;;AAG1E,IAAa,gBAAb,MAAiD;CAgB/C,YAAY,SAA8B,EAAE,EAAE;cAf9B;iBACG;0BAUQ;gCACM,KAAK,KAAK;oCACN;EAGnC,KAAK,SAAS,cAAc,OAAO;EAEnC,MAAM,kBACJ,SACA,YACG;GACH,KAAK,WAAW,SAAS,QAAQ;;EAGnC,KAAK,kBAAkB,IAAI,gBAAgB,KAAK,OAAO;EACvD,KAAK,mBAAmB,IAAI,iBAAiB,KAAK,OAAO;EACzD,KAAK,uBAAuB,IAAI,qBAC9B,KAAK,QACL,eACD;EACD,KAAK,mBAAmB,IAAI,iBAAiB,KAAK,QAAQ,eAAe;;CAG3E,UAAU,KAA0B;EAClC,KAAK,UAAU;EACf,MAAM,QAAQ,IAAI,UAAU;EAE5B,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,WAAW,MAAM;OAEtC,KAAK,iBAAiB,WAAW,MAAM;;CAI3C,cAAoB;EAClB,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,cAAc;OAEnC,KAAK,iBAAiB,cAAc;EAGtC,KAAK,qBAAqB,OAAO;EACjC,KAAK,iBAAiB,OAAO;EAC7B,KAAK,mBAAmB;EACxB,KAAK,yBAAyB,KAAK,KAAK;EACxC,KAAK,6BAA6B;EAClC,KAAK,UAAU,KAAA;;CAGjB,UAAU,KAA0B;EAClC,MAAM,WAAW,IAAI;EACrB,IAAI,CAAC,UAAU;EACf,MAAM,WAAW,IAAI,oBAAoB,SAAS;EAElD,IAAI,CAAC,KAAK,UAAU,UAAU,SAAS,WAAW,SAAS,GAAG,EAC5D;EAGF,KAAK,qBAAqB,kBAAkB,SAAS,UAAU;EAC/D,KAAK,iBAAiB,kBAAkB,SAAS,WAAW,SAAS,GAAG;EAExE,IAAI,CAAC,KAAK,oBAAoB,EAAE;EAEhC,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,mBAAmB,SAAS;OAEjD,KAAK,iBAAiB,mBACpB,UACA,IAAI,SAAS,SAAS,CACvB;;CAIL,cACE,KACA,eACA,cACA,OACM;EACN,MAAM,WAAW,IAAI;EACrB,IAAI,CAAC,UAAU;EACf,MAAM,WAAW,IAAI,oBAAoB,SAAS;EAElD,IAAI,CAAC,KAAK,UAAU,UAAU,SAAS,WAAW,SAAS,GAAG,EAC5D;EAGF,KAAK,iBAAiB,eAAe,SAAS,GAAG;EAEjD,IAAI,CAAC,KAAK,uBAAuB,EAAE;EAGnC,IAAI,KAAK,4BAA4B;EAErC,MAAM,MAAM,KAAK,KAAK;EACtB,IAAI,MAAM,KAAK,0BAA0B,KAAM;GAE7C,KAAK,mBAAmB;GACxB,KAAK,yBAAyB;;EAGhC,KAAK;EAEL,IAAI,KAAK,mBAAmB,yBAAyB;GACnD,KAAK,6BAA6B;GAClC,KAAK,WACH,2CAA2C,wBAAwB,iBACpE;GACD;;EAGF,MAAM,YAAY,KAAK,OAAO,oCAC1B,IAAI,OAAO,EAAC,QACZ,KAAA;EAEJ,MAAM,eAAe,KAAK,OAAO,WAC7B,YAAY,OAAO,SAAS,SAAS,GACrC,KAAA;EAEJ,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,gBACnB,UACA,eACA,cACA,WACA,KAAK,OAAO,kBACZ,aACD;OAED,KAAK,iBAAiB,gBACpB,UACA,eACA,cACA,WACA,KAAK,OAAO,kBACZ,aACD;;CAIL,YAAY,KAA0B;EACpC,MAAM,WAAW,IAAI;EACrB,IAAI,CAAC,UAAU;EACf,MAAM,WAAW,IAAI,oBAAoB,SAAS;EAElD,IAAI,CAAC,KAAK,UAAU,UAAU,SAAS,WAAW,SAAS,GAAG,EAC5D;EAGF,MAAM,OAAO,KAAK,iBAAiB,gBAAgB,SAAS,GAAG;EAC/D,MAAM,aAAa,OAAO,KAAK,KAAK,GAAG,KAAK,YAAY;EACxD,MAAM,mBAAmB,MAAM,oBAAoB;EAEnD,KAAK,qBAAqB,mBAAmB,SAAS,UAAU;EAChE,KAAK,iBAAiB,mBAAmB,SAAS,WAAW,SAAS,GAAG;EAEzE,IAAI,CAAC,KAAK,oBAAoB,EAAE;EAEhC,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,oBAAoB,UAAU,WAAW;OAE9D,KAAK,iBAAiB,oBACpB,UACA,YACA,iBACD;;CAIL,WAAiB;EACf,IAAI,CAAC,KAAK,SAAS;EACnB,MAAM,QAAQ,KAAK,QAAQ,UAAU;EAErC,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,SAAS,MAAM;OAEpC,KAAK,iBAAiB,SAAS,MAAM;;CAIzC,UACE,UACA,WACA,YACS;EACT,IAAI,KAAK,OAAO,WAAW,CAAC,KAAK,OAAO,QAAQ,SAAS,UAAU,EACjE,OAAO;EAGT,IAAI,KAAK,OAAO,SAAS,SAAS,UAAU,EAC1C,OAAO;EAGT,IAAI,KAAK,OAAO,QAAQ;GACtB,MAAM,YAA2B;IAC/B;IACA;IACA;IACD;GACD,OAAO,KAAK,OAAO,OAAO,UAAU;;EAGtC,OAAO;;CAGT,qBAAsC;EACpC,IAAI,CAAC,KAAK,OAAO,cAAc,OAAO;EACtC,OAAO,KAAK,OAAO,UAAU;;CAG/B,wBAAyC;EACvC,IAAI,CAAC,KAAK,OAAO,iBAAiB,OAAO;EACzC,OACE,KAAK,OAAO,UAAU,UACtB,KAAK,OAAO,UAAU,WACtB,KAAK,OAAO,UAAU;;CAI1B,WAAmB,SAAiB,SAAyC;EAC3E,IAAI,KAAK,OAAO,WAAW,UACzB,KAAK,gBAAgB,WAAW,QAAQ;OAExC,KAAK,iBAAiB,WAAW,SAAS,QAAQ"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ALL_PATHS } from "@blac/core";
|
|
1
2
|
//#region src/formatters/SimpleFormatter.ts
|
|
2
3
|
var SimpleFormatter = class {
|
|
3
4
|
constructor(config) {
|
|
@@ -22,11 +23,12 @@ var SimpleFormatter = class {
|
|
|
22
23
|
const lifespan = this.formatDuration(lifespanMs);
|
|
23
24
|
this.logger.log(`${this.prefix} Disposed ${instanceId} (lived ${lifespan})`);
|
|
24
25
|
}
|
|
25
|
-
logStateChanged(metadata, previousState, currentState, _callstack, includeCallstack) {
|
|
26
|
+
logStateChanged(metadata, previousState, currentState, _callstack, includeCallstack, paths) {
|
|
26
27
|
const instanceId = this.formatInstanceId(metadata.className, metadata.id);
|
|
27
28
|
const prev = this.formatState(previousState);
|
|
28
29
|
const curr = this.formatState(currentState);
|
|
29
30
|
this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);
|
|
31
|
+
if (paths !== void 0) this.logger.log(`${this.prefix} Paths: ${paths.join(", ")}`);
|
|
30
32
|
if (includeCallstack && _callstack) this.logger.log(`${this.prefix} Callstack: ${_callstack}`);
|
|
31
33
|
}
|
|
32
34
|
logWarning(message) {
|
|
@@ -85,7 +87,6 @@ var GroupedFormatter = class {
|
|
|
85
87
|
this.logger.log("Class:", metadata.className);
|
|
86
88
|
this.logger.log("Instance ID:", metadata.id);
|
|
87
89
|
this.logger.log("Initial state:", initialState);
|
|
88
|
-
if (metadata.callstack) this.logger.log("Callstack:", metadata.callstack);
|
|
89
90
|
this.groupEnd();
|
|
90
91
|
}
|
|
91
92
|
logInstanceDisposed(metadata, lifespanMs, stateChangeCount) {
|
|
@@ -96,11 +97,12 @@ var GroupedFormatter = class {
|
|
|
96
97
|
this.logger.log("Final state:", metadata.state);
|
|
97
98
|
this.groupEnd();
|
|
98
99
|
}
|
|
99
|
-
logStateChanged(metadata, previousState, currentState, callstack, includeCallstack) {
|
|
100
|
+
logStateChanged(metadata, previousState, currentState, callstack, includeCallstack, paths) {
|
|
100
101
|
const instanceId = this.formatInstanceId(metadata.className, metadata.id);
|
|
101
102
|
this.group(`${this.prefix} ${instanceId} state changed`);
|
|
102
103
|
this.logger.log("Previous:", previousState);
|
|
103
104
|
this.logger.log("Current:", currentState);
|
|
105
|
+
if (paths !== void 0) this.logger.log("Paths:", paths);
|
|
104
106
|
if (includeCallstack && callstack) this.logger.log("Callstack:", callstack);
|
|
105
107
|
this.groupEnd();
|
|
106
108
|
}
|
|
@@ -238,6 +240,7 @@ function resolveConfig(config = {}) {
|
|
|
238
240
|
logLifecycle: config.logLifecycle ?? true,
|
|
239
241
|
logStateChanges: config.logStateChanges ?? true,
|
|
240
242
|
includeCallstack: config.includeCallstack ?? false,
|
|
243
|
+
logPaths: config.logPaths ?? false,
|
|
241
244
|
instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,
|
|
242
245
|
detectRapidLifecycles: config.detectRapidLifecycles ?? true,
|
|
243
246
|
rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1e3,
|
|
@@ -248,6 +251,19 @@ function resolveConfig(config = {}) {
|
|
|
248
251
|
//#endregion
|
|
249
252
|
//#region src/LoggingPlugin.ts
|
|
250
253
|
const STATE_CHANGE_RATE_LIMIT = 1e3;
|
|
254
|
+
/**
|
|
255
|
+
* Decode a `PathSet` to an array of path name strings.
|
|
256
|
+
*
|
|
257
|
+
* Returns `['<all>']` when `paths === ALL_PATHS`.
|
|
258
|
+
* Uses `interner.lookup(id)` for all other IDs.
|
|
259
|
+
*
|
|
260
|
+
* The `interner` is typed structurally to avoid a direct compile-time
|
|
261
|
+
* dependency on `@dirtytalk/structural` from this package.
|
|
262
|
+
*/
|
|
263
|
+
function decodePaths(paths, interner) {
|
|
264
|
+
if (paths === ALL_PATHS) return ["<all>"];
|
|
265
|
+
return Array.from(paths).map((id) => interner.lookup(id));
|
|
266
|
+
}
|
|
251
267
|
var LoggingPlugin = class {
|
|
252
268
|
constructor(config = {}) {
|
|
253
269
|
this.name = "LoggingPlugin";
|
|
@@ -264,9 +280,9 @@ var LoggingPlugin = class {
|
|
|
264
280
|
this.instanceCountMonitor = new InstanceCountMonitor(this.config, warningHandler);
|
|
265
281
|
this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);
|
|
266
282
|
}
|
|
267
|
-
onInstall(
|
|
268
|
-
this.context =
|
|
269
|
-
const stats =
|
|
283
|
+
onInstall(ctx) {
|
|
284
|
+
this.context = ctx;
|
|
285
|
+
const stats = ctx.getStats();
|
|
270
286
|
if (this.config.format === "simple") this.simpleFormatter.logInstall(stats);
|
|
271
287
|
else this.groupedFormatter.logInstall(stats);
|
|
272
288
|
}
|
|
@@ -280,17 +296,21 @@ var LoggingPlugin = class {
|
|
|
280
296
|
this.stateChangeLoggingDisabled = false;
|
|
281
297
|
this.context = void 0;
|
|
282
298
|
}
|
|
283
|
-
|
|
284
|
-
const
|
|
299
|
+
onCreated(ctx) {
|
|
300
|
+
const instance = ctx.container;
|
|
301
|
+
if (!instance) return;
|
|
302
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
285
303
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
286
304
|
this.instanceCountMonitor.onInstanceCreated(metadata.className);
|
|
287
305
|
this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);
|
|
288
306
|
if (!this.shouldLogLifecycle()) return;
|
|
289
307
|
if (this.config.format === "simple") this.simpleFormatter.logInstanceCreated(metadata);
|
|
290
|
-
else this.groupedFormatter.logInstanceCreated(metadata,
|
|
308
|
+
else this.groupedFormatter.logInstanceCreated(metadata, ctx.getState(instance));
|
|
291
309
|
}
|
|
292
|
-
|
|
293
|
-
const
|
|
310
|
+
onStateChange(ctx, previousState, currentState, paths) {
|
|
311
|
+
const instance = ctx.container;
|
|
312
|
+
if (!instance) return;
|
|
313
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
294
314
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
295
315
|
this.lifecycleMonitor.onStateChanged(metadata.id);
|
|
296
316
|
if (!this.shouldLogStateChanges()) return;
|
|
@@ -306,11 +326,15 @@ var LoggingPlugin = class {
|
|
|
306
326
|
this.logWarning(`State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`);
|
|
307
327
|
return;
|
|
308
328
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
const callstack = this.config.includeCallstack ? (/* @__PURE__ */ new Error()).stack : void 0;
|
|
330
|
+
const decodedPaths = this.config.logPaths ? decodePaths(paths, instance.interner) : void 0;
|
|
331
|
+
if (this.config.format === "simple") this.simpleFormatter.logStateChanged(metadata, previousState, currentState, callstack, this.config.includeCallstack, decodedPaths);
|
|
332
|
+
else this.groupedFormatter.logStateChanged(metadata, previousState, currentState, callstack, this.config.includeCallstack, decodedPaths);
|
|
333
|
+
}
|
|
334
|
+
onDestroyed(ctx) {
|
|
335
|
+
const instance = ctx.container;
|
|
336
|
+
if (!instance) return;
|
|
337
|
+
const metadata = ctx.getInstanceMetadata(instance);
|
|
314
338
|
if (!this.shouldLog(instance, metadata.className, metadata.id)) return;
|
|
315
339
|
const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);
|
|
316
340
|
const lifespanMs = info ? Date.now() - info.createdAt : 0;
|
|
@@ -331,12 +355,12 @@ var LoggingPlugin = class {
|
|
|
331
355
|
if (this.config.include && !this.config.include.includes(className)) return false;
|
|
332
356
|
if (this.config.exclude?.includes(className)) return false;
|
|
333
357
|
if (this.config.filter) {
|
|
334
|
-
const
|
|
358
|
+
const filterCtx = {
|
|
335
359
|
instance,
|
|
336
360
|
className,
|
|
337
361
|
instanceId
|
|
338
362
|
};
|
|
339
|
-
return this.config.filter(
|
|
363
|
+
return this.config.filter(filterCtx);
|
|
340
364
|
}
|
|
341
365
|
return true;
|
|
342
366
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/formatters/SimpleFormatter.ts","../src/formatters/GroupedFormatter.ts","../src/monitors/InstanceCountMonitor.ts","../src/monitors/LifecycleMonitor.ts","../src/types.ts","../src/LoggingPlugin.ts"],"sourcesContent":["import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class SimpleFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.logger.log(\n `${this.prefix} Plugin installed (${stats.registeredTypes} types, ${stats.totalInstances} instances)`,\n );\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.logger.log(`${this.prefix} Created ${instanceId}`);\n }\n\n logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const lifespan = this.formatDuration(lifespanMs);\n this.logger.log(\n `${this.prefix} Disposed ${instanceId} (lived ${lifespan})`,\n );\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n _callstack: string | undefined,\n includeCallstack: boolean,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const prev = this.formatState(previousState);\n const curr = this.formatState(currentState);\n this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);\n\n if (includeCallstack && _callstack) {\n this.logger.log(`${this.prefix} Callstack: ${_callstack}`);\n }\n }\n\n logWarning(message: string): void {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.logger.log(\n `${this.prefix} Stats: ${stats.totalInstances} instances across ${stats.registeredTypes} types`,\n );\n }\n\n private formatState(state: unknown): string {\n if (state === null) return 'null';\n if (state === undefined) return 'undefined';\n if (typeof state === 'object') {\n try {\n const str = JSON.stringify(state);\n return str.length > 50 ? str.slice(0, 50) + '...' : str;\n } catch {\n return '[Object]';\n }\n }\n return JSON.stringify(state);\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class GroupedFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n private group(label: string, collapsed = true): void {\n if (collapsed && this.logger.groupCollapsed) {\n this.logger.groupCollapsed(label);\n } else if (this.logger.group) {\n this.logger.group(label);\n } else {\n this.logger.log(label);\n }\n }\n\n private groupEnd(): void {\n if (this.logger.groupEnd) {\n this.logger.groupEnd();\n }\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.group(`${this.prefix} Plugin installed`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.groupEnd();\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata, initialState: unknown): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Created ${instanceId}`);\n this.logger.log('Class:', metadata.className);\n this.logger.log('Instance ID:', metadata.id);\n this.logger.log('Initial state:', initialState);\n if (metadata.callstack) {\n this.logger.log('Callstack:', metadata.callstack);\n }\n this.groupEnd();\n }\n\n logInstanceDisposed(\n metadata: InstanceMetadata,\n lifespanMs: number,\n stateChangeCount: number,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Disposed ${instanceId}`);\n this.logger.log('Lifespan:', this.formatDuration(lifespanMs));\n this.logger.log('State changes:', stateChangeCount);\n this.logger.log('Final state:', metadata.state);\n this.groupEnd();\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n callstack: string | undefined,\n includeCallstack: boolean,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} ${instanceId} state changed`);\n this.logger.log('Previous:', previousState);\n this.logger.log('Current:', currentState);\n if (includeCallstack && callstack) {\n this.logger.log('Callstack:', callstack);\n }\n this.groupEnd();\n }\n\n logWarning(message: string, details?: Record<string, unknown>): void {\n if (details) {\n this.group(`${this.prefix} ⚠️ ${message}`, false);\n for (const [key, value] of Object.entries(details)) {\n this.logger.log(`${key}:`, value);\n }\n this.groupEnd();\n } else {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.group(`${this.prefix} Stats`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.logger.log('Breakdown:', stats.typeBreakdown);\n this.groupEnd();\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { ResolvedConfig } from '../types';\n\nexport class InstanceCountMonitor {\n private instanceCounts = new Map<string, number>();\n private warnedClasses = new Set<string>();\n private threshold: number;\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.threshold = config.instanceCountWarningThreshold;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string): void {\n const count = (this.instanceCounts.get(className) ?? 0) + 1;\n this.instanceCounts.set(className, count);\n\n if (count >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `High instance count: ${className} has ${count} instances`,\n {\n className,\n count,\n threshold: this.threshold,\n },\n );\n }\n }\n\n onInstanceDisposed(className: string): void {\n const count = this.instanceCounts.get(className) ?? 0;\n if (count > 0) {\n this.instanceCounts.set(className, count - 1);\n }\n\n if (count - 1 < this.threshold) {\n this.warnedClasses.delete(className);\n }\n }\n\n getStats(): Map<string, number> {\n return new Map(this.instanceCounts);\n }\n\n reset(): void {\n this.instanceCounts.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { ResolvedConfig } from '../types';\n\ninterface LifecycleEvent {\n timestamp: number;\n type: 'created' | 'disposed';\n}\n\ninterface InstanceInfo {\n createdAt: number;\n stateChangeCount: number;\n}\n\nexport class LifecycleMonitor {\n private lifecycleHistory = new Map<string, LifecycleEvent[]>();\n private instanceInfo = new Map<string, InstanceInfo>();\n private windowMs: number;\n private threshold: number;\n private enabled: boolean;\n private warnedClasses = new Set<string>();\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.windowMs = config.rapidLifecycleWindowMs;\n this.threshold = config.rapidLifecycleThreshold;\n this.enabled = config.detectRapidLifecycles;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.set(instanceId, {\n createdAt: Date.now(),\n stateChangeCount: 0,\n });\n\n this.recordEvent(className, 'created');\n this.checkRapidLifecycle(className);\n }\n\n onInstanceDisposed(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.delete(instanceId);\n this.recordEvent(className, 'disposed');\n this.checkRapidLifecycle(className);\n }\n\n onStateChanged(instanceId: string): void {\n const info = this.instanceInfo.get(instanceId);\n if (info) {\n info.stateChangeCount++;\n }\n }\n\n getInstanceInfo(instanceId: string): InstanceInfo | undefined {\n return this.instanceInfo.get(instanceId);\n }\n\n private recordEvent(className: string, type: 'created' | 'disposed'): void {\n const now = Date.now();\n const events = this.lifecycleHistory.get(className) ?? [];\n\n events.push({ timestamp: now, type });\n\n const cutoff = now - this.windowMs;\n const filtered = events.filter((e) => e.timestamp > cutoff);\n this.lifecycleHistory.set(className, filtered);\n }\n\n private checkRapidLifecycle(className: string): void {\n const events = this.lifecycleHistory.get(className) ?? [];\n const cycleCount = Math.min(\n events.filter((e) => e.type === 'created').length,\n events.filter((e) => e.type === 'disposed').length,\n );\n\n if (cycleCount >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `Rapid lifecycle: ${className} created/disposed ${cycleCount} times in ${this.windowMs}ms`,\n {\n className,\n cycleCount,\n windowMs: this.windowMs,\n threshold: this.threshold,\n },\n );\n\n setTimeout(() => {\n this.warnedClasses.delete(className);\n }, this.windowMs);\n }\n }\n\n reset(): void {\n this.lifecycleHistory.clear();\n this.instanceInfo.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { StateContainer } from '@blac/core';\n\nexport type LogLevel = 'minimal' | 'info' | 'debug' | 'verbose';\n\nexport type LogFormat = 'simple' | 'grouped';\n\nexport interface Logger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n group?(label: string): void;\n groupEnd?(): void;\n groupCollapsed?(label: string): void;\n}\n\nexport interface FilterContext {\n instance: StateContainer<any>;\n className: string;\n instanceId: string;\n}\n\nexport type FilterFn = (ctx: FilterContext) => boolean;\n\nexport interface LoggingPluginConfig {\n /** Log verbosity level (default: 'info') */\n level?: LogLevel;\n\n /** Output format (default: 'grouped') */\n format?: LogFormat;\n\n /** Custom logger implementation (default: console) */\n logger?: Logger;\n\n /** Filter which instances to log */\n filter?: FilterFn;\n\n /** Include class names to log (whitelist) */\n include?: string[];\n\n /** Exclude class names from logging (blacklist) */\n exclude?: string[];\n\n /** Log instance creation/disposal (default: true) */\n logLifecycle?: boolean;\n\n /** Log state changes (default: true) */\n logStateChanges?: boolean;\n\n /** Include callstack in state change logs (default: false) */\n includeCallstack?: boolean;\n\n /** Warn when instance count exceeds threshold (default: 50) */\n instanceCountWarningThreshold?: number;\n\n /** Warn on rapid init/dispose cycles (default: true) */\n detectRapidLifecycles?: boolean;\n\n /** Time window for rapid lifecycle detection in ms (default: 1000) */\n rapidLifecycleWindowMs?: number;\n\n /** Number of cycles in window to trigger warning (default: 5) */\n rapidLifecycleThreshold?: number;\n\n /** Log prefix (default: '[BlaC]') */\n prefix?: string;\n}\n\nexport interface ResolvedConfig {\n level: LogLevel;\n format: LogFormat;\n logger: Logger;\n filter: FilterFn | undefined;\n include: string[] | undefined;\n exclude: string[] | undefined;\n logLifecycle: boolean;\n logStateChanges: boolean;\n includeCallstack: boolean;\n instanceCountWarningThreshold: number;\n detectRapidLifecycles: boolean;\n rapidLifecycleWindowMs: number;\n rapidLifecycleThreshold: number;\n prefix: string;\n}\n\nexport function resolveConfig(\n config: LoggingPluginConfig = {},\n): ResolvedConfig {\n return {\n level: config.level ?? 'info',\n format: config.format ?? 'grouped',\n logger: config.logger ?? console,\n filter: config.filter,\n include: config.include,\n exclude: config.exclude,\n logLifecycle: config.logLifecycle ?? true,\n logStateChanges: config.logStateChanges ?? true,\n includeCallstack: config.includeCallstack ?? false,\n instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,\n detectRapidLifecycles: config.detectRapidLifecycles ?? true,\n rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1000,\n rapidLifecycleThreshold: config.rapidLifecycleThreshold ?? 5,\n prefix: config.prefix ?? '[BlaC]',\n };\n}\n","import type { BlacPlugin, PluginContext, StateContainer } from '@blac/core';\nimport { SimpleFormatter } from './formatters/SimpleFormatter';\nimport { GroupedFormatter } from './formatters/GroupedFormatter';\nimport { InstanceCountMonitor } from './monitors/InstanceCountMonitor';\nimport { LifecycleMonitor } from './monitors/LifecycleMonitor';\nimport type {\n LoggingPluginConfig,\n ResolvedConfig,\n FilterContext,\n} from './types';\nimport { resolveConfig } from './types';\n\nconst STATE_CHANGE_RATE_LIMIT = 1000; // max state changes per second\n\nexport class LoggingPlugin implements BlacPlugin {\n readonly name = 'LoggingPlugin';\n readonly version = '1.0.0';\n\n private config: ResolvedConfig;\n private context?: PluginContext;\n private simpleFormatter: SimpleFormatter;\n private groupedFormatter: GroupedFormatter;\n private instanceCountMonitor: InstanceCountMonitor;\n private lifecycleMonitor: LifecycleMonitor;\n\n // Rate limiting for state changes\n private stateChangeCount = 0;\n private stateChangeWindowStart = Date.now();\n private stateChangeLoggingDisabled = false;\n\n constructor(config: LoggingPluginConfig = {}) {\n this.config = resolveConfig(config);\n\n const warningHandler = (\n message: string,\n details?: Record<string, unknown>,\n ) => {\n this.logWarning(message, details);\n };\n\n this.simpleFormatter = new SimpleFormatter(this.config);\n this.groupedFormatter = new GroupedFormatter(this.config);\n this.instanceCountMonitor = new InstanceCountMonitor(\n this.config,\n warningHandler,\n );\n this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);\n }\n\n onInstall(context: PluginContext): void {\n this.context = context;\n const stats = context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstall(stats);\n } else {\n this.groupedFormatter.logInstall(stats);\n }\n }\n\n onUninstall(): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logUninstall();\n } else {\n this.groupedFormatter.logUninstall();\n }\n\n this.instanceCountMonitor.reset();\n this.lifecycleMonitor.reset();\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = Date.now();\n this.stateChangeLoggingDisabled = false;\n this.context = undefined;\n }\n\n onInstanceCreated(\n instance: StateContainer<any>,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.instanceCountMonitor.onInstanceCreated(metadata.className);\n this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceCreated(metadata);\n } else {\n this.groupedFormatter.logInstanceCreated(\n metadata,\n context.getState(instance),\n );\n }\n }\n\n onStateChanged<S extends object>(\n instance: StateContainer<S>,\n previousState: S,\n currentState: S,\n callstack: string | undefined,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.lifecycleMonitor.onStateChanged(metadata.id);\n\n if (!this.shouldLogStateChanges()) return;\n\n // Check rate limit\n if (this.stateChangeLoggingDisabled) return;\n\n const now = Date.now();\n if (now - this.stateChangeWindowStart >= 1000) {\n // Reset window\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = now;\n }\n\n this.stateChangeCount++;\n\n if (this.stateChangeCount > STATE_CHANGE_RATE_LIMIT) {\n this.stateChangeLoggingDisabled = true;\n this.logWarning(\n `State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`,\n );\n return;\n }\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n );\n } else {\n this.groupedFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n );\n }\n }\n\n onInstanceDisposed(\n instance: StateContainer<any>,\n context: PluginContext,\n ): void {\n const metadata = context.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);\n const lifespanMs = info ? Date.now() - info.createdAt : 0;\n const stateChangeCount = info?.stateChangeCount ?? 0;\n\n this.instanceCountMonitor.onInstanceDisposed(metadata.className);\n this.lifecycleMonitor.onInstanceDisposed(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceDisposed(metadata, lifespanMs);\n } else {\n this.groupedFormatter.logInstanceDisposed(\n metadata,\n lifespanMs,\n stateChangeCount,\n );\n }\n }\n\n logStats(): void {\n if (!this.context) return;\n const stats = this.context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStats(stats);\n } else {\n this.groupedFormatter.logStats(stats);\n }\n }\n\n private shouldLog(\n instance: StateContainer<any>,\n className: string,\n instanceId: string,\n ): boolean {\n if (this.config.include && !this.config.include.includes(className)) {\n return false;\n }\n\n if (this.config.exclude?.includes(className)) {\n return false;\n }\n\n if (this.config.filter) {\n const ctx: FilterContext = {\n instance,\n className,\n instanceId,\n };\n return this.config.filter(ctx);\n }\n\n return true;\n }\n\n private shouldLogLifecycle(): boolean {\n if (!this.config.logLifecycle) return false;\n return this.config.level !== 'minimal';\n }\n\n private shouldLogStateChanges(): boolean {\n if (!this.config.logStateChanges) return false;\n return (\n this.config.level === 'info' ||\n this.config.level === 'debug' ||\n this.config.level === 'verbose'\n );\n }\n\n private logWarning(message: string, details?: Record<string, unknown>): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logWarning(message);\n } else {\n this.groupedFormatter.logWarning(message, details);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/formatters/SimpleFormatter.ts","../src/formatters/GroupedFormatter.ts","../src/monitors/InstanceCountMonitor.ts","../src/monitors/LifecycleMonitor.ts","../src/types.ts","../src/LoggingPlugin.ts"],"sourcesContent":["import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class SimpleFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.logger.log(\n `${this.prefix} Plugin installed (${stats.registeredTypes} types, ${stats.totalInstances} instances)`,\n );\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.logger.log(`${this.prefix} Created ${instanceId}`);\n }\n\n logInstanceDisposed(metadata: InstanceMetadata, lifespanMs: number): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const lifespan = this.formatDuration(lifespanMs);\n this.logger.log(\n `${this.prefix} Disposed ${instanceId} (lived ${lifespan})`,\n );\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n _callstack: string | undefined,\n includeCallstack: boolean,\n paths?: string[],\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n const prev = this.formatState(previousState);\n const curr = this.formatState(currentState);\n this.logger.log(`${this.prefix} ${instanceId} state: ${prev} → ${curr}`);\n\n if (paths !== undefined) {\n this.logger.log(`${this.prefix} Paths: ${paths.join(', ')}`);\n }\n\n if (includeCallstack && _callstack) {\n this.logger.log(`${this.prefix} Callstack: ${_callstack}`);\n }\n }\n\n logWarning(message: string): void {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.logger.log(\n `${this.prefix} Stats: ${stats.totalInstances} instances across ${stats.registeredTypes} types`,\n );\n }\n\n private formatState(state: unknown): string {\n if (state === null) return 'null';\n if (state === undefined) return 'undefined';\n if (typeof state === 'object') {\n try {\n const str = JSON.stringify(state);\n return str.length > 50 ? str.slice(0, 50) + '...' : str;\n } catch {\n return '[Object]';\n }\n }\n return JSON.stringify(state);\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { InstanceMetadata } from '@blac/core';\nimport type { Logger, ResolvedConfig } from '../types';\n\nexport class GroupedFormatter {\n private logger: Logger;\n private prefix: string;\n\n constructor(config: ResolvedConfig) {\n this.logger = config.logger;\n this.prefix = config.prefix;\n }\n\n private formatInstanceId(className: string, id: string): string {\n const shortId = id.length > 8 ? id.slice(0, 8) : id;\n return `${className}#${shortId}`;\n }\n\n private group(label: string, collapsed = true): void {\n if (collapsed && this.logger.groupCollapsed) {\n this.logger.groupCollapsed(label);\n } else if (this.logger.group) {\n this.logger.group(label);\n } else {\n this.logger.log(label);\n }\n }\n\n private groupEnd(): void {\n if (this.logger.groupEnd) {\n this.logger.groupEnd();\n }\n }\n\n logInstall(stats: { registeredTypes: number; totalInstances: number }): void {\n this.group(`${this.prefix} Plugin installed`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.groupEnd();\n }\n\n logUninstall(): void {\n this.logger.log(`${this.prefix} Plugin uninstalled`);\n }\n\n logInstanceCreated(metadata: InstanceMetadata, initialState: unknown): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Created ${instanceId}`);\n this.logger.log('Class:', metadata.className);\n this.logger.log('Instance ID:', metadata.id);\n this.logger.log('Initial state:', initialState);\n this.groupEnd();\n }\n\n logInstanceDisposed(\n metadata: InstanceMetadata,\n lifespanMs: number,\n stateChangeCount: number,\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} Disposed ${instanceId}`);\n this.logger.log('Lifespan:', this.formatDuration(lifespanMs));\n this.logger.log('State changes:', stateChangeCount);\n this.logger.log('Final state:', metadata.state);\n this.groupEnd();\n }\n\n logStateChanged(\n metadata: InstanceMetadata,\n previousState: unknown,\n currentState: unknown,\n callstack: string | undefined,\n includeCallstack: boolean,\n paths?: string[],\n ): void {\n const instanceId = this.formatInstanceId(metadata.className, metadata.id);\n this.group(`${this.prefix} ${instanceId} state changed`);\n this.logger.log('Previous:', previousState);\n this.logger.log('Current:', currentState);\n if (paths !== undefined) {\n this.logger.log('Paths:', paths);\n }\n if (includeCallstack && callstack) {\n this.logger.log('Callstack:', callstack);\n }\n this.groupEnd();\n }\n\n logWarning(message: string, details?: Record<string, unknown>): void {\n if (details) {\n this.group(`${this.prefix} ⚠️ ${message}`, false);\n for (const [key, value] of Object.entries(details)) {\n this.logger.log(`${key}:`, value);\n }\n this.groupEnd();\n } else {\n this.logger.warn(`${this.prefix} ⚠️ ${message}`);\n }\n }\n\n logStats(stats: {\n registeredTypes: number;\n totalInstances: number;\n typeBreakdown: Record<string, number>;\n }): void {\n this.group(`${this.prefix} Stats`);\n this.logger.log('Registered types:', stats.registeredTypes);\n this.logger.log('Total instances:', stats.totalInstances);\n this.logger.log('Breakdown:', stats.typeBreakdown);\n this.groupEnd();\n }\n\n private formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n }\n}\n","import type { ResolvedConfig } from '../types';\n\nexport class InstanceCountMonitor {\n private instanceCounts = new Map<string, number>();\n private warnedClasses = new Set<string>();\n private threshold: number;\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.threshold = config.instanceCountWarningThreshold;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string): void {\n const count = (this.instanceCounts.get(className) ?? 0) + 1;\n this.instanceCounts.set(className, count);\n\n if (count >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `High instance count: ${className} has ${count} instances`,\n {\n className,\n count,\n threshold: this.threshold,\n },\n );\n }\n }\n\n onInstanceDisposed(className: string): void {\n const count = this.instanceCounts.get(className) ?? 0;\n if (count > 0) {\n this.instanceCounts.set(className, count - 1);\n }\n\n if (count - 1 < this.threshold) {\n this.warnedClasses.delete(className);\n }\n }\n\n getStats(): Map<string, number> {\n return new Map(this.instanceCounts);\n }\n\n reset(): void {\n this.instanceCounts.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { ResolvedConfig } from '../types';\n\ninterface LifecycleEvent {\n timestamp: number;\n type: 'created' | 'disposed';\n}\n\ninterface InstanceInfo {\n createdAt: number;\n stateChangeCount: number;\n}\n\nexport class LifecycleMonitor {\n private lifecycleHistory = new Map<string, LifecycleEvent[]>();\n private instanceInfo = new Map<string, InstanceInfo>();\n private windowMs: number;\n private threshold: number;\n private enabled: boolean;\n private warnedClasses = new Set<string>();\n private onWarning: (\n message: string,\n details?: Record<string, unknown>,\n ) => void;\n\n constructor(\n config: ResolvedConfig,\n onWarning: (message: string, details?: Record<string, unknown>) => void,\n ) {\n this.windowMs = config.rapidLifecycleWindowMs;\n this.threshold = config.rapidLifecycleThreshold;\n this.enabled = config.detectRapidLifecycles;\n this.onWarning = onWarning;\n }\n\n onInstanceCreated(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.set(instanceId, {\n createdAt: Date.now(),\n stateChangeCount: 0,\n });\n\n this.recordEvent(className, 'created');\n this.checkRapidLifecycle(className);\n }\n\n onInstanceDisposed(className: string, instanceId: string): void {\n if (!this.enabled) return;\n\n this.instanceInfo.delete(instanceId);\n this.recordEvent(className, 'disposed');\n this.checkRapidLifecycle(className);\n }\n\n onStateChanged(instanceId: string): void {\n const info = this.instanceInfo.get(instanceId);\n if (info) {\n info.stateChangeCount++;\n }\n }\n\n getInstanceInfo(instanceId: string): InstanceInfo | undefined {\n return this.instanceInfo.get(instanceId);\n }\n\n private recordEvent(className: string, type: 'created' | 'disposed'): void {\n const now = Date.now();\n const events = this.lifecycleHistory.get(className) ?? [];\n\n events.push({ timestamp: now, type });\n\n const cutoff = now - this.windowMs;\n const filtered = events.filter((e) => e.timestamp > cutoff);\n this.lifecycleHistory.set(className, filtered);\n }\n\n private checkRapidLifecycle(className: string): void {\n const events = this.lifecycleHistory.get(className) ?? [];\n const cycleCount = Math.min(\n events.filter((e) => e.type === 'created').length,\n events.filter((e) => e.type === 'disposed').length,\n );\n\n if (cycleCount >= this.threshold && !this.warnedClasses.has(className)) {\n this.warnedClasses.add(className);\n this.onWarning(\n `Rapid lifecycle: ${className} created/disposed ${cycleCount} times in ${this.windowMs}ms`,\n {\n className,\n cycleCount,\n windowMs: this.windowMs,\n threshold: this.threshold,\n },\n );\n\n setTimeout(() => {\n this.warnedClasses.delete(className);\n }, this.windowMs);\n }\n }\n\n reset(): void {\n this.lifecycleHistory.clear();\n this.instanceInfo.clear();\n this.warnedClasses.clear();\n }\n}\n","import type { StateContainer } from '@blac/core';\n\nexport type LogLevel = 'minimal' | 'info' | 'debug' | 'verbose';\n\nexport type LogFormat = 'simple' | 'grouped';\n\nexport interface Logger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n group?(label: string): void;\n groupEnd?(): void;\n groupCollapsed?(label: string): void;\n}\n\nexport interface FilterContext {\n instance: StateContainer<any>;\n className: string;\n instanceId: string;\n}\n\nexport type FilterFn = (ctx: FilterContext) => boolean;\n\nexport interface LoggingPluginConfig {\n /** Log verbosity level (default: 'info') */\n level?: LogLevel;\n\n /** Output format (default: 'grouped') */\n format?: LogFormat;\n\n /** Custom logger implementation (default: console) */\n logger?: Logger;\n\n /** Filter which instances to log */\n filter?: FilterFn;\n\n /** Include class names to log (whitelist) */\n include?: string[];\n\n /** Exclude class names from logging (blacklist) */\n exclude?: string[];\n\n /** Log instance creation/disposal (default: true) */\n logLifecycle?: boolean;\n\n /** Log state changes (default: true) */\n logStateChanges?: boolean;\n\n /** Include callstack in state change logs (default: false) */\n includeCallstack?: boolean;\n\n /** Log changed path names in state change output (default: false) */\n logPaths?: boolean;\n\n /** Warn when instance count exceeds threshold (default: 50) */\n instanceCountWarningThreshold?: number;\n\n /** Warn on rapid init/dispose cycles (default: true) */\n detectRapidLifecycles?: boolean;\n\n /** Time window for rapid lifecycle detection in ms (default: 1000) */\n rapidLifecycleWindowMs?: number;\n\n /** Number of cycles in window to trigger warning (default: 5) */\n rapidLifecycleThreshold?: number;\n\n /** Log prefix (default: '[BlaC]') */\n prefix?: string;\n}\n\nexport interface ResolvedConfig {\n level: LogLevel;\n format: LogFormat;\n logger: Logger;\n filter: FilterFn | undefined;\n include: string[] | undefined;\n exclude: string[] | undefined;\n logLifecycle: boolean;\n logStateChanges: boolean;\n includeCallstack: boolean;\n logPaths: boolean;\n instanceCountWarningThreshold: number;\n detectRapidLifecycles: boolean;\n rapidLifecycleWindowMs: number;\n rapidLifecycleThreshold: number;\n prefix: string;\n}\n\nexport function resolveConfig(\n config: LoggingPluginConfig = {},\n): ResolvedConfig {\n return {\n level: config.level ?? 'info',\n format: config.format ?? 'grouped',\n logger: config.logger ?? console,\n filter: config.filter,\n include: config.include,\n exclude: config.exclude,\n logLifecycle: config.logLifecycle ?? true,\n logStateChanges: config.logStateChanges ?? true,\n includeCallstack: config.includeCallstack ?? false,\n logPaths: config.logPaths ?? false,\n instanceCountWarningThreshold: config.instanceCountWarningThreshold ?? 50,\n detectRapidLifecycles: config.detectRapidLifecycles ?? true,\n rapidLifecycleWindowMs: config.rapidLifecycleWindowMs ?? 1000,\n rapidLifecycleThreshold: config.rapidLifecycleThreshold ?? 5,\n prefix: config.prefix ?? '[BlaC]',\n };\n}\n","import type {\n BlacPlugin,\n PathSet,\n PluginContext,\n StateContainer,\n} from '@blac/core';\nimport { ALL_PATHS } from '@blac/core';\nimport { SimpleFormatter } from './formatters/SimpleFormatter';\nimport { GroupedFormatter } from './formatters/GroupedFormatter';\nimport { InstanceCountMonitor } from './monitors/InstanceCountMonitor';\nimport { LifecycleMonitor } from './monitors/LifecycleMonitor';\nimport type {\n LoggingPluginConfig,\n ResolvedConfig,\n FilterContext,\n} from './types';\nimport { resolveConfig } from './types';\n\nconst STATE_CHANGE_RATE_LIMIT = 1000; // max state changes per second\n\n/**\n * Decode a `PathSet` to an array of path name strings.\n *\n * Returns `['<all>']` when `paths === ALL_PATHS`.\n * Uses `interner.lookup(id)` for all other IDs.\n *\n * The `interner` is typed structurally to avoid a direct compile-time\n * dependency on `@dirtytalk/structural` from this package.\n */\nfunction decodePaths(\n paths: PathSet,\n interner: { lookup(id: number): string },\n): string[] {\n if (paths === ALL_PATHS) return ['<all>'];\n return Array.from(paths as Set<number>).map((id) => interner.lookup(id));\n}\n\nexport class LoggingPlugin implements BlacPlugin {\n readonly name = 'LoggingPlugin';\n readonly version = '1.0.0';\n\n private config: ResolvedConfig;\n private context?: PluginContext;\n private simpleFormatter: SimpleFormatter;\n private groupedFormatter: GroupedFormatter;\n private instanceCountMonitor: InstanceCountMonitor;\n private lifecycleMonitor: LifecycleMonitor;\n\n // Rate limiting for state changes\n private stateChangeCount = 0;\n private stateChangeWindowStart = Date.now();\n private stateChangeLoggingDisabled = false;\n\n constructor(config: LoggingPluginConfig = {}) {\n this.config = resolveConfig(config);\n\n const warningHandler = (\n message: string,\n details?: Record<string, unknown>,\n ) => {\n this.logWarning(message, details);\n };\n\n this.simpleFormatter = new SimpleFormatter(this.config);\n this.groupedFormatter = new GroupedFormatter(this.config);\n this.instanceCountMonitor = new InstanceCountMonitor(\n this.config,\n warningHandler,\n );\n this.lifecycleMonitor = new LifecycleMonitor(this.config, warningHandler);\n }\n\n onInstall(ctx: PluginContext): void {\n this.context = ctx;\n const stats = ctx.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstall(stats);\n } else {\n this.groupedFormatter.logInstall(stats);\n }\n }\n\n onUninstall(): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logUninstall();\n } else {\n this.groupedFormatter.logUninstall();\n }\n\n this.instanceCountMonitor.reset();\n this.lifecycleMonitor.reset();\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = Date.now();\n this.stateChangeLoggingDisabled = false;\n this.context = undefined;\n }\n\n onCreated(ctx: PluginContext): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.instanceCountMonitor.onInstanceCreated(metadata.className);\n this.lifecycleMonitor.onInstanceCreated(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceCreated(metadata);\n } else {\n this.groupedFormatter.logInstanceCreated(\n metadata,\n ctx.getState(instance),\n );\n }\n }\n\n onStateChange<S extends object>(\n ctx: PluginContext,\n previousState: S,\n currentState: S,\n paths: PathSet,\n ): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n this.lifecycleMonitor.onStateChanged(metadata.id);\n\n if (!this.shouldLogStateChanges()) return;\n\n // Check rate limit\n if (this.stateChangeLoggingDisabled) return;\n\n const now = Date.now();\n if (now - this.stateChangeWindowStart >= 1000) {\n // Reset window\n this.stateChangeCount = 0;\n this.stateChangeWindowStart = now;\n }\n\n this.stateChangeCount++;\n\n if (this.stateChangeCount > STATE_CHANGE_RATE_LIMIT) {\n this.stateChangeLoggingDisabled = true;\n this.logWarning(\n `State change logging disabled: exceeded ${STATE_CHANGE_RATE_LIMIT} changes/second`,\n );\n return;\n }\n\n const callstack = this.config.includeCallstack\n ? new Error().stack\n : undefined;\n\n const decodedPaths = this.config.logPaths\n ? decodePaths(paths, instance.interner)\n : undefined;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n decodedPaths,\n );\n } else {\n this.groupedFormatter.logStateChanged(\n metadata,\n previousState,\n currentState,\n callstack,\n this.config.includeCallstack,\n decodedPaths,\n );\n }\n }\n\n onDestroyed(ctx: PluginContext): void {\n const instance = ctx.container;\n if (!instance) return;\n const metadata = ctx.getInstanceMetadata(instance);\n\n if (!this.shouldLog(instance, metadata.className, metadata.id)) {\n return;\n }\n\n const info = this.lifecycleMonitor.getInstanceInfo(metadata.id);\n const lifespanMs = info ? Date.now() - info.createdAt : 0;\n const stateChangeCount = info?.stateChangeCount ?? 0;\n\n this.instanceCountMonitor.onInstanceDisposed(metadata.className);\n this.lifecycleMonitor.onInstanceDisposed(metadata.className, metadata.id);\n\n if (!this.shouldLogLifecycle()) return;\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logInstanceDisposed(metadata, lifespanMs);\n } else {\n this.groupedFormatter.logInstanceDisposed(\n metadata,\n lifespanMs,\n stateChangeCount,\n );\n }\n }\n\n logStats(): void {\n if (!this.context) return;\n const stats = this.context.getStats();\n\n if (this.config.format === 'simple') {\n this.simpleFormatter.logStats(stats);\n } else {\n this.groupedFormatter.logStats(stats);\n }\n }\n\n private shouldLog(\n instance: StateContainer<any>,\n className: string,\n instanceId: string,\n ): boolean {\n if (this.config.include && !this.config.include.includes(className)) {\n return false;\n }\n\n if (this.config.exclude?.includes(className)) {\n return false;\n }\n\n if (this.config.filter) {\n const filterCtx: FilterContext = {\n instance,\n className,\n instanceId,\n };\n return this.config.filter(filterCtx);\n }\n\n return true;\n }\n\n private shouldLogLifecycle(): boolean {\n if (!this.config.logLifecycle) return false;\n return this.config.level !== 'minimal';\n }\n\n private shouldLogStateChanges(): boolean {\n if (!this.config.logStateChanges) return false;\n return (\n this.config.level === 'info' ||\n this.config.level === 'debug' ||\n this.config.level === 'verbose'\n );\n }\n\n private logWarning(message: string, details?: Record<string, unknown>): void {\n if (this.config.format === 'simple') {\n this.simpleFormatter.logWarning(message);\n } else {\n this.groupedFormatter.logWarning(message, details);\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export interface LoggingPluginConfig {
|
|
|
34
34
|
logStateChanges?: boolean;
|
|
35
35
|
/** Include callstack in state change logs (default: false) */
|
|
36
36
|
includeCallstack?: boolean;
|
|
37
|
+
/** Log changed path names in state change output (default: false) */
|
|
38
|
+
logPaths?: boolean;
|
|
37
39
|
/** Warn when instance count exceeds threshold (default: 50) */
|
|
38
40
|
instanceCountWarningThreshold?: number;
|
|
39
41
|
/** Warn on rapid init/dispose cycles (default: true) */
|
|
@@ -55,6 +57,7 @@ export interface ResolvedConfig {
|
|
|
55
57
|
logLifecycle: boolean;
|
|
56
58
|
logStateChanges: boolean;
|
|
57
59
|
includeCallstack: boolean;
|
|
60
|
+
logPaths: boolean;
|
|
58
61
|
instanceCountWarningThreshold: number;
|
|
59
62
|
detectRapidLifecycles: boolean;
|
|
60
63
|
rapidLifecycleWindowMs: number;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7C,MAAM,WAAW,MAAM;IACrB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB,cAAc,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,QAAQ,CAAC;IAEjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oCAAoC;IACpC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAElB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,wCAAwC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,+DAA+D;IAC/D,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC,wDAAwD;IACxD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC,sEAAsE;IACtE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC,iEAAiE;IACjE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6BAA6B,EAAE,MAAM,CAAC;IACtC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAC3B,MAAM,GAAE,mBAAwB,GAC/B,cAAc,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7C,MAAM,WAAW,MAAM;IACrB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,KAAK,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB,cAAc,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,KAAK,CAAC,EAAE,QAAQ,CAAC;IAEjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oCAAoC;IACpC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAElB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,wCAAwC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,+DAA+D;IAC/D,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC,wDAAwD;IACxD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC,sEAAsE;IACtE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC,iEAAiE;IACjE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,6BAA6B,EAAE,MAAM,CAAC;IACtC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAC3B,MAAM,GAAE,mBAAwB,GAC/B,cAAc,CAkBhB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blac/logging-plugin",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Brendan Mullins <jsnanigans@gmail.com>",
|
|
6
6
|
"description": "Logging and debugging plugin for BlaC state management",
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
"devtools"
|
|
47
47
|
],
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@blac/core": "^2.0.
|
|
49
|
+
"@blac/core": "^2.0.14"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"typescript": "^5.9.2",
|
|
53
53
|
"vitest": "npm:@voidzero-dev/vite-plus-test@latest",
|
|
54
54
|
"publint": "^0.3.12",
|
|
55
55
|
"vite-plus": "latest",
|
|
56
|
-
"@blac/core": "2.0.
|
|
56
|
+
"@blac/core": "2.0.14"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"dev": "vp pack --watch",
|