@buoy-gg/license 7.0.68 → 7.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DESKTOP_AUDIENCE=exports.CLI_AUDIENCE=void 0;exports.createNodeSession=createNodeSession;exports.defaultSessionFile=defaultSessionFile;exports.fileLock=fileLock;exports.fileSessionStorage=fileSessionStorage;exports.receiveCodeOnLoopback=receiveCodeOnLoopback;var _nodeHttp=_interopRequireDefault(require("node:http"));var _nodeCrypto=require("node:crypto");var _nodeFs=require("node:fs");var _nodePath=require("node:path");var _nodeOs=require("node:os");var _sessionManager=require("./sessionManager.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}/*!
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.WEB_EXTENSION_AUDIENCE=exports.DESKTOP_AUDIENCE=exports.CLI_AUDIENCE=void 0;exports.createNodeSession=createNodeSession;exports.defaultSessionFile=defaultSessionFile;exports.fileLock=fileLock;exports.fileSessionStorage=fileSessionStorage;exports.receiveCodeOnLoopback=receiveCodeOnLoopback;var _nodeHttp=_interopRequireDefault(require("node:http"));var _nodeCrypto=require("node:crypto");var _nodeFs=require("node:fs");var _nodePath=require("node:path");var _nodeOs=require("node:os");var _sessionManager=require("./sessionManager.js");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}/*!
2
2
  * PROPRIETARY — Buoy 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 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)}}
6
+ */const DESKTOP_AUDIENCE=exports.DESKTOP_AUDIENCE="app:gg.buoy.desktop";const CLI_AUDIENCE=exports.CLI_AUDIENCE="app:gg.buoy.cli";const WEB_EXTENSION_AUDIENCE=exports.WEB_EXTENSION_AUDIENCE="app:gg.buoy.web";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 o=JSON.parse(await _nodeFs.promises.readFile(e,"utf8"));return o&&typeof o==="object"?o:{}}catch{return{}}};const u=async o=>{await _nodeFs.promises.mkdir((0,_nodePath.dirname)(e),{recursive:true,mode:448});if(Object.keys(o).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(o),{mode:384});await _nodeFs.promises.rename(i,e)};return{async getItem(o){return(await r())[o]??null},async setItem(o,i){const d=await r();d[o]=i;await u(d)},async removeItem(o){const i=await r();if(!(o in i))return;delete i[o];await u(i)}}}function fileLock(e,r={}){const u=r.staleMs??LOCK_STALE_MS;const o=r.waitMs??LOCK_WAIT_MS;return async(i,d)=>{const a=`${process.pid}:${(0,_nodeCrypto.randomBytes)(8).toString("hex")}`;const p=Date.now()+o;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(n=>setTimeout(n,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 o=Buffer.from(r);return u.length===o.length&&(0,_nodeCrypto.timingSafeEqual)(u,o)}async function receiveCodeOnLoopback(e,r,u,o={}){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 g="";c.on("data",E=>{g+=E;if(g.length>MAX_BODY_BYTES)c.destroy()});c.on("end",()=>{let E=null;try{E=JSON.parse(g)}catch{}if(!E||typeof E.state!=="string"||!safeEqual(E.state,r))return void l.writeHead(400).end();l.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof E.code==="string"&&E.code)n(()=>i(E.code));else n(()=>d(new _sessionManager.SessionError("access_denied","Sign-in was cancelled.")))})});const t=setTimeout(()=>n(()=>d(new _sessionManager.SessionError("timeout","Sign-in took too long."))),o.timeoutMs??LOGIN_TIMEOUT_MS);t.unref?.();const s=()=>n(()=>d(new _sessionManager.SessionError("popup_closed","Sign-in was cancelled.")));o.signal?.addEventListener("abort",s);function n(c){clearTimeout(t);o.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"){n(()=>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 o=(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 n=setTimeout(t,Math.min(s,2147483647));n.unref?.();return n},clearTimer:t=>clearTimeout(t)};const a=new _sessionManager.SessionManagerImpl(d);a.configure({audience:e.audience,signinOrigin:o});const p=async()=>{let t;try{t=await i(`${o}/api/auth/status`,{method:"GET",headers:{},signal:AbortSignal.timeout(STATUS_TIMEOUT_MS)})}catch(n){const f=describeFetchError(n);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,n)=>{const{url:f,code:c}=await receiveCodeOnLoopback(s,n,o,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(`${o}/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 n=await s.json().catch(()=>null);if(s.status===200&&typeof n?.dev_token==="string"){return{ok:true,token:n.dev_token,tier:typeof n.tier==="string"?n.tier:"free"}}return{ok:false,detail:typeof n?.error_description==="string"?n.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)}}
@@ -15,4 +15,4 @@
15
15
  * Pro is $9/mo, and is free every weekend for anyone holding a key —
16
16
  * including a free one (`npx buoy login`). Buy a key at
17
17
  * https://buoy.gg or use it free on Saturday and Sunday.
18
- */function isWeekendFreePro(r=new Date((0,_realNow.realNow)())){const e=r.getDay();return e===0||e===6}function useWeekendFreePro(){const[r,e]=(0,_react.useState)(()=>isWeekendFreePro());(0,_react.useEffect)(()=>{const s=setInterval(()=>{const t=isWeekendFreePro();e(n=>n===t?n:t)},60*1e3);return()=>clearInterval(s)},[]);return r}function weekendPassAppliesTo(r,e){return e&&r}
18
+ */function isWeekendFreePro(r=new Date((0,_realNow.realNow)())){if(globalThis.__buoyWeekendPassOff===true)return false;const e=r.getDay();return e===0||e===6}function useWeekendFreePro(){const[r,e]=(0,_react.useState)(()=>isWeekendFreePro());(0,_react.useEffect)(()=>{const n=setInterval(()=>{const t=isWeekendFreePro();e(s=>s===t?s:t)},60*1e3);return()=>clearInterval(n)},[]);return r}function weekendPassAppliesTo(r,e){return e&&r}
@@ -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 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)}}
6
+ */import S 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 E,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";export const WEB_EXTENSION_AUDIENCE="app:gg.buoy.web";const A=5*60*1e3;const I=4096;const C=6e4;const N=3e4;const v=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 U(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(E(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??C;const n=r.waitMs??N;return async(i,l)=>{const s=`${process.pid}:${y(8).toString("hex")}`;const p=Date.now()+n;await f.mkdir(E(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 H(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=S.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 w="";c.on("data",g=>{w+=g;if(w.length>I)c.destroy()});c.on("end",()=>{let g=null;try{g=JSON.parse(w)}catch{}if(!g||typeof g.state!=="string"||!H(g.state,r))return void d.writeHead(400).end();d.writeHead(200,{"Content-Type":"application/json"}).end('{"ok":true}');if(typeof g.code==="string"&&g.code)o(()=>i(g.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)};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(v)})}catch(o){const m=U(o);return P.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)}}
@@ -15,4 +15,4 @@
15
15
  * Pro is $9/mo, and is free every weekend for anyone holding a key —
