@buoy-gg/license 7.0.60 → 7.0.62

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.
Files changed (47) hide show
  1. package/lib/commonjs/capacitorBridge.js +1 -1
  2. package/lib/commonjs/config.js +2 -2
  3. package/lib/commonjs/freeToken.js +2 -2
  4. package/lib/commonjs/freeTokenKey.js +6 -0
  5. package/lib/commonjs/headless.js +1 -1
  6. package/lib/commonjs/nodeSession.js +1 -1
  7. package/lib/commonjs/serviceKey.js +1 -1
  8. package/lib/commonjs/sessionManager.js +1 -1
  9. package/lib/commonjs/sessionToken.js +2 -2
  10. package/lib/commonjs/sessionTokenKey.js +6 -0
  11. package/lib/module/capacitorBridge.js +1 -1
  12. package/lib/module/config.js +1 -1
  13. package/lib/module/freeToken.js +1 -1
  14. package/lib/module/freeTokenKey.js +6 -0
  15. package/lib/module/headless.js +1 -1
  16. package/lib/module/nodeSession.js +1 -1
  17. package/lib/module/serviceKey.js +1 -1
  18. package/lib/module/sessionManager.js +1 -1
  19. package/lib/module/sessionToken.js +1 -1
  20. package/lib/module/sessionTokenKey.js +6 -0
  21. package/lib/typescript/commonjs/config.d.ts +6 -6
  22. package/lib/typescript/commonjs/freeToken.d.ts +1 -3
  23. package/lib/typescript/commonjs/freeTokenKey.d.ts +9 -0
  24. package/lib/typescript/commonjs/headless.d.ts +2 -2
  25. package/lib/typescript/commonjs/nodeSession.d.ts +0 -2
  26. package/lib/typescript/commonjs/serviceKey.d.ts +0 -1
  27. package/lib/typescript/commonjs/sessionManager.d.ts +0 -4
  28. package/lib/typescript/commonjs/sessionToken.d.ts +0 -3
  29. package/lib/typescript/commonjs/sessionTokenKey.d.ts +9 -0
  30. package/lib/typescript/module/config.d.ts +6 -6
  31. package/lib/typescript/module/freeToken.d.ts +1 -3
  32. package/lib/typescript/module/freeTokenKey.d.ts +9 -0
  33. package/lib/typescript/module/headless.d.ts +2 -2
  34. package/lib/typescript/module/nodeSession.d.ts +0 -2
  35. package/lib/typescript/module/serviceKey.d.ts +0 -1
  36. package/lib/typescript/module/sessionManager.d.ts +0 -4
  37. package/lib/typescript/module/sessionToken.d.ts +0 -3
  38. package/lib/typescript/module/sessionTokenKey.d.ts +9 -0
  39. package/lib/web/capacitor.mjs +1 -1
  40. package/lib/web/chunks/LicenseManager-5SP7AMUW.mjs +1 -0
  41. package/lib/web/chunks/chunk-4ZLILVOY.mjs +73 -0
  42. package/lib/web/chunks/chunk-D5RC3UOG.mjs +1 -0
  43. package/lib/web/index.mjs +1 -1
  44. package/package.json +1 -1
  45. package/lib/web/chunks/LicenseManager-X7ZLSRCH.mjs +0 -1
  46. package/lib/web/chunks/chunk-3JAIQNSD.mjs +0 -73
  47. package/lib/web/chunks/chunk-UPTHA45A.mjs +0 -1
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.callCapacitorAsApp=callCapacitorAsApp;exports.callCapacitorNative=callCapacitorNative;exports.callCapacitorNativeCallback=callCapacitorNativeCallback;exports.capacitorListenerCount=capacitorListenerCount;exports.capacitorPlugin=capacitorPlugin;exports.clearCapacitorCalls=clearCapacitorCalls;exports.colorSchemeQueryValue=colorSchemeQueryValue;exports.emitCapacitorEvent=emitCapacitorEvent;exports.getCapacitorAppHost=getCapacitorAppHost;exports.getCapacitorCalls=getCapacitorCalls;exports.getColorSchemeQueries=getColorSchemeQueries;exports.hasCapacitorPlugin=hasCapacitorPlugin;exports.installCapacitorBridge=installCapacitorBridge;exports.interceptCapacitor=interceptCapacitor;exports.isCapacitorBridgeInstalled=isCapacitorBridgeInstalled;exports.listenCapacitorNative=listenCapacitorNative;exports.loadCapacitorAppHost=loadCapacitorAppHost;exports.makeCapacitorCallbackId=makeCapacitorCallbackId;exports.subscribeCapacitorCalls=subscribeCapacitorCalls;var _capacitorHost=require("./capacitorHost.js");const STATE_KEY="__BUOY_CAPACITOR_BRIDGE__";const LOG_LIMIT=300;function capacitor(){const e=globalThis.Capacitor;return e&&typeof e==="object"?e:null}function state(){const e=globalThis;let t=e[STATE_KEY];if(!t||t.version!==1){t={version:1,originalPromise:null,originalCallback:null,wrappedPromise:null,wrappedCallback:null,interceptors:[],listeners:new Map,log:[],subscribers:new Set,seq:0,fakeIds:0};e[STATE_KEY]=t}return t}function realNow(){const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()}function asOptions(e){return e&&typeof e==="object"?e:{}}function notify(e){for(const t of Array.from(e.subscribers)){try{t()}catch{}}}function record(e,t){const r={seq:++e.seq,...t};e.log.push(r);if(e.log.length>LOG_LIMIT)e.log.splice(0,e.log.length-LOG_LIMIT);notify(e);return r}function matching(e,t,r){return e.interceptors.filter(n=>(n.plugin==="*"||n.plugin===t.plugin)&&(!n.methods||n.methods.includes(t.method))&&typeof n[r]==="function").map((n,o)=>({interceptor:n,index:o})).sort((n,o)=>(o.interceptor.order??0)-(n.interceptor.order??0)||n.index-o.index).map(n=>n.interceptor)}function listenerKey(e,t){return`${e}:${String(t)}`}function makeCapacitorCallbackId(){return`buoy-${++state().fakeIds}`}function installCapacitorBridge(e={}){if(!(0,_capacitorHost.isCapacitorNative)())return false;const t=capacitor();if(!t||typeof t.nativePromise!=="function"||typeof t.nativeCallback!=="function")return false;const r=state();if(r.wrappedPromise&&t.nativePromise===r.wrappedPromise&&t.nativeCallback===r.wrappedCallback)return true;if(t.DEBUG!==true&&e.release!==true)return false;r.originalPromise=t.nativePromise;r.originalCallback=t.nativeCallback;const n=r.originalPromise;const o=r.originalCallback;const i=(a,s,C,v)=>{const f={plugin:a,method:s,options:asOptions(C)};const g=matching(r,f,"promise");const c=d=>{if(d>=g.length){v();if(s==="removeAllListeners"){for(const b of Array.from(r.listeners.keys()))if(b.startsWith(`${a}:`))r.listeners.delete(b)}return n.call(t,a,s,C)}try{return Promise.resolve(g[d].promise(f,()=>c(d+1)))}catch(b){return Promise.reject(b)}};return c(0)};r.runPromise=i;const l=(a,s,C)=>{const v=record(r,{plugin:a,method:s,kind:"promise",options:asOptions(C),start:realNow()});let f=false;const g=i(a,s,C,()=>{f=true});g.then(c=>{Object.assign(v,{end:realNow(),ok:true,result:c,answeredByBuoy:!f});notify(r)},c=>{Object.assign(v,{end:realNow(),ok:false,error:c,answeredByBuoy:!f});notify(r)});return g};const p=(a,s,C,v)=>{let f=C;let g=v;if(typeof f==="function"){g=f;f=null}const c={plugin:a,method:s,options:asOptions(f)};const d=record(r,{plugin:a,method:s,kind:"callback",options:c.options,start:realNow(),events:0});let b=false;const k=matching(r,c,"callback");const P=(m,u)=>{if(m>=k.length){b=true;return o.call(t,a,s,f,u)}return k[m].callback(c,u,h=>P(m+1,h))};const _=s==="addListener";const w=(m,u)=>{d.events=(d.events??0)+1;if(!_&&d.end===void 0){d.end=realNow();d.ok=!u;if(u)d.error=u;else d.result=m;notify(r)}else{const h=realNow();record(r,{plugin:a,method:_?String(c.options.eventName??"event"):s,kind:"event",options:{},start:h,end:h,ok:!u,...u?{error:u}:{result:m}})}g?.(m,u)};const y=P(0,w);d.answeredByBuoy=!b;if(s==="addListener"&&y!=null&&typeof g==="function"){const m=listenerKey(a,c.options.eventName);let u=r.listeners.get(m);if(!u)r.listeners.set(m,u=new Map);u.set(String(y),g)}else if(s==="removeListener"){r.listeners.get(listenerKey(a,c.options.eventName))?.delete(String(c.options.callbackId))}return y};t.nativePromise=l;t.nativeCallback=p;r.wrappedPromise=l;r.wrappedCallback=p;trackColorSchemeQueries();return true}const SCHEME_QUERY=/^\s*\(\s*prefers-color-scheme\s*:\s*(dark|light)\s*\)\s*$/i;const SCHEME_KEY="__BUOY_COLOR_SCHEME_QUERIES__";function colorSchemeQueryValue(e){const t=SCHEME_QUERY.exec(e);return t?t[1].toLowerCase():null}function trackColorSchemeQueries(){const e=globalThis;const t=globalThis.WeakRef;if(e[SCHEME_KEY]||typeof e.matchMedia!=="function"||!t)return;const r=[];e[SCHEME_KEY]=r;const n=e.matchMedia;e.matchMedia=function o(i){const l=n.call(this??globalThis,i);if(l&&colorSchemeQueryValue(String(i))){for(let p=r.length-1;p>=0;p--)if(!r[p].deref())r.splice(p,1);r.push(new t(l))}return l}}function getColorSchemeQueries(){const e=globalThis[SCHEME_KEY];if(!e)return[];return e.map(t=>t.deref()).filter(t=>!!t)}function isCapacitorBridgeInstalled(){const e=capacitor();const t=state();return Boolean(t.wrappedPromise&&e?.nativePromise===t.wrappedPromise)}function interceptCapacitor(e){const t=state();t.interceptors.push(e);return()=>{const r=t.interceptors.indexOf(e);if(r>=0)t.interceptors.splice(r,1)}}function emitCapacitorEvent(e,t,r){const n=state().listeners.get(listenerKey(e,t));if(!n)return 0;let o=0;for(const i of Array.from(n.values())){try{i(r);o++}catch(l){globalThis.console?.error(l)}}return o}function capacitorListenerCount(e,t){return state().listeners.get(listenerKey(e,t))?.size??0}function pluginHeader(e){return capacitor()?.PluginHeaders?.find(t=>t.name===e)}function hasCapacitorPlugin(e){if(!(0,_capacitorHost.isCapacitorNative)())return false;try{return Boolean(pluginHeader(e))||capacitor()?.isPluginAvailable?.(e)===true}catch{return false}}function originals(){const e=capacitor();const t=state();return{cap:e,promise:t.originalPromise??e?.nativePromise??null,callback:t.originalCallback??e?.nativeCallback??null}}function callCapacitorNative(e,t,r={}){const{cap:n,promise:o}=originals();if(!n||!o)return Promise.reject(new Error("Capacitor bridge unavailable"));return o.call(n,e,t,r)}function callCapacitorAsApp(e,t,r={}){const n=state().runPromise;if(n&&isCapacitorBridgeInstalled())return n(e,t,r,()=>{});return callCapacitorNative(e,t,r)}function callCapacitorNativeCallback(e,t,r,n){const{cap:o,callback:i}=originals();if(!o||!i)return null;return i.call(o,e,t,r,n)}function listenCapacitorNative(e,t,r){const{cap:n,promise:o,callback:i}=originals();if(!n||!i)return Promise.reject(new Error("Capacitor bridge unavailable"));const l=i.call(n,e,"addListener",{eventName:t},a=>r(a));const p=async()=>{if(l==null)return;const a={eventName:t,callbackId:l};const s=pluginHeader(e)?.methods?.find(C=>C.name==="removeListener")?.rtype;if(s==="promise"&&o)await o.call(n,e,"removeListener",a);else i.call(n,e,"removeListener",a,()=>{})};return Promise.resolve({remove:p})}function getCapacitorCalls(){return state().log}function clearCapacitorCalls(){const e=state();e.log.length=0;notify(e)}function subscribeCapacitorCalls(e){const t=state();t.subscribers.add(e);return()=>{t.subscribers.delete(e)}}const NOT_METHODS=new Set(["then","catch","finally","$$typeof","toJSON","constructor"]);function capacitorPlugin(e){if(!hasCapacitorPlugin(e))return null;return new Proxy({},{get(t,r){if(typeof r!=="string"||NOT_METHODS.has(r))return void 0;if(r==="addListener"){return(n,o)=>listenCapacitorNative(e,n,o)}return n=>callCapacitorNative(e,r,n??{})}})}const HOST_KEY="__BUOY_CAPACITOR_HOST__";function loadCapacitorAppHost(){if(!(0,_capacitorHost.isCapacitorNative)())return Promise.resolve(null);const e=globalThis;const t=e[HOST_KEY];if(t)return t;const r=i=>typeof i==="string"&&i?i:null;const n=async i=>{if(!hasCapacitorPlugin(i))return{};try{return await callCapacitorNative(i,"getInfo")??{}}catch{return{}}};const o=Promise.all([n("App"),n("Device")]).then(([i,l])=>{const p={isSimulator:typeof l.isVirtual==="boolean"?l.isVirtual:null,deviceName:r(l.name),bundleId:r(i.id),appName:r(i.name)};e[`${HOST_KEY}_value`]=p;return p});e[HOST_KEY]=o;return o}function getCapacitorAppHost(){return globalThis[`${HOST_KEY}_value`]??null}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.callCapacitorAsApp=callCapacitorAsApp;exports.callCapacitorNative=callCapacitorNative;exports.callCapacitorNativeCallback=callCapacitorNativeCallback;exports.capacitorListenerCount=capacitorListenerCount;exports.capacitorPlugin=capacitorPlugin;exports.clearCapacitorCalls=clearCapacitorCalls;exports.colorSchemeQueryValue=colorSchemeQueryValue;exports.emitCapacitorEvent=emitCapacitorEvent;exports.getCapacitorAppHost=getCapacitorAppHost;exports.getCapacitorCalls=getCapacitorCalls;exports.getColorSchemeQueries=getColorSchemeQueries;exports.hasCapacitorPlugin=hasCapacitorPlugin;exports.installCapacitorBridge=installCapacitorBridge;exports.interceptCapacitor=interceptCapacitor;exports.isCapacitorBridgeInstalled=isCapacitorBridgeInstalled;exports.listenCapacitorNative=listenCapacitorNative;exports.loadCapacitorAppHost=loadCapacitorAppHost;exports.makeCapacitorCallbackId=makeCapacitorCallbackId;exports.subscribeCapacitorCalls=subscribeCapacitorCalls;var _capacitorHost=require("./capacitorHost.js");const STATE_KEY="__BUOY_CAPACITOR_BRIDGE__";const LOG_LIMIT=300;function capacitor(){const e=globalThis.Capacitor;return e&&typeof e==="object"?e:null}function state(){const e=globalThis;let t=e[STATE_KEY];if(!t||t.version!==1){t={version:1,originalPromise:null,originalCallback:null,wrappedPromise:null,wrappedCallback:null,interceptors:[],listeners:new Map,log:[],subscribers:new Set,seq:0,fakeIds:0};e[STATE_KEY]=t}return t}function realNow(){const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()}function trackBuoyClicks(e){if(e.clickListenerInstalled||typeof window==="undefined"||typeof window.addEventListener!=="function")return;e.clickListenerInstalled=true;window.addEventListener("click",t=>{let r=t.composedPath?.()[0]??t.target;e.buoyClick=false;while(r){if(r.closest?.("[data-buoy-root], [data-buoy-portal-host]")){e.buoyClick=true;break}r=r.getRootNode?.().host??null}if(e.clickTimer)clearTimeout(e.clickTimer);e.clickTimer=setTimeout(()=>{e.buoyClick=false},0)},true)}function asOptions(e){return e&&typeof e==="object"?e:{}}function isBuoyBreadcrumb(e,t,r,o){if(t!=="SentryCapacitor"||r!=="addBreadcrumb")return false;const n=asOptions(o);if(n.category==="ui.click")return e.buoyClick===true;if(n.category==="console"&&typeof n.message==="string")return/^\[(?:buoy(?:[^\]]*)?|@buoy-gg\/[^\]]+|RnBetterDevTools|React ?Buoy|RN-BUOY DEBUG|js-top|perf-monitor|impersonate|RenderCause|HighlightUpdates|RenderTracker|ProfilerInterceptor|HighlightPerf|DebugBorders|optional-module|route-events|RouteObserver)\]/i.test(n.message);if(n.category!=="fetch"&&n.category!=="xhr")return false;const i=asOptions(n.data);if(typeof i.url!=="string")return false;try{const l=new URL(i.url,typeof location==="undefined"?"http://localhost":location.href);const c=l.hostname.toLowerCase();if(["api.buoy.gg","ai.buoy.gg","gateway.buoy.gg"].includes(c))return true;if(c==="keygen.sh"||c.endsWith(".keygen.sh"))return true;if(["buoy.gg","www.buoy.gg"].includes(c)&&/^\/api\/(license|settings|auth|session|install|t)(?:\/|$)/.test(l.pathname))return true;if(l.pathname==="/buoy-assets.json")return true;const a=globalThis.__BUOY_INTERNAL_HOSTS__;return a instanceof Set&&[...a].some(s=>typeof s==="string"&&s.toLowerCase()===l.host.toLowerCase())}catch{return false}}function notify(e){for(const t of Array.from(e.subscribers)){try{t()}catch{}}}function record(e,t){const r={seq:++e.seq,...t};e.log.push(r);if(e.log.length>LOG_LIMIT)e.log.splice(0,e.log.length-LOG_LIMIT);notify(e);return r}function matching(e,t,r){return e.interceptors.filter(o=>(o.plugin==="*"||o.plugin===t.plugin)&&(!o.methods||o.methods.includes(t.method))&&typeof o[r]==="function").map((o,n)=>({interceptor:o,index:n})).sort((o,n)=>(n.interceptor.order??0)-(o.interceptor.order??0)||o.index-n.index).map(o=>o.interceptor)}function listenerKey(e,t){return`${e}:${String(t)}`}function makeCapacitorCallbackId(){return`buoy-${++state().fakeIds}`}function installCapacitorBridge(e={}){if(!(0,_capacitorHost.isCapacitorNative)())return false;const t=capacitor();if(!t||typeof t.nativePromise!=="function"||typeof t.nativeCallback!=="function")return false;const r=state();if(r.wrappedPromise&&t.nativePromise===r.wrappedPromise&&t.nativeCallback===r.wrappedCallback)return true;if(t.DEBUG!==true&&e.release!==true)return false;r.originalPromise=t.nativePromise;r.originalCallback=t.nativeCallback;const o=r.originalPromise;const n=r.originalCallback;const i=(a,s,g,h)=>{const f={plugin:a,method:s,options:asOptions(g)};const m=matching(r,f,"promise");const u=d=>{if(d>=m.length){h();if(s==="removeAllListeners"){for(const b of Array.from(r.listeners.keys()))if(b.startsWith(`${a}:`))r.listeners.delete(b)}return o.call(t,a,s,g)}try{return Promise.resolve(m[d].promise(f,()=>u(d+1)))}catch(b){return Promise.reject(b)}};return u(0)};r.runPromise=i;const l=(a,s,g)=>{if(isBuoyBreadcrumb(r,a,s,g)){return i(a,s,g,()=>{})}const h=record(r,{plugin:a,method:s,kind:"promise",options:asOptions(g),start:realNow()});let f=false;const m=i(a,s,g,()=>{f=true});m.then(u=>{Object.assign(h,{end:realNow(),ok:true,result:u,answeredByBuoy:!f});notify(r)},u=>{Object.assign(h,{end:realNow(),ok:false,error:u,answeredByBuoy:!f});notify(r)});return m};const c=(a,s,g,h)=>{let f=g;let m=h;if(typeof f==="function"){m=f;f=null}const u={plugin:a,method:s,options:asOptions(f)};const d=record(r,{plugin:a,method:s,kind:"callback",options:u.options,start:realNow(),events:0});let b=false;const k=matching(r,u,"callback");const w=(C,p)=>{if(C>=k.length){b=true;return n.call(t,a,s,f,p)}return k[C].callback(u,p,y=>w(C+1,y))};const P=s==="addListener";const _=(C,p)=>{d.events=(d.events??0)+1;if(!P&&d.end===void 0){d.end=realNow();d.ok=!p;if(p)d.error=p;else d.result=C;notify(r)}else{const y=realNow();record(r,{plugin:a,method:P?String(u.options.eventName??"event"):s,kind:"event",options:{},start:y,end:y,ok:!p,...p?{error:p}:{result:C}})}m?.(C,p)};const v=w(0,_);d.answeredByBuoy=!b;if(s==="addListener"&&v!=null&&typeof m==="function"){const C=listenerKey(a,u.options.eventName);let p=r.listeners.get(C);if(!p)r.listeners.set(C,p=new Map);p.set(String(v),m)}else if(s==="removeListener"){r.listeners.get(listenerKey(a,u.options.eventName))?.delete(String(u.options.callbackId))}return v};t.nativePromise=l;t.nativeCallback=c;r.wrappedPromise=l;r.wrappedCallback=c;trackBuoyClicks(r);trackColorSchemeQueries();return true}const SCHEME_QUERY=/^\s*\(\s*prefers-color-scheme\s*:\s*(dark|light)\s*\)\s*$/i;const SCHEME_KEY="__BUOY_COLOR_SCHEME_QUERIES__";function colorSchemeQueryValue(e){const t=SCHEME_QUERY.exec(e);return t?t[1].toLowerCase():null}function trackColorSchemeQueries(){const e=globalThis;const t=globalThis.WeakRef;if(e[SCHEME_KEY]||typeof e.matchMedia!=="function"||!t)return;const r=[];e[SCHEME_KEY]=r;const o=e.matchMedia;e.matchMedia=function n(i){const l=o.call(this??globalThis,i);if(l&&colorSchemeQueryValue(String(i))){for(let c=r.length-1;c>=0;c--)if(!r[c].deref())r.splice(c,1);r.push(new t(l))}return l}}function getColorSchemeQueries(){const e=globalThis[SCHEME_KEY];if(!e)return[];return e.map(t=>t.deref()).filter(t=>!!t)}function isCapacitorBridgeInstalled(){const e=capacitor();const t=state();return Boolean(t.wrappedPromise&&e?.nativePromise===t.wrappedPromise)}function interceptCapacitor(e){const t=state();t.interceptors.push(e);return()=>{const r=t.interceptors.indexOf(e);if(r>=0)t.interceptors.splice(r,1)}}function emitCapacitorEvent(e,t,r){const o=state().listeners.get(listenerKey(e,t));if(!o)return 0;let n=0;for(const i of Array.from(o.values())){try{i(r);n++}catch(l){globalThis.console?.error(l)}}return n}function capacitorListenerCount(e,t){return state().listeners.get(listenerKey(e,t))?.size??0}function pluginHeader(e){return capacitor()?.PluginHeaders?.find(t=>t.name===e)}function hasCapacitorPlugin(e){if(!(0,_capacitorHost.isCapacitorNative)())return false;try{return Boolean(pluginHeader(e))||capacitor()?.isPluginAvailable?.(e)===true}catch{return false}}function originals(){const e=capacitor();const t=state();return{cap:e,promise:t.originalPromise??e?.nativePromise??null,callback:t.originalCallback??e?.nativeCallback??null}}function callCapacitorNative(e,t,r={}){const{cap:o,promise:n}=originals();if(!o||!n)return Promise.reject(new Error("Capacitor bridge unavailable"));return n.call(o,e,t,r)}function callCapacitorAsApp(e,t,r={}){const o=state().runPromise;if(o&&isCapacitorBridgeInstalled())return o(e,t,r,()=>{});return callCapacitorNative(e,t,r)}function callCapacitorNativeCallback(e,t,r,o){const{cap:n,callback:i}=originals();if(!n||!i)return null;return i.call(n,e,t,r,o)}function listenCapacitorNative(e,t,r){const{cap:o,promise:n,callback:i}=originals();if(!o||!i)return Promise.reject(new Error("Capacitor bridge unavailable"));const l=i.call(o,e,"addListener",{eventName:t},a=>r(a));const c=async()=>{if(l==null)return;const a={eventName:t,callbackId:l};const s=pluginHeader(e)?.methods?.find(g=>g.name==="removeListener")?.rtype;if(s==="promise"&&n)await n.call(o,e,"removeListener",a);else i.call(o,e,"removeListener",a,()=>{})};return Promise.resolve({remove:c})}function getCapacitorCalls(){return state().log}function clearCapacitorCalls(){const e=state();e.log.length=0;notify(e)}function subscribeCapacitorCalls(e){const t=state();t.subscribers.add(e);return()=>{t.subscribers.delete(e)}}const NOT_METHODS=new Set(["then","catch","finally","$$typeof","toJSON","constructor"]);function capacitorPlugin(e){if(!hasCapacitorPlugin(e))return null;return new Proxy({},{get(t,r){if(typeof r!=="string"||NOT_METHODS.has(r))return void 0;if(r==="addListener"){return(o,n)=>listenCapacitorNative(e,o,n)}return o=>callCapacitorNative(e,r,o??{})}})}const HOST_KEY="__BUOY_CAPACITOR_HOST__";function loadCapacitorAppHost(){if(!(0,_capacitorHost.isCapacitorNative)())return Promise.resolve(null);const e=globalThis;const t=e[HOST_KEY];if(t)return t;const r=i=>typeof i==="string"&&i?i:null;const o=async i=>{if(!hasCapacitorPlugin(i))return{};try{return await callCapacitorNative(i,"getInfo")??{}}catch{return{}}};const n=Promise.all([o("App"),o("Device")]).then(([i,l])=>{const c={isSimulator:typeof l.isVirtual==="boolean"?l.isVirtual:null,deviceName:r(l.name),bundleId:r(i.id),appName:r(i.name)};e[`${HOST_KEY}_value`]=c;return c});e[HOST_KEY]=n;return n}function getCapacitorAppHost(){return globalThis[`${HOST_KEY}_value`]??null}
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SESSION_TOKEN_PUBLIC_KEY=exports.LICENSE_VERDICT_CACHE_DURATION=exports.LICENSE_TRANSIENT_RETRY_DELAYS=exports.LICENSE_STORAGE_KEY=exports.LICENSE_REVALIDATION_INTERVAL=exports.LICENSE_RATE_LIMIT_DEFAULT_WAIT=exports.LICENSE_QUOTA_COOLDOWN=exports.LICENSE_QUIET_VALIDATION_TTL=exports.LICENSE_LAUNCH_VALIDATION_TTL=exports.LICENSE_HOLD_STORAGE_KEY=exports.LICENSE_FLEET_MACHINE_THRESHOLD=exports.LICENSE_CACHE_DURATION=exports.KEYGEN_POLICIES=exports.KEYGEN_CONFIG=exports.FREE_TOKEN_PUBLIC_KEY=exports.DEVICE_FINGERPRINT_STORAGE_KEY=void 0;/*!
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DEVICE_FINGERPRINT_STORAGE_KEY=void 0;Object.defineProperty(exports,"FREE_TOKEN_PUBLIC_KEY",{enumerable:true,get:function(){return _freeTokenKey.FREE_TOKEN_PUBLIC_KEY}});exports.LICENSE_VERDICT_CACHE_DURATION=exports.LICENSE_TRANSIENT_RETRY_DELAYS=exports.LICENSE_STORAGE_KEY=exports.LICENSE_REVALIDATION_INTERVAL=exports.LICENSE_RATE_LIMIT_DEFAULT_WAIT=exports.LICENSE_QUOTA_COOLDOWN=exports.LICENSE_QUIET_VALIDATION_TTL=exports.LICENSE_LAUNCH_VALIDATION_TTL=exports.LICENSE_HOLD_STORAGE_KEY=exports.LICENSE_FLEET_MACHINE_THRESHOLD=exports.LICENSE_CACHE_DURATION=exports.KEYGEN_POLICIES=exports.KEYGEN_CONFIG=void 0;Object.defineProperty(exports,"SESSION_TOKEN_PUBLIC_KEY",{enumerable:true,get:function(){return _sessionTokenKey.SESSION_TOKEN_PUBLIC_KEY}});var _freeTokenKey=require("./freeTokenKey.js");var _sessionTokenKey=require("./sessionTokenKey.js");/*!
2
2
  * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
@@ -14,4 +14,4 @@
14
14
  * Pro is $9/mo, and is free every weekend for anyone holding a key —
15
15
  * including a free one (`npx buoy login`). Buy a key at
16
16
  * https://buoy.gg or use it free on Saturday and Sunday.
17
- */const KEYGEN_CONFIG=exports.KEYGEN_CONFIG={accountId:"b0eba0e8-e904-4906-b644-38f9aab57bed",productId:"bf67cb43-eeef-40ca-b308-e6e1b22c0eaa",apiUrl:"https://buoy.gg/api/license"};const FREE_TOKEN_PUBLIC_KEY=exports.FREE_TOKEN_PUBLIC_KEY="3b546fc717a62683f3236c70167899a271bee3ffc04df6ec1eea60a394a2f1e9";const SESSION_TOKEN_PUBLIC_KEY=exports.SESSION_TOKEN_PUBLIC_KEY="36abba0267f7f379d992a5b6df641daab4190bcc9e639e36f1378e3c1ac52746";const KEYGEN_POLICIES=exports.KEYGEN_POLICIES={free:"394e3351-1249-4f73-807a-703408604c0e",solo:"fa5d3c8f-5379-40f1-b63e-ab8a974b2f28",business:"690c2212-8e54-426f-b4b4-002ee1c0ae2b"};const LICENSE_CACHE_DURATION=exports.LICENSE_CACHE_DURATION=30*24*60*60*1e3;const LICENSE_REVALIDATION_INTERVAL=exports.LICENSE_REVALIDATION_INTERVAL=24*60*60*1e3;const LICENSE_STORAGE_KEY=exports.LICENSE_STORAGE_KEY="buoy-gg-license";const DEVICE_FINGERPRINT_STORAGE_KEY=exports.DEVICE_FINGERPRINT_STORAGE_KEY="buoy-gg-device-fingerprint";const LICENSE_LAUNCH_VALIDATION_TTL=exports.LICENSE_LAUNCH_VALIDATION_TTL=60*60*1e3;const LICENSE_TRANSIENT_RETRY_DELAYS=exports.LICENSE_TRANSIENT_RETRY_DELAYS=[5*1e3,20*1e3,60*1e3,5*60*1e3,15*60*1e3];const LICENSE_RATE_LIMIT_DEFAULT_WAIT=exports.LICENSE_RATE_LIMIT_DEFAULT_WAIT=60*1e3;const LICENSE_QUOTA_COOLDOWN=exports.LICENSE_QUOTA_COOLDOWN=60*60*1e3;const LICENSE_VERDICT_CACHE_DURATION=exports.LICENSE_VERDICT_CACHE_DURATION=24*60*60*1e3;const LICENSE_FLEET_MACHINE_THRESHOLD=exports.LICENSE_FLEET_MACHINE_THRESHOLD=50;const LICENSE_QUIET_VALIDATION_TTL=exports.LICENSE_QUIET_VALIDATION_TTL=LICENSE_CACHE_DURATION;const LICENSE_HOLD_STORAGE_KEY=exports.LICENSE_HOLD_STORAGE_KEY="buoy-gg-license-hold";
17
+ */const KEYGEN_CONFIG=exports.KEYGEN_CONFIG=Object.freeze({accountId:"b0eba0e8-e904-4906-b644-38f9aab57bed",productId:"bf67cb43-eeef-40ca-b308-e6e1b22c0eaa",apiUrl:"https://buoy.gg/api/license"});const KEYGEN_POLICIES=exports.KEYGEN_POLICIES=Object.freeze({free:"394e3351-1249-4f73-807a-703408604c0e",solo:"fa5d3c8f-5379-40f1-b63e-ab8a974b2f28",business:"690c2212-8e54-426f-b4b4-002ee1c0ae2b"});const LICENSE_CACHE_DURATION=exports.LICENSE_CACHE_DURATION=30*24*60*60*1e3;const LICENSE_REVALIDATION_INTERVAL=exports.LICENSE_REVALIDATION_INTERVAL=24*60*60*1e3;const LICENSE_STORAGE_KEY=exports.LICENSE_STORAGE_KEY="buoy-gg-license";const DEVICE_FINGERPRINT_STORAGE_KEY=exports.DEVICE_FINGERPRINT_STORAGE_KEY="buoy-gg-device-fingerprint";const LICENSE_LAUNCH_VALIDATION_TTL=exports.LICENSE_LAUNCH_VALIDATION_TTL=60*60*1e3;const LICENSE_TRANSIENT_RETRY_DELAYS=exports.LICENSE_TRANSIENT_RETRY_DELAYS=[5*1e3,20*1e3,60*1e3,5*60*1e3,15*60*1e3];const LICENSE_RATE_LIMIT_DEFAULT_WAIT=exports.LICENSE_RATE_LIMIT_DEFAULT_WAIT=60*1e3;const LICENSE_QUOTA_COOLDOWN=exports.LICENSE_QUOTA_COOLDOWN=60*60*1e3;const LICENSE_VERDICT_CACHE_DURATION=exports.LICENSE_VERDICT_CACHE_DURATION=24*60*60*1e3;const LICENSE_FLEET_MACHINE_THRESHOLD=exports.LICENSE_FLEET_MACHINE_THRESHOLD=50;const LICENSE_QUIET_VALIDATION_TTL=exports.LICENSE_QUIET_VALIDATION_TTL=LICENSE_CACHE_DURATION;const LICENSE_HOLD_STORAGE_KEY=exports.LICENSE_HOLD_STORAGE_KEY="buoy-gg-license-hold";
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FREE_TOKEN_PREFIX=void 0;exports.__setFreeTokenPublicKeyForTests=__setFreeTokenPublicKeyForTests;exports.accountHashFor=accountHashFor;exports.isBuoyToken=isBuoyToken;exports.mintFreeToken=mintFreeToken;exports.publicKeyFor=publicKeyFor;exports.verifyFreeToken=verifyFreeToken;var _tweetnacl=_interopRequireDefault(require("tweetnacl"));var _config=require("./config.js");function _interopRequireDefault(t){return t&&t.__esModule?t:{default:t}}/*!
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FREE_TOKEN_PREFIX=void 0;exports.accountHashFor=accountHashFor;exports.isBuoyToken=isBuoyToken;exports.mintFreeToken=mintFreeToken;exports.publicKeyFor=publicKeyFor;exports.verifyFreeToken=verifyFreeToken;var _tweetnacl=_interopRequireDefault(require("tweetnacl"));var _freeTokenKey=require("./freeTokenKey.js");function _interopRequireDefault(n){return n&&n.__esModule?n:{default:n}}/*!
2
2
  * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */const FREE_TOKEN_PREFIX=exports.FREE_TOKEN_PREFIX="BUOY1";const FREE_TOKEN_VERSION=1;const FREE_TOKEN_TIER_FREE=1;const FREE_TOKEN_DOMAIN="buoy-free-token-v1:";const PAYLOAD_LENGTH=22;const SIGNATURE_LENGTH=64;const TOKEN_PATTERN=/^BUOY1-([A-Z2-7]+)-([A-Z2-7]+)$/;function isBuoyToken(t){return TOKEN_PATTERN.test(t.trim().toUpperCase())}const B32="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function base32Encode(t){let r="";let e=0;let n=0;for(const o of t){n=n<<8|o;e+=8;while(e>=5){r+=B32[n>>>e-5&31];e-=5}}if(e>0)r+=B32[n<<5-e&31];return r}function base32Decode(t){const r=[];let e=0;let n=0;for(const o of t){const s=B32.indexOf(o);if(s===-1)return null;n=n<<5|s;e+=5;if(e>=8){r.push(n>>>e-8&255);e-=8}}return new Uint8Array(r)}function hexToBytes(t){const r=t.trim().toLowerCase();const e=new Uint8Array(r.length/2);for(let n=0;n<e.length;n+=1)e[n]=parseInt(r.slice(n*2,n*2+2),16);return e}function bytesToHex(t){let r="";for(const e of t)r+=e.toString(16).padStart(2,"0");return r}function utf8(t){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(t);const r=new Uint8Array(t.length);for(let e=0;e<t.length;e+=1)r[e]=t.charCodeAt(e)&255;return r}function concat(t,r){const e=new Uint8Array(t.length+r.length);e.set(t,0);e.set(r,t.length);return e}function signedMessage(t){return concat(utf8(FREE_TOKEN_DOMAIN),t)}function accountHashFor(t){return _tweetnacl.default.hash(utf8(t)).slice(0,16)}function encodePayload(t,r){const e=new Uint8Array(PAYLOAD_LENGTH);e[0]=FREE_TOKEN_VERSION;e[1]=FREE_TOKEN_TIER_FREE;const n=Math.max(0,Math.min(4294967295,Math.floor(t)));e[2]=n>>>24&255;e[3]=n>>>16&255;e[4]=n>>>8&255;e[5]=n&255;e.set(r.slice(0,16),6);return e}function mintFreeToken(t,r,e){const n=encodePayload(r/1e3,accountHashFor(t));const{secretKey:o}=_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(e));const s=_tweetnacl.default.sign.detached(signedMessage(n),o);return`${FREE_TOKEN_PREFIX}-${base32Encode(n)}-${base32Encode(s)}`}function publicKeyFor(t){return bytesToHex(_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(t)).publicKey)}let activePublicKey=_config.FREE_TOKEN_PUBLIC_KEY;function __setFreeTokenPublicKeyForTests(t){activePublicKey=t??_config.FREE_TOKEN_PUBLIC_KEY}function verifyFreeToken(t,r=activePublicKey){const e=TOKEN_PATTERN.exec(t.trim().toUpperCase());if(!e)return null;const n=base32Decode(e[1]);const o=base32Decode(e[2]);if(!n||!o)return null;if(n.length!==PAYLOAD_LENGTH||o.length!==SIGNATURE_LENGTH)return null;if(n[0]!==FREE_TOKEN_VERSION||n[1]!==FREE_TOKEN_TIER_FREE)return null;try{if(!_tweetnacl.default.sign.detached.verify(signedMessage(n),o,hexToBytes(r)))return null}catch{return null}const s=(n[2]<<24>>>0)+(n[3]<<16)+(n[4]<<8)+n[5];return{tier:"free",issuedAt:s*1e3,accountHash:bytesToHex(n.slice(6,22))}}
