@lensmcp/valtio-instrumentation 1.21.5 → 1.22.1
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/proxy.js +1 -1
- package/lib/snapshot.d.ts +26 -4
- package/lib/snapshot.js +1 -1
- package/lib/types.d.ts +16 -0
- package/package.json +3 -2
package/lib/proxy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var y=Object.defineProperty;var o=(e,t)=>y(e,"name",{value:t,configurable:!0});var h=Object.defineProperty,n=o((e,t)=>h(e,"name",{value:t,configurable:!0}),"n");import{proxy as g,subscribe as P,unstable_enableOp as w}from"valtio/vanilla";import{publish as $,publishLazy as I,depsHash as f}from"@lensmcp/react-instrumentation";import{boundedClone as x}from"@lensmcp/protocol-types";import{registerStore as E,subscribersForPathAndParents as S,tagProxy as L}from"./store-registry.js";import{truncatePath as _}from"./snapshot.js";let l=!1;function d(){if(!l)try{w(!0),l=!0}catch{}}o(d,"I"),n(d,"ensureOpsEnabled");let O=0;export function proxy(e,t={}){d();const r=t.storeId??`valtio:store:${++O}`;E(r,t.source);const a=g(e);return L(a,r),$({source:"valtio",category:"state",severity:"info",title:`store-created ${r}`,fingerprint:`valtio-store:${r}`,raw:{kind:"store-created",store:{storeId:r,source:t.source,initialPreview:t.emitInitialPreview===!1?void 0:c(e)}}}),P(a,v=>{for(const b of v){const[,s,u,m]=b;if(!(s??[]).length)continue;const p=`valtio-update:${r}:${_(s??[])}`;I(p,()=>{const i=(s??[]).map(String).join(".");return{source:"valtio",category:"state",severity:"info",title:`state-update ${r}.${i}`,fingerprint:p,raw:{kind:"state-update",update:{storeId:r,path:i,changedKeys:(s??[]).map(String),beforeHash:f([m]),afterHash:f([u]),preview:c(u),subscribers:S(r,i)}}}})}},!0),a}o(proxy,"proxy"),n(proxy,"proxy");const H=(()=>{const e=typeof process<"u"?process.env?.LENSMCP_VALTIO_PREVIEW_BYTES:void 0,t=Number(e);return Number.isFinite(t)&&t>=0?Math.floor(t):32*1024})();function c(e){try{return x(e,{rawByteLimit:H}).value}catch{return}}o(c,"f"),n(c,"safePreview");
|
package/lib/snapshot.d.ts
CHANGED
|
@@ -14,7 +14,29 @@ export declare function useTrackedSnapshot<T extends object>(target: T, opts: Us
|
|
|
14
14
|
* `proxy()`; falls back to a single root subscription when nothing is read.
|
|
15
15
|
*/
|
|
16
16
|
export declare function useSnapshot<T extends object>(target: T): T;
|
|
17
|
-
/** Join a visited-property path, truncated to {@link SUB_PATH_DEPTH} segments (0 ⇒ no
|
|
18
|
-
* Built in ONE pass with no intermediate arrays — this runs
|
|
19
|
-
* hot enough to chart in commit-storm profiles when written as
|
|
20
|
-
|
|
17
|
+
/** Join a visited-property path, truncated to {@link SUB_PATH_DEPTH} segments (0 ⇒ no depth limit)
|
|
18
|
+
* and {@link MAX_PATH_CHARS} characters. Built in ONE pass with no intermediate arrays — this runs
|
|
19
|
+
* per visited property per snapshot, hot enough to chart in commit-storm profiles when written as
|
|
20
|
+
* map().slice().join(). */
|
|
21
|
+
export declare function truncatePath(parts: PathParts): string;
|
|
22
|
+
export type PathParts = readonly (string | number | symbol)[];
|
|
23
|
+
/** The bounded read set for one commit, plus what it cost to get there. */
|
|
24
|
+
export interface ReadPathSet {
|
|
25
|
+
/** Distinct reported paths, in first-read order. */
|
|
26
|
+
paths: Set<string>;
|
|
27
|
+
/** Raw entries `affectedToPathList` returned — the number of properties actually visited. */
|
|
28
|
+
scanned: number;
|
|
29
|
+
/** Distinct paths dropped because a bound was hit. `> 0` ⇒ the set is a prefix, not the whole truth. */
|
|
30
|
+
dropped: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Turn `proxy-compare`'s visited-property list into the bounded set of paths this commit subscribes to.
|
|
34
|
+
*
|
|
35
|
+
* ONE pass, no intermediate arrays: this runs per visited property per commit, and the list it walks is
|
|
36
|
+
* the unbounded one (thousands of entries for a component reading a large nested collection).
|
|
37
|
+
*/
|
|
38
|
+
export declare function collectReadPaths(list: readonly PathParts[]): ReadPathSet;
|
|
39
|
+
/** Add/remove subscriptions so the registry matches `read.paths` exactly. */
|
|
40
|
+
export declare function reconcileSubscriptions(prev: Set<string>, read: ReadPathSet, storeId: string, componentInstanceId: string, componentLogicalId?: string): void;
|
|
41
|
+
/** Release everything a hook instance holds — the unmount half of the reconcile. */
|
|
42
|
+
export declare function dropAllSubscriptions(subscribed: Set<string>, storeId: string, componentInstanceId: string, componentLogicalId?: string): void;
|
package/lib/snapshot.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var $=Object.defineProperty;var
|
|
1
|
+
"use strict";var $=Object.defineProperty;var a=(e,t)=>$(e,"name",{value:t,configurable:!0});var T=Object.defineProperty,d=a((e,t)=>T(e,"name",{value:t,configurable:!0}),"a");import{useCallback as x,useEffect as l,useLayoutEffect as N,useMemo as b,useRef as S,useSyncExternalStore as _}from"react";import{snapshot as g,subscribe as A}from"valtio/vanilla";import{useSnapshot as E}from"valtio/react";import{affectedToPathList as k,createProxy as w,isChanged as C}from"proxy-compare";import{estimateJsonBytes as O}from"@lensmcp/protocol-types";import{useComponentIdentity as v,useLensmcpContext as L,publish as W}from"@lensmcp/react-instrumentation";import{addSubscription as B,removeSubscription as H,storeIdOf as R}from"./store-registry.js";const F=new WeakMap;export function useTrackedSnapshot(e,t){const n=L(),o=t.path??"",r=v(),s=n.componentInstanceId??r.componentInstanceId;return l(()=>(I("added",t.storeId,o,s,r.componentLogicalId),()=>{I("removed",t.storeId,o,s,r.componentLogicalId)}),[t.storeId,o,s]),E(e)}a(useTrackedSnapshot,"useTrackedSnapshot"),d(useTrackedSnapshot,"useTrackedSnapshot");export function useSnapshot(e){const t=R(e)??"valtio:store:anonymous",n=L(),o=v(),r=n.componentInstanceId??o.componentInstanceId,s=b(()=>e&&new WeakMap,[e]),i=S(void 0);let p=!0;const c=_(x(u=>{const M=A(e,u,!1);return u(),M},[e]),()=>{const u=g(e);try{if(!p&&i.current&&s&&!C(i.current,u,s,new WeakMap))return i.current}catch{}return u},()=>g(e));p=!1,N(()=>{i.current=c});const y=b(()=>new WeakMap,[]),m=S(void 0);return m.current||(m.current=new Set),l(()=>{const u=collectReadPaths(s?k(c,s,!0):[]);reconcileSubscriptions(m.current,u,t,r,o.componentLogicalId)}),l(()=>{const u=m.current;return()=>{dropAllSubscriptions(u,t,r,o.componentLogicalId)}},[t,r]),s?w(c,s,y,F):c}a(useSnapshot,"useSnapshot"),d(useSnapshot,"useSnapshot");const h=(()=>{const e=typeof process<"u"?process.env?.LENSMCP_VALTIO_PATH_DEPTH:void 0,t=Number(e);return Number.isFinite(t)&&t>=0&&t<=20?Math.floor(t):3})(),P=120;export function truncatePath(e){const t=h>0&&h<e.length?h:e.length;let n="";for(let o=0;o<t;o++)if(n+=o===0?String(e[o]):`.${String(e[o])}`,n.length>=P)return`${n.slice(0,P)}\u2026`;return n}a(truncatePath,"truncatePath"),d(truncatePath,"truncatePath");const V=(()=>{const e=typeof process<"u"?process.env?.LENSMCP_VALTIO_MAX_PATHS:void 0,t=Number(e);return Number.isFinite(t)&&t>=1?Math.floor(t):32})(),z=(()=>{const e=typeof process<"u"?process.env?.LENSMCP_VALTIO_SUB_BYTES:void 0,t=Number(e);return Number.isFinite(t)&&t>0?Math.floor(t):4*1024})();export function collectReadPaths(e){const t=new Set;let n=0,o=0;for(const r of e){const s=truncatePath(r);if(!t.has(s)){if(t.size>=V||o>=z){n++;continue}o+=O(s),t.add(s)}}return t.size===0&&t.add(""),{paths:t,scanned:e.length,dropped:n}}a(collectReadPaths,"collectReadPaths"),d(collectReadPaths,"collectReadPaths");export function reconcileSubscriptions(e,t,n,o,r){const s=t.paths,i=[],p=[];for(const c of s)e.has(c)||i.push(c);for(const c of e)s.has(c)||p.push(c);f("added",i,n,o,r,t.dropped),f("removed",p,n,o,r),e.clear();for(const c of s)e.add(c)}a(reconcileSubscriptions,"reconcileSubscriptions"),d(reconcileSubscriptions,"reconcileSubscriptions");export function dropAllSubscriptions(e,t,n,o){f("removed",[...e],t,n,o),e.clear()}a(dropAllSubscriptions,"dropAllSubscriptions"),d(dropAllSubscriptions,"dropAllSubscriptions");function f(e,t,n,o,r,s=0){if(t.length===0)return;for(const p of t)e==="added"?B({storeId:n,path:p,componentInstanceId:o}):H({storeId:n,path:p,componentInstanceId:o});const i=e==="added"?"sub":"unsub";W({source:"valtio",category:"state",severity:"debug",title:`subscription-${e} ${n} (${t.length} path${t.length===1?"":"s"}${s?`, ${s} dropped`:""})`,fingerprint:`valtio-${i}:${n}`,raw:{kind:`subscription-${e}`,subscription:{storeId:n,path:t[0],paths:[...t],componentInstanceId:o,...r?{componentLogicalId:r}:{},...s?{truncated:!0,droppedPaths:s}:{}}}})}a(f,"p"),d(f,"emitSubscriptions");function I(e,t,n,o,r){f(e,[n],t,o,r)}a(I,"A"),d(I,"emitSubscription");
|
package/lib/types.d.ts
CHANGED
|
@@ -17,10 +17,26 @@ export interface ValtioStoreRecord {
|
|
|
17
17
|
source?: string;
|
|
18
18
|
initialPreview?: unknown;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* One commit's worth of subscription changes for one hook instance — NOT one path.
|
|
22
|
+
*
|
|
23
|
+
* issues/codex-security/58: this used to be one event per path, so a component reading N entries of a
|
|
24
|
+
* large collection published O(N) events per commit and another O(N) on unmount. `paths` carries the
|
|
25
|
+
* whole delta in a single event; `path` is `paths[0]`, kept so a consumer written against the old
|
|
26
|
+
* one-path-per-event shape still keys on a real path.
|
|
27
|
+
*/
|
|
20
28
|
export interface ValtioSubscriptionRecord {
|
|
21
29
|
storeId: string;
|
|
30
|
+
/** First entry of {@link paths}. */
|
|
22
31
|
path: string;
|
|
32
|
+
/** Every path added (or removed) by this commit, bounded in depth, length and cardinality. */
|
|
33
|
+
paths?: string[];
|
|
23
34
|
componentInstanceId?: string;
|
|
35
|
+
componentLogicalId?: string;
|
|
36
|
+
/** `true` when {@link paths} is a PREFIX of the real read set — a bound clipped it. */
|
|
37
|
+
truncated?: boolean;
|
|
38
|
+
/** How many distinct paths were dropped to stay inside the bounds. */
|
|
39
|
+
droppedPaths?: number;
|
|
24
40
|
}
|
|
25
41
|
export type ValtioPublishPayload = {
|
|
26
42
|
kind: 'state-update';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lensmcp/valtio-instrumentation",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@lensmcp/
|
|
17
|
+
"@lensmcp/protocol-types": "1.22.1",
|
|
18
|
+
"@lensmcp/react-instrumentation": "1.22.1",
|
|
18
19
|
"proxy-compare": "^3.0.0",
|
|
19
20
|
"tslib": "^2.3.0"
|
|
20
21
|
},
|