16
16
  * including a free one (`npx buoy login`). Buy a key at
17
17
  * https://buoy.gg or use it free on Saturday and Sunday.
18
- */import{useEffect as s,useState as a}from"react";import{realNow as c}from"./realNow.js";export function isWeekendFreePro(t=new Date(c())){const e=t.getDay();return e===0||e===6}export function useWeekendFreePro(){const[t,e]=a(()=>isWeekendFreePro());s(()=>{const o=setInterval(()=>{const r=isWeekendFreePro();e(n=>n===r?n:r)},60*1e3);return()=>clearInterval(o)},[]);return t}export function weekendPassAppliesTo(t,e){return e&&t}
18
+ */import{useEffect as o,useState as a}from"react";import{realNow as u}from"./realNow.js";export function isWeekendFreePro(t=new Date(u())){if(globalThis.__buoyWeekendPassOff===true)return false;const e=t.getDay();return e===0||e===6}export function useWeekendFreePro(){const[t,e]=a(()=>isWeekendFreePro());o(()=>{const n=setInterval(()=>{const r=isWeekendFreePro();e(s=>s===r?s:r)},60*1e3);return()=>clearInterval(n)},[]);return t}export function weekendPassAppliesTo(t,e){return e&&t}
@@ -8,6 +8,8 @@ import { SessionManagerImpl, type SessionDeps, type SessionStatus } from "./sess
8
8
  /** First-party app ids buoy.gg signs in without a site list. Keep in step with apps/website signin.server.ts. */
9
9
  export declare const DESKTOP_AUDIENCE = "app:gg.buoy.desktop";
10
10
  export declare const CLI_AUDIENCE = "app:gg.buoy.cli";
11
+ /** The Buoy Web Chrome extension (its Ask Buoy panel signs in with a code). */
12
+ export declare const WEB_EXTENSION_AUDIENCE = "app:gg.buoy.web";
11
13
  /**
12
14
  * Whether buoy.gg has sign-in on. "unreachable" is kept apart from
13
15
  * "disabled": a VPN or proxy that lets the browser through but not Node lands
@@ -8,6 +8,8 @@ import { SessionManagerImpl, type SessionDeps, type SessionStatus } from "./sess
8
8
  /** First-party app ids buoy.gg signs in without a site list. Keep in step with apps/website signin.server.ts. */
