@lensmcp/memory-tracker 1.18.3 → 1.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +0 -1
- package/index.js +1 -5
- package/lib/context.d.ts +0 -1
- package/lib/context.js +1 -30
- package/lib/detectors.d.ts +0 -1
- package/lib/detectors.js +1 -62
- package/lib/emit.d.ts +0 -1
- package/lib/emit.js +1 -93
- package/lib/owners.d.ts +0 -1
- package/lib/owners.js +1 -78
- package/lib/track-container.d.ts +0 -1
- package/lib/track-container.js +1 -155
- package/lib/types.d.ts +0 -1
- package/lib/types.js +1 -1
- package/package.json +2 -2
- package/index.d.ts.map +0 -1
- package/lib/context.d.ts.map +0 -1
- package/lib/detectors.d.ts.map +0 -1
- package/lib/emit.d.ts.map +0 -1
- package/lib/owners.d.ts.map +0 -1
- package/lib/track-container.d.ts.map +0 -1
- package/lib/types.d.ts.map +0 -1
package/index.d.ts
CHANGED
|
@@ -4,4 +4,3 @@ export { ensureOwner, allOwners, getOwner, ownerKey, resetOwners, markFlowStart,
|
|
|
4
4
|
export { emitMutation, emitRetention, emitStaleGeneration } from './lib/emit.js';
|
|
5
5
|
export { onFlowStart, onFlowSettled, checkStaleGeneration, } from './lib/detectors.js';
|
|
6
6
|
export type { MemoryEventSink, MemoryContext, ResolvedMemoryOptions, MemoryOwnerSnapshot, MemoryContainerKind, MemoryMutationOperation, } from './lib/types.js';
|
|
7
|
-
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { trackContainer } from './lib/track-container.js';
|
|
3
|
-
export { ensureOwner, allOwners, getOwner, ownerKey, resetOwners, markFlowStart, recordFlowDelta, flowGrowth, } from './lib/owners.js';
|
|
4
|
-
export { emitMutation, emitRetention, emitStaleGeneration } from './lib/emit.js';
|
|
5
|
-
export { onFlowStart, onFlowSettled, checkStaleGeneration, } from './lib/detectors.js';
|
|
1
|
+
"use strict";export{configureMemoryTracker,activeMemoryOptions,currentMemoryContext,resetMemoryTracker}from"./lib/context.js";export{trackContainer}from"./lib/track-container.js";export{ensureOwner,allOwners,getOwner,ownerKey,resetOwners,markFlowStart,recordFlowDelta,flowGrowth}from"./lib/owners.js";export{emitMutation,emitRetention,emitStaleGeneration}from"./lib/emit.js";export{onFlowStart,onFlowSettled,checkStaleGeneration}from"./lib/detectors.js";
|
package/lib/context.d.ts
CHANGED
package/lib/context.js
CHANGED
|
@@ -1,30 +1 @@
|
|
|
1
|
-
let contextGetter = ()
|
|
2
|
-
let options;
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
leakItemThreshold: 50,
|
|
5
|
-
staleGenerationBytesThreshold: 1024 * 1024,
|
|
6
|
-
settleMs: 1000,
|
|
7
|
-
};
|
|
8
|
-
export function configureMemoryTracker(opts) {
|
|
9
|
-
options = {
|
|
10
|
-
sessionId: opts.sessionId,
|
|
11
|
-
sink: opts.sink,
|
|
12
|
-
leakItemThreshold: opts.leakItemThreshold ?? DEFAULTS.leakItemThreshold,
|
|
13
|
-
staleGenerationBytesThreshold: opts.staleGenerationBytesThreshold ?? DEFAULTS.staleGenerationBytesThreshold,
|
|
14
|
-
settleMs: opts.settleMs ?? DEFAULTS.settleMs,
|
|
15
|
-
};
|
|
16
|
-
if (opts.contextGetter)
|
|
17
|
-
contextGetter = opts.contextGetter;
|
|
18
|
-
return options;
|
|
19
|
-
}
|
|
20
|
-
export function activeMemoryOptions() {
|
|
21
|
-
return options;
|
|
22
|
-
}
|
|
23
|
-
export function currentMemoryContext() {
|
|
24
|
-
return contextGetter();
|
|
25
|
-
}
|
|
26
|
-
/** Test hook. */
|
|
27
|
-
export function resetMemoryTracker() {
|
|
28
|
-
options = undefined;
|
|
29
|
-
contextGetter = () => undefined;
|
|
30
|
-
}
|
|
1
|
+
"use strict";var a=Object.defineProperty;var t=(e,n)=>a(e,"name",{value:n,configurable:!0});var c=Object.defineProperty,r=t((e,n)=>c(e,"name",{value:n,configurable:!0}),"t");let s=r(()=>{},"contextGetter"),o;const l={leakItemThreshold:50,staleGenerationBytesThreshold:1024*1024,settleMs:1e3};export function configureMemoryTracker(e){return o={sessionId:e.sessionId,sink:e.sink,leakItemThreshold:e.leakItemThreshold??l.leakItemThreshold,staleGenerationBytesThreshold:e.staleGenerationBytesThreshold??l.staleGenerationBytesThreshold,settleMs:e.settleMs??l.settleMs},e.contextGetter&&(s=e.contextGetter),o}t(configureMemoryTracker,"configureMemoryTracker"),r(configureMemoryTracker,"configureMemoryTracker");export function activeMemoryOptions(){return o}t(activeMemoryOptions,"activeMemoryOptions"),r(activeMemoryOptions,"activeMemoryOptions");export function currentMemoryContext(){return s()}t(currentMemoryContext,"currentMemoryContext"),r(currentMemoryContext,"currentMemoryContext");export function resetMemoryTracker(){o=void 0,s=r(()=>{},"contextGetter")}t(resetMemoryTracker,"resetMemoryTracker"),r(resetMemoryTracker,"resetMemoryTracker");
|
package/lib/detectors.d.ts
CHANGED
package/lib/detectors.js
CHANGED
|
@@ -1,62 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Suspect-leak + stale-generation detectors.
|
|
3
|
-
*
|
|
4
|
-
* `onFlowStart` / `onFlowSettled` bracket a flow: at start we snapshot
|
|
5
|
-
* every owner's count; after the flow settles we compare. If an owner
|
|
6
|
-
* grew past the threshold and didn't shrink back, we emit a
|
|
7
|
-
* `memory-retention` event.
|
|
8
|
-
*
|
|
9
|
-
* `checkStaleGeneration` is called when a singleton instance is
|
|
10
|
-
* disposed; if its sampled retained bytes exceed the threshold we emit
|
|
11
|
-
* a `singleton-stale-generation` event.
|
|
12
|
-
*/
|
|
13
|
-
import { activeMemoryOptions } from './context.js';
|
|
14
|
-
import { clearFlowStart, flowGrowth, markFlowStart, } from './owners.js';
|
|
15
|
-
import { emitRetention, emitStaleGeneration } from './emit.js';
|
|
16
|
-
export function onFlowStart(flowId) {
|
|
17
|
-
markFlowStart(flowId);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Compare each owner's count at flow-start vs now. Owners that grew by
|
|
21
|
-
* more than `leakItemThreshold` and didn't shrink are flagged. Returns
|
|
22
|
-
* the list of flagged owner ids (also useful for tests).
|
|
23
|
-
*/
|
|
24
|
-
export function onFlowSettled(flowId) {
|
|
25
|
-
const opts = activeMemoryOptions();
|
|
26
|
-
if (!opts)
|
|
27
|
-
return [];
|
|
28
|
-
const flagged = [];
|
|
29
|
-
for (const g of flowGrowth(flowId)) {
|
|
30
|
-
// Flag when THIS flow's attributed growth crosses the threshold AND
|
|
31
|
-
// the items are still resident (the container didn't shrink back).
|
|
32
|
-
if (g.growth >= opts.leakItemThreshold && g.endCount >= g.growth) {
|
|
33
|
-
emitRetention({
|
|
34
|
-
options: opts,
|
|
35
|
-
ownerId: g.owner.ownerId,
|
|
36
|
-
flowId,
|
|
37
|
-
startCount: g.startCount,
|
|
38
|
-
endCount: g.endCount,
|
|
39
|
-
growth: g.growth,
|
|
40
|
-
});
|
|
41
|
-
flagged.push(g.owner.ownerId);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
clearFlowStart(flowId);
|
|
45
|
-
return flagged;
|
|
46
|
-
}
|
|
47
|
-
export function checkStaleGeneration(args) {
|
|
48
|
-
const opts = activeMemoryOptions();
|
|
49
|
-
if (!opts)
|
|
50
|
-
return false;
|
|
51
|
-
if (args.retainedBytes > opts.staleGenerationBytesThreshold) {
|
|
52
|
-
emitStaleGeneration({
|
|
53
|
-
options: opts,
|
|
54
|
-
logicalId: args.logicalId,
|
|
55
|
-
instanceId: args.instanceId,
|
|
56
|
-
generation: args.generation,
|
|
57
|
-
retainedBytes: args.retainedBytes,
|
|
58
|
-
});
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
1
|
+
"use strict";var s=Object.defineProperty;var n=(e,t)=>s(e,"name",{value:t,configurable:!0});var l=Object.defineProperty,r=n((e,t)=>l(e,"name",{value:t,configurable:!0}),"n");import{activeMemoryOptions as i}from"./context.js";import{clearFlowStart as c,flowGrowth as d,markFlowStart as w}from"./owners.js";import{emitRetention as u,emitStaleGeneration as f}from"./emit.js";export function onFlowStart(e){w(e)}n(onFlowStart,"onFlowStart"),r(onFlowStart,"onFlowStart");export function onFlowSettled(e){const t=i();if(!t)return[];const a=[];for(const o of d(e))o.growth>=t.leakItemThreshold&&o.endCount>=o.growth&&(u({options:t,ownerId:o.owner.ownerId,flowId:e,startCount:o.startCount,endCount:o.endCount,growth:o.growth}),a.push(o.owner.ownerId));return c(e),a}n(onFlowSettled,"onFlowSettled"),r(onFlowSettled,"onFlowSettled");export function checkStaleGeneration(e){const t=i();return t&&e.retainedBytes>t.staleGenerationBytesThreshold?(f({options:t,logicalId:e.logicalId,instanceId:e.instanceId,generation:e.generation,retainedBytes:e.retainedBytes}),!0):!1}n(checkStaleGeneration,"checkStaleGeneration"),r(checkStaleGeneration,"checkStaleGeneration");
|
package/lib/emit.d.ts
CHANGED
package/lib/emit.js
CHANGED
|
@@ -1,93 +1 @@
|
|
|
1
|
-
|
|
2
|
-
function memId(prefix) {
|
|
3
|
-
seq = (seq + 1) % 0xffffff;
|
|
4
|
-
return `${prefix}-${seq.toString(36)}`;
|
|
5
|
-
}
|
|
6
|
-
function baseContext(options, ctx) {
|
|
7
|
-
return {
|
|
8
|
-
sessionId: ctx?.sessionId ?? options.sessionId,
|
|
9
|
-
...(ctx?.flowId ? { flowId: ctx.flowId } : {}),
|
|
10
|
-
...(ctx?.requestId ? { requestId: ctx.requestId } : {}),
|
|
11
|
-
...(ctx?.originNodeId ? { originNodeId: ctx.originNodeId } : {}),
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
export function emitMutation(args) {
|
|
15
|
-
const { options } = args;
|
|
16
|
-
const event = {
|
|
17
|
-
id: memId('memmut'),
|
|
18
|
-
sessionId: args.context?.sessionId ?? options.sessionId,
|
|
19
|
-
timestamp: args.timestamp ?? nowMs(),
|
|
20
|
-
source: 'memory',
|
|
21
|
-
category: 'memory',
|
|
22
|
-
severity: 'debug',
|
|
23
|
-
context: baseContext(options, args.context),
|
|
24
|
-
fingerprint: `memory-mutation:${args.ownerId}:${args.operation}`,
|
|
25
|
-
title: `${args.operation} ${args.ownerId}`,
|
|
26
|
-
raw: {
|
|
27
|
-
kind: 'memory-mutation',
|
|
28
|
-
mutation: {
|
|
29
|
-
ownerNodeId: args.ownerId,
|
|
30
|
-
operation: args.operation,
|
|
31
|
-
beforeCount: args.beforeCount,
|
|
32
|
-
afterCount: args.afterCount,
|
|
33
|
-
estimatedDeltaBytes: args.estimatedDeltaBytes,
|
|
34
|
-
keyPreview: args.keyPreview,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
options.sink(event);
|
|
39
|
-
}
|
|
40
|
-
export function emitRetention(args) {
|
|
41
|
-
const { options } = args;
|
|
42
|
-
const event = {
|
|
43
|
-
id: memId('memret'),
|
|
44
|
-
sessionId: args.context?.sessionId ?? options.sessionId,
|
|
45
|
-
timestamp: args.timestamp ?? nowMs(),
|
|
46
|
-
source: 'memory',
|
|
47
|
-
category: 'memory',
|
|
48
|
-
severity: 'warning',
|
|
49
|
-
context: { ...baseContext(options, args.context), flowId: args.flowId },
|
|
50
|
-
fingerprint: `memory-retention:${args.ownerId}`,
|
|
51
|
-
title: `Suspected leak: ${args.ownerId} grew by ${args.growth} and did not shrink`,
|
|
52
|
-
raw: {
|
|
53
|
-
kind: 'memory-retention',
|
|
54
|
-
retention: {
|
|
55
|
-
ownerId: args.ownerId,
|
|
56
|
-
flowId: args.flowId,
|
|
57
|
-
startCount: args.startCount,
|
|
58
|
-
endCount: args.endCount,
|
|
59
|
-
growth: args.growth,
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
options.sink(event);
|
|
64
|
-
}
|
|
65
|
-
export function emitStaleGeneration(args) {
|
|
66
|
-
const { options } = args;
|
|
67
|
-
const event = {
|
|
68
|
-
id: memId('memstale'),
|
|
69
|
-
sessionId: options.sessionId,
|
|
70
|
-
timestamp: args.timestamp ?? nowMs(),
|
|
71
|
-
source: 'memory',
|
|
72
|
-
category: 'memory',
|
|
73
|
-
severity: 'warning',
|
|
74
|
-
context: { sessionId: options.sessionId },
|
|
75
|
-
fingerprint: `memory-stale-generation:${args.logicalId}`,
|
|
76
|
-
title: `Stale generation retained: ${args.logicalId} gen ${args.generation} holds ${args.retainedBytes} bytes`,
|
|
77
|
-
raw: {
|
|
78
|
-
kind: 'singleton-stale-generation',
|
|
79
|
-
staleGeneration: {
|
|
80
|
-
logicalId: args.logicalId,
|
|
81
|
-
instanceId: args.instanceId,
|
|
82
|
-
generation: args.generation,
|
|
83
|
-
retainedBytes: args.retainedBytes,
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
options.sink(event);
|
|
88
|
-
}
|
|
89
|
-
function nowMs() {
|
|
90
|
-
// `Date.now` is fine in library runtime code; the workflow-script ban
|
|
91
|
-
// doesn't apply here.
|
|
92
|
-
return Date.now();
|
|
93
|
-
}
|
|
1
|
+
"use strict";var m=Object.defineProperty;var n=(t,e)=>m(t,"name",{value:e,configurable:!0});var I=Object.defineProperty,o=n((t,e)=>I(t,"name",{value:e,configurable:!0}),"n");let d=0;function r(t){return d=(d+1)%16777215,`${t}-${d.toString(36)}`}n(r,"d"),o(r,"memId");function a(t,e){return{sessionId:e?.sessionId??t.sessionId,...e?.flowId?{flowId:e.flowId}:{},...e?.requestId?{requestId:e.requestId}:{},...e?.originNodeId?{originNodeId:e.originNodeId}:{}}}n(a,"r"),o(a,"baseContext");export function emitMutation(t){const{options:e}=t,i={id:r("memmut"),sessionId:t.context?.sessionId??e.sessionId,timestamp:t.timestamp??s(),source:"memory",category:"memory",severity:"debug",context:a(e,t.context),fingerprint:`memory-mutation:${t.ownerId}:${t.operation}`,title:`${t.operation} ${t.ownerId}`,raw:{kind:"memory-mutation",mutation:{ownerNodeId:t.ownerId,operation:t.operation,beforeCount:t.beforeCount,afterCount:t.afterCount,estimatedDeltaBytes:t.estimatedDeltaBytes,keyPreview:t.keyPreview}}};e.sink(i)}n(emitMutation,"emitMutation"),o(emitMutation,"emitMutation");export function emitRetention(t){const{options:e}=t,i={id:r("memret"),sessionId:t.context?.sessionId??e.sessionId,timestamp:t.timestamp??s(),source:"memory",category:"memory",severity:"warning",context:{...a(e,t.context),flowId:t.flowId},fingerprint:`memory-retention:${t.ownerId}`,title:`Suspected leak: ${t.ownerId} grew by ${t.growth} and did not shrink`,raw:{kind:"memory-retention",retention:{ownerId:t.ownerId,flowId:t.flowId,startCount:t.startCount,endCount:t.endCount,growth:t.growth}}};e.sink(i)}n(emitRetention,"emitRetention"),o(emitRetention,"emitRetention");export function emitStaleGeneration(t){const{options:e}=t,i={id:r("memstale"),sessionId:e.sessionId,timestamp:t.timestamp??s(),source:"memory",category:"memory",severity:"warning",context:{sessionId:e.sessionId},fingerprint:`memory-stale-generation:${t.logicalId}`,title:`Stale generation retained: ${t.logicalId} gen ${t.generation} holds ${t.retainedBytes} bytes`,raw:{kind:"singleton-stale-generation",staleGeneration:{logicalId:t.logicalId,instanceId:t.instanceId,generation:t.generation,retainedBytes:t.retainedBytes}}};e.sink(i)}n(emitStaleGeneration,"emitStaleGeneration"),o(emitStaleGeneration,"emitStaleGeneration");function s(){return Date.now()}n(s,"s"),o(s,"nowMs");
|
package/lib/owners.d.ts
CHANGED
package/lib/owners.js
CHANGED
|
@@ -1,78 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
export function ownerKey(ownerInstanceId, fieldName) {
|
|
3
|
-
return `${ownerInstanceId}::${fieldName}`;
|
|
4
|
-
}
|
|
5
|
-
export function ensureOwner(args) {
|
|
6
|
-
const id = ownerKey(args.ownerInstanceId, args.fieldName);
|
|
7
|
-
let rec = owners.get(id);
|
|
8
|
-
if (!rec) {
|
|
9
|
-
rec = {
|
|
10
|
-
ownerId: id,
|
|
11
|
-
ownerInstanceId: args.ownerInstanceId,
|
|
12
|
-
containerKind: args.containerKind,
|
|
13
|
-
fieldName: args.fieldName,
|
|
14
|
-
itemCount: 0,
|
|
15
|
-
estimatedBytes: 0,
|
|
16
|
-
startCount: 0,
|
|
17
|
-
flowStartCounts: new Map(),
|
|
18
|
-
flowDeltas: new Map(),
|
|
19
|
-
};
|
|
20
|
-
owners.set(id, rec);
|
|
21
|
-
}
|
|
22
|
-
return rec;
|
|
23
|
-
}
|
|
24
|
-
export function recordCount(rec, itemCount, estimatedBytes) {
|
|
25
|
-
rec.itemCount = itemCount;
|
|
26
|
-
rec.estimatedBytes = estimatedBytes;
|
|
27
|
-
}
|
|
28
|
-
export function markFlowStart(flowId) {
|
|
29
|
-
for (const rec of owners.values()) {
|
|
30
|
-
if (!rec.flowStartCounts.has(flowId)) {
|
|
31
|
-
rec.flowStartCounts.set(flowId, rec.itemCount);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/** Attribute a net item delta to the flow whose mutation caused it. */
|
|
36
|
-
export function recordFlowDelta(rec, flowId, delta) {
|
|
37
|
-
rec.flowDeltas.set(flowId, (rec.flowDeltas.get(flowId) ?? 0) + delta);
|
|
38
|
-
}
|
|
39
|
-
export function flowGrowth(flowId) {
|
|
40
|
-
const out = [];
|
|
41
|
-
for (const rec of owners.values()) {
|
|
42
|
-
// Only owners this flow actually mutated. `growth` is the flow's own
|
|
43
|
-
// attributed net add, not the global item-count delta.
|
|
44
|
-
const delta = rec.flowDeltas.get(flowId);
|
|
45
|
-
if (delta === undefined)
|
|
46
|
-
continue;
|
|
47
|
-
out.push({
|
|
48
|
-
owner: rec,
|
|
49
|
-
startCount: rec.flowStartCounts.get(flowId) ?? 0,
|
|
50
|
-
endCount: rec.itemCount,
|
|
51
|
-
growth: delta,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return out;
|
|
55
|
-
}
|
|
56
|
-
export function clearFlowStart(flowId) {
|
|
57
|
-
for (const rec of owners.values()) {
|
|
58
|
-
rec.flowStartCounts.delete(flowId);
|
|
59
|
-
rec.flowDeltas.delete(flowId);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
export function allOwners() {
|
|
63
|
-
return [...owners.values()].map((rec) => ({
|
|
64
|
-
ownerId: rec.ownerId,
|
|
65
|
-
ownerInstanceId: rec.ownerInstanceId,
|
|
66
|
-
containerKind: rec.containerKind,
|
|
67
|
-
fieldName: rec.fieldName,
|
|
68
|
-
itemCount: rec.itemCount,
|
|
69
|
-
estimatedBytes: rec.estimatedBytes,
|
|
70
|
-
growthSinceStart: rec.itemCount - rec.startCount,
|
|
71
|
-
}));
|
|
72
|
-
}
|
|
73
|
-
export function getOwner(ownerId) {
|
|
74
|
-
return owners.get(ownerId);
|
|
75
|
-
}
|
|
76
|
-
export function resetOwners() {
|
|
77
|
-
owners.clear();
|
|
78
|
-
}
|
|
1
|
+
"use strict";var l=Object.defineProperty;var o=(e,t)=>l(e,"name",{value:t,configurable:!0});var w=Object.defineProperty,r=o((e,t)=>w(e,"name",{value:t,configurable:!0}),"o");const a=new Map;export function ownerKey(e,t){return`${e}::${t}`}o(ownerKey,"ownerKey"),r(ownerKey,"ownerKey");export function ensureOwner(e){const t=ownerKey(e.ownerInstanceId,e.fieldName);let n=a.get(t);return n||(n={ownerId:t,ownerInstanceId:e.ownerInstanceId,containerKind:e.containerKind,fieldName:e.fieldName,itemCount:0,estimatedBytes:0,startCount:0,flowStartCounts:new Map,flowDeltas:new Map},a.set(t,n)),n}o(ensureOwner,"ensureOwner"),r(ensureOwner,"ensureOwner");export function recordCount(e,t,n){e.itemCount=t,e.estimatedBytes=n}o(recordCount,"recordCount"),r(recordCount,"recordCount");export function markFlowStart(e){for(const t of a.values())t.flowStartCounts.has(e)||t.flowStartCounts.set(e,t.itemCount)}o(markFlowStart,"markFlowStart"),r(markFlowStart,"markFlowStart");export function recordFlowDelta(e,t,n){e.flowDeltas.set(t,(e.flowDeltas.get(t)??0)+n)}o(recordFlowDelta,"recordFlowDelta"),r(recordFlowDelta,"recordFlowDelta");export function flowGrowth(e){const t=[];for(const n of a.values()){const s=n.flowDeltas.get(e);s!==void 0&&t.push({owner:n,startCount:n.flowStartCounts.get(e)??0,endCount:n.itemCount,growth:s})}return t}o(flowGrowth,"flowGrowth"),r(flowGrowth,"flowGrowth");export function clearFlowStart(e){for(const t of a.values())t.flowStartCounts.delete(e),t.flowDeltas.delete(e)}o(clearFlowStart,"clearFlowStart"),r(clearFlowStart,"clearFlowStart");export function allOwners(){return[...a.values()].map(e=>({ownerId:e.ownerId,ownerInstanceId:e.ownerInstanceId,containerKind:e.containerKind,fieldName:e.fieldName,itemCount:e.itemCount,estimatedBytes:e.estimatedBytes,growthSinceStart:e.itemCount-e.startCount}))}o(allOwners,"allOwners"),r(allOwners,"allOwners");export function getOwner(e){return a.get(e)}o(getOwner,"getOwner"),r(getOwner,"getOwner");export function resetOwners(){a.clear()}o(resetOwners,"resetOwners"),r(resetOwners,"resetOwners");
|
package/lib/track-container.d.ts
CHANGED
package/lib/track-container.js
CHANGED
|
@@ -1,155 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Container tracking. Wraps the mutating methods of a Map / Set / Array
|
|
3
|
-
* so each mutation:
|
|
4
|
-
* 1. updates the owner's item count + byte estimate,
|
|
5
|
-
* 2. emits a `memory-mutation` event attributed to the active flow.
|
|
6
|
-
*
|
|
7
|
-
* The wrapping is in-place (we patch the instance's own methods) and
|
|
8
|
-
* non-destructive: original behaviour always runs, return values pass
|
|
9
|
-
* through, and patching is idempotent (guarded by a Symbol flag).
|
|
10
|
-
*/
|
|
11
|
-
import { activeMemoryOptions, currentMemoryContext } from './context.js';
|
|
12
|
-
import { ensureOwner, recordCount, recordFlowDelta } from './owners.js';
|
|
13
|
-
import { emitMutation } from './emit.js';
|
|
14
|
-
const PATCHED = Symbol.for('@lensmcp/memory-tracker/patched');
|
|
15
|
-
/** Rough per-item byte estimate; good enough for growth-trend detection. */
|
|
16
|
-
const BYTES_PER_ITEM = 64;
|
|
17
|
-
export function trackContainer(args) {
|
|
18
|
-
const { container } = args;
|
|
19
|
-
if (!container || typeof container !== 'object')
|
|
20
|
-
return;
|
|
21
|
-
if (container[PATCHED])
|
|
22
|
-
return;
|
|
23
|
-
let kind;
|
|
24
|
-
if (container instanceof Map) {
|
|
25
|
-
kind = 'Map';
|
|
26
|
-
patchMap(args, container);
|
|
27
|
-
}
|
|
28
|
-
else if (container instanceof Set) {
|
|
29
|
-
kind = 'Set';
|
|
30
|
-
patchSet(args, container);
|
|
31
|
-
}
|
|
32
|
-
else if (Array.isArray(container)) {
|
|
33
|
-
kind = 'Array';
|
|
34
|
-
patchArray(args, container);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
container[PATCHED] = true;
|
|
40
|
-
// Register the owner eagerly (at its current size) so a subsequent
|
|
41
|
-
// `markFlowStart` snapshots a baseline even before the first mutation.
|
|
42
|
-
const initial = sizeOf(container);
|
|
43
|
-
const owner = ensureOwner({
|
|
44
|
-
ownerInstanceId: args.ownerInstanceId,
|
|
45
|
-
fieldName: args.fieldName,
|
|
46
|
-
containerKind: kind,
|
|
47
|
-
});
|
|
48
|
-
recordCount(owner, initial, initial * BYTES_PER_ITEM);
|
|
49
|
-
}
|
|
50
|
-
function sizeOf(container) {
|
|
51
|
-
if (container instanceof Map || container instanceof Set)
|
|
52
|
-
return container.size;
|
|
53
|
-
if (Array.isArray(container))
|
|
54
|
-
return container.length;
|
|
55
|
-
return 0;
|
|
56
|
-
}
|
|
57
|
-
function afterMutation(args, kind, operation, before, keyPreview) {
|
|
58
|
-
const opts = activeMemoryOptions();
|
|
59
|
-
if (!opts)
|
|
60
|
-
return;
|
|
61
|
-
const after = sizeOf(args.container);
|
|
62
|
-
const owner = ensureOwner({
|
|
63
|
-
ownerInstanceId: args.ownerInstanceId,
|
|
64
|
-
fieldName: args.fieldName,
|
|
65
|
-
containerKind: kind,
|
|
66
|
-
});
|
|
67
|
-
recordCount(owner, after, after * BYTES_PER_ITEM);
|
|
68
|
-
const ctx = currentMemoryContext();
|
|
69
|
-
// Attribute this mutation's net delta to the active flow so the leak
|
|
70
|
-
// detector blames the flow that actually grew the container. Keyed by
|
|
71
|
-
// requestId (preferred — the interceptor brackets onFlowStart/Settled
|
|
72
|
-
// by requestId) with flowId as the fallback for non-request flows.
|
|
73
|
-
const flowKey = ctx?.requestId ?? ctx?.flowId;
|
|
74
|
-
if (flowKey)
|
|
75
|
-
recordFlowDelta(owner, flowKey, after - before);
|
|
76
|
-
emitMutation({
|
|
77
|
-
options: opts,
|
|
78
|
-
ownerId: owner.ownerId,
|
|
79
|
-
operation,
|
|
80
|
-
beforeCount: before,
|
|
81
|
-
afterCount: after,
|
|
82
|
-
estimatedDeltaBytes: (after - before) * BYTES_PER_ITEM,
|
|
83
|
-
keyPreview,
|
|
84
|
-
context: ctx,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
function patchMap(args, map) {
|
|
88
|
-
const origSet = map.set.bind(map);
|
|
89
|
-
const origDelete = map.delete.bind(map);
|
|
90
|
-
const origClear = map.clear.bind(map);
|
|
91
|
-
map.set = (k, v) => {
|
|
92
|
-
const before = map.size;
|
|
93
|
-
const r = origSet(k, v);
|
|
94
|
-
afterMutation(args, 'Map', 'set', before, previewKey(k));
|
|
95
|
-
return r;
|
|
96
|
-
};
|
|
97
|
-
map.delete = (k) => {
|
|
98
|
-
const before = map.size;
|
|
99
|
-
const r = origDelete(k);
|
|
100
|
-
afterMutation(args, 'Map', 'delete', before, previewKey(k));
|
|
101
|
-
return r;
|
|
102
|
-
};
|
|
103
|
-
map.clear = () => {
|
|
104
|
-
const before = map.size;
|
|
105
|
-
origClear();
|
|
106
|
-
afterMutation(args, 'Map', 'clear', before);
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
function patchSet(args, set) {
|
|
110
|
-
const origAdd = set.add.bind(set);
|
|
111
|
-
const origDelete = set.delete.bind(set);
|
|
112
|
-
const origClear = set.clear.bind(set);
|
|
113
|
-
set.add = (v) => {
|
|
114
|
-
const before = set.size;
|
|
115
|
-
const r = origAdd(v);
|
|
116
|
-
afterMutation(args, 'Set', 'add', before, previewKey(v));
|
|
117
|
-
return r;
|
|
118
|
-
};
|
|
119
|
-
set.delete = (v) => {
|
|
120
|
-
const before = set.size;
|
|
121
|
-
const r = origDelete(v);
|
|
122
|
-
afterMutation(args, 'Set', 'delete', before, previewKey(v));
|
|
123
|
-
return r;
|
|
124
|
-
};
|
|
125
|
-
set.clear = () => {
|
|
126
|
-
const before = set.size;
|
|
127
|
-
origClear();
|
|
128
|
-
afterMutation(args, 'Set', 'clear', before);
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
function patchArray(args, arr) {
|
|
132
|
-
const origPush = arr.push.bind(arr);
|
|
133
|
-
const origSplice = arr.splice.bind(arr);
|
|
134
|
-
arr.push = (...items) => {
|
|
135
|
-
const before = arr.length;
|
|
136
|
-
const r = origPush(...items);
|
|
137
|
-
afterMutation(args, 'Array', 'push', before);
|
|
138
|
-
return r;
|
|
139
|
-
};
|
|
140
|
-
arr.splice = ((start, deleteCount, ...items) => {
|
|
141
|
-
const before = arr.length;
|
|
142
|
-
const r = deleteCount === undefined
|
|
143
|
-
? origSplice(start)
|
|
144
|
-
: origSplice(start, deleteCount, ...items);
|
|
145
|
-
afterMutation(args, 'Array', items.length > 0 ? 'push' : 'delete', before);
|
|
146
|
-
return r;
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
function previewKey(k) {
|
|
150
|
-
if (typeof k === 'string')
|
|
151
|
-
return k.slice(0, 40);
|
|
152
|
-
if (typeof k === 'number' || typeof k === 'boolean')
|
|
153
|
-
return String(k);
|
|
154
|
-
return undefined;
|
|
155
|
-
}
|
|
1
|
+
"use strict";var z=Object.defineProperty;var s=(t,e)=>z(t,"name",{value:e,configurable:!0});var A=Object.defineProperty,f=s((t,e)=>A(t,"name",{value:e,configurable:!0}),"s");import{activeMemoryOptions as g,currentMemoryContext as v}from"./context.js";import{ensureOwner as b,recordCount as h,recordFlowDelta as C}from"./owners.js";import{emitMutation as k}from"./emit.js";const I=Symbol.for("@lensmcp/memory-tracker/patched"),p=64;export function trackContainer(t){const{container:e}=t;if(!e||typeof e!="object"||e[I])return;let a;if(e instanceof Map)a="Map",w(t,e);else if(e instanceof Set)a="Set",M(t,e);else if(Array.isArray(e))a="Array",S(t,e);else return;e[I]=!0;const o=m(e),c=b({ownerInstanceId:t.ownerInstanceId,fieldName:t.fieldName,containerKind:a});h(c,o,o*p)}s(trackContainer,"trackContainer"),f(trackContainer,"trackContainer");function m(t){return t instanceof Map||t instanceof Set?t.size:Array.isArray(t)?t.length:0}s(m,"w"),f(m,"sizeOf");function d(t,e,a,o,c){const r=g();if(!r)return;const n=m(t.container),i=b({ownerInstanceId:t.ownerInstanceId,fieldName:t.fieldName,containerKind:e});h(i,n,n*p);const l=v(),y=l?.requestId??l?.flowId;y&&C(i,y,n-o),k({options:r,ownerId:i.ownerId,operation:a,beforeCount:o,afterCount:n,estimatedDeltaBytes:(n-o)*p,keyPreview:c,context:l})}s(d,"d"),f(d,"afterMutation");function w(t,e){const a=e.set.bind(e),o=e.delete.bind(e),c=e.clear.bind(e);e.set=(r,n)=>{const i=e.size,l=a(r,n);return d(t,"Map","set",i,u(r)),l},e.delete=r=>{const n=e.size,i=o(r);return d(t,"Map","delete",n,u(r)),i},e.clear=()=>{const r=e.size;c(),d(t,"Map","clear",r)}}s(w,"m"),f(w,"patchMap");function M(t,e){const a=e.add.bind(e),o=e.delete.bind(e),c=e.clear.bind(e);e.add=r=>{const n=e.size,i=a(r);return d(t,"Set","add",n,u(r)),i},e.delete=r=>{const n=e.size,i=o(r);return d(t,"Set","delete",n,u(r)),i},e.clear=()=>{const r=e.size;c(),d(t,"Set","clear",r)}}s(M,"C"),f(M,"patchSet");function S(t,e){const a=e.push.bind(e),o=e.splice.bind(e);e.push=(...c)=>{const r=e.length,n=a(...c);return d(t,"Array","push",r),n},e.splice=((c,r,...n)=>{const i=e.length,l=r===void 0?o(c):o(c,r,...n);return d(t,"Array",n.length>0?"push":"delete",i),l})}s(S,"D"),f(S,"patchArray");function u(t){if(typeof t=="string")return t.slice(0,40);if(typeof t=="number"||typeof t=="boolean")return String(t)}s(u,"u"),f(u,"previewKey");
|
package/lib/types.d.ts
CHANGED
package/lib/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
"use strict";export{};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/memory-tracker",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lensmcp/protocol-types": "1.18.
|
|
17
|
+
"@lensmcp/protocol-types": "1.18.6",
|
|
18
18
|
"tslib": "^2.3.0"
|
|
19
19
|
},
|
|
20
20
|
"license": "Apache-2.0",
|
package/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnF,OAAO,EACL,WAAW,EACX,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,aAAa,EACb,eAAe,EACf,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EACL,WAAW,EACX,aAAa,EACb,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,eAAe,EACf,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC"}
|
package/lib/context.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExF,KAAK,aAAa,GAAG,MAAM,aAAa,GAAG,SAAS,CAAC;AAWrD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B,GAAG,qBAAqB,CAWxB;AAED,wBAAgB,mBAAmB,IAAI,qBAAqB,GAAG,SAAS,CAEvE;AAED,wBAAgB,oBAAoB,IAAI,aAAa,GAAG,SAAS,CAEhE;AAED,iBAAiB;AACjB,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
|
package/lib/detectors.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detectors.d.ts","sourceRoot":"","sources":["../../src/lib/detectors.ts"],"names":[],"mappings":"AAoBA,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBtD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAcV"}
|
package/lib/emit.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/lib/emit.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAiBpB,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,uBAAuB,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CAyBP;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CAwBP;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CAuBP"}
|
package/lib/owners.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"owners.d.ts","sourceRoot":"","sources":["../../src/lib/owners.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE3E,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,mBAAmB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;;;OAKG;IACH,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAID,wBAAgB,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,mBAAmB,CAAC;CACpC,GAAG,WAAW,CAkBd;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,IAAI,CAGN;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMlD;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,IAAI,CAEN;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IAChD,KAAK,EAAE,WAAW,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAeD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAKnD;AAED,wBAAgB,SAAS,IAAI,mBAAmB,EAAE,CAUjD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"track-container.d.ts","sourceRoot":"","sources":["../../src/lib/track-container.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAKD,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CA6B7D"}
|
package/lib/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEvG,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,mDAAmD;AACnD,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,qFAAqF;IACrF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IACvF,6BAA6B,EAAE,MAAM,CAAC;IACtC,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,mBAAmB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B"}
|