@unnoodle/browser 0.1.0 → 0.1.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/README.md +29 -0
- package/dist/flow/index.cjs +2 -0
- package/dist/flow/index.cjs.map +1 -0
- package/dist/flow/index.d.cts +142 -0
- package/dist/flow/index.d.ts +142 -0
- package/dist/flow/index.js +2 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/index.cjs +333 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +333 -159
- package/dist/index.js.map +1 -1
- package/package.json +27 -16
package/README.md
CHANGED
|
@@ -398,6 +398,35 @@ See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
|
398
398
|
|
|
399
399
|
---
|
|
400
400
|
|
|
401
|
+
## Release
|
|
402
|
+
|
|
403
|
+
Releases are published by GitHub Actions (`.github/workflows/publish-browser.yml`),
|
|
404
|
+
never from a laptop. Pushing a tag `browser-v<version>` builds, tests and
|
|
405
|
+
publishes that version to npm, signed in with npm trusted publishing (no npm
|
|
406
|
+
token is stored anywhere).
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
cd ui/browser
|
|
410
|
+
npm run release:patch # or release:minor / release:major — bumps package.json only
|
|
411
|
+
VERSION=$(node -p "require('./package.json').version")
|
|
412
|
+
git commit -am "chore(browser): release $VERSION"
|
|
413
|
+
git tag "browser-v$VERSION"
|
|
414
|
+
git push origin main "browser-v$VERSION"
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
The workflow refuses to publish if the tag does not match `package.json`, if
|
|
418
|
+
the version is already on npm, if the tests fail, or if the packed tarball
|
|
419
|
+
does not install and import in an empty project.
|
|
420
|
+
|
|
421
|
+
To check a release without publishing: GitHub → Actions → "Publish
|
|
422
|
+
@unnoodle/browser" → Run workflow (a dry run: everything but the publish).
|
|
423
|
+
|
|
424
|
+
One-time setup (already done if a release has gone out): on npmjs.com,
|
|
425
|
+
@unnoodle/browser → Settings → Trusted publishing → GitHub Actions, with
|
|
426
|
+
organization `unnoodle`, repository `unnoodle`, workflow `publish-browser.yml`.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
401
430
|
## License
|
|
402
431
|
|
|
403
432
|
MIT © [Unnoodle](https://unnoodle.com)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';function z(e){switch(e){case 0:case "EVENT_TYPE_UNSPECIFIED":return 0;case 1:case "EVENT_TYPE_INTERACTION":return 1;case 2:case "EVENT_TYPE_NAVIGATION":return 2;case 3:case "EVENT_TYPE_HEARTBEAT":return 3;default:return -1}}function W(e){switch(e){case 0:return "EVENT_TYPE_UNSPECIFIED";case 1:return "EVENT_TYPE_INTERACTION";case 2:return "EVENT_TYPE_NAVIGATION";case 3:return "EVENT_TYPE_HEARTBEAT";default:return "UNRECOGNIZED"}}function Se(){return {tag:"",role:"",label:"",testId:"",ancestorPath:""}}var R={fromJSON(e){return {tag:d(e.tag)?globalThis.String(e.tag):"",role:d(e.role)?globalThis.String(e.role):"",label:d(e.label)?globalThis.String(e.label):"",testId:d(e.testId)?globalThis.String(e.testId):d(e.test_id)?globalThis.String(e.test_id):"",ancestorPath:d(e.ancestorPath)?globalThis.String(e.ancestorPath):d(e.ancestor_path)?globalThis.String(e.ancestor_path):""}},toJSON(e){let t={};return e.tag!==""&&(t.tag=e.tag),e.role!==""&&(t.role=e.role),e.label!==""&&(t.label=e.label),e.testId!==""&&(t.testId=e.testId),e.ancestorPath!==""&&(t.ancestorPath=e.ancestorPath),t},create(e){return R.fromPartial(e??{})},fromPartial(e){let t=Se();return t.tag=e.tag??"",t.role=e.role??"",t.label=e.label??"",t.testId=e.testId??"",t.ancestorPath=e.ancestorPath??"",t}};function Pe(){return {localKey:"",descriptor:void 0}}var P={fromJSON(e){return {localKey:d(e.localKey)?globalThis.String(e.localKey):d(e.local_key)?globalThis.String(e.local_key):"",descriptor:d(e.descriptor)?R.fromJSON(e.descriptor):void 0}},toJSON(e){let t={};return e.localKey!==""&&(t.localKey=e.localKey),e.descriptor!==void 0&&(t.descriptor=R.toJSON(e.descriptor)),t},create(e){return P.fromPartial(e??{})},fromPartial(e){let t=Pe();return t.localKey=e.localKey??"",t.descriptor=e.descriptor!==void 0&&e.descriptor!==null?R.fromPartial(e.descriptor):void 0,t}};function xe(){return {eventId:"",sessionId:"",seq:0,ts:0,type:0,route:"",appBuild:"",to:void 0,from:void 0}}var N={fromJSON(e){return {eventId:d(e.eventId)?globalThis.String(e.eventId):d(e.event_id)?globalThis.String(e.event_id):"",sessionId:d(e.sessionId)?globalThis.String(e.sessionId):d(e.session_id)?globalThis.String(e.session_id):"",seq:d(e.seq)?globalThis.Number(e.seq):0,ts:d(e.ts)?globalThis.Number(e.ts):0,type:d(e.type)?z(e.type):0,route:d(e.route)?globalThis.String(e.route):"",appBuild:d(e.appBuild)?globalThis.String(e.appBuild):d(e.app_build)?globalThis.String(e.app_build):"",to:d(e.to)?P.fromJSON(e.to):void 0,from:d(e.from)?P.fromJSON(e.from):void 0}},toJSON(e){let t={};return e.eventId!==""&&(t.eventId=e.eventId),e.sessionId!==""&&(t.sessionId=e.sessionId),e.seq!==0&&(t.seq=Math.round(e.seq)),e.ts!==0&&(t.ts=Math.round(e.ts)),e.type!==0&&(t.type=W(e.type)),e.route!==""&&(t.route=e.route),e.appBuild!==""&&(t.appBuild=e.appBuild),e.to!==void 0&&(t.to=P.toJSON(e.to)),e.from!==void 0&&(t.from=P.toJSON(e.from)),t},create(e){return N.fromPartial(e??{})},fromPartial(e){let t=xe();return t.eventId=e.eventId??"",t.sessionId=e.sessionId??"",t.seq=e.seq??0,t.ts=e.ts??0,t.type=e.type??0,t.route=e.route??"",t.appBuild=e.appBuild??"",t.to=e.to!==void 0&&e.to!==null?P.fromPartial(e.to):void 0,t.from=e.from!==void 0&&e.from!==null?P.fromPartial(e.from):void 0,t}};function Ne(){return {sdkVersion:"",appBuild:"",context:"",sessionId:"",events:[]}}var _={fromJSON(e){return {sdkVersion:d(e.sdkVersion)?globalThis.String(e.sdkVersion):d(e.sdk_version)?globalThis.String(e.sdk_version):"",appBuild:d(e.appBuild)?globalThis.String(e.appBuild):d(e.app_build)?globalThis.String(e.app_build):"",context:d(e.context)?globalThis.String(e.context):"",sessionId:d(e.sessionId)?globalThis.String(e.sessionId):d(e.session_id)?globalThis.String(e.session_id):"",events:globalThis.Array.isArray(e?.events)?e.events.map(t=>N.fromJSON(t)):[]}},toJSON(e){let t={};return e.sdkVersion!==""&&(t.sdkVersion=e.sdkVersion),e.appBuild!==""&&(t.appBuild=e.appBuild),e.context!==""&&(t.context=e.context),e.sessionId!==""&&(t.sessionId=e.sessionId),e.events?.length&&(t.events=e.events.map(n=>N.toJSON(n))),t},create(e){return _.fromPartial(e??{})},fromPartial(e){let t=Ne();return t.sdkVersion=e.sdkVersion??"",t.appBuild=e.appBuild??"",t.context=e.context??"",t.sessionId=e.sessionId??"",t.events=e.events?.map(n=>N.fromPartial(n))||[],t}};function d(e){return e!=null}function we(){return {appBuild:"",policyVersion:0,captureAll:false,heartbeatRate:0,refreshAfterSeconds:0}}var B={fromJSON(e){return {appBuild:b(e.appBuild)?globalThis.String(e.appBuild):b(e.app_build)?globalThis.String(e.app_build):"",policyVersion:b(e.policyVersion)?globalThis.Number(e.policyVersion):b(e.policy_version)?globalThis.Number(e.policy_version):0,captureAll:b(e.captureAll)?globalThis.Boolean(e.captureAll):b(e.capture_all)?globalThis.Boolean(e.capture_all):false,heartbeatRate:b(e.heartbeatRate)?globalThis.Number(e.heartbeatRate):b(e.heartbeat_rate)?globalThis.Number(e.heartbeat_rate):0,refreshAfterSeconds:b(e.refreshAfterSeconds)?globalThis.Number(e.refreshAfterSeconds):b(e.refresh_after_seconds)?globalThis.Number(e.refresh_after_seconds):0}},toJSON(e){let t={};return e.appBuild!==""&&(t.appBuild=e.appBuild),e.policyVersion!==0&&(t.policyVersion=Math.round(e.policyVersion)),e.captureAll!==false&&(t.captureAll=e.captureAll),e.heartbeatRate!==0&&(t.heartbeatRate=e.heartbeatRate),e.refreshAfterSeconds!==0&&(t.refreshAfterSeconds=Math.round(e.refreshAfterSeconds)),t},create(e){return B.fromPartial(e??{})},fromPartial(e){let t=we();return t.appBuild=e.appBuild??"",t.policyVersion=e.policyVersion??0,t.captureAll=e.captureAll??false,t.heartbeatRate=e.heartbeatRate??0,t.refreshAfterSeconds=e.refreshAfterSeconds??0,t}};function b(e){return e!=null}var L={ringBufferCapacity:500,batchMaxEvents:100,batchMaxBodyBytes:61440,flushMinIntervalMs:5e3,admissionCapacity:100,admissionRefillPerSec:1,warmupWindowMs:9e5,degradedSampleRate:.1,policyStalenessFactor:6,policyRetryBaseMs:3e4,policyRetryMaxMs:6e5,continuityWindowMs:18e5,continuityBlobMaxBytes:4096,quiescenceMutationQuietMs:200,quiescenceNetworkQuietMs:500,quiescenceHardCapMs:3e3,rageClickCount:3,rageClickWindowMs:1e3,heartbeatSessionCap:20,idleFrameBudgetMs:4,gateKeyLabelCap:64};var Q=false,q=new Set;function X(e){Q=e,e||q.clear();}function p(e){return (...t)=>{try{return e(...t)}catch(n){if(Q){let r=n instanceof Error?`${n.name}:${n.message}`:String(n);q.has(r)||(q.add(r),console.debug("[unnoodle/flow] swallowed:",r));}return}}}var Be=150,Ae=8;function Z(e){let t=[],n=false,r=false,i,o=typeof requestIdleCallback=="function",a=p(l=>{if(n=!1,!r){for(;t.length>0&&l.timeRemaining()>e;){let h=t.shift();p(h)();}t.length>0&&s();}});function s(){n||r||(n=true,o?i=requestIdleCallback(l=>a(l)):i=setTimeout(()=>{let l=Date.now();a({timeRemaining:()=>Math.max(0,Ae-(Date.now()-l))});},Be));}return {schedule(l){r||(t.push(l),s());},stop(){r=true,t.length=0,i!==void 0&&(o?cancelIdleCallback(i):clearTimeout(i));}}}var Me="data-unnoodle-ignore",De=new Set(["input","textarea","select","option"]);function te(e,t=[]){if(e.closest(`[${Me}]`)!==null)return true;for(let n of t)try{if(e.closest(n)!==null)return !0}catch{}return false}function ne(e){let t=e.getAttribute("aria-label");return t?ee(j(t)):De.has(e.tagName.toLowerCase())?"":ee(j(e.textContent??""))}function re(e){return K(e.pathname||"/",512)}function j(e){return e.replace(/\s+/g," ").trim()}function ee(e){return K(e,40)}function K(e,t){if(e.length<=t)return e;let n=e.charCodeAt(t-1);return e.slice(0,n>=55296&&n<=56319?t-1:t)}var Re=8,ke=64,Oe='button, a[href], [role="button"], [role="link"], [role="menuitem"], [role="tab"], input, select, textarea, summary';function ie(e){return e instanceof Element?e.closest(Oe):null}function oe(e){return {tag:e.tagName.toLowerCase(),role:e.getAttribute("role")??"",label:ne(e),testId:e.getAttribute("data-testid")??e.id??"",ancestorPath:Ce(e)}}function Ce(e){let t=[],n=e.parentElement;for(;n!==null&&t.length<Re;){let r=n.tagName.toLowerCase();if(r==="html")break;t.push(K(n.getAttribute("role")??r,ke)),n=n.parentElement;}return t.reverse().join(">")}function ae(e){return {tag:"page",role:"document",label:e,testId:"",ancestorPath:""}}function se(e){return e.testId?`${e.tag}#${e.testId}`:`${e.tag}@${Ke(`${e.role}|${e.label}|${e.ancestorPath}`)}`}function Ke(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n)|0;return (t>>>0).toString(36)}var Fe=1;function de(e){let n=(typeof e.normalize=="function"?e.normalize("NFC"):e).replace(/[ \t\n\v\f\r]+/g," "),r=Ue(n).toLowerCase();return r.length>64?r.slice(0,64):r}function Ue(e){let t=0,n=e.length;for(;t<n&&e.charCodeAt(t)<=32;)t++;for(;n>t&&e.charCodeAt(n-1)<=32;)n--;return t===0&&n===e.length?e:e.slice(t,n)}function le(e){return [e.tag.toLowerCase(),e.role,de(e.label),e.testId,e.ancestorPath].join("")}function J(e,t,n){let r=(e===null?"\u2205":le(e))+""+le(t)+""+n;return pe(r)}var Ve=BigInt("0xcbf29ce484222325"),ue=BigInt("0x100000001b3"),ce=BigInt("0xffffffffffffffff");function pe(e){let t=Ve;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t^=BigInt(r&255),t=t*ue&ce,t^=BigInt(r>>>8),t=t*ue&ce;}return t}var fe={has:()=>false};function he(e,t){let n=0,r=0,i=false,o,a;if(typeof MutationObserver=="function"&&typeof document<"u"&&(o=new MutationObserver(p(()=>{n=Date.now();})),o.observe(document.documentElement,{subtree:true,childList:true,attributes:true,characterData:true})),typeof PerformanceObserver=="function")try{a=new PerformanceObserver(p(()=>{r=Date.now();})),a.observe({entryTypes:["resource"]});}catch{a=void 0;}return {awaitSettled({hardCapMs:s}){let l=Date.now(),h=n,E=false,T,x,g=new Promise(f=>{x=f;}),m=f=>{T!==void 0&&clearTimeout(T),T=void 0,x({settledTs:Date.now(),mutated:n>h,navigated:i,timedOut:f,interrupted:E}),i=false;},c=p(()=>{let f=Date.now();if(f-l>=s){m(!0);return}let S=f-Math.max(n,l)>=e,M=a===void 0||f-Math.max(r,l)>=t;if(S&&M){m(!1);return}T=setTimeout(c,Math.min(e,100));});return T=setTimeout(c,e),{promise:g,interrupt:()=>{E=true,m(false);}}},noteNavigation(){i=true;},stop(){o?.disconnect(),a?.disconnect();}}}function me(e,t){let n=p(e),r=history.pushState,i=history.replaceState;history.pushState=function(...l){let h=r.apply(this,l);return n({route:location.pathname,ts:Date.now(),cause:"push"}),h},history.replaceState=function(...l){let h=i.apply(this,l);return n({route:location.pathname,ts:Date.now(),cause:"replace"}),h};let o=p(()=>n({route:location.pathname,ts:Date.now(),cause:"pop"})),a=p(()=>n({route:location.pathname,ts:Date.now(),cause:"hash"})),s=p(t);return window.addEventListener("popstate",o,{passive:true}),window.addEventListener("hashchange",a,{passive:true}),window.addEventListener("pagehide",s),{stop:p(()=>{history.pushState!==r&&(history.pushState=r),history.replaceState!==i&&(history.replaceState=i),window.removeEventListener("popstate",o),window.removeEventListener("hashchange",a),window.removeEventListener("pagehide",s);})}}var ge="__unnoodle_flow_v1";function ye(e,t,n=Je()){return {resumeOrStart(r){let i=Le(n,r,e,t);return i!==null?{sessionId:i.sessionId,seq:i.seq,currentNode:i.currentNode,resumed:true}:{sessionId:He(),seq:0,currentNode:null,resumed:false}},persist(r,i){if(n===null)return;let o={v:1,sessionId:r.sessionId,seq:r.seq,appBuild:i,lastTs:Date.now(),currentNode:r.currentNode};try{let a=JSON.stringify(o);a.length<=t&&n.setItem(ge,a);}catch{}}}}function Le(e,t,n,r){if(e===null)return null;try{let i=e.getItem(ge);if(i===null||i.length>r)return null;let o=JSON.parse(i);return o.v!==1||typeof o.sessionId!="string"||o.sessionId.length===0||o.sessionId.length>128||typeof o.seq!="number"||!Number.isInteger(o.seq)||o.seq<0||typeof o.appBuild!="string"||o.appBuild!==t||typeof o.lastTs!="number"||Date.now()-o.lastTs>n||o.lastTs>Date.now()+6e4||o.currentNode!==null&&!qe(o.currentNode)?null:o}catch{return null}}function qe(e){if(typeof e!="object"||e===null)return false;let t=e;if(typeof t.localKey!="string"||t.localKey.length>256)return false;let n=t.descriptor;if(typeof n!="object"||n===null)return false;let r=["tag","role","label","testId","ancestorPath"];for(let i of r)if(typeof n[i]!="string"||n[i].length>512)return false;return Object.keys(n).length===r.length}function Je(){try{let e=window.sessionStorage;return e.setItem("__unnoodle_probe","1"),e.removeItem("__unnoodle_probe"),e}catch{return null}}function He(){try{return crypto.randomUUID()}catch{return `s-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}}function Ee(e,t,n){let r=[];return {goalsFor(i,o){let a=[];for(let s of e)if(!(typeof s.name!="string"||s.name.length===0||s.name.length>32)&&!(s.route!==void 0&&!Ge(s.route,o))){if(s.selector!==void 0)try{if(!i.matches(s.selector))continue}catch{continue}(s.route!==void 0||s.selector!==void 0)&&a.push({kind:"goal",name:s.name});}return a},noteInteraction(i,o){r.push({key:i,ts:o}),r.length>4&&r.shift();let a=o-n;return r.filter(l=>l.key===i&&l.ts>=a).length>=t},derive(i,o,a){let s=[...a];return o&&s.push({kind:"rage_click"}),i.timedOut&&!i.mutated&&!i.navigated&&s.push({kind:"dead_click"}),s}}}function Ge(e,t){return e.endsWith("*")?t.startsWith(e.slice(0,-1)):t===e}function Te(e){let{params:t}=e,n=e.storage===void 0?Ye():e.storage,r=e.fetchFn??(typeof fetch=="function"?fetch:void 0),i=`__unnoodle_policy_${e.context}`,o=h(),a=t.policyRetryBaseMs,s,l=false;function h(){if(n===null)return null;try{let g=n.getItem(i);if(g===null)return null;let m=JSON.parse(g);return typeof m.fetchedAtMs!="number"||m.appBuild!==e.appBuild?null:{policy:B.fromJSON(m.policy),fetchedAtMs:m.fetchedAtMs}}catch{return null}}function E(g,m){if(n!==null)try{let c={policy:B.toJSON(g),fetchedAtMs:m,appBuild:e.appBuild};n.setItem(i,JSON.stringify(c));}catch{}}async function T(){if(!(l||r===void 0))try{let g=`${e.policyUrl}?context=${encodeURIComponent(e.context)}&appBuild=${encodeURIComponent(e.appBuild)}`,m=await r(g,{method:"GET",headers:{"X-UNNOODLE-API-KEY":e.apiKey}});if(!m.ok)throw new Error(`policy ${m.status}`);let c=B.fromJSON(await m.json()),f=Date.now();o={policy:c,fetchedAtMs:f},E(c,f),a=t.policyRetryBaseMs,x(Math.max(1e3,c.refreshAfterSeconds*1e3));}catch{x(a),a=Math.min(a*2,t.policyRetryMaxMs);}}function x(g){l||(s!==void 0&&clearTimeout(s),s=setTimeout(()=>{p(T)();},g));}return {current(){let g=Date.now();if(o!==null){let c=g-o.fetchedAtMs,f=Math.max(1,o.policy.refreshAfterSeconds)*1e3;return c<=f?{phase:"active",policy:o.policy,ageMs:c}:c<=t.policyStalenessFactor*f?{phase:"stale",policy:o.policy,ageMs:c}:{phase:"expired",ageMs:c}}return g-e.sessionStartMs<=t.warmupWindowMs?{phase:"warmup",ageMs:1/0}:{phase:"degraded_sample",ageMs:1/0}},start(){x(0);},stop(){l=true,s!==void 0&&clearTimeout(s);}}}function Ye(){try{let e=window.localStorage;return e.setItem("__unnoodle_probe","1"),e.removeItem("__unnoodle_probe"),e}catch{return null}}var A=class{constructor(t,n,r=Date.now()){this.capacity=t;this.refillPerSec=n;this.tokens=t,this.lastRefillMs=r;}take(t=Date.now()){if(this.refillPerSec>0){let n=Math.max(0,t-this.lastRefillMs);this.tokens=Math.min(this.capacity,this.tokens+n/1e3*this.refillPerSec),this.lastRefillMs=t;}return this.tokens>=1?(this.tokens-=1,true):false}};function Ie(e){let t=new A(e.params.heartbeatSessionCap,0),n=e.random??Math.random;return {decide(r,i,o){if(i.length>0)return "capture";let{phase:a,policy:s}=o;return a==="warmup"||a==="expired"?"capture":a==="degraded_sample"?n()<e.params.degradedSampleRate?"capture":"silent":s===void 0||s.captureAll||s.appBuild!==e.appBuild||!e.gateKeyVersionOk()||!e.membership().has(r)?"capture":n()<s.heartbeatRate&&t.take()?"heartbeat":"silent"}}}var F=class{constructor(t){this.capacity=t;this.head=0;this.count=0;this.dropped=0;this.slots=new Array(t);}enqueue(t){this.count===this.capacity?(this.head=(this.head+1)%this.capacity,this.dropped+=1):this.count+=1,this.slots[(this.head+this.count-1)%this.capacity]=t;}drain(t){let n=Math.min(t,this.count),r=[];for(let i=0;i<n;i++){let o=(this.head+i)%this.capacity;r.push(this.slots[o]),this.slots[o]=void 0;}return this.head=(this.head+n)%this.capacity,this.count-=n,r}get size(){return this.count}get droppedTotal(){return this.dropped}countDrop(){this.dropped+=1;}};var $e="browser-flow/1.0.0",U=class{constructor(t){this.config=t;this.inFlight=false;this.lastFlushMs=0;this.buffer=new F(t.params.ringBufferCapacity);}enqueue(t){this.buffer.enqueue(t);}countDrop(){this.buffer.countDrop();}get pending(){return this.buffer.size}get droppedTotal(){return this.buffer.droppedTotal}flush(t){p(()=>this.flushInner(t))();}flushInner(t){if(this.buffer.size===0)return;let n=Date.now();if(t==="cadence"){if(this.inFlight||n-this.lastFlushMs<this.config.params.flushMinIntervalMs)return;this.lastFlushMs=n;}let r=this.buffer.drain(this.config.params.batchMaxEvents);this.send(r,t);}serialize(t){let n=_.fromPartial({sdkVersion:$e,appBuild:this.config.appBuild,context:this.config.context,sessionId:this.config.sessionId(),events:t});return JSON.stringify(_.toJSON(n))}send(t,n){if(t.length===0)return;let r=this.serialize(t);if(r.length>this.config.params.batchMaxBodyBytes&&t.length>1){let i=Math.ceil(t.length/2);this.send(t.slice(0,i),n),this.send(t.slice(i),n);return}if(n==="pagehide"){this.sendBeaconOrKeepalive(r);return}this.sendCompressed(r);}sendBeaconOrKeepalive(t){try{if(typeof navigator<"u"&&typeof navigator.sendBeacon=="function"){let n=new Blob([t],{type:"text/plain"});if(navigator.sendBeacon(this.keyedEndpoint(),n))return}}catch{}this.postRaw(t);}async sendCompressed(t){this.inFlight=true;try{let n=await ze(t);n!==null?await this.post(n,{"Content-Type":"application/json","Content-Encoding":"gzip"}):await this.post(t,{"Content-Type":"application/json"});}catch{}finally{this.inFlight=false;}}postRaw(t){try{this.post(t,{"Content-Type":"application/json"}).catch(()=>{});}catch{}}keyedEndpoint(){let t=this.config.endpoint.includes("?")?"&":"?";return `${this.config.endpoint}${t}k=${encodeURIComponent(this.config.apiKey)}`}post(t,n){return (this.config.fetchFn??fetch)(this.config.endpoint,{method:"POST",headers:{...n,"X-UNNOODLE-API-KEY":this.config.apiKey},body:t,keepalive:true,credentials:"omit"}).then(i=>{})}};async function ze(e){if(typeof CompressionStream!="function"||typeof TextEncoder!="function")return null;try{let t=new CompressionStream("gzip"),n=t.writable.getWriter();n.write(new TextEncoder().encode(e)),n.close();let r=t.readable.getReader(),i=[],o=0;for(;;){let{done:l,value:h}=await r.read();if(l)break;i.push(h),o+=h.length;}let a=new Uint8Array(o),s=0;for(let l of i)a.set(l,s),s+=l.length;return a}catch{return null}}function We(e){if(typeof e.apiKey!="string"||e.apiKey.length===0)throw new Error("@unnoodle/browser/flow: apiKey is required (closure C-2)");let t={...L,...e.__params};X(e.debug===true);let n=typeof e.appBuild=="function"?e.appBuild():e.appBuild??"dev",r=e.redaction?.ignoreSelectors??[],i=Date.now(),o=ye(t.continuityWindowMs,t.continuityBlobMaxBytes),a=o.resumeOrStart(n),s=Z(t.idleFrameBudgetMs),l=he(t.quiescenceMutationQuietMs,t.quiescenceNetworkQuietMs),h=Ee(e.goals??[],t.rageClickCount,t.rageClickWindowMs),E=new U({endpoint:e.endpoint,apiKey:e.apiKey,context:e.context,appBuild:n,sessionId:()=>a.sessionId,params:t}),T=Te({policyUrl:e.policyEndpoint??Qe(e.endpoint),apiKey:e.apiKey,context:e.context,appBuild:n,params:t,sessionStartMs:i}),g=Ie({params:t,appBuild:n,membership:()=>fe,gateKeyVersionOk:()=>true}),m=new A(t.admissionCapacity,t.admissionRefillPerSec),c=null,f=null,S=false,M=(u,y,I,v)=>{let w=u.descriptor;if(w===void 0)return;let D=g.decide(J(a.currentNode?.descriptor??null,w,I),v,T.current());D!=="silent"&&(m.take()?(a.seq+=1,E.enqueue(N.fromPartial({eventId:`${a.sessionId}:${a.seq}`,sessionId:a.sessionId,seq:a.seq,ts:Date.now(),type:D==="heartbeat"?3:y,route:I,appBuild:n,to:u,from:a.currentNode??void 0}))):E.countDrop()),a.currentNode=u,o.persist(a,n);},k=[],H=e.debug===true?u=>{k.length>=512&&k.shift(),k.push(performance.now()-u);}:null,O=p(u=>{if(S)return;let y=H!==null?performance.now():0,I=ie(u.target);if(I===null)return;c?.interrupt?.();let v={targetRef:new WeakRef(I),kind:1,ts:Date.now(),pathname:location.pathname};c=v,s.schedule(()=>G(v)),H?.(y);}),G=u=>{if(S)return;let y=u.targetRef.deref();if(y===void 0){c===u&&(c=null);return}if(te(y,r)){c===u&&(c=null);return}let I=oe(y),v={localKey:se(I),descriptor:I},w=re({pathname:u.pathname}),D=h.noteInteraction(v.localKey,u.ts),Y=h.goalsFor(y,w);if(c!==u||f!==null&&f>=u.ts){c===u&&(c=null);let V={settledTs:Date.now(),mutated:false,navigated:f!==null,timedOut:false,interrupted:true};M(v,u.kind,w,h.derive(V,D,Y));return}let $=l.awaitSettled({hardCapMs:t.quiescenceHardCapMs});u.interrupt=$.interrupt,$.promise.then(p(V=>{S||(c===u&&(c=null),M(v,u.kind,w,h.derive(V,D,Y)));}));},ve=me(u=>{S||(l.noteNavigation(),f=u.ts,c?.interrupt?.(),s.schedule(()=>{f=null;let y=ae(u.route);M({localKey:`page:${u.route}`,descriptor:y},2,u.route,[]);}));},()=>{c!==null&&(f=Date.now(),G(c),f=null),o.persist(a,n),E.flush("pagehide");}),C={capture:true,passive:true};document.addEventListener("click",O,C),document.addEventListener("submit",O,C);let be=setInterval(p(()=>E.flush("cadence")),t.flushMinIntervalMs);return T.start(),e.debug===true&&(window.__unnoodle_flow_stats={get pending(){return E.pending},get dropped(){return E.droppedTotal},get phase(){return T.current().phase},get session(){return {id:a.sessionId,seq:a.seq,resumed:a.resumed}},get hotPath(){let u=[...k].sort((I,v)=>I-v),y=I=>u[Math.min(u.length-1,Math.floor(I*u.length))]??0;return {count:u.length,p50:y(.5),p99:y(.99)}}}),{stop:p(()=>{S||(S=!0,clearInterval(be),document.removeEventListener("click",O,C),document.removeEventListener("submit",O,C),ve.stop(),l.stop(),T.stop(),s.stop(),E.flush("pagehide"));})}}function Qe(e){try{let t=new URL(e);return t.pathname="/policy",t.search="",t.toString()}catch{return "/policy"}}exports.DEFAULT_PARAMS=L;exports.GATE_KEY_VERSION=Fe;exports.fnv1a64=pe;exports.gateKey=J;exports.normalizeLabel=de;exports.startFlowSensor=We;//# sourceMappingURL=index.cjs.map
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../contracts/gen/ts/src/unnoodle/flow/v0/event.ts","../../../../contracts/gen/ts/src/unnoodle/flow/v0/policy.ts","../../src/flow/params.ts","../../src/flow/failSilent.ts","../../src/flow/idleScheduler.ts","../../src/flow/redaction.ts","../../src/flow/descriptor.ts","../../src/flow/keyer.ts","../../src/flow/gateKey.ts","../../src/flow/membership.ts","../../src/flow/quiescence.ts","../../src/flow/navigation.ts","../../src/flow/continuity.ts","../../src/flow/outcome.ts","../../src/flow/policy.ts","../../src/flow/tokenBucket.ts","../../src/flow/gate.ts","../../src/flow/ringBuffer.ts","../../src/flow/uploader.ts","../../src/flow/sensor.ts"],"names":["eventTypeFromJSON","object","eventTypeToJSON","createBaseElementDescriptor","ElementDescriptor","isSet","message","obj","base","createBaseNodeRef","NodeRef","createBaseEvent","Event","createBaseEventBatch","EventBatch","e","value","createBaseCapturePolicy","CapturePolicy","DEFAULT_PARAMS","debugEnabled","seen","setFailSilentDebug","on","failSilent","fn","args","err","sig","SHIM_DELAY_MS","SHIM_BUDGET_MS","createIdleScheduler","frameBudgetMs","queue","scheduled","stopped","handle","hasRic","run","deadline","task","request","d","start","IGNORE_ATTRIBUTE","VALUE_BEARING_TAGS","isIgnored","el","extraSelectors","selector","redactedLabel","aria","cap","collapse","sanitizedRoute","loc","capUnits","s","n","last","ANCESTOR_PATH_MAX_DEPTH","ANCESTOR_ENTRY_MAX","INTERACTIVE_SELECTOR","resolveInteractive","target","buildDescriptor","ancestorPath","parts","node","tag","pageDescriptor","route","localKey","djb2","h","i","GATE_KEY_VERSION","normalizeLabel","label","collapsed","trimmed","javaTrim","end","normDescriptor","gateKey","from","to","fnv1a64","FNV_OFFSET","FNV_PRIME","MASK64","c","NOTHING_LEARNED","createQuiescenceDetector","mutationQuietMs","networkQuietMs","lastMutationTs","lastNetworkTs","navSeen","mo","po","hardCapMs","startTs","startMutation","interrupted","timer","resolveFn","promise","resolve","finish","timedOut","poll","now","mutationQuiet","networkQuiet","attachNavigationListeners","sink","onPageHide","safeSink","originalPush","originalReplace","result","onPop","onHash","onHide","CONTINUITY_KEY","createContinuityStore","windowMs","maxBytes","storage","defaultStorage","appBuild","blob","read","newSessionId","json","raw","b","isStructuralNodeRef","ref","fields","f","createOutcomeDeriver","goals","rageCount","rageWindowMs","recent","out","g","routeMatches","ts","cutoff","r","settled","rage","hints","pattern","createPolicyClient","opts","params","fetchFn","cacheKey","cached","readCache","retryMs","entry","writeCache","policy","fetchedAtMs","refresh","url","res","schedule","inMs","ageMs","refreshMs","TokenBucket","capacity","refillPerSec","elapsed","createCaptureGate","heartbeatBucket","random","edgeKey","state","phase","RingBuffer","item","take","idx","SDK_VERSION","Uploader","config","event","reason","events","batch","mid","gz","gzip","sep","body","headers","cs","writer","reader","chunks","total","done","offset","startFlowSensor","ignoreSelectors","sessionStartMs","continuity","session","scheduler","quiescence","outcome","uploader","policyClient","derivePolicyUrl","gate","admission","pending","navQueuedTs","closeStep","type","toDescriptor","decision","hotPathSamples","recordHotPath","t0","onInteraction","domEvent","step","sliceA","descriptor","nav","listenerOptions","flushTimer","a","q","p","ingestEndpoint","u"],"mappings":"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","file":"index.cjs","sourcesContent":["// Code generated by protoc-gen-ts_proto. DO NOT EDIT.\n// versions:\n// protoc-gen-ts_proto v2.12.4\n// protoc unknown\n// source: unnoodle/flow/v0/event.proto\n\n/* eslint-disable */\n\nexport const protobufPackage = \"unnoodle.flow.v0\";\n\nexport enum EventType {\n EVENT_TYPE_UNSPECIFIED = 0,\n /** EVENT_TYPE_INTERACTION - click, submit, input-change, ... */\n EVENT_TYPE_INTERACTION = 1,\n /** EVENT_TYPE_NAVIGATION - route / history change */\n EVENT_TYPE_NAVIGATION = 2,\n /** EVENT_TYPE_HEARTBEAT - sampled confirmation on a learned path (Phase 2) */\n EVENT_TYPE_HEARTBEAT = 3,\n UNRECOGNIZED = -1,\n}\n\nexport function eventTypeFromJSON(object: any): EventType {\n switch (object) {\n case 0:\n case \"EVENT_TYPE_UNSPECIFIED\":\n return EventType.EVENT_TYPE_UNSPECIFIED;\n case 1:\n case \"EVENT_TYPE_INTERACTION\":\n return EventType.EVENT_TYPE_INTERACTION;\n case 2:\n case \"EVENT_TYPE_NAVIGATION\":\n return EventType.EVENT_TYPE_NAVIGATION;\n case 3:\n case \"EVENT_TYPE_HEARTBEAT\":\n return EventType.EVENT_TYPE_HEARTBEAT;\n case -1:\n case \"UNRECOGNIZED\":\n default:\n return EventType.UNRECOGNIZED;\n }\n}\n\nexport function eventTypeToJSON(object: EventType): string {\n switch (object) {\n case EventType.EVENT_TYPE_UNSPECIFIED:\n return \"EVENT_TYPE_UNSPECIFIED\";\n case EventType.EVENT_TYPE_INTERACTION:\n return \"EVENT_TYPE_INTERACTION\";\n case EventType.EVENT_TYPE_NAVIGATION:\n return \"EVENT_TYPE_NAVIGATION\";\n case EventType.EVENT_TYPE_HEARTBEAT:\n return \"EVENT_TYPE_HEARTBEAT\";\n case EventType.UNRECOGNIZED:\n default:\n return \"UNRECOGNIZED\";\n }\n}\n\n/**\n * ElementDescriptor — a structural, REDACTED description of a DOM element.\n *\n * PRIVACY INVARIANT (Principle #4): structural only. No input values, no\n * secrets. `label` is a redacted, length-capped accessible name / visible text.\n * A descriptor carrying user content is a bug, not a schema question.\n */\nexport interface ElementDescriptor {\n /** e.g. \"button\", \"a\", \"input\" */\n tag: string;\n /** ARIA role or inferred; \"\" = unknown */\n role: string;\n /** redacted accessible name / visible text (capped) */\n label: string;\n /** id / data-testid if present; \"\" = absent */\n testId: string;\n /** structural signature (ancestor roles/tags, not nth-child) */\n ancestorPath: string;\n}\n\n/**\n * NodeRef — a reference to a UI node.\n *\n * `local_key` is cheap and stable WITHIN a session only (edge threading).\n * The canonical Fingerprint is computed SERVER-SIDE (Stage 4) from `descriptor`\n * — it is deliberately NOT in this contract (ADR-0003, version-skew).\n */\nexport interface NodeRef {\n localKey: string;\n descriptor?: ElementDescriptor | undefined;\n}\n\n/** Event — the smallest unit the Sensor emits (ADR-0003). */\nexport interface Event {\n /** unique */\n eventId: string;\n /** sensor-local, opaque */\n sessionId: string;\n /** per-session monotonic (ordering + dedupe) */\n seq: number;\n /** epoch millis */\n ts: number;\n type: EventType;\n /** sanitised path (tokens / PII stripped) */\n route: string;\n /** host build; lets fingerprints reset on deploy */\n appBuild: string;\n /** the node the event happened on */\n to?:\n | NodeRef\n | undefined;\n /** previous node; UNSET = first event in the session */\n from?: NodeRef | undefined;\n}\n\n/**\n * EventBatch — fire-and-forget batch, Sensor -> Gateway.\n *\n * WIRE FORMAT (ADR-0001): the edge is JSON (gzip) whose shape mirrors this\n * message field-for-field; the Gateway transcodes to Protobuf internally.\n */\nexport interface EventBatch {\n sdkVersion: string;\n appBuild: string;\n /** config slug; AUTHORITATIVE tenant is stamped by the Gateway (see ingest.proto) */\n context: string;\n sessionId: string;\n events: Event[];\n}\n\nfunction createBaseElementDescriptor(): ElementDescriptor {\n return { tag: \"\", role: \"\", label: \"\", testId: \"\", ancestorPath: \"\" };\n}\n\nexport const ElementDescriptor: MessageFns<ElementDescriptor> = {\n fromJSON(object: any): ElementDescriptor {\n return {\n tag: isSet(object.tag) ? globalThis.String(object.tag) : \"\",\n role: isSet(object.role) ? globalThis.String(object.role) : \"\",\n label: isSet(object.label) ? globalThis.String(object.label) : \"\",\n testId: isSet(object.testId)\n ? globalThis.String(object.testId)\n : isSet(object.test_id)\n ? globalThis.String(object.test_id)\n : \"\",\n ancestorPath: isSet(object.ancestorPath)\n ? globalThis.String(object.ancestorPath)\n : isSet(object.ancestor_path)\n ? globalThis.String(object.ancestor_path)\n : \"\",\n };\n },\n\n toJSON(message: ElementDescriptor): unknown {\n const obj: any = {};\n if (message.tag !== \"\") {\n obj.tag = message.tag;\n }\n if (message.role !== \"\") {\n obj.role = message.role;\n }\n if (message.label !== \"\") {\n obj.label = message.label;\n }\n if (message.testId !== \"\") {\n obj.testId = message.testId;\n }\n if (message.ancestorPath !== \"\") {\n obj.ancestorPath = message.ancestorPath;\n }\n return obj;\n },\n\n create<I extends Exact<DeepPartial<ElementDescriptor>, I>>(base?: I): ElementDescriptor {\n return ElementDescriptor.fromPartial(base ?? ({} as any));\n },\n fromPartial<I extends Exact<DeepPartial<ElementDescriptor>, I>>(object: I): ElementDescriptor {\n const message = createBaseElementDescriptor();\n message.tag = object.tag ?? \"\";\n message.role = object.role ?? \"\";\n message.label = object.label ?? \"\";\n message.testId = object.testId ?? \"\";\n message.ancestorPath = object.ancestorPath ?? \"\";\n return message;\n },\n};\n\nfunction createBaseNodeRef(): NodeRef {\n return { localKey: \"\", descriptor: undefined };\n}\n\nexport const NodeRef: MessageFns<NodeRef> = {\n fromJSON(object: any): NodeRef {\n return {\n localKey: isSet(object.localKey)\n ? globalThis.String(object.localKey)\n : isSet(object.local_key)\n ? globalThis.String(object.local_key)\n : \"\",\n descriptor: isSet(object.descriptor) ? ElementDescriptor.fromJSON(object.descriptor) : undefined,\n };\n },\n\n toJSON(message: NodeRef): unknown {\n const obj: any = {};\n if (message.localKey !== \"\") {\n obj.localKey = message.localKey;\n }\n if (message.descriptor !== undefined) {\n obj.descriptor = ElementDescriptor.toJSON(message.descriptor);\n }\n return obj;\n },\n\n create<I extends Exact<DeepPartial<NodeRef>, I>>(base?: I): NodeRef {\n return NodeRef.fromPartial(base ?? ({} as any));\n },\n fromPartial<I extends Exact<DeepPartial<NodeRef>, I>>(object: I): NodeRef {\n const message = createBaseNodeRef();\n message.localKey = object.localKey ?? \"\";\n message.descriptor = (object.descriptor !== undefined && object.descriptor !== null)\n ? ElementDescriptor.fromPartial(object.descriptor)\n : undefined;\n return message;\n },\n};\n\nfunction createBaseEvent(): Event {\n return {\n eventId: \"\",\n sessionId: \"\",\n seq: 0,\n ts: 0,\n type: 0,\n route: \"\",\n appBuild: \"\",\n to: undefined,\n from: undefined,\n };\n}\n\nexport const Event: MessageFns<Event> = {\n fromJSON(object: any): Event {\n return {\n eventId: isSet(object.eventId)\n ? globalThis.String(object.eventId)\n : isSet(object.event_id)\n ? globalThis.String(object.event_id)\n : \"\",\n sessionId: isSet(object.sessionId)\n ? globalThis.String(object.sessionId)\n : isSet(object.session_id)\n ? globalThis.String(object.session_id)\n : \"\",\n seq: isSet(object.seq) ? globalThis.Number(object.seq) : 0,\n ts: isSet(object.ts) ? globalThis.Number(object.ts) : 0,\n type: isSet(object.type) ? eventTypeFromJSON(object.type) : 0,\n route: isSet(object.route) ? globalThis.String(object.route) : \"\",\n appBuild: isSet(object.appBuild)\n ? globalThis.String(object.appBuild)\n : isSet(object.app_build)\n ? globalThis.String(object.app_build)\n : \"\",\n to: isSet(object.to) ? NodeRef.fromJSON(object.to) : undefined,\n from: isSet(object.from) ? NodeRef.fromJSON(object.from) : undefined,\n };\n },\n\n toJSON(message: Event): unknown {\n const obj: any = {};\n if (message.eventId !== \"\") {\n obj.eventId = message.eventId;\n }\n if (message.sessionId !== \"\") {\n obj.sessionId = message.sessionId;\n }\n if (message.seq !== 0) {\n obj.seq = Math.round(message.seq);\n }\n if (message.ts !== 0) {\n obj.ts = Math.round(message.ts);\n }\n if (message.type !== 0) {\n obj.type = eventTypeToJSON(message.type);\n }\n if (message.route !== \"\") {\n obj.route = message.route;\n }\n if (message.appBuild !== \"\") {\n obj.appBuild = message.appBuild;\n }\n if (message.to !== undefined) {\n obj.to = NodeRef.toJSON(message.to);\n }\n if (message.from !== undefined) {\n obj.from = NodeRef.toJSON(message.from);\n }\n return obj;\n },\n\n create<I extends Exact<DeepPartial<Event>, I>>(base?: I): Event {\n return Event.fromPartial(base ?? ({} as any));\n },\n fromPartial<I extends Exact<DeepPartial<Event>, I>>(object: I): Event {\n const message = createBaseEvent();\n message.eventId = object.eventId ?? \"\";\n message.sessionId = object.sessionId ?? \"\";\n message.seq = object.seq ?? 0;\n message.ts = object.ts ?? 0;\n message.type = object.type ?? 0;\n message.route = object.route ?? \"\";\n message.appBuild = object.appBuild ?? \"\";\n message.to = (object.to !== undefined && object.to !== null) ? NodeRef.fromPartial(object.to) : undefined;\n message.from = (object.from !== undefined && object.from !== null) ? NodeRef.fromPartial(object.from) : undefined;\n return message;\n },\n};\n\nfunction createBaseEventBatch(): EventBatch {\n return { sdkVersion: \"\", appBuild: \"\", context: \"\", sessionId: \"\", events: [] };\n}\n\nexport const EventBatch: MessageFns<EventBatch> = {\n fromJSON(object: any): EventBatch {\n return {\n sdkVersion: isSet(object.sdkVersion)\n ? globalThis.String(object.sdkVersion)\n : isSet(object.sdk_version)\n ? globalThis.String(object.sdk_version)\n : \"\",\n appBuild: isSet(object.appBuild)\n ? globalThis.String(object.appBuild)\n : isSet(object.app_build)\n ? globalThis.String(object.app_build)\n : \"\",\n context: isSet(object.context) ? globalThis.String(object.context) : \"\",\n sessionId: isSet(object.sessionId)\n ? globalThis.String(object.sessionId)\n : isSet(object.session_id)\n ? globalThis.String(object.session_id)\n : \"\",\n events: globalThis.Array.isArray(object?.events)\n ? object.events.map((e: any) => Event.fromJSON(e))\n : [],\n };\n },\n\n toJSON(message: EventBatch): unknown {\n const obj: any = {};\n if (message.sdkVersion !== \"\") {\n obj.sdkVersion = message.sdkVersion;\n }\n if (message.appBuild !== \"\") {\n obj.appBuild = message.appBuild;\n }\n if (message.context !== \"\") {\n obj.context = message.context;\n }\n if (message.sessionId !== \"\") {\n obj.sessionId = message.sessionId;\n }\n if (message.events?.length) {\n obj.events = message.events.map((e) => Event.toJSON(e));\n }\n return obj;\n },\n\n create<I extends Exact<DeepPartial<EventBatch>, I>>(base?: I): EventBatch {\n return EventBatch.fromPartial(base ?? ({} as any));\n },\n fromPartial<I extends Exact<DeepPartial<EventBatch>, I>>(object: I): EventBatch {\n const message = createBaseEventBatch();\n message.sdkVersion = object.sdkVersion ?? \"\";\n message.appBuild = object.appBuild ?? \"\";\n message.context = object.context ?? \"\";\n message.sessionId = object.sessionId ?? \"\";\n message.events = object.events?.map((e) => Event.fromPartial(e)) || [];\n return message;\n },\n};\n\ntype Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;\n\nexport type DeepPartial<T> = T extends Builtin ? T\n : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>\n : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>\n : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }\n : Partial<T>;\n\ntype KeysOfUnion<T> = T extends T ? keyof T : never;\nexport type Exact<P, I extends P> = P extends Builtin ? P\n : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };\n\nfunction isSet(value: any): boolean {\n return value !== null && value !== undefined;\n}\n\nexport interface MessageFns<T> {\n fromJSON(object: any): T;\n toJSON(message: T): unknown;\n create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;\n fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;\n}\n","// Code generated by protoc-gen-ts_proto. DO NOT EDIT.\n// versions:\n// protoc-gen-ts_proto v2.12.4\n// protoc unknown\n// source: unnoodle/flow/v0/policy.proto\n\n/* eslint-disable */\n\nexport const protobufPackage = \"unnoodle.flow.v0\";\n\n/**\n * CapturePolicy — the Sensor's instruction on what to capture.\n *\n * v0 SKELETON: a trivial \"capture everything\" warm-up. The `learned_edges`\n * membership structure (Bloom vs versioned set) that lets the Sensor stay silent\n * on known transitions is DEFERRED to v1 / Phase 2 (ADR-0002; Stage 1 §10 open Qs).\n */\nexport interface CapturePolicy {\n /** build this policy was learned on; mismatch => sensor treats all as novel */\n appBuild: string;\n /** monotonic; bump => sensor refreshes */\n policyVersion: number;\n /** skeleton warm-up: true = capture everything */\n captureAll: boolean;\n /** e.g. 0.01; trickle on learned paths (Phase 2) */\n heartbeatRate: number;\n /** when the sensor should re-pull */\n refreshAfterSeconds: number;\n}\n\nfunction createBaseCapturePolicy(): CapturePolicy {\n return { appBuild: \"\", policyVersion: 0, captureAll: false, heartbeatRate: 0, refreshAfterSeconds: 0 };\n}\n\nexport const CapturePolicy: MessageFns<CapturePolicy> = {\n fromJSON(object: any): CapturePolicy {\n return {\n appBuild: isSet(object.appBuild)\n ? globalThis.String(object.appBuild)\n : isSet(object.app_build)\n ? globalThis.String(object.app_build)\n : \"\",\n policyVersion: isSet(object.policyVersion)\n ? globalThis.Number(object.policyVersion)\n : isSet(object.policy_version)\n ? globalThis.Number(object.policy_version)\n : 0,\n captureAll: isSet(object.captureAll)\n ? globalThis.Boolean(object.captureAll)\n : isSet(object.capture_all)\n ? globalThis.Boolean(object.capture_all)\n : false,\n heartbeatRate: isSet(object.heartbeatRate)\n ? globalThis.Number(object.heartbeatRate)\n : isSet(object.heartbeat_rate)\n ? globalThis.Number(object.heartbeat_rate)\n : 0,\n refreshAfterSeconds: isSet(object.refreshAfterSeconds)\n ? globalThis.Number(object.refreshAfterSeconds)\n : isSet(object.refresh_after_seconds)\n ? globalThis.Number(object.refresh_after_seconds)\n : 0,\n };\n },\n\n toJSON(message: CapturePolicy): unknown {\n const obj: any = {};\n if (message.appBuild !== \"\") {\n obj.appBuild = message.appBuild;\n }\n if (message.policyVersion !== 0) {\n obj.policyVersion = Math.round(message.policyVersion);\n }\n if (message.captureAll !== false) {\n obj.captureAll = message.captureAll;\n }\n if (message.heartbeatRate !== 0) {\n obj.heartbeatRate = message.heartbeatRate;\n }\n if (message.refreshAfterSeconds !== 0) {\n obj.refreshAfterSeconds = Math.round(message.refreshAfterSeconds);\n }\n return obj;\n },\n\n create<I extends Exact<DeepPartial<CapturePolicy>, I>>(base?: I): CapturePolicy {\n return CapturePolicy.fromPartial(base ?? ({} as any));\n },\n fromPartial<I extends Exact<DeepPartial<CapturePolicy>, I>>(object: I): CapturePolicy {\n const message = createBaseCapturePolicy();\n message.appBuild = object.appBuild ?? \"\";\n message.policyVersion = object.policyVersion ?? 0;\n message.captureAll = object.captureAll ?? false;\n message.heartbeatRate = object.heartbeatRate ?? 0;\n message.refreshAfterSeconds = object.refreshAfterSeconds ?? 0;\n return message;\n },\n};\n\ntype Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;\n\nexport type DeepPartial<T> = T extends Builtin ? T\n : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>\n : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>\n : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }\n : Partial<T>;\n\ntype KeysOfUnion<T> = T extends T ? keyof T : never;\nexport type Exact<P, I extends P> = P extends Builtin ? P\n : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };\n\nfunction isSet(value: any): boolean {\n return value !== null && value !== undefined;\n}\n\nexport interface MessageFns<T> {\n fromJSON(object: any): T;\n toJSON(message: T): unknown;\n create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;\n fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;\n}\n","/**\n * Flow Sensor parameters — mirrors LLD §8 (the one place every tunable lives).\n * Values marked `⚠ corpus` in the LLD are provisional until validated against\n * the alignment-spike corpus; change them HERE and in the LLD table together.\n */\nexport interface FlowParams {\n ringBufferCapacity: number;\n batchMaxEvents: number;\n batchMaxBodyBytes: number;\n flushMinIntervalMs: number;\n admissionCapacity: number;\n admissionRefillPerSec: number;\n warmupWindowMs: number;\n degradedSampleRate: number;\n policyStalenessFactor: number;\n policyRetryBaseMs: number;\n policyRetryMaxMs: number;\n continuityWindowMs: number;\n continuityBlobMaxBytes: number;\n quiescenceMutationQuietMs: number;\n quiescenceNetworkQuietMs: number;\n quiescenceHardCapMs: number;\n rageClickCount: number;\n rageClickWindowMs: number;\n heartbeatSessionCap: number;\n idleFrameBudgetMs: number;\n gateKeyLabelCap: number;\n}\n\nexport const DEFAULT_PARAMS: FlowParams = {\n ringBufferCapacity: 500,\n batchMaxEvents: 100,\n batchMaxBodyBytes: 60 * 1024, // keepalive/sendBeacon quota is 64 KB (browser-enforced)\n flushMinIntervalMs: 5000,\n admissionCapacity: 100, // ⚠ corpus\n admissionRefillPerSec: 1, // = 60/min ⚠ corpus\n warmupWindowMs: 15 * 60 * 1000, // ⚠ corpus\n degradedSampleRate: 0.1, // ⚠ corpus\n policyStalenessFactor: 6,\n policyRetryBaseMs: 30_000,\n policyRetryMaxMs: 10 * 60 * 1000,\n continuityWindowMs: 30 * 60 * 1000, // Stage-4 inactivity-gap alignment (HLD §5.7)\n continuityBlobMaxBytes: 4096,\n quiescenceMutationQuietMs: 200, // ⚠ corpus\n quiescenceNetworkQuietMs: 500, // ⚠ corpus\n quiescenceHardCapMs: 3000, // ⚠ corpus\n rageClickCount: 3, // ⚠ corpus\n rageClickWindowMs: 1000, // ⚠ corpus\n heartbeatSessionCap: 20,\n idleFrameBudgetMs: 4, // design §9.1, binding\n gateKeyLabelCap: 64,\n};\n","/**\n * Fail-silent discipline (design §9.4): the sensor may NEVER throw into the\n * host. Every host-triggered entry point is wrapped. In debug mode each unique\n * error signature is logged once (LLD §4); production swallows silently.\n */\nlet debugEnabled = false;\nconst seen = new Set<string>();\n\nexport function setFailSilentDebug(on: boolean): void {\n debugEnabled = on;\n if (!on) seen.clear();\n}\n\nexport function failSilent<A extends unknown[], R>(\n fn: (...args: A) => R,\n): (...args: A) => R | undefined {\n return (...args: A) => {\n try {\n return fn(...args);\n } catch (err) {\n if (debugEnabled) {\n const sig = err instanceof Error ? `${err.name}:${err.message}` : String(err);\n if (!seen.has(sig)) {\n seen.add(sig);\n // eslint-disable-next-line no-console\n console.debug(\"[unnoodle/flow] swallowed:\", sig);\n }\n }\n return undefined;\n }\n };\n}\n","/**\n * Idle scheduler (LLD §2 / design §9.1): the ONLY way deferred work runs.\n * FIFO, time-sliced under the rIC deadline; yields when the remaining budget\n * drops below idleFrameBudgetMs. Safari (no requestIdleCallback) gets a\n * setTimeout shim with a synthetic deadline (LLD §4).\n */\nimport { failSilent } from \"./failSilent\";\n\ntype Task = () => void;\n\nexport interface IdleScheduler {\n schedule(task: Task): void;\n /** Cancel pending work (teardown). */\n stop(): void;\n}\n\nconst SHIM_DELAY_MS = 150;\nconst SHIM_BUDGET_MS = 8;\n\nexport function createIdleScheduler(frameBudgetMs: number): IdleScheduler {\n const queue: Task[] = [];\n let scheduled = false;\n let stopped = false;\n let handle: number | undefined;\n\n const hasRic = typeof requestIdleCallback === \"function\";\n\n const run = failSilent((deadline: { timeRemaining(): number }) => {\n scheduled = false;\n if (stopped) return;\n while (queue.length > 0 && deadline.timeRemaining() > frameBudgetMs) {\n const task = queue.shift() as Task;\n failSilent(task)();\n }\n if (queue.length > 0) request(); // yield — resume on the next idle period\n });\n\n function request(): void {\n if (scheduled || stopped) return;\n scheduled = true;\n if (hasRic) {\n handle = requestIdleCallback((d) => run(d));\n } else {\n handle = setTimeout(() => {\n const start = Date.now(); // budget starts when the slice RUNS\n run({ timeRemaining: () => Math.max(0, SHIM_BUDGET_MS - (Date.now() - start)) });\n }, SHIM_DELAY_MS) as unknown as number;\n }\n }\n\n return {\n schedule(task: Task): void {\n if (stopped) return;\n queue.push(task);\n request();\n },\n stop(): void {\n stopped = true;\n queue.length = 0;\n if (handle !== undefined) {\n if (hasRic) cancelIdleCallback(handle);\n else clearTimeout(handle);\n }\n },\n };\n}\n","/**\n * Default-deny redaction (design §9.2 — privacy budgets are BINDING, \"0 by\n * construction\"). Carried forward from the skeleton with its test suite.\n *\n * - No input values ever leave the page: descriptors are structural; this\n * module is the only place label text is produced, and it never reads\n * `.value` or form-control text.\n * - Routes carry no query strings / fragments (where tokens live).\n * - `[data-unnoodle-ignore]` regions (and configured selectors) are never\n * captured.\n */\nexport const LABEL_MAX_LENGTH = 40; // < the 64-unit wire cap (closure C-6)\n/** C-6: route wire cap — the gateway 400s longer strings; cap here, never there. */\nexport const ROUTE_MAX_LENGTH = 512;\nexport const IGNORE_ATTRIBUTE = \"data-unnoodle-ignore\";\n\n/** Tags whose text IS user content — their labels come from ARIA only. */\nconst VALUE_BEARING_TAGS = new Set([\"input\", \"textarea\", \"select\", \"option\"]);\n\n/** True if the element is inside a region the sensor must not observe. */\nexport function isIgnored(el: Element, extraSelectors: readonly string[] = []): boolean {\n if (el.closest(`[${IGNORE_ATTRIBUTE}]`) !== null) return true;\n for (const selector of extraSelectors) {\n try {\n if (el.closest(selector) !== null) return true;\n } catch {\n /* invalid configured selector — ignore the rule, not the region */\n }\n }\n return false;\n}\n\n/**\n * Redacted, capped label: ARIA name first; visible text only for elements\n * that cannot carry user-entered values.\n */\nexport function redactedLabel(el: Element): string {\n const aria = el.getAttribute(\"aria-label\");\n if (aria) return cap(collapse(aria));\n if (VALUE_BEARING_TAGS.has(el.tagName.toLowerCase())) return \"\";\n return cap(collapse(el.textContent ?? \"\"));\n}\n\n/** Sanitised route: pathname only — query strings and fragments never leave. */\nexport function sanitizedRoute(loc: Pick<Location, \"pathname\">): string {\n return capUnits(loc.pathname || \"/\", ROUTE_MAX_LENGTH);\n}\n\nfunction collapse(s: string): string {\n return s.replace(/\\s+/g, \" \").trim();\n}\n\nfunction cap(s: string): string {\n return capUnits(s, LABEL_MAX_LENGTH);\n}\n\n/**\n * Cap at n UTF-16 units WITHOUT splitting a surrogate pair: a lone high\n * surrogate JSON-encodes as an unpaired escape the gateway's strict parser\n * rejects — one truncated emoji label must never 400 a whole batch.\n */\nexport function capUnits(s: string, n: number): string {\n if (s.length <= n) return s;\n const last = s.charCodeAt(n - 1);\n return s.slice(0, last >= 0xd800 && last <= 0xdbff ? n - 1 : n);\n}\n","/**\n * Structural, redacted ElementDescriptor (ADR-0003) — the server computes the\n * canonical Fingerprint from this. Structural ONLY: a descriptor carrying user\n * content is a bug, not a schema question. Carried forward from the skeleton.\n */\nimport type { ElementDescriptor } from \"@unnoodle/flow-contracts\";\nimport { capUnits, redactedLabel } from \"./redaction\";\n\nconst ANCESTOR_PATH_MAX_DEPTH = 8;\n/** C-6: each ancestor entry capped at 64 UTF-16 units (role attrs are author-controlled). */\nconst ANCESTOR_ENTRY_MAX = 64;\n\n/** Elements the sensor considers meaningful interaction targets. */\nexport const INTERACTIVE_SELECTOR =\n 'button, a[href], [role=\"button\"], [role=\"link\"], [role=\"menuitem\"], [role=\"tab\"], input, select, textarea, summary';\n\n/** Nearest meaningful interactive ancestor of an event target, if any. */\nexport function resolveInteractive(target: EventTarget | null): Element | null {\n if (!(target instanceof Element)) return null;\n return target.closest(INTERACTIVE_SELECTOR);\n}\n\nexport function buildDescriptor(el: Element): ElementDescriptor {\n return {\n tag: el.tagName.toLowerCase(),\n role: el.getAttribute(\"role\") ?? \"\",\n label: redactedLabel(el),\n testId: el.getAttribute(\"data-testid\") ?? el.id ?? \"\",\n ancestorPath: ancestorPath(el),\n };\n}\n\n/**\n * Structural signature of the ancestry: role-or-tag per ancestor, outermost\n * first, depth-capped. Deliberately NO nth-child / ids — low cardinality is\n * what makes the server-side fingerprint mineable (design §5).\n */\nfunction ancestorPath(el: Element): string {\n const parts: string[] = [];\n let node: Element | null = el.parentElement;\n while (node !== null && parts.length < ANCESTOR_PATH_MAX_DEPTH) {\n const tag = node.tagName.toLowerCase();\n if (tag === \"html\") break;\n parts.push(capUnits(node.getAttribute(\"role\") ?? tag, ANCESTOR_ENTRY_MAX));\n node = node.parentElement;\n }\n return parts.reverse().join(\">\");\n}\n\n/** Synthetic page node for navigation events (LLD: route only — no title). */\nexport function pageDescriptor(route: string): ElementDescriptor {\n return { tag: \"page\", role: \"document\", label: route, testId: \"\", ancestorPath: \"\" };\n}\n","/**\n * The cheap LOCAL node key (ADR-0003, frozen at LLD §5.3): stable within a\n * session, used only to thread from→to edges. The canonical, cross-session\n * Fingerprint is computed SERVER-SIDE from the descriptor (Stage 4).\n */\nimport type { ElementDescriptor } from \"@unnoodle/flow-contracts\";\n\nexport function localKey(d: ElementDescriptor): string {\n if (d.testId) return `${d.tag}#${d.testId}`;\n return `${d.tag}@${djb2(`${d.role}|${d.label}|${d.ancestorPath}`)}`;\n}\n\n/** djb2 — tiny, fast, good enough for a within-session key. */\nfunction djb2(s: string): string {\n let h = 5381;\n for (let i = 0; i < s.length; i++) {\n h = ((h << 5) + h + s.charCodeAt(i)) | 0;\n }\n return (h >>> 0).toString(36);\n}\n","/**\n * GateKey v1 (HLD 5.2a, LLD 2.6) — the membership-test identity, computed\n * IDENTICALLY here and at Stage-6 policy-compile time. Deliberately dumb and\n * versioned; NOT the canonical Fingerprint (server-side, evolvable) and NOT\n * the localKey (session-local). Collisions are benign by construction:\n * miss => capture (safe), collision => silence healed like a Bloom FP.\n *\n * Reference vectors: /contracts/fixtures/gatekey-v1.json — shared with\n * Stage 6's implementation. Changing ANY rule here bumps GATE_KEY_VERSION.\n */\nimport type { ElementDescriptor } from \"@unnoodle/flow-contracts\";\n\nexport const GATE_KEY_VERSION = 1;\n\nconst FIELD_SEP = \"\u001e\"; // RS — between fields of one descriptor\nconst PART_SEP = \"\u001f\"; // US — between from / to / route\nconst NULL_FROM = \"∅\"; // \"empty set\" — from is null (first event in session)\nconst LABEL_CAP = 64;\n\n/** Normalise a label for identity purposes (LLD 2.6 table). */\nexport function normalizeLabel(label: string): string {\n const nfc = typeof label.normalize === \"function\" ? label.normalize(\"NFC\") : label;\n // AGREEMENT WITH THE PRODUCER (see contracts/fixtures/gatekey-v1.json).\n //\n // The learned set this key is tested against is produced by the JAVA\n // implementation (Stage 4's fold -> Stage 6's compile). Where the three\n // implementations cannot all agree, they follow Java — and Java's regex\n // \\s is ASCII-ONLY, while JS's \\s is the full Unicode set. Using JS's\n // \\s here MERGES labels Java keeps apart: \"Save\\u00a0\" would collapse\n // onto the key Java publishes for \"Save\".\n //\n // That direction is the dangerous one. Separating what Java merges is a\n // membership MISS, so the event is captured — harmless. Merging what\n // Java separates makes an edge nobody learned collide with a learned\n // one, and the gate silences it. At the sensor there is no counter and\n // no observe mode, so it would be silent and permanent.\n //\n // Java: replaceAll(\"\\\\s+\", \" \") over [ \\t\\n\\x0B\\f\\r], then trim(),\n // which strips every unit <= U+0020 at the ends.\n const collapsed = nfc.replace(/[ \\t\\n\\v\\f\\r]+/g, \" \");\n const trimmed = javaTrim(collapsed).toLowerCase();\n return trimmed.length > LABEL_CAP ? trimmed.slice(0, LABEL_CAP) : trimmed;\n}\n\n/** String.trim() as Java defines it: strip code units <= U+0020 at both ends. */\nfunction javaTrim(s: string): string {\n let start = 0;\n let end = s.length;\n while (start < end && s.charCodeAt(start) <= 0x20) start++;\n while (end > start && s.charCodeAt(end - 1) <= 0x20) end--;\n return start === 0 && end === s.length ? s : s.slice(start, end);\n}\n\nfunction normDescriptor(d: ElementDescriptor): string {\n return [\n d.tag.toLowerCase(),\n d.role,\n normalizeLabel(d.label),\n d.testId, // verbatim — host-authored identity\n d.ancestorPath, // built normalised by descriptor.ts\n ].join(FIELD_SEP);\n}\n\n/**\n * 64-bit GateKey as a BigInt. On a policy gate_key_version mismatch the\n * CALLER must skip membership and capture (safe direction, LLD 4) — this\n * function stays total and never throws.\n */\nexport function gateKey(\n from: ElementDescriptor | null,\n to: ElementDescriptor,\n route: string,\n): bigint {\n const s =\n (from === null ? NULL_FROM : normDescriptor(from)) +\n PART_SEP +\n normDescriptor(to) +\n PART_SEP +\n route;\n return fnv1a64(s);\n}\n\nconst FNV_OFFSET = BigInt(\"0xcbf29ce484222325\");\nconst FNV_PRIME = BigInt(\"0x100000001b3\");\nconst MASK64 = BigInt(\"0xffffffffffffffff\");\n\n/**\n * FNV-1a 64-bit over the UTF-16 code units of s, two bytes per unit,\n * little-endian — so the Java implementation (char -> 2 bytes LE) produces\n * identical keys. Both sides are pinned by the shared fixture vectors.\n */\nexport function fnv1a64(s: string): bigint {\n let h = FNV_OFFSET;\n for (let i = 0; i < s.length; i++) {\n const c = s.charCodeAt(i);\n h ^= BigInt(c & 0xff);\n h = (h * FNV_PRIME) & MASK64;\n h ^= BigInt(c >>> 8);\n h = (h * FNV_PRIME) & MASK64;\n }\n return h;\n}\n","/**\n * learned_edges membership structures (HLD §5.2, LLD §2.5): adaptive oneof —\n * exact set (small tenants, no FPs) or Bloom filter (1% FPR at scale). The\n * sensor only PROBES; sizing is Stage 6's job at policy-compile time.\n *\n * v0 note: the wire policy has no learned_edges yet (v1 contract delta) —\n * these are built and tested now, wired to the gate, and fed from the policy\n * once v1 lands.\n */\nexport interface Membership {\n has(key: bigint): boolean;\n}\n\n/** Exact set over sorted 64-bit keys (≤ ~1k edges). */\nexport class ExactSet implements Membership {\n private readonly sorted: bigint[];\n\n constructor(keys: readonly bigint[]) {\n this.sorted = [...keys].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n }\n\n has(key: bigint): boolean {\n let lo = 0;\n let hi = this.sorted.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >> 1;\n const v = this.sorted[mid] as bigint;\n if (v === key) return true;\n if (v < key) lo = mid + 1;\n else hi = mid - 1;\n }\n return false;\n }\n}\n\n/**\n * Bloom filter probe. k probes via double hashing h_i = (h1 + i·h2) mod m,\n * h1 = low 32 bits of the GateKey, h2 = high 32 bits | 1 (odd ⇒ full cycle).\n * No extra hash functions in the SDK (LLD §2.5).\n */\nexport class BloomFilter implements Membership {\n constructor(\n private readonly mBits: number,\n private readonly k: number,\n private readonly bits: Uint8Array,\n ) {}\n\n has(key: bigint): boolean {\n const h1 = Number(key & BigInt(0xffffffff)) >>> 0;\n const h2 = (Number((key >> BigInt(32)) & BigInt(0xffffffff)) | 1) >>> 0;\n for (let i = 0; i < this.k; i++) {\n const bit = (h1 + i * h2) % this.mBits;\n const byte = this.bits[bit >> 3] ?? 0;\n if ((byte & (1 << (bit & 7))) === 0) return false;\n }\n return true;\n }\n\n /** Test/Stage-6-mirror helper: set the bits for a key (not used at runtime). */\n static insert(mBits: number, k: number, bits: Uint8Array, key: bigint): void {\n const h1 = Number(key & BigInt(0xffffffff)) >>> 0;\n const h2 = (Number((key >> BigInt(32)) & BigInt(0xffffffff)) | 1) >>> 0;\n for (let i = 0; i < k; i++) {\n const bit = (h1 + i * h2) % mBits;\n bits[bit >> 3] = (bits[bit >> 3] ?? 0) | (1 << (bit & 7));\n }\n }\n}\n\n/** Nothing learned (v0 reality, and the safe default): everything is novel. */\nexport const NOTHING_LEARNED: Membership = { has: () => false };\n","/**\n * Quiescence detector (LLD 3.3): the settled state after an interaction.\n * Two quiet signals ANDed — mutation-quiet and network-quiet — under one hard\n * cap. Observers are SHARED SINGLETONS (never per-interaction attach/detach).\n * jsdom/older Safari without PerformanceObserver: network considered quiet\n * (feature-detected, LLD 4).\n */\nimport { failSilent } from \"./failSilent\";\n\nexport interface Settled {\n settledTs: number;\n mutated: boolean;\n navigated: boolean;\n timedOut: boolean;\n /** A newer interaction closed this step early (LLD 3.2 interrupted-step rule). */\n interrupted: boolean;\n}\n\nexport interface QuiescenceDetector {\n /** Resolves exactly once. `interrupt()` on the returned handle closes early. */\n awaitSettled(opts: { hardCapMs: number }): { promise: Promise<Settled>; interrupt: () => void };\n /** Mark that a navigation happened (fed by the navigation listener). */\n noteNavigation(): void;\n stop(): void;\n}\n\nexport function createQuiescenceDetector(\n mutationQuietMs: number,\n networkQuietMs: number,\n): QuiescenceDetector {\n let lastMutationTs = 0;\n let lastNetworkTs = 0;\n let navSeen = false;\n let mo: MutationObserver | undefined;\n let po: PerformanceObserver | undefined;\n\n if (typeof MutationObserver === \"function\" && typeof document !== \"undefined\") {\n mo = new MutationObserver(failSilent(() => {\n lastMutationTs = Date.now();\n }));\n mo.observe(document.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n characterData: true,\n });\n }\n if (typeof PerformanceObserver === \"function\") {\n try {\n po = new PerformanceObserver(failSilent(() => {\n lastNetworkTs = Date.now();\n }));\n po.observe({ entryTypes: [\"resource\"] });\n } catch {\n po = undefined; // entryType unsupported — network considered quiet\n }\n }\n\n return {\n awaitSettled({ hardCapMs }) {\n const startTs = Date.now();\n const startMutation = lastMutationTs;\n let interrupted = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let resolveFn: (s: Settled) => void;\n\n const promise = new Promise<Settled>((resolve) => {\n resolveFn = resolve;\n });\n\n const finish = (timedOut: boolean): void => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n resolveFn({\n settledTs: Date.now(),\n mutated: lastMutationTs > startMutation,\n navigated: navSeen,\n timedOut,\n interrupted,\n });\n navSeen = false;\n };\n\n const poll = failSilent(() => {\n const now = Date.now();\n if (now - startTs >= hardCapMs) {\n finish(true);\n return;\n }\n const mutationQuiet = now - Math.max(lastMutationTs, startTs) >= mutationQuietMs;\n const networkQuiet =\n po === undefined || now - Math.max(lastNetworkTs, startTs) >= networkQuietMs;\n if (mutationQuiet && networkQuiet) {\n finish(false);\n return;\n }\n timer = setTimeout(poll, Math.min(mutationQuietMs, 100));\n });\n timer = setTimeout(poll, mutationQuietMs);\n\n return {\n promise,\n interrupt: () => {\n interrupted = true;\n finish(false);\n },\n };\n },\n noteNavigation() {\n navSeen = true;\n },\n stop() {\n mo?.disconnect();\n po?.disconnect();\n },\n };\n}\n","/**\n * Navigation listener (LLD module map): SPA route changes via a REVERSIBLE\n * history patch + popstate/hashchange; MPA handoff via pagehide. Pure\n * web-platform APIs — every client router ultimately calls\n * pushState/replaceState, so this observes them all without knowing any\n * framework exists. Delegates to the host's original functions FIRST,\n * observes after (LLD 4: patch collision rule).\n */\nimport { failSilent } from \"./failSilent\";\n\nexport interface RawNavigation {\n route: string;\n ts: number;\n cause: \"push\" | \"replace\" | \"pop\" | \"hash\";\n}\n\nexport interface NavigationListener {\n stop(): void;\n}\n\nexport function attachNavigationListeners(\n sink: (n: RawNavigation) => void,\n onPageHide: () => void,\n): NavigationListener {\n const safeSink = failSilent(sink);\n const originalPush = history.pushState;\n const originalReplace = history.replaceState;\n\n history.pushState = function (this: History, ...args: Parameters<History[\"pushState\"]>) {\n const result = originalPush.apply(this, args); // host first\n safeSink({ route: location.pathname, ts: Date.now(), cause: \"push\" });\n return result;\n };\n history.replaceState = function (this: History, ...args: Parameters<History[\"replaceState\"]>) {\n const result = originalReplace.apply(this, args);\n safeSink({ route: location.pathname, ts: Date.now(), cause: \"replace\" });\n return result;\n };\n\n const onPop = failSilent(() =>\n safeSink({ route: location.pathname, ts: Date.now(), cause: \"pop\" }),\n );\n const onHash = failSilent(() =>\n safeSink({ route: location.pathname, ts: Date.now(), cause: \"hash\" }),\n );\n const onHide = failSilent(onPageHide);\n\n window.addEventListener(\"popstate\", onPop, { passive: true });\n window.addEventListener(\"hashchange\", onHash, { passive: true });\n window.addEventListener(\"pagehide\", onHide);\n\n return {\n stop: failSilent(() => {\n // Restore OUR link only — if the host patched after us, its patch stays.\n if (history.pushState !== originalPush) history.pushState = originalPush;\n if (history.replaceState !== originalReplace) history.replaceState = originalReplace;\n window.removeEventListener(\"popstate\", onPop);\n window.removeEventListener(\"hashchange\", onHash);\n window.removeEventListener(\"pagehide\", onHide);\n }) as () => void,\n };\n}\n","/**\n * Session continuity across full page loads (HLD 5.7, LLD 2.3 / 3.7): the MPA\n * fix from alignment-spike Finding 1. sessionStorage is per-tab by\n * construction — matching Session semantics; localStorage/cookies were\n * rejected (cross-tab bleed). Blob is structural-only; persisting a NodeRef\n * adds no new data class (descriptor is redacted before it exists).\n */\nimport type { NodeRef } from \"@unnoodle/flow-contracts\";\n\nexport const CONTINUITY_KEY = \"__unnoodle_flow_v1\";\n\nexport interface SessionState {\n sessionId: string;\n seq: number;\n currentNode: NodeRef | null;\n resumed: boolean;\n}\n\ninterface Blob1 {\n v: 1;\n sessionId: string;\n seq: number;\n appBuild: string;\n lastTs: number;\n currentNode: NodeRef | null;\n}\n\nexport interface ContinuityStore {\n resumeOrStart(appBuild: string): SessionState;\n persist(s: SessionState, appBuild: string): void;\n}\n\nexport function createContinuityStore(\n windowMs: number,\n maxBytes: number,\n storage: Pick<Storage, \"getItem\" | \"setItem\"> | null = defaultStorage(),\n): ContinuityStore {\n return {\n resumeOrStart(appBuild: string): SessionState {\n const blob = read(storage, appBuild, windowMs, maxBytes);\n if (blob !== null) {\n return { sessionId: blob.sessionId, seq: blob.seq, currentNode: blob.currentNode, resumed: true };\n }\n return { sessionId: newSessionId(), seq: 0, currentNode: null, resumed: false };\n },\n persist(s: SessionState, appBuild: string): void {\n if (storage === null) return;\n const blob: Blob1 = {\n v: 1,\n sessionId: s.sessionId,\n seq: s.seq,\n appBuild,\n lastTs: Date.now(),\n currentNode: s.currentNode,\n };\n try {\n const json = JSON.stringify(blob);\n if (json.length <= maxBytes) storage.setItem(CONTINUITY_KEY, json);\n } catch {\n /* quota / private mode — per-page sessions, never worse (LLD 4) */\n }\n },\n };\n}\n\n/** EVERY predicate must pass or the blob is discarded (LLD 2.3 — never partially trust). */\nfunction read(\n storage: Pick<Storage, \"getItem\" | \"setItem\"> | null,\n appBuild: string,\n windowMs: number,\n maxBytes: number,\n): Blob1 | null {\n if (storage === null) return null;\n try {\n const raw = storage.getItem(CONTINUITY_KEY);\n if (raw === null || raw.length > maxBytes) return null;\n const b = JSON.parse(raw) as Partial<Blob1>;\n if (b.v !== 1) return null;\n if (typeof b.sessionId !== \"string\" || b.sessionId.length === 0 || b.sessionId.length > 128) return null;\n if (typeof b.seq !== \"number\" || !Number.isInteger(b.seq) || b.seq < 0) return null;\n if (typeof b.appBuild !== \"string\" || b.appBuild !== appBuild) return null;\n if (typeof b.lastTs !== \"number\" || Date.now() - b.lastTs > windowMs || b.lastTs > Date.now() + 60_000) return null;\n if (b.currentNode !== null && !isStructuralNodeRef(b.currentNode)) return null;\n return b as Blob1;\n } catch {\n return null;\n }\n}\n\n/** Privacy backstop: the blob is INPUT now, not just output (LLD 2.3). */\nfunction isStructuralNodeRef(n: unknown): n is NodeRef {\n if (typeof n !== \"object\" || n === null) return false;\n const ref = n as Record<string, unknown>;\n if (typeof ref.localKey !== \"string\" || ref.localKey.length > 256) return false;\n const d = ref.descriptor as Record<string, unknown> | undefined;\n if (typeof d !== \"object\" || d === null) return false;\n const fields = [\"tag\", \"role\", \"label\", \"testId\", \"ancestorPath\"] as const;\n for (const f of fields) {\n if (typeof d[f] !== \"string\" || (d[f] as string).length > 512) return false;\n }\n if (Object.keys(d).length !== fields.length) return false; // no smuggled fields\n return true;\n}\n\nfunction defaultStorage(): Pick<Storage, \"getItem\" | \"setItem\"> | null {\n try {\n const s = window.sessionStorage;\n // Probe: private-mode Safari throws on write.\n s.setItem(\"__unnoodle_probe\", \"1\");\n s.removeItem(\"__unnoodle_probe\");\n return s;\n } catch {\n return null;\n }\n}\n\nfunction newSessionId(): string {\n try {\n return crypto.randomUUID();\n } catch {\n return `s-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n }\n}\n","/**\n * Outcome hints (HLD 5.4, LLD 3.4): only what quiescence gives for free —\n * dead_click, rage_click — plus host-declared goal matchers. The taxonomy is\n * CLOSED at these three; richer inference violates the dumb-sensor principle.\n *\n * v0 wire note: Event has no outcome_hints field yet (v1 contract delta) —\n * hints work locally (they bypass the CaptureGate) and go on the wire at v1.\n */\nimport type { Settled } from \"./quiescence\";\n\nexport type OutcomeHint =\n | { kind: \"dead_click\" }\n | { kind: \"rage_click\" }\n | { kind: \"goal\"; name: string };\n\nexport interface GoalMatcher {\n name: string;\n /** Sanitised-path match: exact, or prefix when ending with \"*\". */\n route?: string;\n /** CSS selector evaluated against the live target element (slice A). */\n selector?: string;\n}\n\nexport interface OutcomeDeriver {\n /** Call in slice A while the element is alive; result carried to slice B. */\n goalsFor(el: Element, route: string): OutcomeHint[];\n /** Call on each interaction (hot-path-adjacent, O(ring)); detects rage. */\n noteInteraction(localKey: string, ts: number): boolean;\n /** Slice B: assemble final hints. */\n derive(settled: Settled, rage: boolean, goals: OutcomeHint[]): OutcomeHint[];\n}\n\nexport function createOutcomeDeriver(\n goals: readonly GoalMatcher[],\n rageCount: number,\n rageWindowMs: number,\n): OutcomeDeriver {\n const recent: { key: string; ts: number }[] = []; // ring of 4 (LLD 2.7)\n\n return {\n goalsFor(el: Element, route: string): OutcomeHint[] {\n const out: OutcomeHint[] = [];\n for (const g of goals) {\n if (typeof g.name !== \"string\" || g.name.length === 0 || g.name.length > 32) continue;\n if (g.route !== undefined && !routeMatches(g.route, route)) continue;\n if (g.selector !== undefined) {\n try {\n if (!el.matches(g.selector)) continue;\n } catch {\n continue; // invalid selector — rule ignored, never thrown\n }\n }\n if (g.route !== undefined || g.selector !== undefined) out.push({ kind: \"goal\", name: g.name });\n }\n return out;\n },\n noteInteraction(localKey: string, ts: number): boolean {\n recent.push({ key: localKey, ts });\n if (recent.length > 4) recent.shift();\n const cutoff = ts - rageWindowMs;\n const sameTarget = recent.filter((r) => r.key === localKey && r.ts >= cutoff);\n return sameTarget.length >= rageCount;\n },\n derive(settled: Settled, rage: boolean, goals: OutcomeHint[]): OutcomeHint[] {\n const hints: OutcomeHint[] = [...goals];\n if (rage) hints.push({ kind: \"rage_click\" });\n if (settled.timedOut && !settled.mutated && !settled.navigated) hints.push({ kind: \"dead_click\" });\n return hints;\n },\n };\n}\n\nfunction routeMatches(pattern: string, route: string): boolean {\n if (pattern.endsWith(\"*\")) return route.startsWith(pattern.slice(0, -1));\n return route === pattern;\n}\n","/**\n * PolicyClient (HLD 3.2, LLD 2.4 / 3.6): pulls GET /policy on cadence, caches\n * in localStorage (tenant-level, per-origin), and derives the lifecycle phase\n * LAZILY at decision time — a suspended tab wakes up already in the right\n * state. The 202-attached policy from POST /ingest is NOT a supported input\n * (design 4.1: pull only — a silent sensor must still learn of re-opened\n * capture).\n */\nimport { CapturePolicy } from \"@unnoodle/flow-contracts\";\nimport { failSilent } from \"./failSilent\";\nimport type { FlowParams } from \"./params\";\n\nexport type PolicyPhase = \"warmup\" | \"degraded_sample\" | \"active\" | \"stale\" | \"expired\";\n\nexport interface PolicyState {\n phase: PolicyPhase;\n policy?: CapturePolicy;\n ageMs: number;\n}\n\nexport interface PolicyClient {\n current(): PolicyState;\n start(): void;\n stop(): void;\n}\n\ninterface CacheEntry {\n policy: unknown; // CapturePolicy.toJSON shape\n fetchedAtMs: number;\n appBuild: string;\n}\n\nexport function createPolicyClient(opts: {\n policyUrl: string; // e.g. http://localhost:8090/policy\n /** C-2: tenant auth — the tenant is the key's tenant, never a query param. */\n apiKey: string;\n context: string;\n appBuild: string;\n params: FlowParams;\n sessionStartMs: number;\n storage?: Pick<Storage, \"getItem\" | \"setItem\"> | null;\n fetchFn?: typeof fetch;\n}): PolicyClient {\n const { params } = opts;\n const storage = opts.storage === undefined ? defaultStorage() : opts.storage;\n const fetchFn = opts.fetchFn ?? (typeof fetch === \"function\" ? fetch : undefined);\n const cacheKey = `__unnoodle_policy_${opts.context}`;\n\n let cached: { policy: CapturePolicy; fetchedAtMs: number } | null = readCache();\n let retryMs = params.policyRetryBaseMs;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let stopped = false;\n\n function readCache(): { policy: CapturePolicy; fetchedAtMs: number } | null {\n if (storage === null) return null;\n try {\n const raw = storage.getItem(cacheKey);\n if (raw === null) return null;\n const entry = JSON.parse(raw) as Partial<CacheEntry>;\n if (typeof entry.fetchedAtMs !== \"number\" || entry.appBuild !== opts.appBuild) return null;\n return { policy: CapturePolicy.fromJSON(entry.policy), fetchedAtMs: entry.fetchedAtMs };\n } catch {\n return null;\n }\n }\n\n function writeCache(policy: CapturePolicy, fetchedAtMs: number): void {\n if (storage === null) return;\n try {\n const entry: CacheEntry = { policy: CapturePolicy.toJSON(policy), fetchedAtMs, appBuild: opts.appBuild };\n storage.setItem(cacheKey, JSON.stringify(entry));\n } catch {\n /* quota — in-memory only */\n }\n }\n\n async function refresh(): Promise<void> {\n if (stopped || fetchFn === undefined) return;\n try {\n const url = `${opts.policyUrl}?context=${encodeURIComponent(opts.context)}&appBuild=${encodeURIComponent(opts.appBuild)}`;\n const res = await fetchFn(url, {\n method: \"GET\",\n headers: { \"X-UNNOODLE-API-KEY\": opts.apiKey },\n });\n if (!res.ok) throw new Error(`policy ${res.status}`);\n const policy = CapturePolicy.fromJSON(await res.json());\n const now = Date.now();\n cached = { policy, fetchedAtMs: now };\n writeCache(policy, now);\n retryMs = params.policyRetryBaseMs;\n schedule(Math.max(1000, policy.refreshAfterSeconds * 1000));\n } catch {\n // Keep last cache (design 10 failure mode); retry with backoff 2x, capped.\n schedule(retryMs);\n retryMs = Math.min(retryMs * 2, params.policyRetryMaxMs);\n }\n }\n\n function schedule(inMs: number): void {\n if (stopped) return;\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(() => void failSilent(refresh)(), inMs);\n }\n\n return {\n current(): PolicyState {\n const now = Date.now();\n if (cached !== null) {\n const ageMs = now - cached.fetchedAtMs;\n const refreshMs = Math.max(1, cached.policy.refreshAfterSeconds) * 1000;\n if (ageMs <= refreshMs) return { phase: \"active\", policy: cached.policy, ageMs };\n if (ageMs <= params.policyStalenessFactor * refreshMs)\n return { phase: \"stale\", policy: cached.policy, ageMs };\n return { phase: \"expired\", ageMs }; // discard: cold-start rules (LLD 3.6)\n }\n const sessionAge = now - opts.sessionStartMs;\n return sessionAge <= params.warmupWindowMs\n ? { phase: \"warmup\", ageMs: Infinity }\n : { phase: \"degraded_sample\", ageMs: Infinity };\n },\n start(): void {\n schedule(0); // immediate first pull\n },\n stop(): void {\n stopped = true;\n if (timer !== undefined) clearTimeout(timer);\n },\n };\n}\n\nfunction defaultStorage(): Pick<Storage, \"getItem\" | \"setItem\"> | null {\n try {\n const s = window.localStorage;\n s.setItem(\"__unnoodle_probe\", \"1\");\n s.removeItem(\"__unnoodle_probe\");\n return s;\n } catch {\n return null;\n }\n}\n","/**\n * Token bucket (LLD §2.2). Two instances exist: `admission` (Q1 loop\n * protection: 100 burst, 1/s refill) and `heartbeat` (absolute per-session\n * cap: refillPerSec = 0 makes it a plain counter).\n */\nexport class TokenBucket {\n private tokens: number;\n private lastRefillMs: number;\n\n constructor(\n private readonly capacity: number,\n private readonly refillPerSec: number,\n now: number = Date.now(),\n ) {\n this.tokens = capacity;\n this.lastRefillMs = now;\n }\n\n take(now: number = Date.now()): boolean {\n if (this.refillPerSec > 0) {\n const elapsed = Math.max(0, now - this.lastRefillMs);\n this.tokens = Math.min(this.capacity, this.tokens + (elapsed / 1000) * this.refillPerSec);\n this.lastRefillMs = now;\n }\n if (this.tokens >= 1) {\n this.tokens -= 1;\n return true;\n }\n return false;\n }\n}\n","/**\n * CaptureGate (HLD 3.1/5.4/5.5, LLD 3.5). Decision order is CONTRACT:\n * 1. hints bypass (drift visibility on silent paths)\n * 2. policy phase (warmup/expired => capture; degraded => 10% sample)\n * 3. capture_all / appBuild mismatch => capture\n * 4. novel (not in learned membership) => capture\n * 5. learned => per-edge Bernoulli heartbeat (session-capped) or silent\n *\n * v0 reality: no learned_edges on the wire yet => membership is\n * NOTHING_LEARNED and steps 4-5 always capture. The order is still exercised\n * by unit tests so v1 is a data change, not a logic change.\n */\nimport { TokenBucket } from \"./tokenBucket\";\nimport type { Membership } from \"./membership\";\nimport type { OutcomeHint } from \"./outcome\";\nimport type { PolicyState } from \"./policy\";\nimport type { FlowParams } from \"./params\";\n\nexport type GateDecision = \"capture\" | \"heartbeat\" | \"silent\";\n\nexport interface CaptureGate {\n decide(edgeKey: bigint, hints: readonly OutcomeHint[], state: PolicyState): GateDecision;\n}\n\nexport function createCaptureGate(opts: {\n params: FlowParams;\n appBuild: string;\n membership: () => Membership;\n /** Policy's gate_key_version, when v1 lands; mismatch => skip membership. */\n gateKeyVersionOk: () => boolean;\n random?: () => number;\n}): CaptureGate {\n const heartbeatBucket = new TokenBucket(opts.params.heartbeatSessionCap, 0);\n const random = opts.random ?? Math.random;\n\n return {\n decide(edgeKey, hints, state): GateDecision {\n if (hints.length > 0) return \"capture\"; // 1. bypass — never silence anomalies\n\n const { phase, policy } = state;\n if (phase === \"warmup\" || phase === \"expired\") return \"capture\"; // 2.\n if (phase === \"degraded_sample\") return random() < opts.params.degradedSampleRate ? \"capture\" : \"silent\";\n\n // phase is active/stale: a policy object exists\n if (policy === undefined) return \"capture\"; // defensive — never silent without a policy\n if (policy.captureAll) return \"capture\"; // 3.\n if (policy.appBuild !== opts.appBuild) return \"capture\"; // 3. deploy re-opens capture\n\n if (!opts.gateKeyVersionOk()) return \"capture\"; // safe direction (LLD 4)\n if (!opts.membership().has(edgeKey)) return \"capture\"; // 4. novel\n\n // 5. learned: per-edge Bernoulli, session-capped\n if (random() < policy.heartbeatRate && heartbeatBucket.take()) return \"heartbeat\";\n return \"silent\";\n },\n };\n}\n","/**\n * Fixed-capacity ring buffer (LLD §2.1): bounded by construction, O(1)\n * enqueue, drop-OLDEST under pressure, every drop counted. Drop-oldest is\n * deliberate: recency matters most to a learning system, and explicit `from`\n * threading means a dropped predecessor loses an Edge but never fabricates one.\n */\nexport class RingBuffer<T> {\n private readonly slots: (T | undefined)[];\n private head = 0;\n private count = 0;\n private dropped = 0;\n\n constructor(private readonly capacity: number) {\n this.slots = new Array<T | undefined>(capacity);\n }\n\n enqueue(item: T): void {\n if (this.count === this.capacity) {\n this.head = (this.head + 1) % this.capacity;\n this.dropped += 1;\n } else {\n this.count += 1;\n }\n this.slots[(this.head + this.count - 1) % this.capacity] = item;\n }\n\n /** Remove and return up to n oldest items (FIFO — preserves seq order). */\n drain(n: number): T[] {\n const take = Math.min(n, this.count);\n const out: T[] = [];\n for (let i = 0; i < take; i++) {\n const idx = (this.head + i) % this.capacity;\n out.push(this.slots[idx] as T);\n this.slots[idx] = undefined;\n }\n this.head = (this.head + take) % this.capacity;\n this.count -= take;\n return out;\n }\n\n get size(): number {\n return this.count;\n }\n\n /** Monotonic count of items lost to overflow (batch telemetry at v1). */\n get droppedTotal(): number {\n return this.dropped;\n }\n\n /** Count an externally-caused drop (e.g. admission rate limit). */\n countDrop(): void {\n this.dropped += 1;\n }\n}\n","/**\n * Uploader (LLD 3.8): ring buffer drain -> canonical proto3 JSON -> gzip\n * (CompressionStream, cadence path) -> fire-and-forget.\n *\n * - Wire format: JSON+gzip per ADR-0001, re-confirmed by measurement (Q6\n * closed, LLD 9). Content-Encoding: gzip is set on the compressed path;\n * the gateway content-negotiates.\n * - pagehide path: navigator.sendBeacon with UNCOMPRESSED JSON, typed\n * text/plain so no CORS preflight is needed (F41) — beacon\n * cannot set headers and cannot await async compression reliably during\n * unload. Recorded deviation from the LLD's \"gzip when available\": the\n * unload batch is small (drain of a mostly-flushed buffer).\n * - 64 KB keepalive/sendBeacon quota is browser-enforced: body cap 60 KB,\n * re-split by halving the event count (LLD 3.8).\n * - The 202 response body is IGNORED — policy comes only from GET /policy.\n */\nimport { Event, EventBatch } from \"@unnoodle/flow-contracts\";\nimport { RingBuffer } from \"./ringBuffer\";\nimport { failSilent } from \"./failSilent\";\nimport type { FlowParams } from \"./params\";\n\nexport const SDK_VERSION = \"browser-flow/1.0.0\";\n\nexport interface UploaderConfig {\n endpoint: string;\n /** C-2: tenant auth. Header on fetch paths; ?k= on the beacon (no headers there). */\n apiKey: string;\n context: string;\n appBuild: string;\n sessionId: () => string; // late-bound: session can resume/rotate\n params: FlowParams;\n fetchFn?: typeof fetch;\n}\n\nexport class Uploader {\n private readonly buffer: RingBuffer<Event>;\n private inFlight = false;\n private lastFlushMs = 0;\n\n constructor(private readonly config: UploaderConfig) {\n this.buffer = new RingBuffer<Event>(config.params.ringBufferCapacity);\n }\n\n enqueue(event: Event): void {\n this.buffer.enqueue(event);\n }\n\n /** Externally-caused drop (admission rate limit) — counted for telemetry. */\n countDrop(): void {\n this.buffer.countDrop();\n }\n\n get pending(): number {\n return this.buffer.size;\n }\n\n get droppedTotal(): number {\n return this.buffer.droppedTotal;\n }\n\n flush(reason: \"cadence\" | \"pagehide\"): void {\n failSilent(() => this.flushInner(reason))();\n }\n\n private flushInner(reason: \"cadence\" | \"pagehide\"): void {\n if (this.buffer.size === 0) return;\n const now = Date.now();\n if (reason === \"cadence\") {\n if (this.inFlight || now - this.lastFlushMs < this.config.params.flushMinIntervalMs) return;\n this.lastFlushMs = now;\n }\n\n const events = this.buffer.drain(this.config.params.batchMaxEvents);\n this.send(events, reason);\n }\n\n private serialize(events: Event[]): string {\n const batch = EventBatch.fromPartial({\n sdkVersion: SDK_VERSION,\n appBuild: this.config.appBuild,\n context: this.config.context,\n sessionId: this.config.sessionId(),\n events,\n });\n return JSON.stringify(EventBatch.toJSON(batch));\n }\n\n private send(events: Event[], reason: \"cadence\" | \"pagehide\"): void {\n if (events.length === 0) return;\n const json = this.serialize(events);\n\n // Body-size cap (64 KB quota): halve and send both parts.\n if (json.length > this.config.params.batchMaxBodyBytes && events.length > 1) {\n const mid = Math.ceil(events.length / 2);\n this.send(events.slice(0, mid), reason);\n this.send(events.slice(mid), reason);\n return;\n }\n\n if (reason === \"pagehide\") {\n this.sendBeaconOrKeepalive(json);\n return;\n }\n void this.sendCompressed(json);\n }\n\n private sendBeaconOrKeepalive(json: string): void {\n try {\n if (typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\") {\n // text/plain, NOT application/json (F41, TaskFlow onboarding run 01).\n // The gateway is always on another origin and a beacon always carries\n // credentials. A non-safelisted type forces a CORS preflight, and the\n // gateway's `Access-Control-Allow-Origin: *` cannot answer a\n // credentialed request — the browser drops the POST AFTER sendBeacon()\n // has returned true, so nothing falls back and nothing is logged. A\n // safelisted type sends no preflight; the gateway parses the body\n // whatever its Content-Type, and the key already rides as ?k=.\n // Pinned by uploader.test.ts and, in a real browser, e2e/flow-unload.spec.ts.\n const blob = new Blob([json], { type: \"text/plain\" });\n if (navigator.sendBeacon(this.keyedEndpoint(), blob)) return;\n }\n } catch {\n /* fall through to keepalive fetch */\n }\n this.postRaw(json);\n }\n\n private async sendCompressed(json: string): Promise<void> {\n this.inFlight = true;\n try {\n const gz = await gzip(json);\n if (gz !== null) {\n // cast: TS 5.7 generic Uint8Array<ArrayBufferLike> vs DOM BodyInit\n await this.post(gz as unknown as BodyInit, {\n \"Content-Type\": \"application/json\",\n \"Content-Encoding\": \"gzip\",\n });\n } else {\n await this.post(json, { \"Content-Type\": \"application/json\" });\n }\n } catch {\n /* network failure — batch dropped by design, host never bothered */\n } finally {\n this.inFlight = false;\n }\n }\n\n private postRaw(json: string): void {\n try {\n void this.post(json, { \"Content-Type\": \"application/json\" }).catch(() => undefined);\n } catch {\n /* fire-and-forget */\n }\n }\n\n /** Beacon cannot set headers: the key rides as ?k= (S2 design D1's recorded deviation). */\n private keyedEndpoint(): string {\n const sep = this.config.endpoint.includes(\"?\") ? \"&\" : \"?\";\n return `${this.config.endpoint}${sep}k=${encodeURIComponent(this.config.apiKey)}`;\n }\n\n private post(body: BodyInit, headers: Record<string, string>): Promise<unknown> {\n const fetchFn = this.config.fetchFn ?? fetch;\n return fetchFn(this.config.endpoint, {\n method: \"POST\",\n headers: { ...headers, \"X-UNNOODLE-API-KEY\": this.config.apiKey },\n body,\n keepalive: true,\n // Auth is the API key, never a cookie; the gateway's `*` origin cannot\n // answer a credentialed request (F41). Explicit, so no deployment shape\n // or default change can turn uploads into credentialed requests.\n credentials: \"omit\",\n }).then((res) => {\n // 202 body deliberately ignored (policy is pull-only, design 4.1).\n void res;\n });\n }\n}\n\n/**\n * gzip via CompressionStream; null when unavailable (Safari < 16.4, LLD 4).\n * Driven directly through writer/reader — no Blob/Response dependency, which\n * partial DOM environments (jsdom) don't wire to real streams.\n */\nasync function gzip(s: string): Promise<Uint8Array | null> {\n if (typeof CompressionStream !== \"function\" || typeof TextEncoder !== \"function\") return null;\n try {\n const cs = new CompressionStream(\"gzip\");\n const writer = cs.writable.getWriter();\n void writer.write(new TextEncoder().encode(s));\n void writer.close();\n const reader = cs.readable.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n total += value.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const c of chunks) {\n out.set(c, offset);\n offset += c.length;\n }\n return out;\n } catch {\n return null;\n }\n}\n","/**\n * Flow Sensor composition root (Stage 1, Phase 2 — Design/HLD/LLD all signed\n * off 7 Jul 2026). Wires the LLD 3.2 two-slice pipeline:\n *\n * hot path: resolve interactive ancestor, capture a RawInteraction ref,\n * schedule — NOTHING else (design 9.1: p99 < 1 ms, 0 layout reads)\n * slice A: deref, ignore-region check, descriptor, keys, goal matchers\n * slice B: on quiescence — hints, gate decision, admission, enqueue;\n * currentNode advances EVEN WHEN SILENT (ADR-0003 threading)\n *\n * Interrupted-step rule (LLD 3.2): a new interaction closes the pending step\n * immediately — clicking faster than quiescence IS the settled signal.\n */\nimport { Event, EventType, NodeRef } from \"@unnoodle/flow-contracts\";\nimport { DEFAULT_PARAMS, type FlowParams } from \"./params\";\nimport { failSilent, setFailSilentDebug } from \"./failSilent\";\nimport { createIdleScheduler } from \"./idleScheduler\";\nimport { resolveInteractive, buildDescriptor, pageDescriptor } from \"./descriptor\";\nimport { isIgnored, sanitizedRoute } from \"./redaction\";\nimport { localKey } from \"./keyer\";\nimport { gateKey } from \"./gateKey\";\nimport { NOTHING_LEARNED, type Membership } from \"./membership\";\nimport { createQuiescenceDetector } from \"./quiescence\";\nimport { attachNavigationListeners } from \"./navigation\";\nimport { createContinuityStore, type SessionState } from \"./continuity\";\nimport { createOutcomeDeriver, type GoalMatcher, type OutcomeHint } from \"./outcome\";\nimport { createPolicyClient } from \"./policy\";\nimport { createCaptureGate } from \"./gate\";\nimport { TokenBucket } from \"./tokenBucket\";\nimport { Uploader } from \"./uploader\";\n\nexport interface FlowSensorConfig {\n /** Ingest endpoint, e.g. \"http://localhost:8090/ingest\". */\n endpoint: string;\n /** Tenant API key (closure C-2) — required; header on fetch, ?k= on the beacon. */\n apiKey: string;\n /** Policy endpoint; default: sibling \"/policy\" of the ingest endpoint. */\n policyEndpoint?: string;\n context: string;\n appBuild?: string | (() => string);\n redaction?: { ignoreSelectors?: readonly string[] };\n goals?: readonly GoalMatcher[];\n debug?: boolean;\n /** TEST-ONLY parameter overrides (LLD 8 table values are the defaults). */\n __params?: Partial<FlowParams>;\n}\n\nexport interface FlowSensor {\n stop(): void;\n}\n\nexport function startFlowSensor(config: FlowSensorConfig): FlowSensor {\n if (typeof config.apiKey !== \"string\" || config.apiKey.length === 0) {\n // Untyped consumers bypass the compile-time requirement; without this an\n // undefined key means every request 401s fire-and-forget — zero data,\n // zero diagnostics (closure C-2).\n throw new Error(\"@unnoodle/browser/flow: apiKey is required (closure C-2)\");\n }\n const params: FlowParams = { ...DEFAULT_PARAMS, ...config.__params };\n setFailSilentDebug(config.debug === true);\n\n const appBuild =\n typeof config.appBuild === \"function\" ? config.appBuild() : (config.appBuild ?? \"dev\");\n const ignoreSelectors = config.redaction?.ignoreSelectors ?? [];\n const sessionStartMs = Date.now();\n\n // --- session (MPA continuity, HLD 5.7) ---\n const continuity = createContinuityStore(params.continuityWindowMs, params.continuityBlobMaxBytes);\n const session: SessionState = continuity.resumeOrStart(appBuild);\n\n // --- collaborators ---\n const scheduler = createIdleScheduler(params.idleFrameBudgetMs);\n const quiescence = createQuiescenceDetector(\n params.quiescenceMutationQuietMs,\n params.quiescenceNetworkQuietMs,\n );\n const outcome = createOutcomeDeriver(config.goals ?? [], params.rageClickCount, params.rageClickWindowMs);\n const uploader = new Uploader({\n endpoint: config.endpoint,\n apiKey: config.apiKey,\n context: config.context,\n appBuild,\n sessionId: () => session.sessionId,\n params,\n });\n const policyClient = createPolicyClient({\n policyUrl: config.policyEndpoint ?? derivePolicyUrl(config.endpoint),\n apiKey: config.apiKey,\n context: config.context,\n appBuild,\n params,\n sessionStartMs,\n });\n // v0: no learned_edges on the wire yet — nothing is learned (LLD/gate note).\n const membership: () => Membership = () => NOTHING_LEARNED;\n const gate = createCaptureGate({\n params,\n appBuild,\n membership,\n gateKeyVersionOk: () => true, // v1: compare policy.gate_key_version to GATE_KEY_VERSION\n });\n const admission = new TokenBucket(params.admissionCapacity, params.admissionRefillPerSec);\n\n // --- pipeline state ---\n interface PendingStep {\n targetRef: WeakRef<Element>;\n kind: EventType;\n ts: number;\n /**\n * `location.pathname` AT THE INTERACTION — raw, sanitised later in slice A\n * (no redaction on the hot path). Reading the route in slice A instead\n * filed every step still waiting for idle time under the NEXT page\n * (TaskFlow onboarding run 01, F37: task-page actions landed on /my-work).\n */\n pathname: string;\n interrupt?: () => void;\n }\n let pending: PendingStep | null = null;\n /** ts of a navigation that must close any earlier pending step first. */\n let navQueuedTs: number | null = null;\n let stopped = false;\n\n const closeStep = (\n to: NodeRef,\n type: EventType,\n route: string,\n hints: readonly OutcomeHint[],\n ): void => {\n const toDescriptor = to.descriptor;\n if (toDescriptor === undefined) return; // never constructed without one; defensive\n const decision = gate.decide(\n gateKey(session.currentNode?.descriptor ?? null, toDescriptor, route),\n hints,\n policyClient.current(),\n );\n if (decision !== \"silent\") {\n if (admission.take()) {\n session.seq += 1;\n uploader.enqueue(\n Event.fromPartial({\n eventId: `${session.sessionId}:${session.seq}`,\n sessionId: session.sessionId,\n seq: session.seq,\n ts: Date.now(),\n type: decision === \"heartbeat\" ? EventType.EVENT_TYPE_HEARTBEAT : type,\n route,\n appBuild,\n to,\n from: session.currentNode ?? undefined,\n }),\n );\n } else {\n uploader.countDrop(); // rate-limited, counted (LLD 3.2)\n }\n }\n // Threading must stay correct across skipped edges (ADR-0003).\n session.currentNode = to;\n continuity.persist(session, appBuild);\n };\n\n // --- hot path (the entire ≤1 ms budget) ---\n // Debug builds sample the handler's own duration (bounded ring) so the perf\n // harness (e2e/flow-perf.spec.ts) can assert the 9.1 budget on a real,\n // CPU-throttled browser. Production skips even the performance.now() calls.\n const hotPathSamples: number[] = [];\n const recordHotPath =\n config.debug === true\n ? (t0: number): void => {\n if (hotPathSamples.length >= 512) hotPathSamples.shift();\n hotPathSamples.push(performance.now() - t0);\n }\n : null;\n\n const onInteraction = failSilent((domEvent: globalThis.Event): void => {\n if (stopped) return;\n const t0 = recordHotPath !== null ? performance.now() : 0;\n const el = resolveInteractive(domEvent.target);\n if (el === null) return;\n pending?.interrupt?.(); // interrupted-step rule\n const step: PendingStep = {\n targetRef: new WeakRef(el),\n kind: EventType.EVENT_TYPE_INTERACTION,\n ts: Date.now(),\n pathname: location.pathname, // a property read: no layout, no allocation beyond the string\n };\n pending = step;\n scheduler.schedule(() => sliceA(step));\n recordHotPath?.(t0);\n });\n\n // --- idle pipeline ---\n const sliceA = (step: PendingStep): void => {\n if (stopped) return;\n const el = step.targetRef.deref();\n if (el === undefined) {\n if (pending === step) pending = null;\n return; // GC'd — drop, never guess (LLD 4)\n }\n if (isIgnored(el, ignoreSelectors)) {\n if (pending === step) pending = null;\n return; // never even buffered (design 9.2)\n }\n\n const descriptor = buildDescriptor(el);\n const to: NodeRef = { localKey: localKey(descriptor), descriptor };\n const route = sanitizedRoute({ pathname: step.pathname });\n const rage = outcome.noteInteraction(to.localKey, step.ts);\n const goals = outcome.goalsFor(el, route);\n\n // Interrupted-step rule, pre-quiescence races (LLD 3.2): a newer\n // interaction OR a navigation that happened after this step means the UI\n // already moved on — the step closes NOW, threading intact, and the\n // scheduler's FIFO order keeps steps closing in interaction order.\n if (pending !== step || (navQueuedTs !== null && navQueuedTs >= step.ts)) {\n if (pending === step) pending = null;\n const interrupted = {\n settledTs: Date.now(),\n mutated: false,\n navigated: navQueuedTs !== null,\n timedOut: false,\n interrupted: true,\n };\n closeStep(to, step.kind, route, outcome.derive(interrupted, rage, goals));\n return;\n }\n\n const handle = quiescence.awaitSettled({ hardCapMs: params.quiescenceHardCapMs });\n step.interrupt = handle.interrupt;\n void handle.promise.then(\n failSilent((settled) => {\n if (stopped) return;\n if (pending === step) pending = null;\n closeStep(to, step.kind, route, outcome.derive(settled, rage, goals));\n }),\n );\n };\n\n // --- navigation (SPA route changes; synthetic page node, LLD note) ---\n const nav = attachNavigationListeners(\n (n) => {\n if (stopped) return;\n quiescence.noteNavigation();\n // A navigation is a settled signal for the step in flight: interrupt if\n // it reached quiescence, or flag it for slice A (FIFO keeps the order\n // click-step first, nav-step second).\n navQueuedTs = n.ts;\n pending?.interrupt?.();\n scheduler.schedule(() => {\n navQueuedTs = null;\n const d = pageDescriptor(n.route);\n closeStep({ localKey: `page:${n.route}`, descriptor: d }, EventType.EVENT_TYPE_NAVIGATION, n.route, []);\n });\n },\n () => {\n // pagehide: close any step still IN FLIGHT, then persist the from-thread\n // for the MPA handoff, then flush.\n //\n // The close must happen here and must be SYNCHRONOUS. `sliceA` is normally\n // scheduled on idle and, on a full page navigation, the page dies before it\n // runs — so a click that CAUSES the navigation was silently lost, and with\n // it every cross-page edge (alignment-spike Finding 2, measured 27 Aug 2026:\n // zero edges with a.route <> b.route). Closing via the quiescence promise\n // does not work either: `.then` is a microtask queued AFTER this block, so\n // uploader.flush() would beacon an empty buffer.\n //\n // Setting navQueuedTs forces sliceA's existing interrupted-step branch,\n // which is semantically right — a navigation IS happening.\n if (pending !== null) {\n navQueuedTs = Date.now();\n sliceA(pending);\n navQueuedTs = null;\n }\n continuity.persist(session, appBuild);\n uploader.flush(\"pagehide\");\n },\n );\n\n // --- listeners: ONE delegated, passive, capture-phase set (design 8) ---\n const listenerOptions: AddEventListenerOptions = { capture: true, passive: true };\n document.addEventListener(\"click\", onInteraction, listenerOptions);\n document.addEventListener(\"submit\", onInteraction, listenerOptions);\n\n const flushTimer = setInterval(\n failSilent(() => uploader.flush(\"cadence\")),\n params.flushMinIntervalMs,\n );\n policyClient.start();\n\n if (config.debug === true) {\n (window as unknown as Record<string, unknown>).__unnoodle_flow_stats = {\n get pending() {\n return uploader.pending;\n },\n get dropped() {\n return uploader.droppedTotal;\n },\n get phase() {\n return policyClient.current().phase;\n },\n get session() {\n return { id: session.sessionId, seq: session.seq, resumed: session.resumed };\n },\n get hotPath() {\n const s = [...hotPathSamples].sort((a, b) => a - b);\n const q = (p: number): number => s[Math.min(s.length - 1, Math.floor(p * s.length))] ?? 0;\n return { count: s.length, p50: q(0.5), p99: q(0.99) };\n },\n };\n }\n\n return {\n stop: failSilent(() => {\n if (stopped) return;\n stopped = true;\n clearInterval(flushTimer);\n document.removeEventListener(\"click\", onInteraction, listenerOptions);\n document.removeEventListener(\"submit\", onInteraction, listenerOptions);\n nav.stop();\n quiescence.stop();\n policyClient.stop();\n scheduler.stop();\n uploader.flush(\"pagehide\"); // best-effort final flush\n }) as () => void,\n };\n}\n\nfunction derivePolicyUrl(ingestEndpoint: string): string {\n try {\n const u = new URL(ingestEndpoint);\n u.pathname = \"/policy\";\n u.search = \"\";\n return u.toString();\n } catch {\n return \"/policy\";\n }\n}\n"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow Sensor parameters — mirrors LLD §8 (the one place every tunable lives).
|
|
3
|
+
* Values marked `⚠ corpus` in the LLD are provisional until validated against
|
|
4
|
+
* the alignment-spike corpus; change them HERE and in the LLD table together.
|
|
5
|
+
*/
|
|
6
|
+
interface FlowParams {
|
|
7
|
+
ringBufferCapacity: number;
|
|
8
|
+
batchMaxEvents: number;
|
|
9
|
+
batchMaxBodyBytes: number;
|
|
10
|
+
flushMinIntervalMs: number;
|
|
11
|
+
admissionCapacity: number;
|
|
12
|
+
admissionRefillPerSec: number;
|
|
13
|
+
warmupWindowMs: number;
|
|
14
|
+
degradedSampleRate: number;
|
|
15
|
+
policyStalenessFactor: number;
|
|
16
|
+
policyRetryBaseMs: number;
|
|
17
|
+
policyRetryMaxMs: number;
|
|
18
|
+
continuityWindowMs: number;
|
|
19
|
+
continuityBlobMaxBytes: number;
|
|
20
|
+
quiescenceMutationQuietMs: number;
|
|
21
|
+
quiescenceNetworkQuietMs: number;
|
|
22
|
+
quiescenceHardCapMs: number;
|
|
23
|
+
rageClickCount: number;
|
|
24
|
+
rageClickWindowMs: number;
|
|
25
|
+
heartbeatSessionCap: number;
|
|
26
|
+
idleFrameBudgetMs: number;
|
|
27
|
+
gateKeyLabelCap: number;
|
|
28
|
+
}
|
|
29
|
+
declare const DEFAULT_PARAMS: FlowParams;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Outcome hints (HLD 5.4, LLD 3.4): only what quiescence gives for free —
|
|
33
|
+
* dead_click, rage_click — plus host-declared goal matchers. The taxonomy is
|
|
34
|
+
* CLOSED at these three; richer inference violates the dumb-sensor principle.
|
|
35
|
+
*
|
|
36
|
+
* v0 wire note: Event has no outcome_hints field yet (v1 contract delta) —
|
|
37
|
+
* hints work locally (they bypass the CaptureGate) and go on the wire at v1.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
type OutcomeHint = {
|
|
41
|
+
kind: "dead_click";
|
|
42
|
+
} | {
|
|
43
|
+
kind: "rage_click";
|
|
44
|
+
} | {
|
|
45
|
+
kind: "goal";
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
interface GoalMatcher {
|
|
49
|
+
name: string;
|
|
50
|
+
/** Sanitised-path match: exact, or prefix when ending with "*". */
|
|
51
|
+
route?: string;
|
|
52
|
+
/** CSS selector evaluated against the live target element (slice A). */
|
|
53
|
+
selector?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface FlowSensorConfig {
|
|
57
|
+
/** Ingest endpoint, e.g. "http://localhost:8090/ingest". */
|
|
58
|
+
endpoint: string;
|
|
59
|
+
/** Tenant API key (closure C-2) — required; header on fetch, ?k= on the beacon. */
|
|
60
|
+
apiKey: string;
|
|
61
|
+
/** Policy endpoint; default: sibling "/policy" of the ingest endpoint. */
|
|
62
|
+
policyEndpoint?: string;
|
|
63
|
+
context: string;
|
|
64
|
+
appBuild?: string | (() => string);
|
|
65
|
+
redaction?: {
|
|
66
|
+
ignoreSelectors?: readonly string[];
|
|
67
|
+
};
|
|
68
|
+
goals?: readonly GoalMatcher[];
|
|
69
|
+
debug?: boolean;
|
|
70
|
+
/** TEST-ONLY parameter overrides (LLD 8 table values are the defaults). */
|
|
71
|
+
__params?: Partial<FlowParams>;
|
|
72
|
+
}
|
|
73
|
+
interface FlowSensor {
|
|
74
|
+
stop(): void;
|
|
75
|
+
}
|
|
76
|
+
declare function startFlowSensor(config: FlowSensorConfig): FlowSensor;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ElementDescriptor — a structural, REDACTED description of a DOM element.
|
|
80
|
+
*
|
|
81
|
+
* PRIVACY INVARIANT (Principle #4): structural only. No input values, no
|
|
82
|
+
* secrets. `label` is a redacted, length-capped accessible name / visible text.
|
|
83
|
+
* A descriptor carrying user content is a bug, not a schema question.
|
|
84
|
+
*/
|
|
85
|
+
interface ElementDescriptor {
|
|
86
|
+
/** e.g. "button", "a", "input" */
|
|
87
|
+
tag: string;
|
|
88
|
+
/** ARIA role or inferred; "" = unknown */
|
|
89
|
+
role: string;
|
|
90
|
+
/** redacted accessible name / visible text (capped) */
|
|
91
|
+
label: string;
|
|
92
|
+
/** id / data-testid if present; "" = absent */
|
|
93
|
+
testId: string;
|
|
94
|
+
/** structural signature (ancestor roles/tags, not nth-child) */
|
|
95
|
+
ancestorPath: string;
|
|
96
|
+
}
|
|
97
|
+
declare const ElementDescriptor: MessageFns<ElementDescriptor>;
|
|
98
|
+
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
|
99
|
+
type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
|
100
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
101
|
+
} : Partial<T>;
|
|
102
|
+
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
|
103
|
+
type Exact<P, I extends P> = P extends Builtin ? P : P & {
|
|
104
|
+
[K in keyof P]: Exact<P[K], I[K]>;
|
|
105
|
+
} & {
|
|
106
|
+
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
|
|
107
|
+
};
|
|
108
|
+
interface MessageFns<T> {
|
|
109
|
+
fromJSON(object: any): T;
|
|
110
|
+
toJSON(message: T): unknown;
|
|
111
|
+
create<I extends Exact<DeepPartial<T>, I>>(base?: I): T;
|
|
112
|
+
fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* GateKey v1 (HLD 5.2a, LLD 2.6) — the membership-test identity, computed
|
|
117
|
+
* IDENTICALLY here and at Stage-6 policy-compile time. Deliberately dumb and
|
|
118
|
+
* versioned; NOT the canonical Fingerprint (server-side, evolvable) and NOT
|
|
119
|
+
* the localKey (session-local). Collisions are benign by construction:
|
|
120
|
+
* miss => capture (safe), collision => silence healed like a Bloom FP.
|
|
121
|
+
*
|
|
122
|
+
* Reference vectors: /contracts/fixtures/gatekey-v1.json — shared with
|
|
123
|
+
* Stage 6's implementation. Changing ANY rule here bumps GATE_KEY_VERSION.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
declare const GATE_KEY_VERSION = 1;
|
|
127
|
+
/** Normalise a label for identity purposes (LLD 2.6 table). */
|
|
128
|
+
declare function normalizeLabel(label: string): string;
|
|
129
|
+
/**
|
|
130
|
+
* 64-bit GateKey as a BigInt. On a policy gate_key_version mismatch the
|
|
131
|
+
* CALLER must skip membership and capture (safe direction, LLD 4) — this
|
|
132
|
+
* function stays total and never throws.
|
|
133
|
+
*/
|
|
134
|
+
declare function gateKey(from: ElementDescriptor | null, to: ElementDescriptor, route: string): bigint;
|
|
135
|
+
/**
|
|
136
|
+
* FNV-1a 64-bit over the UTF-16 code units of s, two bytes per unit,
|
|
137
|
+
* little-endian — so the Java implementation (char -> 2 bytes LE) produces
|
|
138
|
+
* identical keys. Both sides are pinned by the shared fixture vectors.
|
|
139
|
+
*/
|
|
140
|
+
declare function fnv1a64(s: string): bigint;
|
|
141
|
+
|
|
142
|
+
export { DEFAULT_PARAMS, type FlowParams, type FlowSensor, type FlowSensorConfig, GATE_KEY_VERSION, type GoalMatcher, type OutcomeHint, fnv1a64, gateKey, normalizeLabel, startFlowSensor };
|