@lensmcp/bridge 1.18.7 → 1.18.8

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/lib/env-sink.js CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";var y=Object.defineProperty;var f=(e,n)=>y(e,"name",{value:n,configurable:!0});var b=Object.defineProperty,l=f((e,n)=>b(e,"name",{value:n,configurable:!0}),"f"),_=Object.defineProperty,c=l((e,n)=>_(e,"name",{value:n,configurable:!0}),"i");import{connect as M}from"node:net";import{createSocket as C}from"node:dgram";import{appendFileSync as g,renameSync as d,statSync as A,unlinkSync as L}from"node:fs";const P=(()=>{const e=Number(process.env.LENSMCP_EVENT_MAX_BYTES);return Number.isFinite(e)&&e>0?e:50*1024*1024})(),h=(()=>{const e=Number(process.env.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(e)&&e>=1&&e<=20?Math.floor(e):5})(),w=1024*1024;let p=0;function E(e,n){if(p+=n,!(p<w)){p=0;try{if(A(e).size<=P)return}catch{return}try{L(`${e}.${h}`)}catch{}for(let t=h-1;t>=1;t--)try{d(`${e}.${t}`,`${e}.${t+1}`)}catch{}try{d(e,`${e}.1`)}catch{}}}f(E,"d"),l(E,"C"),c(E,"rotateIfLarge");const S=(()=>{const e=process.env.LENSMCP_EVENT_MAX_EPS;if(e==="off")return 1/0;const n=Number(e);return e!==void 0&&e!==""&&Number.isFinite(n)?n<=0?1/0:n:5})(),m=Math.max(30,S===1/0?0:S*4),a=new Map;function v(e){if(S===1/0)return 0;const n=Date.now();let t=a.get(e);if(!t){if(a.size>=2048){for(const[r,s]of a)n-s.lastSeenAt>6e4&&a.delete(r);a.size>=2048&&a.clear()}t={tokens:m,lastRefillAt:n,suppressed:0,lastSeenAt:n},a.set(e,t)}if(t.lastSeenAt=n,t.tokens=Math.min(m,t.tokens+(n-t.lastRefillAt)/1e3*S),t.lastRefillAt=n,t.tokens>=1){t.tokens-=1;const r=t.suppressed;return t.suppressed=0,r}return t.suppressed+=1,-1}f(v,"v"),l(v,"T"),c(v,"floodAdmit");let o;export function resolveEnvSink(){if(o!==void 0)return o;const e=process.env.LENSMCP_EVENT_FILE;if(e)return o=c(r=>{try{const s=v(r.fingerprint);if(s<0)return;const u=JSON.stringify(s>0?{...r,raw:{...r.raw??{},floodSuppressed:s}}:r)+`
2
- `;E(e,u.length),g(e,u)}catch{}},"cachedEnvSink"),o;const n=process.env.LENSMCP_UDS;if(n)return o=udsEnvSink(n),o;const t=process.env.LENSMCP_IPC_SOCKET;if(t){const[r,s]=t.split(":"),u=Number(s);if(r&&Number.isFinite(u)){const i=C("udp4");return i.unref(),o=c(N=>{try{const k=Buffer.from(JSON.stringify(N));i.send(k,u,r,()=>{})}catch{}},"cachedEnvSink"),o}}return o=null,null}f(resolveEnvSink,"resolveEnvSink"),l(resolveEnvSink,"resolveEnvSink"),c(resolveEnvSink,"resolveEnvSink");export function resetEnvSinkCache(){o=void 0}f(resetEnvSinkCache,"resetEnvSinkCache"),l(resetEnvSinkCache,"resetEnvSinkCache"),c(resetEnvSinkCache,"resetEnvSinkCache");export function udsEnvSink(e){const n=[];let t=null,r=!1;const s=c(()=>{if(!(!t||!t.writable))for(;n.length>0;)t.write(n.shift())},"flush"),u=c(()=>{if(r||t)return;r=!0;const i=M(e);i.on("connect",()=>{r=!1,t=i,s()}),i.on("drain",s),i.on("error",()=>{r=!1,t=null}),i.on("close",()=>{t=null}),i.unref()},"open");return u(),i=>{for(n.push(JSON.stringify(i)+`
3
- `);n.length>1e4;)n.shift();if(t&&t.writable){s();return}if(t){try{t.destroy()}catch{}t=null}u()}}f(udsEnvSink,"udsEnvSink"),l(udsEnvSink,"udsEnvSink"),c(udsEnvSink,"udsEnvSink");
1
+ "use strict";var y=Object.defineProperty;var f=(n,t)=>y(n,"name",{value:t,configurable:!0});var k=Object.defineProperty,c=f((n,t)=>k(n,"name",{value:t,configurable:!0}),"i");import{connect as _}from"node:net";import{createSocket as M}from"node:dgram";import{appendFileSync as b,renameSync as S,statSync as A,unlinkSync as C}from"node:fs";const g=(()=>{const n=Number(process.env.LENSMCP_EVENT_MAX_BYTES);return Number.isFinite(n)&&n>0?n:50*1024*1024})(),E=(()=>{const n=Number(process.env.LENSMCP_EVENT_MAX_FILES);return Number.isFinite(n)&&n>=1&&n<=20?Math.floor(n):5})(),L=1024*1024;let p=0;function d(n,t){if(p+=t,!(p<L)){p=0;try{if(A(n).size<=g)return}catch{return}try{C(`${n}.${E}`)}catch{}for(let e=E-1;e>=1;e--)try{S(`${n}.${e}`,`${n}.${e+1}`)}catch{}try{S(n,`${n}.1`)}catch{}}}f(d,"C"),c(d,"rotateIfLarge");const a=(()=>{const n=process.env.LENSMCP_EVENT_MAX_EPS;if(n==="off")return 1/0;const t=Number(n);return n!==void 0&&n!==""&&Number.isFinite(t)?t<=0?1/0:t:5})(),h=Math.max(30,a===1/0?0:a*4),l=new Map;function v(n){if(a===1/0)return 0;const t=Date.now();let e=l.get(n);if(!e){if(l.size>=2048){for(const[r,s]of l)t-s.lastSeenAt>6e4&&l.delete(r);l.size>=2048&&l.clear()}e={tokens:h,lastRefillAt:t,suppressed:0,lastSeenAt:t},l.set(n,e)}if(e.lastSeenAt=t,e.tokens=Math.min(h,e.tokens+(t-e.lastRefillAt)/1e3*a),e.lastRefillAt=t,e.tokens>=1){e.tokens-=1;const r=e.suppressed;return e.suppressed=0,r}return e.suppressed+=1,-1}f(v,"T"),c(v,"floodAdmit");let i;export function resolveEnvSink(){if(i!==void 0)return i;const n=process.env.LENSMCP_EVENT_FILE;if(n)return i=c(r=>{try{const s=v(r.fingerprint);if(s<0)return;const u=JSON.stringify(s>0?{...r,raw:{...r.raw??{},floodSuppressed:s}}:r)+`
2
+ `;d(n,u.length),b(n,u)}catch{}},"cachedEnvSink"),i;const t=process.env.LENSMCP_UDS;if(t)return i=udsEnvSink(t),i;const e=process.env.LENSMCP_IPC_SOCKET;if(e){const[r,s]=e.split(":"),u=Number(s);if(r&&Number.isFinite(u)){const o=M("udp4");return o.unref(),i=c(N=>{try{const m=Buffer.from(JSON.stringify(N));o.send(m,u,r,()=>{})}catch{}},"cachedEnvSink"),i}}return i=null,null}f(resolveEnvSink,"resolveEnvSink"),c(resolveEnvSink,"resolveEnvSink");export function resetEnvSinkCache(){i=void 0}f(resetEnvSinkCache,"resetEnvSinkCache"),c(resetEnvSinkCache,"resetEnvSinkCache");export function udsEnvSink(n){const t=[];let e=null,r=!1;const s=c(()=>{if(!(!e||!e.writable))for(;t.length>0;)e.write(t.shift())},"flush"),u=c(()=>{if(r||e)return;r=!0;const o=_(n);o.on("connect",()=>{r=!1,e=o,s()}),o.on("drain",s),o.on("error",()=>{r=!1,e=null}),o.on("close",()=>{e=null}),o.unref()},"open");return u(),o=>{for(t.push(JSON.stringify(o)+`
3
+ `);t.length>1e4;)t.shift();if(e&&e.writable){s();return}if(e){try{e.destroy()}catch{}e=null}u()}}f(udsEnvSink,"udsEnvSink"),c(udsEnvSink,"udsEnvSink");
@@ -24,4 +24,6 @@ import type { ClientEnvelope } from './types.js';
24
24
  * (`./redact.js`) — enrichment is exactly what creates the leak risk, so the
25
25
  * two land together. See that module for what is and is not scrubbed.
26
26
  */
27
- export declare function envelopeToEvent(env: ClientEnvelope, sessionId?: string): BaseEvent;
27
+ export declare function envelopeToEvent(env: Exclude<ClientEnvelope, {
28
+ kind: 'batch';
29
+ }>, sessionId?: string): BaseEvent;
@@ -1,3 +1,3 @@
1
- "use strict";var h=Object.defineProperty;var c=(t,e)=>h(t,"name",{value:e,configurable:!0});var x=Object.defineProperty,l=c((t,e)=>x(t,"name",{value:e,configurable:!0}),"c"),U=Object.defineProperty,d=l((t,e)=>U(t,"name",{value:e,configurable:!0}),"s");import{fingerprint as o,ulid as a}from"@lensmcp/core";import{redactDeep as f,redactText as I,redactUrl as m,safeText as u,safeTitle as g}from"./redact.js";const b="pending";export function envelopeToEvent(t,e=b){const s=t.tabId?{tabId:t.tabId}:{};switch(t.kind){case"error":{const r=!t.stack&&!t.source&&(!t.message||t.message==="Script error."),i=t.name&&t.name!=="Error"?`${t.name}: `:"",n=r?"Uncaught cross-origin script error (no detail available \u2014 add crossorigin to the script tag)":t.message?`${i}${t.message}`:`Uncaught ${t.name??"error"}`;return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:e,...s},fingerprint:o({kind:"runtime",identity:`error:${v(t.stack)}`,file:t.source,detail:t.message??t.name}),title:g(n),message:u(t.stack??t.message),location:t.source?{file:m(t.source),line:t.lineno,column:t.colno}:void 0,raw:{...t,...t.message?{message:I(t.message)}:{},...t.stack?{stack:u(t.stack)}:{},...t.source?{source:m(t.source)}:{}}}}case"resource-error":{const r=t.url?m(t.url):void 0;return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:e,...s},fingerprint:o({kind:"runtime",identity:`resource-error:${t.tagName}:${p(t.url??"")}`}),title:g(`Failed to load <${t.tagName}>${r?` ${r}`:""}`),...r?{relatedUrls:[r]}:{},raw:{...t,...r?{url:r}:{}}}}case"unhandledrejection":{const r=t.name&&t.name!=="Error"?`${t.name}: `:"",i=t.reason.split(`
2
- `)[0]??t.reason;return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:e,...s},fingerprint:o({kind:"runtime",identity:`unhandledrejection:${t.reason.slice(0,80)}`}),title:g(`Unhandled promise rejection: ${r}${i}`),message:u(t.stack??t.reason),raw:{...t,reason:I(t.reason),...t.stack?{stack:u(t.stack)}:{}}}}case"console":{const r=t.level==="error"?"error":t.level==="warn"?"warning":"info",i=f(t.args),n=i.map($).join(" ");return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:r,context:{sessionId:e,...s},fingerprint:o({kind:"runtime",identity:`console:${t.level}:${n.slice(0,80)}`}),title:`console.${t.level}`,message:u(n),raw:{...t,args:i}}}case"fetch":{const r=t.error!==void 0||t.status!==void 0&&t.status>=400,i=m(t.url),n=t.status!==void 0?` \u2192 ${t.status}${t.statusText?` ${t.statusText}`:""}`:"";return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"network",severity:r?"error":"info",context:{sessionId:e,...s},fingerprint:o({kind:"network",identity:`${t.method}:${p(t.url)}:${t.status??"err"}`}),title:g(`${t.method} ${i}${n}`),message:u(t.error),relatedUrls:[i],raw:{...t,url:i}}}case"route":return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:e,url:t.url,...s},fingerprint:o({kind:"runtime",identity:`route:${t.url}`}),title:`Route \u2192 ${t.url}`,raw:t};case"ready":return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:e,url:t.url,...s},fingerprint:o({kind:"runtime",identity:"client-ready"}),title:"Client runtime ready",message:t.userAgent,raw:t};case"gone":return{id:a(),sessionId:e,timestamp:t.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:e,...s},fingerprint:o({kind:"runtime",identity:"client-gone"}),title:"Client runtime gone",raw:t};case"publish":{const r=y(t.category,t.raw),i=r&&r.status!==void 0&&r.status>=400?"error":t.severity??"info",n=d(w=>r&&r.url!==r.redactedUrl?w.split(r.url).join(r.redactedUrl):w,"scrub"),k=n(t.title);return{id:a(),sessionId:e,timestamp:t.at,source:t.source,category:t.category,severity:i,context:{sessionId:e,...s,...t.context??{}},fingerprint:t.fingerprint?n(t.fingerprint):o({kind:"publish",identity:k}),title:g(k),message:u(t.message),...r?{relatedUrls:[r.redactedUrl]}:{},raw:r?{...f(t.raw),url:r.redactedUrl}:f(t.raw)}}}}c(envelopeToEvent,"envelopeToEvent"),l(envelopeToEvent,"envelopeToEvent"),d(envelopeToEvent,"envelopeToEvent");function y(t,e){if(t!=="network"||!e||typeof e!="object")return;const s=e;if(!(typeof s.url!="string"||s.url.length===0))return{url:s.url,redactedUrl:m(s.url),...typeof s.status=="number"?{status:s.status}:{}}}c(y,"k"),l(y,"w"),d(y,"networkDetails");function v(t){if(!t)return"unknown";const e=t.split(`
3
- `).slice(0,2);for(const s of e){const r=s.match(/at\s+(\S+)/);if(r&&r[1])return r[1]}return"unknown"}c(v,"v"),l(v,"h"),d(v,"normaliseStackTopFrame");function p(t){try{return`${new URL(t,"http://x").pathname}`}catch{return t}}c(p,"p"),l(p,"y"),d(p,"normaliseUrl");function $(t){if(typeof t=="string")return t;try{return JSON.stringify(t)}catch{return String(t)}}c($,"w"),l($,"x"),d($,"stringify");
1
+ "use strict";var I=Object.defineProperty;var c=(e,n)=>I(e,"name",{value:n,configurable:!0});var h=Object.defineProperty,l=c((e,n)=>h(e,"name",{value:n,configurable:!0}),"s");import{fingerprint as o,ulid as a}from"@lensmcp/core";import{redactDeep as g,redactText as $,redactUrl as d,safeText as u,safeTitle as m}from"./redact.js";const x="pending";export function envelopeToEvent(e,n=x){const s=e.tabId?{tabId:e.tabId}:{};switch(e.kind){case"error":{const r=!e.stack&&!e.source&&(!e.message||e.message==="Script error."),i=e.name&&e.name!=="Error"?`${e.name}: `:"",t=r?"Uncaught cross-origin script error (no detail available \u2014 add crossorigin to the script tag)":e.message?`${i}${e.message}`:`Uncaught ${e.name??"error"}`;return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:n,...s},fingerprint:o({kind:"runtime",identity:`error:${v(e.stack)}`,file:e.source,detail:e.message??e.name}),title:m(t),message:u(e.stack??e.message),location:e.source?{file:d(e.source),line:e.lineno,column:e.colno}:void 0,raw:{...e,...e.message?{message:$(e.message)}:{},...e.stack?{stack:u(e.stack)}:{},...e.source?{source:d(e.source)}:{}}}}case"resource-error":{const r=e.url?d(e.url):void 0;return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:n,...s},fingerprint:o({kind:"runtime",identity:`resource-error:${e.tagName}:${p(e.url??"")}`}),title:m(`Failed to load <${e.tagName}>${r?` ${r}`:""}`),...r?{relatedUrls:[r]}:{},raw:{...e,...r?{url:r}:{}}}}case"unhandledrejection":{const r=e.name&&e.name!=="Error"?`${e.name}: `:"",i=e.reason.split(`
2
+ `)[0]??e.reason;return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"error",context:{sessionId:n,...s},fingerprint:o({kind:"runtime",identity:`unhandledrejection:${e.reason.slice(0,80)}`}),title:m(`Unhandled promise rejection: ${r}${i}`),message:u(e.stack??e.reason),raw:{...e,reason:$(e.reason),...e.stack?{stack:u(e.stack)}:{}}}}case"console":{const r=e.level==="error"?"error":e.level==="warn"?"warning":"info",i=g(e.args),t=i.map(w).join(" ");return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:r,context:{sessionId:n,...s},fingerprint:o({kind:"runtime",identity:`console:${e.level}:${t.slice(0,80)}`}),title:`console.${e.level}`,message:u(t),raw:{...e,args:i}}}case"fetch":{const r=e.error!==void 0||e.status!==void 0&&e.status>=400,i=d(e.url),t=e.status!==void 0?` \u2192 ${e.status}${e.statusText?` ${e.statusText}`:""}`:"";return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"network",severity:r?"error":"info",context:{sessionId:n,...s},fingerprint:o({kind:"network",identity:`${e.method}:${p(e.url)}:${e.status??"err"}`}),title:m(`${e.method} ${i}${t}`),message:u(e.error),relatedUrls:[i],raw:{...e,url:i}}}case"route":return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:n,url:e.url,...s},fingerprint:o({kind:"runtime",identity:`route:${e.url}`}),title:`Route \u2192 ${e.url}`,raw:e};case"ready":return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:n,url:e.url,...s},fingerprint:o({kind:"runtime",identity:"client-ready"}),title:"Client runtime ready",message:e.userAgent,raw:e};case"gone":return{id:a(),sessionId:n,timestamp:e.at,source:"client-runtime",category:"runtime",severity:"info",context:{sessionId:n,...s},fingerprint:o({kind:"runtime",identity:"client-gone"}),title:"Client runtime gone",raw:e};case"publish":{const r=k(e.category,e.raw),i=r&&r.status!==void 0&&r.status>=400?"error":e.severity??"info",t=l(y=>r&&r.url!==r.redactedUrl?y.split(r.url).join(r.redactedUrl):y,"scrub"),f=t(e.title);return{id:a(),sessionId:n,timestamp:e.at,source:e.source,category:e.category,severity:i,context:{sessionId:n,...s,...e.context??{}},fingerprint:e.fingerprint?t(e.fingerprint):o({kind:"publish",identity:f}),title:m(f),message:u(e.message),...r?{relatedUrls:[r.redactedUrl]}:{},raw:r?{...g(e.raw),url:r.redactedUrl}:g(e.raw)}}}}c(envelopeToEvent,"envelopeToEvent"),l(envelopeToEvent,"envelopeToEvent");function k(e,n){if(e!=="network"||!n||typeof n!="object")return;const s=n;if(!(typeof s.url!="string"||s.url.length===0))return{url:s.url,redactedUrl:d(s.url),...typeof s.status=="number"?{status:s.status}:{}}}c(k,"w"),l(k,"networkDetails");function v(e){if(!e)return"unknown";const n=e.split(`
3
+ `).slice(0,2);for(const s of n){const r=s.match(/at\s+(\S+)/);if(r&&r[1])return r[1]}return"unknown"}c(v,"h"),l(v,"normaliseStackTopFrame");function p(e){try{return`${new URL(e,"http://x").pathname}`}catch{return e}}c(p,"y"),l(p,"normaliseUrl");function w(e){if(typeof e=="string")return e;try{return JSON.stringify(e)}catch{return String(e)}}c(w,"x"),l(w,"stringify");
package/lib/server.js CHANGED
@@ -1 +1 @@
1
- "use strict";var v=Object.defineProperty;var i=(e,r)=>v(e,"name",{value:r,configurable:!0});var b=Object.defineProperty,c=i((e,r)=>b(e,"name",{value:r,configurable:!0}),"i"),m=Object.defineProperty,t=c((e,r)=>m(e,"name",{value:r,configurable:!0}),"o");import{createServer as g}from"node:net";import{WebSocketServer as S}from"ws";import{DEFAULT_WS_HOST as h,DEFAULT_WS_PORT as y}from"./constants.js";import{resolveEnvSink as P}from"./env-sink.js";import{envelopeToEvent as k}from"./event-mappers.js";export function makePublisher(e){let r;return o=>{if(e.bus){e.bus.publish(o);return}if(e.sink){e.sink(o);return}if(r===void 0&&(r=P()),r){r(o);return}(o.severity==="error"||o.severity==="fatal")&&console.debug(`[lensmcp-bridge] ${o.severity}: ${o.title}`)}}i(makePublisher,"makePublisher"),c(makePublisher,"makePublisher"),t(makePublisher,"makePublisher");export function handleClientEnvelope(e,r,o){let n;try{n=JSON.parse(e)}catch{return}!n||typeof n!="object"||!("kind"in n)||r(k(n,o))}i(handleClientEnvelope,"handleClientEnvelope"),c(handleClientEnvelope,"handleClientEnvelope"),t(handleClientEnvelope,"handleClientEnvelope");export function readTabId(e){try{const r=JSON.parse(e);return typeof r?.tabId=="string"&&r.tabId?r.tabId:void 0}catch{return}}i(readTabId,"readTabId"),c(readTabId,"readTabId"),t(readTabId,"readTabId");export async function createBridgeServer(e={}){const r=e.host??h,o=e.port??y,n=o===0?await findFreePort():o,f=makePublisher(e),s=new S({host:r,port:n});return s.on("connection",a=>{let l;a.on("message",u=>{const d=u.toString();l??=readTabId(d),handleClientEnvelope(d,f,e.sessionId)}),a.on("close",()=>{l&&handleClientEnvelope(JSON.stringify({kind:"gone",at:Date.now(),tabId:l}),f,e.sessionId)})}),await new Promise((a,l)=>{const u=t(p=>{s.off("listening",d),l(p)},"onError"),d=t(()=>{s.off("error",u),a()},"onListening");s.once("error",u),s.once("listening",d)}),{port:n,host:r,close:t(()=>new Promise(a=>{s.close(()=>a())}),"close")}}i(createBridgeServer,"createBridgeServer"),c(createBridgeServer,"createBridgeServer"),t(createBridgeServer,"createBridgeServer");export function findFreePort(){return new Promise((e,r)=>{const o=g();o.unref(),o.on("error",r),o.listen(0,()=>{const n=o.address();if(!n){o.close(),r(new Error("Could not allocate free port"));return}const f=n.port;o.close(()=>e(f))})})}i(findFreePort,"findFreePort"),c(findFreePort,"findFreePort"),t(findFreePort,"findFreePort");
1
+ "use strict";var b=Object.defineProperty;var s=(r,e)=>b(r,"name",{value:e,configurable:!0});var v=Object.defineProperty,i=s((r,e)=>v(r,"name",{value:e,configurable:!0}),"i");import{createServer as m}from"node:net";import{WebSocketServer as g}from"ws";import{DEFAULT_WS_HOST as y,DEFAULT_WS_PORT as S}from"./constants.js";import{resolveEnvSink as h}from"./env-sink.js";import{envelopeToEvent as u}from"./event-mappers.js";export function makePublisher(r){let e;return t=>{if(r.bus){r.bus.publish(t);return}if(r.sink){r.sink(t);return}if(e===void 0&&(e=h()),e){e(t);return}(t.severity==="error"||t.severity==="fatal")&&console.debug(`[lensmcp-bridge] ${t.severity}: ${t.title}`)}}s(makePublisher,"makePublisher"),i(makePublisher,"makePublisher");export function handleClientEnvelope(r,e,t){let o;try{o=JSON.parse(r)}catch{return}if(!(!o||typeof o!="object"||!("kind"in o))){if(o.kind==="batch"){if(!Array.isArray(o.events))return;for(const n of o.events)!n||typeof n!="object"||!("kind"in n)||n.kind!=="batch"&&e(u(n,t));return}e(u(o,t))}}s(handleClientEnvelope,"handleClientEnvelope"),i(handleClientEnvelope,"handleClientEnvelope");export function readTabId(r){try{const e=JSON.parse(r);return typeof e?.tabId=="string"&&e.tabId?e.tabId:void 0}catch{return}}s(readTabId,"readTabId"),i(readTabId,"readTabId");export async function createBridgeServer(r={}){const e=r.host??y,t=r.port??S,o=t===0?await findFreePort():t,n=makePublisher(r),a=new g({host:e,port:o});return a.on("connection",c=>{let f;c.on("message",d=>{const l=d.toString();f??=readTabId(l),handleClientEnvelope(l,n,r.sessionId)}),c.on("close",()=>{f&&handleClientEnvelope(JSON.stringify({kind:"gone",at:Date.now(),tabId:f}),n,r.sessionId)})}),await new Promise((c,f)=>{const d=i(p=>{a.off("listening",l),f(p)},"onError"),l=i(()=>{a.off("error",d),c()},"onListening");a.once("error",d),a.once("listening",l)}),{port:o,host:e,close:i(()=>new Promise(c=>{a.close(()=>c())}),"close")}}s(createBridgeServer,"createBridgeServer"),i(createBridgeServer,"createBridgeServer");export function findFreePort(){return new Promise((r,e)=>{const t=m();t.unref(),t.on("error",e),t.listen(0,()=>{const o=t.address();if(!o){t.close(),e(new Error("Could not allocate free port"));return}const n=o.port;t.close(()=>r(n))})})}s(findFreePort,"findFreePort"),i(findFreePort,"findFreePort");
package/lib/types.d.ts CHANGED
@@ -108,6 +108,19 @@ export type ClientEnvelope = (
108
108
  fingerprint?: string;
109
109
  context?: Record<string, unknown>;
110
110
  raw?: unknown;
111
+ }
112
+ /**
113
+ * A COALESCED frame: every envelope the page produced within one flush
114
+ * window (a macrotask), in capture order. The client runtime batches so a
115
+ * render storm costs ONE stringify + ONE socket frame scheduled OFF the
116
+ * interaction task instead of hundreds inline in it — each inner event
117
+ * still carries its own capture-time `at` (and `tabId`), so the recorded
118
+ * timeline is unchanged; only where the transport work happens moves.
119
+ */
120
+ | {
121
+ kind: 'batch';
122
+ at: number;
123
+ events: ClientEnvelope[];
111
124
  }) & {
112
125
  /** Per-tab identity stamped by the client runtime (sessionStorage is per-tab) — keys `browser://tabs`. */
