@buoy-gg/external-sync 7.0.63 → 7.0.64

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.
@@ -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:p,getTools:u,watched:h,throttleMs:M=200,enableLogs:v=false}){let O=false;let y=false;let w=0;const o=()=>!O&&y&&r.connected&&_license.LicenseManager.hasAccountAccess();const c=new Map;const _={};const i={};const T=e=>e==="All"||e===p;const S=(e,t)=>{if(!o())return;try{r.emit(e,t)}catch(n){(0,_logger.log)(`${LOG} Failed to emit "${e}": ${n}. Payload must be JSON-serializable.`,v,"error")}};const B=new Set;const l=e=>{if(!o())return;const t=u()[e];if(!t)return;_[e]=(0,_realNow.realNow)();let n;try{n=t.getSnapshot()}catch{return}const{over:a,approxBytes:f}=(0,_emitBudget.approxSizeOver)(n,_emitBudget.MAX_SNAPSHOT_EMIT_BYTES);if(a){if(!B.has(e)){B.add(e);console.warn(`${LOG} "${e}" snapshot \u2248${(f/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 A={toolId:e,persistentDeviceId:p,timestamp:_[e],version:t.version,kind:"snapshot",payload:n};S("devtool-sync",A)};const N=e=>{if(i[e])return;const t=(0,_realNow.realNow)()-(_[e]??0);if(t>=M){l(e);return}i[e]=setTimeout(()=>{delete i[e];l(e)},M-t)};const E=e=>{if(!r.connected)return;if(!c.has(e))return;if(i[e]){clearTimeout(i[e]);delete i[e]}l(e)};(0,_crashFlush.registerToolFlusher)(E);const m=new Map;const q=(e,t)=>{if(!o())return;const n=u()[e];if(!n)return;if(c.has(e)){if(m.get(e)===t)return;const a=c.get(e);c.set(e,n.subscribe(t==="stream"?()=>N(e):()=>{}));m.set(e,t);a?.();(0,_logger.log)(`${LOG} "${e}" watch mode \u2192 ${t}`,v);return}c.set(e,n.subscribe(t==="stream"?()=>N(e):()=>{}));m.set(e,t);(0,_logger.log)(`${LOG} Watching "${e}" (${t})`,v)};const $=e=>{c.get(e)?.();c.delete(e);m.delete(e);if(i[e]){clearTimeout(i[e]);delete i[e]}(0,_logger.log)(`${LOG} Stopped watching "${e}"`,v)};const j=()=>{const e={persistentDeviceId:p,protocolVersion:_types.SYNC_PROTOCOL_VERSION,tools:Object.entries(u()).map(([t,n])=>({toolId:t,version:n.version,actions:Object.keys(n.actions??{})}))};S("devtool-capabilities",e)};const x=e=>{if(!o()||!T(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";h.set(e.toolId,t);q(e.toolId,t);if(t==="stream")l(e.toolId)}else{h.delete(e.toolId);$(e.toolId)}};const D=e=>{if(!o()||!T(e.targetDeviceId))return;l(e.toolId)};const F=async e=>{if(!o()||!T(e.targetDeviceId))return;const t=w;const{requestId:n,toolId:a,action:f,params:A}=e;const s={requestId:n,toolId:a,action:f,persistentDeviceId:p,timestamp:(0,_realNow.realNow)(),ok:false};const L=u()[a];const Y=L?.actions?.[f];if(!Y){s.error=L?`Unknown action "${f}" on tool "${a}"`:`Unknown tool "${a}"`;S("devtool-action-result",s);return}try{s.result=await Y(A);s.ok=true}catch(d){s.error=d instanceof Error?d.message:String(d)}if(t!==w||!o())return;if(s.ok){const{over:d,approxBytes:U}=(0,_emitBudget.approxSizeOver)(s.result,_emitBudget.MAX_ACTION_RESULT_BYTES);if(d){s.ok=false;s.result=void 0;s.error=`Result \u2248${(U/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)();S("devtool-action-result",s)};const b=()=>{w+=1;for(const t of[...c.keys()])$(t);h.clear();for(const t of Object.values(i))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 P=()=>{const e=_license.LicenseManager.getState();r.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});j()};const R=e=>{y=e?.protocol===1&&e.ready===true;if(!o())b();else P()};const z=_license.LicenseManager.subscribe(()=>{if(!_license.LicenseManager.hasAccountAccess()){if(r.connected)r.emit("device-license",{tier:"locked",isPro:"0"});b()}else if(o())P()});const g=()=>{y=false;r.emit("buoy:access:request")};const C=()=>{y=false;b()};r.on("buoy:access",R);for(const[e,t]of h){if(u()[e])q(e,t)}r.on("connect",g);r.on("disconnect",C);r.on("devtool-watch",x);r.on("request-devtool-state",D);r.on("devtool-action",F);if(r.connected)g();return()=>{O=true;z();r.off("buoy:access",R);b();(0,_crashFlush.unregisterToolFlusher)(E);r.off("connect",g);r.off("disconnect",C);r.off("devtool-watch",x);r.off("request-devtool-state",D);r.off("devtool-action",F);for(const e of[...c.keys()])$(e)}}
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:p,getTools:u,watched:h,throttleMs:M=200,enableLogs:v=false}){let O=false;let y=false;let w=0;const i=()=>!O&&y&&r.connected&&_license.LicenseManager.hasAccountAccess();const c=new Map;const _={};const o={};const T=e=>e==="All"||e===p;const S=(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.`,v,"error")}};const B=new Set;const l=e=>{if(!i())return;const t=u()[e];if(!t)return;_[e]=(0,_realNow.realNow)();let n;try{n=t.getSnapshot()}catch{return}const{over:a,approxBytes:f}=(0,_emitBudget.approxSizeOver)(n,_emitBudget.MAX_SNAPSHOT_EMIT_BYTES);if(a){if(!B.has(e)){B.add(e);console.warn("[Buoy]",`${LOG} "${e}" snapshot \u2248${(f/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 A={toolId:e,persistentDeviceId:p,timestamp:_[e],version:t.version,kind:"snapshot",payload:n};S("devtool-sync",A)};const N=e=>{if(o[e])return;const t=(0,_realNow.realNow)()-(_[e]??0);if(t>=M){l(e);return}o[e]=setTimeout(()=>{delete o[e];l(e)},M-t)};const E=e=>{if(!r.connected)return;if(!c.has(e))return;if(o[e]){clearTimeout(o[e]);delete o[e]}l(e)};(0,_crashFlush.registerToolFlusher)(E);const m=new Map;const q=(e,t)=>{if(!i())return;const n=u()[e];if(!n)return;if(c.has(e)){if(m.get(e)===t)return;const a=c.get(e);c.set(e,n.subscribe(t==="stream"?()=>N(e):()=>{}));m.set(e,t);a?.();(0,_logger.log)(`${LOG} "${e}" watch mode \u2192 ${t}`,v);return}c.set(e,n.subscribe(t==="stream"?()=>N(e):()=>{}));m.set(e,t);(0,_logger.log)(`${LOG} Watching "${e}" (${t})`,v)};const $=e=>{c.get(e)?.();c.delete(e);m.delete(e);if(o[e]){clearTimeout(o[e]);delete o[e]}(0,_logger.log)(`${LOG} Stopped watching "${e}"`,v)};const j=()=>{const e={persistentDeviceId:p,protocolVersion:_types.SYNC_PROTOCOL_VERSION,tools:Object.entries(u()).map(([t,n])=>({toolId:t,version:n.version,actions:Object.keys(n.actions??{})}))};S("devtool-capabilities",e)};const x=e=>{if(!i()||!T(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";h.set(e.toolId,t);q(e.toolId,t);if(t==="stream")l(e.toolId)}else{h.delete(e.toolId);$(e.toolId)}};const D=e=>{if(!i()||!T(e.targetDeviceId))return;l(e.toolId)};const F=async e=>{if(!i()||!T(e.targetDeviceId))return;const t=w;const{requestId:n,toolId:a,action:f,params:A}=e;const s={requestId:n,toolId:a,action:f,persistentDeviceId:p,timestamp:(0,_realNow.realNow)(),ok:false};const L=u()[a];const Y=L?.actions?.[f];if(!Y){s.error=L?`Unknown action "${f}" on tool "${a}"`:`Unknown tool "${a}"`;S("devtool-action-result",s);return}try{s.result=await Y(A);s.ok=true}catch(d){s.error=d instanceof Error?d.message:String(d)}if(t!==w||!i())return;if(s.ok){const{over:d,approxBytes:U}=(0,_emitBudget.approxSizeOver)(s.result,_emitBudget.MAX_ACTION_RESULT_BYTES);if(d){s.ok=false;s.result=void 0;s.error=`Result \u2248${(U/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)();S("devtool-action-result",s)};const b=()=>{w+=1;for(const t of[...c.keys()])$(t);h.clear();for(const t of Object.values(o))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 P=()=>{const e=_license.LicenseManager.getState();r.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});j()};const R=e=>{y=e?.protocol===1&&e.ready===true;if(!i())b();else P()};const z=_license.LicenseManager.subscribe(()=>{if(!_license.LicenseManager.hasAccountAccess()){if(r.connected)r.emit("device-license",{tier:"locked",isPro:"0"});b()}else if(i())P()});const g=()=>{y=false;r.emit("buoy:access:request")};const C=()=>{y=false;b()};r.on("buoy:access",R);for(const[e,t]of h){if(u()[e])q(e,t)}r.on("connect",g);r.on("disconnect",C);r.on("devtool-watch",x);r.on("request-devtool-state",D);r.on("devtool-action",F);if(r.connected)g();return()=>{O=true;z();r.off("buoy:access",R);b();(0,_crashFlush.unregisterToolFlusher)(E);r.off("connect",g);r.off("disconnect",C);r.off("devtool-watch",x);r.off("request-devtool-state",D);r.off("devtool-action",F);for(const e of[...c.keys()])$(e)}}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.buildHandshakeQuery=buildHandshakeQuery;exports.getInstanceId=getInstanceId;exports.useExternalSyncSocket=useExternalSyncSocket;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 c=globalThis;if(!c.__buoyInstanceId)c.__buoyInstanceId=makeConnectionNonce();return c.__buoyInstanceId}function buildHandshakeQuery(c){const l=s=>s&&Object.fromEntries(Object.entries(s).filter(([a])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(a)));return{deviceName:c.deviceName,deviceId:c.persistentDeviceId,platform:c.platform,extraDeviceInfo:JSON.stringify(l(c.extraDeviceInfo)),envVariables:JSON.stringify(l(c.envVariables)),connectionNonce:makeConnectionNonce(),instanceId:getInstanceId()}}function useExternalSyncSocket({deviceName:c,socketURL:l,persistentDeviceId:s,extraDeviceInfo:a,envVariables:$,platform:u,enableLogs:t=false}){const r=(0,_react.useRef)(null);const[i,U]=(0,_react.useState)(null);const[v,f]=(0,_react.useState)(false);const S=l??(0,_getDefaultSocketURL.getDefaultSocketURL)();const d=(0,_react.useRef)(false);const o=`[${c}]`;const _=()=>{(0,_logger.log)(`${o} Socket connected successfully`,t);d.current=false;f(true);(0,_syncStatusStore.setSyncStatus)({state:"connected",lastError:null})};const k=n=>{(0,_logger.log)(`${o} Socket disconnected. Reason: ${n}`,t);f(false);(0,_syncStatusStore.setSyncStatus)({state:"retrying"})};const g=n=>{(0,_syncStatusStore.setSyncStatus)({state:"retrying",lastError:n.message});if(!isDev)return;if(d.current)return;d.current=true;const e=u==="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. ${e}(${n.message})`,t,"warn")};const y=()=>{(0,_logger.log)(`${o} Socket connection timeout`,t,"error")};(0,_react.useEffect)(()=>{if(!s)return;const n=(0,_platformUtils.getPlatformSpecificURL)(S,u);(0,_syncStatusStore.setSyncStatus)({targetURL:n,state:"connecting",lastError:null});(0,_logger.log)(`${o} Platform: ${u}, using URL: ${n}`,t);try{if(globalSocketInstance&&(currentSocketURL!==n||currentDeviceId!==s||currentPlatform!==u)){globalSocketInstance.disconnect();globalSocketInstance=null}if(!globalSocketInstance){(0,_logger.log)(`${o} Creating new socket instance to ${n}`,t);globalSocketInstance=(0,_socket.io)(n,{autoConnect:true,query:buildHandshakeQuery({deviceName:c,persistentDeviceId:s,platform:u,extraDeviceInfo:a,envVariables:$}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});(0,_realNow.pinSocketTimers)(globalSocketInstance);currentSocketURL=n;currentDeviceId=s;currentPlatform=u}else{(0,_logger.log)(`${o} Reusing existing socket instance to ${n}`,t)}r.current=globalSocketInstance;const e=r.current;socketUsers++;if(releaseTimer){(0,_realNow.realClearTimeout)(releaseTimer);releaseTimer=null}U(e);e.on("connect_error",g);e.on("connect_timeout",y);f(e.connected);if(e.connected){(0,_logger.log)(`${o} Socket already connected on init`,t)}e.on("connect",_);e.on("disconnect",k);return()=>{(0,_logger.log)(`${o} Cleaning up socket event listeners`,t);e.off("connect",_);e.off("disconnect",k);e.off("connect_error",g);e.off("connect_timeout",y);socketUsers--;if(socketUsers===0){releaseTimer=(0,_realNow.realSetTimeout)(()=>{releaseTimer=null;if(socketUsers>0||globalSocketInstance!==e)return;(0,_logger.log)(`${o} No longer used; disconnecting`,t);e.disconnect();globalSocketInstance=null;(0,_syncStatusStore.setSyncStatus)({state:"idle",lastError:null})},RELEASE_GRACE_MS)}}}catch(e){(0,_logger.log)(`${o} Failed to initialize socket: ${e}`,t,"error")}},[s,S,u]);(0,_react.useEffect)(()=>{if(r.current&&r.current.io.opts.query&&s){(0,_logger.log)(`${o} Updating device name in socket connection`,t);r.current.io.opts.query={...r.current.io.opts.query,deviceName:c,deviceId:s,platform:u}}},[c,o,s,u,t]);function I(){if(r.current&&!r.current.connected){(0,_logger.log)(`${o} Manually connecting to socket server`,t);r.current.connect()}}function m(){if(r.current&&r.current.connected){(0,_logger.log)(`${o} Manually disconnecting from socket server`,t);r.current.disconnect()}}const[E,R]=(0,_react.useState)(null);(0,_react.useEffect)(()=>{if(!i)return;return(0,_brokerAccess.watchBrokerAccess)(i,n=>{R(n?i:null);(0,_syncStatusStore.setSyncStatus)(n?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[i]);return{socket:E===i?i:null,connect:I,disconnect:m,isConnected:v&&E===i&&i!==null}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.buildHandshakeQuery=buildHandshakeQuery;exports.getInstanceId=getInstanceId;exports.useExternalSyncSocket=useExternalSyncSocket;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 c=globalThis;if(!c.__buoyInstanceId)c.__buoyInstanceId=makeConnectionNonce();return c.__buoyInstanceId}function buildHandshakeQuery(c){const l=s=>s&&Object.fromEntries(Object.entries(s).filter(([a])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(a)));return{deviceName:c.deviceName,deviceId:c.persistentDeviceId,platform:c.platform,extraDeviceInfo:JSON.stringify(l(c.extraDeviceInfo)),envVariables:JSON.stringify(l(c.envVariables)),connectionNonce:makeConnectionNonce(),instanceId:getInstanceId()}}function useExternalSyncSocket({deviceName:c,socketURL:l,persistentDeviceId:s,extraDeviceInfo:a,envVariables:U,platform:i,enableLogs:n=false}){const r=(0,_react.useRef)(null);const[u,$]=(0,_react.useState)(null);const[I,f]=(0,_react.useState)(false);const S=l??(0,_getDefaultSocketURL.getDefaultSocketURL)();const d=(0,_react.useRef)(false);const o=`[${c}]`;const _=()=>{(0,_logger.log)(`${o} Socket connected successfully`,n);d.current=false;f(true);(0,_syncStatusStore.setSyncStatus)({state:"connected",lastError:null})};const g=t=>{(0,_logger.log)(`${o} Socket disconnected. Reason: ${t}`,n);f(false);(0,_syncStatusStore.setSyncStatus)({state:"retrying"})};const k=t=>{(0,_syncStatusStore.setSyncStatus)({state:"retrying",lastError:t.message});if(!isDev)return;if(d.current)return;d.current=true;const e=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. ${e}(${t.message})`,n,"warn")};const y=()=>{(0,_logger.log)(`${o} Socket connection timeout`,n,"error")};(0,_react.useEffect)(()=>{if(!s)return;const t=(0,_platformUtils.getPlatformSpecificURL)(S,i);(0,_syncStatusStore.setSyncStatus)({targetURL:t,state:"connecting",lastError:null});(0,_logger.log)(`${o} Platform: ${i}, using URL: ${t}`,n);try{if(globalSocketInstance&&(currentSocketURL!==t||currentDeviceId!==s||currentPlatform!==i)){globalSocketInstance.disconnect();globalSocketInstance=null}if(!globalSocketInstance){(0,_logger.log)(`${o} Creating new socket instance to ${t}`,n);try{const m=globalThis;(m.__BUOY_INTERNAL_HOSTS__??=new Set).add(new URL(t).host.toLowerCase())}catch{}globalSocketInstance=(0,_socket.io)(t,{autoConnect:true,query:buildHandshakeQuery({deviceName:c,persistentDeviceId:s,platform:i,extraDeviceInfo:a,envVariables:U}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});(0,_realNow.pinSocketTimers)(globalSocketInstance);currentSocketURL=t;currentDeviceId=s;currentPlatform=i}else{(0,_logger.log)(`${o} Reusing existing socket instance to ${t}`,n)}r.current=globalSocketInstance;const e=r.current;socketUsers++;if(releaseTimer){(0,_realNow.realClearTimeout)(releaseTimer);releaseTimer=null}$(e);e.on("connect_error",k);e.on("connect_timeout",y);f(e.connected);if(e.connected){(0,_logger.log)(`${o} Socket already connected on init`,n)}e.on("connect",_);e.on("disconnect",g);return()=>{(0,_logger.log)(`${o} Cleaning up socket event listeners`,n);e.off("connect",_);e.off("disconnect",g);e.off("connect_error",k);e.off("connect_timeout",y);socketUsers--;if(socketUsers===0){releaseTimer=(0,_realNow.realSetTimeout)(()=>{releaseTimer=null;if(socketUsers>0||globalSocketInstance!==e)return;(0,_logger.log)(`${o} No longer used; disconnecting`,n);e.disconnect();globalSocketInstance=null;(0,_syncStatusStore.setSyncStatus)({state:"idle",lastError:null})},RELEASE_GRACE_MS)}}}catch(e){(0,_logger.log)(`${o} Failed to initialize socket: ${e}`,n,"error")}},[s,S,i]);(0,_react.useEffect)(()=>{if(r.current&&r.current.io.opts.query&&s){(0,_logger.log)(`${o} Updating device name in socket connection`,n);r.current.io.opts.query={...r.current.io.opts.query,deviceName:c,deviceId:s,platform:i}}},[c,o,s,i,n]);function R(){if(r.current&&!r.current.connected){(0,_logger.log)(`${o} Manually connecting to socket server`,n);r.current.connect()}}function h(){if(r.current&&r.current.connected){(0,_logger.log)(`${o} Manually disconnecting from socket server`,n);r.current.disconnect()}}const[E,v]=(0,_react.useState)(null);(0,_react.useEffect)(()=>{if(!u)return;return(0,_brokerAccess.watchBrokerAccess)(u,t=>{v(t?u:null);(0,_syncStatusStore.setSyncStatus)(t?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[u]);return{socket:E===u?u:null,connect:R,disconnect:h,isConnected:I&&E===u&&u!==null}}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.log=log;function log(o,e,r="log"){if(!e&&r==="log")return;switch(r){case"warn":console.warn(o);break;case"error":console.error(o);break;default:console.log(o)}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.log=log;function log(o,e,r="log"){if(!e&&r==="log")return;switch(r){case"warn":console.warn("[Buoy]",o);break;case"error":console.error("[Buoy]",o);break;default:console.log("[Buoy]",o)}}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getPlatformSpecificURL=void 0;const isAndroidEmulator=()=>{try{const{Platform:t}=require("react-native");if(t.OS!=="android")return false;const e=t.constants?.Fingerprint??"";return/generic|emulator|goldfish|ranchu|sdk_gphone|vbox/i.test(e)}catch{return false}};const getPlatformSpecificURL=(t,e)=>{try{const r=new URL(t);if(e==="android"&&(r.hostname==="localhost"||r.hostname==="127.0.0.1")&&isAndroidEmulator()){r.hostname="10.0.2.2";return r.toString()}return t}catch(r){console.warn("Error getting platform-specific URL:",r);return t}};exports.getPlatformSpecificURL=getPlatformSpecificURL;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getPlatformSpecificURL=void 0;const isAndroidEmulator=()=>{try{const{Platform:t}=require("react-native");if(t.OS!=="android")return false;const e=t.constants?.Fingerprint??"";return/generic|emulator|goldfish|ranchu|sdk_gphone|vbox/i.test(e)}catch{return false}};const getPlatformSpecificURL=(t,e)=>{try{const r=new URL(t);if(e==="android"&&(r.hostname==="localhost"||r.hostname==="127.0.0.1")&&isAndroidEmulator()){r.hostname="10.0.2.2";return r.toString()}return t}catch(r){console.warn("[Buoy]","Error getting platform-specific URL:",r);return t}};exports.getPlatformSpecificURL=getPlatformSpecificURL;
@@ -1 +1 @@
1
- "use strict";import{LicenseManager as w}from"@buoy-gg/license";import{log as A}from"./utils/logger";import{registerToolFlusher as Q,unregisterToolFlusher as Z}from"./crashFlush";import{MAX_ACTION_RESULT_BYTES as G,MAX_SNAPSHOT_EMIT_BYTES as X,approxSizeOver as H}from"./emitBudget";import{SYNC_PROTOCOL_VERSION as k}from"./types";import{realNow as T}from"./realNow";const p="[ExternalSync]";export function attachDeviceSync({socket:n,deviceId:h,getTools:f,watched:m,throttleMs:N=200,enableLogs:v=false}){let _=false;let y=false;let O=0;const i=()=>!_&&y&&n.connected&&w.hasAccountAccess();const c=new Map;const B={};const o={};const M=e=>e==="All"||e===h;const b=(e,t)=>{if(!i())return;try{n.emit(e,t)}catch(r){A(`${p} Failed to emit "${e}": ${r}. Payload must be JSON-serializable.`,v,"error")}};const q=new Set;const u=e=>{if(!i())return;const t=f()[e];if(!t)return;B[e]=T();let r;try{r=t.getSnapshot()}catch{return}const{over:a,approxBytes:l}=H(r,X);if(a){if(!q.has(e)){q.add(e);console.warn(`${p} "${e}" snapshot \u2248${(l/1e6).toFixed(1)}MB exceeds the ${X/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 D={toolId:e,persistentDeviceId:h,timestamp:B[e],version:t.version,kind:"snapshot",payload:r};b("devtool-sync",D)};const F=e=>{if(o[e])return;const t=T()-(B[e]??0);if(t>=N){u(e);return}o[e]=setTimeout(()=>{delete o[e];u(e)},N-t)};const P=e=>{if(!n.connected)return;if(!c.has(e))return;if(o[e]){clearTimeout(o[e]);delete o[e]}u(e)};Q(P);const $=new Map;const R=(e,t)=>{if(!i())return;const r=f()[e];if(!r)return;if(c.has(e)){if($.get(e)===t)return;const a=c.get(e);c.set(e,r.subscribe(t==="stream"?()=>F(e):()=>{}));$.set(e,t);a?.();A(`${p} "${e}" watch mode \u2192 ${t}`,v);return}c.set(e,r.subscribe(t==="stream"?()=>F(e):()=>{}));$.set(e,t);A(`${p} Watching "${e}" (${t})`,v)};const x=e=>{c.get(e)?.();c.delete(e);$.delete(e);if(o[e]){clearTimeout(o[e]);delete o[e]}A(`${p} Stopped watching "${e}"`,v)};const J=()=>{const e={persistentDeviceId:h,protocolVersion:k,tools:Object.entries(f()).map(([t,r])=>({toolId:t,version:r.version,actions:Object.keys(r.actions??{})}))};b("devtool-capabilities",e)};const C=e=>{if(!i()||!M(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";m.set(e.toolId,t);R(e.toolId,t);if(t==="stream")u(e.toolId)}else{m.delete(e.toolId);x(e.toolId)}};const g=e=>{if(!i()||!M(e.targetDeviceId))return;u(e.toolId)};const j=async e=>{if(!i()||!M(e.targetDeviceId))return;const t=O;const{requestId:r,toolId:a,action:l,params:D}=e;const s={requestId:r,toolId:a,action:l,persistentDeviceId:h,timestamp:T(),ok:false};const W=f()[a];const Y=W?.actions?.[l];if(!Y){s.error=W?`Unknown action "${l}" on tool "${a}"`:`Unknown tool "${a}"`;b("devtool-action-result",s);return}try{s.result=await Y(D);s.ok=true}catch(d){s.error=d instanceof Error?d.message:String(d)}if(t!==O||!i())return;if(s.ok){const{over:d,approxBytes:K}=H(s.result,G);if(d){s.ok=false;s.result=void 0;s.error=`Result \u2248${(K/1e6).toFixed(1)}MB exceeds the ${G/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`}}s.timestamp=T();b("devtool-action-result",s)};const S=()=>{O+=1;for(const t of[...c.keys()])x(t);m.clear();for(const t of Object.values(o))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 z=()=>{const e=w.getState();n.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});J()};const U=e=>{y=e?.protocol===1&&e.ready===true;if(!i())S();else z()};const L=w.subscribe(()=>{if(!w.hasAccountAccess()){if(n.connected)n.emit("device-license",{tier:"locked",isPro:"0"});S()}else if(i())z()});const E=()=>{y=false;n.emit("buoy:access:request")};const V=()=>{y=false;S()};n.on("buoy:access",U);for(const[e,t]of m){if(f()[e])R(e,t)}n.on("connect",E);n.on("disconnect",V);n.on("devtool-watch",C);n.on("request-devtool-state",g);n.on("devtool-action",j);if(n.connected)E();return()=>{_=true;L();n.off("buoy:access",U);S();Z(P);n.off("connect",E);n.off("disconnect",V);n.off("devtool-watch",C);n.off("request-devtool-state",g);n.off("devtool-action",j);for(const e of[...c.keys()])x(e)}}
1
+ "use strict";import{LicenseManager as w}from"@buoy-gg/license";import{log as A}from"./utils/logger";import{registerToolFlusher as Q,unregisterToolFlusher as Z}from"./crashFlush";import{MAX_ACTION_RESULT_BYTES as G,MAX_SNAPSHOT_EMIT_BYTES as X,approxSizeOver as H}from"./emitBudget";import{SYNC_PROTOCOL_VERSION as k}from"./types";import{realNow as T}from"./realNow";const p="[ExternalSync]";export function attachDeviceSync({socket:n,deviceId:h,getTools:f,watched:m,throttleMs:N=200,enableLogs:v=false}){let _=false;let y=false;let O=0;const i=()=>!_&&y&&n.connected&&w.hasAccountAccess();const c=new Map;const B={};const o={};const M=e=>e==="All"||e===h;const b=(e,t)=>{if(!i())return;try{n.emit(e,t)}catch(r){A(`${p} Failed to emit "${e}": ${r}. Payload must be JSON-serializable.`,v,"error")}};const q=new Set;const u=e=>{if(!i())return;const t=f()[e];if(!t)return;B[e]=T();let r;try{r=t.getSnapshot()}catch{return}const{over:a,approxBytes:l}=H(r,X);if(a){if(!q.has(e)){q.add(e);console.warn("[Buoy]",`${p} "${e}" snapshot \u2248${(l/1e6).toFixed(1)}MB exceeds the ${X/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 D={toolId:e,persistentDeviceId:h,timestamp:B[e],version:t.version,kind:"snapshot",payload:r};b("devtool-sync",D)};const F=e=>{if(o[e])return;const t=T()-(B[e]??0);if(t>=N){u(e);return}o[e]=setTimeout(()=>{delete o[e];u(e)},N-t)};const P=e=>{if(!n.connected)return;if(!c.has(e))return;if(o[e]){clearTimeout(o[e]);delete o[e]}u(e)};Q(P);const $=new Map;const R=(e,t)=>{if(!i())return;const r=f()[e];if(!r)return;if(c.has(e)){if($.get(e)===t)return;const a=c.get(e);c.set(e,r.subscribe(t==="stream"?()=>F(e):()=>{}));$.set(e,t);a?.();A(`${p} "${e}" watch mode \u2192 ${t}`,v);return}c.set(e,r.subscribe(t==="stream"?()=>F(e):()=>{}));$.set(e,t);A(`${p} Watching "${e}" (${t})`,v)};const x=e=>{c.get(e)?.();c.delete(e);$.delete(e);if(o[e]){clearTimeout(o[e]);delete o[e]}A(`${p} Stopped watching "${e}"`,v)};const J=()=>{const e={persistentDeviceId:h,protocolVersion:k,tools:Object.entries(f()).map(([t,r])=>({toolId:t,version:r.version,actions:Object.keys(r.actions??{})}))};b("devtool-capabilities",e)};const C=e=>{if(!i()||!M(e.targetDeviceId))return;if(e.watching){const t=e.consolidated===true&&e.stream===false?"capture":"stream";m.set(e.toolId,t);R(e.toolId,t);if(t==="stream")u(e.toolId)}else{m.delete(e.toolId);x(e.toolId)}};const g=e=>{if(!i()||!M(e.targetDeviceId))return;u(e.toolId)};const j=async e=>{if(!i()||!M(e.targetDeviceId))return;const t=O;const{requestId:r,toolId:a,action:l,params:D}=e;const s={requestId:r,toolId:a,action:l,persistentDeviceId:h,timestamp:T(),ok:false};const W=f()[a];const Y=W?.actions?.[l];if(!Y){s.error=W?`Unknown action "${l}" on tool "${a}"`:`Unknown tool "${a}"`;b("devtool-action-result",s);return}try{s.result=await Y(D);s.ok=true}catch(d){s.error=d instanceof Error?d.message:String(d)}if(t!==O||!i())return;if(s.ok){const{over:d,approxBytes:K}=H(s.result,G);if(d){s.ok=false;s.result=void 0;s.error=`Result \u2248${(K/1e6).toFixed(1)}MB exceeds the ${G/1e6}MB sync budget. Narrow the request (e.g. includeValues:false, a limit, or a more specific action).`}}s.timestamp=T();b("devtool-action-result",s)};const S=()=>{O+=1;for(const t of[...c.keys()])x(t);m.clear();for(const t of Object.values(o))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 z=()=>{const e=w.getState();n.emit("device-license",{tier:e.tier,isPro:e.isPro?"1":"0"});J()};const U=e=>{y=e?.protocol===1&&e.ready===true;if(!i())S();else z()};const L=w.subscribe(()=>{if(!w.hasAccountAccess()){if(n.connected)n.emit("device-license",{tier:"locked",isPro:"0"});S()}else if(i())z()});const E=()=>{y=false;n.emit("buoy:access:request")};const V=()=>{y=false;S()};n.on("buoy:access",U);for(const[e,t]of m){if(f()[e])R(e,t)}n.on("connect",E);n.on("disconnect",V);n.on("devtool-watch",C);n.on("request-devtool-state",g);n.on("devtool-action",j);if(n.connected)E();return()=>{_=true;L();n.off("buoy:access",U);S();Z(P);n.off("connect",E);n.off("disconnect",V);n.off("devtool-watch",C);n.off("request-devtool-state",g);n.off("devtool-action",j);for(const e of[...c.keys()])x(e)}}
@@ -1 +1 @@
1
- "use strict";import{watchBrokerAccess as w}from"./brokerAccess";import{useEffect as $,useRef as B,useState as g}from"react";import{io as N}from"socket.io-client";import{getPlatformSpecificURL as M}from"./utils/platformUtils";import{getDefaultSocketURL as V}from"./utils/getDefaultSocketURL";import{log as r}from"./utils/logger";import{setSyncStatus as f}from"./syncStatusStore";import{pinSocketTimers as q,realClearTimeout as j,realSetTimeout as J}from"./realNow";const X=typeof __DEV__!=="undefined"?__DEV__:false;let l=null;let _="";let O="";let Y="";let m=0;let d=null;const b=2e3;const v=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;export function getInstanceId(){const o=globalThis;if(!o.__buoyInstanceId)o.__buoyInstanceId=v();return o.__buoyInstanceId}export function buildHandshakeQuery(o){const k=i=>i&&Object.fromEntries(Object.entries(i).filter(([E])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(E)));return{deviceName:o.deviceName,deviceId:o.persistentDeviceId,platform:o.platform,extraDeviceInfo:JSON.stringify(k(o.extraDeviceInfo)),envVariables:JSON.stringify(k(o.envVariables)),connectionNonce:v(),instanceId:getInstanceId()}}export function useExternalSyncSocket({deviceName:o,socketURL:k,persistentDeviceId:i,extraDeviceInfo:E,envVariables:x,platform:u,enableLogs:n=false}){const s=B(null);const[a,P]=g(null);const[T,S]=g(false);const p=k??V();const y=B(false);const c=`[${o}]`;const U=()=>{r(`${c} Socket connected successfully`,n);y.current=false;S(true);f({state:"connected",lastError:null})};const I=e=>{r(`${c} Socket disconnected. Reason: ${e}`,n);S(false);f({state:"retrying"})};const C=e=>{f({state:"retrying",lastError:e.message});if(!X)return;if(y.current)return;y.current=true;const t=u==="android"&&/localhost|127\.0\.0\.1/.test(_)?`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. `;r(`[buoy] desktop sync: can't reach ${_} (is Buoy Desktop running?). Retrying in the background. ${t}(${e.message})`,n,"warn")};const h=()=>{r(`${c} Socket connection timeout`,n,"error")};$(()=>{if(!i)return;const e=M(p,u);f({targetURL:e,state:"connecting",lastError:null});r(`${c} Platform: ${u}, using URL: ${e}`,n);try{if(l&&(_!==e||O!==i||Y!==u)){l.disconnect();l=null}if(!l){r(`${c} Creating new socket instance to ${e}`,n);l=N(e,{autoConnect:true,query:buildHandshakeQuery({deviceName:o,persistentDeviceId:i,platform:u,extraDeviceInfo:E,envVariables:x}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});q(l);_=e;O=i;Y=u}else{r(`${c} Reusing existing socket instance to ${e}`,n)}s.current=l;const t=s.current;m++;if(d){j(d);d=null}P(t);t.on("connect_error",C);t.on("connect_timeout",h);S(t.connected);if(t.connected){r(`${c} Socket already connected on init`,n)}t.on("connect",U);t.on("disconnect",I);return()=>{r(`${c} Cleaning up socket event listeners`,n);t.off("connect",U);t.off("disconnect",I);t.off("connect_error",C);t.off("connect_timeout",h);m--;if(m===0){d=J(()=>{d=null;if(m>0||l!==t)return;r(`${c} No longer used; disconnecting`,n);t.disconnect();l=null;f({state:"idle",lastError:null})},b)}}}catch(t){r(`${c} Failed to initialize socket: ${t}`,n,"error")}},[i,p,u]);$(()=>{if(s.current&&s.current.io.opts.query&&i){r(`${c} Updating device name in socket connection`,n);s.current.io.opts.query={...s.current.io.opts.query,deviceName:o,deviceId:i,platform:u}}},[o,c,i,u,n]);function A(){if(s.current&&!s.current.connected){r(`${c} Manually connecting to socket server`,n);s.current.connect()}}function K(){if(s.current&&s.current.connected){r(`${c} Manually disconnecting from socket server`,n);s.current.disconnect()}}const[R,D]=g(null);$(()=>{if(!a)return;return w(a,e=>{D(e?a:null);f(e?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[a]);return{socket:R===a?a:null,connect:A,disconnect:K,isConnected:T&&R===a&&a!==null}}
1
+ "use strict";import{watchBrokerAccess as D}from"./brokerAccess";import{useEffect as $,useRef as O,useState as g}from"react";import{io as M}from"socket.io-client";import{getPlatformSpecificURL as V}from"./utils/platformUtils";import{getDefaultSocketURL as q}from"./utils/getDefaultSocketURL";import{log as r}from"./utils/logger";import{setSyncStatus as f}from"./syncStatusStore";import{pinSocketTimers as b,realClearTimeout as j,realSetTimeout as H}from"./realNow";const J=typeof __DEV__!=="undefined"?__DEV__:false;let l=null;let k="";let B="";let Y="";let m=0;let d=null;const X=2e3;const T=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;export function getInstanceId(){const o=globalThis;if(!o.__buoyInstanceId)o.__buoyInstanceId=T();return o.__buoyInstanceId}export function buildHandshakeQuery(o){const _=i=>i&&Object.fromEntries(Object.entries(i).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:o.deviceName,deviceId:o.persistentDeviceId,platform:o.platform,extraDeviceInfo:JSON.stringify(_(o.extraDeviceInfo)),envVariables:JSON.stringify(_(o.envVariables)),connectionNonce:T(),instanceId:getInstanceId()}}export function useExternalSyncSocket({deviceName:o,socketURL:_,persistentDeviceId:i,extraDeviceInfo:S,envVariables:v,platform:u,enableLogs:e=false}){const s=O(null);const[a,x]=g(null);const[w,E]=g(false);const U=_??q();const y=O(false);const c=`[${o}]`;const p=()=>{r(`${c} Socket connected successfully`,e);y.current=false;E(true);f({state:"connected",lastError:null})};const I=n=>{r(`${c} Socket disconnected. Reason: ${n}`,e);E(false);f({state:"retrying"})};const h=n=>{f({state:"retrying",lastError:n.message});if(!J)return;if(y.current)return;y.current=true;const t=u==="android"&&/localhost|127\.0\.0\.1/.test(k)?`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. `;r(`[buoy] desktop sync: can't reach ${k} (is Buoy Desktop running?). Retrying in the background. ${t}(${n.message})`,e,"warn")};const C=()=>{r(`${c} Socket connection timeout`,e,"error")};$(()=>{if(!i)return;const n=V(U,u);f({targetURL:n,state:"connecting",lastError:null});r(`${c} Platform: ${u}, using URL: ${n}`,e);try{if(l&&(k!==n||B!==i||Y!==u)){l.disconnect();l=null}if(!l){r(`${c} Creating new socket instance to ${n}`,e);try{const N=globalThis;(N.__BUOY_INTERNAL_HOSTS__??=new Set).add(new URL(n).host.toLowerCase())}catch{}l=M(n,{autoConnect:true,query:buildHandshakeQuery({deviceName:o,persistentDeviceId:i,platform:u,extraDeviceInfo:S,envVariables:v}),reconnection:true,reconnectionAttempts:Infinity,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]});b(l);k=n;B=i;Y=u}else{r(`${c} Reusing existing socket instance to ${n}`,e)}s.current=l;const t=s.current;m++;if(d){j(d);d=null}x(t);t.on("connect_error",h);t.on("connect_timeout",C);E(t.connected);if(t.connected){r(`${c} Socket already connected on init`,e)}t.on("connect",p);t.on("disconnect",I);return()=>{r(`${c} Cleaning up socket event listeners`,e);t.off("connect",p);t.off("disconnect",I);t.off("connect_error",h);t.off("connect_timeout",C);m--;if(m===0){d=H(()=>{d=null;if(m>0||l!==t)return;r(`${c} No longer used; disconnecting`,e);t.disconnect();l=null;f({state:"idle",lastError:null})},X)}}}catch(t){r(`${c} Failed to initialize socket: ${t}`,e,"error")}},[i,U,u]);$(()=>{if(s.current&&s.current.io.opts.query&&i){r(`${c} Updating device name in socket connection`,e);s.current.io.opts.query={...s.current.io.opts.query,deviceName:o,deviceId:i,platform:u}}},[o,c,i,u,e]);function A(){if(s.current&&!s.current.connected){r(`${c} Manually connecting to socket server`,e);s.current.connect()}}function P(){if(s.current&&s.current.connected){r(`${c} Manually disconnecting from socket server`,e);s.current.disconnect()}}const[R,K]=g(null);$(()=>{if(!a)return;return D(a,n=>{K(n?a:null);f(n?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[a]);return{socket:R===a?a:null,connect:A,disconnect:P,isConnected:w&&R===a&&a!==null}}
@@ -1 +1 @@
1
- "use strict";export function log(o,c,r="log"){if(!c&&r==="log")return;switch(r){case"warn":console.warn(o);break;case"error":console.error(o);break;default:console.log(o)}}
1
+ "use strict";export function log(o,c,r="log"){if(!c&&r==="log")return;switch(r){case"warn":console.warn("[Buoy]",o);break;case"error":console.error("[Buoy]",o);break;default:console.log("[Buoy]",o)}}
@@ -1 +1 @@
1
- "use strict";const e=()=>{try{const{Platform:t}=require("react-native");if(t.OS!=="android")return false;const n=t.constants?.Fingerprint??"";return/generic|emulator|goldfish|ranchu|sdk_gphone|vbox/i.test(n)}catch{return false}};export const getPlatformSpecificURL=(t,n)=>{try{const r=new URL(t);if(n==="android"&&(r.hostname==="localhost"||r.hostname==="127.0.0.1")&&e()){r.hostname="10.0.2.2";return r.toString()}return t}catch(r){console.warn("Error getting platform-specific URL:",r);return t}};
1
+ "use strict";const e=()=>{try{const{Platform:t}=require("react-native");if(t.OS!=="android")return false;const n=t.constants?.Fingerprint??"";return/generic|emulator|goldfish|ranchu|sdk_gphone|vbox/i.test(n)}catch{return false}};export const getPlatformSpecificURL=(t,n)=>{try{const r=new URL(t);if(n==="android"&&(r.hostname==="localhost"||r.hostname==="127.0.0.1")&&e()){r.hostname="10.0.2.2";return r.toString()}return t}catch(r){console.warn("[Buoy]","Error getting platform-specific URL:",r);return t}};
package/lib/web/index.mjs CHANGED
@@ -1 +1 @@
1
- "use client";var oe=(()=>{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 he}from"@buoy-gg/license/web";import{useEffect as ve,useRef as ne}from"react";import{LicenseManager as A}from"@buoy-gg/license/web";function p(e,n,o="log"){if(!(!n&&o==="log"))switch(o){case"warn":console.warn(e);break;case"error":console.error(e);break;default:console.log(e)}}var j="__buoyFlushToolSync";function K(){let e=globalThis;return e[j]||(e[j]=new Set),e[j]}function re(e){K().add(e)}function ce(e){K().delete(e)}function be(e){try{for(let n of K())try{n(e)}catch{}}catch{}}function se(e,n){let o=0,i=[e],l=new Set;for(;i.length>0;){if(o>n)return{over:true,approxBytes:o};let r=i.pop();if(r==null)o+=4;else if(typeof r=="string")o+=r.length+2;else if(typeof r=="number")o+=8;else if(typeof r=="boolean")o+=5;else if(typeof r=="object"){if(l.has(r))continue;if(l.add(r),Array.isArray(r)){o+=2+r.length;for(let c=0;c<r.length;c++)i.push(r[c])}else{o+=2;for(let c in r)o+=c.length+4,i.push(r[c])}}else o+=4}return{over:o>n,approxBytes:o}}var _e=1;function x(){let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()}function ie(){return globalThis.__buoyRealTimers??globalThis}function ae(e,n){return ie().setTimeout(e,n)}function le(e){ie().clearTimeout(e)}function $e(e){let n=globalThis.__buoyWithRealClock;return typeof n=="function"?n(e):e()}var Ie=["_resetPingTimeout","_hasPingExpired"];function ke(e){let n=e?.io;if(!n||n.__buoyRealTimers)return;let o=l=>{if(l){l.setTimeoutFn=ae,l.clearTimeoutFn=le;for(let r of Ie){let c=l[r];if(typeof c!="function"||c.__buoyReal)continue;let a=function(...y){return $e(()=>c.apply(this,y))};a.__buoyReal=true,l[r]=a}}};o(n),o(n.engine);let i=n.open;typeof i=="function"&&(n.open=function(...l){let r=i.apply(this,l);return o(this?.engine),r}),n.__buoyRealTimers=true}var N="[ExternalSync]";function Se({socket:e,deviceId:n,getTools:o,watched:i,throttleMs:l=200,enableLogs:r=false}){let c=false,a=false,y=0,m=()=>!c&&a&&e.connected&&A.hasAccountAccess(),b=new Map,k={},h={},S=t=>t==="All"||t===n,f=(t,s)=>{if(m())try{e.emit(t,s)}catch(g){p(`${N} Failed to emit "${t}": ${g}. Payload must be JSON-serializable.`,r,"error")}},B=new Set,$=t=>{if(!m())return;let s=o()[t];if(!s)return;k[t]=x();let g;try{g=s.getSnapshot()}catch{return}let{over:I,approxBytes:O}=se(g,2097152);if(I){B.has(t)||(B.add(t),console.warn(`${N} "${t}" snapshot \u2248${(O/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 V={toolId:t,persistentDeviceId:n,timestamp:k[t],version:s.version,kind:"snapshot",payload:g};f("devtool-sync",V)},R=t=>{if(h[t])return;let s=x()-(k[t]??0);if(s>=l){$(t);return}h[t]=setTimeout(()=>{delete h[t],$(t)},l-s)},D=t=>{e.connected&&b.has(t)&&(h[t]&&(clearTimeout(h[t]),delete h[t]),$(t))};re(D);let w=new Map,L=(t,s)=>{if(!m())return;let g=o()[t];if(g){if(b.has(t)){if(w.get(t)===s)return;let I=b.get(t);b.set(t,g.subscribe(s==="stream"?()=>R(t):()=>{})),w.set(t,s),I?.(),p(`${N} "${t}" watch mode \u2192 ${s}`,r);return}b.set(t,g.subscribe(s==="stream"?()=>R(t):()=>{})),w.set(t,s),p(`${N} Watching "${t}" (${s})`,r)}},E=t=>{b.get(t)?.(),b.delete(t),w.delete(t),h[t]&&(clearTimeout(h[t]),delete h[t]),p(`${N} Stopped watching "${t}"`,r)},q=()=>{let t={persistentDeviceId:n,protocolVersion:1,tools:Object.entries(o()).map(([s,g])=>({toolId:s,version:g.version,actions:Object.keys(g.actions??{})}))};f("devtool-capabilities",t)},d=t=>{if(!(!m()||!S(t.targetDeviceId)))if(t.watching){let s=t.consolidated===true&&t.stream===false?"capture":"stream";i.set(t.toolId,s),L(t.toolId,s),s==="stream"&&$(t.toolId)}else i.delete(t.toolId),E(t.toolId)},u=t=>{!m()||!S(t.targetDeviceId)||$(t.toolId)},G=async t=>{if(!m()||!S(t.targetDeviceId))return;let s=y,{requestId:g,toolId:I,action:O,params:V}=t,v={requestId:g,toolId:I,action:O,persistentDeviceId:n,timestamp:x(),ok:false},ee=o()[I],te=ee?.actions?.[O];if(!te){v.error=ee?`Unknown action "${O}" on tool "${I}"`:`Unknown tool "${I}"`,f("devtool-action-result",v);return}try{v.result=await te(V),v.ok=true}catch(U){v.error=U instanceof Error?U.message:String(U)}if(!(s!==y||!m())){if(v.ok){let{over:U,approxBytes:me}=se(v.result,8388608);U&&(v.ok=false,v.result=void 0,v.error=`Result \u2248${(me/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).`)}v.timestamp=x(),f("devtool-action-result",v)}},P=()=>{y+=1;for(let s of[...b.keys()])E(s);i.clear();for(let s of Object.values(h))clearTimeout(s);let t=e;t.sendBuffer&&(t.sendBuffer=t.sendBuffer.filter(s=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(s.data?.[0]))))},H=()=>{let t=A.getState();e.emit("device-license",{tier:t.tier,isPro:t.isPro?"1":"0"}),q()},Q=t=>{a=t?.protocol===1&&t.ready===true,m()?H():P()},ge=A.subscribe(()=>{A.hasAccountAccess()?m()&&H():(e.connected&&e.emit("device-license",{tier:"locked",isPro:"0"}),P())}),F=()=>{a=false,e.emit("buoy:access:request")},Z=()=>{a=false,P()};e.on("buoy:access",Q);for(let[t,s]of i)o()[t]&&L(t,s);return e.on("connect",F),e.on("disconnect",Z),e.on("devtool-watch",d),e.on("request-devtool-state",u),e.on("devtool-action",G),e.connected&&F(),()=>{c=true,ge(),e.off("buoy:access",Q),P(),ce(D),e.off("connect",F),e.off("disconnect",Z),e.off("devtool-watch",d),e.off("request-devtool-state",u),e.off("devtool-action",G);for(let t of[...b.keys()])E(t)}}function Te({tools:e,socket:n,deviceId:o,enabled:i=true,throttleMs:l=200,enableLogs:r=false}){let c=he().status==="admitted",a=ne(e);a.current=e;let y=ne(new Map),m=Object.keys(e).sort().join(",");ve(()=>{if(!n||!o||!i||!c){y.current.clear();return}return Se({socket:n,deviceId:o,getTools:()=>a.current,watched:y.current,throttleMs:l,enableLogs:r})},[n,o,i,c,l,r,m])}function we(e,n){let o=()=>n(false),i=()=>{o(),e.emit("buoy:access:request")},l=r=>{let c=r;n(c?.protocol===1&&c?.ready===true)};return e.on("connect",i),e.on("disconnect",o),e.on("buoy:access",l),o(),e.connected&&i(),()=>{e.off("connect",i),e.off("disconnect",o),e.off("buoy:access",l)}}import{useEffect as J,useRef as ue,useState as W}from"react";import{io as Ee}from"socket.io-client";function Be(e,n){return e}var Re=42831;function De(e){return`http://${e??"localhost"}:42831`}function Oe(){return null}function fe(){return De(typeof location>"u"?null:location.hostname)}var z={targetURL:null,state:"idle",lastError:null,since:0},X=new Set;function T(e){z={...z,...e,since:x()},X.forEach(n=>n())}function Ue(){return z}function xe(e){return X.add(e),()=>{X.delete(e)}}var Ne=typeof oe<"u"?oe:false,_=null,C="",de="",pe="",Y=0,M=null,Me=2e3,ye=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function Le(){let e=globalThis;return e.__buoyInstanceId||(e.__buoyInstanceId=ye()),e.__buoyInstanceId}function Pe(e){let n=o=>o&&Object.fromEntries(Object.entries(o).filter(([i])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(i)));return{deviceName:e.deviceName,deviceId:e.persistentDeviceId,platform:e.platform,extraDeviceInfo:JSON.stringify(n(e.extraDeviceInfo)),envVariables:JSON.stringify(n(e.envVariables)),connectionNonce:ye(),instanceId:Le()}}function Ae({deviceName:e,socketURL:n,persistentDeviceId:o,extraDeviceInfo:i,envVariables:l,platform:r,enableLogs:c=false}){let a=ue(null),[y,m]=W(null),[b,k]=W(false),h=n??fe(),S=ue(false),f=`[${e}]`,B=()=>{p(`${f} Socket connected successfully`,c),S.current=false,k(true),T({state:"connected",lastError:null})},$=d=>{p(`${f} Socket disconnected. Reason: ${d}`,c),k(false),T({state:"retrying"})},R=d=>{if(T({state:"retrying",lastError:d.message}),!Ne||S.current)return;S.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")},D=()=>{p(`${f} Socket connection timeout`,c,"error")};J(()=>{if(!o)return;let d=Be(h,r);T({targetURL:d,state:"connecting",lastError:null}),p(`${f} Platform: ${r}, using URL: ${d}`,c);try{_&&(C!==d||de!==o||pe!==r)&&(_.disconnect(),_=null),_?p(`${f} Reusing existing socket instance to ${d}`,c):(p(`${f} Creating new socket instance to ${d}`,c),_=Ee(d,{autoConnect:true,query:Pe({deviceName:e,persistentDeviceId:o,platform:r,extraDeviceInfo:i,envVariables:l}),reconnection:true,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]}),ke(_),C=d,de=o,pe=r),a.current=_;let u=a.current;return Y++,M&&(le(M),M=null),m(u),u.on("connect_error",R),u.on("connect_timeout",D),k(u.connected),u.connected&&p(`${f} Socket already connected on init`,c),u.on("connect",B),u.on("disconnect",$),()=>{p(`${f} Cleaning up socket event listeners`,c),u.off("connect",B),u.off("disconnect",$),u.off("connect_error",R),u.off("connect_timeout",D),Y--,Y===0&&(M=ae(()=>{M=null,!(Y>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")}},[o,h,r]),J(()=>{a.current&&a.current.io.opts.query&&o&&(p(`${f} Updating device name in socket connection`,c),a.current.io.opts.query={...a.current.io.opts.query,deviceName:e,deviceId:o,platform:r})},[e,f,o,r,c]);function w(){a.current&&!a.current.connected&&(p(`${f} Manually connecting to socket server`,c),a.current.connect())}function L(){a.current&&a.current.connected&&(p(`${f} Manually disconnecting from socket server`,c),a.current.disconnect())}let[E,q]=W(null);return J(()=>{if(y)return we(y,d=>{q(d?y:null),T(d?{state:"connected",lastError:null}:{state:"retrying",lastError:"Update Buoy Desktop and sign in to enable desktop sync."})})},[y]),{socket:E===y?y:null,connect:w,disconnect:L,isConnected:b&&E===y&&y!==null}}export{Re as DEFAULT_BROKER_PORT,_e as SYNC_PROTOCOL_VERSION,be as flushToolSyncNow,fe as getDefaultSocketURL,Oe as getMetroHost,Ue as getSyncStatus,re as registerToolFlusher,T as setSyncStatus,xe as subscribeSyncStatus,ce as unregisterToolFlusher,Te as useExternalSync,Ae as useExternalSyncSocket};
1
+ "use client";var oe=(()=>{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 me}from"@buoy-gg/license/web";import{useEffect as ve,useRef as ne}from"react";import{LicenseManager as C}from"@buoy-gg/license/web";function p(e,n,o="log"){if(!(!n&&o==="log"))switch(o){case"warn":console.warn("[Buoy]",e);break;case"error":console.error("[Buoy]",e);break;default:console.log("[Buoy]",e)}}var j="__buoyFlushToolSync";function H(){let e=globalThis;return e[j]||(e[j]=new Set),e[j]}function re(e){H().add(e)}function ce(e){H().delete(e)}function be(e){try{for(let n of H())try{n(e)}catch{}}catch{}}function se(e,n){let o=0,i=[e],l=new Set;for(;i.length>0;){if(o>n)return{over:true,approxBytes:o};let r=i.pop();if(r==null)o+=4;else if(typeof r=="string")o+=r.length+2;else if(typeof r=="number")o+=8;else if(typeof r=="boolean")o+=5;else if(typeof r=="object"){if(l.has(r))continue;if(l.add(r),Array.isArray(r)){o+=2+r.length;for(let c=0;c<r.length;c++)i.push(r[c])}else{o+=2;for(let c in r)o+=c.length+4,i.push(r[c])}}else o+=4}return{over:o>n,approxBytes:o}}var _e=1;function x(){let e=globalThis.__buoyRealNow;return typeof e=="function"?e():Date.now()}function ie(){return globalThis.__buoyRealTimers??globalThis}function ae(e,n){return ie().setTimeout(e,n)}function le(e){ie().clearTimeout(e)}function $e(e){let n=globalThis.__buoyWithRealClock;return typeof n=="function"?n(e):e()}var Ie=["_resetPingTimeout","_hasPingExpired"];function Se(e){let n=e?.io;if(!n||n.__buoyRealTimers)return;let o=l=>{if(l){l.setTimeoutFn=ae,l.clearTimeoutFn=le;for(let r of Ie){let c=l[r];if(typeof c!="function"||c.__buoyReal)continue;let a=function(...y){return $e(()=>c.apply(this,y))};a.__buoyReal=true,l[r]=a}}};o(n),o(n.engine);let i=n.open;typeof i=="function"&&(n.open=function(...l){let r=i.apply(this,l);return o(this?.engine),r}),n.__buoyRealTimers=true}var L="[ExternalSync]";function ke({socket:e,deviceId:n,getTools:o,watched:i,throttleMs:l=200,enableLogs:r=false}){let c=false,a=false,y=0,h=()=>!c&&a&&e.connected&&C.hasAccountAccess(),b=new Map,S={},m={},k=t=>t==="All"||t===n,f=(t,s)=>{if(h())try{e.emit(t,s)}catch(g){p(`${L} Failed to emit "${t}": ${g}. Payload must be JSON-serializable.`,r,"error")}},B=new Set,$=t=>{if(!h())return;let s=o()[t];if(!s)return;S[t]=x();let g;try{g=s.getSnapshot()}catch{return}let{over:I,approxBytes:U}=se(g,2097152);if(I){B.has(t)||(B.add(t),console.warn("[Buoy]",`${L} "${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 V={toolId:t,persistentDeviceId:n,timestamp:S[t],version:s.version,kind:"snapshot",payload:g};f("devtool-sync",V)},O=t=>{if(m[t])return;let s=x()-(S[t]??0);if(s>=l){$(t);return}m[t]=setTimeout(()=>{delete m[t],$(t)},l-s)},R=t=>{e.connected&&b.has(t)&&(m[t]&&(clearTimeout(m[t]),delete m[t]),$(t))};re(R);let w=new Map,P=(t,s)=>{if(!h())return;let g=o()[t];if(g){if(b.has(t)){if(w.get(t)===s)return;let I=b.get(t);b.set(t,g.subscribe(s==="stream"?()=>O(t):()=>{})),w.set(t,s),I?.(),p(`${L} "${t}" watch mode \u2192 ${s}`,r);return}b.set(t,g.subscribe(s==="stream"?()=>O(t):()=>{})),w.set(t,s),p(`${L} Watching "${t}" (${s})`,r)}},E=t=>{b.get(t)?.(),b.delete(t),w.delete(t),m[t]&&(clearTimeout(m[t]),delete m[t]),p(`${L} Stopped watching "${t}"`,r)},F=()=>{let t={persistentDeviceId:n,protocolVersion:1,tools:Object.entries(o()).map(([s,g])=>({toolId:s,version:g.version,actions:Object.keys(g.actions??{})}))};f("devtool-capabilities",t)},d=t=>{if(!(!h()||!k(t.targetDeviceId)))if(t.watching){let s=t.consolidated===true&&t.stream===false?"capture":"stream";i.set(t.toolId,s),P(t.toolId,s),s==="stream"&&$(t.toolId)}else i.delete(t.toolId),E(t.toolId)},u=t=>{!h()||!k(t.targetDeviceId)||$(t.toolId)},N=async t=>{if(!h()||!k(t.targetDeviceId))return;let s=y,{requestId:g,toolId:I,action:U,params:V}=t,v={requestId:g,toolId:I,action:U,persistentDeviceId:n,timestamp:x(),ok:false},ee=o()[I],te=ee?.actions?.[U];if(!te){v.error=ee?`Unknown action "${U}" on tool "${I}"`:`Unknown tool "${I}"`,f("devtool-action-result",v);return}try{v.result=await te(V),v.ok=true}catch(D){v.error=D instanceof Error?D.message:String(D)}if(!(s!==y||!h())){if(v.ok){let{over:D,approxBytes:he}=se(v.result,8388608);D&&(v.ok=false,v.result=void 0,v.error=`Result \u2248${(he/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).`)}v.timestamp=x(),f("devtool-action-result",v)}},A=()=>{y+=1;for(let s of[...b.keys()])E(s);i.clear();for(let s of Object.values(m))clearTimeout(s);let t=e;t.sendBuffer&&(t.sendBuffer=t.sendBuffer.filter(s=>!["devtool-sync","devtool-capabilities","devtool-action-result","device-license"].includes(String(s.data?.[0]))))},G=()=>{let t=C.getState();e.emit("device-license",{tier:t.tier,isPro:t.isPro?"1":"0"}),F()},Q=t=>{a=t?.protocol===1&&t.ready===true,h()?G():A()},ge=C.subscribe(()=>{C.hasAccountAccess()?h()&&G():(e.connected&&e.emit("device-license",{tier:"locked",isPro:"0"}),A())}),K=()=>{a=false,e.emit("buoy:access:request")},Z=()=>{a=false,A()};e.on("buoy:access",Q);for(let[t,s]of i)o()[t]&&P(t,s);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,ge(),e.off("buoy:access",Q),A(),ce(R),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[...b.keys()])E(t)}}function Te({tools:e,socket:n,deviceId:o,enabled:i=true,throttleMs:l=200,enableLogs:r=false}){let c=me().status==="admitted",a=ne(e);a.current=e;let y=ne(new Map),h=Object.keys(e).sort().join(",");ve(()=>{if(!n||!o||!i||!c){y.current.clear();return}return ke({socket:n,deviceId:o,getTools:()=>a.current,watched:y.current,throttleMs:l,enableLogs:r})},[n,o,i,c,l,r,h])}function we(e,n){let o=()=>n(false),i=()=>{o(),e.emit("buoy:access:request")},l=r=>{let c=r;n(c?.protocol===1&&c?.ready===true)};return e.on("connect",i),e.on("disconnect",o),e.on("buoy:access",l),o(),e.connected&&i(),()=>{e.off("connect",i),e.off("disconnect",o),e.off("buoy:access",l)}}import{useEffect as J,useRef as ue,useState as W}from"react";import{io as Ee}from"socket.io-client";function Be(e,n){return e}var Oe=42831;function Re(e){return`http://${e??"localhost"}:42831`}function Ne(){return null}function fe(){return Re(typeof location>"u"?null:location.hostname)}var z={targetURL:null,state:"idle",lastError:null,since:0},X=new Set;function T(e){z={...z,...e,since:x()},X.forEach(n=>n())}function Ue(){return z}function De(e){return X.add(e),()=>{X.delete(e)}}var xe=typeof oe<"u"?oe:false,_=null,Y="",de="",pe="",q=0,M=null,Le=2e3,ye=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`;function Me(){let e=globalThis;return e.__buoyInstanceId||(e.__buoyInstanceId=ye()),e.__buoyInstanceId}function Pe(e){let n=o=>o&&Object.fromEntries(Object.entries(o).filter(([i])=>!["BUOY_LICENSE_KEY","BUOY_KEY","EXPO_PUBLIC_BUOY_KEY","VITE_BUOY_KEY","NEXT_PUBLIC_BUOY_KEY","REACT_APP_BUOY_KEY","licenseKey"].includes(i)));return{deviceName:e.deviceName,deviceId:e.persistentDeviceId,platform:e.platform,extraDeviceInfo:JSON.stringify(n(e.extraDeviceInfo)),envVariables:JSON.stringify(n(e.envVariables)),connectionNonce:ye(),instanceId:Me()}}function Ae({deviceName:e,socketURL:n,persistentDeviceId:o,extraDeviceInfo:i,envVariables:l,platform:r,enableLogs:c=false}){let a=ue(null),[y,h]=W(null),[b,S]=W(false),m=n??fe(),k=ue(false),f=`[${e}]`,B=()=>{p(`${f} Socket connected successfully`,c),k.current=false,S(true),T({state:"connected",lastError:null})},$=d=>{p(`${f} Socket disconnected. Reason: ${d}`,c),S(false),T({state:"retrying"})},O=d=>{if(T({state:"retrying",lastError:d.message}),!xe||k.current)return;k.current=true;let u=r==="android"&&/localhost|127\.0\.0\.1/.test(Y)?"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 ${Y} (is Buoy Desktop running?). Retrying in the background. ${u}(${d.message})`,c,"warn")},R=()=>{p(`${f} Socket connection timeout`,c,"error")};J(()=>{if(!o)return;let d=Be(m,r);T({targetURL:d,state:"connecting",lastError:null}),p(`${f} Platform: ${r}, using URL: ${d}`,c);try{if(_&&(Y!==d||de!==o||pe!==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{}_=Ee(d,{autoConnect:true,query:Pe({deviceName:e,persistentDeviceId:o,platform:r,extraDeviceInfo:i,envVariables:l}),reconnection:true,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,transports:["websocket"]}),Se(_),Y=d,de=o,pe=r}a.current=_;let u=a.current;return q++,M&&(le(M),M=null),h(u),u.on("connect_error",O),u.on("connect_timeout",R),S(u.connected),u.connected&&p(`${f} Socket already connected on init`,c),u.on("connect",B),u.on("disconnect",$),()=>{p(`${f} Cleaning up socket event listeners`,c),u.off("connect",B),u.off("disconnect",$),u.off("connect_error",O),u.off("connect_timeout",R),q--,q===0&&(M=ae(()=>{M=null,!(q>0||_!==u)&&(p(`${f} No longer used; disconnecting`,c),u.disconnect(),_=null,T({state:"idle",lastError:null}))},Le))}}catch(u){p(`${f} Failed to initialize socket: ${u}`,c,"error")}},[o,m,r]),J(()=>{a.current&&a.current.io.opts.query&&o&&(p(`${f} Updating device name in socket connection`,c),a.current.io.opts.query={...a.current.io.opts.query,deviceName:e,deviceId:o,platform:r})},[e,f,o,r,c]);function w(){a.current&&!a.current.connected&&(p(`${f} Manually connecting to socket server`,c),a.current.connect())}function P(){a.current&&a.current.connected&&(p(`${f} Manually disconnecting from socket server`,c),a.current.disconnect())}let[E,F]=W(null);return J(()=>{if(y)return we(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:E===y?y:null,connect:w,disconnect:P,isConnected:b&&E===y&&y!==null}}export{Oe as DEFAULT_BROKER_PORT,_e as SYNC_PROTOCOL_VERSION,be as flushToolSyncNow,fe as getDefaultSocketURL,Ne as getMetroHost,Ue as getSyncStatus,re as registerToolFlusher,T as setSyncStatus,De as subscribeSyncStatus,ce as unregisterToolFlusher,Te as useExternalSync,Ae as useExternalSyncSocket};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/external-sync",
3
- "version": "7.0.63",
3
+ "version": "7.0.64",
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.1",
38
- "@buoy-gg/license": "^7.0.63"
38
+ "@buoy-gg/license": "^7.0.64"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "react": "*"