@buoy-gg/external-sync 7.0.77 → 7.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/attachDeviceSync.js +1 -1
- package/lib/commonjs/useExternalSync.js +1 -1
- package/lib/commonjs/useExternalSyncSocket.js +1 -1
- package/lib/module/attachDeviceSync.js +1 -1
- package/lib/module/useExternalSync.js +1 -1
- package/lib/module/useExternalSyncSocket.js +1 -1
- package/lib/typescript/attachDeviceSync.d.ts +8 -1
- package/lib/web/index.mjs +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.attachDeviceSync=attachDeviceSync;var _license=require("@buoy-gg/license");var _logger=require("./utils/logger");var _crashFlush=require("./crashFlush");var _emitBudget=require("./emitBudget");var _types=require("./types");var _realNow=require("./realNow");const LOG="[ExternalSync]";function attachDeviceSync({socket:r,deviceId:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.attachDeviceSync=attachDeviceSync;var _license=require("@buoy-gg/license");var _logger=require("./utils/logger");var _crashFlush=require("./crashFlush");var _emitBudget=require("./emitBudget");var _types=require("./types");var _realNow=require("./realNow");const LOG="[ExternalSync]";function attachDeviceSync({socket:r,deviceId:v,getTools:l,watched:b,throttleMs:E=200,enableLogs:d=false}){let q=false;let y=false;let g=0;const i=()=>!q&&y&&r.connected&&_license.LicenseManager.hasAccountAccess();const o=new Map;const _={};const a={};const $=e=>e==="All"||e===v;const m=(e,t)=>{if(!i())return;try{r.emit(e,t)}catch(n){(0,_logger.log)(`${LOG} Failed to emit "${e}": ${n}. Payload must be JSON-serializable.`,d,"error")}};const x=new Set;const p=e=>{if(!i())return;const t=l()[e];if(!t)return;_[e]=(0,_realNow.realNow)();let n;try{n=t.getSnapshot()}catch{return}const{over:c,approxBytes:u}=(0,_emitBudget.approxSizeOver)(n,_emitBudget.MAX_SNAPSHOT_EMIT_BYTES);if(c){if(!x.has(e)){x.add(e);console.warn("[Buoy]",`${LOG} "${e}" snapshot \u2248${(u/1e6).toFixed(1)}MB exceeds the ${_emitBudget.MAX_SNAPSHOT_EMIT_BYTES/1e6}MB sync budget \u2014 dropped (dashboard will be stale for this tool). The adapter should ship a wire-form snapshot (summaries + on-demand detail).`)}return}const N={toolId:e,persistentDeviceId:v,timestamp:_[e],version:t.version,kind:"snapshot",payload:n};m("devtool-sync",N)};const T=e=>{if(a[e])return;const t=(0,_realNow.realNow)()-(_[e]??0);if(t>=E){p(e);return}a[e]=setTimeout(()=>{delete a[e];p(e)},E-t)};const D=e=>{if(!r.connected)return;if(!o.has(e))return;if(a[e]){clearTimeout(a[e]);delete a[e]}p(e)};(0,_crashFlush.registerToolFlusher)(D);const f=new Map;const S=new Map;const M=(e,t)=>{if(!i())return;const n=l()[e];if(!n)return;if(o.has(e)){if(f.get(e)===t)return;const c=o.get(e);o.set(e,n.subscribe(t==="stream"?()=>T(e):()=>{}));f.set(e,t);S.set(e,n.subscribe);c?.();(0,_logger.log)(`${LOG} "${e}" watch mode \u2192 ${t}`,d);return}o.set(e,n.subscribe(t==="stream"?()=>T(e):()=>{}));f.set(e,t);S.set(e,n.subscribe);(0,_logger.log)(`${LOG} Watching "${e}" (${t})`,d)};const A=e=>{o.get(e)?.();o.delete(e);f.delete(e);S.delete(e);if(a[e]){clearTimeout(a[e]);delete a[e]}(0,_logger.log)(`${LOG} Stopped watching "${e}"`,d)};const V=()=>{if(!i())return;const e=l();for(const[t,n]of[...f]){const c=e[t];if(!c||S.get(t)===c.subscribe)continue;const u=o.get(t);o.delete(t);f.delete(t);M(t,n);u?.();(0,_logger.log)(`${LOG} "${t}" adapter replaced; watch moved`,d);if(n==="stream")T(t)}};const Y=()=>{const e={persistentDeviceId:v,protocolVersion:_types.SYNC_PROTOCOL_VERSION,tools:Object.entries(l()).map(([t,n])=>({toolId:t,version:n.version,actions:Object.keys(n.actions??{})}))};m("devtool-capabilities",e)};const F=e=>{if(!i()||!$(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";b.set(e.toolId,t);M(e.toolId,t);if(t==="stream")p(e.toolId)}else{b.delete(e.toolId);A(e.toolId)}};const P=e=>{if(!i()||!$(e.targetDeviceId))return;p(e.toolId)};const z=async e=>{if(!i()||!$(e.targetDeviceId))return;const t=g;const{requestId:n,toolId:c,action:u,params:N}=e;const s={requestId:n,toolId:c,action:u,persistentDeviceId:v,timestamp:(0,_realNow.realNow)(),ok:false};const j=l()[c];const L=j?.actions?.[u];if(!L){s.error=j?`Unknown action "${u}" on tool "${c}"`:`Unknown tool "${c}"`;m("devtool-action-result",s);return}try{s.result=await L(N);s.ok=true}catch(h){s.error=h instanceof Error?h.message:String(h)}if(t!==g||!i())return;if(s.ok){const{over:h,approxBytes:W}=(0,_emitBudget.approxSizeOver)(s.result,_emitBudget.MAX_ACTION_RESULT_BYTES);if(h){s.ok=false;s.result=void 0;s.error=`Result \u2248${(W/1e6).toFixed(1)}MB exceeds the ${_emitBudget.MAX_ACTION_RESULT_BYTES/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`}}s.timestamp=(0,_realNow.realNow)();m("devtool-action-result",s)};const w=()=>{g+=1;for(const t of[...o.keys()])A(t);b.clear();for(const t of Object.values(a))clearTimeout(t);const e=r;if(e.sendBuffer)e.sendBuffer=e.sendBuffer.filter(t=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(t.data?.[0])))};const O=()=>{const e=_license.LicenseManager.getState();if(e.tier!=="pro"&&(e.isInitialized===false||e.isValidating===true)){if(e.isInitialized===false)void _license.LicenseManager.initialize().then(()=>{if(i())O()},()=>void 0);return}r.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});Y()};const R=e=>{y=e?.protocol===1&&e.ready===true;if(!i())w();else O()};const U=_license.LicenseManager.subscribe(()=>{if(!_license.LicenseManager.hasAccountAccess()){if(r.connected)r.emit("device-license",{tier:"locked",isPro:"0"});w()}else if(i())O()});const B=()=>{y=false;r.emit("buoy:access:request")};const C=()=>{y=false;w()};r.on("buoy:access",R);for(const[e,t]of b){if(l()[e])M(e,t)}r.on("connect",B);r.on("disconnect",C);r.on("devtool-watch",F);r.on("request-devtool-state",P);r.on("devtool-action",z);if(r.connected)B();const X=()=>{q=true;U();r.off("buoy:access",R);w();(0,_crashFlush.unregisterToolFlusher)(D);r.off("connect",B);r.off("disconnect",C);r.off("devtool-watch",F);r.off("request-devtool-state",P);r.off("devtool-action",z);for(const e of[...o.keys()])A(e)};return Object.assign(X,{refreshTools:V})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useExternalSync=useExternalSync;var _license=require("@buoy-gg/license");var _react=require("react");var _attachDeviceSync=require("./attachDeviceSync");function useExternalSync({tools:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useExternalSync=useExternalSync;var _license=require("@buoy-gg/license");var _react=require("react");var _attachDeviceSync=require("./attachDeviceSync");function useExternalSync({tools:r,socket:e,deviceId:n,enabled:s=true,throttleMs:a=200,enableLogs:f=false}){const u=(0,_license.useAccountAccess)();const i=u.status==="admitted";const o=(0,_react.useRef)(r);o.current=r;const l=(0,_react.useRef)(new Map);(0,_react.useEffect)(()=>{if(!e||u.status!=="locked")return;const t=()=>e.emit("device-license",{tier:"locked",isPro:"0"});if(e.connected)t();e.on("connect",t);return()=>{e.off("connect",t)}},[e,u.status]);const d=Object.keys(r).sort().join(",");const c=(0,_react.useRef)(null);(0,_react.useEffect)(()=>{if(!e||!n||!s||!i){l.current.clear();return}const t=(0,_attachDeviceSync.attachDeviceSync)({socket:e,deviceId:n,getTools:()=>o.current,watched:l.current,throttleMs:a,enableLogs:f});c.current=t;return()=>{if(c.current===t)c.current=null;t()}},[e,n,s,i,a,f,d]);(0,_react.useEffect)(()=>{c.current?.refreshTools()},[r])}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.buildHandshakeQuery=buildHandshakeQuery;exports.closeWithPage=closeWithPage;exports.getInstanceId=getInstanceId;exports.useExternalSyncSocket=useExternalSyncSocket;exports.withPage=withPage;var _brokerAccess=require("./brokerAccess");var _react=require("react");var _socket=require("socket.io-client");var _platformUtils=require("./utils/platformUtils");var _getDefaultSocketURL=require("./utils/getDefaultSocketURL");var _logger=require("./utils/logger");var _syncStatusStore=require("./syncStatusStore");var _realNow=require("./realNow");const isDev=typeof __DEV__!=="undefined"?__DEV__:false;let globalSocketInstance=null;let currentSocketURL="";let currentDeviceId="";let currentPlatform="";let socketUsers=0;let releaseTimer=null;const RELEASE_GRACE_MS=2e3;const makeConnectionNonce=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function getInstanceId(){const e=globalThis;if(!e.__buoyInstanceId)e.__buoyInstanceId=makeConnectionNonce();return e.__buoyInstanceId}function buildHandshakeQuery(e){const u=t=>t&&Object.fromEntries(Object.entries(t).filter(([l])=>!
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.buildHandshakeQuery=buildHandshakeQuery;exports.closeWithPage=closeWithPage;exports.getInstanceId=getInstanceId;exports.useExternalSyncSocket=useExternalSyncSocket;exports.withPage=withPage;var _license=require("@buoy-gg/license");var _brokerAccess=require("./brokerAccess");var _react=require("react");var _socket=require("socket.io-client");var _platformUtils=require("./utils/platformUtils");var _getDefaultSocketURL=require("./utils/getDefaultSocketURL");var _logger=require("./utils/logger");var _syncStatusStore=require("./syncStatusStore");var _realNow=require("./realNow");const isDev=typeof __DEV__!=="undefined"?__DEV__:false;let globalSocketInstance=null;let currentSocketURL="";let currentDeviceId="";let currentPlatform="";let socketUsers=0;let releaseTimer=null;const RELEASE_GRACE_MS=2e3;const makeConnectionNonce=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function getInstanceId(){const e=globalThis;if(!e.__buoyInstanceId)e.__buoyInstanceId=makeConnectionNonce();return e.__buoyInstanceId}function buildHandshakeQuery(e){const u=t=>t&&Object.fromEntries(Object.entries(t).filter(([l])=>!(0,_license.isBuoyAccountKeyName)(l)));return{deviceName:e.deviceName,deviceId:e.persistentDeviceId,platform:e.platform,extraDeviceInfo:JSON.stringify(u(e.extraDeviceInfo)),envVariables:JSON.stringify(u(e.envVariables)),connectionNonce:makeConnectionNonce(),instanceId:getInstanceId()}}function withPage(e,u,t=globalThis.location){if(u!=="web"||!t?.host)return e;const l=t.pathname&&t.pathname!=="/"?t.pathname:"";return`${e} \xB7 ${t.host}${l.length>24?`${l.slice(0,23)}\u2026`:l}`}function closeWithPage(e,u){e.addEventListener("pagehide",()=>u()?.disconnect());e.addEventListener("pageshow",t=>{if(t.persisted)u()?.connect()})}let pageHooked=false;function disconnectWithPage(){const e=globalThis;if(pageHooked||!e.document||typeof e.addEventListener!=="function")return;pageHooked=true;closeWithPage(e,()=>globalSocketInstance)}function useExternalSyncSocket({deviceName:e,socketURL:u,persistentDeviceId:t,extraDeviceInfo:l,envVariables:$,platform:i,enableLogs:c=false}){const s=(0,_react.useRef)(null);const[a,v]=(0,_react.useState)(null);const[E,f]=(0,_react.useState)(false);const g=u??(0,_getDefaultSocketURL.getDefaultSocketURL)();const d=(0,_react.useRef)(false);const r=`[${e}]`;const S=()=>{(0,_logger.log)(`${r} Socket connected successfully`,c);d.current=false;f(true);(0,_syncStatusStore.setSyncStatus)({state:"connected",lastError:null})};const k=o=>{(0,_logger.log)(`${r} Socket disconnected. Reason: ${o}`,c);f(false);(0,_syncStatusStore.setSyncStatus)({state:"retrying"})};const y=o=>{(0,_syncStatusStore.setSyncStatus)({state:"retrying",lastError:o.message});if(!isDev)return;if(d.current)return;d.current=true;const n=i==="android"&&/localhost|127\.0\.0\.1/.test(currentSocketURL)?`If this device is connected over USB, run: adb reverse tcp:42831 tcp:42831. `:`If it's running on another machine or port, pass socketURL via the externalSync prop. `;(0,_logger.log)(`[buoy] desktop sync: can't reach ${currentSocketURL} (is Buoy Desktop running?). Retrying in the background. ${n}(${o.message})`,c,"warn")};const _=()=>{(0,_logger.log)(`${r} Socket connection timeout`,c,"error")};(0,_react.useEffect)(()=>{if(!t)return;const o=(0,_platformUtils.getPlatformSpecificURL)(g,i);(0,_syncStatusStore.setSyncStatus)({targetURL:o,state:"connecting",lastError:null});(0,_logger.log)(`${r} Platform: ${i}, using URL: ${o}`,c);try{if(globalSocketInstance&&(currentSocketURL!==o||currentDeviceId!==t||currentPlatform!==i)){globalSocketInstance.disconnect();globalSocketInstance=null}if(!globalSocketInstance){(0,_logger.log)(`${r} Creating new socket instance to ${o}`,c);try{const U=globalThis;(U.__BUOY_INTERNAL_HOSTS__??=new Set).add(new URL(o).host.toLowerCase())}catch{}globalSocketInstance=(0,_socket.io)(o,{autoConnect:true,query:buildHandshakeQuery({deviceName:withPage(e,i),persistentDeviceId:t,platform:i,extraDeviceInfo:l,envVariables:$}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});(0,_realNow.pinSocketTimers)(globalSocketInstance);disconnectWithPage();currentSocketURL=o;currentDeviceId=t;currentPlatform=i}else{(0,_logger.log)(`${r} Reusing existing socket instance to ${o}`,c)}s.current=globalSocketInstance;const n=s.current;socketUsers++;if(releaseTimer){(0,_realNow.realClearTimeout)(releaseTimer);releaseTimer=null}v(n);n.on("connect_error",y);n.on("connect_timeout",_);f(n.connected);if(n.connected){(0,_logger.log)(`${r} Socket already connected on init`,c)}n.on("connect",S);n.on("disconnect",k);return()=>{(0,_logger.log)(`${r} Cleaning up socket event listeners`,c);n.off("connect",S);n.off("disconnect",k);n.off("connect_error",y);n.off("connect_timeout",_);socketUsers--;if(socketUsers===0){releaseTimer=(0,_realNow.realSetTimeout)(()=>{releaseTimer=null;if(socketUsers>0||globalSocketInstance!==n)return;(0,_logger.log)(`${r} No longer used; disconnecting`,c);n.disconnect();globalSocketInstance=null;(0,_syncStatusStore.setSyncStatus)({state:"idle",lastError:null})},RELEASE_GRACE_MS)}}}catch(n){(0,_logger.log)(`${r} Failed to initialize socket: ${n}`,c,"error")}},[t,g,i]);(0,_react.useEffect)(()=>{if(s.current&&s.current.io.opts.query&&t){(0,_logger.log)(`${r} Updating device name in socket connection`,c);s.current.io.opts.query={...s.current.io.opts.query,deviceName:withPage(e,i),deviceId:t,platform:i}}},[e,r,t,i,c]);function m(){if(s.current&&!s.current.connected){(0,_logger.log)(`${r} Manually connecting to socket server`,c);s.current.connect()}}function p(){if(s.current&&s.current.connected){(0,_logger.log)(`${r} Manually disconnecting from socket server`,c);s.current.disconnect()}}const[h,R]=(0,_react.useState)(null);(0,_react.useEffect)(()=>{if(!a)return;return(0,_brokerAccess.watchBrokerAccess)(a,o=>{R(o?a:null);(0,_syncStatusStore.setSyncStatus)(o?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[a]);return{socket:h===a?a:null,connect:m,disconnect:p,isConnected:E&&h===a&&a!==null}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{LicenseManager as
|
|
1
|
+
"use strict";import{LicenseManager as v}from"@buoy-gg/license";import{log as b}from"./utils/logger";import{registerToolFlusher as I,unregisterToolFlusher as ee}from"./crashFlush";import{MAX_ACTION_RESULT_BYTES as X,MAX_SNAPSHOT_EMIT_BYTES as H,approxSizeOver as J}from"./emitBudget";import{SYNC_PROTOCOL_VERSION as te}from"./types";import{realNow as T}from"./realNow";const d="[ExternalSync]";export function attachDeviceSync({socket:n,deviceId:y,getTools:u,watched:$,throttleMs:z=200,enableLogs:p=false}){let F=false;let w=false;let B=0;const i=()=>!F&&w&&n.connected&&v.hasAccountAccess();const o=new Map;const M={};const a={};const x=e=>e==="All"||e===y;const S=(e,t)=>{if(!i())return;try{n.emit(e,t)}catch(r){b(`${d} Failed to emit "${e}": ${r}. Payload must be JSON-serializable.`,p,"error")}};const P=new Set;const h=e=>{if(!i())return;const t=u()[e];if(!t)return;M[e]=T();let r;try{r=t.getSnapshot()}catch{return}const{over:c,approxBytes:f}=J(r,H);if(c){if(!P.has(e)){P.add(e);console.warn("[Buoy]",`${d} "${e}" snapshot \u2248${(f/1e6).toFixed(1)}MB exceeds the ${H/1e6}MB sync budget \u2014 dropped (dashboard will be stale for this tool). The adapter should ship a wire-form snapshot (summaries + on-demand detail).`)}return}const q={toolId:e,persistentDeviceId:y,timestamp:M[e],version:t.version,kind:"snapshot",payload:r};S("devtool-sync",q)};const E=e=>{if(a[e])return;const t=T()-(M[e]??0);if(t>=z){h(e);return}a[e]=setTimeout(()=>{delete a[e];h(e)},z-t)};const R=e=>{if(!n.connected)return;if(!o.has(e))return;if(a[e]){clearTimeout(a[e]);delete a[e]}h(e)};I(R);const l=new Map;const A=new Map;const D=(e,t)=>{if(!i())return;const r=u()[e];if(!r)return;if(o.has(e)){if(l.get(e)===t)return;const c=o.get(e);o.set(e,r.subscribe(t==="stream"?()=>E(e):()=>{}));l.set(e,t);A.set(e,r.subscribe);c?.();b(`${d} "${e}" watch mode \u2192 ${t}`,p);return}o.set(e,r.subscribe(t==="stream"?()=>E(e):()=>{}));l.set(e,t);A.set(e,r.subscribe);b(`${d} Watching "${e}" (${t})`,p)};const N=e=>{o.get(e)?.();o.delete(e);l.delete(e);A.delete(e);if(a[e]){clearTimeout(a[e]);delete a[e]}b(`${d} Stopped watching "${e}"`,p)};const K=()=>{if(!i())return;const e=u();for(const[t,r]of[...l]){const c=e[t];if(!c||A.get(t)===c.subscribe)continue;const f=o.get(t);o.delete(t);l.delete(t);D(t,r);f?.();b(`${d} "${t}" adapter replaced; watch moved`,p);if(r==="stream")E(t)}};const L=()=>{const e={persistentDeviceId:y,protocolVersion:te,tools:Object.entries(u()).map(([t,r])=>({toolId:t,version:r.version,actions:Object.keys(r.actions??{})}))};S("devtool-capabilities",e)};const C=e=>{if(!i()||!x(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";$.set(e.toolId,t);D(e.toolId,t);if(t==="stream")h(e.toolId)}else{$.delete(e.toolId);N(e.toolId)}};const V=e=>{if(!i()||!x(e.targetDeviceId))return;h(e.toolId)};const j=async e=>{if(!i()||!x(e.targetDeviceId))return;const t=B;const{requestId:r,toolId:c,action:f,params:q}=e;const s={requestId:r,toolId:c,action:f,persistentDeviceId:y,timestamp:T(),ok:false};const Y=u()[c];const G=Y?.actions?.[f];if(!G){s.error=Y?`Unknown action "${f}" on tool "${c}"`:`Unknown tool "${c}"`;S("devtool-action-result",s);return}try{s.result=await G(q);s.ok=true}catch(m){s.error=m instanceof Error?m.message:String(m)}if(t!==B||!i())return;if(s.ok){const{over:m,approxBytes:k}=J(s.result,X);if(m){s.ok=false;s.result=void 0;s.error=`Result \u2248${(k/1e6).toFixed(1)}MB exceeds the ${X/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`}}s.timestamp=T();S("devtool-action-result",s)};const O=()=>{B+=1;for(const t of[...o.keys()])N(t);$.clear();for(const t of Object.values(a))clearTimeout(t);const e=n;if(e.sendBuffer)e.sendBuffer=e.sendBuffer.filter(t=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(t.data?.[0])))};const _=()=>{const e=v.getState();if(e.tier!=="pro"&&(e.isInitialized===false||e.isValidating===true)){if(e.isInitialized===false)void v.initialize().then(()=>{if(i())_()},()=>void 0);return}n.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});L()};const U=e=>{w=e?.protocol===1&&e.ready===true;if(!i())O();else _()};const Q=v.subscribe(()=>{if(!v.hasAccountAccess()){if(n.connected)n.emit("device-license",{tier:"locked",isPro:"0"});O()}else if(i())_()});const g=()=>{w=false;n.emit("buoy:access:request")};const W=()=>{w=false;O()};n.on("buoy:access",U);for(const[e,t]of $){if(u()[e])D(e,t)}n.on("connect",g);n.on("disconnect",W);n.on("devtool-watch",C);n.on("request-devtool-state",V);n.on("devtool-action",j);if(n.connected)g();const Z=()=>{F=true;Q();n.off("buoy:access",U);O();ee(R);n.off("connect",g);n.off("disconnect",W);n.off("devtool-watch",C);n.off("request-devtool-state",V);n.off("devtool-action",j);for(const e of[...o.keys()])N(e)};return Object.assign(Z,{refreshTools:K})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{useAccountAccess as
|
|
1
|
+
"use strict";import{useAccountAccess as h}from"@buoy-gg/license";import{useEffect as o,useRef as s}from"react";import{attachDeviceSync as y}from"./attachDeviceSync";export function useExternalSync({tools:e,socket:t,deviceId:c,enabled:f=true,throttleMs:i=200,enableLogs:a=false}){const u=h();const m=u.status==="admitted";const d=s(e);d.current=e;const l=s(new Map);o(()=>{if(!t||u.status!=="locked")return;const r=()=>t.emit("device-license",{tier:"locked",isPro:"0"});if(t.connected)r();t.on("connect",r);return()=>{t.off("connect",r)}},[t,u.status]);const p=Object.keys(e).sort().join(",");const n=s(null);o(()=>{if(!t||!c||!f||!m){l.current.clear();return}const r=y({socket:t,deviceId:c,getTools:()=>d.current,watched:l.current,throttleMs:i,enableLogs:a});n.current=r;return()=>{if(n.current===r)n.current=null;r()}},[t,c,f,m,i,a,p]);o(()=>{n.current?.refreshTools()},[e])}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{watchBrokerAccess as
|
|
1
|
+
"use strict";import{isBuoyAccountKeyName as q}from"@buoy-gg/license";import{watchBrokerAccess as V}from"./brokerAccess";import{useEffect as g,useRef as U,useState as p}from"react";import{io as H}from"socket.io-client";import{getPlatformSpecificURL as j}from"./utils/platformUtils";import{getDefaultSocketURL as J}from"./utils/getDefaultSocketURL";import{log as i}from"./utils/logger";import{setSyncStatus as m}from"./syncStatusStore";import{pinSocketTimers as K,realClearTimeout as W,realSetTimeout as z}from"./realNow";const F=typeof __DEV__!=="undefined"?__DEV__:false;let a=null;let h="";let w="";let x="";let y=0;let k=null;const G=2e3;const T=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;export function getInstanceId(){const t=globalThis;if(!t.__buoyInstanceId)t.__buoyInstanceId=T();return t.__buoyInstanceId}export function buildHandshakeQuery(t){const l=n=>n&&Object.fromEntries(Object.entries(n).filter(([d])=>!q(d)));return{deviceName:t.deviceName,deviceId:t.persistentDeviceId,platform:t.platform,extraDeviceInfo:JSON.stringify(l(t.extraDeviceInfo)),envVariables:JSON.stringify(l(t.envVariables)),connectionNonce:T(),instanceId:getInstanceId()}}export function withPage(t,l,n=globalThis.location){if(l!=="web"||!n?.host)return t;const d=n.pathname&&n.pathname!=="/"?n.pathname:"";return`${t} \xB7 ${n.host}${d.length>24?`${d.slice(0,23)}\u2026`:d}`}export function closeWithPage(t,l){t.addEventListener("pagehide",()=>l()?.disconnect());t.addEventListener("pageshow",n=>{if(n.persisted)l()?.connect()})}let A=false;function L(){const t=globalThis;if(A||!t.document||typeof t.addEventListener!=="function")return;A=true;closeWithPage(t,()=>a)}export function useExternalSyncSocket({deviceName:t,socketURL:l,persistentDeviceId:n,extraDeviceInfo:d,envVariables:N,platform:u,enableLogs:c=false}){const s=U(null);const[f,D]=p(null);const[O,S]=p(false);const _=l??J();const $=U(false);const r=`[${t}]`;const E=()=>{i(`${r} Socket connected successfully`,c);$.current=false;S(true);m({state:"connected",lastError:null})};const R=o=>{i(`${r} Socket disconnected. Reason: ${o}`,c);S(false);m({state:"retrying"})};const I=o=>{m({state:"retrying",lastError:o.message});if(!F)return;if($.current)return;$.current=true;const e=u==="android"&&/localhost|127\.0\.0\.1/.test(h)?`If this device is connected over USB, run: adb reverse tcp:42831 tcp:42831. `:`If it's running on another machine or port, pass socketURL via the externalSync prop. `;i(`[buoy] desktop sync: can't reach ${h} (is Buoy Desktop running?). Retrying in the background. ${e}(${o.message})`,c,"warn")};const v=()=>{i(`${r} Socket connection timeout`,c,"error")};g(()=>{if(!n)return;const o=j(_,u);m({targetURL:o,state:"connecting",lastError:null});i(`${r} Platform: ${u}, using URL: ${o}`,c);try{if(a&&(h!==o||w!==n||x!==u)){a.disconnect();a=null}if(!a){i(`${r} Creating new socket instance to ${o}`,c);try{const M=globalThis;(M.__BUOY_INTERNAL_HOSTS__??=new Set).add(new URL(o).host.toLowerCase())}catch{}a=H(o,{autoConnect:true,query:buildHandshakeQuery({deviceName:withPage(t,u),persistentDeviceId:n,platform:u,extraDeviceInfo:d,envVariables:N}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});K(a);L();h=o;w=n;x=u}else{i(`${r} Reusing existing socket instance to ${o}`,c)}s.current=a;const e=s.current;y++;if(k){W(k);k=null}D(e);e.on("connect_error",I);e.on("connect_timeout",v);S(e.connected);if(e.connected){i(`${r} Socket already connected on init`,c)}e.on("connect",E);e.on("disconnect",R);return()=>{i(`${r} Cleaning up socket event listeners`,c);e.off("connect",E);e.off("disconnect",R);e.off("connect_error",I);e.off("connect_timeout",v);y--;if(y===0){k=z(()=>{k=null;if(y>0||a!==e)return;i(`${r} No longer used; disconnecting`,c);e.disconnect();a=null;m({state:"idle",lastError:null})},G)}}}catch(e){i(`${r} Failed to initialize socket: ${e}`,c,"error")}},[n,_,u]);g(()=>{if(s.current&&s.current.io.opts.query&&n){i(`${r} Updating device name in socket connection`,c);s.current.io.opts.query={...s.current.io.opts.query,deviceName:withPage(t,u),deviceId:n,platform:u}}},[t,r,n,u,c]);function P(){if(s.current&&!s.current.connected){i(`${r} Manually connecting to socket server`,c);s.current.connect()}}function b(){if(s.current&&s.current.connected){i(`${r} Manually disconnecting from socket server`,c);s.current.disconnect()}}const[C,B]=p(null);g(()=>{if(!f)return;return V(f,o=>{B(o?f:null);m(o?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[f]);return{socket:C===f?f:null,connect:P,disconnect:b,isConnected:O&&C===f&&f!==null}}
|
|
@@ -24,9 +24,16 @@ export type AttachDeviceSyncOptions = {
|
|
|
24
24
|
throttleMs?: number;
|
|
25
25
|
enableLogs?: boolean;
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Detaches the bridge. `refreshTools` moves any live watch whose adapter was
|
|
29
|
+
* replaced under the same toolId onto the new adapter.
|
|
30
|
+
*/
|
|
31
|
+
export type DetachDeviceSync = (() => void) & {
|
|
32
|
+
refreshTools: () => void;
|
|
33
|
+
};
|
|
27
34
|
/**
|
|
28
35
|
* Device-side sync bridge (no React). A tool's adapter is only subscribed
|
|
29
36
|
* while a dashboard is watching it (`devtool-watch`).
|
|
30
37
|
*/
|
|
31
|
-
export declare function attachDeviceSync({ socket, deviceId, getTools, watched, throttleMs, enableLogs, }: AttachDeviceSyncOptions):
|
|
38
|
+
export declare function attachDeviceSync({ socket, deviceId, getTools, watched, throttleMs, enableLogs, }: AttachDeviceSyncOptions): DetachDeviceSync;
|
|
32
39
|
//# sourceMappingURL=attachDeviceSync.d.ts.map
|
package/lib/web/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";var ne=(()=>{try{let e=globalThis.Capacitor;if(e&&typeof e.isNativePlatform=="function"&&e.isNativePlatform())return e.DEBUG===true}catch{}return process.env.NODE_ENV!=="production"})();typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);import{useAccountAccess as _e}from"@buoy-gg/license/web";import{useEffect as oe,useRef as re}from"react";import{LicenseManager as L}from"@buoy-gg/license/web";function p(e,o,n="log"){if(!(!o&&n==="log"))switch(n){case"warn":console.warn("[Buoy]",e);break;case"error":console.error("[Buoy]",e);break;default:console.log("[Buoy]",e)}}var z="__buoyFlushToolSync";function H(){let e=globalThis;return e[z]||(e[z]=new Set),e[z]}function ce(e){H().add(e)}function ie(e){H().delete(e)}function $e(e){try{for(let o of H())try{o(e)}catch{}}catch{}}function se(e,o){let n=0,s=[e],l=new Set;for(;s.length>0;){if(n>o)return{over:true,approxBytes:n};let r=s.pop();if(r==null)n+=4;else if(typeof r=="string")n+=r.length+2;else if(typeof r=="number")n+=8;else if(typeof r=="boolean")n+=5;else if(typeof r=="object"){if(l.has(r))continue;if(l.add(r),Array.isArray(r)){n+=2+r.length;for(let c=0;c<r.length;c++)s.push(r[c])}else{n+=2;for(let c in r)n+=c.length+4,s.push(r[c])}}else n+=4}return{over:n>o,approxBytes:n}}var Ie=1;function x(){let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()}function ae(){return globalThis.__buoyRealTimers??globalThis}function le(e,o){return ae().setTimeout(e,o)}function ue(e){ae().clearTimeout(e)}function Se(e){let o=globalThis.__buoyWithRealClock;return typeof o=="function"?o(e):e()}var ke=["_resetPingTimeout","_hasPingExpired"];function Te(e){let o=e?.io;if(!o||o.__buoyRealTimers)return;let n=l=>{if(l){l.setTimeoutFn=le,l.clearTimeoutFn=ue;for(let r of ke){let c=l[r];if(typeof c!="function"||c.__buoyReal)continue;let a=function(...y){return Se(()=>c.apply(this,y))};a.__buoyReal=true,l[r]=a}}};n(o),n(o.engine);let s=o.open;typeof s=="function"&&(o.open=function(...l){let r=s.apply(this,l);return n(this?.engine),r}),o.__buoyRealTimers=true}var P="[ExternalSync]";function Ee({socket:e,deviceId:o,getTools:n,watched:s,throttleMs:l=200,enableLogs:r=false}){let c=false,a=false,y=0,h=()=>!c&&a&&e.connected&&L.hasAccountAccess(),m=new Map,_={},v={},k=t=>t==="All"||t===o,f=(t,i)=>{if(h())try{e.emit(t,i)}catch(g){p(`${P} Failed to emit "${t}": ${g}. Payload must be JSON-serializable.`,r,"error")}},B=new Set,I=t=>{if(!h())return;let i=n()[t];if(!i)return;_[t]=x();let g;try{g=i.getSnapshot()}catch{return}let{over:S,approxBytes:U}=se(g,2097152);if(S){B.has(t)||(B.add(t),console.warn("[Buoy]",`${P} "${t}" snapshot \u2248${(U/1e6).toFixed(1)}MB exceeds the ${2097152/1e6}MB sync budget \u2014 dropped (dashboard will be stale for this tool). The adapter should ship a wire-form snapshot (summaries + on-demand detail).`));return}let j={toolId:t,persistentDeviceId:o,timestamp:_[t],version:i.version,kind:"snapshot",payload:g};f("devtool-sync",j)},R=t=>{if(v[t])return;let i=x()-(_[t]??0);if(i>=l){I(t);return}v[t]=setTimeout(()=>{delete v[t],I(t)},l-i)},O=t=>{e.connected&&m.has(t)&&(v[t]&&(clearTimeout(v[t]),delete v[t]),I(t))};ce(O);let E=new Map,A=(t,i)=>{if(!h())return;let g=n()[t];if(g){if(m.has(t)){if(E.get(t)===i)return;let S=m.get(t);m.set(t,g.subscribe(i==="stream"?()=>R(t):()=>{})),E.set(t,i),S?.(),p(`${P} "${t}" watch mode \u2192 ${i}`,r);return}m.set(t,g.subscribe(i==="stream"?()=>R(t):()=>{})),E.set(t,i),p(`${P} Watching "${t}" (${i})`,r)}},w=t=>{m.get(t)?.(),m.delete(t),E.delete(t),v[t]&&(clearTimeout(v[t]),delete v[t]),p(`${P} Stopped watching "${t}"`,r)},F=()=>{let t={persistentDeviceId:o,protocolVersion:1,tools:Object.entries(n()).map(([i,g])=>({toolId:i,version:g.version,actions:Object.keys(g.actions??{})}))};f("devtool-capabilities",t)},d=t=>{if(!(!h()||!k(t.targetDeviceId)))if(t.watching){let i=t.consolidated===true&&t.stream===false?"capture":"stream";s.set(t.toolId,i),A(t.toolId,i),i==="stream"&&I(t.toolId)}else s.delete(t.toolId),w(t.toolId)},u=t=>{!h()||!k(t.targetDeviceId)||I(t.toolId)},N=async t=>{if(!h()||!k(t.targetDeviceId))return;let i=y,{requestId:g,toolId:S,action:U,params:j}=t,b={requestId:g,toolId:S,action:U,persistentDeviceId:o,timestamp:x(),ok:false},ee=n()[S],te=ee?.actions?.[U];if(!te){b.error=ee?`Unknown action "${U}" on tool "${S}"`:`Unknown tool "${S}"`,f("devtool-action-result",b);return}try{b.result=await te(j),b.ok=true}catch(D){b.error=D instanceof Error?D.message:String(D)}if(!(i!==y||!h())){if(b.ok){let{over:D,approxBytes:be}=se(b.result,8388608);D&&(b.ok=false,b.result=void 0,b.error=`Result \u2248${(be/1e6).toFixed(1)}MB exceeds the ${8388608/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`)}b.timestamp=x(),f("devtool-action-result",b)}},Y=()=>{y+=1;for(let i of[...m.keys()])w(i);s.clear();for(let i of Object.values(v))clearTimeout(i);let t=e;t.sendBuffer&&(t.sendBuffer=t.sendBuffer.filter(i=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(i.data?.[0]))))},V=()=>{let t=L.getState();if(t.tier!=="pro"&&(t.isInitialized===false||t.isValidating===true)){t.isInitialized===false&&L.initialize().then(()=>{h()&&V()},()=>{});return}e.emit("device-license",{tier:t.tier,isPro:t.isPro?"1":"0"}),F()},Q=t=>{a=t?.protocol===1&&t.ready===true,h()?V():Y()},ve=L.subscribe(()=>{L.hasAccountAccess()?h()&&V():(e.connected&&e.emit("device-license",{tier:"locked",isPro:"0"}),Y())}),K=()=>{a=false,e.emit("buoy:access:request")},Z=()=>{a=false,Y()};e.on("buoy:access",Q);for(let[t,i]of s)n()[t]&&A(t,i);return e.on("connect",K),e.on("disconnect",Z),e.on("devtool-watch",d),e.on("request-devtool-state",u),e.on("devtool-action",N),e.connected&&K(),()=>{c=true,ve(),e.off("buoy:access",Q),Y(),ie(O),e.off("connect",K),e.off("disconnect",Z),e.off("devtool-watch",d),e.off("request-devtool-state",u),e.off("devtool-action",N);for(let t of[...m.keys()])w(t)}}function we({tools:e,socket:o,deviceId:n,enabled:s=true,throttleMs:l=200,enableLogs:r=false}){let c=_e(),a=c.status==="admitted",y=re(e);y.current=e;let h=re(new Map);oe(()=>{if(!o||c.status!=="locked")return;let _=()=>o.emit("device-license",{tier:"locked",isPro:"0"});return o.connected&&_(),o.on("connect",_),()=>{o.off("connect",_)}},[o,c.status]);let m=Object.keys(e).sort().join(",");oe(()=>{if(!o||!n||!s||!a){h.current.clear();return}return Ee({socket:o,deviceId:n,getTools:()=>y.current,watched:h.current,throttleMs:l,enableLogs:r})},[o,n,s,a,l,r,m])}function Be(e,o){let n=()=>o(false),s=()=>{n(),e.emit("buoy:access:request")},l=r=>{let c=r;o(c?.protocol===1&&c?.ready===true)};return e.on("connect",s),e.on("disconnect",n),e.on("buoy:access",l),n(),e.connected&&s(),()=>{e.off("connect",s),e.off("disconnect",n),e.off("buoy:access",l)}}import{useEffect as J,useRef as fe,useState as W}from"react";import{io as Re}from"socket.io-client";function Oe(e,o){return e}var Ne=42831;function Ue(e){return`http://${e??"localhost"}:42831`}function De(){return null}function de(){return Ue(typeof location>"u"?null:location.hostname)}var X={targetURL:null,state:"idle",lastError:null,since:0},G=new Set;function T(e){X={...X,...e,since:x()},G.forEach(o=>o())}function Le(){return X}function xe(e){return G.add(e),()=>{G.delete(e)}}var Pe=typeof ne<"u"?ne:false,$=null,C="",pe="",ye="",q=0,M=null,Me=2e3,he=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function Ae(){let e=globalThis;return e.__buoyInstanceId||(e.__buoyInstanceId=he()),e.__buoyInstanceId}function Ye(e){let o=n=>n&&Object.fromEntries(Object.entries(n).filter(([s])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(s)));return{deviceName:e.deviceName,deviceId:e.persistentDeviceId,platform:e.platform,extraDeviceInfo:JSON.stringify(o(e.extraDeviceInfo)),envVariables:JSON.stringify(o(e.envVariables)),connectionNonce:he(),instanceId:Ae()}}function ge(e,o,n=globalThis.location){if(o!=="web"||!n?.host)return e;let s=n.pathname&&n.pathname!=="/"?n.pathname:"";return`${e} \xB7 ${n.host}${s.length>24?`${s.slice(0,23)}\u2026`:s}`}function Ce(e,o){e.addEventListener("pagehide",()=>o()?.disconnect()),e.addEventListener("pageshow",n=>{n.persisted&&o()?.connect()})}var me=false;function qe(){let e=globalThis;me||!e.document||typeof e.addEventListener!="function"||(me=true,Ce(e,()=>$))}function Fe({deviceName:e,socketURL:o,persistentDeviceId:n,extraDeviceInfo:s,envVariables:l,platform:r,enableLogs:c=false}){let a=fe(null),[y,h]=W(null),[m,_]=W(false),v=o??de(),k=fe(false),f=`[${e}]`,B=()=>{p(`${f} Socket connected successfully`,c),k.current=false,_(true),T({state:"connected",lastError:null})},I=d=>{p(`${f} Socket disconnected. Reason: ${d}`,c),_(false),T({state:"retrying"})},R=d=>{if(T({state:"retrying",lastError:d.message}),!Pe||k.current)return;k.current=true;let u=r==="android"&&/localhost|127\.0\.0\.1/.test(C)?"If this device is connected over USB, run: adb reverse tcp:42831 tcp:42831. ":"If it's running on another machine or port, pass socketURL via the externalSync prop. ";p(`[buoy] desktop sync: can't reach ${C} (is Buoy Desktop running?). Retrying in the background. ${u}(${d.message})`,c,"warn")},O=()=>{p(`${f} Socket connection timeout`,c,"error")};J(()=>{if(!n)return;let d=Oe(v,r);T({targetURL:d,state:"connecting",lastError:null}),p(`${f} Platform: ${r}, using URL: ${d}`,c);try{if($&&(C!==d||pe!==n||ye!==r)&&($.disconnect(),$=null),$)p(`${f} Reusing existing socket instance to ${d}`,c);else{p(`${f} Creating new socket instance to ${d}`,c);try{let N=globalThis;(N.__BUOY_INTERNAL_HOSTS__??(N.__BUOY_INTERNAL_HOSTS__=new Set)).add(new URL(d).host.toLowerCase())}catch{}$=Re(d,{autoConnect:true,query:Ye({deviceName:ge(e,r),persistentDeviceId:n,platform:r,extraDeviceInfo:s,envVariables:l}),reconnection:true,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]}),Te($),qe(),C=d,pe=n,ye=r}a.current=$;let u=a.current;return q++,M&&(ue(M),M=null),h(u),u.on("connect_error",R),u.on("connect_timeout",O),_(u.connected),u.connected&&p(`${f} Socket already connected on init`,c),u.on("connect",B),u.on("disconnect",I),()=>{p(`${f} Cleaning up socket event listeners`,c),u.off("connect",B),u.off("disconnect",I),u.off("connect_error",R),u.off("connect_timeout",O),q--,q===0&&(M=le(()=>{M=null,!(q>0||$!==u)&&(p(`${f} No longer used; disconnecting`,c),u.disconnect(),$=null,T({state:"idle",lastError:null}))},Me))}}catch(u){p(`${f} Failed to initialize socket: ${u}`,c,"error")}},[n,v,r]),J(()=>{a.current&&a.current.io.opts.query&&n&&(p(`${f} Updating device name in socket connection`,c),a.current.io.opts.query={...a.current.io.opts.query,deviceName:ge(e,r),deviceId:n,platform:r})},[e,f,n,r,c]);function E(){a.current&&!a.current.connected&&(p(`${f} Manually connecting to socket server`,c),a.current.connect())}function A(){a.current&&a.current.connected&&(p(`${f} Manually disconnecting from socket server`,c),a.current.disconnect())}let[w,F]=W(null);return J(()=>{if(y)return Be(y,d=>{F(d?y:null),T(d?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[y]),{socket:w===y?y:null,connect:E,disconnect:A,isConnected:m&&w===y&&y!==null}}export{Ne as DEFAULT_BROKER_PORT,Ie as SYNC_PROTOCOL_VERSION,$e as flushToolSyncNow,de as getDefaultSocketURL,De as getMetroHost,Le as getSyncStatus,ce as registerToolFlusher,T as setSyncStatus,xe as subscribeSyncStatus,ie as unregisterToolFlusher,we as useExternalSync,Fe as useExternalSyncSocket};
|
|
1
|
+
"use client";var se=(()=>{try{let e=globalThis.Capacitor;if(e&&typeof e.isNativePlatform=="function"&&e.isNativePlatform())return e.DEBUG===true}catch{}return process.env.NODE_ENV!=="production"})();typeof window<"u"&&typeof globalThis.global>"u"&&(globalThis.global=globalThis);import{useAccountAccess as _e}from"@buoy-gg/license/web";import{useEffect as K,useRef as Y}from"react";import{LicenseManager as A}from"@buoy-gg/license/web";function y(e,o,n="log"){if(!(!o&&n==="log"))switch(n){case"warn":console.warn("[Buoy]",e);break;case"error":console.error("[Buoy]",e);break;default:console.log("[Buoy]",e)}}var J="__buoyFlushToolSync";function W(){let e=globalThis;return e[J]||(e[J]=new Set),e[J]}function ie(e){W().add(e)}function ae(e){W().delete(e)}function Ie(e){try{for(let o of W())try{o(e)}catch{}}catch{}}function le(e,o){let n=0,i=[e],l=new Set;for(;i.length>0;){if(n>o)return{over:true,approxBytes:n};let r=i.pop();if(r==null)n+=4;else if(typeof r=="string")n+=r.length+2;else if(typeof r=="number")n+=8;else if(typeof r=="boolean")n+=5;else if(typeof r=="object"){if(l.has(r))continue;if(l.add(r),Array.isArray(r)){n+=2+r.length;for(let s=0;s<r.length;s++)i.push(r[s])}else{n+=2;for(let s in r)n+=s.length+4,i.push(r[s])}}else n+=4}return{over:n>o,approxBytes:n}}var Se=1;function P(){let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()}function ue(){return globalThis.__buoyRealTimers??globalThis}function de(e,o){return ue().setTimeout(e,o)}function fe(e){ue().clearTimeout(e)}function Te(e){let o=globalThis.__buoyWithRealClock;return typeof o=="function"?o(e):e()}var we=["_resetPingTimeout","_hasPingExpired"];function Ee(e){let o=e?.io;if(!o||o.__buoyRealTimers)return;let n=l=>{if(l){l.setTimeoutFn=de,l.clearTimeoutFn=fe;for(let r of we){let s=l[r];if(typeof s!="function"||s.__buoyReal)continue;let a=function(...h){return Te(()=>s.apply(this,h))};a.__buoyReal=true,l[r]=a}}};n(o),n(o.engine);let i=o.open;typeof i=="function"&&(o.open=function(...l){let r=i.apply(this,l);return n(this?.engine),r}),o.__buoyRealTimers=true}var D="[ExternalSync]";function Re({socket:e,deviceId:o,getTools:n,watched:i,throttleMs:l=200,enableLogs:r=false}){let s=false,a=false,h=0,m=()=>!s&&a&&e.connected&&A.hasAccountAccess(),b=new Map,v={},u={},T=t=>t==="All"||t===o,d=(t,c)=>{if(m())try{e.emit(t,c)}catch(p){y(`${D} Failed to emit "${t}": ${p}. Payload must be JSON-serializable.`,r,"error")}},x=new Set,I=t=>{if(!m())return;let c=n()[t];if(!c)return;v[t]=P();let p;try{p=c.getSnapshot()}catch{return}let{over:k,approxBytes:w}=le(p,2097152);if(k){x.has(t)||(x.add(t),console.warn("[Buoy]",`${D} "${t}" snapshot \u2248${(w/1e6).toFixed(1)}MB exceeds the ${2097152/1e6}MB sync budget \u2014 dropped (dashboard will be stale for this tool). The adapter should ship a wire-form snapshot (summaries + on-demand detail).`));return}let H={toolId:t,persistentDeviceId:o,timestamp:v[t],version:c.version,kind:"snapshot",payload:p};d("devtool-sync",H)},R=t=>{if(u[t])return;let c=P()-(v[t]??0);if(c>=l){I(t);return}u[t]=setTimeout(()=>{delete u[t],I(t)},l-c)},O=t=>{e.connected&&b.has(t)&&(u[t]&&(clearTimeout(u[t]),delete u[t]),I(t))};ie(O);let S=new Map,B=new Map,N=(t,c)=>{if(!m())return;let p=n()[t];if(p){if(b.has(t)){if(S.get(t)===c)return;let k=b.get(t);b.set(t,p.subscribe(c==="stream"?()=>R(t):()=>{})),S.set(t,c),B.set(t,p.subscribe),k?.(),y(`${D} "${t}" watch mode \u2192 ${c}`,r);return}b.set(t,p.subscribe(c==="stream"?()=>R(t):()=>{})),S.set(t,c),B.set(t,p.subscribe),y(`${D} Watching "${t}" (${c})`,r)}},L=t=>{b.get(t)?.(),b.delete(t),S.delete(t),B.delete(t),u[t]&&(clearTimeout(u[t]),delete u[t]),y(`${D} Stopped watching "${t}"`,r)},g=()=>{if(!m())return;let t=n();for(let[c,p]of[...S]){let k=t[c];if(!k||B.get(c)===k.subscribe)continue;let w=b.get(c);b.delete(c),S.delete(c),N(c,p),w?.(),y(`${D} "${c}" adapter replaced; watch moved`,r),p==="stream"&&R(c)}},f=()=>{let t={persistentDeviceId:o,protocolVersion:1,tools:Object.entries(n()).map(([c,p])=>({toolId:c,version:p.version,actions:Object.keys(p.actions??{})}))};d("devtool-capabilities",t)},M=t=>{if(!(!m()||!T(t.targetDeviceId)))if(t.watching){let c=t.consolidated===true&&t.stream===false?"capture":"stream";i.set(t.toolId,c),N(t.toolId,c),c==="stream"&&I(t.toolId)}else i.delete(t.toolId),L(t.toolId)},ee=t=>{!m()||!T(t.targetDeviceId)||I(t.toolId)},te=async t=>{if(!m()||!T(t.targetDeviceId))return;let c=h,{requestId:p,toolId:k,action:w,params:H}=t,$={requestId:p,toolId:k,action:w,persistentDeviceId:o,timestamp:P(),ok:false},re=n()[k],ce=re?.actions?.[w];if(!ce){$.error=re?`Unknown action "${w}" on tool "${k}"`:`Unknown tool "${k}"`,d("devtool-action-result",$);return}try{$.result=await ce(H),$.ok=true}catch(U){$.error=U instanceof Error?U.message:String(U)}if(!(c!==h||!m())){if($.ok){let{over:U,approxBytes:ke}=le($.result,8388608);U&&($.ok=false,$.result=void 0,$.error=`Result \u2248${(ke/1e6).toFixed(1)}MB exceeds the ${8388608/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`)}$.timestamp=P(),d("devtool-action-result",$)}},F=()=>{h+=1;for(let c of[...b.keys()])L(c);i.clear();for(let c of Object.values(u))clearTimeout(c);let t=e;t.sendBuffer&&(t.sendBuffer=t.sendBuffer.filter(c=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(c.data?.[0]))))},V=()=>{let t=A.getState();if(t.tier!=="pro"&&(t.isInitialized===false||t.isValidating===true)){t.isInitialized===false&&A.initialize().then(()=>{m()&&V()},()=>{});return}e.emit("device-license",{tier:t.tier,isPro:t.isPro?"1":"0"}),f()},ne=t=>{a=t?.protocol===1&&t.ready===true,m()?V():F()},$e=A.subscribe(()=>{A.hasAccountAccess()?m()&&V():(e.connected&&e.emit("device-license",{tier:"locked",isPro:"0"}),F())}),z=()=>{a=false,e.emit("buoy:access:request")},oe=()=>{a=false,F()};e.on("buoy:access",ne);for(let[t,c]of i)n()[t]&&N(t,c);return e.on("connect",z),e.on("disconnect",oe),e.on("devtool-watch",M),e.on("request-devtool-state",ee),e.on("devtool-action",te),e.connected&&z(),Object.assign(()=>{s=true,$e(),e.off("buoy:access",ne),F(),ae(O),e.off("connect",z),e.off("disconnect",oe),e.off("devtool-watch",M),e.off("request-devtool-state",ee),e.off("devtool-action",te);for(let t of[...b.keys()])L(t)},{refreshTools:g})}function Be({tools:e,socket:o,deviceId:n,enabled:i=true,throttleMs:l=200,enableLogs:r=false}){let s=_e(),a=s.status==="admitted",h=Y(e);h.current=e;let m=Y(new Map);K(()=>{if(!o||s.status!=="locked")return;let u=()=>o.emit("device-license",{tier:"locked",isPro:"0"});return o.connected&&u(),o.on("connect",u),()=>{o.off("connect",u)}},[o,s.status]);let b=Object.keys(e).sort().join(","),v=Y(null);K(()=>{if(!o||!n||!i||!a){m.current.clear();return}let u=Re({socket:o,deviceId:n,getTools:()=>h.current,watched:m.current,throttleMs:l,enableLogs:r});return v.current=u,()=>{v.current===u&&(v.current=null),u()}},[o,n,i,a,l,r,b]),K(()=>{v.current?.refreshTools()},[e])}import{isBuoyAccountKeyName as Ne}from"@buoy-gg/license/web";function De(e,o){let n=()=>o(false),i=()=>{n(),e.emit("buoy:access:request")},l=r=>{let s=r;o(s?.protocol===1&&s?.ready===true)};return e.on("connect",i),e.on("disconnect",n),e.on("buoy:access",l),n(),e.connected&&i(),()=>{e.off("connect",i),e.off("disconnect",n),e.off("buoy:access",l)}}import{useEffect as G,useRef as pe,useState as Q}from"react";import{io as xe}from"socket.io-client";function Oe(e,o){return e}var Le=42831;function Me(e){return`http://${e??"localhost"}:42831`}function Ue(){return null}function ye(){return Me(typeof location>"u"?null:location.hostname)}var X={targetURL:null,state:"idle",lastError:null,since:0},Z=new Set;function E(e){X={...X,...e,since:P()},Z.forEach(o=>o())}function Ae(){return X}function Pe(e){return Z.add(e),()=>{Z.delete(e)}}var qe=typeof se<"u"?se:false,_=null,C="",ge="",he="",j=0,q=null,Fe=2e3,me=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function Ce(){let e=globalThis;return e.__buoyInstanceId||(e.__buoyInstanceId=me()),e.__buoyInstanceId}function je(e){let o=n=>n&&Object.fromEntries(Object.entries(n).filter(([i])=>!Ne(i)));return{deviceName:e.deviceName,deviceId:e.persistentDeviceId,platform:e.platform,extraDeviceInfo:JSON.stringify(o(e.extraDeviceInfo)),envVariables:JSON.stringify(o(e.envVariables)),connectionNonce:me(),instanceId:Ce()}}function be(e,o,n=globalThis.location){if(o!=="web"||!n?.host)return e;let i=n.pathname&&n.pathname!=="/"?n.pathname:"";return`${e} \xB7 ${n.host}${i.length>24?`${i.slice(0,23)}\u2026`:i}`}function Ve(e,o){e.addEventListener("pagehide",()=>o()?.disconnect()),e.addEventListener("pageshow",n=>{n.persisted&&o()?.connect()})}var ve=false;function ze(){let e=globalThis;ve||!e.document||typeof e.addEventListener!="function"||(ve=true,Ve(e,()=>_))}function He({deviceName:e,socketURL:o,persistentDeviceId:n,extraDeviceInfo:i,envVariables:l,platform:r,enableLogs:s=false}){let a=pe(null),[h,m]=Q(null),[b,v]=Q(false),u=o??ye(),T=pe(false),d=`[${e}]`,x=()=>{y(`${d} Socket connected successfully`,s),T.current=false,v(true),E({state:"connected",lastError:null})},I=g=>{y(`${d} Socket disconnected. Reason: ${g}`,s),v(false),E({state:"retrying"})},R=g=>{if(E({state:"retrying",lastError:g.message}),!qe||T.current)return;T.current=true;let f=r==="android"&&/localhost|127\.0\.0\.1/.test(C)?"If this device is connected over USB, run: adb reverse tcp:42831 tcp:42831. ":"If it's running on another machine or port, pass socketURL via the externalSync prop. ";y(`[buoy] desktop sync: can't reach ${C} (is Buoy Desktop running?). Retrying in the background. ${f}(${g.message})`,s,"warn")},O=()=>{y(`${d} Socket connection timeout`,s,"error")};G(()=>{if(!n)return;let g=Oe(u,r);E({targetURL:g,state:"connecting",lastError:null}),y(`${d} Platform: ${r}, using URL: ${g}`,s);try{if(_&&(C!==g||ge!==n||he!==r)&&(_.disconnect(),_=null),_)y(`${d} Reusing existing socket instance to ${g}`,s);else{y(`${d} Creating new socket instance to ${g}`,s);try{let M=globalThis;(M.__BUOY_INTERNAL_HOSTS__??(M.__BUOY_INTERNAL_HOSTS__=new Set)).add(new URL(g).host.toLowerCase())}catch{}_=xe(g,{autoConnect:true,query:je({deviceName:be(e,r),persistentDeviceId:n,platform:r,extraDeviceInfo:i,envVariables:l}),reconnection:true,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]}),Ee(_),ze(),C=g,ge=n,he=r}a.current=_;let f=a.current;return j++,q&&(fe(q),q=null),m(f),f.on("connect_error",R),f.on("connect_timeout",O),v(f.connected),f.connected&&y(`${d} Socket already connected on init`,s),f.on("connect",x),f.on("disconnect",I),()=>{y(`${d} Cleaning up socket event listeners`,s),f.off("connect",x),f.off("disconnect",I),f.off("connect_error",R),f.off("connect_timeout",O),j--,j===0&&(q=de(()=>{q=null,!(j>0||_!==f)&&(y(`${d} No longer used; disconnecting`,s),f.disconnect(),_=null,E({state:"idle",lastError:null}))},Fe))}}catch(f){y(`${d} Failed to initialize socket: ${f}`,s,"error")}},[n,u,r]),G(()=>{a.current&&a.current.io.opts.query&&n&&(y(`${d} Updating device name in socket connection`,s),a.current.io.opts.query={...a.current.io.opts.query,deviceName:be(e,r),deviceId:n,platform:r})},[e,d,n,r,s]);function S(){a.current&&!a.current.connected&&(y(`${d} Manually connecting to socket server`,s),a.current.connect())}function B(){a.current&&a.current.connected&&(y(`${d} Manually disconnecting from socket server`,s),a.current.disconnect())}let[N,L]=Q(null);return G(()=>{if(h)return De(h,g=>{L(g?h:null),E(g?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[h]),{socket:N===h?h:null,connect:S,disconnect:B,isConnected:b&&N===h&&h!==null}}export{Le as DEFAULT_BROKER_PORT,Se as SYNC_PROTOCOL_VERSION,Ie as flushToolSyncNow,ye as getDefaultSocketURL,Ue as getMetroHost,Ae as getSyncStatus,ie as registerToolFlusher,E as setSyncStatus,Pe as subscribeSyncStatus,ae as unregisterToolFlusher,Be as useExternalSync,He as useExternalSyncSocket};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/external-sync",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.79",
|
|
4
4
|
"description": "Generic device-to-desktop sync for Buoy dev tools",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"sideEffects": false,
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"socket.io-client": "^4.8.4",
|
|
38
|
-
"@buoy-gg/license": "^7.0.
|
|
38
|
+
"@buoy-gg/license": "^7.0.79"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"react": "*"
|