6
+ */const FREE_TOKEN_PREFIX=exports.FREE_TOKEN_PREFIX="BUOY1";const FREE_TOKEN_VERSION=1;const FREE_TOKEN_TIER_FREE=1;const FREE_TOKEN_DOMAIN="buoy-free-token-v1:";const PAYLOAD_LENGTH=22;const SIGNATURE_LENGTH=64;const TOKEN_PATTERN=/^BUOY1-([A-Z2-7]+)-([A-Z2-7]+)$/;function isBuoyToken(n){return TOKEN_PATTERN.test(n.trim().toUpperCase())}const B32="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function base32Encode(n){let t="";let e=0;let r=0;for(const o of n){r=r<<8|o;e+=8;while(e>=5){t+=B32[r>>>e-5&31];e-=5}}if(e>0)t+=B32[r<<5-e&31];return t}function base32Decode(n){const t=[];let e=0;let r=0;for(const o of n){const c=B32.indexOf(o);if(c===-1)return null;r=r<<5|c;e+=5;if(e>=8){t.push(r>>>e-8&255);e-=8}}return new Uint8Array(t)}function hexToBytes(n){const t=n.trim().toLowerCase();const e=new Uint8Array(t.length/2);for(let r=0;r<e.length;r+=1)e[r]=parseInt(t.slice(r*2,r*2+2),16);return e}function bytesToHex(n){let t="";for(const e of n)t+=e.toString(16).padStart(2,"0");return t}function utf8(n){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(n);const t=new Uint8Array(n.length);for(let e=0;e<n.length;e+=1)t[e]=n.charCodeAt(e)&255;return t}function concat(n,t){const e=new Uint8Array(n.length+t.length);e.set(n,0);e.set(t,n.length);return e}function signedMessage(n){return concat(utf8(FREE_TOKEN_DOMAIN),n)}function accountHashFor(n){return _tweetnacl.default.hash(utf8(n)).slice(0,16)}function encodePayload(n,t){const e=new Uint8Array(PAYLOAD_LENGTH);e[0]=FREE_TOKEN_VERSION;e[1]=FREE_TOKEN_TIER_FREE;const r=Math.max(0,Math.min(4294967295,Math.floor(n)));e[2]=r>>>24&255;e[3]=r>>>16&255;e[4]=r>>>8&255;e[5]=r&255;e.set(t.slice(0,16),6);return e}function mintFreeToken(n,t,e){const r=encodePayload(t/1e3,accountHashFor(n));const{secretKey:o}=_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(e));const c=_tweetnacl.default.sign.detached(signedMessage(r),o);return`${FREE_TOKEN_PREFIX}-${base32Encode(r)}-${base32Encode(c)}`}function publicKeyFor(n){return bytesToHex(_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(n)).publicKey)}const verifyingPublicKey=_freeTokenKey.FREE_TOKEN_PUBLIC_KEY;function verifyFreeToken(n){const t=TOKEN_PATTERN.exec(n.trim().toUpperCase());if(!t)return null;const e=base32Decode(t[1]);const r=base32Decode(t[2]);if(!e||!r)return null;if(e.length!==PAYLOAD_LENGTH||r.length!==SIGNATURE_LENGTH)return null;if(e[0]!==FREE_TOKEN_VERSION||e[1]!==FREE_TOKEN_TIER_FREE)return null;try{if(!_tweetnacl.default.sign.detached.verify(signedMessage(e),r,hexToBytes(verifyingPublicKey)))return null}catch{return null}const o=(e[2]<<24>>>0)+(e[3]<<16)+(e[4]<<8)+e[5];return{tier:"free",issuedAt:o*1e3,accountHash:bytesToHex(e.slice(6,22))}}
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FREE_TOKEN_PUBLIC_KEY=void 0;/*!
2
+ * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
+ *
4
+ * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
+ * (https://buoy.gg/terms), not an OSS license.
6
+ */const FREE_TOKEN_PUBLIC_KEY=exports.FREE_TOKEN_PUBLIC_KEY="3b546fc717a62683f3236c70167899a271bee3ffc04df6ec1eea60a394a2f1e9";
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"CLI_AUDIENCE",{enumerable:true,get:function(){return _nodeSession.CLI_AUDIENCE}});Object.defineProperty(exports,"DESKTOP_AUDIENCE",{enumerable:true,get:function(){return _nodeSession.DESKTOP_AUDIENCE}});Object.defineProperty(exports,"DEV_AUDIENCE",{enumerable:true,get:function(){return _devToken.DEV_AUDIENCE}});Object.defineProperty(exports,"KEYGEN_CONFIG",{enumerable:true,get:function(){return _config.KEYGEN_CONFIG}});Object.defineProperty(exports,"LICENSE_CACHE_DURATION",{enumerable:true,get:function(){return _config.LICENSE_CACHE_DURATION}});Object.defineProperty(exports,"LICENSE_LAUNCH_VALIDATION_TTL",{enumerable:true,get:function(){return _config.LICENSE_LAUNCH_VALIDATION_TTL}});Object.defineProperty(exports,"LICENSE_REVALIDATION_INTERVAL",{enumerable:true,get:function(){return _config.LICENSE_REVALIDATION_INTERVAL}});Object.defineProperty(exports,"LICENSE_TRANSIENT_RETRY_DELAYS",{enumerable:true,get:function(){return _config.LICENSE_TRANSIENT_RETRY_DELAYS}});Object.defineProperty(exports,"LicenseTransportError",{enumerable:true,get:function(){return _api.LicenseTransportError}});Object.defineProperty(exports,"SERVICE_AUDIENCE",{enumerable:true,get:function(){return _serviceKey.SERVICE_AUDIENCE}});Object.defineProperty(exports,"SERVICE_KEY_PREFIX",{enumerable:true,get:function(){return _serviceKey.SERVICE_KEY_PREFIX}});Object.defineProperty(exports,"SESSION_OFFLINE_GRACE_MS",{enumerable:true,get:function(){return _sessionManager.SESSION_OFFLINE_GRACE_MS}});Object.defineProperty(exports,"SessionError",{enumerable:true,get:function(){return _sessionManager.SessionError}});Object.defineProperty(exports,"SessionManagerImpl",{enumerable:true,get:function(){return _sessionManager.SessionManagerImpl}});Object.defineProperty(exports,"__setFreeTokenPublicKeyForTests",{enumerable:true,get:function(){return _freeToken.__setFreeTokenPublicKeyForTests}});Object.defineProperty(exports,"__setSessionTokenPublicKeyForTests",{enumerable:true,get:function(){return _sessionToken.__setSessionTokenPublicKeyForTests}});Object.defineProperty(exports,"accountHashFor",{enumerable:true,get:function(){return _freeToken.accountHashFor}});Object.defineProperty(exports,"checkDevToken",{enumerable:true,get:function(){return _devToken.checkDevToken}});Object.defineProperty(exports,"createNodeSession",{enumerable:true,get:function(){return _nodeSession.createNodeSession}});Object.defineProperty(exports,"defaultSessionFile",{enumerable:true,get:function(){return _nodeSession.defaultSessionFile}});Object.defineProperty(exports,"exchangeServiceKey",{enumerable:true,get:function(){return _serviceKey.exchangeServiceKey}});Object.defineProperty(exports,"fileLock",{enumerable:true,get:function(){return _nodeSession.fileLock}});Object.defineProperty(exports,"fileSessionStorage",{enumerable:true,get:function(){return _nodeSession.fileSessionStorage}});Object.defineProperty(exports,"isAcceptedValidation",{enumerable:true,get:function(){return _api.isAcceptedValidation}});Object.defineProperty(exports,"isBuoyToken",{enumerable:true,get:function(){return _freeToken.isBuoyToken}});Object.defineProperty(exports,"isDevToken",{enumerable:true,get:function(){return _devToken.isDevToken}});Object.defineProperty(exports,"isRecognizedAccount",{enumerable:true,get:function(){return _tier.isRecognizedAccount}});Object.defineProperty(exports,"isServiceKey",{enumerable:true,get:function(){return _serviceKey.isServiceKey}});Object.defineProperty(exports,"isTransientLicenseError",{enumerable:true,get:function(){return _api.isTransientLicenseError}});Object.defineProperty(exports,"mintFreeToken",{enumerable:true,get:function(){return _freeToken.mintFreeToken}});Object.defineProperty(exports,"mintSessionToken",{enumerable:true,get:function(){return _sessionToken.mintSessionToken}});Object.defineProperty(exports,"normalizeLicenseKey",{enumerable:true,get:function(){return _serviceKey.normalizeLicenseKey}});Object.defineProperty(exports,"publicKeyFor",{enumerable:true,get:function(){return _freeToken.publicKeyFor}});Object.defineProperty(exports,"receiveCodeOnLoopback",{enumerable:true,get:function(){return _nodeSession.receiveCodeOnLoopback}});Object.defineProperty(exports,"resolveAccountAccess",{enumerable:true,get:function(){return _accountAccess.resolveAccountAccess}});Object.defineProperty(exports,"resolveTier",{enumerable:true,get:function(){return _tier.resolveTier}});Object.defineProperty(exports,"sameLicenseKey",{enumerable:true,get:function(){return _serviceKey.sameLicenseKey}});Object.defineProperty(exports,"signCache",{enumerable:true,get:function(){return _cacheSignature.signCache}});Object.defineProperty(exports,"validateLicense",{enumerable:true,get:function(){return _api.validateLicense}});Object.defineProperty(exports,"verifyCacheSignature",{enumerable:true,get:function(){return _cacheSignature.verifyCacheSignature}});Object.defineProperty(exports,"verifyFreeToken",{enumerable:true,get:function(){return _freeToken.verifyFreeToken}});Object.defineProperty(exports,"verifySessionToken",{enumerable:true,get:function(){return _sessionToken.verifySessionToken}});var _api=require("./api.js");var _tier=require("./tier.js");var _freeToken=require("./freeToken.js");var _accountAccess=require("./accountAccess.js");var _cacheSignature=require("./cacheSignature.js");var _config=require("./config.js");var _nodeSession=require("./nodeSession.js");var _sessionManager=require("./sessionManager.js");var _sessionToken=require("./sessionToken.js");var _serviceKey=require("./serviceKey.js");var _devToken=require("./devToken.js");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"CLI_AUDIENCE",{enumerable:true,get:function(){return _nodeSession.CLI_AUDIENCE}});Object.defineProperty(exports,"DESKTOP_AUDIENCE",{enumerable:true,get:function(){return _nodeSession.DESKTOP_AUDIENCE}});Object.defineProperty(exports,"DEV_AUDIENCE",{enumerable:true,get:function(){return _devToken.DEV_AUDIENCE}});Object.defineProperty(exports,"KEYGEN_CONFIG",{enumerable:true,get:function(){return _config.KEYGEN_CONFIG}});Object.defineProperty(exports,"LICENSE_CACHE_DURATION",{enumerable:true,get:function(){return _config.LICENSE_CACHE_DURATION}});Object.defineProperty(exports,"LICENSE_LAUNCH_VALIDATION_TTL",{enumerable:true,get:function(){return _config.LICENSE_LAUNCH_VALIDATION_TTL}});Object.defineProperty(exports,"LICENSE_REVALIDATION_INTERVAL",{enumerable:true,get:function(){return _config.LICENSE_REVALIDATION_INTERVAL}});Object.defineProperty(exports,"LICENSE_TRANSIENT_RETRY_DELAYS",{enumerable:true,get:function(){return _config.LICENSE_TRANSIENT_RETRY_DELAYS}});Object.defineProperty(exports,"LicenseTransportError",{enumerable:true,get:function(){return _api.LicenseTransportError}});Object.defineProperty(exports,"SERVICE_AUDIENCE",{enumerable:true,get:function(){return _serviceKey.SERVICE_AUDIENCE}});Object.defineProperty(exports,"SERVICE_KEY_PREFIX",{enumerable:true,get:function(){return _serviceKey.SERVICE_KEY_PREFIX}});Object.defineProperty(exports,"SESSION_OFFLINE_GRACE_MS",{enumerable:true,get:function(){return _sessionManager.SESSION_OFFLINE_GRACE_MS}});Object.defineProperty(exports,"SessionError",{enumerable:true,get:function(){return _sessionManager.SessionError}});Object.defineProperty(exports,"SessionManagerImpl",{enumerable:true,get:function(){return _sessionManager.SessionManagerImpl}});Object.defineProperty(exports,"accountHashFor",{enumerable:true,get:function(){return _freeToken.accountHashFor}});Object.defineProperty(exports,"checkDevToken",{enumerable:true,get:function(){return _devToken.checkDevToken}});Object.defineProperty(exports,"createNodeSession",{enumerable:true,get:function(){return _nodeSession.createNodeSession}});Object.defineProperty(exports,"defaultSessionFile",{enumerable:true,get:function(){return _nodeSession.defaultSessionFile}});Object.defineProperty(exports,"exchangeServiceKey",{enumerable:true,get:function(){return _serviceKey.exchangeServiceKey}});Object.defineProperty(exports,"fileLock",{enumerable:true,get:function(){return _nodeSession.fileLock}});Object.defineProperty(exports,"fileSessionStorage",{enumerable:true,get:function(){return _nodeSession.fileSessionStorage}});Object.defineProperty(exports,"isAcceptedValidation",{enumerable:true,get:function(){return _api.isAcceptedValidation}});Object.defineProperty(exports,"isBuoyToken",{enumerable:true,get:function(){return _freeToken.isBuoyToken}});Object.defineProperty(exports,"isDevToken",{enumerable:true,get:function(){return _devToken.isDevToken}});Object.defineProperty(exports,"isRecognizedAccount",{enumerable:true,get:function(){return _tier.isRecognizedAccount}});Object.defineProperty(exports,"isServiceKey",{enumerable:true,get:function(){return _serviceKey.isServiceKey}});Object.defineProperty(exports,"isTransientLicenseError",{enumerable:true,get:function(){return _api.isTransientLicenseError}});Object.defineProperty(exports,"mintFreeToken",{enumerable:true,get:function(){return _freeToken.mintFreeToken}});Object.defineProperty(exports,"mintSessionToken",{enumerable:true,get:function(){return _sessionToken.mintSessionToken}});Object.defineProperty(exports,"normalizeLicenseKey",{enumerable:true,get:function(){return _serviceKey.normalizeLicenseKey}});Object.defineProperty(exports,"publicKeyFor",{enumerable:true,get:function(){return _freeToken.publicKeyFor}});Object.defineProperty(exports,"receiveCodeOnLoopback",{enumerable:true,get:function(){return _nodeSession.receiveCodeOnLoopback}});Object.defineProperty(exports,"resolveAccountAccess",{enumerable:true,get:function(){return _accountAccess.resolveAccountAccess}});Object.defineProperty(exports,"resolveTier",{enumerable:true,get:function(){return _tier.resolveTier}});Object.defineProperty(exports,"sameLicenseKey",{enumerable:true,get:function(){return _serviceKey.sameLicenseKey}});Object.defineProperty(exports,"signCache",{enumerable:true,get:function(){return _cacheSignature.signCache}});Object.defineProperty(exports,"validateLicense",{enumerable:true,get:function(){return _api.validateLicense}});Object.defineProperty(exports,"verifyCacheSignature",{enumerable:true,get:function(){return _cacheSignature.verifyCacheSignature}});Object.defineProperty(exports,"verifyFreeToken",{enumerable:true,get:function(){return _freeToken.verifyFreeToken}});Object.defineProperty(exports,"verifySessionToken",{enumerable:true,get:function(){return _sessionToken.verifySessionToken}});var _api=require("./api.js");var _tier=require("./tier.js");var _freeToken=require("./freeToken.js");var _accountAccess=require("./accountAccess.js");var _cacheSignature=require("./cacheSignature.js");var _config=require("./config.js");var _nodeSession=require("./nodeSession.js");var _sessionManager=require("./sessionManager.js");var _sessionToken=require("./sessionToken.js");var _serviceKey=require("./serviceKey.js");var _devToken=require("./devToken.js");
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */const DESKTOP_AUDIENCE=exports.DESKTOP_AUDIENCE="app:gg.buoy.desktop";const CLI_AUDIENCE=exports.CLI_AUDIENCE="app:gg.buoy.cli";const LOGIN_TIMEOUT_MS=5*60*1e3;const MAX_BODY_BYTES=4096;const LOCK_STALE_MS=6e4;const LOCK_WAIT_MS=3e4;const STATUS_TIMEOUT_MS=8e3;const DEV_TOKEN_TIMEOUT_MS=15e3;const TLS_INTERCEPT_CODES=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","CERT_UNTRUSTED"]);function describeFetchError(e){const r=e?.cause;if(r&&typeof r.code==="string")return r.code;if(e?.name==="TimeoutError")return"timed out";if(r&&typeof r.message==="string")return r.message;return e instanceof Error?e.message:String(e)}function defaultSessionFile(){return process.env.BUOY_SESSION_FILE||(0,_nodePath.join)((0,_nodeOs.homedir)(),".buoy","session.json")}function fileSessionStorage(e){const r=async()=>{try{const n=JSON.parse(await _nodeFs.promises.readFile(e,"utf8"));return n&&typeof n==="object"?n:{}}catch{return{}}};const u=async n=>{await _nodeFs.promises.mkdir((0,_nodePath.dirname)(e),{recursive:true,mode:448});if(Object.keys(n).length===0){await _nodeFs.promises.rm(e,{force:true});return}const i=`${e}.${process.pid}.${(0,_nodeCrypto.randomBytes)(4).toString("hex")}.tmp`;await _nodeFs.promises.writeFile(i,JSON.stringify(n),{mode:384});await _nodeFs.promises.rename(i,e)};return{async getItem(n){return(await r())[n]??null},async setItem(n,i){const d=await r();d[n]=i;await u(d)},async removeItem(n){const i=await r();if(!(n in i))return;delete i[n];await u(i)}}}function fileLock(e,r={}){const u=r.staleMs??LOCK_STALE_MS;const n=r.waitMs??LOCK_WAIT_MS;return async(i,d)=>{const a=`${process.pid}:${(0,_nodeCrypto.randomBytes)(8).toString("hex")}`;const p=Date.now()+n;await _nodeFs.promises.mkdir((0,_nodePath.dirname)(e),{recursive:true,mode:448});for(;;){try{await _nodeFs.promises.writeFile(e,a,{flag:"wx",mode:384});break}catch(t){if(t.code!=="EEXIST")throw t;const s=await _nodeFs.promises.stat(e).catch(()=>null);if(s&&Date.now()-s.mtimeMs>u){await _nodeFs.promises.rm(e,{force:true});continue}if(Date.now()>p)throw new Error("Another Buoy process holds the sign-in lock.");await new Promise(o=>setTimeout(o,50))}}try{return await d()}finally{const t=await _nodeFs.promises.readFile(e,"utf8").catch(()=>null);if(t===a)await _nodeFs.promises.rm(e,{force:true})}}}function safeEqual(e,r){const u=Buffer.from(e);const n=Buffer.from(r);return u.length===n.length&&(0,_nodeCrypto.timingSafeEqual)(u,n)}async function receiveCodeOnLoopback(e,r,u,n={}){let i;let d;const a=new Promise((c,l)=>{i=c;d=l});a.catch(()=>{});const p=_nodeHttp.default.createServer((c,l)=>{if(c.headers.origin===u){l.setHeader("Access-Control-Allow-Origin",u);l.setHeader("Access-Control-Allow-Headers","Content-Type");l.setHeader("Access-Control-Allow-Methods","POST, OPTIONS");l.setHeader("Access-Control-Allow-Private-Network","true")}if(c.method==="OPTIONS")return void l.writeHead(204).end();if(c.method!=="POST")return void l.writeHead(405).end();let m="";c.on("data",g=>{m+=g;if(m.length>MAX_BODY_BYTES)c.destroy()});c.on("end",()=>{let g=null;try{g=JSON.parse(m)}catch{}if(!g||typeof g.state!=="string"||!safeEqual(g.state,r))return void l.writeHead(400).end();l.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof g.code==="string"&&g.code)o(()=>i(g.code));else o(()=>d(new _sessionManager.SessionError("access_denied","Sign-in was cancelled.")))})});const t=setTimeout(()=>o(()=>d(new _sessionManager.SessionError("timeout","Sign-in took too long."))),n.timeoutMs??LOGIN_TIMEOUT_MS);t.unref?.();const s=()=>o(()=>d(new _sessionManager.SessionError("popup_closed","Sign-in was cancelled.")));n.signal?.addEventListener("abort",s);function o(c){clearTimeout(t);n.signal?.removeEventListener("abort",s);p.close();c()}await new Promise((c,l)=>{p.once("error",l);p.listen(0,"127.0.0.1",()=>c())});const f=p.address();if(!f||typeof f==="string"){o(()=>d(new Error("Could not open a local port")));throw new Error("Could not open a local port")}return{url:`${e}&port=${f.port}`,code:a}}function createNodeSession(e){const r=defaultSessionFile();const u=e.storage??fileSessionStorage(r);const n=(e.signinOrigin??process.env.BUOY_SITE_URL??"https://buoy.gg").replace(/\/$/,"");const i=e.fetch??((t,s)=>fetch(t,s));const d={fetch:i,storage:async()=>u,now:e.now??(()=>Date.now()),random:t=>new Uint8Array((0,_nodeCrypto.randomBytes)(t)),sha256:async t=>new Uint8Array((0,_nodeCrypto.createHash)("sha256").update(t).digest()),openPopup:()=>null,onMessage:()=>()=>{},withLock:fileLock(e.lockFile??`${r}.lock`),setTimer:(t,s)=>{const o=setTimeout(t,Math.min(s,2147483647));o.unref?.();return o},clearTimer:t=>clearTimeout(t),publicKeyHex:e.publicKeyHex};const a=new _sessionManager.SessionManagerImpl(d);a.configure({audience:e.audience,signinOrigin:n});const p=async()=>{let t;try{t=await i(`${n}/api/auth/status`,{method:"GET",headers:{},signal:AbortSignal.timeout(STATUS_TIMEOUT_MS)})}catch(o){const f=describeFetchError(o);return TLS_INTERCEPT_CODES.has(f)?{state:"unreachable",detail:f,hint:"Your network may re-sign secure traffic. Point NODE_EXTRA_CA_CERTS at your company's root certificate."}:{state:"unreachable",detail:f}}const s=await t.json().catch(()=>null);if(t.status===200&&s?.enabled===true)return{state:"enabled"};if(t.status===200&&s?.enabled===false)return{state:"disabled"};return{state:"unreachable",detail:s?`HTTP ${t.status}`:`HTTP ${t.status}, not a Buoy answer`}};return{manager:a,async load(){await a.load();return a.getStatus()},getStatus:()=>a.getStatus(),signIn:(t={})=>a.signInWith(async(s,o)=>{const{url:f,code:c}=await receiveCodeOnLoopback(s,o,n,t);await e.openBrowser(f);return c}),signOut:()=>a.signOut(),refresh:t=>a.refresh(t),sync:()=>a.sync(),async devToken(){const t=a.getAccessToken();if(!t)return{ok:false,detail:"This computer is not signed in. Run `npx buoy login`."};try{const s=await i(`${n}/api/auth/dev-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:t}),signal:AbortSignal.timeout(DEV_TOKEN_TIMEOUT_MS)});const o=await s.json().catch(()=>null);if(s.status===200&&typeof o?.dev_token==="string"){return{ok:true,token:o.dev_token,tier:typeof o.tier==="string"?o.tier:"free"}}return{ok:false,detail:typeof o?.error_description==="string"?o.error_description:"buoy.gg did not make a dev token."}}catch{return{ok:false,detail:"Buoy could not be reached. Check your connection and try again."}}},checkAvailability:p,async isAvailable(){return(await p()).state==="enabled"},subscribe:t=>a.subscribe(t)}}
6
+ */const DESKTOP_AUDIENCE=exports.DESKTOP_AUDIENCE="app:gg.buoy.desktop";const CLI_AUDIENCE=exports.CLI_AUDIENCE="app:gg.buoy.cli";const LOGIN_TIMEOUT_MS=5*60*1e3;const MAX_BODY_BYTES=4096;const LOCK_STALE_MS=6e4;const LOCK_WAIT_MS=3e4;const STATUS_TIMEOUT_MS=8e3;const DEV_TOKEN_TIMEOUT_MS=15e3;const TLS_INTERCEPT_CODES=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","CERT_UNTRUSTED"]);function describeFetchError(e){const r=e?.cause;if(r&&typeof r.code==="string")return r.code;if(e?.name==="TimeoutError")return"timed out";if(r&&typeof r.message==="string")return r.message;return e instanceof Error?e.message:String(e)}function defaultSessionFile(){return process.env.BUOY_SESSION_FILE||(0,_nodePath.join)((0,_nodeOs.homedir)(),".buoy","session.json")}function fileSessionStorage(e){const r=async()=>{try{const n=JSON.parse(await _nodeFs.promises.readFile(e,"utf8"));return n&&typeof n==="object"?n:{}}catch{return{}}};const u=async n=>{await _nodeFs.promises.mkdir((0,_nodePath.dirname)(e),{recursive:true,mode:448});if(Object.keys(n).length===0){await _nodeFs.promises.rm(e,{force:true});return}const i=`${e}.${process.pid}.${(0,_nodeCrypto.randomBytes)(4).toString("hex")}.tmp`;await _nodeFs.promises.writeFile(i,JSON.stringify(n),{mode:384});await _nodeFs.promises.rename(i,e)};return{async getItem(n){return(await r())[n]??null},async setItem(n,i){const d=await r();d[n]=i;await u(d)},async removeItem(n){const i=await r();if(!(n in i))return;delete i[n];await u(i)}}}function fileLock(e,r={}){const u=r.staleMs??LOCK_STALE_MS;const n=r.waitMs??LOCK_WAIT_MS;return async(i,d)=>{const a=`${process.pid}:${(0,_nodeCrypto.randomBytes)(8).toString("hex")}`;const p=Date.now()+n;await _nodeFs.promises.mkdir((0,_nodePath.dirname)(e),{recursive:true,mode:448});for(;;){try{await _nodeFs.promises.writeFile(e,a,{flag:"wx",mode:384});break}catch(t){if(t.code!=="EEXIST")throw t;const s=await _nodeFs.promises.stat(e).catch(()=>null);if(s&&Date.now()-s.mtimeMs>u){await _nodeFs.promises.rm(e,{force:true});continue}if(Date.now()>p)throw new Error("Another Buoy process holds the sign-in lock.");await new Promise(o=>setTimeout(o,50))}}try{return await d()}finally{const t=await _nodeFs.promises.readFile(e,"utf8").catch(()=>null);if(t===a)await _nodeFs.promises.rm(e,{force:true})}}}function safeEqual(e,r){const u=Buffer.from(e);const n=Buffer.from(r);return u.length===n.length&&(0,_nodeCrypto.timingSafeEqual)(u,n)}async function receiveCodeOnLoopback(e,r,u,n={}){let i;let d;const a=new Promise((c,l)=>{i=c;d=l});a.catch(()=>{});const p=_nodeHttp.default.createServer((c,l)=>{if(c.headers.origin===u){l.setHeader("Access-Control-Allow-Origin",u);l.setHeader("Access-Control-Allow-Headers","Content-Type");l.setHeader("Access-Control-Allow-Methods","POST, OPTIONS");l.setHeader("Access-Control-Allow-Private-Network","true")}if(c.method==="OPTIONS")return void l.writeHead(204).end();if(c.method!=="POST")return void l.writeHead(405).end();let m="";c.on("data",g=>{m+=g;if(m.length>MAX_BODY_BYTES)c.destroy()});c.on("end",()=>{let g=null;try{g=JSON.parse(m)}catch{}if(!g||typeof g.state!=="string"||!safeEqual(g.state,r))return void l.writeHead(400).end();l.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof g.code==="string"&&g.code)o(()=>i(g.code));else o(()=>d(new _sessionManager.SessionError("access_denied","Sign-in was cancelled.")))})});const t=setTimeout(()=>o(()=>d(new _sessionManager.SessionError("timeout","Sign-in took too long."))),n.timeoutMs??LOGIN_TIMEOUT_MS);t.unref?.();const s=()=>o(()=>d(new _sessionManager.SessionError("popup_closed","Sign-in was cancelled.")));n.signal?.addEventListener("abort",s);function o(c){clearTimeout(t);n.signal?.removeEventListener("abort",s);p.close();c()}await new Promise((c,l)=>{p.once("error",l);p.listen(0,"127.0.0.1",()=>c())});const f=p.address();if(!f||typeof f==="string"){o(()=>d(new Error("Could not open a local port")));throw new Error("Could not open a local port")}return{url:`${e}&port=${f.port}`,code:a}}function createNodeSession(e){const r=defaultSessionFile();const u=e.storage??fileSessionStorage(r);const n=(e.signinOrigin??process.env.BUOY_SITE_URL??"https://buoy.gg").replace(/\/$/,"");const i=e.fetch??((t,s)=>fetch(t,s));const d={fetch:i,storage:async()=>u,now:e.now??(()=>Date.now()),random:t=>new Uint8Array((0,_nodeCrypto.randomBytes)(t)),sha256:async t=>new Uint8Array((0,_nodeCrypto.createHash)("sha256").update(t).digest()),openPopup:()=>null,onMessage:()=>()=>{},withLock:fileLock(e.lockFile??`${r}.lock`),setTimer:(t,s)=>{const o=setTimeout(t,Math.min(s,2147483647));o.unref?.();return o},clearTimer:t=>clearTimeout(t)};const a=new _sessionManager.SessionManagerImpl(d);a.configure({audience:e.audience,signinOrigin:n});const p=async()=>{let t;try{t=await i(`${n}/api/auth/status`,{method:"GET",headers:{},signal:AbortSignal.timeout(STATUS_TIMEOUT_MS)})}catch(o){const f=describeFetchError(o);return TLS_INTERCEPT_CODES.has(f)?{state:"unreachable",detail:f,hint:"Your network may re-sign secure traffic. Point NODE_EXTRA_CA_CERTS at your company's root certificate."}:{state:"unreachable",detail:f}}const s=await t.json().catch(()=>null);if(t.status===200&&s?.enabled===true)return{state:"enabled"};if(t.status===200&&s?.enabled===false)return{state:"disabled"};return{state:"unreachable",detail:s?`HTTP ${t.status}`:`HTTP ${t.status}, not a Buoy answer`}};return{manager:a,async load(){await a.load();return a.getStatus()},getStatus:()=>a.getStatus(),signIn:(t={})=>a.signInWith(async(s,o)=>{const{url:f,code:c}=await receiveCodeOnLoopback(s,o,n,t);await e.openBrowser(f);return c}),signOut:()=>a.signOut(),refresh:t=>a.refresh(t),sync:()=>a.sync(),async devToken(){const t=a.getAccessToken();if(!t)return{ok:false,detail:"This computer is not signed in. Run `npx buoy login`."};try{const s=await i(`${n}/api/auth/dev-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:t}),signal:AbortSignal.timeout(DEV_TOKEN_TIMEOUT_MS)});const o=await s.json().catch(()=>null);if(s.status===200&&typeof o?.dev_token==="string"){return{ok:true,token:o.dev_token,tier:typeof o.tier==="string"?o.tier:"free"}}return{ok:false,detail:typeof o?.error_description==="string"?o.error_description:"buoy.gg did not make a dev token."}}catch{return{ok:false,detail:"Buoy could not be reached. Check your connection and try again."}}},checkAvailability:p,async isAvailable(){return(await p()).state==="enabled"},subscribe:t=>a.subscribe(t)}}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */const SERVICE_KEY_PREFIX=exports.SERVICE_KEY_PREFIX="bsk1_";const SERVICE_AUDIENCE=exports.SERVICE_AUDIENCE="service";const CALL_TIMEOUT_MS=15e3;function isServiceKey(o){return o.startsWith(SERVICE_KEY_PREFIX)}function normalizeLicenseKey(o){const e=o.trim();return isServiceKey(e)||(0,_sessionToken.isSessionToken)(e)?e:e.toUpperCase()}function sameLicenseKey(o,e){return normalizeLicenseKey(o??"")===normalizeLicenseKey(e??"")}async function exchangeServiceKey(o,e){const c=e.fetch??((r,l)=>fetch(r,l));const n=typeof AbortController!=="undefined"?new AbortController:void 0;const a=setTimeout(()=>n?.abort(),CALL_TIMEOUT_MS);let s;let t;try{const r=await c(`${e.origin.replace(/\/$/,"")}/api/auth/service-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:o}),signal:n?.signal});s=r.status;t=await r.json().catch(()=>null)}catch{return{ok:false,reason:"network",detail:"Buoy could not be reached to check the bot key."}}finally{clearTimeout(a)}if(s>=500||s===429)return{ok:false,reason:"network",detail:"Buoy is busy. The bot key will be checked again soon."};if(s!==200||typeof t?.access_token!=="string"){return{ok:false,reason:"rejected",detail:typeof t?.error_description==="string"?t.error_description:"This bot key was not accepted."}}const i=(0,_sessionToken.verifySessionToken)(t.access_token,{audience:SERVICE_AUDIENCE,nowMs:(0,_realNow.realNow)(),publicKeyHex:e.publicKeyHex});return i.ok?{ok:true,claims:i.claims}:{ok:false,reason:"rejected",detail:"Buoy sent a token this app could not check."}}
6
+ */const SERVICE_KEY_PREFIX=exports.SERVICE_KEY_PREFIX="bsk1_";const SERVICE_AUDIENCE=exports.SERVICE_AUDIENCE="service";const CALL_TIMEOUT_MS=15e3;function isServiceKey(o){return o.startsWith(SERVICE_KEY_PREFIX)}function normalizeLicenseKey(o){const e=o.trim();return isServiceKey(e)||(0,_sessionToken.isSessionToken)(e)?e:e.toUpperCase()}function sameLicenseKey(o,e){return normalizeLicenseKey(o??"")===normalizeLicenseKey(e??"")}async function exchangeServiceKey(o,e){const c=e.fetch??((r,l)=>fetch(r,l));const n=typeof AbortController!=="undefined"?new AbortController:void 0;const a=setTimeout(()=>n?.abort(),CALL_TIMEOUT_MS);let s;let t;try{const r=await c(`${e.origin.replace(/\/$/,"")}/api/auth/service-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:o}),signal:n?.signal});s=r.status;t=await r.json().catch(()=>null)}catch{return{ok:false,reason:"network",detail:"Buoy could not be reached to check the bot key."}}finally{clearTimeout(a)}if(s>=500||s===429)return{ok:false,reason:"network",detail:"Buoy is busy. The bot key will be checked again soon."};if(s!==200||typeof t?.access_token!=="string"){return{ok:false,reason:"rejected",detail:typeof t?.error_description==="string"?t.error_description:"This bot key was not accepted."}}const i=(0,_sessionToken.verifySessionToken)(t.access_token,{audience:SERVICE_AUDIENCE,nowMs:(0,_realNow.realNow)()});return i.ok?{ok:true,claims:i.claims}:{ok:false,reason:"rejected",detail:"Buoy sent a token this app could not check."}}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */const SESSION_STORAGE_PREFIX=exports.SESSION_STORAGE_PREFIX="@buoy/session:";const SESSION_OFFLINE_GRACE_MS=exports.SESSION_OFFLINE_GRACE_MS=7*24*60*60*1e3;const SESSION_REFRESH_LEAD_MS=exports.SESSION_REFRESH_LEAD_MS=6*60*60*1e3;const SESSION_RETRY_MS=exports.SESSION_RETRY_MS=5*60*1e3;const SESSION_CALL_TIMEOUT_MS=exports.SESSION_CALL_TIMEOUT_MS=15e3;const DEFAULT_SIGNIN_ORIGIN=exports.DEFAULT_SIGNIN_ORIGIN="https://buoy.gg";const MESSAGE_TYPE="buoy:signin";const POPUP_TIMEOUT_MS=10*60*1e3;class SessionError extends Error{constructor(e,t){super(t);this.code=e;this.name="SessionError"}}exports.SessionError=SessionError;function browserDeps(){const o=globalThis;return{fetch:(e,t)=>fetch(e,t),storage:_storage.getLicenseStorage,now:_realNow.realNow,random:e=>{const t=new Uint8Array(e);if(!o.crypto?.getRandomValues)throw new SessionError("not_configured","This platform has no secure random source.");return o.crypto.getRandomValues(t)},sha256:async e=>{if(!o.crypto?.subtle)throw new SessionError("not_configured","Sign-in needs a secure page (https or localhost).");return new Uint8Array(await o.crypto.subtle.digest("SHA-256",e))},openPopup:()=>{if(!o.window?.open)return null;const e=480;const t=640;const i=Math.max(0,(o.window.screenX??0)+((o.window.outerWidth??e)-e)/2);const r=Math.max(0,(o.window.screenY??0)+((o.window.outerHeight??t)-t)/2);return o.window.open("about:blank","buoy-signin",`popup,width=${e},height=${t},left=${i},top=${r}`)},onMessage:e=>{if(!o.window?.addEventListener)return()=>{};const t=i=>e({origin:i.origin,data:i.data});o.window.addEventListener("message",t);return()=>o.window?.removeEventListener("message",t)},withLock:(e,t)=>o.navigator?.locks?o.navigator.locks.request(e,t):t(),watch:e=>{const t=o.window;if(!t?.addEventListener)return()=>{};const i=n=>e.storage(n.key);const r=()=>{if(t.document?.visibilityState!=="hidden")e.wake()};t.addEventListener("storage",i);t.addEventListener("online",e.wake);t.document?.addEventListener?.("visibilitychange",r);return()=>{t.removeEventListener("storage",i);t.removeEventListener("online",e.wake);t.document?.removeEventListener?.("visibilitychange",r)}},setTimer:(e,t)=>setTimeout(e,Math.min(t,2147483647)),clearTimer:e=>clearTimeout(e)}}function defaultAudience(){const o=globalThis.location;if(!o?.origin||!/^https?:$/.test(o.protocol??""))return void 0;return o.origin}class SessionManagerImpl{signinOrigin=DEFAULT_SIGNIN_ORIGIN;current=null;claims=null;listeners=new Set;timer=null;refreshing=null;loaded=null;unwatch=null;limitTimer=null;epoch=0;constructor(e){this.deps=e??browserDeps();this.audience=defaultAudience()}get origin(){return this.signinOrigin}configure(e){if(e.audience!==void 0)this.audience=e.audience;if(e.signinOrigin!==void 0)this.signinOrigin=e.signinOrigin.replace(/\/$/,"");this.reset()}__setDeps(e){this.deps=e;this.reset()}reset(){this.unwatch?.();this.unwatch=null;this.epoch+=1;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;this.current=null;this.claims=null;this.loaded=null;this.refreshing=null}get storageKey(){return SESSION_STORAGE_PREFIX+(this.audience??"")}subscribe(e){this.listeners.add(e);return()=>this.listeners.delete(e)}notify(){for(const e of[...this.listeners]){try{e()}catch(t){console.warn("[Buoy] sign-in listener error:",t)}}}getAccessToken(){const e=this.getStatus();return e.state==="active"&&!e.grace?this.current?.accessToken??null:null}getStatus(){const e=this.claims;if(!e)return{state:"signed_out"};const t=e.exp*1e3;const i=this.deps.now();if(i<(e.iat-_sessionToken.SESSION_CLOCK_SKEW_SECONDS)*1e3)return{state:"signed_out"};if(i<t)return{state:"active",claims:e,grace:false,validUntil:t};if(i<t+SESSION_OFFLINE_GRACE_MS){return{state:"active",claims:e,grace:true,validUntil:t+SESSION_OFFLINE_GRACE_MS}}return{state:"signed_out"}}load(){if(!this.loaded)this.loaded=this.loadOnce();return this.loaded}async loadOnce(){if(!this.audience)return;this.unwatch??=this.deps.watch?.({storage:t=>{if(t===null||t===this.storageKey)void this.sync()},wake:()=>{if(this.claims)void this.refresh()}})??null;const e=await this.read();if(e&&this.adopt(e)){this.notify();this.schedule()}}async sync(){if(!this.audience)return;const e=await this.read();if(!e){if(this.current)this.clearLocal();return}if(e.refreshToken!==this.current?.refreshToken&&this.adopt(e)){this.notify();this.schedule()}}async read(){try{const e=await(await this.deps.storage()).getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t?.v===1&&typeof t.accessToken==="string"&&typeof t.refreshToken==="string"?t:null}catch{return null}}async write(e){const t=await this.deps.storage();if(e)await t.setItem(this.storageKey,JSON.stringify(e));else await t.removeItem(this.storageKey)}adopt(e){if(!this.audience)return false;const t=(0,_sessionToken.verifySessionToken)(e.accessToken,{audience:this.audience,ignoreTime:true,publicKeyHex:this.deps.publicKeyHex});const i=t.ok?t.claims:null;if(!i)return false;this.current=e;this.claims=i;return true}armLimit(){if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(!this.claims)return;const e=this.claims.exp*1e3;const t=this.deps.now();const i=t<e?e:t<e+SESSION_OFFLINE_GRACE_MS?e+SESSION_OFFLINE_GRACE_MS:null;if(i===null)return;this.limitTimer=this.deps.setTimer(()=>{this.limitTimer=null;this.notify();this.armLimit()},i-t)}call(e,t){return new Promise((i,r)=>{const n=this.deps.setTimer(()=>r(new Error("timeout")),SESSION_CALL_TIMEOUT_MS);this.deps.fetch(e,t).then(s=>{this.deps.clearTimer(n);i(s)},s=>{this.deps.clearTimer(n);r(s)})})}schedule(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(!this.claims)return;const e=this.claims.exp*1e3-SESSION_REFRESH_LEAD_MS-this.deps.now();this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh()},Math.max(0,e))}refresh(e=false){if(!this.refreshing){this.refreshing=this.deps.withLock(this.lockName,()=>this.refreshLocked(e)).catch(()=>this.retryLater()).finally(()=>{this.refreshing=null})}return this.refreshing}get lockName(){return`buoy-session:${this.audience??""}`}async refreshLocked(e){const t=this.epoch;const i=await this.read();if(!i){if(this.current)this.clearLocal();return}if(i.refreshToken!==this.current?.refreshToken){if(this.adopt(i)){this.notify();this.schedule();return}}if(!this.claims)return;if(!e&&this.claims.exp*1e3-this.deps.now()>SESSION_REFRESH_LEAD_MS){this.schedule();return}let r;let n;try{const s=await this.call(`${this.signinOrigin}/api/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:i.refreshToken,audience:this.audience})});r=s.status;n=await s.json().catch(()=>null)}catch{this.retryLater();return}if(t!==this.epoch)return;if(r===200&&n&&typeof n.access_token==="string"&&typeof n.refresh_token==="string"){const s={v:1,accessToken:n.access_token,refreshToken:n.refresh_token};if(this.adopt(s)){await this.write(s);this.notify();this.schedule();return}}if(r===400||r===401||r===403){await this.write(null);this.clearLocal();return}this.retryLater()}retryLater(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh(true)},SESSION_RETRY_MS);this.notify()}clearLocal(){if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;this.current=null;this.claims=null;this.notify()}async signIn(){if(!this.audience)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const e=this.deps.openPopup();if(!e)throw new SessionError("popup_blocked","The browser blocked the sign-in window. Allow pop-ups for this site and try again.");try{return await this.signInWith((t,i)=>new Promise((r,n)=>{e.location.href=t;const s=this.deps.now();let l=null;const h=u=>{if(l!==null)this.deps.clearTimer(l);a();u()};const a=this.deps.onMessage(u=>{if(u.origin!==this.signinOrigin)return;const d=u.data;if(!d||d.type!==MESSAGE_TYPE||d.state!==i)return;if(typeof d.code==="string")h(()=>r(d.code));else h(()=>n(new SessionError("access_denied","Sign-in was cancelled.")))});const c=()=>{if(e.closed)return h(()=>n(new SessionError("popup_closed","The sign-in window was closed.")));if(this.deps.now()-s>POPUP_TIMEOUT_MS)return h(()=>n(new SessionError("timeout","Sign-in took too long.")));l=this.deps.setTimer(c,500)};l=this.deps.setTimer(c,500)}))}finally{try{if(!e.closed)e.close()}catch{}}}async signInWith(e){const t=this.audience;if(!t)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const i=(0,_sessionToken.base64urlEncode)(this.deps.random(32));const r=(0,_sessionToken.base64urlEncode)(this.deps.random(16));const n=(0,_sessionToken.base64urlEncode)(await this.deps.sha256(new TextEncoder().encode(i)));const s=`${this.signinOrigin}/auth/authorize?audience=${encodeURIComponent(t)}&code_challenge=${n}&code_challenge_method=S256&state=${r}`;const l=await e(s,r);let h;try{h=await this.call(`${this.signinOrigin}/api/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:l,code_verifier:i,audience:t})})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const a=await h.json().catch(()=>null);if(h.status!==200||!a||typeof a.access_token!=="string"||typeof a.refresh_token!=="string"){const c=a&&typeof a.error_description==="string"?a.error_description:"Buoy did not accept this sign-in.";throw new SessionError(h.status===503?"unavailable":"rejected",c)}return this.finishSignIn(a.access_token,a.refresh_token)}async finishSignIn(e,t){const i={v:1,accessToken:e,refreshToken:t};this.epoch+=1;if(!this.adopt(i))throw new SessionError("rejected","Buoy sent a sign-in this app could not check.");await this.write(i);await this.load();this.notify();this.schedule();return this.getStatus()}async signInWithCode(e,t={}){const i=this.audience;if(!i)throw new SessionError("not_configured","Sign-in with a code needs this app's id (app:com.example.app).");const r=(a,c)=>this.call(`${this.signinOrigin}/api/auth/device/${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});let n;try{n=await r("start",{audience:i})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const s=await n.json().catch(()=>null);if(n.status!==200||!s||typeof s.device_code!=="string"||typeof s.user_code!=="string"||typeof s.verification_uri!=="string"||typeof s.verification_uri_complete!=="string"){const a=s&&typeof s.error_description==="string"?s.error_description:"Buoy could not start a sign-in.";throw new SessionError(n.status===503?"unavailable":"rejected",a)}const l=this.deps.now()+(Number(s.expires_in)||600)*1e3;let h=Math.max(5,Number(s.interval)||5)*1e3;e({userCode:s.user_code,verificationUri:s.verification_uri,verificationUriComplete:s.verification_uri_complete,expiresAt:l});for(;;){await this.wait(h,t.signal);if(this.deps.now()>l)throw new SessionError("timeout","The code ran out. Start again for a new one.");let a;try{a=await r("poll",{device_code:s.device_code})}catch{continue}const c=await a.json().catch(()=>null);if(a.status===200&&c&&typeof c.access_token==="string"&&typeof c.refresh_token==="string"){return this.finishSignIn(c.access_token,c.refresh_token)}const u=c&&typeof c.error==="string"?c.error:"";if(u==="authorization_pending"||a.status>=500)continue;if(u==="slow_down"||a.status===429){h+=5e3;continue}if(u==="access_denied")throw new SessionError("access_denied","The sign-in was turned down on buoy.gg.");if(u==="expired_token")throw new SessionError("timeout","The code ran out. Start again for a new one.");const d=c&&typeof c.error_description==="string"?c.error_description:"Buoy did not accept this sign-in.";throw new SessionError("rejected",d)}}wait(e,t){return new Promise((i,r)=>{const n=()=>new SessionError("access_denied","Sign-in was cancelled.");if(t?.aborted)return r(n());const s=()=>{this.deps.clearTimer(l);r(n())};const l=this.deps.setTimer(()=>{t?.removeEventListener?.("abort",s);i()},e);t?.addEventListener?.("abort",s)})}async signOut(){this.epoch+=1;const e=this.current;this.clearLocal();let t=e;try{await this.deps.withLock(this.lockName,async()=>{t=await this.read()??e;await this.write(null)})}catch{await this.write(null).catch(()=>{})}if(!t)return;try{await this.call(`${this.signinOrigin}/api/auth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:t.refreshToken})})}catch{}}}exports.SessionManagerImpl=SessionManagerImpl;const SessionManager=exports.SessionManager=new SessionManagerImpl;
6
+ */const SESSION_STORAGE_PREFIX=exports.SESSION_STORAGE_PREFIX="@buoy/session:";const SESSION_OFFLINE_GRACE_MS=exports.SESSION_OFFLINE_GRACE_MS=7*24*60*60*1e3;const SESSION_REFRESH_LEAD_MS=exports.SESSION_REFRESH_LEAD_MS=6*60*60*1e3;const SESSION_RETRY_MS=exports.SESSION_RETRY_MS=5*60*1e3;const SESSION_CALL_TIMEOUT_MS=exports.SESSION_CALL_TIMEOUT_MS=15e3;const DEFAULT_SIGNIN_ORIGIN=exports.DEFAULT_SIGNIN_ORIGIN="https://buoy.gg";const MESSAGE_TYPE="buoy:signin";const POPUP_TIMEOUT_MS=10*60*1e3;class SessionError extends Error{constructor(e,t){super(t);this.code=e;this.name="SessionError"}}exports.SessionError=SessionError;function browserDeps(){const o=globalThis;return{fetch:(e,t)=>fetch(e,t),storage:_storage.getLicenseStorage,now:_realNow.realNow,random:e=>{const t=new Uint8Array(e);if(!o.crypto?.getRandomValues)throw new SessionError("not_configured","This platform has no secure random source.");return o.crypto.getRandomValues(t)},sha256:async e=>{if(!o.crypto?.subtle)throw new SessionError("not_configured","Sign-in needs a secure page (https or localhost).");return new Uint8Array(await o.crypto.subtle.digest("SHA-256",e))},openPopup:()=>{if(!o.window?.open)return null;const e=480;const t=640;const i=Math.max(0,(o.window.screenX??0)+((o.window.outerWidth??e)-e)/2);const r=Math.max(0,(o.window.screenY??0)+((o.window.outerHeight??t)-t)/2);return o.window.open("about:blank","buoy-signin",`popup,width=${e},height=${t},left=${i},top=${r}`)},onMessage:e=>{if(!o.window?.addEventListener)return()=>{};const t=i=>e({origin:i.origin,data:i.data});o.window.addEventListener("message",t);return()=>o.window?.removeEventListener("message",t)},withLock:(e,t)=>o.navigator?.locks?o.navigator.locks.request(e,t):t(),watch:e=>{const t=o.window;if(!t?.addEventListener)return()=>{};const i=n=>e.storage(n.key);const r=()=>{if(t.document?.visibilityState!=="hidden")e.wake()};t.addEventListener("storage",i);t.addEventListener("online",e.wake);t.document?.addEventListener?.("visibilitychange",r);return()=>{t.removeEventListener("storage",i);t.removeEventListener("online",e.wake);t.document?.removeEventListener?.("visibilitychange",r)}},setTimer:(e,t)=>setTimeout(e,Math.min(t,2147483647)),clearTimer:e=>clearTimeout(e)}}function defaultAudience(){const o=globalThis.location;if(!o?.origin||!/^https?:$/.test(o.protocol??""))return void 0;return o.origin}class SessionManagerImpl{signinOrigin=DEFAULT_SIGNIN_ORIGIN;current=null;claims=null;listeners=new Set;timer=null;refreshing=null;loaded=null;unwatch=null;limitTimer=null;epoch=0;constructor(e){this.deps=e??browserDeps();this.audience=defaultAudience()}get origin(){return this.signinOrigin}configure(e){if(e.audience!==void 0)this.audience=e.audience;if(e.signinOrigin!==void 0)this.signinOrigin=e.signinOrigin.replace(/\/$/,"");this.reset()}reset(){this.unwatch?.();this.unwatch=null;this.epoch+=1;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;this.current=null;this.claims=null;this.loaded=null;this.refreshing=null}get storageKey(){return SESSION_STORAGE_PREFIX+(this.audience??"")}subscribe(e){this.listeners.add(e);return()=>this.listeners.delete(e)}notify(){for(const e of[...this.listeners]){try{e()}catch(t){console.warn("[Buoy] sign-in listener error:",t)}}}getAccessToken(){const e=this.getStatus();return e.state==="active"&&!e.grace?this.current?.accessToken??null:null}getStatus(){const e=this.claims;if(!e)return{state:"signed_out"};const t=e.exp*1e3;const i=this.deps.now();if(i<(e.iat-_sessionToken.SESSION_CLOCK_SKEW_SECONDS)*1e3)return{state:"signed_out"};if(i<t)return{state:"active",claims:e,grace:false,validUntil:t};if(i<t+SESSION_OFFLINE_GRACE_MS){return{state:"active",claims:e,grace:true,validUntil:t+SESSION_OFFLINE_GRACE_MS}}return{state:"signed_out"}}load(){if(!this.loaded)this.loaded=this.loadOnce();return this.loaded}async loadOnce(){if(!this.audience)return;this.unwatch??=this.deps.watch?.({storage:t=>{if(t===null||t===this.storageKey)void this.sync()},wake:()=>{if(this.claims)void this.refresh()}})??null;const e=await this.read();if(e&&this.adopt(e)){this.notify();this.schedule()}}async sync(){if(!this.audience)return;const e=await this.read();if(!e){if(this.current)this.clearLocal();return}if(e.refreshToken!==this.current?.refreshToken&&this.adopt(e)){this.notify();this.schedule()}}async read(){try{const e=await(await this.deps.storage()).getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t?.v===1&&typeof t.accessToken==="string"&&typeof t.refreshToken==="string"?t:null}catch{return null}}async write(e){const t=await this.deps.storage();if(e)await t.setItem(this.storageKey,JSON.stringify(e));else await t.removeItem(this.storageKey)}adopt(e){if(!this.audience)return false;const t=(0,_sessionToken.verifySessionToken)(e.accessToken,{audience:this.audience,ignoreTime:true});const i=t.ok?t.claims:null;if(!i)return false;this.current=e;this.claims=i;return true}armLimit(){if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(!this.claims)return;const e=this.claims.exp*1e3;const t=this.deps.now();const i=t<e?e:t<e+SESSION_OFFLINE_GRACE_MS?e+SESSION_OFFLINE_GRACE_MS:null;if(i===null)return;this.limitTimer=this.deps.setTimer(()=>{this.limitTimer=null;this.notify();this.armLimit()},i-t)}call(e,t){return new Promise((i,r)=>{const n=this.deps.setTimer(()=>r(new Error("timeout")),SESSION_CALL_TIMEOUT_MS);this.deps.fetch(e,t).then(s=>{this.deps.clearTimer(n);i(s)},s=>{this.deps.clearTimer(n);r(s)})})}schedule(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(!this.claims)return;const e=this.claims.exp*1e3-SESSION_REFRESH_LEAD_MS-this.deps.now();this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh()},Math.max(0,e))}refresh(e=false){if(!this.refreshing){this.refreshing=this.deps.withLock(this.lockName,()=>this.refreshLocked(e)).catch(()=>this.retryLater()).finally(()=>{this.refreshing=null})}return this.refreshing}get lockName(){return`buoy-session:${this.audience??""}`}async refreshLocked(e){const t=this.epoch;const i=await this.read();if(!i){if(this.current)this.clearLocal();return}if(i.refreshToken!==this.current?.refreshToken){if(this.adopt(i)){this.notify();this.schedule();return}}if(!this.claims)return;if(!e&&this.claims.exp*1e3-this.deps.now()>SESSION_REFRESH_LEAD_MS){this.schedule();return}let r;let n;try{const s=await this.call(`${this.signinOrigin}/api/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:i.refreshToken,audience:this.audience})});r=s.status;n=await s.json().catch(()=>null)}catch{this.retryLater();return}if(t!==this.epoch)return;if(r===200&&n&&typeof n.access_token==="string"&&typeof n.refresh_token==="string"){const s={v:1,accessToken:n.access_token,refreshToken:n.refresh_token};if(this.adopt(s)){await this.write(s);this.notify();this.schedule();return}}if(r===400||r===401||r===403){await this.write(null);this.clearLocal();return}this.retryLater()}retryLater(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh(true)},SESSION_RETRY_MS);this.notify()}clearLocal(){if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;this.current=null;this.claims=null;this.notify()}async signIn(){if(!this.audience)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const e=this.deps.openPopup();if(!e)throw new SessionError("popup_blocked","The browser blocked the sign-in window. Allow pop-ups for this site and try again.");try{return await this.signInWith((t,i)=>new Promise((r,n)=>{e.location.href=t;const s=this.deps.now();let l=null;const h=u=>{if(l!==null)this.deps.clearTimer(l);a();u()};const a=this.deps.onMessage(u=>{if(u.origin!==this.signinOrigin)return;const d=u.data;if(!d||d.type!==MESSAGE_TYPE||d.state!==i)return;if(typeof d.code==="string")h(()=>r(d.code));else h(()=>n(new SessionError("access_denied","Sign-in was cancelled.")))});const c=()=>{if(e.closed)return h(()=>n(new SessionError("popup_closed","The sign-in window was closed.")));if(this.deps.now()-s>POPUP_TIMEOUT_MS)return h(()=>n(new SessionError("timeout","Sign-in took too long.")));l=this.deps.setTimer(c,500)};l=this.deps.setTimer(c,500)}))}finally{try{if(!e.closed)e.close()}catch{}}}async signInWith(e){const t=this.audience;if(!t)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const i=(0,_sessionToken.base64urlEncode)(this.deps.random(32));const r=(0,_sessionToken.base64urlEncode)(this.deps.random(16));const n=(0,_sessionToken.base64urlEncode)(await this.deps.sha256(new TextEncoder().encode(i)));const s=`${this.signinOrigin}/auth/authorize?audience=${encodeURIComponent(t)}&code_challenge=${n}&code_challenge_method=S256&state=${r}`;const l=await e(s,r);let h;try{h=await this.call(`${this.signinOrigin}/api/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:l,code_verifier:i,audience:t})})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const a=await h.json().catch(()=>null);if(h.status!==200||!a||typeof a.access_token!=="string"||typeof a.refresh_token!=="string"){const c=a&&typeof a.error_description==="string"?a.error_description:"Buoy did not accept this sign-in.";throw new SessionError(h.status===503?"unavailable":"rejected",c)}return this.finishSignIn(a.access_token,a.refresh_token)}async finishSignIn(e,t){const i={v:1,accessToken:e,refreshToken:t};this.epoch+=1;if(!this.adopt(i))throw new SessionError("rejected","Buoy sent a sign-in this app could not check.");await this.write(i);await this.load();this.notify();this.schedule();return this.getStatus()}async signInWithCode(e,t={}){const i=this.audience;if(!i)throw new SessionError("not_configured","Sign-in with a code needs this app's id (app:com.example.app).");const r=(a,c)=>this.call(`${this.signinOrigin}/api/auth/device/${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});let n;try{n=await r("start",{audience:i})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const s=await n.json().catch(()=>null);if(n.status!==200||!s||typeof s.device_code!=="string"||typeof s.user_code!=="string"||typeof s.verification_uri!=="string"||typeof s.verification_uri_complete!=="string"){const a=s&&typeof s.error_description==="string"?s.error_description:"Buoy could not start a sign-in.";throw new SessionError(n.status===503?"unavailable":"rejected",a)}const l=this.deps.now()+(Number(s.expires_in)||600)*1e3;let h=Math.max(5,Number(s.interval)||5)*1e3;e({userCode:s.user_code,verificationUri:s.verification_uri,verificationUriComplete:s.verification_uri_complete,expiresAt:l});for(;;){await this.wait(h,t.signal);if(this.deps.now()>l)throw new SessionError("timeout","The code ran out. Start again for a new one.");let a;try{a=await r("poll",{device_code:s.device_code})}catch{continue}const c=await a.json().catch(()=>null);if(a.status===200&&c&&typeof c.access_token==="string"&&typeof c.refresh_token==="string"){return this.finishSignIn(c.access_token,c.refresh_token)}const u=c&&typeof c.error==="string"?c.error:"";if(u==="authorization_pending"||a.status>=500)continue;if(u==="slow_down"||a.status===429){h+=5e3;continue}if(u==="access_denied")throw new SessionError("access_denied","The sign-in was turned down on buoy.gg.");if(u==="expired_token")throw new SessionError("timeout","The code ran out. Start again for a new one.");const d=c&&typeof c.error_description==="string"?c.error_description:"Buoy did not accept this sign-in.";throw new SessionError("rejected",d)}}wait(e,t){return new Promise((i,r)=>{const n=()=>new SessionError("access_denied","Sign-in was cancelled.");if(t?.aborted)return r(n());const s=()=>{this.deps.clearTimer(l);r(n())};const l=this.deps.setTimer(()=>{t?.removeEventListener?.("abort",s);i()},e);t?.addEventListener?.("abort",s)})}async signOut(){this.epoch+=1;const e=this.current;this.clearLocal();let t=e;try{await this.deps.withLock(this.lockName,async()=>{t=await this.read()??e;await this.write(null)})}catch{await this.write(null).catch(()=>{})}if(!t)return;try{await this.call(`${this.signinOrigin}/api/auth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:t.refreshToken})})}catch{}}}exports.SessionManagerImpl=SessionManagerImpl;const SessionManager=exports.SessionManager=new SessionManagerImpl;
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SESSION_TOKEN_PREFIX=exports.SESSION_CLOCK_SKEW_SECONDS=void 0;exports.__setSessionTokenPublicKeyForTests=__setSessionTokenPublicKeyForTests;exports.base64urlEncode=base64urlEncode;exports.isSessionToken=isSessionToken;exports.mintSessionToken=mintSessionToken;exports.verifySessionToken=verifySessionToken;var _tweetnacl=_interopRequireDefault(require("tweetnacl"));var _config=require("./config.js");var _realNow=require("./realNow.js");function _interopRequireDefault(t){return t&&t.__esModule?t:{default:t}}/*!
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SESSION_TOKEN_PREFIX=exports.SESSION_CLOCK_SKEW_SECONDS=void 0;exports.base64urlEncode=base64urlEncode;exports.isSessionToken=isSessionToken;exports.mintSessionToken=mintSessionToken;exports.verifySessionToken=verifySessionToken;var _tweetnacl=_interopRequireDefault(require("tweetnacl"));var _sessionTokenKey=require("./sessionTokenKey.js");var _realNow=require("./realNow.js");function _interopRequireDefault(t){return t&&t.__esModule?t:{default:t}}/*!
2
2
  * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */const SESSION_TOKEN_PREFIX=exports.SESSION_TOKEN_PREFIX="buoys1";const SESSION_TOKEN_DOMAIN="buoy-session-v1:";const SESSION_TOKEN_VERSION=1;const SESSION_CLOCK_SKEW_SECONDS=exports.SESSION_CLOCK_SKEW_SECONDS=60;const SIGNATURE_LENGTH=64;const TIERS=["free","pro","business"];const B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function base64urlEncode(t){let e="";let r=0;for(;r+2<t.length;r+=3){const n=t[r]<<16|t[r+1]<<8|t[r+2];e+=B64[n>>>18&63]+B64[n>>>12&63]+B64[n>>>6&63]+B64[n&63]}const o=t.length-r;if(o===1){const n=t[r]<<16;e+=B64[n>>>18&63]+B64[n>>>12&63]}else if(o===2){const n=t[r]<<16|t[r+1]<<8;e+=B64[n>>>18&63]+B64[n>>>12&63]+B64[n>>>6&63]}return e}function base64urlDecode(t){if(!/^[A-Za-z0-9_-]*$/.test(t)||t.length%4===1)return null;const e=[];let r=0;let o=0;for(const n of t){o=o<<6|B64.indexOf(n);r+=6;if(r>=8){e.push(o>>>r-8&255);r-=8}}return new Uint8Array(e)}function utf8Encode(t){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(t);const e=unescape(encodeURIComponent(t));const r=new Uint8Array(e.length);for(let o=0;o<e.length;o+=1)r[o]=e.charCodeAt(o);return r}function utf8Decode(t){try{if(typeof TextDecoder!=="undefined")return new TextDecoder("utf-8",{fatal:true}).decode(t);let e="";for(const r of t)e+=String.fromCharCode(r);return decodeURIComponent(escape(e))}catch{return null}}function hexToBytes(t){const e=t.trim().toLowerCase();const r=new Uint8Array(e.length/2);for(let o=0;o<r.length;o+=1)r[o]=parseInt(e.slice(o*2,o*2+2),16);return r}function signedMessage(t){return utf8Encode(SESSION_TOKEN_DOMAIN+t)}function isShortString(t,e=256){return typeof t==="string"&&t.length>0&&t.length<=e}function isSeconds(t){return typeof t==="number"&&Number.isInteger(t)&&t>0}function readClaims(t){if(!t||typeof t!=="object"||Array.isArray(t))return null;const e=t;if(!isShortString(e.sid)||!isShortString(e.sub)||!isShortString(e.aud,512))return null;if(e.team!==null&&!isShortString(e.team))return null;if(!TIERS.includes(e.tier))return null;if(e.role!==void 0&&!isShortString(e.role,64))return null;if(e.tools!==void 0&&(!Array.isArray(e.tools)||e.tools.length>256||!e.tools.every(r=>isShortString(r,64)))){return null}if(!isSeconds(e.iat)||!isSeconds(e.exp)||e.exp<=e.iat)return null;return{v:SESSION_TOKEN_VERSION,sid:e.sid,sub:e.sub,team:e.team,tier:e.tier,...e.role!==void 0?{role:e.role}:{},...e.tools!==void 0?{tools:[...e.tools]}:{},aud:e.aud,iat:e.iat,exp:e.exp}}function mintSessionToken(t,e){const r=base64urlEncode(utf8Encode(JSON.stringify(t)));const{secretKey:o}=_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(e));const n=_tweetnacl.default.sign.detached(signedMessage(r),o);return`${SESSION_TOKEN_PREFIX}.${r}.${base64urlEncode(n)}`}let activePublicKey=_config.SESSION_TOKEN_PUBLIC_KEY;function __setSessionTokenPublicKeyForTests(t){activePublicKey=t??_config.SESSION_TOKEN_PUBLIC_KEY}function isSessionToken(t){return t.startsWith(`${SESSION_TOKEN_PREFIX}.`)}function verifySessionToken(t,e){const r=e.publicKeyHex??activePublicKey;if(!r)return{ok:false,reason:"no-key"};const o=typeof t==="string"?t.split("."):[];if(o.length!==3||o[0]!==SESSION_TOKEN_PREFIX)return{ok:false,reason:"malformed"};const[,n,f]=o;const l=base64urlDecode(n);const u=base64urlDecode(f);if(!l||!u||u.length!==SIGNATURE_LENGTH)return{ok:false,reason:"malformed"};try{if(!_tweetnacl.default.sign.detached.verify(signedMessage(n),u,hexToBytes(r))){return{ok:false,reason:"signature"}}}catch{return{ok:false,reason:"signature"}}const a=utf8Decode(l);let s;try{s=a===null?null:JSON.parse(a)}catch{return{ok:false,reason:"malformed"}}if(!s||typeof s!=="object"||s.v!==SESSION_TOKEN_VERSION){return{ok:false,reason:s&&typeof s==="object"?"version":"malformed"}}const i=readClaims(s);if(!i)return{ok:false,reason:"claims"};if(i.aud!==e.audience)return{ok:false,reason:"audience"};if(e.ignoreTime)return{ok:true,claims:i};const c=Math.floor((e.nowMs??(0,_realNow.realNow)())/1e3);if(c>=i.exp+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"expired"};if(i.iat>c+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"not-yet-valid"};return{ok:true,claims:i}}
6
+ */const SESSION_TOKEN_PREFIX=exports.SESSION_TOKEN_PREFIX="buoys1";const SESSION_TOKEN_DOMAIN="buoy-session-v1:";const SESSION_TOKEN_VERSION=1;const SESSION_CLOCK_SKEW_SECONDS=exports.SESSION_CLOCK_SKEW_SECONDS=60;const SIGNATURE_LENGTH=64;const TIERS=["free","pro","business"];const B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";function base64urlEncode(t){let e="";let r=0;for(;r+2<t.length;r+=3){const n=t[r]<<16|t[r+1]<<8|t[r+2];e+=B64[n>>>18&63]+B64[n>>>12&63]+B64[n>>>6&63]+B64[n&63]}const o=t.length-r;if(o===1){const n=t[r]<<16;e+=B64[n>>>18&63]+B64[n>>>12&63]}else if(o===2){const n=t[r]<<16|t[r+1]<<8;e+=B64[n>>>18&63]+B64[n>>>12&63]+B64[n>>>6&63]}return e}function base64urlDecode(t){if(!/^[A-Za-z0-9_-]*$/.test(t)||t.length%4===1)return null;const e=[];let r=0;let o=0;for(const n of t){o=o<<6|B64.indexOf(n);r+=6;if(r>=8){e.push(o>>>r-8&255);r-=8}}return new Uint8Array(e)}function utf8Encode(t){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(t);const e=unescape(encodeURIComponent(t));const r=new Uint8Array(e.length);for(let o=0;o<e.length;o+=1)r[o]=e.charCodeAt(o);return r}function utf8Decode(t){try{if(typeof TextDecoder!=="undefined")return new TextDecoder("utf-8",{fatal:true}).decode(t);let e="";for(const r of t)e+=String.fromCharCode(r);return decodeURIComponent(escape(e))}catch{return null}}function hexToBytes(t){const e=t.trim().toLowerCase();const r=new Uint8Array(e.length/2);for(let o=0;o<r.length;o+=1)r[o]=parseInt(e.slice(o*2,o*2+2),16);return r}function signedMessage(t){return utf8Encode(SESSION_TOKEN_DOMAIN+t)}function isShortString(t,e=256){return typeof t==="string"&&t.length>0&&t.length<=e}function isSeconds(t){return typeof t==="number"&&Number.isInteger(t)&&t>0}function readClaims(t){if(!t||typeof t!=="object"||Array.isArray(t))return null;const e=t;if(!isShortString(e.sid)||!isShortString(e.sub)||!isShortString(e.aud,512))return null;if(e.team!==null&&!isShortString(e.team))return null;if(!TIERS.includes(e.tier))return null;if(e.role!==void 0&&!isShortString(e.role,64))return null;if(e.tools!==void 0&&(!Array.isArray(e.tools)||e.tools.length>256||!e.tools.every(r=>isShortString(r,64)))){return null}if(!isSeconds(e.iat)||!isSeconds(e.exp)||e.exp<=e.iat)return null;return{v:SESSION_TOKEN_VERSION,sid:e.sid,sub:e.sub,team:e.team,tier:e.tier,...e.role!==void 0?{role:e.role}:{},...e.tools!==void 0?{tools:[...e.tools]}:{},aud:e.aud,iat:e.iat,exp:e.exp}}function mintSessionToken(t,e){const r=base64urlEncode(utf8Encode(JSON.stringify(t)));const{secretKey:o}=_tweetnacl.default.sign.keyPair.fromSeed(hexToBytes(e));const n=_tweetnacl.default.sign.detached(signedMessage(r),o);return`${SESSION_TOKEN_PREFIX}.${r}.${base64urlEncode(n)}`}const verifyingPublicKey=_sessionTokenKey.SESSION_TOKEN_PUBLIC_KEY;function isSessionToken(t){return t.startsWith(`${SESSION_TOKEN_PREFIX}.`)}function verifySessionToken(t,e){const r=verifyingPublicKey;if(!r)return{ok:false,reason:"no-key"};const o=typeof t==="string"?t.split("."):[];if(o.length!==3||o[0]!==SESSION_TOKEN_PREFIX)return{ok:false,reason:"malformed"};const[,n,c]=o;const l=base64urlDecode(n);const u=base64urlDecode(c);if(!l||!u||u.length!==SIGNATURE_LENGTH)return{ok:false,reason:"malformed"};try{if(!_tweetnacl.default.sign.detached.verify(signedMessage(n),u,hexToBytes(r))){return{ok:false,reason:"signature"}}}catch{return{ok:false,reason:"signature"}}const a=utf8Decode(l);let s;try{s=a===null?null:JSON.parse(a)}catch{return{ok:false,reason:"malformed"}}if(!s||typeof s!=="object"||s.v!==SESSION_TOKEN_VERSION){return{ok:false,reason:s&&typeof s==="object"?"version":"malformed"}}const i=readClaims(s);if(!i)return{ok:false,reason:"claims"};if(i.aud!==e.audience)return{ok:false,reason:"audience"};if(e.ignoreTime)return{ok:true,claims:i};const f=Math.floor((e.nowMs??(0,_realNow.realNow)())/1e3);if(f>=i.exp+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"expired"};if(i.iat>f+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"not-yet-valid"};return{ok:true,claims:i}}
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.SESSION_TOKEN_PUBLIC_KEY=void 0;/*!
2
+ * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
+ *
4
+ * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
+ * (https://buoy.gg/terms), not an OSS license.
6
+ */const SESSION_TOKEN_PUBLIC_KEY=exports.SESSION_TOKEN_PUBLIC_KEY="36abba0267f7f379d992a5b6df641daab4190bcc9e639e36f1378e3c1ac52746";
@@ -1 +1 @@
1
- "use strict";import{isCapacitorNative as A}from"./capacitorHost.js";const $="__BUOY_CAPACITOR_BRIDGE__";const j=300;function k(){const e=globalThis.Capacitor;return e&&typeof e==="object"?e:null}function d(){const e=globalThis;let t=e[$];if(!t||t.version!==1){t={version:1,originalPromise:null,originalCallback:null,wrappedPromise:null,wrappedCallback:null,interceptors:[],listeners:new Map,log:[],subscribers:new Set,seq:0,fakeIds:0};e[$]=t}return t}function y(){const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()}function S(e){return e&&typeof e==="object"?e:{}}function P(e){for(const t of Array.from(e.subscribers)){try{t()}catch{}}}function N(e,t){const n={seq:++e.seq,...t};e.log.push(n);if(e.log.length>j)e.log.splice(0,e.log.length-j);P(e);return n}function R(e,t,n){return e.interceptors.filter(r=>(r.plugin==="*"||r.plugin===t.plugin)&&(!r.methods||r.methods.includes(t.method))&&typeof r[n]==="function").map((r,o)=>({interceptor:r,index:o})).sort((r,o)=>(o.interceptor.order??0)-(r.interceptor.order??0)||r.index-o.index).map(r=>r.interceptor)}function x(e,t){return`${e}:${String(t)}`}export function makeCapacitorCallbackId(){return`buoy-${++d().fakeIds}`}export function installCapacitorBridge(e={}){if(!A())return false;const t=k();if(!t||typeof t.nativePromise!=="function"||typeof t.nativeCallback!=="function")return false;const n=d();if(n.wrappedPromise&&t.nativePromise===n.wrappedPromise&&t.nativeCallback===n.wrappedCallback)return true;if(t.DEBUG!==true&&e.release!==true)return false;n.originalPromise=t.nativePromise;n.originalCallback=t.nativeCallback;const r=n.originalPromise;const o=n.originalCallback;const i=(s,l,h,C)=>{const f={plugin:s,method:l,options:S(h)};const g=R(n,f,"promise");const c=m=>{if(m>=g.length){C();if(l==="removeAllListeners"){for(const v of Array.from(n.listeners.keys()))if(v.startsWith(`${s}:`))n.listeners.delete(v)}return r.call(t,s,l,h)}try{return Promise.resolve(g[m].promise(f,()=>c(m+1)))}catch(v){return Promise.reject(v)}};return c(0)};n.runPromise=i;const a=(s,l,h)=>{const C=N(n,{plugin:s,method:l,kind:"promise",options:S(h),start:y()});let f=false;const g=i(s,l,h,()=>{f=true});g.then(c=>{Object.assign(C,{end:y(),ok:true,result:c,answeredByBuoy:!f});P(n)},c=>{Object.assign(C,{end:y(),ok:false,error:c,answeredByBuoy:!f});P(n)});return g};const p=(s,l,h,C)=>{let f=h;let g=C;if(typeof f==="function"){g=f;f=null}const c={plugin:s,method:l,options:S(f)};const m=N(n,{plugin:s,method:l,kind:"callback",options:c.options,start:y(),events:0});let v=false;const L=R(n,c,"callback");const O=(b,u)=>{if(b>=L.length){v=true;return o.call(t,s,l,f,u)}return L[b].callback(c,u,w=>O(b+1,w))};const E=l==="addListener";const H=(b,u)=>{m.events=(m.events??0)+1;if(!E&&m.end===void 0){m.end=y();m.ok=!u;if(u)m.error=u;else m.result=b;P(n)}else{const w=y();N(n,{plugin:s,method:E?String(c.options.eventName??"event"):l,kind:"event",options:{},start:w,end:w,ok:!u,...u?{error:u}:{result:b}})}g?.(b,u)};const B=O(0,H);m.answeredByBuoy=!v;if(l==="addListener"&&B!=null&&typeof g==="function"){const b=x(s,c.options.eventName);let u=n.listeners.get(b);if(!u)n.listeners.set(b,u=new Map);u.set(String(B),g)}else if(l==="removeListener"){n.listeners.get(x(s,c.options.eventName))?.delete(String(c.options.callbackId))}return B};t.nativePromise=a;t.nativeCallback=p;n.wrappedPromise=a;n.wrappedCallback=p;D();return true}const U=/^\s*\(\s*prefers-color-scheme\s*:\s*(dark|light)\s*\)\s*$/i;const T="__BUOY_COLOR_SCHEME_QUERIES__";export function colorSchemeQueryValue(e){const t=U.exec(e);return t?t[1].toLowerCase():null}function D(){const e=globalThis;const t=globalThis.WeakRef;if(e[T]||typeof e.matchMedia!=="function"||!t)return;const n=[];e[T]=n;const r=e.matchMedia;e.matchMedia=function o(i){const a=r.call(this??globalThis,i);if(a&&colorSchemeQueryValue(String(i))){for(let p=n.length-1;p>=0;p--)if(!n[p].deref())n.splice(p,1);n.push(new t(a))}return a}}export function getColorSchemeQueries(){const e=globalThis[T];if(!e)return[];return e.map(t=>t.deref()).filter(t=>!!t)}export function isCapacitorBridgeInstalled(){const e=k();const t=d();return Boolean(t.wrappedPromise&&e?.nativePromise===t.wrappedPromise)}export function interceptCapacitor(e){const t=d();t.interceptors.push(e);return()=>{const n=t.interceptors.indexOf(e);if(n>=0)t.interceptors.splice(n,1)}}export function emitCapacitorEvent(e,t,n){const r=d().listeners.get(x(e,t));if(!r)return 0;let o=0;for(const i of Array.from(r.values())){try{i(n);o++}catch(a){globalThis.console?.error(a)}}return o}export function capacitorListenerCount(e,t){return d().listeners.get(x(e,t))?.size??0}function M(e){return k()?.PluginHeaders?.find(t=>t.name===e)}export function hasCapacitorPlugin(e){if(!A())return false;try{return Boolean(M(e))||k()?.isPluginAvailable?.(e)===true}catch{return false}}function I(){const e=k();const t=d();return{cap:e,promise:t.originalPromise??e?.nativePromise??null,callback:t.originalCallback??e?.nativeCallback??null}}export function callCapacitorNative(e,t,n={}){const{cap:r,promise:o}=I();if(!r||!o)return Promise.reject(new Error("Capacitor bridge unavailable"));return o.call(r,e,t,n)}export function callCapacitorAsApp(e,t,n={}){const r=d().runPromise;if(r&&isCapacitorBridgeInstalled())return r(e,t,n,()=>{});return callCapacitorNative(e,t,n)}export function callCapacitorNativeCallback(e,t,n,r){const{cap:o,callback:i}=I();if(!o||!i)return null;return i.call(o,e,t,n,r)}export function listenCapacitorNative(e,t,n){const{cap:r,promise:o,callback:i}=I();if(!r||!i)return Promise.reject(new Error("Capacitor bridge unavailable"));const a=i.call(r,e,"addListener",{eventName:t},s=>n(s));const p=async()=>{if(a==null)return;const s={eventName:t,callbackId:a};const l=M(e)?.methods?.find(h=>h.name==="removeListener")?.rtype;if(l==="promise"&&o)await o.call(r,e,"removeListener",s);else i.call(r,e,"removeListener",s,()=>{})};return Promise.resolve({remove:p})}export function getCapacitorCalls(){return d().log}export function clearCapacitorCalls(){const e=d();e.log.length=0;P(e)}export function subscribeCapacitorCalls(e){const t=d();t.subscribers.add(e);return()=>{t.subscribers.delete(e)}}const Y=new Set(["then","catch","finally","$$typeof","toJSON","constructor"]);export function capacitorPlugin(e){if(!hasCapacitorPlugin(e))return null;return new Proxy({},{get(t,n){if(typeof n!=="string"||Y.has(n))return void 0;if(n==="addListener"){return(r,o)=>listenCapacitorNative(e,r,o)}return r=>callCapacitorNative(e,n,r??{})}})}const _="__BUOY_CAPACITOR_HOST__";export function loadCapacitorAppHost(){if(!A())return Promise.resolve(null);const e=globalThis;const t=e[_];if(t)return t;const n=i=>typeof i==="string"&&i?i:null;const r=async i=>{if(!hasCapacitorPlugin(i))return{};try{return await callCapacitorNative(i,"getInfo")??{}}catch{return{}}};const o=Promise.all([r("App"),r("Device")]).then(([i,a])=>{const p={isSimulator:typeof a.isVirtual==="boolean"?a.isVirtual:null,deviceName:n(a.name),bundleId:n(i.id),appName:n(i.name)};e[`${_}_value`]=p;return p});e[_]=o;return o}export function getCapacitorAppHost(){return globalThis[`${_}_value`]??null}
1
+ "use strict";import{isCapacitorNative as L}from"./capacitorHost.js";const E="__BUOY_CAPACITOR_BRIDGE__";const U=300;function k(){const e=globalThis.Capacitor;return e&&typeof e==="object"?e:null}function m(){const e=globalThis;let t=e[E];if(!t||t.version!==1){t={version:1,originalPromise:null,originalCallback:null,wrappedPromise:null,wrappedCallback:null,interceptors:[],listeners:new Map,log:[],subscribers:new Set,seq:0,fakeIds:0};e[E]=t}return t}function v(){const e=globalThis.__buoyRealNow;return typeof e==="function"?e():Date.now()}function D(e){if(e.clickListenerInstalled||typeof window==="undefined"||typeof window.addEventListener!=="function")return;e.clickListenerInstalled=true;window.addEventListener("click",t=>{let r=t.composedPath?.()[0]??t.target;e.buoyClick=false;while(r){if(r.closest?.("[data-buoy-root], [data-buoy-portal-host]")){e.buoyClick=true;break}r=r.getRootNode?.().host??null}if(e.clickTimer)clearTimeout(e.clickTimer);e.clickTimer=setTimeout(()=>{e.buoyClick=false},0)},true)}function w(e){return e&&typeof e==="object"?e:{}}function M(e,t,r,n){if(t!=="SentryCapacitor"||r!=="addBreadcrumb")return false;const o=w(n);if(o.category==="ui.click")return e.buoyClick===true;if(o.category==="console"&&typeof o.message==="string")return/^\[(?:buoy(?:[^\]]*)?|@buoy-gg\/[^\]]+|RnBetterDevTools|React ?Buoy|RN-BUOY DEBUG|js-top|perf-monitor|impersonate|RenderCause|HighlightUpdates|RenderTracker|ProfilerInterceptor|HighlightPerf|DebugBorders|optional-module|route-events|RouteObserver)\]/i.test(o.message);if(o.category!=="fetch"&&o.category!=="xhr")return false;const i=w(o.data);if(typeof i.url!=="string")return false;try{const a=new URL(i.url,typeof location==="undefined"?"http://localhost":location.href);const c=a.hostname.toLowerCase();if(["api.buoy.gg","ai.buoy.gg","gateway.buoy.gg"].includes(c))return true;if(c==="keygen.sh"||c.endsWith(".keygen.sh"))return true;if(["buoy.gg","www.buoy.gg"].includes(c)&&/^\/api\/(license|settings|auth|session|install|t)(?:\/|$)/.test(a.pathname))return true;if(a.pathname==="/buoy-assets.json")return true;const s=globalThis.__BUOY_INTERNAL_HOSTS__;return s instanceof Set&&[...s].some(l=>typeof l==="string"&&l.toLowerCase()===a.host.toLowerCase())}catch{return false}}function P(e){for(const t of Array.from(e.subscribers)){try{t()}catch{}}}function S(e,t){const r={seq:++e.seq,...t};e.log.push(r);if(e.log.length>U)e.log.splice(0,e.log.length-U);P(e);return r}function $(e,t,r){return e.interceptors.filter(n=>(n.plugin==="*"||n.plugin===t.plugin)&&(!n.methods||n.methods.includes(t.method))&&typeof n[r]==="function").map((n,o)=>({interceptor:n,index:o})).sort((n,o)=>(o.interceptor.order??0)-(n.interceptor.order??0)||n.index-o.index).map(n=>n.interceptor)}function x(e,t){return`${e}:${String(t)}`}export function makeCapacitorCallbackId(){return`buoy-${++m().fakeIds}`}export function installCapacitorBridge(e={}){if(!L())return false;const t=k();if(!t||typeof t.nativePromise!=="function"||typeof t.nativeCallback!=="function")return false;const r=m();if(r.wrappedPromise&&t.nativePromise===r.wrappedPromise&&t.nativeCallback===r.wrappedCallback)return true;if(t.DEBUG!==true&&e.release!==true)return false;r.originalPromise=t.nativePromise;r.originalCallback=t.nativeCallback;const n=r.originalPromise;const o=r.originalCallback;const i=(s,l,g,C)=>{const f={plugin:s,method:l,options:w(g)};const b=$(r,f,"promise");const u=d=>{if(d>=b.length){C();if(l==="removeAllListeners"){for(const y of Array.from(r.listeners.keys()))if(y.startsWith(`${s}:`))r.listeners.delete(y)}return n.call(t,s,l,g)}try{return Promise.resolve(b[d].promise(f,()=>u(d+1)))}catch(y){return Promise.reject(y)}};return u(0)};r.runPromise=i;const a=(s,l,g)=>{if(M(r,s,l,g)){return i(s,l,g,()=>{})}const C=S(r,{plugin:s,method:l,kind:"promise",options:w(g),start:v()});let f=false;const b=i(s,l,g,()=>{f=true});b.then(u=>{Object.assign(C,{end:v(),ok:true,result:u,answeredByBuoy:!f});P(r)},u=>{Object.assign(C,{end:v(),ok:false,error:u,answeredByBuoy:!f});P(r)});return b};const c=(s,l,g,C)=>{let f=g;let b=C;if(typeof f==="function"){b=f;f=null}const u={plugin:s,method:l,options:w(f)};const d=S(r,{plugin:s,method:l,kind:"callback",options:u.options,start:v(),events:0});let y=false;const O=$(r,u,"callback");const R=(h,p)=>{if(h>=O.length){y=true;return o.call(t,s,l,f,p)}return O[h].callback(u,p,_=>R(h+1,_))};const A=l==="addListener";const H=(h,p)=>{d.events=(d.events??0)+1;if(!A&&d.end===void 0){d.end=v();d.ok=!p;if(p)d.error=p;else d.result=h;P(r)}else{const _=v();S(r,{plugin:s,method:A?String(u.options.eventName??"event"):l,kind:"event",options:{},start:_,end:_,ok:!p,...p?{error:p}:{result:h}})}b?.(h,p)};const B=R(0,H);d.answeredByBuoy=!y;if(l==="addListener"&&B!=null&&typeof b==="function"){const h=x(s,u.options.eventName);let p=r.listeners.get(h);if(!p)r.listeners.set(h,p=new Map);p.set(String(B),b)}else if(l==="removeListener"){r.listeners.get(x(s,u.options.eventName))?.delete(String(u.options.callbackId))}return B};t.nativePromise=a;t.nativeCallback=c;r.wrappedPromise=a;r.wrappedCallback=c;D(r);G();return true}const Y=/^\s*\(\s*prefers-color-scheme\s*:\s*(dark|light)\s*\)\s*$/i;const N="__BUOY_COLOR_SCHEME_QUERIES__";export function colorSchemeQueryValue(e){const t=Y.exec(e);return t?t[1].toLowerCase():null}function G(){const e=globalThis;const t=globalThis.WeakRef;if(e[N]||typeof e.matchMedia!=="function"||!t)return;const r=[];e[N]=r;const n=e.matchMedia;e.matchMedia=function o(i){const a=n.call(this??globalThis,i);if(a&&colorSchemeQueryValue(String(i))){for(let c=r.length-1;c>=0;c--)if(!r[c].deref())r.splice(c,1);r.push(new t(a))}return a}}export function getColorSchemeQueries(){const e=globalThis[N];if(!e)return[];return e.map(t=>t.deref()).filter(t=>!!t)}export function isCapacitorBridgeInstalled(){const e=k();const t=m();return Boolean(t.wrappedPromise&&e?.nativePromise===t.wrappedPromise)}export function interceptCapacitor(e){const t=m();t.interceptors.push(e);return()=>{const r=t.interceptors.indexOf(e);if(r>=0)t.interceptors.splice(r,1)}}export function emitCapacitorEvent(e,t,r){const n=m().listeners.get(x(e,t));if(!n)return 0;let o=0;for(const i of Array.from(n.values())){try{i(r);o++}catch(a){globalThis.console?.error(a)}}return o}export function capacitorListenerCount(e,t){return m().listeners.get(x(e,t))?.size??0}function j(e){return k()?.PluginHeaders?.find(t=>t.name===e)}export function hasCapacitorPlugin(e){if(!L())return false;try{return Boolean(j(e))||k()?.isPluginAvailable?.(e)===true}catch{return false}}function I(){const e=k();const t=m();return{cap:e,promise:t.originalPromise??e?.nativePromise??null,callback:t.originalCallback??e?.nativeCallback??null}}export function callCapacitorNative(e,t,r={}){const{cap:n,promise:o}=I();if(!n||!o)return Promise.reject(new Error("Capacitor bridge unavailable"));return o.call(n,e,t,r)}export function callCapacitorAsApp(e,t,r={}){const n=m().runPromise;if(n&&isCapacitorBridgeInstalled())return n(e,t,r,()=>{});return callCapacitorNative(e,t,r)}export function callCapacitorNativeCallback(e,t,r,n){const{cap:o,callback:i}=I();if(!o||!i)return null;return i.call(o,e,t,r,n)}export function listenCapacitorNative(e,t,r){const{cap:n,promise:o,callback:i}=I();if(!n||!i)return Promise.reject(new Error("Capacitor bridge unavailable"));const a=i.call(n,e,"addListener",{eventName:t},s=>r(s));const c=async()=>{if(a==null)return;const s={eventName:t,callbackId:a};const l=j(e)?.methods?.find(g=>g.name==="removeListener")?.rtype;if(l==="promise"&&o)await o.call(n,e,"removeListener",s);else i.call(n,e,"removeListener",s,()=>{})};return Promise.resolve({remove:c})}export function getCapacitorCalls(){return m().log}export function clearCapacitorCalls(){const e=m();e.log.length=0;P(e)}export function subscribeCapacitorCalls(e){const t=m();t.subscribers.add(e);return()=>{t.subscribers.delete(e)}}const Q=new Set(["then","catch","finally","$$typeof","toJSON","constructor"]);export function capacitorPlugin(e){if(!hasCapacitorPlugin(e))return null;return new Proxy({},{get(t,r){if(typeof r!=="string"||Q.has(r))return void 0;if(r==="addListener"){return(n,o)=>listenCapacitorNative(e,n,o)}return n=>callCapacitorNative(e,r,n??{})}})}const T="__BUOY_CAPACITOR_HOST__";export function loadCapacitorAppHost(){if(!L())return Promise.resolve(null);const e=globalThis;const t=e[T];if(t)return t;const r=i=>typeof i==="string"&&i?i:null;const n=async i=>{if(!hasCapacitorPlugin(i))return{};try{return await callCapacitorNative(i,"getInfo")??{}}catch{return{}}};const o=Promise.all([n("App"),n("Device")]).then(([i,a])=>{const c={isSimulator:typeof a.isVirtual==="boolean"?a.isVirtual:null,deviceName:r(a.name),bundleId:r(i.id),appName:r(i.name)};e[`${T}_value`]=c;return c});e[T]=o;return o}export function getCapacitorAppHost(){return globalThis[`${T}_value`]??null}
@@ -14,4 +14,4 @@
14
14
  * Pro is $9/mo, and is free every weekend for anyone holding a key —
15
15
  * including a free one (`npx buoy login`). Buy a key at
16
16
  * https://buoy.gg or use it free on Saturday and Sunday.
17
- */export const KEYGEN_CONFIG={accountId:"b0eba0e8-e904-4906-b644-38f9aab57bed",productId:"bf67cb43-eeef-40ca-b308-e6e1b22c0eaa",apiUrl:"https://buoy.gg/api/license"};export const FREE_TOKEN_PUBLIC_KEY="3b546fc717a62683f3236c70167899a271bee3ffc04df6ec1eea60a394a2f1e9";export const SESSION_TOKEN_PUBLIC_KEY="36abba0267f7f379d992a5b6df641daab4190bcc9e639e36f1378e3c1ac52746";export const KEYGEN_POLICIES={free:"394e3351-1249-4f73-807a-703408604c0e",solo:"fa5d3c8f-5379-40f1-b63e-ab8a974b2f28",business:"690c2212-8e54-426f-b4b4-002ee1c0ae2b"};export const LICENSE_CACHE_DURATION=30*24*60*60*1e3;export const LICENSE_REVALIDATION_INTERVAL=24*60*60*1e3;export const LICENSE_STORAGE_KEY="buoy-gg-license";export const DEVICE_FINGERPRINT_STORAGE_KEY="buoy-gg-device-fingerprint";export const LICENSE_LAUNCH_VALIDATION_TTL=60*60*1e3;export const LICENSE_TRANSIENT_RETRY_DELAYS=[5*1e3,20*1e3,60*1e3,5*60*1e3,15*60*1e3];export const LICENSE_RATE_LIMIT_DEFAULT_WAIT=60*1e3;export const LICENSE_QUOTA_COOLDOWN=60*60*1e3;export const LICENSE_VERDICT_CACHE_DURATION=24*60*60*1e3;export const LICENSE_FLEET_MACHINE_THRESHOLD=50;export const LICENSE_QUIET_VALIDATION_TTL=LICENSE_CACHE_DURATION;export const LICENSE_HOLD_STORAGE_KEY="buoy-gg-license-hold";
17
+ */export const KEYGEN_CONFIG=Object.freeze({accountId:"b0eba0e8-e904-4906-b644-38f9aab57bed",productId:"bf67cb43-eeef-40ca-b308-e6e1b22c0eaa",apiUrl:"https://buoy.gg/api/license"});export{FREE_TOKEN_PUBLIC_KEY}from"./freeTokenKey.js";export{SESSION_TOKEN_PUBLIC_KEY}from"./sessionTokenKey.js";export const KEYGEN_POLICIES=Object.freeze({free:"394e3351-1249-4f73-807a-703408604c0e",solo:"fa5d3c8f-5379-40f1-b63e-ab8a974b2f28",business:"690c2212-8e54-426f-b4b4-002ee1c0ae2b"});export const LICENSE_CACHE_DURATION=30*24*60*60*1e3;export const LICENSE_REVALIDATION_INTERVAL=24*60*60*1e3;export const LICENSE_STORAGE_KEY="buoy-gg-license";export const DEVICE_FINGERPRINT_STORAGE_KEY="buoy-gg-device-fingerprint";export const LICENSE_LAUNCH_VALIDATION_TTL=60*60*1e3;export const LICENSE_TRANSIENT_RETRY_DELAYS=[5*1e3,20*1e3,60*1e3,5*60*1e3,15*60*1e3];export const LICENSE_RATE_LIMIT_DEFAULT_WAIT=60*1e3;export const LICENSE_QUOTA_COOLDOWN=60*60*1e3;export const LICENSE_VERDICT_CACHE_DURATION=24*60*60*1e3;export const LICENSE_FLEET_MACHINE_THRESHOLD=50;export const LICENSE_QUIET_VALIDATION_TTL=LICENSE_CACHE_DURATION;export const LICENSE_HOLD_STORAGE_KEY="buoy-gg-license-hold";
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */import i from"tweetnacl";import{FREE_TOKEN_PUBLIC_KEY as f}from"./config.js";export const FREE_TOKEN_PREFIX="BUOY1";const l=1;const a=1;const A="buoy-free-token-v1:";const h=22;const F=64;const p=/^BUOY1-([A-Z2-7]+)-([A-Z2-7]+)$/;export function isBuoyToken(n){return p.test(n.trim().toUpperCase())}const s="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function y(n){let r="";let t=0;let e=0;for(const o of n){e=e<<8|o;t+=8;while(t>=5){r+=s[e>>>t-5&31];t-=5}}if(t>0)r+=s[e<<5-t&31];return r}function d(n){const r=[];let t=0;let e=0;for(const o of n){const c=s.indexOf(o);if(c===-1)return null;e=e<<5|c;t+=5;if(t>=8){r.push(e>>>t-8&255);t-=8}}return new Uint8Array(r)}function u(n){const r=n.trim().toLowerCase();const t=new Uint8Array(r.length/2);for(let e=0;e<t.length;e+=1)t[e]=parseInt(r.slice(e*2,e*2+2),16);return t}function g(n){let r="";for(const t of n)r+=t.toString(16).padStart(2,"0");return r}function m(n){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(n);const r=new Uint8Array(n.length);for(let t=0;t<n.length;t+=1)r[t]=n.charCodeAt(t)&255;return r}function T(n,r){const t=new Uint8Array(n.length+r.length);t.set(n,0);t.set(r,n.length);return t}function x(n){return T(m(A),n)}export function accountHashFor(n){return i.hash(m(n)).slice(0,16)}function U(n,r){const t=new Uint8Array(h);t[0]=l;t[1]=a;const e=Math.max(0,Math.min(4294967295,Math.floor(n)));t[2]=e>>>24&255;t[3]=e>>>16&255;t[4]=e>>>8&255;t[5]=e&255;t.set(r.slice(0,16),6);return t}export function mintFreeToken(n,r,t){const e=U(r/1e3,accountHashFor(n));const{secretKey:o}=i.sign.keyPair.fromSeed(u(t));const c=i.sign.detached(x(e),o);return`${FREE_TOKEN_PREFIX}-${y(e)}-${y(c)}`}export function publicKeyFor(n){return g(i.sign.keyPair.fromSeed(u(n)).publicKey)}let E=f;export function __setFreeTokenPublicKeyForTests(n){E=n??f}export function verifyFreeToken(n,r=E){const t=p.exec(n.trim().toUpperCase());if(!t)return null;const e=d(t[1]);const o=d(t[2]);if(!e||!o)return null;if(e.length!==h||o.length!==F)return null;if(e[0]!==l||e[1]!==a)return null;try{if(!i.sign.detached.verify(x(e),o,u(r)))return null}catch{return null}const c=(e[2]<<24>>>0)+(e[3]<<16)+(e[4]<<8)+e[5];return{tier:"free",issuedAt:c*1e3,accountHash:g(e.slice(6,22))}}
6
+ */import c from"tweetnacl";import{FREE_TOKEN_PUBLIC_KEY as E}from"./freeTokenKey.js";export const FREE_TOKEN_PREFIX="BUOY1";const f=1;const l=1;const x="buoy-free-token-v1:";const a=22;const A=64;const h=/^BUOY1-([A-Z2-7]+)-([A-Z2-7]+)$/;export function isBuoyToken(n){return h.test(n.trim().toUpperCase())}const s="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";function p(n){let e="";let t=0;let r=0;for(const o of n){r=r<<8|o;t+=8;while(t>=5){e+=s[r>>>t-5&31];t-=5}}if(t>0)e+=s[r<<5-t&31];return e}function y(n){const e=[];let t=0;let r=0;for(const o of n){const i=s.indexOf(o);if(i===-1)return null;r=r<<5|i;t+=5;if(t>=8){e.push(r>>>t-8&255);t-=8}}return new Uint8Array(e)}function u(n){const e=n.trim().toLowerCase();const t=new Uint8Array(e.length/2);for(let r=0;r<t.length;r+=1)t[r]=parseInt(e.slice(r*2,r*2+2),16);return t}function d(n){let e="";for(const t of n)e+=t.toString(16).padStart(2,"0");return e}function g(n){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(n);const e=new Uint8Array(n.length);for(let t=0;t<n.length;t+=1)e[t]=n.charCodeAt(t)&255;return e}function U(n,e){const t=new Uint8Array(n.length+e.length);t.set(n,0);t.set(e,n.length);return t}function m(n){return U(g(x),n)}export function accountHashFor(n){return c.hash(g(n)).slice(0,16)}function T(n,e){const t=new Uint8Array(a);t[0]=f;t[1]=l;const r=Math.max(0,Math.min(4294967295,Math.floor(n)));t[2]=r>>>24&255;t[3]=r>>>16&255;t[4]=r>>>8&255;t[5]=r&255;t.set(e.slice(0,16),6);return t}export function mintFreeToken(n,e,t){const r=T(e/1e3,accountHashFor(n));const{secretKey:o}=c.sign.keyPair.fromSeed(u(t));const i=c.sign.detached(m(r),o);return`${FREE_TOKEN_PREFIX}-${p(r)}-${p(i)}`}export function publicKeyFor(n){return d(c.sign.keyPair.fromSeed(u(n)).publicKey)}const w=E;export function verifyFreeToken(n){const e=h.exec(n.trim().toUpperCase());if(!e)return null;const t=y(e[1]);const r=y(e[2]);if(!t||!r)return null;if(t.length!==a||r.length!==A)return null;if(t[0]!==f||t[1]!==l)return null;try{if(!c.sign.detached.verify(m(t),r,u(w)))return null}catch{return null}const o=(t[2]<<24>>>0)+(t[3]<<16)+(t[4]<<8)+t[5];return{tier:"free",issuedAt:o*1e3,accountHash:d(t.slice(6,22))}}
@@ -0,0 +1,6 @@
1
+ "use strict";/*!
2
+ * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
+ *
4
+ * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
+ * (https://buoy.gg/terms), not an OSS license.
6
+ */export const FREE_TOKEN_PUBLIC_KEY="3b546fc717a62683f3236c70167899a271bee3ffc04df6ec1eea60a394a2f1e9";
@@ -1 +1 @@
1
- "use strict";export{validateLicense,isAcceptedValidation,isTransientLicenseError,LicenseTransportError}from"./api.js";export{resolveTier,isRecognizedAccount}from"./tier.js";export{isBuoyToken,verifyFreeToken,mintFreeToken,accountHashFor,publicKeyFor,__setFreeTokenPublicKeyForTests}from"./freeToken.js";export{resolveAccountAccess}from"./accountAccess.js";export{signCache,verifyCacheSignature}from"./cacheSignature.js";export{LICENSE_CACHE_DURATION,LICENSE_REVALIDATION_INTERVAL,LICENSE_LAUNCH_VALIDATION_TTL,LICENSE_TRANSIENT_RETRY_DELAYS,KEYGEN_CONFIG}from"./config.js";export{createNodeSession,fileSessionStorage,fileLock,receiveCodeOnLoopback,defaultSessionFile,DESKTOP_AUDIENCE,CLI_AUDIENCE}from"./nodeSession.js";export{SessionError,SessionManagerImpl,SESSION_OFFLINE_GRACE_MS}from"./sessionManager.js";export{verifySessionToken,mintSessionToken,__setSessionTokenPublicKeyForTests}from"./sessionToken.js";export{exchangeServiceKey,isServiceKey,normalizeLicenseKey,sameLicenseKey,SERVICE_KEY_PREFIX,SERVICE_AUDIENCE}from"./serviceKey.js";export{checkDevToken,isDevToken,DEV_AUDIENCE}from"./devToken.js";
1
+ "use strict";export{validateLicense,isAcceptedValidation,isTransientLicenseError,LicenseTransportError}from"./api.js";export{resolveTier,isRecognizedAccount}from"./tier.js";export{isBuoyToken,verifyFreeToken,mintFreeToken,accountHashFor,publicKeyFor}from"./freeToken.js";export{resolveAccountAccess}from"./accountAccess.js";export{signCache,verifyCacheSignature}from"./cacheSignature.js";export{LICENSE_CACHE_DURATION,LICENSE_REVALIDATION_INTERVAL,LICENSE_LAUNCH_VALIDATION_TTL,LICENSE_TRANSIENT_RETRY_DELAYS,KEYGEN_CONFIG}from"./config.js";export{createNodeSession,fileSessionStorage,fileLock,receiveCodeOnLoopback,defaultSessionFile,DESKTOP_AUDIENCE,CLI_AUDIENCE}from"./nodeSession.js";export{SessionError,SessionManagerImpl,SESSION_OFFLINE_GRACE_MS}from"./sessionManager.js";export{verifySessionToken,mintSessionToken}from"./sessionToken.js";export{exchangeServiceKey,isServiceKey,normalizeLicenseKey,sameLicenseKey,SERVICE_KEY_PREFIX,SERVICE_AUDIENCE}from"./serviceKey.js";export{checkDevToken,isDevToken,DEV_AUDIENCE}from"./devToken.js";
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */import E from"node:http";import{createHash as T,randomBytes as y,timingSafeEqual as _}from"node:crypto";import{promises as f}from"node:fs";import{dirname as S,join as b}from"node:path";import{homedir as k}from"node:os";import{SessionManagerImpl as O,SessionError as h}from"./sessionManager.js";export const DESKTOP_AUDIENCE="app:gg.buoy.desktop";export const CLI_AUDIENCE="app:gg.buoy.cli";const A=5*60*1e3;const C=4096;const I=6e4;const v=3e4;const N=8e3;const L=15e3;const H=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","CERT_UNTRUSTED"]);function P(t){const r=t?.cause;if(r&&typeof r.code==="string")return r.code;if(t?.name==="TimeoutError")return"timed out";if(r&&typeof r.message==="string")return r.message;return t instanceof Error?t.message:String(t)}export function defaultSessionFile(){return process.env.BUOY_SESSION_FILE||b(k(),".buoy","session.json")}export function fileSessionStorage(t){const r=async()=>{try{const n=JSON.parse(await f.readFile(t,"utf8"));return n&&typeof n==="object"?n:{}}catch{return{}}};const u=async n=>{await f.mkdir(S(t),{recursive:true,mode:448});if(Object.keys(n).length===0){await f.rm(t,{force:true});return}const i=`${t}.${process.pid}.${y(4).toString("hex")}.tmp`;await f.writeFile(i,JSON.stringify(n),{mode:384});await f.rename(i,t)};return{async getItem(n){return(await r())[n]??null},async setItem(n,i){const l=await r();l[n]=i;await u(l)},async removeItem(n){const i=await r();if(!(n in i))return;delete i[n];await u(i)}}}export function fileLock(t,r={}){const u=r.staleMs??I;const n=r.waitMs??v;return async(i,l)=>{const s=`${process.pid}:${y(8).toString("hex")}`;const p=Date.now()+n;await f.mkdir(S(t),{recursive:true,mode:448});for(;;){try{await f.writeFile(t,s,{flag:"wx",mode:384});break}catch(e){if(e.code!=="EEXIST")throw e;const a=await f.stat(t).catch(()=>null);if(a&&Date.now()-a.mtimeMs>u){await f.rm(t,{force:true});continue}if(Date.now()>p)throw new Error("Another Buoy process holds the sign-in lock.");await new Promise(o=>setTimeout(o,50))}}try{return await l()}finally{const e=await f.readFile(t,"utf8").catch(()=>null);if(e===s)await f.rm(t,{force:true})}}}function U(t,r){const u=Buffer.from(t);const n=Buffer.from(r);return u.length===n.length&&_(u,n)}export async function receiveCodeOnLoopback(t,r,u,n={}){let i;let l;const s=new Promise((c,d)=>{i=c;l=d});s.catch(()=>{});const p=E.createServer((c,d)=>{if(c.headers.origin===u){d.setHeader("Access-Control-Allow-Origin",u);d.setHeader("Access-Control-Allow-Headers","Content-Type");d.setHeader("Access-Control-Allow-Methods","POST, OPTIONS");d.setHeader("Access-Control-Allow-Private-Network","true")}if(c.method==="OPTIONS")return void d.writeHead(204).end();if(c.method!=="POST")return void d.writeHead(405).end();let g="";c.on("data",w=>{g+=w;if(g.length>C)c.destroy()});c.on("end",()=>{let w=null;try{w=JSON.parse(g)}catch{}if(!w||typeof w.state!=="string"||!U(w.state,r))return void d.writeHead(400).end();d.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof w.code==="string"&&w.code)o(()=>i(w.code));else o(()=>l(new h("access_denied","Sign-in was cancelled.")))})});const e=setTimeout(()=>o(()=>l(new h("timeout","Sign-in took too long."))),n.timeoutMs??A);e.unref?.();const a=()=>o(()=>l(new h("popup_closed","Sign-in was cancelled.")));n.signal?.addEventListener("abort",a);function o(c){clearTimeout(e);n.signal?.removeEventListener("abort",a);p.close();c()}await new Promise((c,d)=>{p.once("error",d);p.listen(0,"127.0.0.1",()=>c())});const m=p.address();if(!m||typeof m==="string"){o(()=>l(new Error("Could not open a local port")));throw new Error("Could not open a local port")}return{url:`${t}&port=${m.port}`,code:s}}export function createNodeSession(t){const r=defaultSessionFile();const u=t.storage??fileSessionStorage(r);const n=(t.signinOrigin??process.env.BUOY_SITE_URL??"https://buoy.gg").replace(/\/$/,"");const i=t.fetch??((e,a)=>fetch(e,a));const l={fetch:i,storage:async()=>u,now:t.now??(()=>Date.now()),random:e=>new Uint8Array(y(e)),sha256:async e=>new Uint8Array(T("sha256").update(e).digest()),openPopup:()=>null,onMessage:()=>()=>{},withLock:fileLock(t.lockFile??`${r}.lock`),setTimer:(e,a)=>{const o=setTimeout(e,Math.min(a,2147483647));o.unref?.();return o},clearTimer:e=>clearTimeout(e),publicKeyHex:t.publicKeyHex};const s=new O(l);s.configure({audience:t.audience,signinOrigin:n});const p=async()=>{let e;try{e=await i(`${n}/api/auth/status`,{method:"GET",headers:{},signal:AbortSignal.timeout(N)})}catch(o){const m=P(o);return H.has(m)?{state:"unreachable",detail:m,hint:"Your network may re-sign secure traffic. Point NODE_EXTRA_CA_CERTS at your company's root certificate."}:{state:"unreachable",detail:m}}const a=await e.json().catch(()=>null);if(e.status===200&&a?.enabled===true)return{state:"enabled"};if(e.status===200&&a?.enabled===false)return{state:"disabled"};return{state:"unreachable",detail:a?`HTTP ${e.status}`:`HTTP ${e.status}, not a Buoy answer`}};return{manager:s,async load(){await s.load();return s.getStatus()},getStatus:()=>s.getStatus(),signIn:(e={})=>s.signInWith(async(a,o)=>{const{url:m,code:c}=await receiveCodeOnLoopback(a,o,n,e);await t.openBrowser(m);return c}),signOut:()=>s.signOut(),refresh:e=>s.refresh(e),sync:()=>s.sync(),async devToken(){const e=s.getAccessToken();if(!e)return{ok:false,detail:"This computer is not signed in. Run `npx buoy login`."};try{const a=await i(`${n}/api/auth/dev-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:e}),signal:AbortSignal.timeout(L)});const o=await a.json().catch(()=>null);if(a.status===200&&typeof o?.dev_token==="string"){return{ok:true,token:o.dev_token,tier:typeof o.tier==="string"?o.tier:"free"}}return{ok:false,detail:typeof o?.error_description==="string"?o.error_description:"buoy.gg did not make a dev token."}}catch{return{ok:false,detail:"Buoy could not be reached. Check your connection and try again."}}},checkAvailability:p,async isAvailable(){return(await p()).state==="enabled"},subscribe:e=>s.subscribe(e)}}
6
+ */import E from"node:http";import{createHash as T,randomBytes as y,timingSafeEqual as _}from"node:crypto";import{promises as f}from"node:fs";import{dirname as S,join as b}from"node:path";import{homedir as k}from"node:os";import{SessionManagerImpl as O,SessionError as h}from"./sessionManager.js";export const DESKTOP_AUDIENCE="app:gg.buoy.desktop";export const CLI_AUDIENCE="app:gg.buoy.cli";const A=5*60*1e3;const C=4096;const I=6e4;const v=3e4;const N=8e3;const L=15e3;const P=new Set(["UNABLE_TO_GET_ISSUER_CERT_LOCALLY","SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","CERT_UNTRUSTED"]);function H(t){const r=t?.cause;if(r&&typeof r.code==="string")return r.code;if(t?.name==="TimeoutError")return"timed out";if(r&&typeof r.message==="string")return r.message;return t instanceof Error?t.message:String(t)}export function defaultSessionFile(){return process.env.BUOY_SESSION_FILE||b(k(),".buoy","session.json")}export function fileSessionStorage(t){const r=async()=>{try{const n=JSON.parse(await f.readFile(t,"utf8"));return n&&typeof n==="object"?n:{}}catch{return{}}};const u=async n=>{await f.mkdir(S(t),{recursive:true,mode:448});if(Object.keys(n).length===0){await f.rm(t,{force:true});return}const i=`${t}.${process.pid}.${y(4).toString("hex")}.tmp`;await f.writeFile(i,JSON.stringify(n),{mode:384});await f.rename(i,t)};return{async getItem(n){return(await r())[n]??null},async setItem(n,i){const l=await r();l[n]=i;await u(l)},async removeItem(n){const i=await r();if(!(n in i))return;delete i[n];await u(i)}}}export function fileLock(t,r={}){const u=r.staleMs??I;const n=r.waitMs??v;return async(i,l)=>{const s=`${process.pid}:${y(8).toString("hex")}`;const m=Date.now()+n;await f.mkdir(S(t),{recursive:true,mode:448});for(;;){try{await f.writeFile(t,s,{flag:"wx",mode:384});break}catch(e){if(e.code!=="EEXIST")throw e;const a=await f.stat(t).catch(()=>null);if(a&&Date.now()-a.mtimeMs>u){await f.rm(t,{force:true});continue}if(Date.now()>m)throw new Error("Another Buoy process holds the sign-in lock.");await new Promise(o=>setTimeout(o,50))}}try{return await l()}finally{const e=await f.readFile(t,"utf8").catch(()=>null);if(e===s)await f.rm(t,{force:true})}}}function U(t,r){const u=Buffer.from(t);const n=Buffer.from(r);return u.length===n.length&&_(u,n)}export async function receiveCodeOnLoopback(t,r,u,n={}){let i;let l;const s=new Promise((c,d)=>{i=c;l=d});s.catch(()=>{});const m=E.createServer((c,d)=>{if(c.headers.origin===u){d.setHeader("Access-Control-Allow-Origin",u);d.setHeader("Access-Control-Allow-Headers","Content-Type");d.setHeader("Access-Control-Allow-Methods","POST, OPTIONS");d.setHeader("Access-Control-Allow-Private-Network","true")}if(c.method==="OPTIONS")return void d.writeHead(204).end();if(c.method!=="POST")return void d.writeHead(405).end();let g="";c.on("data",w=>{g+=w;if(g.length>C)c.destroy()});c.on("end",()=>{let w=null;try{w=JSON.parse(g)}catch{}if(!w||typeof w.state!=="string"||!U(w.state,r))return void d.writeHead(400).end();d.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof w.code==="string"&&w.code)o(()=>i(w.code));else o(()=>l(new h("access_denied","Sign-in was cancelled.")))})});const e=setTimeout(()=>o(()=>l(new h("timeout","Sign-in took too long."))),n.timeoutMs??A);e.unref?.();const a=()=>o(()=>l(new h("popup_closed","Sign-in was cancelled.")));n.signal?.addEventListener("abort",a);function o(c){clearTimeout(e);n.signal?.removeEventListener("abort",a);m.close();c()}await new Promise((c,d)=>{m.once("error",d);m.listen(0,"127.0.0.1",()=>c())});const p=m.address();if(!p||typeof p==="string"){o(()=>l(new Error("Could not open a local port")));throw new Error("Could not open a local port")}return{url:`${t}&port=${p.port}`,code:s}}export function createNodeSession(t){const r=defaultSessionFile();const u=t.storage??fileSessionStorage(r);const n=(t.signinOrigin??process.env.BUOY_SITE_URL??"https://buoy.gg").replace(/\/$/,"");const i=t.fetch??((e,a)=>fetch(e,a));const l={fetch:i,storage:async()=>u,now:t.now??(()=>Date.now()),random:e=>new Uint8Array(y(e)),sha256:async e=>new Uint8Array(T("sha256").update(e).digest()),openPopup:()=>null,onMessage:()=>()=>{},withLock:fileLock(t.lockFile??`${r}.lock`),setTimer:(e,a)=>{const o=setTimeout(e,Math.min(a,2147483647));o.unref?.();return o},clearTimer:e=>clearTimeout(e)};const s=new O(l);s.configure({audience:t.audience,signinOrigin:n});const m=async()=>{let e;try{e=await i(`${n}/api/auth/status`,{method:"GET",headers:{},signal:AbortSignal.timeout(N)})}catch(o){const p=H(o);return P.has(p)?{state:"unreachable",detail:p,hint:"Your network may re-sign secure traffic. Point NODE_EXTRA_CA_CERTS at your company's root certificate."}:{state:"unreachable",detail:p}}const a=await e.json().catch(()=>null);if(e.status===200&&a?.enabled===true)return{state:"enabled"};if(e.status===200&&a?.enabled===false)return{state:"disabled"};return{state:"unreachable",detail:a?`HTTP ${e.status}`:`HTTP ${e.status}, not a Buoy answer`}};return{manager:s,async load(){await s.load();return s.getStatus()},getStatus:()=>s.getStatus(),signIn:(e={})=>s.signInWith(async(a,o)=>{const{url:p,code:c}=await receiveCodeOnLoopback(a,o,n,e);await t.openBrowser(p);return c}),signOut:()=>s.signOut(),refresh:e=>s.refresh(e),sync:()=>s.sync(),async devToken(){const e=s.getAccessToken();if(!e)return{ok:false,detail:"This computer is not signed in. Run `npx buoy login`."};try{const a=await i(`${n}/api/auth/dev-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:e}),signal:AbortSignal.timeout(L)});const o=await a.json().catch(()=>null);if(a.status===200&&typeof o?.dev_token==="string"){return{ok:true,token:o.dev_token,tier:typeof o.tier==="string"?o.tier:"free"}}return{ok:false,detail:typeof o?.error_description==="string"?o.error_description:"buoy.gg did not make a dev token."}}catch{return{ok:false,detail:"Buoy could not be reached. Check your connection and try again."}}},checkAvailability:m,async isAvailable(){return(await m()).state==="enabled"},subscribe:e=>s.subscribe(e)}}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */import{isSessionToken as u,verifySessionToken as p}from"./sessionToken.js";import{realNow as y}from"./realNow.js";export const SERVICE_KEY_PREFIX="bsk1_";export const SERVICE_AUDIENCE="service";const k=15e3;export function isServiceKey(t){return t.startsWith(SERVICE_KEY_PREFIX)}export function normalizeLicenseKey(t){const e=t.trim();return isServiceKey(e)||u(e)?e:e.toUpperCase()}export function sameLicenseKey(t,e){return normalizeLicenseKey(t??"")===normalizeLicenseKey(e??"")}export async function exchangeServiceKey(t,e){const c=e.fetch??((r,l)=>fetch(r,l));const s=typeof AbortController!=="undefined"?new AbortController:void 0;const a=setTimeout(()=>s?.abort(),k);let n;let o;try{const r=await c(`${e.origin.replace(/\/$/,"")}/api/auth/service-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:t}),signal:s?.signal});n=r.status;o=await r.json().catch(()=>null)}catch{return{ok:false,reason:"network",detail:"Buoy could not be reached to check the bot key."}}finally{clearTimeout(a)}if(n>=500||n===429)return{ok:false,reason:"network",detail:"Buoy is busy. The bot key will be checked again soon."};if(n!==200||typeof o?.access_token!=="string"){return{ok:false,reason:"rejected",detail:typeof o?.error_description==="string"?o.error_description:"This bot key was not accepted."}}const i=p(o.access_token,{audience:SERVICE_AUDIENCE,nowMs:y(),publicKeyHex:e.publicKeyHex});return i.ok?{ok:true,claims:i.claims}:{ok:false,reason:"rejected",detail:"Buoy sent a token this app could not check."}}
6
+ */import{isSessionToken as u,verifySessionToken as p}from"./sessionToken.js";import{realNow as f}from"./realNow.js";export const SERVICE_KEY_PREFIX="bsk1_";export const SERVICE_AUDIENCE="service";const k=15e3;export function isServiceKey(t){return t.startsWith(SERVICE_KEY_PREFIX)}export function normalizeLicenseKey(t){const e=t.trim();return isServiceKey(e)||u(e)?e:e.toUpperCase()}export function sameLicenseKey(t,e){return normalizeLicenseKey(t??"")===normalizeLicenseKey(e??"")}export async function exchangeServiceKey(t,e){const c=e.fetch??((r,l)=>fetch(r,l));const s=typeof AbortController!=="undefined"?new AbortController:void 0;const a=setTimeout(()=>s?.abort(),k);let n;let o;try{const r=await c(`${e.origin.replace(/\/$/,"")}/api/auth/service-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:t}),signal:s?.signal});n=r.status;o=await r.json().catch(()=>null)}catch{return{ok:false,reason:"network",detail:"Buoy could not be reached to check the bot key."}}finally{clearTimeout(a)}if(n>=500||n===429)return{ok:false,reason:"network",detail:"Buoy is busy. The bot key will be checked again soon."};if(n!==200||typeof o?.access_token!=="string"){return{ok:false,reason:"rejected",detail:typeof o?.error_description==="string"?o.error_description:"This bot key was not accepted."}}const i=p(o.access_token,{audience:SERVICE_AUDIENCE,nowMs:f()});return i.ok?{ok:true,claims:i.claims}:{ok:false,reason:"rejected",detail:"Buoy sent a token this app could not check."}}
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */import{getLicenseStorage as p}from"./storage";import{base64urlEncode as f,verifySessionToken as g,SESSION_CLOCK_SKEW_SECONDS as w}from"./sessionToken.js";import{realNow as m}from"./realNow.js";export const SESSION_STORAGE_PREFIX="@buoy/session:";export const SESSION_OFFLINE_GRACE_MS=7*24*60*60*1e3;export const SESSION_REFRESH_LEAD_MS=6*60*60*1e3;export const SESSION_RETRY_MS=5*60*1e3;export const SESSION_CALL_TIMEOUT_MS=15e3;export const DEFAULT_SIGNIN_ORIGIN="https://buoy.gg";const y="buoy:signin";const T=10*60*1e3;export class SessionError extends Error{constructor(e,t){super(t);this.code=e;this.name="SessionError"}}function _(){const o=globalThis;return{fetch:(e,t)=>fetch(e,t),storage:p,now:m,random:e=>{const t=new Uint8Array(e);if(!o.crypto?.getRandomValues)throw new SessionError("not_configured","This platform has no secure random source.");return o.crypto.getRandomValues(t)},sha256:async e=>{if(!o.crypto?.subtle)throw new SessionError("not_configured","Sign-in needs a secure page (https or localhost).");return new Uint8Array(await o.crypto.subtle.digest("SHA-256",e))},openPopup:()=>{if(!o.window?.open)return null;const e=480;const t=640;const i=Math.max(0,(o.window.screenX??0)+((o.window.outerWidth??e)-e)/2);const r=Math.max(0,(o.window.screenY??0)+((o.window.outerHeight??t)-t)/2);return o.window.open("about:blank","buoy-signin",`popup,width=${e},height=${t},left=${i},top=${r}`)},onMessage:e=>{if(!o.window?.addEventListener)return()=>{};const t=i=>e({origin:i.origin,data:i.data});o.window.addEventListener("message",t);return()=>o.window?.removeEventListener("message",t)},withLock:(e,t)=>o.navigator?.locks?o.navigator.locks.request(e,t):t(),watch:e=>{const t=o.window;if(!t?.addEventListener)return()=>{};const i=n=>e.storage(n.key);const r=()=>{if(t.document?.visibilityState!=="hidden")e.wake()};t.addEventListener("storage",i);t.addEventListener("online",e.wake);t.document?.addEventListener?.("visibilitychange",r);return()=>{t.removeEventListener("storage",i);t.removeEventListener("online",e.wake);t.document?.removeEventListener?.("visibilitychange",r)}},setTimer:(e,t)=>setTimeout(e,Math.min(t,2147483647)),clearTimer:e=>clearTimeout(e)}}function S(){const o=globalThis.location;if(!o?.origin||!/^https?:$/.test(o.protocol??""))return void 0;return o.origin}export class SessionManagerImpl{signinOrigin=DEFAULT_SIGNIN_ORIGIN;current=null;claims=null;listeners=new Set;timer=null;refreshing=null;loaded=null;unwatch=null;limitTimer=null;epoch=0;constructor(e){this.deps=e??_();this.audience=S()}get origin(){return this.signinOrigin}configure(e){if(e.audience!==void 0)this.audience=e.audience;if(e.signinOrigin!==void 0)this.signinOrigin=e.signinOrigin.replace(/\/$/,"");this.reset()}__setDeps(e){this.deps=e;this.reset()}reset(){this.unwatch?.();this.unwatch=null;this.epoch+=1;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;this.current=null;this.claims=null;this.loaded=null;this.refreshing=null}get storageKey(){return SESSION_STORAGE_PREFIX+(this.audience??"")}subscribe(e){this.listeners.add(e);return()=>this.listeners.delete(e)}notify(){for(const e of[...this.listeners]){try{e()}catch(t){console.warn("[Buoy] sign-in listener error:",t)}}}getAccessToken(){const e=this.getStatus();return e.state==="active"&&!e.grace?this.current?.accessToken??null:null}getStatus(){const e=this.claims;if(!e)return{state:"signed_out"};const t=e.exp*1e3;const i=this.deps.now();if(i<(e.iat-w)*1e3)return{state:"signed_out"};if(i<t)return{state:"active",claims:e,grace:false,validUntil:t};if(i<t+SESSION_OFFLINE_GRACE_MS){return{state:"active",claims:e,grace:true,validUntil:t+SESSION_OFFLINE_GRACE_MS}}return{state:"signed_out"}}load(){if(!this.loaded)this.loaded=this.loadOnce();return this.loaded}async loadOnce(){if(!this.audience)return;this.unwatch??=this.deps.watch?.({storage:t=>{if(t===null||t===this.storageKey)void this.sync()},wake:()=>{if(this.claims)void this.refresh()}})??null;const e=await this.read();if(e&&this.adopt(e)){this.notify();this.schedule()}}async sync(){if(!this.audience)return;const e=await this.read();if(!e){if(this.current)this.clearLocal();return}if(e.refreshToken!==this.current?.refreshToken&&this.adopt(e)){this.notify();this.schedule()}}async read(){try{const e=await(await this.deps.storage()).getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t?.v===1&&typeof t.accessToken==="string"&&typeof t.refreshToken==="string"?t:null}catch{return null}}async write(e){const t=await this.deps.storage();if(e)await t.setItem(this.storageKey,JSON.stringify(e));else await t.removeItem(this.storageKey)}adopt(e){if(!this.audience)return false;const t=g(e.accessToken,{audience:this.audience,ignoreTime:true,publicKeyHex:this.deps.publicKeyHex});const i=t.ok?t.claims:null;if(!i)return false;this.current=e;this.claims=i;return true}armLimit(){if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(!this.claims)return;const e=this.claims.exp*1e3;const t=this.deps.now();const i=t<e?e:t<e+SESSION_OFFLINE_GRACE_MS?e+SESSION_OFFLINE_GRACE_MS:null;if(i===null)return;this.limitTimer=this.deps.setTimer(()=>{this.limitTimer=null;this.notify();this.armLimit()},i-t)}call(e,t){return new Promise((i,r)=>{const n=this.deps.setTimer(()=>r(new Error("timeout")),SESSION_CALL_TIMEOUT_MS);this.deps.fetch(e,t).then(s=>{this.deps.clearTimer(n);i(s)},s=>{this.deps.clearTimer(n);r(s)})})}schedule(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(!this.claims)return;const e=this.claims.exp*1e3-SESSION_REFRESH_LEAD_MS-this.deps.now();this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh()},Math.max(0,e))}refresh(e=false){if(!this.refreshing){this.refreshing=this.deps.withLock(this.lockName,()=>this.refreshLocked(e)).catch(()=>this.retryLater()).finally(()=>{this.refreshing=null})}return this.refreshing}get lockName(){return`buoy-session:${this.audience??""}`}async refreshLocked(e){const t=this.epoch;const i=await this.read();if(!i){if(this.current)this.clearLocal();return}if(i.refreshToken!==this.current?.refreshToken){if(this.adopt(i)){this.notify();this.schedule();return}}if(!this.claims)return;if(!e&&this.claims.exp*1e3-this.deps.now()>SESSION_REFRESH_LEAD_MS){this.schedule();return}let r;let n;try{const s=await this.call(`${this.signinOrigin}/api/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:i.refreshToken,audience:this.audience})});r=s.status;n=await s.json().catch(()=>null)}catch{this.retryLater();return}if(t!==this.epoch)return;if(r===200&&n&&typeof n.access_token==="string"&&typeof n.refresh_token==="string"){const s={v:1,accessToken:n.access_token,refreshToken:n.refresh_token};if(this.adopt(s)){await this.write(s);this.notify();this.schedule();return}}if(r===400||r===401||r===403){await this.write(null);this.clearLocal();return}this.retryLater()}retryLater(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh(true)},SESSION_RETRY_MS);this.notify()}clearLocal(){if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;this.current=null;this.claims=null;this.notify()}async signIn(){if(!this.audience)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const e=this.deps.openPopup();if(!e)throw new SessionError("popup_blocked","The browser blocked the sign-in window. Allow pop-ups for this site and try again.");try{return await this.signInWith((t,i)=>new Promise((r,n)=>{e.location.href=t;const s=this.deps.now();let l=null;const h=u=>{if(l!==null)this.deps.clearTimer(l);a();u()};const a=this.deps.onMessage(u=>{if(u.origin!==this.signinOrigin)return;const d=u.data;if(!d||d.type!==y||d.state!==i)return;if(typeof d.code==="string")h(()=>r(d.code));else h(()=>n(new SessionError("access_denied","Sign-in was cancelled.")))});const c=()=>{if(e.closed)return h(()=>n(new SessionError("popup_closed","The sign-in window was closed.")));if(this.deps.now()-s>T)return h(()=>n(new SessionError("timeout","Sign-in took too long.")));l=this.deps.setTimer(c,500)};l=this.deps.setTimer(c,500)}))}finally{try{if(!e.closed)e.close()}catch{}}}async signInWith(e){const t=this.audience;if(!t)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const i=f(this.deps.random(32));const r=f(this.deps.random(16));const n=f(await this.deps.sha256(new TextEncoder().encode(i)));const s=`${this.signinOrigin}/auth/authorize?audience=${encodeURIComponent(t)}&code_challenge=${n}&code_challenge_method=S256&state=${r}`;const l=await e(s,r);let h;try{h=await this.call(`${this.signinOrigin}/api/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:l,code_verifier:i,audience:t})})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const a=await h.json().catch(()=>null);if(h.status!==200||!a||typeof a.access_token!=="string"||typeof a.refresh_token!=="string"){const c=a&&typeof a.error_description==="string"?a.error_description:"Buoy did not accept this sign-in.";throw new SessionError(h.status===503?"unavailable":"rejected",c)}return this.finishSignIn(a.access_token,a.refresh_token)}async finishSignIn(e,t){const i={v:1,accessToken:e,refreshToken:t};this.epoch+=1;if(!this.adopt(i))throw new SessionError("rejected","Buoy sent a sign-in this app could not check.");await this.write(i);await this.load();this.notify();this.schedule();return this.getStatus()}async signInWithCode(e,t={}){const i=this.audience;if(!i)throw new SessionError("not_configured","Sign-in with a code needs this app's id (app:com.example.app).");const r=(a,c)=>this.call(`${this.signinOrigin}/api/auth/device/${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});let n;try{n=await r("start",{audience:i})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const s=await n.json().catch(()=>null);if(n.status!==200||!s||typeof s.device_code!=="string"||typeof s.user_code!=="string"||typeof s.verification_uri!=="string"||typeof s.verification_uri_complete!=="string"){const a=s&&typeof s.error_description==="string"?s.error_description:"Buoy could not start a sign-in.";throw new SessionError(n.status===503?"unavailable":"rejected",a)}const l=this.deps.now()+(Number(s.expires_in)||600)*1e3;let h=Math.max(5,Number(s.interval)||5)*1e3;e({userCode:s.user_code,verificationUri:s.verification_uri,verificationUriComplete:s.verification_uri_complete,expiresAt:l});for(;;){await this.wait(h,t.signal);if(this.deps.now()>l)throw new SessionError("timeout","The code ran out. Start again for a new one.");let a;try{a=await r("poll",{device_code:s.device_code})}catch{continue}const c=await a.json().catch(()=>null);if(a.status===200&&c&&typeof c.access_token==="string"&&typeof c.refresh_token==="string"){return this.finishSignIn(c.access_token,c.refresh_token)}const u=c&&typeof c.error==="string"?c.error:"";if(u==="authorization_pending"||a.status>=500)continue;if(u==="slow_down"||a.status===429){h+=5e3;continue}if(u==="access_denied")throw new SessionError("access_denied","The sign-in was turned down on buoy.gg.");if(u==="expired_token")throw new SessionError("timeout","The code ran out. Start again for a new one.");const d=c&&typeof c.error_description==="string"?c.error_description:"Buoy did not accept this sign-in.";throw new SessionError("rejected",d)}}wait(e,t){return new Promise((i,r)=>{const n=()=>new SessionError("access_denied","Sign-in was cancelled.");if(t?.aborted)return r(n());const s=()=>{this.deps.clearTimer(l);r(n())};const l=this.deps.setTimer(()=>{t?.removeEventListener?.("abort",s);i()},e);t?.addEventListener?.("abort",s)})}async signOut(){this.epoch+=1;const e=this.current;this.clearLocal();let t=e;try{await this.deps.withLock(this.lockName,async()=>{t=await this.read()??e;await this.write(null)})}catch{await this.write(null).catch(()=>{})}if(!t)return;try{await this.call(`${this.signinOrigin}/api/auth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:t.refreshToken})})}catch{}}}export const SessionManager=new SessionManagerImpl;
6
+ */import{getLicenseStorage as p}from"./storage";import{base64urlEncode as f,verifySessionToken as g,SESSION_CLOCK_SKEW_SECONDS as w}from"./sessionToken.js";import{realNow as m}from"./realNow.js";export const SESSION_STORAGE_PREFIX="@buoy/session:";export const SESSION_OFFLINE_GRACE_MS=7*24*60*60*1e3;export const SESSION_REFRESH_LEAD_MS=6*60*60*1e3;export const SESSION_RETRY_MS=5*60*1e3;export const SESSION_CALL_TIMEOUT_MS=15e3;export const DEFAULT_SIGNIN_ORIGIN="https://buoy.gg";const y="buoy:signin";const T=10*60*1e3;export class SessionError extends Error{constructor(e,t){super(t);this.code=e;this.name="SessionError"}}function _(){const o=globalThis;return{fetch:(e,t)=>fetch(e,t),storage:p,now:m,random:e=>{const t=new Uint8Array(e);if(!o.crypto?.getRandomValues)throw new SessionError("not_configured","This platform has no secure random source.");return o.crypto.getRandomValues(t)},sha256:async e=>{if(!o.crypto?.subtle)throw new SessionError("not_configured","Sign-in needs a secure page (https or localhost).");return new Uint8Array(await o.crypto.subtle.digest("SHA-256",e))},openPopup:()=>{if(!o.window?.open)return null;const e=480;const t=640;const i=Math.max(0,(o.window.screenX??0)+((o.window.outerWidth??e)-e)/2);const r=Math.max(0,(o.window.screenY??0)+((o.window.outerHeight??t)-t)/2);return o.window.open("about:blank","buoy-signin",`popup,width=${e},height=${t},left=${i},top=${r}`)},onMessage:e=>{if(!o.window?.addEventListener)return()=>{};const t=i=>e({origin:i.origin,data:i.data});o.window.addEventListener("message",t);return()=>o.window?.removeEventListener("message",t)},withLock:(e,t)=>o.navigator?.locks?o.navigator.locks.request(e,t):t(),watch:e=>{const t=o.window;if(!t?.addEventListener)return()=>{};const i=n=>e.storage(n.key);const r=()=>{if(t.document?.visibilityState!=="hidden")e.wake()};t.addEventListener("storage",i);t.addEventListener("online",e.wake);t.document?.addEventListener?.("visibilitychange",r);return()=>{t.removeEventListener("storage",i);t.removeEventListener("online",e.wake);t.document?.removeEventListener?.("visibilitychange",r)}},setTimer:(e,t)=>setTimeout(e,Math.min(t,2147483647)),clearTimer:e=>clearTimeout(e)}}function S(){const o=globalThis.location;if(!o?.origin||!/^https?:$/.test(o.protocol??""))return void 0;return o.origin}export class SessionManagerImpl{signinOrigin=DEFAULT_SIGNIN_ORIGIN;current=null;claims=null;listeners=new Set;timer=null;refreshing=null;loaded=null;unwatch=null;limitTimer=null;epoch=0;constructor(e){this.deps=e??_();this.audience=S()}get origin(){return this.signinOrigin}configure(e){if(e.audience!==void 0)this.audience=e.audience;if(e.signinOrigin!==void 0)this.signinOrigin=e.signinOrigin.replace(/\/$/,"");this.reset()}reset(){this.unwatch?.();this.unwatch=null;this.epoch+=1;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;this.current=null;this.claims=null;this.loaded=null;this.refreshing=null}get storageKey(){return SESSION_STORAGE_PREFIX+(this.audience??"")}subscribe(e){this.listeners.add(e);return()=>this.listeners.delete(e)}notify(){for(const e of[...this.listeners]){try{e()}catch(t){console.warn("[Buoy] sign-in listener error:",t)}}}getAccessToken(){const e=this.getStatus();return e.state==="active"&&!e.grace?this.current?.accessToken??null:null}getStatus(){const e=this.claims;if(!e)return{state:"signed_out"};const t=e.exp*1e3;const i=this.deps.now();if(i<(e.iat-w)*1e3)return{state:"signed_out"};if(i<t)return{state:"active",claims:e,grace:false,validUntil:t};if(i<t+SESSION_OFFLINE_GRACE_MS){return{state:"active",claims:e,grace:true,validUntil:t+SESSION_OFFLINE_GRACE_MS}}return{state:"signed_out"}}load(){if(!this.loaded)this.loaded=this.loadOnce();return this.loaded}async loadOnce(){if(!this.audience)return;this.unwatch??=this.deps.watch?.({storage:t=>{if(t===null||t===this.storageKey)void this.sync()},wake:()=>{if(this.claims)void this.refresh()}})??null;const e=await this.read();if(e&&this.adopt(e)){this.notify();this.schedule()}}async sync(){if(!this.audience)return;const e=await this.read();if(!e){if(this.current)this.clearLocal();return}if(e.refreshToken!==this.current?.refreshToken&&this.adopt(e)){this.notify();this.schedule()}}async read(){try{const e=await(await this.deps.storage()).getItem(this.storageKey);if(!e)return null;const t=JSON.parse(e);return t?.v===1&&typeof t.accessToken==="string"&&typeof t.refreshToken==="string"?t:null}catch{return null}}async write(e){const t=await this.deps.storage();if(e)await t.setItem(this.storageKey,JSON.stringify(e));else await t.removeItem(this.storageKey)}adopt(e){if(!this.audience)return false;const t=g(e.accessToken,{audience:this.audience,ignoreTime:true});const i=t.ok?t.claims:null;if(!i)return false;this.current=e;this.claims=i;return true}armLimit(){if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;if(!this.claims)return;const e=this.claims.exp*1e3;const t=this.deps.now();const i=t<e?e:t<e+SESSION_OFFLINE_GRACE_MS?e+SESSION_OFFLINE_GRACE_MS:null;if(i===null)return;this.limitTimer=this.deps.setTimer(()=>{this.limitTimer=null;this.notify();this.armLimit()},i-t)}call(e,t){return new Promise((i,r)=>{const n=this.deps.setTimer(()=>r(new Error("timeout")),SESSION_CALL_TIMEOUT_MS);this.deps.fetch(e,t).then(s=>{this.deps.clearTimer(n);i(s)},s=>{this.deps.clearTimer(n);r(s)})})}schedule(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(!this.claims)return;const e=this.claims.exp*1e3-SESSION_REFRESH_LEAD_MS-this.deps.now();this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh()},Math.max(0,e))}refresh(e=false){if(!this.refreshing){this.refreshing=this.deps.withLock(this.lockName,()=>this.refreshLocked(e)).catch(()=>this.retryLater()).finally(()=>{this.refreshing=null})}return this.refreshing}get lockName(){return`buoy-session:${this.audience??""}`}async refreshLocked(e){const t=this.epoch;const i=await this.read();if(!i){if(this.current)this.clearLocal();return}if(i.refreshToken!==this.current?.refreshToken){if(this.adopt(i)){this.notify();this.schedule();return}}if(!this.claims)return;if(!e&&this.claims.exp*1e3-this.deps.now()>SESSION_REFRESH_LEAD_MS){this.schedule();return}let r;let n;try{const s=await this.call(`${this.signinOrigin}/api/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:i.refreshToken,audience:this.audience})});r=s.status;n=await s.json().catch(()=>null)}catch{this.retryLater();return}if(t!==this.epoch)return;if(r===200&&n&&typeof n.access_token==="string"&&typeof n.refresh_token==="string"){const s={v:1,accessToken:n.access_token,refreshToken:n.refresh_token};if(this.adopt(s)){await this.write(s);this.notify();this.schedule();return}}if(r===400||r===401||r===403){await this.write(null);this.clearLocal();return}this.retryLater()}retryLater(){this.armLimit();if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=this.deps.setTimer(()=>{this.timer=null;void this.refresh(true)},SESSION_RETRY_MS);this.notify()}clearLocal(){if(this.timer!==null)this.deps.clearTimer(this.timer);this.timer=null;if(this.limitTimer!==null)this.deps.clearTimer(this.limitTimer);this.limitTimer=null;this.current=null;this.claims=null;this.notify()}async signIn(){if(!this.audience)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const e=this.deps.openPopup();if(!e)throw new SessionError("popup_blocked","The browser blocked the sign-in window. Allow pop-ups for this site and try again.");try{return await this.signInWith((t,i)=>new Promise((r,n)=>{e.location.href=t;const s=this.deps.now();let l=null;const h=u=>{if(l!==null)this.deps.clearTimer(l);a();u()};const a=this.deps.onMessage(u=>{if(u.origin!==this.signinOrigin)return;const d=u.data;if(!d||d.type!==y||d.state!==i)return;if(typeof d.code==="string")h(()=>r(d.code));else h(()=>n(new SessionError("access_denied","Sign-in was cancelled.")))});const c=()=>{if(e.closed)return h(()=>n(new SessionError("popup_closed","The sign-in window was closed.")));if(this.deps.now()-s>T)return h(()=>n(new SessionError("timeout","Sign-in took too long.")));l=this.deps.setTimer(c,500)};l=this.deps.setTimer(c,500)}))}finally{try{if(!e.closed)e.close()}catch{}}}async signInWith(e){const t=this.audience;if(!t)throw new SessionError("not_configured","Sign-in needs a web page or a configured app id.");const i=f(this.deps.random(32));const r=f(this.deps.random(16));const n=f(await this.deps.sha256(new TextEncoder().encode(i)));const s=`${this.signinOrigin}/auth/authorize?audience=${encodeURIComponent(t)}&code_challenge=${n}&code_challenge_method=S256&state=${r}`;const l=await e(s,r);let h;try{h=await this.call(`${this.signinOrigin}/api/auth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:l,code_verifier:i,audience:t})})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const a=await h.json().catch(()=>null);if(h.status!==200||!a||typeof a.access_token!=="string"||typeof a.refresh_token!=="string"){const c=a&&typeof a.error_description==="string"?a.error_description:"Buoy did not accept this sign-in.";throw new SessionError(h.status===503?"unavailable":"rejected",c)}return this.finishSignIn(a.access_token,a.refresh_token)}async finishSignIn(e,t){const i={v:1,accessToken:e,refreshToken:t};this.epoch+=1;if(!this.adopt(i))throw new SessionError("rejected","Buoy sent a sign-in this app could not check.");await this.write(i);await this.load();this.notify();this.schedule();return this.getStatus()}async signInWithCode(e,t={}){const i=this.audience;if(!i)throw new SessionError("not_configured","Sign-in with a code needs this app's id (app:com.example.app).");const r=(a,c)=>this.call(`${this.signinOrigin}/api/auth/device/${a}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});let n;try{n=await r("start",{audience:i})}catch{throw new SessionError("network","Buoy could not be reached. Check your connection and try again.")}const s=await n.json().catch(()=>null);if(n.status!==200||!s||typeof s.device_code!=="string"||typeof s.user_code!=="string"||typeof s.verification_uri!=="string"||typeof s.verification_uri_complete!=="string"){const a=s&&typeof s.error_description==="string"?s.error_description:"Buoy could not start a sign-in.";throw new SessionError(n.status===503?"unavailable":"rejected",a)}const l=this.deps.now()+(Number(s.expires_in)||600)*1e3;let h=Math.max(5,Number(s.interval)||5)*1e3;e({userCode:s.user_code,verificationUri:s.verification_uri,verificationUriComplete:s.verification_uri_complete,expiresAt:l});for(;;){await this.wait(h,t.signal);if(this.deps.now()>l)throw new SessionError("timeout","The code ran out. Start again for a new one.");let a;try{a=await r("poll",{device_code:s.device_code})}catch{continue}const c=await a.json().catch(()=>null);if(a.status===200&&c&&typeof c.access_token==="string"&&typeof c.refresh_token==="string"){return this.finishSignIn(c.access_token,c.refresh_token)}const u=c&&typeof c.error==="string"?c.error:"";if(u==="authorization_pending"||a.status>=500)continue;if(u==="slow_down"||a.status===429){h+=5e3;continue}if(u==="access_denied")throw new SessionError("access_denied","The sign-in was turned down on buoy.gg.");if(u==="expired_token")throw new SessionError("timeout","The code ran out. Start again for a new one.");const d=c&&typeof c.error_description==="string"?c.error_description:"Buoy did not accept this sign-in.";throw new SessionError("rejected",d)}}wait(e,t){return new Promise((i,r)=>{const n=()=>new SessionError("access_denied","Sign-in was cancelled.");if(t?.aborted)return r(n());const s=()=>{this.deps.clearTimer(l);r(n())};const l=this.deps.setTimer(()=>{t?.removeEventListener?.("abort",s);i()},e);t?.addEventListener?.("abort",s)})}async signOut(){this.epoch+=1;const e=this.current;this.clearLocal();let t=e;try{await this.deps.withLock(this.lockName,async()=>{t=await this.read()??e;await this.write(null)})}catch{await this.write(null).catch(()=>{})}if(!t)return;try{await this.call(`${this.signinOrigin}/api/auth/revoke`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:t.refreshToken})})}catch{}}}export const SessionManager=new SessionManagerImpl;
@@ -3,4 +3,4 @@
3
3
  *