9
9
  export declare const DESKTOP_AUDIENCE = "app:gg.buoy.desktop";
10
10
  export declare const CLI_AUDIENCE = "app:gg.buoy.cli";
11
+ /** The Buoy Web Chrome extension (its Ask Buoy panel signs in with a code). */
12
+ export declare const WEB_EXTENSION_AUDIENCE = "app:gg.buoy.web";
11
13
  /**
12
14
  * Whether buoy.gg has sign-in on. "unreachable" is kept apart from
13
15
  * "disabled": a VPN or proxy that lets the browser through but not Node lands
package/lib/web/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- "use client";import{a as k,b as S,c as y,d as A,e as L,f as b,g as P,h as v,i as h,j as I,k as E,l as K,m as z,n as w,o as T,p as B,q as D,r as F,s as N}from"./chunks/chunk-D5RC3UOG.mjs";import{a as M,b as W,c as j,d as H,e as O,f as Q,g as n,h as V,i as q,j as x,k as f,l as G,m as t}from"./chunks/chunk-OP6QSLZS.mjs";import{b as J,c as R,d as U,e as X}from"./chunks/chunk-J7MW3NXU.mjs";import{useEffect as Y,useState as Z}from"react";function l(s=new Date(M())){let e=s.getDay();return e===0||e===6}function p(){let[s,e]=Z(()=>l());return Y(()=>{let r=setInterval(()=>{let a=l();e(i=>i===a?i:a)},6e4);return()=>clearInterval(r)},[]),s}function g(s,e){return e&&s}import{useState as d,useEffect as C,useCallback as u}from"react";function c(){let[s,e]=d(t.getState());C(()=>{let i=t.subscribe(o=>{e(t.getState())});return t.initialize().then(()=>{e(t.getState())}),i},[]);let r=u(async i=>{let o=await t.setLicenseKey(i,{force:true});return e(t.getState()),o},[]),a=u(async()=>{await t.clearLicense(),e(t.getState())},[]);return{...s,setLicenseKey:r,clearLicense:a}}function _(){return c().access}function $(){let{tier:s,isInitialized:e}=c();return e?s:"free"}function ee(s){let{isPro:e,isInitialized:r,isValidating:a}=c();return{hasAccess:e,isPro:e,isLoading:!r||a}}function se(){let{isPro:s,isInitialized:e,access:r}=c(),a=g(r.status==="admitted",p());return e&&s||a}function ae(){let{isPro:s,isInitialized:e,access:r}=c(),a=e&&s,i=g(r.status==="admitted",p())&&!a;return{isPro:a||i,isLicensed:a,isWeekendFree:i,reason:a?"licensed":i?"weekend":null}}function te(){let[s,e]=d(()=>n.getStatus());C(()=>{let i=()=>e(n.getStatus()),o=n.subscribe(i);return n.load().then(i,i),o},[]);let r=u(()=>n.signIn(),[]),a=u(()=>n.signOut(),[]);return{status:s,signIn:r,signOut:a}}function ie(){let s=n.getAccessToken();if(s)return{token:s,origin:n.origin};let e=t.getState().licenseKey;return e&&f(e)&&t.hasAccountAccess()&&G(e).ok?{token:e,origin:n.origin}:null}async function re(s){let{LicenseManager:e}=await import("./chunks/LicenseManager-G4PF6ILL.mjs");return await e.initialize(),e.setLicenseKey(s)}function m(){return g(t.hasAccountAccess(),l())}function ne(){return t.isPro()?true:m()}function ce(s){return t.hasEntitlement(s)?true:m()}export{t as LicenseManager,W as LicenseTransportError,Q as SessionError,n as SessionManager,E as callCapacitorAsApp,I as callCapacitorNative,K as callCapacitorNativeCallback,U as capacitorDebug,v as capacitorListenerCount,R as capacitorPlatform,D as capacitorPlugin,T as clearCapacitorCalls,y as colorSchemeQueryValue,P as emitCapacitorEvent,N as getCapacitorAppHost,w as getCapacitorCalls,A as getColorSchemeQueries,ie as getSyncCredential,h as hasCapacitorPlugin,ce as hasEntitlement,S as installCapacitorBridge,b as interceptCapacitor,H as isBuoyToken,L as isCapacitorBridgeInstalled,J as isCapacitorNative,f as isDevToken,ne as isPro,V as isServiceKey,j as isTransientLicenseError,l as isWeekendFreePro,z as listenCapacitorNative,F as loadCapacitorAppHost,k as makeCapacitorCallbackId,q as normalizeLicenseKey,O as resolveAccountAccess,X as resolveDevBuild,x as sameLicenseKey,re as setLicenseKey,B as subscribeCapacitorCalls,_ as useAccountAccess,te as useBuoySession,ee as useFeatureAccess,se as useIsPro,c as useLicense,ae as useProAccess,$ as useTier,p as useWeekendFreePro};/*!
1
+ "use client";import{a as k,b as y,c as A,d as S,e as L,f as P,g as b,h,i as v,j as I,k as E,l as K,m as z,n as T,o as w,p as B,q as D,r as F,s as N}from"./chunks/chunk-D5RC3UOG.mjs";import{a as W,b as M,c as O,d as j,e as x,f as H,g as n,h as Q,i as V,j as _,k as f,l as q,m as t}from"./chunks/chunk-OP6QSLZS.mjs";import{b as G,c as J,d as R,e as U}from"./chunks/chunk-J7MW3NXU.mjs";import{useEffect as X,useState as Y}from"react";function l(s=new Date(W())){if(globalThis.__buoyWeekendPassOff===true)return false;let e=s.getDay();return e===0||e===6}function p(){let[s,e]=Y(()=>l());return X(()=>{let r=setInterval(()=>{let a=l();e(i=>i===a?i:a)},6e4);return()=>clearInterval(r)},[]),s}function g(s,e){return e&&s}import{useState as d,useEffect as C,useCallback as u}from"react";function c(){let[s,e]=d(t.getState());C(()=>{let i=t.subscribe(o=>{e(t.getState())});return t.initialize().then(()=>{e(t.getState())}),i},[]);let r=u(async i=>{let o=await t.setLicenseKey(i,{force:true});return e(t.getState()),o},[]),a=u(async()=>{await t.clearLicense(),e(t.getState())},[]);return{...s,setLicenseKey:r,clearLicense:a}}function Z(){return c().access}function $(){let{tier:s,isInitialized:e}=c();return e?s:"free"}function ee(s){let{isPro:e,isInitialized:r,isValidating:a}=c();return{hasAccess:e,isPro:e,isLoading:!r||a}}function se(){let{isPro:s,isInitialized:e,access:r}=c(),a=g(r.status==="admitted",p());return e&&s||a}function ae(){let{isPro:s,isInitialized:e,access:r}=c(),a=e&&s,i=g(r.status==="admitted",p())&&!a;return{isPro:a||i,isLicensed:a,isWeekendFree:i,reason:a?"licensed":i?"weekend":null}}function te(){let[s,e]=d(()=>n.getStatus());C(()=>{let i=()=>e(n.getStatus()),o=n.subscribe(i);return n.load().then(i,i),o},[]);let r=u(()=>n.signIn(),[]),a=u(()=>n.signOut(),[]);return{status:s,signIn:r,signOut:a}}function ie(){let s=n.getAccessToken();if(s)return{token:s,origin:n.origin};let e=t.getState().licenseKey;return e&&f(e)&&t.hasAccountAccess()&&q(e).ok?{token:e,origin:n.origin}:null}async function re(s){let{LicenseManager:e}=await import("./chunks/LicenseManager-G4PF6ILL.mjs");return await e.initialize(),e.setLicenseKey(s)}function m(){return g(t.hasAccountAccess(),l())}function ne(){return t.isPro()?true:m()}function ce(s){return t.hasEntitlement(s)?true:m()}export{t as LicenseManager,M as LicenseTransportError,H as SessionError,n as SessionManager,E as callCapacitorAsApp,I as callCapacitorNative,K as callCapacitorNativeCallback,R as capacitorDebug,h as capacitorListenerCount,J as capacitorPlatform,D as capacitorPlugin,w as clearCapacitorCalls,A as colorSchemeQueryValue,b as emitCapacitorEvent,N as getCapacitorAppHost,T as getCapacitorCalls,S as getColorSchemeQueries,ie as getSyncCredential,v as hasCapacitorPlugin,ce as hasEntitlement,y as installCapacitorBridge,P as interceptCapacitor,j as isBuoyToken,L as isCapacitorBridgeInstalled,G as isCapacitorNative,f as isDevToken,ne as isPro,Q as isServiceKey,O as isTransientLicenseError,l as isWeekendFreePro,z as listenCapacitorNative,F as loadCapacitorAppHost,k as makeCapacitorCallbackId,V as normalizeLicenseKey,x as resolveAccountAccess,U as resolveDevBuild,_ as sameLicenseKey,re as setLicenseKey,B as subscribeCapacitorCalls,Z as useAccountAccess,te as useBuoySession,ee as useFeatureAccess,se as useIsPro,c as useLicense,ae as useProAccess,$ as useTier,p as useWeekendFreePro};/*!
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/license",
3
- "version": "7.0.68",
3
+ "version": "7.0.70",
4
4
  "description": "License validation for React Buoy Pro features",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "main": "lib/commonjs/index.js",