@lensmcp/node-instrumentation 1.24.2 → 1.24.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Zero-touch Node runtime taps for [LensMCP](https://github.com/kiwiapps-ltd/lensmcp) — the observability lens for coding agents.
4
4
 
5
- `@lensmcp/node-instrumentation` instruments a running Node.js service **without touching its source**. It is loaded by the runner via `node --require @lensmcp/node-instrumentation/register`, before your app bundle, so it can patch Node built-ins and external modules (`fs`, `fetch`/`http(s)`, `child_process`, `pg`, `ioredis`, `bullmq`, `@nestjs/core`) and the process streams **in place**. As your service runs, those patches emit LensMCP events onto the bus that the dashboard and MCP server consume.
5
+ `@lensmcp/node-instrumentation` instruments a running Node.js service **without touching its source**. It is loaded by the runner via `node --require @lensmcp/node-instrumentation/register`, before your app bundle, so it can patch Node built-ins and external modules (`fs`, `fetch`/`http(s)`, `child_process`, `pg`, `ioredis`, `bullmq`, `@nestjs/core`, `@nestjs/common`) and the process streams **in place**. As your service runs, those patches emit LensMCP events onto the bus that the dashboard and MCP server consume.
6
6
 
7
7
  The whole point is that the host stays completely ordinary. There are no emit helpers, no `createLensmcpNestApp`, no dual-mode bootstrap — your `main.ts` looks exactly like an uninstrumented service. Requiring the module *is* the installation: it must run before the app loads so the require hook sees every external on first `require`/`import`. Every tap is wrapped in `try/catch` and the bus writer fails silently, so instrumentation can never throw into — or break — the host.
8
8
 
@@ -36,7 +36,7 @@ The package root also re-exports the individual tap functions (`tapFs`, `tapEgre
36
36
 
37
37
  ## What it taps
38
38
 
39
- Built-ins and globals are patched at install; external modules (`pg`, `ioredis`, `bullmq`, `@nestjs/core`) are patched lazily through a require hook the first time they load.
39
+ Built-ins and globals are patched at install; external modules (`pg`, `ioredis`, `bullmq`, `@nestjs/core`, `@nestjs/common`) are patched lazily through a require hook the first time they load.
40
40
 
41
41
  | Layer | How it's patched | Emits (source / kind) |
42
42
  |---|---|---|
@@ -48,6 +48,7 @@ Built-ins and globals are patched at install; external modules (`pg`, `ioredis`,
48
48
  | Queues | require hook → `bullmq` `Queue`/`Worker` prototypes | `queue` / `queue-enqueued`, `queue-active`, `queue-completed`, `queue-failed`, `queue-process`, plus a 2s `queue-state` snapshot |
49
49
  | NestJS | require hook → `@nestjs/core` `NestFactory.create` grafts `LensmcpModule` | the events from [`@lensmcp/nest-instrumentation`](https://github.com/kiwiapps-ltd/lensmcp) — class traces, request flows, memory |
50
50
  | stdout / stderr | `process.stdout`/`stderr` `write` wrap | `nestjs` / `runtime` — one log event per line (original output is preserved) |
51
+ | Logger calls | require hook → `@nestjs/common` `Logger` prototype + statics | `nestjs` / `runtime` — one log event per call made **inside a request or a job**, at every level, before the app's own level filter (`raw.stream: "logger"`, with the logger's context and level); redacted at capture; flood-guarded per logger and message shape. A line both logged and printed is one event. |
51
52
 
52
53
  Under the cluster devserver (`APP_RUNNER=1`) the NestJS tap also makes a standard `NestFactory.create(...)` + `app.listen(port)` service pod-servable: `listen` is intercepted to `init()` the app and hand its raw request handler to a capture queue instead of binding TCP, with no devserver contract in your `main.ts`.
53
54
 
@@ -59,7 +60,7 @@ All configuration is via environment variables (the cluster serve executor sets
59
60
  |---|---|
60
61
  | `LENSMCP_AUTO=0` | Disable **all** instrumentation — no taps are installed. |
61
62
  | `LENSMCP_NEST=0` | Keep the other taps but **skip the NestJS graft** (`NestFactory.create` is left untouched). |
62
- | `LENSMCP_LOGS=0` | Disable the stdout/stderr log tap. |
63
+ | `LENSMCP_LOGS=0` | Disable the stdout/stderr log tap and the `Logger` call capture. |
63
64
  | `LENSMCP_PROJECT` | Service identity stamped on every event. Falls back to `SERVICE_NAME`, then `"app"`. |
64
65
  | `LENSMCP_EVENT_FILE` | Path to the JSONL event bus. Defaults to `$CWD/.lensmcp/events.jsonl`. |
65
66
 
package/lib/emit.d.ts CHANGED
@@ -39,6 +39,8 @@ export interface FlowCtx {
39
39
  flowId?: string;
40
40
  requestId?: string;
41
41
  originNodeId?: string;
42
+ /** How the flow started — only on the event that starts one (a job nobody stamped: `job`). */
43
+ originType?: string;
42
44
  }
43
45
  /**
44
46
  * Returns whether the event was actually written. Almost every caller ignores it; a producer that
@@ -72,6 +74,24 @@ export declare function lensEmitOutcome(source: string, severity: LensSeverity,
72
74
  * write path as {@link lensEmit}; `source: 'nestjs'` + `raw.project` carries the
73
75
  * concrete service name (which the dashboard prefers as the log's source).
74
76
  */
75
- export declare function lensLog(severity: LogSeverity, title: string, detail?: {
77
+ export interface LogDetail {
76
78
  stack?: string;
77
- }): void;
79
+ text?: string;
80
+ continues?: boolean;
81
+ /** Where the record came from: what the pod wrote (`stdout` / `stderr`), or what a handler handed its logger. */
82
+ stream?: 'stdout' | 'stderr' | 'logger';
83
+ /** The logger's own level (`verbose`, `debug`, `log`, …), when the record came from one. */
84
+ level?: string;
85
+ /** The logger's context (`OnboardingConductor`). */
86
+ logger?: string;
87
+ /**
88
+ * Its own flood bucket, ALREADY admitted by the caller's guard: a logger line is bucketed per (context, message
89
+ * shape), not with everything the pod prints, and its caller decides before it serialises anything. The
90
+ * fingerprint is `log:<project>:<bucket>` — the bucket IS the fingerprint. `suppressed`: lines that bucket held
91
+ * back before this one.
92
+ */
93
+ bucket?: string;
94
+ suppressed?: number;
95
+ }
96
+ /** Returns whether the record was written (`false`: held back by its flood bucket, or the lens is offline). */
97
+ export declare function lensLog(severity: LogSeverity, title: string, detail?: LogDetail): boolean;
package/lib/emit.js CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";var m=Object.defineProperty;var i=(e,r)=>m(e,"name",{value:r,configurable:!0});var u=Object.defineProperty,c=i((e,r)=>u(e,"name",{value:r,configurable:!0}),"c");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EVENT_FILE=exports.PROJECT=exports.EVENT_MAX_FILES=exports.EVENT_MAX_BYTES=void 0,exports.maybeRotateEventFile=maybeRotateEventFile,exports.isLensWriting=isLensWriting,exports.lensEmit=lensEmit,exports.lensEmitOutcome=lensEmitOutcome,exports.lensLog=lensLog;const tslib_1=require("tslib"),nodeFs=tslib_1.__importStar(require("node:fs")),node_path_1=require("node:path"),bus_rotation_1=require("@lensmcp/core/bus-rotation"),flood_guard_1=require("./flood-guard"),flow_context_1=require("./flow-context"),appendFileSync=nodeFs.appendFileSync,mkdirSync=nodeFs.mkdirSync,statSync=nodeFs.statSync,renameSync=nodeFs.renameSync,unlinkSync=nodeFs.unlinkSync,openSync=nodeFs.openSync,closeSync=nodeFs.closeSync,BUS_CAPS=(0,bus_rotation_1.busCapsFromEnv)();exports.EVENT_MAX_BYTES=BUS_CAPS.maxBytes,exports.EVENT_MAX_FILES=BUS_CAPS.maxFiles;const rotators=new Map,BUS_FS={statSync,renameSync,unlinkSync,openSync,closeSync};function maybeRotateEventFile(e,r,o){if(o!==void 0){const n=o.maxBytes??exports.EVENT_MAX_BYTES,t=o.maxFiles??exports.EVENT_MAX_FILES;(0,bus_rotation_1.createBusRotator)(e,{maxBytes:n,maxFiles:t,fs:BUS_FS,checkEveryBytes:0})(r);return}let s=rotators.get(e);s||(s=(0,bus_rotation_1.createBusRotator)(e,{maxBytes:exports.EVENT_MAX_BYTES,maxFiles:exports.EVENT_MAX_FILES,fs:BUS_FS}),rotators.set(e,s)),s(r)}i(maybeRotateEventFile,"maybeRotateEventFile"),c(maybeRotateEventFile,"maybeRotateEventFile"),exports.PROJECT=process.env.LENSMCP_PROJECT||process.env.SERVICE_NAME||"app",exports.EVENT_FILE=process.env.LENSMCP_EVENT_FILE||`${process.cwd()}/.lensmcp/events.jsonl`;let writing=!1,dirReady=!1;const emitGuard=(0,flood_guard_1.createEventFloodGuard)({burst:30,perSec:5}),logGuard=(0,flood_guard_1.createEventFloodGuard)({burst:120,perSec:20});function isLensWriting(){return writing}i(isLensWriting,"isLensWriting"),c(isLensWriting,"isLensWriting");function lensEmit(e,r,o,s,n,t,a="cluster"){return lensEmitOutcome(e,r,o,s,n,t,a)==="written"}i(lensEmit,"lensEmit"),c(lensEmit,"lensEmit");function lensEmitOutcome(e,r,o,s,n,t,a="cluster",l=emitGuard){try{writing=!0;const E=n??`${e}:${String(s.name??e)}`,p=l.admit(E);if(!p.ok)return"suppressed";dirReady||(mkdirSync((0,node_path_1.dirname)(exports.EVENT_FILE),{recursive:!0}),dirReady=!0);const d=JSON.stringify({id:Date.now().toString(36)+Math.random().toString(36).slice(2,10),sessionId:"pending",timestamp:Date.now(),source:e,category:a,severity:r,context:{sessionId:"pending",projectName:exports.PROJECT,...t?.flowId?{flowId:t.flowId}:{},...t?.requestId?{requestId:t.requestId}:{},...t?.originNodeId?{originNodeId:t.originNodeId}:{}},fingerprint:E,title:o,raw:{project:exports.PROJECT,...s,...p.suppressed>0?{floodSuppressed:p.suppressed}:{}}})+`
2
- `;return maybeRotateEventFile(exports.EVENT_FILE,d.length),appendFileSync(exports.EVENT_FILE,d),"written"}catch{return"failed"}finally{writing=!1}}i(lensEmitOutcome,"lensEmitOutcome"),c(lensEmitOutcome,"lensEmitOutcome");function lensLog(e,r,o){try{writing=!0;const s=e==="error"||e==="fatal"?`log:error:${exports.PROJECT}`:`log:${exports.PROJECT}`,n=logGuard.admit(s);if(!n.ok)return;dirReady||(mkdirSync((0,node_path_1.dirname)(exports.EVENT_FILE),{recursive:!0}),dirReady=!0);const t=(0,flow_context_1.flowContext)(),a=JSON.stringify({id:Date.now().toString(36)+Math.random().toString(36).slice(2,10),sessionId:"pending",timestamp:Date.now(),source:"nestjs",category:"runtime",severity:e,context:{sessionId:"pending",projectName:exports.PROJECT,...t?.flowId?{flowId:t.flowId}:{},...t?.requestId?{requestId:t.requestId}:{}},fingerprint:s,title:r,raw:{project:exports.PROJECT,kind:"log",...o?.stack?{request:{error:{message:r,stack:o.stack}}}:{},...n.suppressed>0?{floodSuppressed:n.suppressed}:{}}})+`
3
- `;maybeRotateEventFile(exports.EVENT_FILE,a.length),appendFileSync(exports.EVENT_FILE,a)}catch{}finally{writing=!1}}i(lensLog,"lensLog"),c(lensLog,"lensLog");
1
+ "use strict";var m=Object.defineProperty;var p=(t,s)=>m(t,"name",{value:s,configurable:!0});var d=Object.defineProperty,i=p((t,s)=>d(t,"name",{value:s,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.EVENT_FILE=exports.PROJECT=exports.EVENT_MAX_FILES=exports.EVENT_MAX_BYTES=void 0,exports.maybeRotateEventFile=maybeRotateEventFile,exports.isLensWriting=isLensWriting,exports.lensEmit=lensEmit,exports.lensEmitOutcome=lensEmitOutcome,exports.lensLog=lensLog;const tslib_1=require("tslib"),nodeFs=tslib_1.__importStar(require("node:fs")),node_path_1=require("node:path"),bus_rotation_1=require("@lensmcp/core/bus-rotation"),flood_guard_1=require("./flood-guard"),flow_context_1=require("./flow-context"),appendFileSync=nodeFs.appendFileSync,mkdirSync=nodeFs.mkdirSync,statSync=nodeFs.statSync,renameSync=nodeFs.renameSync,unlinkSync=nodeFs.unlinkSync,openSync=nodeFs.openSync,closeSync=nodeFs.closeSync,BUS_CAPS=(0,bus_rotation_1.busCapsFromEnv)();exports.EVENT_MAX_BYTES=BUS_CAPS.maxBytes,exports.EVENT_MAX_FILES=BUS_CAPS.maxFiles;const rotators=new Map,BUS_FS={statSync,renameSync,unlinkSync,openSync,closeSync};function maybeRotateEventFile(t,s,e){if(e!==void 0){const n=e.maxBytes??exports.EVENT_MAX_BYTES,r=e.maxFiles??exports.EVENT_MAX_FILES;(0,bus_rotation_1.createBusRotator)(t,{maxBytes:n,maxFiles:r,fs:BUS_FS,checkEveryBytes:0})(s);return}let o=rotators.get(t);o||(o=(0,bus_rotation_1.createBusRotator)(t,{maxBytes:exports.EVENT_MAX_BYTES,maxFiles:exports.EVENT_MAX_FILES,fs:BUS_FS}),rotators.set(t,o)),o(s)}p(maybeRotateEventFile,"maybeRotateEventFile"),i(maybeRotateEventFile,"maybeRotateEventFile"),exports.PROJECT=process.env.LENSMCP_PROJECT||process.env.SERVICE_NAME||"app",exports.EVENT_FILE=process.env.LENSMCP_EVENT_FILE||`${process.cwd()}/.lensmcp/events.jsonl`;let writing=!1,dirReady=!1;const emitGuard=(0,flood_guard_1.createEventFloodGuard)({burst:30,perSec:5}),logGuard=(0,flood_guard_1.createEventFloodGuard)({burst:120,perSec:20});function isLensWriting(){return writing}p(isLensWriting,"isLensWriting"),i(isLensWriting,"isLensWriting");function lensEmit(t,s,e,o,n,r,a="cluster"){return lensEmitOutcome(t,s,e,o,n,r,a)==="written"}p(lensEmit,"lensEmit"),i(lensEmit,"lensEmit");function lensEmitOutcome(t,s,e,o,n,r,a="cluster",u=emitGuard){try{writing=!0;const E=n??`${t}:${String(o.name??t)}`,c=u.admit(E);if(!c.ok)return"suppressed";dirReady||(mkdirSync((0,node_path_1.dirname)(exports.EVENT_FILE),{recursive:!0}),dirReady=!0);const l=JSON.stringify({id:Date.now().toString(36)+Math.random().toString(36).slice(2,10),sessionId:"pending",timestamp:Date.now(),source:t,category:a,severity:s,context:{sessionId:"pending",projectName:exports.PROJECT,...r?.flowId?{flowId:r.flowId}:{},...r?.requestId?{requestId:r.requestId}:{},...r?.originNodeId?{originNodeId:r.originNodeId}:{},...r?.originType?{originType:r.originType}:{}},fingerprint:E,title:e,raw:{project:exports.PROJECT,...o,...c.suppressed>0?{floodSuppressed:c.suppressed}:{}}})+`
2
+ `;return maybeRotateEventFile(exports.EVENT_FILE,l.length),appendFileSync(exports.EVENT_FILE,l),"written"}catch{return"failed"}finally{writing=!1}}p(lensEmitOutcome,"lensEmitOutcome"),i(lensEmitOutcome,"lensEmitOutcome");function lensLog(t,s,e){try{writing=!0;const o=e?.bucket!==void 0?`log:${exports.PROJECT}:${e.bucket}`:t==="error"||t==="fatal"?`log:error:${exports.PROJECT}`:`log:${exports.PROJECT}`,n=e?.bucket!==void 0?{ok:!0,suppressed:e.suppressed??0}:logGuard.admit(o);if(!n.ok)return!1;dirReady||(mkdirSync((0,node_path_1.dirname)(exports.EVENT_FILE),{recursive:!0}),dirReady=!0);const r=(0,flow_context_1.flowContext)(),a=JSON.stringify({id:Date.now().toString(36)+Math.random().toString(36).slice(2,10),sessionId:"pending",timestamp:Date.now(),source:"nestjs",category:"runtime",severity:t,context:{sessionId:"pending",projectName:exports.PROJECT,...r?.flowId?{flowId:r.flowId}:{},...r?.requestId?{requestId:r.requestId}:{}},fingerprint:o,title:s,raw:{project:exports.PROJECT,kind:"log",...e?.stack?{request:{error:{message:s,stack:e.stack}}}:{},...e?.text?{text:e.text}:{},...e?.continues?{continues:!0}:{},...e?.stream?{stream:e.stream}:{},...e?.level?{level:e.level}:{},...e?.logger?{logger:e.logger}:{},...n.suppressed>0?{floodSuppressed:n.suppressed}:{}}})+`
3
+ `;return maybeRotateEventFile(exports.EVENT_FILE,a.length),appendFileSync(exports.EVENT_FILE,a),!0}catch{return!1}finally{writing=!1}}p(lensLog,"lensLog"),i(lensLog,"lensLog");
package/lib/install.js CHANGED
@@ -1 +1 @@
1
- "use strict";var p=Object.defineProperty;var a=(t,r)=>p(t,"name",{value:r,configurable:!0});var s=Object.defineProperty,e=a((t,r)=>s(t,"name",{value:r,configurable:!0}),"e");Object.defineProperty(exports,"__esModule",{value:!0}),exports.installLensmcpNodeInstrumentation=installLensmcpNodeInstrumentation;const require_hook_1=require("./require-hook"),flow_context_1=require("./flow-context"),tap_egress_1=require("./tap-egress"),tap_ai_1=require("./tap-ai"),tap_fs_1=require("./tap-fs"),tap_exec_1=require("./tap-exec"),tap_pg_1=require("./tap-pg"),tap_redis_1=require("./tap-redis"),active_work_1=require("./active-work"),tap_bullmq_1=require("./tap-bullmq"),tap_nest_1=require("./tap-nest"),tap_event_loop_1=require("./tap-event-loop"),tap_stdout_1=require("./tap-stdout");function installLensmcpNodeInstrumentation(){const t=globalThis;if(!t.__lensmcpNodeInstrumented&&(t.__lensmcpNodeInstrumented=!0,process.env.LENSMCP_AUTO!=="0")){try{(0,active_work_1.installActiveWorkProbe)()}catch{}try{(0,flow_context_1.primeFlowContext)()}catch{}try{(0,tap_egress_1.tapEgress)()}catch{}try{(0,tap_ai_1.tapAi)()}catch{}try{(0,tap_fs_1.tapFs)()}catch{}try{(0,tap_exec_1.tapExec)()}catch{}try{(0,tap_stdout_1.tapStdout)()}catch{}try{(0,tap_event_loop_1.tapEventLoop)()}catch{}try{(0,require_hook_1.installRequireHook)({pg:tap_pg_1.pgTap,ioredis:tap_redis_1.redisTap,bullmq:tap_bullmq_1.bullmqTap,"@nestjs/core":tap_nest_1.nestTap})}catch{}try{(0,tap_nest_1.installChildAppBridge)()}catch{}}}a(installLensmcpNodeInstrumentation,"installLensmcpNodeInstrumentation"),e(installLensmcpNodeInstrumentation,"installLensmcpNodeInstrumentation");
1
+ "use strict";var p=Object.defineProperty;var a=(t,r)=>p(t,"name",{value:r,configurable:!0});var s=Object.defineProperty,e=a((t,r)=>s(t,"name",{value:r,configurable:!0}),"e");Object.defineProperty(exports,"__esModule",{value:!0}),exports.installLensmcpNodeInstrumentation=installLensmcpNodeInstrumentation;const require_hook_1=require("./require-hook"),flow_context_1=require("./flow-context"),tap_egress_1=require("./tap-egress"),tap_ai_1=require("./tap-ai"),tap_fs_1=require("./tap-fs"),tap_exec_1=require("./tap-exec"),tap_pg_1=require("./tap-pg"),tap_redis_1=require("./tap-redis"),active_work_1=require("./active-work"),tap_bullmq_1=require("./tap-bullmq"),tap_nest_1=require("./tap-nest"),tap_nest_logger_1=require("./tap-nest-logger"),tap_event_loop_1=require("./tap-event-loop"),tap_stdout_1=require("./tap-stdout");function installLensmcpNodeInstrumentation(){const t=globalThis;if(!t.__lensmcpNodeInstrumented&&(t.__lensmcpNodeInstrumented=!0,process.env.LENSMCP_AUTO!=="0")){try{(0,active_work_1.installActiveWorkProbe)()}catch{}try{(0,flow_context_1.primeFlowContext)()}catch{}try{(0,tap_egress_1.tapEgress)()}catch{}try{(0,tap_ai_1.tapAi)()}catch{}try{(0,tap_fs_1.tapFs)()}catch{}try{(0,tap_exec_1.tapExec)()}catch{}try{(0,tap_stdout_1.tapStdout)()}catch{}try{(0,tap_event_loop_1.tapEventLoop)()}catch{}try{(0,require_hook_1.installRequireHook)({pg:tap_pg_1.pgTap,ioredis:tap_redis_1.redisTap,bullmq:tap_bullmq_1.bullmqTap,"@nestjs/core":tap_nest_1.nestTap,"@nestjs/common":tap_nest_logger_1.nestLoggerTap})}catch{}try{(0,tap_nest_1.installChildAppBridge)()}catch{}}}a(installLensmcpNodeInstrumentation,"installLensmcpNodeInstrumentation"),e(installLensmcpNodeInstrumentation,"installLensmcpNodeInstrumentation");
package/lib/tap-bullmq.js CHANGED
@@ -1 +1 @@
1
- "use strict";var y=Object.defineProperty;var a=(t,e)=>y(t,"name",{value:e,configurable:!0});var g=Object.defineProperty,u=a((t,e)=>g(t,"name",{value:e,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.bullmqTap=bullmqTap,exports.stopWorkIntake=stopWorkIntake,exports.workIntakeReport=workIntakeReport,exports.resetQueueStatePublishersForTests=resetQueueStatePublishersForTests,exports.resetWorkIntakeForTests=resetWorkIntakeForTests;const active_work_1=require("./active-work"),workerGeneration=new WeakMap,emit_1=require("./emit"),flow_context_1=require("./flow-context");function jobFlow(t){const e=t?.opts?.__lensmcpFlow;return e&&typeof e=="object"?e:void 0}a(jobFlow,"jobFlow"),u(jobFlow,"jobFlow");const jobLegId=u((t,e)=>`job:${t}#${e?.id??"?"}`,"jobLegId"),publishers=new Map,sources=new Map,sourceFor=u(t=>{let e=sources.get(t);return e||sources.set(t,e={}),e},"sourceFor"),usable=u(t=>!!t&&t.closing===void 0,"usable"),currentQueue=u(t=>{const e=sources.get(t),o=e?.app?.deref();return usable(o)?o:e?.own},"currentQueue");function ownConnection(t){if(!t||typeof t!="object")return;const e=t;if(typeof e.duplicate=="function")try{return e.duplicate()}catch{return}return Object.fromEntries(Object.entries(e).filter(([,o])=>typeof o!="function"))}a(ownConnection,"ownConnection"),u(ownConnection,"ownConnection");function bullmqTap(t){const e=t;if(typeof e?.Queue!="function"||typeof e?.Worker!="function")return!1;tappedQueue=e.Queue;try{tapQueueAdd(e)}catch{}try{tapWorkerEmit(e)}catch{}try{tapWorkerProcess(e)}catch{}try{tapWorkerStamp(e)}catch{}try{tapWorkerIntake(e)}catch{}try{tapWorkerConstruct(e)}catch{}try{installWorkIntakeControl()}catch{}return!0}a(bullmqTap,"bullmqTap"),u(bullmqTap,"bullmqTap");function stampWorker(t){try{if(workerGeneration.has(t))return;workerGeneration.set(t,(0,active_work_1.activeWorkGeneration)()),knownWorkers.add(new WeakRef(t))}catch{}}a(stampWorker,"stampWorker"),u(stampWorker,"stampWorker");function tapWorkerConstruct(t){const e=t.Worker;if(typeof e!="function"||e.__lensmcpGen)return;const o=new Proxy(e,{construct(r,n,s){const p=Reflect.construct(r,n,s);return stampWorker(p),p}});Object.defineProperty(e,"__lensmcpGen",{value:!0,enumerable:!1}),t.Worker=o}a(tapWorkerConstruct,"tapWorkerConstruct"),u(tapWorkerConstruct,"tapWorkerConstruct");function tapWorkerStamp(t){const e=t.Worker?.prototype;if(e)for(const o of["createLockManager","run"]){const r=e[o];if(typeof r!="function"||r.__lensmcpStamp)continue;const n=u(function(...s){return stampWorker(this),r.apply(this,s)},"wrapped");n.__lensmcpStamp=!0,e[o]=n}}a(tapWorkerStamp,"tapWorkerStamp"),u(tapWorkerStamp,"tapWorkerStamp");const knownWorkers=new Set,stoppedWorkers=new WeakSet,intake=new Map,INTAKE_GENERATIONS_KEPT=64;function intakeOf(t){let e=intake.get(t);if(!e){intake.set(t,e={workers:0,running:0,runningAtStop:0,takenAfterStop:0,finishedAfterStop:0});for(const o of intake.keys()){if(intake.size<=INTAKE_GENERATIONS_KEPT)break;intake.delete(o)}}return e}a(intakeOf,"intakeOf"),u(intakeOf,"intakeOf");function beginIntake(t,e){if(e===void 0)return()=>{};const o=intakeOf(e);return o.running+=1,stoppedWorkers.has(t)&&(o.takenAfterStop+=1),()=>{o.running-=1,o.stoppedAt!==void 0&&(o.finishedAfterStop+=1)}}a(beginIntake,"beginIntake"),u(beginIntake,"beginIntake");function stopWorkIntake(t){const e={workers:0,running:0,runningAtStop:0,takenAfterStop:0,finishedAfterStop:0},o=Date.now();for(const r of knownWorkers){const n=r.deref();if(!n){knownWorkers.delete(r);continue}const s=workerGeneration.get(n);if(s===void 0||s>=t||stoppedWorkers.has(n))continue;const p=n.pause;if(typeof p!="function")continue;stoppedWorkers.add(n),knownWorkers.delete(r);try{Promise.resolve(p.call(n,!0)).catch(()=>{})}catch{}const i=intakeOf(s);i.stoppedAt===void 0&&(i.stoppedAt=o,i.runningAtStop=i.running,e.running+=i.running,e.runningAtStop+=i.running),i.workers+=1,e.workers+=1}return e}a(stopWorkIntake,"stopWorkIntake"),u(stopWorkIntake,"stopWorkIntake");function workIntakeReport(t){const e=intake.get(t);if(!(!e||e.stoppedAt===void 0))return{workers:e.workers,running:e.running,runningAtStop:e.runningAtStop,takenAfterStop:e.takenAfterStop,finishedAfterStop:e.finishedAfterStop}}a(workIntakeReport,"workIntakeReport"),u(workIntakeReport,"workIntakeReport");function tapWorkerIntake(t){const e=t.Worker?.prototype;if(!e)return;const o=e.moveToActive;if(typeof o=="function"&&!o.__lensmcpIntake){const n=u(function(...s){return stoppedWorkers.has(this)?Promise.resolve(void 0):o.apply(this,s)},"wrapped");n.__lensmcpIntake=!0,e.moveToActive=n}const r=e.resume;if(typeof r=="function"&&!r.__lensmcpIntake){const n=u(function(...s){if(!stoppedWorkers.has(this))return r.apply(this,s)},"wrapped");n.__lensmcpIntake=!0,e.resume=n}}a(tapWorkerIntake,"tapWorkerIntake"),u(tapWorkerIntake,"tapWorkerIntake");function installWorkIntakeControl(){const t=globalThis;t.__lensmcpStopWorkIntake=stopWorkIntake,t.__lensmcpWorkIntakeReport=workIntakeReport}a(installWorkIntakeControl,"installWorkIntakeControl"),u(installWorkIntakeControl,"installWorkIntakeControl");function tapWorkerProcess(t){const e=t.Worker?.prototype,o=e?.callProcessJob;if(!e||typeof o!="function"||o.__lensmcp)return;const r=u(async function(n,...s){const p=workerGeneration.get(this),i=(0,active_work_1.beginActiveWork)(p),f=beginIntake(this,p),c=u(()=>{i(),f()},"endWork"),k=jobFlow(n);if(!k?.flowId)return o.call(this,n,...s).finally(c);const d=String(this?.name??n?.queueName??"queue"),w=jobLegId(d,n),l=Date.now(),h={flowId:k.flowId,requestId:w};return(0,flow_context_1.runInFlowContext)(h,async()=>{try{const m=await o.call(this,n,...s);return(0,emit_1.lensEmit)("queue","info",`process ${n?.name}#${n?.id} (${Date.now()-l}ms)`,{queue:d,kind:"queue-process",job:n?.name,jobId:n?.id,startedAt:l,durationMs:Date.now()-l,status:"ok"},`queue:${d}`,h),m}catch(m){throw(0,emit_1.lensEmit)("queue","error",`process ${n?.name}#${n?.id} failed (${Date.now()-l}ms)`,{queue:d,kind:"queue-process",job:n?.name,jobId:n?.id,startedAt:l,durationMs:Date.now()-l,status:"error",error:String(m?.message??m)},`queue:${d}`,h),m}finally{c()}})},"wrapped");r.__lensmcp=!0,e.callProcessJob=r}a(tapWorkerProcess,"tapWorkerProcess"),u(tapWorkerProcess,"tapWorkerProcess");function tapQueueAdd(t){const e=t.Queue?.prototype,o=e?.add;if(!e||typeof o!="function"||o.__lensmcp)return;const r=u(async function(n,...s){const p=Date.now(),i=(0,flow_context_1.flowContext)();if(i?.flowId){const c=s[1]??{};s[1]={...c,__lensmcpFlow:{flowId:i.flowId,...i.requestId?{originRequestId:i.requestId}:{}}}}const f=await o.call(this,n,...s);try{const c=String(this?.name??"queue"),k=s[0];let d;try{const l=JSON.stringify(k);d=l&&l!=="undefined"?l.length>300?l.slice(0,299)+"\u2026":l:void 0}catch{}(0,emit_1.lensEmit)("queue","info",`enqueued ${n}#${f?.id} \u2192 ${c}`,{queue:c,kind:"queue-enqueued",job:n,jobId:f?.id,...d?{data:d}:{},startedAt:p,durationMs:Date.now()-p},`queue:${c}`,i);const w=sourceFor(c);w.app?.deref()!==this&&(w.app=new WeakRef(this)),ensureStatePublisher(c)}catch{}return f},"wrapped");r.__lensmcp=!0,e.add=r}a(tapQueueAdd,"tapQueueAdd"),u(tapQueueAdd,"tapQueueAdd");function tapWorkerEmit(t){const e=t.Worker?.prototype,o=e?.emit;if(!e||typeof o!="function"||o.__lensmcp)return;const r=u(function(n,...s){try{observeWorkerEvent(this,String(n),s)}catch{}return o.call(this,n,...s)},"wrapped");r.__lensmcp=!0,e.emit=r}a(tapWorkerEmit,"tapWorkerEmit"),u(tapWorkerEmit,"tapWorkerEmit");function observeWorkerEvent(t,e,o){if(e!=="active"&&e!=="completed"&&e!=="failed")return;const r=String(t.name??"queue"),n=o[0],s=jobFlow(n),p=s?.flowId?{flowId:s.flowId,requestId:jobLegId(r,n)}:void 0;if(e==="active")(0,emit_1.lensEmit)("queue","info",`processing ${n?.name}#${n?.id}`,{queue:r,kind:"queue-active",jobId:n?.id},`queue:${r}`,p);else if(e==="completed"){let i;try{const f=n?.returnvalue??o[1],c=JSON.stringify(f);i=c&&c!=="undefined"?c.length>160?c.slice(0,159)+"\u2026":c:void 0}catch{}(0,emit_1.lensEmit)("queue","info",`completed ${n?.name}#${n?.id}`,{queue:r,kind:"queue-completed",jobId:n?.id,...i?{returned:i}:{}},`queue:${r}`,p)}else{const i=o[1];(0,emit_1.lensEmit)("queue","error",`job ${n?.id} failed: ${i?.message}`,{queue:r,kind:"queue-failed",jobId:n?.id,error:String(i?.message??i)},`queue:${r}`,p)}if(!currentQueue(r))try{const i=t.opts,f=ownConnection(i?.connection);if(f){const c=snapshotQueueClass();c&&(sourceFor(r).own=new c(r,{connection:f}))}}catch{}ensureStatePublisher(r)}a(observeWorkerEvent,"observeWorkerEvent"),u(observeWorkerEvent,"observeWorkerEvent");let tappedQueue;function snapshotQueueClass(){if(tappedQueue)return tappedQueue;try{return require("bullmq").Queue}catch{return}}a(snapshotQueueClass,"snapshotQueueClass"),u(snapshotQueueClass,"snapshotQueueClass");function ensureStatePublisher(t){if(publishers.has(t))return;let e="";const o=setInterval(()=>{(async()=>{try{const r=currentQueue(t);if(!r)return;const n=await r.getJobCounts(),s=[];for(const f of["active","waiting","failed","completed","delayed"])for(const c of await r.getJobs([f],0,7)){const k=c?.data?.to;s.push({id:String(c.id),name:c.name,state:f,timestamp:c.timestamp??0,...typeof k=="string"?{to:k}:{}})}s.sort((f,c)=>Number(c.timestamp)-Number(f.timestamp));const p=s.slice(0,8),i=JSON.stringify([n,p.map(f=>`${f.id}${f.state}`)]);if(i===e)return;e=i,(0,emit_1.lensEmit)("queue","info",`queue state: ${n.active??0} active \xB7 ${n.waiting??0} waiting \xB7 ${n.failed??0} failed`,{queue:t,kind:"queue-state",counts:n,recent:p},`queue:${t}`)}catch{}})()},2e3);o.unref?.(),publishers.set(t,o)}a(ensureStatePublisher,"ensureStatePublisher"),u(ensureStatePublisher,"ensureStatePublisher");function resetQueueStatePublishersForTests(){for(const t of publishers.values())clearInterval(t);publishers.clear(),sources.clear()}a(resetQueueStatePublishersForTests,"resetQueueStatePublishersForTests"),u(resetQueueStatePublishersForTests,"resetQueueStatePublishersForTests");function resetWorkIntakeForTests(){knownWorkers.clear(),intake.clear()}a(resetWorkIntakeForTests,"resetWorkIntakeForTests"),u(resetWorkIntakeForTests,"resetWorkIntakeForTests");
1
+ "use strict";var b=Object.defineProperty;var a=(t,e)=>b(t,"name",{value:e,configurable:!0});var g=Object.defineProperty,i=a((t,e)=>g(t,"name",{value:e,configurable:!0}),"i");Object.defineProperty(exports,"__esModule",{value:!0}),exports.bullmqTap=bullmqTap,exports.stopWorkIntake=stopWorkIntake,exports.workIntakeReport=workIntakeReport,exports.resetQueueStatePublishersForTests=resetQueueStatePublishersForTests,exports.resetWorkIntakeForTests=resetWorkIntakeForTests;const active_work_1=require("./active-work"),workerGeneration=new WeakMap,headless_flow_1=require("@lensmcp/core/headless-flow"),emit_1=require("./emit"),flow_context_1=require("./flow-context");function jobFlow(t){const e=t?.opts?.__lensmcpFlow;return e&&typeof e=="object"?e:void 0}a(jobFlow,"jobFlow"),i(jobFlow,"jobFlow");const jobLegId=i((t,e)=>`job:${t}#${e?.id??"?"}`,"jobLegId");function flowOfJob(t,e){const o=jobFlow(e)?.flowId;if(o)return{flowId:o,own:!1};if((0,headless_flow_1.headlessFlowsEnabled)())return{flowId:(0,headless_flow_1.headlessJobFlowId)(t,e?.id),own:!0}}a(flowOfJob,"flowOfJob"),i(flowOfJob,"flowOfJob");const publishers=new Map,sources=new Map,sourceFor=i(t=>{let e=sources.get(t);return e||sources.set(t,e={}),e},"sourceFor"),usable=i(t=>!!t&&t.closing===void 0,"usable"),currentQueue=i(t=>{const e=sources.get(t),o=e?.app?.deref();return usable(o)?o:e?.own},"currentQueue");function ownConnection(t){if(!t||typeof t!="object")return;const e=t;if(typeof e.duplicate=="function")try{return e.duplicate()}catch{return}return Object.fromEntries(Object.entries(e).filter(([,o])=>typeof o!="function"))}a(ownConnection,"ownConnection"),i(ownConnection,"ownConnection");function bullmqTap(t){const e=t;if(typeof e?.Queue!="function"||typeof e?.Worker!="function")return!1;tappedQueue=e.Queue;try{tapQueueAdd(e)}catch{}try{tapWorkerEmit(e)}catch{}try{tapWorkerProcess(e)}catch{}try{tapWorkerStamp(e)}catch{}try{tapWorkerIntake(e)}catch{}try{tapWorkerConstruct(e)}catch{}try{installWorkIntakeControl()}catch{}return!0}a(bullmqTap,"bullmqTap"),i(bullmqTap,"bullmqTap");function stampWorker(t){try{if(workerGeneration.has(t))return;workerGeneration.set(t,(0,active_work_1.activeWorkGeneration)()),knownWorkers.add(new WeakRef(t))}catch{}}a(stampWorker,"stampWorker"),i(stampWorker,"stampWorker");function tapWorkerConstruct(t){const e=t.Worker;if(typeof e!="function"||e.__lensmcpGen)return;const o=new Proxy(e,{construct(r,n,s){const f=Reflect.construct(r,n,s);return stampWorker(f),f}});Object.defineProperty(e,"__lensmcpGen",{value:!0,enumerable:!1}),t.Worker=o}a(tapWorkerConstruct,"tapWorkerConstruct"),i(tapWorkerConstruct,"tapWorkerConstruct");function tapWorkerStamp(t){const e=t.Worker?.prototype;if(e)for(const o of["createLockManager","run"]){const r=e[o];if(typeof r!="function"||r.__lensmcpStamp)continue;const n=i(function(...s){return stampWorker(this),r.apply(this,s)},"wrapped");n.__lensmcpStamp=!0,e[o]=n}}a(tapWorkerStamp,"tapWorkerStamp"),i(tapWorkerStamp,"tapWorkerStamp");const knownWorkers=new Set,stoppedWorkers=new WeakSet,intake=new Map,INTAKE_GENERATIONS_KEPT=64;function intakeOf(t){let e=intake.get(t);if(!e){intake.set(t,e={workers:0,running:0,runningAtStop:0,takenAfterStop:0,finishedAfterStop:0});for(const o of intake.keys()){if(intake.size<=INTAKE_GENERATIONS_KEPT)break;intake.delete(o)}}return e}a(intakeOf,"intakeOf"),i(intakeOf,"intakeOf");function beginIntake(t,e){if(e===void 0)return()=>{};const o=intakeOf(e);return o.running+=1,stoppedWorkers.has(t)&&(o.takenAfterStop+=1),()=>{o.running-=1,o.stoppedAt!==void 0&&(o.finishedAfterStop+=1)}}a(beginIntake,"beginIntake"),i(beginIntake,"beginIntake");function stopWorkIntake(t){const e={workers:0,running:0,runningAtStop:0,takenAfterStop:0,finishedAfterStop:0},o=Date.now();for(const r of knownWorkers){const n=r.deref();if(!n){knownWorkers.delete(r);continue}const s=workerGeneration.get(n);if(s===void 0||s>=t||stoppedWorkers.has(n))continue;const f=n.pause;if(typeof f!="function")continue;stoppedWorkers.add(n),knownWorkers.delete(r);try{Promise.resolve(f.call(n,!0)).catch(()=>{})}catch{}const u=intakeOf(s);u.stoppedAt===void 0&&(u.stoppedAt=o,u.runningAtStop=u.running,e.running+=u.running,e.runningAtStop+=u.running),u.workers+=1,e.workers+=1}return e}a(stopWorkIntake,"stopWorkIntake"),i(stopWorkIntake,"stopWorkIntake");function workIntakeReport(t){const e=intake.get(t);if(!(!e||e.stoppedAt===void 0))return{workers:e.workers,running:e.running,runningAtStop:e.runningAtStop,takenAfterStop:e.takenAfterStop,finishedAfterStop:e.finishedAfterStop}}a(workIntakeReport,"workIntakeReport"),i(workIntakeReport,"workIntakeReport");function tapWorkerIntake(t){const e=t.Worker?.prototype;if(!e)return;const o=e.moveToActive;if(typeof o=="function"&&!o.__lensmcpIntake){const n=i(function(...s){return stoppedWorkers.has(this)?Promise.resolve(void 0):o.apply(this,s)},"wrapped");n.__lensmcpIntake=!0,e.moveToActive=n}const r=e.resume;if(typeof r=="function"&&!r.__lensmcpIntake){const n=i(function(...s){if(!stoppedWorkers.has(this))return r.apply(this,s)},"wrapped");n.__lensmcpIntake=!0,e.resume=n}}a(tapWorkerIntake,"tapWorkerIntake"),i(tapWorkerIntake,"tapWorkerIntake");function installWorkIntakeControl(){const t=globalThis;t.__lensmcpStopWorkIntake=stopWorkIntake,t.__lensmcpWorkIntakeReport=workIntakeReport}a(installWorkIntakeControl,"installWorkIntakeControl"),i(installWorkIntakeControl,"installWorkIntakeControl");function tapWorkerProcess(t){const e=t.Worker?.prototype,o=e?.callProcessJob;if(!e||typeof o!="function"||o.__lensmcp)return;const r=i(async function(n,...s){const f=workerGeneration.get(this),u=(0,active_work_1.beginActiveWork)(f),p=beginIntake(this,f),c=i(()=>{u(),p()},"endWork"),l=String(this?.name??n?.queueName??"queue"),m=flowOfJob(l,n);if(!m)return o.call(this,n,...s).finally(c);const w=jobLegId(l,n),d=Date.now(),h={flowId:m.flowId,requestId:w};if(m.own){const k=`job:${l}/${n?.name??"job"}`;(0,emit_1.lensEmit)("queue","info",`job ${n?.name??""}#${n?.id??"?"} \xB7 ${l}`,{queue:l,kind:"flow-origin",job:n?.name,jobId:n?.id,originNodeId:k},`queue-origin:${l}`,{...h,originType:"job",originNodeId:k})}return(0,flow_context_1.runInFlowContext)(h,async()=>{try{const k=await o.call(this,n,...s);return(0,emit_1.lensEmit)("queue","info",`process ${n?.name}#${n?.id} (${Date.now()-d}ms)`,{queue:l,kind:"queue-process",job:n?.name,jobId:n?.id,startedAt:d,durationMs:Date.now()-d,status:"ok"},`queue:${l}`,h),k}catch(k){throw(0,emit_1.lensEmit)("queue","error",`process ${n?.name}#${n?.id} failed (${Date.now()-d}ms)`,{queue:l,kind:"queue-process",job:n?.name,jobId:n?.id,startedAt:d,durationMs:Date.now()-d,status:"error",error:String(k?.message??k)},`queue:${l}`,h),k}finally{c()}})},"wrapped");r.__lensmcp=!0,e.callProcessJob=r}a(tapWorkerProcess,"tapWorkerProcess"),i(tapWorkerProcess,"tapWorkerProcess");function tapQueueAdd(t){const e=t.Queue?.prototype,o=e?.add;if(!e||typeof o!="function"||o.__lensmcp)return;const r=i(async function(n,...s){const f=Date.now(),u=(0,flow_context_1.flowContext)();if(u?.flowId){const c=s[1]??{};s[1]={...c,__lensmcpFlow:{flowId:u.flowId,...u.requestId?{originRequestId:u.requestId}:{}}}}const p=await o.call(this,n,...s);try{const c=String(this?.name??"queue"),l=s[0];let m;try{const d=JSON.stringify(l);m=d&&d!=="undefined"?d.length>300?d.slice(0,299)+"\u2026":d:void 0}catch{}(0,emit_1.lensEmit)("queue","info",`enqueued ${n}#${p?.id} \u2192 ${c}`,{queue:c,kind:"queue-enqueued",job:n,jobId:p?.id,...m?{data:m}:{},startedAt:f,durationMs:Date.now()-f},`queue:${c}`,u);const w=sourceFor(c);w.app?.deref()!==this&&(w.app=new WeakRef(this)),ensureStatePublisher(c)}catch{}return p},"wrapped");r.__lensmcp=!0,e.add=r}a(tapQueueAdd,"tapQueueAdd"),i(tapQueueAdd,"tapQueueAdd");function tapWorkerEmit(t){const e=t.Worker?.prototype,o=e?.emit;if(!e||typeof o!="function"||o.__lensmcp)return;const r=i(function(n,...s){try{observeWorkerEvent(this,String(n),s)}catch{}return o.call(this,n,...s)},"wrapped");r.__lensmcp=!0,e.emit=r}a(tapWorkerEmit,"tapWorkerEmit"),i(tapWorkerEmit,"tapWorkerEmit");function observeWorkerEvent(t,e,o){if(e!=="active"&&e!=="completed"&&e!=="failed")return;const r=String(t.name??"queue"),n=o[0],s=flowOfJob(r,n),f=s?{flowId:s.flowId,requestId:jobLegId(r,n)}:void 0;if(e==="active")(0,emit_1.lensEmit)("queue","info",`processing ${n?.name}#${n?.id}`,{queue:r,kind:"queue-active",jobId:n?.id},`queue:${r}`,f);else if(e==="completed"){let u;try{const p=n?.returnvalue??o[1],c=JSON.stringify(p);u=c&&c!=="undefined"?c.length>160?c.slice(0,159)+"\u2026":c:void 0}catch{}(0,emit_1.lensEmit)("queue","info",`completed ${n?.name}#${n?.id}`,{queue:r,kind:"queue-completed",jobId:n?.id,...u?{returned:u}:{}},`queue:${r}`,f)}else{const u=o[1];(0,emit_1.lensEmit)("queue","error",`job ${n?.id} failed: ${u?.message}`,{queue:r,kind:"queue-failed",jobId:n?.id,error:String(u?.message??u)},`queue:${r}`,f)}if(!currentQueue(r))try{const u=t.opts,p=ownConnection(u?.connection);if(p){const c=snapshotQueueClass();c&&(sourceFor(r).own=new c(r,{connection:p}))}}catch{}ensureStatePublisher(r)}a(observeWorkerEvent,"observeWorkerEvent"),i(observeWorkerEvent,"observeWorkerEvent");let tappedQueue;function snapshotQueueClass(){if(tappedQueue)return tappedQueue;try{return require("bullmq").Queue}catch{return}}a(snapshotQueueClass,"snapshotQueueClass"),i(snapshotQueueClass,"snapshotQueueClass");function ensureStatePublisher(t){if(publishers.has(t))return;let e="";const o=setInterval(()=>{(async()=>{try{const r=currentQueue(t);if(!r)return;const n=await r.getJobCounts(),s=[];for(const p of["active","waiting","failed","completed","delayed"])for(const c of await r.getJobs([p],0,7)){const l=c?.data?.to;s.push({id:String(c.id),name:c.name,state:p,timestamp:c.timestamp??0,...typeof l=="string"?{to:l}:{}})}s.sort((p,c)=>Number(c.timestamp)-Number(p.timestamp));const f=s.slice(0,8),u=JSON.stringify([n,f.map(p=>`${p.id}${p.state}`)]);if(u===e)return;e=u,(0,emit_1.lensEmit)("queue","info",`queue state: ${n.active??0} active \xB7 ${n.waiting??0} waiting \xB7 ${n.failed??0} failed`,{queue:t,kind:"queue-state",counts:n,recent:f},`queue:${t}`)}catch{}})()},2e3);o.unref?.(),publishers.set(t,o)}a(ensureStatePublisher,"ensureStatePublisher"),i(ensureStatePublisher,"ensureStatePublisher");function resetQueueStatePublishersForTests(){for(const t of publishers.values())clearInterval(t);publishers.clear(),sources.clear()}a(resetQueueStatePublishersForTests,"resetQueueStatePublishersForTests"),i(resetQueueStatePublishersForTests,"resetQueueStatePublishersForTests");function resetWorkIntakeForTests(){knownWorkers.clear(),intake.clear()}a(resetWorkIntakeForTests,"resetWorkIntakeForTests"),i(resetWorkIntakeForTests,"resetWorkIntakeForTests");
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Is this written record the print of a line the logger tap already captured?
3
+ *
4
+ * The app's logger formats the message its own way (a timestamp, a level, a JSON tail), so the
5
+ * print is recognised by CONTAINING the message's opening text — as written, or as a JSON logger
6
+ * escapes it — within two seconds. Found, it is consumed: a second identical print is a second record.
7
+ */
8
+ export declare function isLoggerEcho(record: string, now?: number): boolean;
9
+ /** Test seam. */
10
+ export declare function resetNestLoggerTapForTests(): void;
11
+ /** `@nestjs/common` loaded: patch its `Logger`. `false` while the exports are not there yet (a circular require). */
12
+ export declare function nestLoggerTap(exportsObject: unknown): boolean;
@@ -0,0 +1,6 @@
1
+ "use strict";var T=Object.defineProperty;var s=(e,t)=>T(e,"name",{value:t,configurable:!0});var S=Object.defineProperty,o=s((e,t)=>S(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.isLoggerEcho=isLoggerEcho,exports.resetNestLoggerTapForTests=resetNestLoggerTapForTests,exports.nestLoggerTap=nestLoggerTap;const redact_1=require("@lensmcp/core/redact"),flood_guard_1=require("./flood-guard"),emit_1=require("./emit"),flow_context_1=require("./flow-context"),LEVELS=["verbose","debug","log","warn","error","fatal"],SEVERITY={verbose:"debug",debug:"debug",log:"info",warn:"warning",error:"error",fatal:"fatal"},MAX_TEXT_CHARS=4e3,TITLE_CHARS=240,shapeGuard=(0,flood_guard_1.createEventFloodGuard)({burst:30,perSec:5}),podGuard=(0,flood_guard_1.createEventFloodGuard)({burst:400,perSec:100});let depth=0;const recent=[],ECHO_WINDOW_MS=2e3,ECHO_NEEDLE_CHARS=96,ECHO_MIN_CHARS=12,MAX_RECENT=64;function isLoggerEcho(e,t=Date.now()){for(let r=recent.length-1;r>=0;r--){const n=recent[r];if(t-n.at>ECHO_WINDOW_MS)return recent.splice(0,r+1),!1;if(e.includes(n.needle)||n.escaped!==void 0&&e.includes(n.escaped))return recent.splice(r,1),!0}return!1}s(isLoggerEcho,"isLoggerEcho"),o(isLoggerEcho,"isLoggerEcho");function expectEcho(e,t){const r=e.split(`
2
+ `,1)[0]??"";if(r.length<ECHO_MIN_CHARS)return;const n=r.slice(0,ECHO_NEEDLE_CHARS),c=JSON.stringify(n).slice(1,-1);recent.push({needle:n,at:t,...c!==n?{escaped:c}:{}}),recent.length>MAX_RECENT&&recent.splice(0,recent.length-MAX_RECENT)}s(expectEcho,"expectEcho"),o(expectEcho,"expectEcho");function resetNestLoggerTapForTests(){recent.length=0,depth=0}s(resetNestLoggerTapForTests,"resetNestLoggerTapForTests"),o(resetNestLoggerTapForTests,"resetNestLoggerTapForTests");function textOf(e){if(typeof e=="string")return e;if(e instanceof Error)return e.stack??`${e.name}: ${e.message}`;if(e===null||typeof e!="object")return String(e);try{return JSON.stringify(e)??String(e)}catch{return Object.prototype.toString.call(e)}}s(textOf,"textOf"),o(textOf,"textOf");function openingOf(e){return typeof e=="string"?e.split(`
3
+ `,1)[0]??"":e instanceof Error?`${e.name}: ${e.message}`.split(`
4
+ `,1)[0]??"":e===null||typeof e!="object"?String(e):"{object}"}s(openingOf,"openingOf"),o(openingOf,"openingOf");const looksLikeStack=o(e=>typeof e=="string"&&/\n\s+at\s/.test(e),"looksLikeStack");function shapeOf(e){return e.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,"#").replace(/\b[0-9a-f]{12,}\b/gi,"#").replace(/\d+/g,"#").slice(0,80)}s(shapeOf,"shapeOf"),o(shapeOf,"shapeOf");function capture(e,t,r,n){const c=(0,flow_context_1.flowContext)();if(!c?.flowId&&!c?.requestId)return;const l=t?.context,i=n.slice();let f=typeof l=="string"&&l?l:void 0;!f&&i.length>0&&typeof i[i.length-1]=="string"&&!looksLikeStack(i[i.length-1])&&(f=i.pop());const h=openingOf(r),E=`${f??""}:${shapeOf((0,redact_1.redactText)(h.slice(0,MAX_TEXT_CHARS*2)))}`,_=Date.now(),u=shapeGuard.admit(E),L=u.ok?podGuard.admit("pod"):u;if(!u.ok||!L.ok){expectEcho(h,_);return}const y=[r,...i].filter(a=>a!==void 0).map(textOf);let d="";for(const a of y)d+=d===""?a:(looksLikeStack(a)?`
5
+ `:" ")+a;const p=(0,redact_1.redactText)(d.slice(0,MAX_TEXT_CHARS*2)).slice(0,MAX_TEXT_CHARS);if(!p)return;const g=p.split(`
6
+ `,1)[0]??"",b=looksLikeStack(p);(0,emit_1.lensLog)(SEVERITY[e],g.length>TITLE_CHARS?`${g.slice(0,TITLE_CHARS)}\u2026`:g,{...b?{stack:p}:p!==g||g.length>TITLE_CHARS?{text:p}:{},stream:"logger",level:e,...f?{logger:f}:{},bucket:E,suppressed:u.suppressed+L.suppressed});for(const a of y)expectEcho(a,_)}s(capture,"capture"),o(capture,"capture");function wrap(e,t){const r=e[t];if(typeof r!="function"||r.__lensmcpLog)return;const n=o(function(c,...l){if(depth===0)try{capture(t,this,c,l)}catch{}depth+=1;try{return r.call(this,c,...l)}finally{depth-=1}},"wrapped");n.__lensmcpLog=!0,e[t]=n}s(wrap,"wrap"),o(wrap,"wrap");function nestLoggerTap(e){if(process.env.LENSMCP_LOGS==="0")return!0;const t=e?.Logger;if(typeof t!="function"||!t.prototype)return!1;for(const r of LEVELS)wrap(t.prototype,r),wrap(t,r);return!0}s(nestLoggerTap,"nestLoggerTap"),o(nestLoggerTap,"nestLoggerTap");
package/lib/tap-stdout.js CHANGED
@@ -1,3 +1,5 @@
1
- "use strict";var a=Object.defineProperty;var c=(e,t)=>a(e,"name",{value:t,configurable:!0});var u=Object.defineProperty,o=c((e,t)=>u(e,"name",{value:t,configurable:!0}),"o");Object.defineProperty(exports,"__esModule",{value:!0}),exports.tapStdout=tapStdout;const emit_1=require("./emit"),ANSI=new RegExp("\x1B\\[[0-9;]*m","g");function severityOf(e,t){return/\bFATAL\b/.test(e)?"fatal":/\bERROR\b/.test(e)?"error":/\bWARN\b/.test(e)?"warning":/\bDEBUG\b/.test(e)||/\bVERBOSE\b/.test(e)?"debug":/\bLOG\b/.test(e)?"info":t}c(severityOf,"severityOf"),o(severityOf,"severityOf");const STACK_FRAME=/^\s+(at\s|\.\.\.\s\d+\smore)/;function emitChunk(e,t){const i=e.split(`
2
- `).map(r=>r.replace(ANSI,"").replace(/\s+$/,""));let s=0;for(;s<i.length;){const r=i[s];if(s+=1,!r.trim())continue;const n=[];for(;s<i.length&&STACK_FRAME.test(i[s]);)n.push(i[s]),s+=1;const f=n.length>0?"error":severityOf(r,t);(0,emit_1.lensLog)(f,r,n.length>0?{stack:[r,...n].join(`
3
- `)}:void 0)}}c(emitChunk,"emitChunk"),o(emitChunk,"emitChunk");function tapStdout(){if(process.env.LENSMCP_LOGS==="0"||process.env.APP_RUNNER!=="1")return;const e=[[process.stdout,"info"],[process.stderr,"error"]];for(const[t,i]of e){if(t.write.__lensmcp)continue;const s=t.write.bind(t),r=o(function(n,...f){try{if(!(0,emit_1.isLensWriting)()){const p=typeof n=="string"?n:Buffer.isBuffer(n)?n.toString("utf8"):"";p&&p.indexOf("[lensmcp]")===-1&&emitChunk(p,i)}}catch{}return s(n,...f)},"wrapped");r.__lensmcp=!0,t.write=r}}c(tapStdout,"tapStdout"),o(tapStdout,"tapStdout");
1
+ "use strict";var R=Object.defineProperty;var f=(t,e)=>R(t,"name",{value:e,configurable:!0});var E=Object.defineProperty,u=f((t,e)=>E(t,"name",{value:e,configurable:!0}),"u");Object.defineProperty(exports,"__esModule",{value:!0}),exports.tapStdout=tapStdout;const emit_1=require("./emit"),tap_nest_logger_1=require("./tap-nest-logger"),ANSI=new RegExp("\x1B\\[[0-9;]*m","g");function severityOf(t,e){return/\bFATAL\b/.test(t)?"fatal":/\bERROR\b/.test(t)?"error":/\bWARN\b/.test(t)?"warning":/\bDEBUG\b/.test(t)||/\bVERBOSE\b/.test(t)?"debug":/\bLOG\b/.test(t)?"info":e}f(severityOf,"severityOf"),u(severityOf,"severityOf");const STACK_FRAME=/^\s+(at\s|\.\.\.\s\d+\smore)/,CONTINUATION=/^(\s+\S|[}\])]+[,;]?$)/,CONTINUES_WITHIN_MS=1e3;function emitChunk(t,e,p,c,l){const o=t.split(`
2
+ `).map(r=>r.replace(ANSI,"").replace(/\s+$/,""));let s=0,n=p;for(;s<o.length;){const r=o[s];if(s+=1,!r.trim())continue;const i=[];for(;s<o.length&&o[s].trim()&&CONTINUATION.test(o[s]);)i.push(o[s]),s+=1;const g=[r,...i].filter(_=>STACK_FRAME.test(_)),a=CONTINUATION.test(r)&&n&&c-n.at<=CONTINUES_WITHIN_MS?n.severity:void 0,m=severityOf(r,e),O=m!==e||/\b(?:FATAL|ERROR|WARN|DEBUG|VERBOSE|LOG)\b/.test(r),b=a??(O?m:g.length>0?"error":e),d=[r,...i];if(!a&&(0,tap_nest_logger_1.isLoggerEcho)(d.join(`
3
+ `),c)){n={severity:b,at:c};continue}(0,emit_1.lensLog)(b,a?r.trim():r,{...g.length>0?{stack:d.join(`
4
+ `)}:{},...i.length>0&&g.length<i.length?{text:d.join(`
5
+ `)}:{},...a?{continues:!0}:{},stream:l}),n={severity:b,at:c}}return n}f(emitChunk,"emitChunk"),u(emitChunk,"emitChunk");function tapStdout(){if(process.env.LENSMCP_LOGS==="0"||process.env.APP_RUNNER!=="1")return;const t=[[process.stdout,"info","stdout"],[process.stderr,"error","stderr"]];for(const[e,p,c]of t){if(e.write.__lensmcp)continue;const l=e.write.bind(e);let o;const s=u(function(n,...r){try{if(!(0,emit_1.isLensWriting)()){const i=typeof n=="string"?n:Buffer.isBuffer(n)?n.toString("utf8"):"";i&&i.indexOf("[lensmcp]")===-1&&(o=emitChunk(i,p,o,Date.now(),c))}}catch{}return l(n,...r)},"wrapped");s.__lensmcp=!0,e.write=s}}f(tapStdout,"tapStdout"),u(tapStdout,"tapStdout");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/node-instrumentation",
3
- "version": "1.24.2",
3
+ "version": "1.24.4",
4
4
  "main": "./index.js",
5
5
  "types": "./index.d.ts",
6
6
  "exports": {
@@ -15,9 +15,9 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@lensmcp/core": "1.24.2",
19
- "@lensmcp/nest-instrumentation": "1.24.2",
20
- "@lensmcp/protocol-types": "1.24.2",
18
+ "@lensmcp/core": "1.24.4",
19
+ "@lensmcp/nest-instrumentation": "1.24.4",
20
+ "@lensmcp/protocol-types": "1.24.4",
21
21
  "tslib": "^2.3.0"
22
22
  },
23
23
  "optionalDependencies": {