4
4
  * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
5
  * (https://buoy.gg/terms), not an OSS license.
6
- */import c from"tweetnacl";import{SESSION_TOKEN_PUBLIC_KEY as m}from"./config.js";import{realNow as T}from"./realNow.js";export const SESSION_TOKEN_PREFIX="buoys1";const v="buoy-session-v1:";const y=1;export const SESSION_CLOCK_SKEW_SECONDS=60;const _=64;const N=["free","pro","business"];const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";export function base64urlEncode(t){let e="";let r=0;for(;r+2<t.length;r+=3){const n=t[r]<<16|t[r+1]<<8|t[r+2];e+=s[n>>>18&63]+s[n>>>12&63]+s[n>>>6&63]+s[n&63]}const o=t.length-r;if(o===1){const n=t[r]<<16;e+=s[n>>>18&63]+s[n>>>12&63]}else if(o===2){const n=t[r]<<16|t[r+1]<<8;e+=s[n>>>18&63]+s[n>>>12&63]+s[n>>>6&63]}return e}function g(t){if(!/^[A-Za-z0-9_-]*$/.test(t)||t.length%4===1)return null;const e=[];let r=0;let o=0;for(const n of t){o=o<<6|s.indexOf(n);r+=6;if(r>=8){e.push(o>>>r-8&255);r-=8}}return new Uint8Array(e)}function h(t){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(t);const e=unescape(encodeURIComponent(t));const r=new Uint8Array(e.length);for(let o=0;o<e.length;o+=1)r[o]=e.charCodeAt(o);return r}function O(t){try{if(typeof TextDecoder!=="undefined")return new TextDecoder("utf-8",{fatal:true}).decode(t);let e="";for(const r of t)e+=String.fromCharCode(r);return decodeURIComponent(escape(e))}catch{return null}}function S(t){const e=t.trim().toLowerCase();const r=new Uint8Array(e.length/2);for(let o=0;o<r.length;o+=1)r[o]=parseInt(e.slice(o*2,o*2+2),16);return r}function k(t){return h(v+t)}function l(t,e=256){return typeof t==="string"&&t.length>0&&t.length<=e}function x(t){return typeof t==="number"&&Number.isInteger(t)&&t>0}function C(t){if(!t||typeof t!=="object"||Array.isArray(t))return null;const e=t;if(!l(e.sid)||!l(e.sub)||!l(e.aud,512))return null;if(e.team!==null&&!l(e.team))return null;if(!N.includes(e.tier))return null;if(e.role!==void 0&&!l(e.role,64))return null;if(e.tools!==void 0&&(!Array.isArray(e.tools)||e.tools.length>256||!e.tools.every(r=>l(r,64)))){return null}if(!x(e.iat)||!x(e.exp)||e.exp<=e.iat)return null;return{v:y,sid:e.sid,sub:e.sub,team:e.team,tier:e.tier,...e.role!==void 0?{role:e.role}:{},...e.tools!==void 0?{tools:[...e.tools]}:{},aud:e.aud,iat:e.iat,exp:e.exp}}export function mintSessionToken(t,e){const r=base64urlEncode(h(JSON.stringify(t)));const{secretKey:o}=c.sign.keyPair.fromSeed(S(e));const n=c.sign.detached(k(r),o);return`${SESSION_TOKEN_PREFIX}.${r}.${base64urlEncode(n)}`}let b=m;export function __setSessionTokenPublicKeyForTests(t){b=t??m}export function isSessionToken(t){return t.startsWith(`${SESSION_TOKEN_PREFIX}.`)}export function verifySessionToken(t,e){const r=e.publicKeyHex??b;if(!r)return{ok:false,reason:"no-key"};const o=typeof t==="string"?t.split("."):[];if(o.length!==3||o[0]!==SESSION_TOKEN_PREFIX)return{ok:false,reason:"malformed"};const[,n,E]=o;const a=g(n);const f=g(E);if(!a||!f||f.length!==_)return{ok:false,reason:"malformed"};try{if(!c.sign.detached.verify(k(n),f,S(r))){return{ok:false,reason:"signature"}}}catch{return{ok:false,reason:"signature"}}const d=O(a);let i;try{i=d===null?null:JSON.parse(d)}catch{return{ok:false,reason:"malformed"}}if(!i||typeof i!=="object"||i.v!==y){return{ok:false,reason:i&&typeof i==="object"?"version":"malformed"}}const u=C(i);if(!u)return{ok:false,reason:"claims"};if(u.aud!==e.audience)return{ok:false,reason:"audience"};if(e.ignoreTime)return{ok:true,claims:u};const p=Math.floor((e.nowMs??T())/1e3);if(p>=u.exp+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"expired"};if(u.iat>p+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"not-yet-valid"};return{ok:true,claims:u}}
6
+ */import a from"tweetnacl";import{SESSION_TOKEN_PUBLIC_KEY as E}from"./sessionTokenKey.js";import{realNow as b}from"./realNow.js";export const SESSION_TOKEN_PREFIX="buoys1";const v="buoy-session-v1:";const m=1;export const SESSION_CLOCK_SKEW_SECONDS=60;const C=64;const N=["free","pro","business"];const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";export function base64urlEncode(t){let e="";let r=0;for(;r+2<t.length;r+=3){const n=t[r]<<16|t[r+1]<<8|t[r+2];e+=s[n>>>18&63]+s[n>>>12&63]+s[n>>>6&63]+s[n&63]}const o=t.length-r;if(o===1){const n=t[r]<<16;e+=s[n>>>18&63]+s[n>>>12&63]}else if(o===2){const n=t[r]<<16|t[r+1]<<8;e+=s[n>>>18&63]+s[n>>>12&63]+s[n>>>6&63]}return e}function y(t){if(!/^[A-Za-z0-9_-]*$/.test(t)||t.length%4===1)return null;const e=[];let r=0;let o=0;for(const n of t){o=o<<6|s.indexOf(n);r+=6;if(r>=8){e.push(o>>>r-8&255);r-=8}}return new Uint8Array(e)}function g(t){if(typeof TextEncoder!=="undefined")return new TextEncoder().encode(t);const e=unescape(encodeURIComponent(t));const r=new Uint8Array(e.length);for(let o=0;o<e.length;o+=1)r[o]=e.charCodeAt(o);return r}function O(t){try{if(typeof TextDecoder!=="undefined")return new TextDecoder("utf-8",{fatal:true}).decode(t);let e="";for(const r of t)e+=String.fromCharCode(r);return decodeURIComponent(escape(e))}catch{return null}}function h(t){const e=t.trim().toLowerCase();const r=new Uint8Array(e.length/2);for(let o=0;o<r.length;o+=1)r[o]=parseInt(e.slice(o*2,o*2+2),16);return r}function S(t){return g(v+t)}function l(t,e=256){return typeof t==="string"&&t.length>0&&t.length<=e}function k(t){return typeof t==="number"&&Number.isInteger(t)&&t>0}function T(t){if(!t||typeof t!=="object"||Array.isArray(t))return null;const e=t;if(!l(e.sid)||!l(e.sub)||!l(e.aud,512))return null;if(e.team!==null&&!l(e.team))return null;if(!N.includes(e.tier))return null;if(e.role!==void 0&&!l(e.role,64))return null;if(e.tools!==void 0&&(!Array.isArray(e.tools)||e.tools.length>256||!e.tools.every(r=>l(r,64)))){return null}if(!k(e.iat)||!k(e.exp)||e.exp<=e.iat)return null;return{v:m,sid:e.sid,sub:e.sub,team:e.team,tier:e.tier,...e.role!==void 0?{role:e.role}:{},...e.tools!==void 0?{tools:[...e.tools]}:{},aud:e.aud,iat:e.iat,exp:e.exp}}export function mintSessionToken(t,e){const r=base64urlEncode(g(JSON.stringify(t)));const{secretKey:o}=a.sign.keyPair.fromSeed(h(e));const n=a.sign.detached(S(r),o);return`${SESSION_TOKEN_PREFIX}.${r}.${base64urlEncode(n)}`}const A=E;export function isSessionToken(t){return t.startsWith(`${SESSION_TOKEN_PREFIX}.`)}export function verifySessionToken(t,e){const r=A;if(!r)return{ok:false,reason:"no-key"};const o=typeof t==="string"?t.split("."):[];if(o.length!==3||o[0]!==SESSION_TOKEN_PREFIX)return{ok:false,reason:"malformed"};const[,n,x]=o;const c=y(n);const f=y(x);if(!c||!f||f.length!==C)return{ok:false,reason:"malformed"};try{if(!a.sign.detached.verify(S(n),f,h(r))){return{ok:false,reason:"signature"}}}catch{return{ok:false,reason:"signature"}}const d=O(c);let i;try{i=d===null?null:JSON.parse(d)}catch{return{ok:false,reason:"malformed"}}if(!i||typeof i!=="object"||i.v!==m){return{ok:false,reason:i&&typeof i==="object"?"version":"malformed"}}const u=T(i);if(!u)return{ok:false,reason:"claims"};if(u.aud!==e.audience)return{ok:false,reason:"audience"};if(e.ignoreTime)return{ok:true,claims:u};const p=Math.floor((e.nowMs??b())/1e3);if(p>=u.exp+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"expired"};if(u.iat>p+SESSION_CLOCK_SKEW_SECONDS)return{ok:false,reason:"not-yet-valid"};return{ok:true,claims:u}}
@@ -0,0 +1,6 @@
1
+ "use strict";/*!
2
+ * PROPRIETARY — Buoy Pro license enforcement. NOT open source.
3
+ *
4
+ * Copyright (c) Buoy. All rights reserved. Licensed under the Buoy EULA
5
+ * (https://buoy.gg/terms), not an OSS license.
6
+ */export const SESSION_TOKEN_PUBLIC_KEY="36abba0267f7f379d992a5b6df641daab4190bcc9e639e36f1378e3c1ac52746";