@qontinui/ui-bridge 0.21.0 → 0.21.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/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/injected/bundle.global.js +1 -1
- package/dist/{nextjs-NxTdtHhA.d.ts → nextjs-Bu7ZGwGe.d.ts} +35 -7
- package/dist/{nextjs-DZf4_LXo.d.mts → nextjs-DCLP7WgI.d.mts} +35 -7
- package/dist/react/index.js +1 -1
- package/dist/react/index.mjs +1 -1
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +57 -11
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +57 -11
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/nextjs.d.mts +1 -1
- package/dist/server/nextjs.d.ts +1 -1
- package/dist/server/nextjs.js +15 -2
- package/dist/server/nextjs.js.map +1 -1
- package/dist/server/nextjs.mjs +15 -2
- package/dist/server/nextjs.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26949,7 +26949,7 @@ function exposeProviderOnWindow(internals) {
|
|
|
26949
26949
|
if (typeof window === "undefined") return;
|
|
26950
26950
|
const w = window;
|
|
26951
26951
|
const root = w.__UI_BRIDGE__ ?? (w.__UI_BRIDGE__ = {});
|
|
26952
|
-
root.version = "0.21.
|
|
26952
|
+
root.version = "0.21.1";
|
|
26953
26953
|
root.specs = { getGlobalSpecStore };
|
|
26954
26954
|
root.registry = internals.registry;
|
|
26955
26955
|
root.browserCapture = internals.browserCapture;
|
package/dist/index.mjs
CHANGED
|
@@ -26947,7 +26947,7 @@ function exposeProviderOnWindow(internals) {
|
|
|
26947
26947
|
if (typeof window === "undefined") return;
|
|
26948
26948
|
const w = window;
|
|
26949
26949
|
const root = w.__UI_BRIDGE__ ?? (w.__UI_BRIDGE__ = {});
|
|
26950
|
-
root.version = "0.21.
|
|
26950
|
+
root.version = "0.21.1";
|
|
26951
26951
|
root.specs = { getGlobalSpecStore };
|
|
26952
26952
|
root.registry = internals.registry;
|
|
26953
26953
|
root.browserCapture = internals.browserCapture;
|
|
@@ -31,5 +31,5 @@ ${l(f+p,a-30)}`);}if(e.contentChanges&&a>30){let{metricChanges:m,statusChanges:f
|
|
|
31
31
|
`)){if(t.startsWith(":")||!t.startsWith("data:"))continue;let r=t.slice(5);r.startsWith(" ")&&(r=r.slice(1)),e.push(r);}return e.length>0?e.join(`
|
|
32
32
|
`):null}function cd(n){if(!n)return null;try{let e=n();if(!e||typeof e!="object")return null;let t=e.userId,r=e.sessionId;return typeof t!="string"||t.trim().length===0||typeof r!="string"||r.trim().length===0?null:{userId:t.trim(),sessionId:r.trim()}}catch{return null}}function Ci(n){try{typeof sessionStorage<"u"&&sessionStorage.setItem(Sa,n);}catch{}}function ld(){if(typeof window>"u")return null;try{let n=window,e=n.__uiBridgeTabId;if(typeof e=="string"&&e.length>0)return e;let t=n.__uiBridgeInjectedConfig?.tabId;if(typeof t=="string"&&t.length>0)return t}catch{}return null}function ud(){let n=ld();if(n)return Ci(n),n;let e=null;try{typeof sessionStorage<"u"&&(e=sessionStorage.getItem(Sa));}catch{}if(e)return e;let t=crypto.randomUUID();return Ci(t),t}function Ta(n){let{basePath:e,execute:t,heartbeatIntervalMs:r=1e4,authHeader:i,registrationMetadata:s,appType:o,capabilities:a,appId:c,appName:l,framework:u,version:d,onError:m=(A,M)=>console.error(A,M)}=n,f=n.tabId??ud();n.tabId&&Ci(n.tabId);let p=false,h=null,y=null,b=null,E=async(A,M,T)=>{try{await fetch(`${e}/commands`,{method:"POST",headers:wa(i),body:od({commandId:A,success:M,result:T,tabId:f,error:M?void 0:T?.error})});}catch(N){m("[UIBridge] Failed to send command response:",N);}},v=async A=>{try{let M=await t(A.action,A.payload),T=M;if(T&&T.success===!1){await E(A.commandId,!1,M);return}await E(A.commandId,!0,M);}catch(M){let T=M instanceof Error?M.message:String(M),N="UNKNOWN_ERROR";T.includes("not found")?N="ELEMENT_NOT_FOUND":T.includes("timeout")?N="ACTION_TIMEOUT":T.includes("Unknown command")&&(N="UNKNOWN_COMMAND"),await E(A.commandId,false,{success:false,error:T,failureDetails:{errorCode:N,message:T,timestamp:Date.now()},durationMs:0,timestamp:Date.now()});}},w=()=>{h&&(h.abort(),h=null);},R=()=>{p||y||(y=setTimeout(()=>{y=null,p||L();},1e4));},L=()=>{if(p)return;w();let A=new AbortController;h=A;let M=`${e}/commands/stream${f?`?tabId=${encodeURIComponent(f)}`:""}`,T={Accept:"text/event-stream"},N=Ca(i);N&&(T.Authorization=`Bearer ${N}`),fetch(M,{method:"GET",headers:T,signal:A.signal,cache:"no-store"}).then(async I=>{if(!I.ok||!I.body){h===A&&(h=null),R();return}let V=I.body.getReader(),Q=new TextDecoder,W="";try{for(;;){let{value:de,done:Ce}=await V.read();if(Ce)break;W+=Q.decode(de,{stream:!0});let Te;for(;(Te=W.indexOf(`
|
|
33
33
|
|
|
34
|
-
`))!==-1;){let Ct=W.slice(0,Te);W=W.slice(Te+2);let Ge=ad(Ct);if(Ge!=null)try{let ee=JSON.parse(Ge);if(ee.type==="connected")continue;ee.commandId&&ee.action&&v(ee);}catch(ee){m("[UIBridge] Failed to parse SSE message:",ee);}}}}catch{}h===A&&(h=null),!p&&!A.signal.aborted&&R();}).catch(()=>{h===A&&(h=null),!p&&!A.signal.aborted&&R();});},x=()=>{p||(w(),y&&(clearTimeout(y),y=null),L());},O=()=>{typeof document>"u"||document.visibilityState==="visible"&&(h||(y&&(clearTimeout(y),y=null),L()));},k=async()=>{try{let A={timestamp:Date.now(),tabId:f,url:typeof window<"u"?window.location.href:void 0,title:typeof document<"u"?document.title:void 0,visibility:typeof document<"u"?document.visibilityState:void 0};c!==void 0&&(A.appId=c),l!==void 0&&(A.appName=l),o!==void 0&&(A.appType=o),u!==void 0&&(A.framework=u),a!==void 0&&(A.capabilities=a),d!==void 0&&(A.version=d);let M=cd(s);M!==null&&(A.registrationMetadata=M);let T=await fetch(`${e}/heartbeat`,{method:"POST",headers:wa(i),body:JSON.stringify(A)});if(T.ok)try{let N=await T.json();(N?.tabRegistered??N?.data?.tabRegistered??null)===!1&&x();}catch{}}catch{}};return L(),typeof document<"u"&&document.addEventListener("visibilitychange",O),k(),b=setInterval(()=>{k();},r),{tabId:f,forceReconnect:x,stop(){p||(p=true,w(),y&&(clearTimeout(y),y=null),b&&(clearInterval(b),b=null),typeof document<"u"&&document.removeEventListener("visibilitychange",O));}}}function dd(n){return n.element.isConnected}function fd(n,e,t={}){let r=t.tracked,i=Ws(e),s=new Set(n.getAllElements().map(a=>a.id)),o=0;for(let a of i){if(r?.has(a.element)||!dd(a))continue;let c=a.id;if(s.has(c)){let u=2;for(;s.has(`${c}-${u}`);)u++;c=`${c}-${u}`;}let l=n.registerElement(c,a.element,{label:a.label||void 0,origin:"auto"});s.add(l.id),r?.set(a.element,l.id),o++;}return {registered:o,total:i.length}}function xa(n,e=document.body,t={}){let r=new Map,i=t.debounceMs??100,s=t.onSeed,o=null,a=()=>{let u=fd(n,e,{tracked:r});return s?.(n.getAllElements().length),u};a();let c=u=>{let d=r.get(u);d&&!u.isConnected&&(n.unregisterElement(d),r.delete(u));},l=new MutationObserver(u=>{for(let d of u)d.removedNodes.forEach(m=>{if(m.nodeType!==Node.ELEMENT_NODE)return;let f=m;c(f),f.querySelectorAll("*").forEach(c);});o&&clearTimeout(o),o=setTimeout(a,i);});return l.observe(e,{childList:true,subtree:true,attributes:true,attributeFilter:["class","style","hidden","disabled","aria-hidden"]}),()=>{l.disconnect(),o&&(clearTimeout(o),o=null);}}function Aa(n){let{quietMs:e,timeoutMs:t}=n,r=false,i=false,s=0,o=false,a=null,c=null,l=[],u=()=>({settled:r,elementCount:s,settledByTimeout:i,expectSatisfied:o}),d=()=>{a&&(clearTimeout(a),a=null);},m=()=>{c&&(clearTimeout(c),c=null);},f=p=>{if(r)return;r=true,i=p,d(),m();let h=u();for(;l.length;)l.shift()?.(h);};return {get settled(){return r},get elementCount(){return s},get settledByTimeout(){return i},get expectSatisfied(){return o},start(){r||c||(c=setTimeout(()=>f(true),t));},noteSeed(p,h){s=p,o=h??p>0,!r&&(o?(d(),a=setTimeout(()=>f(false),e)):d());},whenSettled(p){return r?Promise.resolve(u()):new Promise(h=>{let y=false,b=v=>{y||(y=true,h(v));};l.push(b),setTimeout(()=>b(u()),typeof p=="number"?p:t);})},dispose(){d(),m();}}}function Ra(n){return {get elements(){return n.getAllElements()},getElement:e=>n.getElement(e),get components(){return n.getAllComponents()},get workflows(){return n.getAllWorkflows()}}}(function(){if(typeof window>"u"||window.__uiBridgeInjected)return;let e=new Je;ps(e);let t=Ra(e),r=window.__uiBridgeInjectedConfig,i=Aa({quietMs:typeof r?.settleQuietMs=="number"?r.settleQuietMs:500,timeoutMs:typeof r?.settleTimeoutMs=="number"?r.settleTimeoutMs:1e4}),s=typeof r?.expectSelector=="string"&&r.expectSelector.length>0?r.expectSelector:null,o=()=>{if(!s)return true;try{return document.querySelector(s)!==null}catch{return true}},a=()=>{c.settled=i.settled,c.settledByTimeout=i.settledByTimeout,c.expectSatisfied=i.expectSatisfied;},c={ready:false,settled:false,settledByTimeout:false,expectSatisfied:false,expectSelector:s,elementCount:0,version:"0.21.
|
|
34
|
+
`))!==-1;){let Ct=W.slice(0,Te);W=W.slice(Te+2);let Ge=ad(Ct);if(Ge!=null)try{let ee=JSON.parse(Ge);if(ee.type==="connected")continue;ee.commandId&&ee.action&&v(ee);}catch(ee){m("[UIBridge] Failed to parse SSE message:",ee);}}}}catch{}h===A&&(h=null),!p&&!A.signal.aborted&&R();}).catch(()=>{h===A&&(h=null),!p&&!A.signal.aborted&&R();});},x=()=>{p||(w(),y&&(clearTimeout(y),y=null),L());},O=()=>{typeof document>"u"||document.visibilityState==="visible"&&(h||(y&&(clearTimeout(y),y=null),L()));},k=async()=>{try{let A={timestamp:Date.now(),tabId:f,url:typeof window<"u"?window.location.href:void 0,title:typeof document<"u"?document.title:void 0,visibility:typeof document<"u"?document.visibilityState:void 0};c!==void 0&&(A.appId=c),l!==void 0&&(A.appName=l),o!==void 0&&(A.appType=o),u!==void 0&&(A.framework=u),a!==void 0&&(A.capabilities=a),d!==void 0&&(A.version=d);let M=cd(s);M!==null&&(A.registrationMetadata=M);let T=await fetch(`${e}/heartbeat`,{method:"POST",headers:wa(i),body:JSON.stringify(A)});if(T.ok)try{let N=await T.json();(N?.tabRegistered??N?.data?.tabRegistered??null)===!1&&x();}catch{}}catch{}};return L(),typeof document<"u"&&document.addEventListener("visibilitychange",O),k(),b=setInterval(()=>{k();},r),{tabId:f,forceReconnect:x,stop(){p||(p=true,w(),y&&(clearTimeout(y),y=null),b&&(clearInterval(b),b=null),typeof document<"u"&&document.removeEventListener("visibilitychange",O));}}}function dd(n){return n.element.isConnected}function fd(n,e,t={}){let r=t.tracked,i=Ws(e),s=new Set(n.getAllElements().map(a=>a.id)),o=0;for(let a of i){if(r?.has(a.element)||!dd(a))continue;let c=a.id;if(s.has(c)){let u=2;for(;s.has(`${c}-${u}`);)u++;c=`${c}-${u}`;}let l=n.registerElement(c,a.element,{label:a.label||void 0,origin:"auto"});s.add(l.id),r?.set(a.element,l.id),o++;}return {registered:o,total:i.length}}function xa(n,e=document.body,t={}){let r=new Map,i=t.debounceMs??100,s=t.onSeed,o=null,a=()=>{let u=fd(n,e,{tracked:r});return s?.(n.getAllElements().length),u};a();let c=u=>{let d=r.get(u);d&&!u.isConnected&&(n.unregisterElement(d),r.delete(u));},l=new MutationObserver(u=>{for(let d of u)d.removedNodes.forEach(m=>{if(m.nodeType!==Node.ELEMENT_NODE)return;let f=m;c(f),f.querySelectorAll("*").forEach(c);});o&&clearTimeout(o),o=setTimeout(a,i);});return l.observe(e,{childList:true,subtree:true,attributes:true,attributeFilter:["class","style","hidden","disabled","aria-hidden"]}),()=>{l.disconnect(),o&&(clearTimeout(o),o=null);}}function Aa(n){let{quietMs:e,timeoutMs:t}=n,r=false,i=false,s=0,o=false,a=null,c=null,l=[],u=()=>({settled:r,elementCount:s,settledByTimeout:i,expectSatisfied:o}),d=()=>{a&&(clearTimeout(a),a=null);},m=()=>{c&&(clearTimeout(c),c=null);},f=p=>{if(r)return;r=true,i=p,d(),m();let h=u();for(;l.length;)l.shift()?.(h);};return {get settled(){return r},get elementCount(){return s},get settledByTimeout(){return i},get expectSatisfied(){return o},start(){r||c||(c=setTimeout(()=>f(true),t));},noteSeed(p,h){s=p,o=h??p>0,!r&&(o?(d(),a=setTimeout(()=>f(false),e)):d());},whenSettled(p){return r?Promise.resolve(u()):new Promise(h=>{let y=false,b=v=>{y||(y=true,h(v));};l.push(b),setTimeout(()=>b(u()),typeof p=="number"?p:t);})},dispose(){d(),m();}}}function Ra(n){return {get elements(){return n.getAllElements()},getElement:e=>n.getElement(e),get components(){return n.getAllComponents()},get workflows(){return n.getAllWorkflows()}}}(function(){if(typeof window>"u"||window.__uiBridgeInjected)return;let e=new Je;ps(e);let t=Ra(e),r=window.__uiBridgeInjectedConfig,i=Aa({quietMs:typeof r?.settleQuietMs=="number"?r.settleQuietMs:500,timeoutMs:typeof r?.settleTimeoutMs=="number"?r.settleTimeoutMs:1e4}),s=typeof r?.expectSelector=="string"&&r.expectSelector.length>0?r.expectSelector:null,o=()=>{if(!s)return true;try{return document.querySelector(s)!==null}catch{return true}},a=()=>{c.settled=i.settled,c.settledByTimeout=i.settledByTimeout,c.expectSatisfied=i.expectSatisfied;},c={ready:false,settled:false,settledByTimeout:false,expectSatisfied:false,expectSelector:s,elementCount:0,version:"0.21.1",whenSettled:u=>i.whenSettled(u),execute:(u,d)=>Promise.resolve(Hn(u,d,t))};window.__uiBridgeInjected=c;let l=()=>{i.start(),xa(e,document.body,{onSeed:u=>{c.elementCount=u,i.noteSeed(u,s?o():void 0),a();}}),c.ready=true,i.whenSettled().then(a),r?.uiBridgeBase&&Ta({basePath:r.uiBridgeBase,execute:c.execute,tabId:r.tabId,authHeader:()=>r.authToken??null,registrationMetadata:()=>r.registrationMetadata??null,appType:"injected",capabilities:["control","discovery"],appId:r.appId,appName:r.appName,version:c.version});};document.body?l():typeof document<"u"&&document.addEventListener("DOMContentLoaded",l,{once:true});})();})();//# sourceMappingURL=bundle.global.js.map
|
|
35
35
|
//# sourceMappingURL=bundle.global.js.map
|
|
@@ -495,17 +495,45 @@ declare class CommandRelay {
|
|
|
495
495
|
* has been called for it. `listOwnedTabs`, `assertOwnership`, and the
|
|
496
496
|
* bus-envelope receiver check all key off this map.
|
|
497
497
|
*
|
|
498
|
-
* Re-registration under a DIFFERENT `userId`
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
498
|
+
* Re-registration under a DIFFERENT `userId` (e.g. a tab survives a
|
|
499
|
+
* re-login) is permitted ONLY when the new user is AUTH-PROVEN, not
|
|
500
|
+
* merely asserted. `metadata.userId` rides in the (browser-supplied)
|
|
501
|
+
* heartbeat body and is therefore untrusted on its own: without a
|
|
502
|
+
* proof gate, anyone who learns a victim's `tabId` could POST a
|
|
503
|
+
* heartbeat claiming any `userId` and silently seize ownership of the
|
|
504
|
+
* tab (and with it the ability to drive it / settle its commands).
|
|
505
|
+
*
|
|
506
|
+
* `options.callerUserId` is the identity the consumer's auth gate
|
|
507
|
+
* proved and injected as `X-Caller-User-Id` (never a browser value).
|
|
508
|
+
* The rule:
|
|
509
|
+
*
|
|
510
|
+
* - Same-owner heartbeat (existing owner === claimed userId): always
|
|
511
|
+
* a refresh — `sessionId`/`lastSeen` updated in place. No proof
|
|
512
|
+
* needed; you already hold the tab and the claim matches.
|
|
513
|
+
* - TRANSFER (a DIFFERENT user already owns the tab): the claimed
|
|
514
|
+
* `userId` MUST be auth-proven and equal to `callerUserId`. An
|
|
515
|
+
* unauthenticated (`callerUserId` absent) or mismatched claim is
|
|
516
|
+
* REFUSED and the prior owner is left untouched — this is the
|
|
517
|
+
* takeover primitive being closed. A genuine re-login carries the
|
|
518
|
+
* new user's proven identity and therefore still transfers.
|
|
519
|
+
* - First CLAIM (tab has no owner yet — bootstrap): honored, so a
|
|
520
|
+
* header-less / single-trust-domain deployment can still register
|
|
521
|
+
* tabs. A *present* proven identity must still match the claimed
|
|
522
|
+
* `userId` (you cannot bootstrap a tab under an identity you
|
|
523
|
+
* cannot back).
|
|
524
|
+
*
|
|
525
|
+
* Returns whether ownership was (re)assigned so the HTTP layer can
|
|
526
|
+
* surface the refusal without bricking the heartbeat loop.
|
|
504
527
|
*/
|
|
505
528
|
recordRegistration(tabId: string, metadata: {
|
|
506
529
|
userId: string;
|
|
507
530
|
sessionId: string;
|
|
508
|
-
}
|
|
531
|
+
}, options?: {
|
|
532
|
+
callerUserId?: string | null;
|
|
533
|
+
}): {
|
|
534
|
+
ownershipAssigned: boolean;
|
|
535
|
+
rejectedReason?: 'OWNER_CHANGE_UNVERIFIED';
|
|
536
|
+
};
|
|
509
537
|
/**
|
|
510
538
|
* Return the stored ownership record for a tab, or `null` if the tab
|
|
511
539
|
* has not registered yet. The full record (including timestamps) is
|
|
@@ -495,17 +495,45 @@ declare class CommandRelay {
|
|
|
495
495
|
* has been called for it. `listOwnedTabs`, `assertOwnership`, and the
|
|
496
496
|
* bus-envelope receiver check all key off this map.
|
|
497
497
|
*
|
|
498
|
-
* Re-registration under a DIFFERENT `userId`
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
498
|
+
* Re-registration under a DIFFERENT `userId` (e.g. a tab survives a
|
|
499
|
+
* re-login) is permitted ONLY when the new user is AUTH-PROVEN, not
|
|
500
|
+
* merely asserted. `metadata.userId` rides in the (browser-supplied)
|
|
501
|
+
* heartbeat body and is therefore untrusted on its own: without a
|
|
502
|
+
* proof gate, anyone who learns a victim's `tabId` could POST a
|
|
503
|
+
* heartbeat claiming any `userId` and silently seize ownership of the
|
|
504
|
+
* tab (and with it the ability to drive it / settle its commands).
|
|
505
|
+
*
|
|
506
|
+
* `options.callerUserId` is the identity the consumer's auth gate
|
|
507
|
+
* proved and injected as `X-Caller-User-Id` (never a browser value).
|
|
508
|
+
* The rule:
|
|
509
|
+
*
|
|
510
|
+
* - Same-owner heartbeat (existing owner === claimed userId): always
|
|
511
|
+
* a refresh — `sessionId`/`lastSeen` updated in place. No proof
|
|
512
|
+
* needed; you already hold the tab and the claim matches.
|
|
513
|
+
* - TRANSFER (a DIFFERENT user already owns the tab): the claimed
|
|
514
|
+
* `userId` MUST be auth-proven and equal to `callerUserId`. An
|
|
515
|
+
* unauthenticated (`callerUserId` absent) or mismatched claim is
|
|
516
|
+
* REFUSED and the prior owner is left untouched — this is the
|
|
517
|
+
* takeover primitive being closed. A genuine re-login carries the
|
|
518
|
+
* new user's proven identity and therefore still transfers.
|
|
519
|
+
* - First CLAIM (tab has no owner yet — bootstrap): honored, so a
|
|
520
|
+
* header-less / single-trust-domain deployment can still register
|
|
521
|
+
* tabs. A *present* proven identity must still match the claimed
|
|
522
|
+
* `userId` (you cannot bootstrap a tab under an identity you
|
|
523
|
+
* cannot back).
|
|
524
|
+
*
|
|
525
|
+
* Returns whether ownership was (re)assigned so the HTTP layer can
|
|
526
|
+
* surface the refusal without bricking the heartbeat loop.
|
|
504
527
|
*/
|
|
505
528
|
recordRegistration(tabId: string, metadata: {
|
|
506
529
|
userId: string;
|
|
507
530
|
sessionId: string;
|
|
508
|
-
}
|
|
531
|
+
}, options?: {
|
|
532
|
+
callerUserId?: string | null;
|
|
533
|
+
}): {
|
|
534
|
+
ownershipAssigned: boolean;
|
|
535
|
+
rejectedReason?: 'OWNER_CHANGE_UNVERIFIED';
|
|
536
|
+
};
|
|
509
537
|
/**
|
|
510
538
|
* Return the stored ownership record for a tab, or `null` if the tab
|
|
511
539
|
* has not registered yet. The full record (including timestamps) is
|
package/dist/react/index.js
CHANGED
|
@@ -26035,7 +26035,7 @@ function exposeProviderOnWindow(internals) {
|
|
|
26035
26035
|
if (typeof window === "undefined") return;
|
|
26036
26036
|
const w = window;
|
|
26037
26037
|
const root = w.__UI_BRIDGE__ ?? (w.__UI_BRIDGE__ = {});
|
|
26038
|
-
root.version = "0.21.
|
|
26038
|
+
root.version = "0.21.1";
|
|
26039
26039
|
root.specs = { getGlobalSpecStore };
|
|
26040
26040
|
root.registry = internals.registry;
|
|
26041
26041
|
root.browserCapture = internals.browserCapture;
|
package/dist/react/index.mjs
CHANGED
|
@@ -26033,7 +26033,7 @@ function exposeProviderOnWindow(internals) {
|
|
|
26033
26033
|
if (typeof window === "undefined") return;
|
|
26034
26034
|
const w = window;
|
|
26035
26035
|
const root = w.__UI_BRIDGE__ ?? (w.__UI_BRIDGE__ = {});
|
|
26036
|
-
root.version = "0.21.
|
|
26036
|
+
root.version = "0.21.1";
|
|
26037
26037
|
root.specs = { getGlobalSpecStore };
|
|
26038
26038
|
root.registry = internals.registry;
|
|
26039
26039
|
root.browserCapture = internals.browserCapture;
|
package/dist/server/index.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { a as UIBridgeServerHandlers, H as HandlerContext } from '../types-DHctE
|
|
|
2
2
|
export { A as APIResponse, B as BrowserEventsResponse, C as CORSOptions, b as CapabilitiesResponse, c as ControlBatchRequest, d as ControlBatchResponse, e as ControlBatchStep, f as ControlBatchStepResult, D as DOMChangeEvent, E as ElementConditionSelector, g as ElementExpectRequest, h as ElementExpectResponse, i as EndpointCategory, j as EndpointInfo, I as INTERACTION_RELAY_COMMAND_ACTIONS, k as InteractionRelayCommandAction, P as PageEvaluateRequest, R as RateLimitOptions, l as RenderLogQuery, m as RouteDefinition, n as RunnerWindow, o as RunnerWindowsList, S as SpawnHeadlessRequest, p as SpawnHeadlessResponse, q as StateSummary, U as UIBridgeServerConfig, r as UI_BRIDGE_ROUTES, s as WaitForElementByConditionRequest, t as WaitForElementByConditionResponse, u as WaitForElementPredicate, v as WaitForElementRequest, w as WaitForElementSuccessResponse, x as WaitForRouteChangeRequest, y as WaitForRouteChangeResponse, W as WebSocketMessage, z as WebSocketMessageType } from '../types-DHctEsDy.mjs';
|
|
3
3
|
export { ActionExecutorLike, CreateHandlersConfig, RegistryLike, closeAllSpawnedHeadlessTabs, createAIHandlers, createHandlers } from './handlers.mjs';
|
|
4
4
|
export { ExpressAdapterConfig, createExpressApp, createExpressRouter, uiBridgeMiddleware } from './express.mjs';
|
|
5
|
-
import { C as CommandRelay } from '../nextjs-
|
|
6
|
-
export { a as CommandListener, b as CommandRelayOptions, N as NextJSAdapterConfig, c as NextRouteHandler, P as PendingCommand, Q as QueuedCommand, R as RedisRelayBus, d as RelayBus, e as RelayCommandEnvelope, f as RelayResponseEnvelope, T as TabInfo, g as TabListener, h as TabRoutingError, i as TransportDiagnostics, W as WebSocketClient, j as createControlHandlers, k as createDebugHandlers, l as createNextRouteHandlers, m as createRedisRelayBus, n as createRenderLogHandlers, o as createUIBridgeHandler } from '../nextjs-
|
|
5
|
+
import { C as CommandRelay } from '../nextjs-DCLP7WgI.mjs';
|
|
6
|
+
export { a as CommandListener, b as CommandRelayOptions, N as NextJSAdapterConfig, c as NextRouteHandler, P as PendingCommand, Q as QueuedCommand, R as RedisRelayBus, d as RelayBus, e as RelayCommandEnvelope, f as RelayResponseEnvelope, T as TabInfo, g as TabListener, h as TabRoutingError, i as TransportDiagnostics, W as WebSocketClient, j as createControlHandlers, k as createDebugHandlers, l as createNextRouteHandlers, m as createRedisRelayBus, n as createRenderLogHandlers, o as createUIBridgeHandler } from '../nextjs-DCLP7WgI.mjs';
|
|
7
7
|
import { U as UIBridgeWSHandler } from '../standalone-Bz312WSC.mjs';
|
|
8
8
|
export { S as StandaloneServer, a as StandaloneServerConfig, W as WebSocketLike, c as createStandaloneServer, s as startCLI } from '../standalone-Bz312WSC.mjs';
|
|
9
9
|
import { e as BridgeEvent, i as AnyCapturedEvent, Q as ControlActionRequest } from '../types-CDn2gSl_.mjs';
|
package/dist/server/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { a as UIBridgeServerHandlers, H as HandlerContext } from '../types-DRCea
|
|
|
2
2
|
export { A as APIResponse, B as BrowserEventsResponse, C as CORSOptions, b as CapabilitiesResponse, c as ControlBatchRequest, d as ControlBatchResponse, e as ControlBatchStep, f as ControlBatchStepResult, D as DOMChangeEvent, E as ElementConditionSelector, g as ElementExpectRequest, h as ElementExpectResponse, i as EndpointCategory, j as EndpointInfo, I as INTERACTION_RELAY_COMMAND_ACTIONS, k as InteractionRelayCommandAction, P as PageEvaluateRequest, R as RateLimitOptions, l as RenderLogQuery, m as RouteDefinition, n as RunnerWindow, o as RunnerWindowsList, S as SpawnHeadlessRequest, p as SpawnHeadlessResponse, q as StateSummary, U as UIBridgeServerConfig, r as UI_BRIDGE_ROUTES, s as WaitForElementByConditionRequest, t as WaitForElementByConditionResponse, u as WaitForElementPredicate, v as WaitForElementRequest, w as WaitForElementSuccessResponse, x as WaitForRouteChangeRequest, y as WaitForRouteChangeResponse, W as WebSocketMessage, z as WebSocketMessageType } from '../types-DRCeaV6_.js';
|
|
3
3
|
export { ActionExecutorLike, CreateHandlersConfig, RegistryLike, closeAllSpawnedHeadlessTabs, createAIHandlers, createHandlers } from './handlers.js';
|
|
4
4
|
export { ExpressAdapterConfig, createExpressApp, createExpressRouter, uiBridgeMiddleware } from './express.js';
|
|
5
|
-
import { C as CommandRelay } from '../nextjs-
|
|
6
|
-
export { a as CommandListener, b as CommandRelayOptions, N as NextJSAdapterConfig, c as NextRouteHandler, P as PendingCommand, Q as QueuedCommand, R as RedisRelayBus, d as RelayBus, e as RelayCommandEnvelope, f as RelayResponseEnvelope, T as TabInfo, g as TabListener, h as TabRoutingError, i as TransportDiagnostics, W as WebSocketClient, j as createControlHandlers, k as createDebugHandlers, l as createNextRouteHandlers, m as createRedisRelayBus, n as createRenderLogHandlers, o as createUIBridgeHandler } from '../nextjs-
|
|
5
|
+
import { C as CommandRelay } from '../nextjs-Bu7ZGwGe.js';
|
|
6
|
+
export { a as CommandListener, b as CommandRelayOptions, N as NextJSAdapterConfig, c as NextRouteHandler, P as PendingCommand, Q as QueuedCommand, R as RedisRelayBus, d as RelayBus, e as RelayCommandEnvelope, f as RelayResponseEnvelope, T as TabInfo, g as TabListener, h as TabRoutingError, i as TransportDiagnostics, W as WebSocketClient, j as createControlHandlers, k as createDebugHandlers, l as createNextRouteHandlers, m as createRedisRelayBus, n as createRenderLogHandlers, o as createUIBridgeHandler } from '../nextjs-Bu7ZGwGe.js';
|
|
7
7
|
import { U as UIBridgeWSHandler } from '../standalone-Q5b8CZwc.js';
|
|
8
8
|
export { S as StandaloneServer, a as StandaloneServerConfig, W as WebSocketLike, c as createStandaloneServer, s as startCLI } from '../standalone-Q5b8CZwc.js';
|
|
9
9
|
import { e as BridgeEvent, i as AnyCapturedEvent, Q as ControlActionRequest } from '../types-DJO1izBV.js';
|
package/dist/server/index.js
CHANGED
|
@@ -25867,7 +25867,12 @@ function handleRelayRoute(method, path, request, relay, config) {
|
|
|
25867
25867
|
400
|
|
25868
25868
|
);
|
|
25869
25869
|
}
|
|
25870
|
-
|
|
25870
|
+
const callerUserId = request.headers.get("x-caller-user-id") ?? request.headers.get("X-Caller-User-Id") ?? void 0;
|
|
25871
|
+
const registration = relay.recordRegistration(
|
|
25872
|
+
heartbeatTabId,
|
|
25873
|
+
{ userId, sessionId },
|
|
25874
|
+
{ callerUserId }
|
|
25875
|
+
);
|
|
25871
25876
|
relay.receiveHeartbeat(heartbeatTabId, {
|
|
25872
25877
|
url: typeof body?.url === "string" ? body.url : void 0,
|
|
25873
25878
|
title: typeof body?.title === "string" ? body.title : void 0,
|
|
@@ -25877,7 +25882,15 @@ function handleRelayRoute(method, path, request, relay, config) {
|
|
|
25877
25882
|
const tabRegistered = diag.connectedTabs.includes(heartbeatTabId);
|
|
25878
25883
|
return jsonResponse({
|
|
25879
25884
|
success: true,
|
|
25880
|
-
data: {
|
|
25885
|
+
data: {
|
|
25886
|
+
received: true,
|
|
25887
|
+
tabRegistered,
|
|
25888
|
+
// Observability: signals an ownership claim/transfer was refused
|
|
25889
|
+
// because the claimed userId was not auth-proven. Not a fatal
|
|
25890
|
+
// heartbeat error — the loop continues; the tab simply keeps its
|
|
25891
|
+
// prior (or no) owner. Absent when ownership was assigned.
|
|
25892
|
+
...registration.ownershipAssigned ? {} : { ownershipAssigned: false, ownerChangeRejected: registration.rejectedReason }
|
|
25893
|
+
},
|
|
25881
25894
|
timestamp: Date.now()
|
|
25882
25895
|
});
|
|
25883
25896
|
})();
|
|
@@ -29127,20 +29140,52 @@ var CommandRelay = class {
|
|
|
29127
29140
|
* has been called for it. `listOwnedTabs`, `assertOwnership`, and the
|
|
29128
29141
|
* bus-envelope receiver check all key off this map.
|
|
29129
29142
|
*
|
|
29130
|
-
* Re-registration under a DIFFERENT `userId`
|
|
29131
|
-
*
|
|
29132
|
-
*
|
|
29133
|
-
*
|
|
29134
|
-
*
|
|
29135
|
-
*
|
|
29136
|
-
|
|
29137
|
-
|
|
29143
|
+
* Re-registration under a DIFFERENT `userId` (e.g. a tab survives a
|
|
29144
|
+
* re-login) is permitted ONLY when the new user is AUTH-PROVEN, not
|
|
29145
|
+
* merely asserted. `metadata.userId` rides in the (browser-supplied)
|
|
29146
|
+
* heartbeat body and is therefore untrusted on its own: without a
|
|
29147
|
+
* proof gate, anyone who learns a victim's `tabId` could POST a
|
|
29148
|
+
* heartbeat claiming any `userId` and silently seize ownership of the
|
|
29149
|
+
* tab (and with it the ability to drive it / settle its commands).
|
|
29150
|
+
*
|
|
29151
|
+
* `options.callerUserId` is the identity the consumer's auth gate
|
|
29152
|
+
* proved and injected as `X-Caller-User-Id` (never a browser value).
|
|
29153
|
+
* The rule:
|
|
29154
|
+
*
|
|
29155
|
+
* - Same-owner heartbeat (existing owner === claimed userId): always
|
|
29156
|
+
* a refresh — `sessionId`/`lastSeen` updated in place. No proof
|
|
29157
|
+
* needed; you already hold the tab and the claim matches.
|
|
29158
|
+
* - TRANSFER (a DIFFERENT user already owns the tab): the claimed
|
|
29159
|
+
* `userId` MUST be auth-proven and equal to `callerUserId`. An
|
|
29160
|
+
* unauthenticated (`callerUserId` absent) or mismatched claim is
|
|
29161
|
+
* REFUSED and the prior owner is left untouched — this is the
|
|
29162
|
+
* takeover primitive being closed. A genuine re-login carries the
|
|
29163
|
+
* new user's proven identity and therefore still transfers.
|
|
29164
|
+
* - First CLAIM (tab has no owner yet — bootstrap): honored, so a
|
|
29165
|
+
* header-less / single-trust-domain deployment can still register
|
|
29166
|
+
* tabs. A *present* proven identity must still match the claimed
|
|
29167
|
+
* `userId` (you cannot bootstrap a tab under an identity you
|
|
29168
|
+
* cannot back).
|
|
29169
|
+
*
|
|
29170
|
+
* Returns whether ownership was (re)assigned so the HTTP layer can
|
|
29171
|
+
* surface the refusal without bricking the heartbeat loop.
|
|
29172
|
+
*/
|
|
29173
|
+
recordRegistration(tabId, metadata, options) {
|
|
29138
29174
|
const now = Date.now();
|
|
29175
|
+
const proven = options?.callerUserId;
|
|
29176
|
+
if (proven != null && proven !== metadata.userId) {
|
|
29177
|
+
return { ownershipAssigned: false, rejectedReason: "OWNER_CHANGE_UNVERIFIED" };
|
|
29178
|
+
}
|
|
29139
29179
|
const existing = this.tabOwnership.get(tabId);
|
|
29140
29180
|
if (existing && existing.userId === metadata.userId) {
|
|
29141
29181
|
existing.sessionId = metadata.sessionId;
|
|
29142
29182
|
existing.lastSeen = now;
|
|
29143
|
-
return;
|
|
29183
|
+
return { ownershipAssigned: true };
|
|
29184
|
+
}
|
|
29185
|
+
if (existing) {
|
|
29186
|
+
if (proven == null) {
|
|
29187
|
+
return { ownershipAssigned: false, rejectedReason: "OWNER_CHANGE_UNVERIFIED" };
|
|
29188
|
+
}
|
|
29144
29189
|
}
|
|
29145
29190
|
this.tabOwnership.set(tabId, {
|
|
29146
29191
|
userId: metadata.userId,
|
|
@@ -29148,6 +29193,7 @@ var CommandRelay = class {
|
|
|
29148
29193
|
firstSeen: existing?.firstSeen ?? now,
|
|
29149
29194
|
lastSeen: now
|
|
29150
29195
|
});
|
|
29196
|
+
return { ownershipAssigned: true };
|
|
29151
29197
|
}
|
|
29152
29198
|
/**
|
|
29153
29199
|
* Return the stored ownership record for a tab, or `null` if the tab
|