113
126
  tabId?: string;
package/main.js CHANGED
@@ -1 +1 @@
1
- "use strict";var d=Object.defineProperty;var n=(s,e)=>d(s,"name",{value:e,configurable:!0});var v=Object.defineProperty,a=n((s,e)=>v(s,"name",{value:e,configurable:!0}),"n"),g=Object.defineProperty,l=a((s,e)=>g(s,"name",{value:e,configurable:!0}),"n");import{DEFAULT_WS_HOST as u,DEFAULT_WS_PORT as _,ENV_SESSION_ID as b,ENV_WS_HOST as T,ENV_WS_PORT as p}from"./lib/constants.js";import{createBridgeServer as f}from"./lib/server.js";async function t(){const s=process.env[T]??u,e=process.env[p],o=e!==void 0&&e!==""?Number(e):_;(!Number.isFinite(o)||o<0)&&(console.error(`[lensmcp-bridge] invalid ${p}=${e}`),process.exit(2));const m=process.env[b];let r;try{r=await f({host:s,port:o,sessionId:m})}catch(S){console.error(`[lensmcp-bridge] failed to listen on ws://${s}:${o} \u2014 ${S.message}`),process.exit(1)}console.log(`[lensmcp-bridge] listening on ws://${r.host}:${r.port}`);let c=!1;const i=l(()=>{c||(c=!0,r.close().then(()=>process.exit(0)))},"shutdown");process.on("SIGINT",i),process.on("SIGTERM",i)}n(t,"l"),a(t,"g"),l(t,"main"),t();
1
+ "use strict";var S=Object.defineProperty;var n=(s,e)=>S(s,"name",{value:e,configurable:!0});var d=Object.defineProperty,i=n((s,e)=>d(s,"name",{value:e,configurable:!0}),"n");import{DEFAULT_WS_HOST as _,DEFAULT_WS_PORT as g,ENV_SESSION_ID as v,ENV_WS_HOST as u,ENV_WS_PORT as a}from"./lib/constants.js";import{createBridgeServer as T}from"./lib/server.js";async function l(){const s=process.env[u]??_,e=process.env[a],o=e!==void 0&&e!==""?Number(e):g;(!Number.isFinite(o)||o<0)&&(console.error(`[lensmcp-bridge] invalid ${a}=${e}`),process.exit(2));const p=process.env[v];let r;try{r=await T({host:s,port:o,sessionId:p})}catch(m){console.error(`[lensmcp-bridge] failed to listen on ws://${s}:${o} \u2014 ${m.message}`),process.exit(1)}console.log(`[lensmcp-bridge] listening on ws://${r.host}:${r.port}`);let t=!1;const c=i(()=>{t||(t=!0,r.close().then(()=>process.exit(0)))},"shutdown");process.on("SIGINT",c),process.on("SIGTERM",c)}n(l,"g"),i(l,"main"),l();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensmcp/bridge",
3
- "version": "1.18.7",
3
+ "version": "1.18.8",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -19,8 +19,8 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "@lensmcp/core": "1.18.7",
23
- "@lensmcp/protocol-types": "1.18.7",
22
+ "@lensmcp/core": "1.18.8",
23
+ "@lensmcp/protocol-types": "1.18.8",
24
24
  "tslib": "^2.3.0",
25
25
  "ws": "^8.21.0"
26
26
  },