@lensmcp/client-runtime 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/auto.d.ts +0 -1
- package/auto.js +1 -16
- package/index.d.ts +0 -1
- package/index.js +1 -2
- package/lib/auto.d.ts +0 -1
- package/lib/auto.js +1 -72
- package/lib/install.d.ts +0 -1
- package/lib/install.js +1 -157
- package/package.json +1 -1
- package/auto.d.ts.map +0 -1
- package/index.d.ts.map +0 -1
- package/lib/auto.d.ts.map +0 -1
- package/lib/install.d.ts.map +0 -1
package/auto.d.ts
CHANGED
package/auto.js
CHANGED
|
@@ -1,16 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Side-effecting no-build entry.
|
|
3
|
-
*
|
|
4
|
-
* import '@lensmcp/client-runtime/auto';
|
|
5
|
-
*
|
|
6
|
-
* Installs the browser capture layer immediately, resolving the bridge WS
|
|
7
|
-
* endpoint at runtime (global → `<meta>` → `ws://<host>:5747`). Pair it with a
|
|
8
|
-
* standalone bridge (`lensmcp bridge`) for hosts with no LensMCP build plugin:
|
|
9
|
-
* webpack, Next.js, or no bundler at all.
|
|
10
|
-
*
|
|
11
|
-
* For explicit control over the URL or reconnect behaviour, import
|
|
12
|
-
* `{ installLensmcp }` and call it yourself instead of importing this entry.
|
|
13
|
-
*/
|
|
14
|
-
import { installLensmcp } from './lib/auto.js';
|
|
15
|
-
installLensmcp();
|
|
16
|
-
export { installLensmcp, resolveLensmcpWsUrl } from './lib/auto.js';
|
|
1
|
+
"use strict";import{installLensmcp as s}from"./lib/auto.js";s();export{installLensmcp,resolveLensmcpWsUrl}from"./lib/auto.js";
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { installLensmcp, resolveLensmcpWsUrl, } from './lib/auto.js';
|
|
1
|
+
"use strict";export{installClientRuntime}from"./lib/install.js";export{installLensmcp,resolveLensmcpWsUrl}from"./lib/auto.js";
|
package/lib/auto.d.ts
CHANGED
package/lib/auto.js
CHANGED
|
@@ -1,72 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Runtime WS-endpoint resolution for the no-build path.
|
|
3
|
-
*
|
|
4
|
-
* The Vite plugin bakes the bridge WS port into the injected runtime at
|
|
5
|
-
* build/serve time. Without a bundler there's nothing to bake it in, so the
|
|
6
|
-
* endpoint is resolved at runtime from (in order):
|
|
7
|
-
*
|
|
8
|
-
* 1. an explicit `wsUrl` argument,
|
|
9
|
-
* 2. `globalThis.__LENSMCP_WS_URL__` (a full `ws://…` URL),
|
|
10
|
-
* 3. `<meta name="lensmcp-ws" content="ws://…">`,
|
|
11
|
-
* 4. `ws://<host>:<port>` assembled from
|
|
12
|
-
* `__LENSMCP_WS_HOST__` / `<meta name="lensmcp-ws-host">` / `location.hostname`
|
|
13
|
-
* and `__LENSMCP_WS_PORT__` / `<meta name="lensmcp-ws-port">` / the default.
|
|
14
|
-
*
|
|
15
|
-
* This is what lets `import '@lensmcp/client-runtime/auto'` work in any host
|
|
16
|
-
* (webpack, Next.js, plain `<script type=module>`, no build at all).
|
|
17
|
-
*/
|
|
18
|
-
import { installClientRuntime } from './install.js';
|
|
19
|
-
// Must match `@lensmcp/bridge`'s DEFAULT_WS_PORT. The bridge is a Node-only
|
|
20
|
-
// package (it imports `ws`/`node:net`) and can't be pulled into a browser
|
|
21
|
-
// bundle, so the literal is duplicated here on purpose — keep them in sync.
|
|
22
|
-
const DEFAULT_WS_PORT = 5747;
|
|
23
|
-
const DEFAULT_WS_HOST = '127.0.0.1';
|
|
24
|
-
/** Resolve the bridge WebSocket URL from the runtime environment. */
|
|
25
|
-
export function resolveLensmcpWsUrl(override) {
|
|
26
|
-
if (override)
|
|
27
|
-
return override;
|
|
28
|
-
const g = globalThis;
|
|
29
|
-
const globalUrl = g['__LENSMCP_WS_URL__'];
|
|
30
|
-
if (typeof globalUrl === 'string' && globalUrl.length > 0)
|
|
31
|
-
return globalUrl;
|
|
32
|
-
const metaUrl = readMeta('lensmcp-ws');
|
|
33
|
-
if (metaUrl)
|
|
34
|
-
return metaUrl;
|
|
35
|
-
const globalPort = g['__LENSMCP_WS_PORT__'];
|
|
36
|
-
const port = typeof globalPort === 'number' || typeof globalPort === 'string'
|
|
37
|
-
? String(globalPort)
|
|
38
|
-
: readMeta('lensmcp-ws-port') ?? String(DEFAULT_WS_PORT);
|
|
39
|
-
const globalHost = g['__LENSMCP_WS_HOST__'];
|
|
40
|
-
const host = typeof globalHost === 'string' && globalHost.length > 0
|
|
41
|
-
? globalHost
|
|
42
|
-
: readMeta('lensmcp-ws-host') ??
|
|
43
|
-
(typeof location !== 'undefined' && location.hostname ? location.hostname : DEFAULT_WS_HOST);
|
|
44
|
-
return `ws://${host}:${port}`;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Resolve the bridge WS endpoint and install the capture layer. The no-build
|
|
48
|
-
* seam: any app can call this (or `import '@lensmcp/client-runtime/auto'`)
|
|
49
|
-
* without a bundler plugin. No-op outside a browser (SSR-safe), and
|
|
50
|
-
* idempotent (the underlying runtime guards against double-install).
|
|
51
|
-
*/
|
|
52
|
-
export function installLensmcp(opts = {}) {
|
|
53
|
-
if (typeof window === 'undefined')
|
|
54
|
-
return;
|
|
55
|
-
const options = { wsUrl: resolveLensmcpWsUrl(opts.wsUrl) };
|
|
56
|
-
if (opts.reconnectIntervalMs !== undefined) {
|
|
57
|
-
options.reconnectIntervalMs = opts.reconnectIntervalMs;
|
|
58
|
-
}
|
|
59
|
-
installClientRuntime(options);
|
|
60
|
-
}
|
|
61
|
-
function readMeta(name) {
|
|
62
|
-
if (typeof document === 'undefined')
|
|
63
|
-
return undefined;
|
|
64
|
-
try {
|
|
65
|
-
const el = document.querySelector(`meta[name="${name}"]`);
|
|
66
|
-
const content = el?.getAttribute('content');
|
|
67
|
-
return content && content.length > 0 ? content : undefined;
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
"use strict";var u=Object.defineProperty;var n=(e,t)=>u(e,"name",{value:t,configurable:!0});var f=Object.defineProperty,i=n((e,t)=>f(e,"name",{value:t,configurable:!0}),"o");import{installClientRuntime as p}from"./install.js";const _=5747,m="127.0.0.1";export function resolveLensmcpWsUrl(e){if(e)return e;const t=globalThis,o=t.__LENSMCP_WS_URL__;if(typeof o=="string"&&o.length>0)return o;const l=r("lensmcp-ws");if(l)return l;const s=t.__LENSMCP_WS_PORT__,a=typeof s=="number"||typeof s=="string"?String(s):r("lensmcp-ws-port")??String(_),c=t.__LENSMCP_WS_HOST__;return`ws://${typeof c=="string"&&c.length>0?c:r("lensmcp-ws-host")??(typeof location<"u"&&location.hostname?location.hostname:m)}:${a}`}n(resolveLensmcpWsUrl,"resolveLensmcpWsUrl"),i(resolveLensmcpWsUrl,"resolveLensmcpWsUrl");export function installLensmcp(e={}){if(typeof window>"u")return;const t={wsUrl:resolveLensmcpWsUrl(e.wsUrl)};e.reconnectIntervalMs!==void 0&&(t.reconnectIntervalMs=e.reconnectIntervalMs),p(t)}n(installLensmcp,"installLensmcp"),i(installLensmcp,"installLensmcp");function r(e){if(!(typeof document>"u"))try{const t=document.querySelector(`meta[name="${e}"]`)?.getAttribute("content");return t&&t.length>0?t:void 0}catch{return}}n(r,"c"),i(r,"readMeta");
|
package/lib/install.d.ts
CHANGED
package/lib/install.js
CHANGED
|
@@ -1,157 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @lensmcp/client-runtime — the browser-side capture layer.
|
|
3
|
-
*
|
|
4
|
-
* Vite (via `@lensmcp/vite-plugin`) injects this into served HTML. It
|
|
5
|
-
* connects to a localhost WebSocket the plugin spawns, and emits one
|
|
6
|
-
* `ClientEnvelope` per observed event. The runtime is **strictly
|
|
7
|
-
* passive**: it never mutates app state, never swallows errors, never
|
|
8
|
-
* changes scheduling.
|
|
9
|
-
*
|
|
10
|
-
* Phase 1 scope (mirror of the inline runtime in `@lensmcp/vite-plugin`,
|
|
11
|
-
* promoted out so the plugin can resolve it as a real package import
|
|
12
|
-
* in Phase 2):
|
|
13
|
-
* • `window.error` / `unhandledrejection`
|
|
14
|
-
* • `console.{log,info,warn,error,debug}` wrapping that preserves original
|
|
15
|
-
* • `fetch` wrapping (timing + status, no body inspection)
|
|
16
|
-
* • History API + popstate route changes
|
|
17
|
-
* • `ready` event on first connect
|
|
18
|
-
*
|
|
19
|
-
* Each envelope is timestamped on send.
|
|
20
|
-
*/
|
|
21
|
-
const FLAG = '__LENSMCP_CLIENT__';
|
|
22
|
-
export function installClientRuntime(opts) {
|
|
23
|
-
if (typeof window === 'undefined')
|
|
24
|
-
return;
|
|
25
|
-
if (window[FLAG])
|
|
26
|
-
return;
|
|
27
|
-
window[FLAG] = true;
|
|
28
|
-
const wsUrl = opts.wsUrl;
|
|
29
|
-
const reconnect = opts.reconnectIntervalMs ?? 1000;
|
|
30
|
-
let ws = null;
|
|
31
|
-
let openOnce = false;
|
|
32
|
-
const queue = [];
|
|
33
|
-
const send = (env) => {
|
|
34
|
-
env.at = Date.now();
|
|
35
|
-
if (ws && ws.readyState === 1 /* OPEN */) {
|
|
36
|
-
try {
|
|
37
|
-
ws.send(JSON.stringify(env));
|
|
38
|
-
}
|
|
39
|
-
catch { /* swallow */ }
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
queue.push(env);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
const open = () => {
|
|
46
|
-
try {
|
|
47
|
-
ws = new WebSocket(wsUrl);
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
setTimeout(open, reconnect);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
ws.addEventListener('open', () => {
|
|
54
|
-
openOnce = true;
|
|
55
|
-
while (queue.length) {
|
|
56
|
-
try {
|
|
57
|
-
ws.send(JSON.stringify(queue.shift()));
|
|
58
|
-
}
|
|
59
|
-
catch { /* swallow */ }
|
|
60
|
-
}
|
|
61
|
-
send({ kind: 'ready', userAgent: navigator.userAgent, url: location.href });
|
|
62
|
-
});
|
|
63
|
-
ws.addEventListener('close', () => {
|
|
64
|
-
if (openOnce)
|
|
65
|
-
setTimeout(open, reconnect);
|
|
66
|
-
});
|
|
67
|
-
ws.addEventListener('error', () => { });
|
|
68
|
-
};
|
|
69
|
-
open();
|
|
70
|
-
// Bridge for in-page instrumentation (@lensmcp/react-instrumentation,
|
|
71
|
-
// @lensmcp/valtio-instrumentation): their publish() output rides the
|
|
72
|
-
// same WS as a `publish` envelope so React/Valtio events reach the bus.
|
|
73
|
-
window.__LENSMCP_PUBLISH__ = (envelope) => {
|
|
74
|
-
send({ kind: 'publish', ...envelope });
|
|
75
|
-
};
|
|
76
|
-
// Errors
|
|
77
|
-
window.addEventListener('error', (e) => {
|
|
78
|
-
send({
|
|
79
|
-
kind: 'error',
|
|
80
|
-
message: e.message,
|
|
81
|
-
stack: e.error?.stack,
|
|
82
|
-
source: e.filename,
|
|
83
|
-
lineno: e.lineno,
|
|
84
|
-
colno: e.colno,
|
|
85
|
-
});
|
|
86
|
-
}, true);
|
|
87
|
-
window.addEventListener('unhandledrejection', (e) => {
|
|
88
|
-
const reason = e.reason;
|
|
89
|
-
const text = typeof reason === 'object' && reason
|
|
90
|
-
? reason.stack ?? reason.message ?? String(reason)
|
|
91
|
-
: String(reason);
|
|
92
|
-
send({ kind: 'unhandledrejection', reason: text });
|
|
93
|
-
});
|
|
94
|
-
const levels = ['log', 'info', 'warn', 'error', 'debug'];
|
|
95
|
-
for (const level of levels) {
|
|
96
|
-
const orig = console[level];
|
|
97
|
-
console[level] = function (...args) {
|
|
98
|
-
try {
|
|
99
|
-
send({ kind: 'console', level, args: args.map(safe) });
|
|
100
|
-
}
|
|
101
|
-
catch { /* swallow */ }
|
|
102
|
-
orig.apply(console, args);
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
// Fetch
|
|
106
|
-
const origFetch = window.fetch.bind(window);
|
|
107
|
-
window.fetch = async function (input, init) {
|
|
108
|
-
const method = init?.method ??
|
|
109
|
-
(typeof input === 'object' && input && 'method' in input ? input.method : 'GET');
|
|
110
|
-
const url = typeof input === 'string'
|
|
111
|
-
? input
|
|
112
|
-
: input instanceof URL
|
|
113
|
-
? input.toString()
|
|
114
|
-
: input.url;
|
|
115
|
-
const start = Date.now();
|
|
116
|
-
try {
|
|
117
|
-
const res = await origFetch(input, init);
|
|
118
|
-
send({ kind: 'fetch', method, url, status: res.status, ok: res.ok, durationMs: Date.now() - start });
|
|
119
|
-
return res;
|
|
120
|
-
}
|
|
121
|
-
catch (err) {
|
|
122
|
-
const e = err;
|
|
123
|
-
send({ kind: 'fetch', method, url, error: e.message ?? String(e), durationMs: Date.now() - start });
|
|
124
|
-
throw err;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
// History
|
|
128
|
-
const origPush = history.pushState.bind(history);
|
|
129
|
-
const origReplace = history.replaceState.bind(history);
|
|
130
|
-
const notify = (from) => send({ kind: 'route', url: location.href, from });
|
|
131
|
-
history.pushState = function (...args) {
|
|
132
|
-
const from = location.href;
|
|
133
|
-
const r = origPush(...args);
|
|
134
|
-
notify(from);
|
|
135
|
-
return r;
|
|
136
|
-
};
|
|
137
|
-
history.replaceState = function (...args) {
|
|
138
|
-
const from = location.href;
|
|
139
|
-
const r = origReplace(...args);
|
|
140
|
-
notify(from);
|
|
141
|
-
return r;
|
|
142
|
-
};
|
|
143
|
-
window.addEventListener('popstate', () => notify());
|
|
144
|
-
}
|
|
145
|
-
function safe(v) {
|
|
146
|
-
if (v === null)
|
|
147
|
-
return null;
|
|
148
|
-
const t = typeof v;
|
|
149
|
-
if (t === 'string' || t === 'number' || t === 'boolean')
|
|
150
|
-
return v;
|
|
151
|
-
try {
|
|
152
|
-
return JSON.parse(JSON.stringify(v));
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
return String(v);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
1
|
+
"use strict";var C=Object.defineProperty;var u=(t,r)=>C(t,"name",{value:r,configurable:!0});var j=Object.defineProperty,c=u((t,r)=>j(t,"name",{value:r,configurable:!0}),"c");const k="__LENSMCP_CLIENT__";export function installClientRuntime(t){if(typeof window>"u"||window[k])return;window[k]=!0;const r=t.wsUrl,w=t.reconnectIntervalMs??1e3;let i=null,y=!1;const l=[],s=c(n=>{if(n.at=Date.now(),i&&i.readyState===1)try{i.send(JSON.stringify(n))}catch{}else l.push(n)},"send"),f=c(()=>{try{i=new WebSocket(r)}catch{setTimeout(f,w);return}i.addEventListener("open",()=>{for(y=!0;l.length;)try{i.send(JSON.stringify(l.shift()))}catch{}s({kind:"ready",userAgent:navigator.userAgent,url:location.href})}),i.addEventListener("close",()=>{y&&setTimeout(f,w)}),i.addEventListener("error",()=>{})},"open");f(),window.__LENSMCP_PUBLISH__=n=>{s({kind:"publish",...n})},window.addEventListener("error",n=>{const e=n.target;if(e&&e!==window&&e.tagName&&!n.message){s({kind:"resource-error",tagName:e.tagName.toLowerCase(),url:e.currentSrc||e.src||e.href||void 0});return}const o=n.error;s({kind:"error",message:n.message,name:o?.name,stack:d(o?.stack),source:n.filename,lineno:n.lineno,colno:n.colno})},!0),window.addEventListener("unhandledrejection",n=>{const e=n.reason;s({kind:"unhandledrejection",reason:d(v(e)),name:typeof e=="object"&&e?e.name:void 0,stack:typeof e=="object"&&e?d(e.stack):void 0})});const L=["log","info","warn","error","debug"];for(const n of L){const e=console[n];console[n]=function(...o){try{s({kind:"console",level:n,args:o.map(b)})}catch{}e.apply(console,o)}}const N=window.fetch.bind(window);window.fetch=async function(n,e){const o=e?.method??(typeof n=="object"&&n&&"method"in n?n.method:"GET"),m=typeof n=="string"?n:n instanceof URL?n.toString():n.url,p=Date.now();try{const a=await N(n,e);return s({kind:"fetch",method:o,url:m,status:a.status,statusText:a.statusText,ok:a.ok,durationMs:Date.now()-p}),a}catch(a){const S=a;throw s({kind:"fetch",method:o,url:m,error:S.message??String(S),durationMs:Date.now()-p}),a}};const E=history.pushState.bind(history),_=history.replaceState.bind(history),h=c(n=>s({kind:"route",url:location.href,from:n}),"notify");history.pushState=function(...n){const e=location.href,o=E(...n);return h(e),o},history.replaceState=function(...n){const e=location.href,o=_(...n);return h(e),o},window.addEventListener("popstate",()=>h())}u(installClientRuntime,"installClientRuntime"),c(installClientRuntime,"installClientRuntime");const g=4096;function d(t){return t===void 0||t.length<=g?t:`${t.slice(0,g)}\u2026[lensmcp truncated: ${t.length-g} more chars]`}u(d,"h"),c(d,"clipStack");function v(t){if(t==null)return String(t);if(typeof t=="string")return t;if(typeof t.message=="string"&&t.message)return t.message;try{const r=JSON.stringify(t);if(r&&r!=="{}"&&r!=="null")return r}catch{}return String(t)}u(v,"E"),c(v,"describeReason");function b(t){if(t===null)return null;const r=typeof t;if(r==="string"||r==="number"||r==="boolean")return t;try{return JSON.parse(JSON.stringify(t))}catch{return String(t)}}u(b,"C"),c(b,"safe");
|
package/package.json
CHANGED
package/auto.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../src/auto.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
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,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC"}
|
package/lib/auto.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto.d.ts","sourceRoot":"","sources":["../../src/lib/auto.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAwB7D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,kBAAuB,GAAG,IAAI,CAOlE"}
|
package/lib/install.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/lib/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAQD,QAAA,MAAM,IAAI,uBAAuB,CAAC;AAElC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC;KAClB;CACF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CA+H/D"}
|