@stacknet/keyutils 0.5.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- 'use strict';var react=require('react');require('react/jsx-runtime');var ne=react.createContext(null);function y(){let e=react.useContext(ne);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function se(e,n){if(typeof e!="string"||e.length===0)return n;let t=e.replace(/[\u0000-\u001F\u007F]/g," ");return t.length>500?t.slice(0,500)+"\u2026":t}async function p(e,n){try{let t=await e.json();if(t&&typeof t=="object"&&"error"in t)return se(t.error,n)}catch{}return n}function ie(){let{config:e}=y(),[n,t]=react.useState(null),[f,d]=react.useState(true),[m,u]=react.useState(null),i=react.useRef(true),o=react.useRef(e.apiBaseUrl);o.current=e.apiBaseUrl;let a=async()=>{try{i.current&&(d(!0),u(null));let s=await fetch(`${o.current}/api/keys/pricing`,{credentials:"include"});if(!s.ok)throw new Error(await p(s,`Pricing unavailable (${s.status})`));let r=await s.json();i.current&&t(r);}catch(s){i.current&&u(s instanceof Error?s.message:"Failed to fetch pricing");}finally{i.current&&d(false);}};return react.useEffect(()=>{i.current=true,a();let s=setInterval(a,6e4);return ()=>{i.current=false,clearInterval(s);}},[]),{pricing:n,loading:f,error:m,refresh:a}}function ue(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key:e.id||e.key||e.keyPrefix||"",userId:e.userId||e.user_id||"",status:e.status||"active",tokenBalance:e.tokenBalance??e.currentTokenBalance??e.current_token_balance??0,maxTokens:e.maxTokens??e.initialTokenBalance??e.initial_token_balance??0,createdAt:String(e.createdAt??e.created_at??""),expiresAt:e.expiresAt,label:e.label||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function fe(){let{config:e}=y(),[n,t]=react.useState([]),[f,d]=react.useState(true),[m,u]=react.useState(null),i=react.useRef(true),o=e.apiBaseUrl,a=react.useCallback(async()=>{try{d(!0),u(null);let r=await fetch(`${o}/api/keys`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to fetch keys (${r.status})`));let c=await r.json(),l=Array.isArray(c)?c:c.keys??[];i.current&&t(l.map(ue));}catch(r){i.current&&u(r instanceof Error?r.message:"Failed to fetch keys");}finally{i.current&&d(false);}},[o]);react.useEffect(()=>(i.current=true,a(),()=>{i.current=false;}),[a]);let s=n.reduce((r,c)=>r+c.tokenBalance,0);return {keys:n,totalBalance:s,loading:f,error:m,refresh:a}}var N=false;function k(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);if(!e)return N||(N=true,console.warn("[keyutils] __csrf cookie not found; mutations will be sent without a CSRF token")),{};let n=e[1];try{n=decodeURIComponent(n);}catch{}return {"x-csrf-token":n}}function _(e){let n=e.type||e.entry_type||"debit",t=e.amount??e.tokens??e.token_amount??0,f=e.description||e.memo||e.reason||de(n);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:n,amount:t,description:f,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function de(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function ge(e){let{config:n}=y(),[t,f]=react.useState([]),[d,m]=react.useState(false),[u,i]=react.useState(null),o=react.useRef(true),a=n.apiBaseUrl,s=react.useCallback(async()=>{if(e)try{m(!0),i(null);let r=await fetch(`${a}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to fetch ledger (${r.status})`));let c=await r.json(),l=Array.isArray(c)?c:c.entries??[];o.current&&f(l.map(_));}catch(r){o.current&&i(r instanceof Error?r.message:"Failed to fetch ledger");}finally{o.current&&m(false);}},[a,e]);return react.useEffect(()=>(o.current=true,s(),()=>{o.current=false;}),[s]),{entries:t,loading:d,error:u,refresh:s}}function he(){let{config:e,callbacks:n}=y(),[t,f]=react.useState(false),[d,m]=react.useState(null),[u,i]=react.useState(null);return {mint:react.useCallback(async(a,s,r=1)=>{try{f(!0),i(null),n.onPaymentComplete?.(a,s);let c=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({paymentMethod:a,paymentRef:s,quantity:r,stackId:e.stackId})});if(!c.ok)throw new Error(await p(c,`Key generation failed (${c.status})`));let l=await c.json(),g=l.keys?.[0]||l,h={success:!0,key:{id:g.keyId||g.id||"",key:g.key||"",userId:g.userId||"",status:"active",tokenBalance:g.tokenBalance??g.currentTokenBalance??0,maxTokens:g.initialTokenBalance??g.tokenBalance??0,createdAt:String(g.createdAt||Date.now())},transactionId:s};return m(h),n.onMintSuccess?.(h),h}catch(c){let l=c instanceof Error?c:new Error("Key generation failed");return i(l.message),n.onMintError?.(l),{success:false,error:l.message}}finally{f(false);}},[e.apiBaseUrl,n]),minting:t,result:d,error:u}}function Pe(){let{config:e,callbacks:n}=y(),[t,f]=react.useState(false),[d,m]=react.useState(null),[u,i]=react.useState(null),o=react.useRef(true),a=react.useCallback(async(r,c)=>{try{f(!0),i(null);let l=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({askPriceCents:c,stackId:e.stackId,stackName:e.stackName})});if(!l.ok)throw new Error(await p(l,`Listing failed (${l.status})`));let g=await l.json();return o.current&&(m(g),n.onListingCreated?.(g)),g}catch(l){let g=l instanceof Error?l.message:"Listing failed";return o.current&&i(g),null}finally{o.current&&f(false);}},[e.apiBaseUrl,e.stackId,e.stackName,n]),s=react.useCallback(async r=>{try{f(!0),i(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/list`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!c.ok)throw new Error(await p(c,`Delist failed (${c.status})`));return o.current&&m(null),!0}catch(c){let l=c instanceof Error?c.message:"Delist failed";return o.current&&i(l),false}finally{o.current&&f(false);}},[e.apiBaseUrl]);return {listKey:a,delistKey:s,listing:t,result:d,error:u}}function we(){let{config:e}=y(),[n,t]=react.useState(false),[f,d]=react.useState(null),m=react.useRef(true);return {createSession:react.useCallback(async(i,o)=>{try{t(!0),d(null);let a=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({priceCents:i,quantity:o,stackId:e.stackId,referrerUrl:window.location.href})});if(!a.ok)throw new Error(await p(a,`Checkout failed (${a.status})`));let{url:s}=await a.json();if(!s)throw new Error("No checkout URL returned");let r;try{r=new URL(s);}catch{throw new Error("Invalid checkout URL")}if(r.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(r.hostname))throw new Error("Refusing to redirect to non-Stripe URL");try{sessionStorage.setItem("keyutils_stripe_pending","1"),sessionStorage.setItem("keyutils_stripe_quantity",String(o));}catch{}window.location.href=r.toString();}catch(a){if(m.current){let s=a instanceof Error?a.message:"Checkout failed";d(s),t(false);}}},[e.apiBaseUrl,e.stackId]),loading:n,error:f}}function O(e,n="#"){if(!e||typeof e!="string")return n;let t=e.trim();if(t===""||t==="#")return n;if(t.startsWith("/")||t.startsWith("./")||t.startsWith("../"))return t;try{let f=new URL(t);if(f.protocol==="http:"||f.protocol==="https:")return f.toString()}catch{}return n}var W=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function Ce(){let{config:e}=y(),[n,t]=react.useState(false),[f,d]=react.useState(null);return {pay:react.useCallback(async u=>{if(!e.merchantWallet||!W.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{t(!0),d(null);let{Connection:i,PublicKey:o,Transaction:a,SystemProgram:s}=await import('@solana/web3.js'),r=typeof window<"u"?window.solana:void 0;if(!r||typeof r!="object"||!r.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let c=r,l=new o(e.merchantWallet),g=await c.connect(),h=new o(g.publicKey.toString()),M="https://api.mainnet-beta.solana.com",$=O(e.solanaRpcUrl,M),X=$==="#"?M:$,Y=new i(X),{blockhash:Z}=await Y.getLatestBlockhash(),P=BigInt(Math.floor(u*1e9)),b=e.protocolTreasuryWallet,F=e.protocolFeeBps??500,U=new a({recentBlockhash:Z,feePayer:h});if(b&&W.test(b)&&F>0){let A=P*BigInt(F)/10000n,Q=P-A,ee=new o(b);U.add(s.transfer({fromPubkey:h,toPubkey:l,lamports:Number(Q)}),s.transfer({fromPubkey:h,toPubkey:ee,lamports:Number(A)}));}else U.add(s.transfer({fromPubkey:h,toPubkey:l,lamports:Number(P)}));let{signature:G}=await c.signAndSendTransaction(U);return G}catch(i){let o=i instanceof Error?i:new Error("SOL payment failed");throw d(o.message),o}finally{t(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:n,error:f}}function xe(){let{config:e,callbacks:n}=y(),[t,f]=react.useState(false),[d,m]=react.useState(null),[u,i]=react.useState(null),o=react.useRef(true);return {transferKey:react.useCallback(async(s,r)=>{try{f(!0),i(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(s)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({recipientId:r})});if(!c.ok)throw new Error(await p(c,`Transfer failed (${c.status})`));let l=await c.json();return o.current&&(m(l),n.onTransferComplete?.(l)),l}catch(c){let l=c instanceof Error?c.message:"Transfer failed";return o.current&&i(l),null}finally{o.current&&f(false);}},[e.apiBaseUrl,n]),transferring:t,result:d,error:u}}function Le(){let{config:e,callbacks:n}=y(),[t,f]=react.useState(false),[d,m]=react.useState(null),[u,i]=react.useState(null),o=react.useRef(true);react.useEffect(()=>(o.current=true,()=>{o.current=false;}),[]);let a=react.useCallback(async(r,c)=>{try{f(!0),i(null);let l={stackId:e.stackId};c&&(l.payoutMethod=c);let g=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify(l)});if(!g.ok)throw new Error(await p(g,`Filing failed (${g.status})`));let h=await g.json();return o.current&&(m(h),n.onFilingComplete?.(h)),h}catch(l){let g=l instanceof Error?l:new Error("Filing failed");return o.current&&i(g.message),n.onFilingError?.(g),null}finally{o.current&&f(false);}},[e.apiBaseUrl,e.stackId,n]),s=react.useCallback(()=>{m(null),i(null);},[]);return {filePaperwork:a,filing:t,result:d,error:u,reset:s}}function Fe(){let{config:e}=y(),[n,t]=react.useState([]),[f,d]=react.useState(true),[m,u]=react.useState(null),i=react.useRef(true),o=e.apiBaseUrl,a=react.useCallback(async()=>{try{d(!0),u(null);let s=await fetch(`${o}/api/keys/filings`,{credentials:"include"});if(!s.ok)throw new Error(await p(s,`Failed to fetch filings (${s.status})`));let r=await s.json(),c=Array.isArray(r)?r:r.filings??[];i.current&&t(c);}catch(s){i.current&&u(s instanceof Error?s.message:"Failed to fetch filings");}finally{i.current&&d(false);}},[o]);return react.useEffect(()=>(i.current=true,a(),()=>{i.current=false;}),[a]),{entries:n,loading:f,error:m,refresh:a}}function _e(e){let{config:n}=y(),t=e??n.stackId,f=n.apiBaseUrl,[d,m]=react.useState(null),[u,i]=react.useState(!!t),[o,a]=react.useState(null),s=react.useRef(true),r=react.useCallback(async()=>{if(!t){m(null),i(false);return}try{i(!0),a(null);let c=await fetch(`${f}/api/stacks/${encodeURIComponent(t)}/payout-capabilities`,{credentials:"include"});if(!c.ok)throw new Error(await p(c,`Failed to load payout capabilities (${c.status})`));let l=await c.json();s.current&&m(l);}catch(c){s.current&&a(c instanceof Error?c.message:"Failed to load payout capabilities");}finally{s.current&&i(false);}},[f,t]);return react.useEffect(()=>(s.current=true,r(),()=>{s.current=false;}),[r]),{caps:d,loading:u,error:o,refresh:r}}var je=5e3;function We(e){return e==="paid"||e==="failed"}function Je(e){let{config:n}=y(),t=n.apiBaseUrl,[f,d]=react.useState(null),[m,u]=react.useState(!!e),[i,o]=react.useState(null),a=react.useRef(true),s=react.useCallback(async()=>{if(!e){d(null),u(false);return}try{o(null);let r=await fetch(`${t}/api/keys/filings/${encodeURIComponent(e)}`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to load filing (${r.status})`));let c=await r.json();a.current&&d(c);}catch(r){a.current&&o(r instanceof Error?r.message:"Failed to load filing");}finally{a.current&&u(false);}},[t,e]);return react.useEffect(()=>{if(a.current=true,!e)return d(null),u(false),()=>{a.current=false;};u(true),s();let r=setInterval(()=>{a.current&&(f&&We(f.status)||s());},je);return ()=>{a.current=false,clearInterval(r);}},[e,s,f]),{detail:f,loading:m,error:i,refresh:s}}function ze(){let{config:e}=y(),[n,t]=react.useState(null),[f,d]=react.useState(true),[m,u]=react.useState(null),[i,o]=react.useState(false),a=react.useRef(true),s=e.apiBaseUrl,r=react.useCallback(async()=>{try{d(!0),u(null);let l=await fetch(`${s}/api/payout`,{credentials:"include"});if(!l.ok)throw new Error(await p(l,`Failed to load payout account (${l.status})`));let g=await l.json();a.current&&t(g);}catch(l){a.current&&u(l instanceof Error?l.message:"Failed to load payout account");}finally{a.current&&d(false);}},[s]);react.useEffect(()=>(a.current=true,r(),()=>{a.current=false;}),[r]);let c=react.useCallback(async()=>{try{o(!0),u(null);let l=await fetch(`${s}/api/payout`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!l.ok&&l.status!==204)throw new Error(await p(l,`Disconnect failed (${l.status})`));return a.current&&t({method:null}),!0}catch(l){return a.current&&u(l instanceof Error?l.message:"Disconnect failed"),false}finally{a.current&&o(false);}},[s]);return {account:n,loading:f,error:m,refresh:r,disconnect:c,disconnecting:i}}function Ye(){let{config:e}=y(),[n,t]=react.useState(false),[f,d]=react.useState(null);return {startStripeConnect:react.useCallback(async()=>{try{t(!0),d(null);let u=await fetch(`${e.apiBaseUrl}/api/payout/stripe/start`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({stackId:e.stackId})});if(!u.ok)throw new Error(await p(u,`Stripe Connect start failed (${u.status})`));let i=await u.json();if(typeof window<"u"&&i.onboardingUrl){let o;try{o=new URL(i.onboardingUrl);}catch{throw new Error("Invalid onboarding URL")}if(o.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(o.hostname))throw new Error("Refusing to redirect to non-Stripe URL");window.location.href=o.toString();return}}catch(u){d(u instanceof Error?u.message:"Stripe Connect start failed");}finally{t(false);}},[e.apiBaseUrl,e.stackId]),starting:n,error:f}}function Ge(){if(typeof window>"u")return null;let e=window,n=e.solana,t=e.phantom?.solana;return ((n&&n.isPhantom?n:null)||(t&&t.isPhantom?t:null))??null}function Qe(e){let n="";for(let t=0;t<e.length;t+=1)n+=String.fromCharCode(e[t]);return typeof btoa=="function"?btoa(n):Buffer.from(e).toString("base64")}function et(){let{config:e}=y(),[n,t]=react.useState(false),[f,d]=react.useState(null);return {connectAndVerify:react.useCallback(async()=>{try{t(!0),d(null);let u=Ge();if(!u)throw new Error("Phantom wallet not found. Install Phantom to continue.");let o=(await u.connect()).publicKey.toString(),a=await fetch(`${e.apiBaseUrl}/api/payout/crypto/nonce`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({address:o})});if(!a.ok)throw new Error(await p(a,`Nonce request failed (${a.status})`));let{nonce:s,message:r}=await a.json(),c=new TextEncoder().encode(r),l=await u.signMessage(c,"utf8"),g=Qe(l.signature),h=await fetch(`${e.apiBaseUrl}/api/payout/crypto/verify`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({address:o,nonce:s,signature:g})});if(!h.ok)throw new Error(await p(h,`Verification failed (${h.status})`));return {address:o}}catch(u){let i=u instanceof Error?u:new Error("Wallet verification failed");return d(i.message),null}finally{t(false);}},[e.apiBaseUrl]),connecting:n,error:f}}
2
- exports.useCryptoConnect=et;exports.useFilePaperwork=Le;exports.useFilingDetail=Je;exports.useFilingHistory=Fe;exports.useKeyLedger=ge;exports.useKeys=fe;exports.useListKey=Pe;exports.useMintKey=he;exports.usePayoutAccount=ze;exports.usePricing=ie;exports.useSolanaPayment=Ce;exports.useStackPayoutCapabilities=_e;exports.useStripeCheckout=we;exports.useStripeConnect=Ye;exports.useTransferKey=xe;
1
+ 'use strict';var react=require('react');require('react/jsx-runtime');var se=react.createContext(null);function y(){let e=react.useContext(se);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function oe(e,n){if(typeof e!="string"||e.length===0)return n;let r=e.replace(/[\u0000-\u001F\u007F]/g," ");return r.length>500?r.slice(0,500)+"\u2026":r}async function m(e,n){try{let r=await e.json();if(r&&typeof r=="object"&&"error"in r)return oe(r.error,n)}catch{}return n}function ae(){let{config:e}=y(),[n,r]=react.useState(null),[l,d]=react.useState(true),[p,f]=react.useState(null),c=react.useRef(true),s=react.useRef(e.apiBaseUrl);s.current=e.apiBaseUrl;let a=async()=>{try{c.current&&(d(!0),f(null));let t=await fetch(`${s.current}/api/keys/pricing`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Pricing unavailable (${t.status})`));let o=await t.json();c.current&&r(o);}catch(t){c.current&&f(t instanceof Error?t.message:"Failed to fetch pricing");}finally{c.current&&d(false);}};return react.useEffect(()=>{c.current=true,a();let t=setInterval(a,6e4);return ()=>{c.current=false,clearInterval(t);}},[]),{pricing:n,loading:l,error:p,refresh:a}}function fe(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key:e.id||e.key||e.keyPrefix||"",userId:e.userId||e.user_id||"",status:e.status||"active",tokenBalance:e.tokenBalance??e.currentTokenBalance??e.current_token_balance??0,maxTokens:e.maxTokens??e.initialTokenBalance??e.initial_token_balance??0,createdAt:String(e.createdAt??e.created_at??""),expiresAt:e.expiresAt,label:e.label||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function de(){let{config:e}=y(),[n,r]=react.useState([]),[l,d]=react.useState(true),[p,f]=react.useState(null),c=react.useRef(true),s=e.apiBaseUrl,a=react.useCallback(async()=>{try{d(!0),f(null);let o=await fetch(`${s}/api/keys`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to fetch keys (${o.status})`));let i=await o.json(),u=Array.isArray(i)?i:i.keys??[];c.current&&r(u.map(fe));}catch(o){c.current&&f(o instanceof Error?o.message:"Failed to fetch keys");}finally{c.current&&d(false);}},[s]);react.useEffect(()=>(c.current=true,a(),()=>{c.current=false;}),[a]);let t=n.reduce((o,i)=>o+i.tokenBalance,0);return {keys:n,totalBalance:t,loading:l,error:p,refresh:a}}var _=false;function h(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);if(!e)return _||(_=true,console.warn("[keyutils] __csrf cookie not found; mutations will be sent without a CSRF token")),{};let n=e[1];try{n=decodeURIComponent(n);}catch{}return {"x-csrf-token":n}}function H(e){let n=e.type||e.entry_type||"debit",r=e.amount??e.tokens??e.token_amount??0,l=e.description||e.memo||e.reason||pe(n);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:n,amount:r,description:l,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function pe(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function ke(e){let{config:n}=y(),[r,l]=react.useState([]),[d,p]=react.useState(false),[f,c]=react.useState(null),s=react.useRef(true),a=n.apiBaseUrl,t=react.useCallback(async()=>{if(e)try{p(!0),c(null);let o=await fetch(`${a}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to fetch ledger (${o.status})`));let i=await o.json(),u=Array.isArray(i)?i:i.entries??[];s.current&&l(u.map(H));}catch(o){s.current&&c(o instanceof Error?o.message:"Failed to fetch ledger");}finally{s.current&&p(false);}},[a,e]);return react.useEffect(()=>(s.current=true,t(),()=>{s.current=false;}),[t]),{entries:r,loading:d,error:f,refresh:t}}function Re(){let{config:e,callbacks:n}=y(),[r,l]=react.useState(false),[d,p]=react.useState(null),[f,c]=react.useState(null);return {mint:react.useCallback(async(a,t,o=1)=>{try{l(!0),c(null),n.onPaymentComplete?.(a,t);let i=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({paymentMethod:a,paymentRef:t,quantity:o,stackId:e.stackId})});if(!i.ok)throw new Error(await m(i,`Key generation failed (${i.status})`));let u=await i.json(),g=u.keys?.[0]||u,k={success:!0,key:{id:g.keyId||g.id||"",key:g.key||"",userId:g.userId||"",status:"active",tokenBalance:g.tokenBalance??g.currentTokenBalance??0,maxTokens:g.initialTokenBalance??g.tokenBalance??0,createdAt:String(g.createdAt||Date.now())},transactionId:t};return p(k),n.onMintSuccess?.(k),k}catch(i){let u=i instanceof Error?i:new Error("Key generation failed");return c(u.message),n.onMintError?.(u),{success:false,error:u.message}}finally{l(false);}},[e.apiBaseUrl,n]),minting:r,result:d,error:f}}function Ue(){let{config:e,callbacks:n}=y(),[r,l]=react.useState(false),[d,p]=react.useState(null),[f,c]=react.useState(null),s=react.useRef(true),a=react.useCallback(async(o,i)=>{try{l(!0),c(null);let u=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({askPriceCents:i,stackId:e.stackId,stackName:e.stackName})});if(!u.ok)throw new Error(await m(u,`Listing failed (${u.status})`));let g=await u.json();return s.current&&(p(g),n.onListingCreated?.(g)),g}catch(u){let g=u instanceof Error?u.message:"Listing failed";return s.current&&c(g),null}finally{s.current&&l(false);}},[e.apiBaseUrl,e.stackId,e.stackName,n]),t=react.useCallback(async o=>{try{l(!0),c(null);let i=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/list`,{method:"DELETE",headers:{...h()},credentials:"include"});if(!i.ok)throw new Error(await m(i,`Delist failed (${i.status})`));return s.current&&p(null),!0}catch(i){let u=i instanceof Error?i.message:"Delist failed";return s.current&&c(u),false}finally{s.current&&l(false);}},[e.apiBaseUrl]);return {listKey:a,delistKey:t,listing:r,result:d,error:f}}function Ee(){let{config:e}=y(),[n,r]=react.useState(false),[l,d]=react.useState(null),p=react.useRef(true);return {createSession:react.useCallback(async(c,s)=>{try{r(!0),d(null);let a=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({priceCents:c,quantity:s,stackId:e.stackId,referrerUrl:window.location.href})});if(!a.ok)throw new Error(await m(a,`Checkout failed (${a.status})`));let{url:t}=await a.json();if(!t)throw new Error("No checkout URL returned");let o;try{o=new URL(t);}catch{throw new Error("Invalid checkout URL")}if(o.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(o.hostname))throw new Error("Refusing to redirect to non-Stripe URL");try{sessionStorage.setItem("keyutils_stripe_pending","1"),sessionStorage.setItem("keyutils_stripe_quantity",String(s));}catch{}window.location.href=o.toString();}catch(a){if(p.current){let t=a instanceof Error?a.message:"Checkout failed";d(t),r(false);}}},[e.apiBaseUrl,e.stackId]),loading:n,error:l}}function j(e,n="#"){if(!e||typeof e!="string")return n;let r=e.trim();if(r===""||r==="#")return n;if(r.startsWith("/")||r.startsWith("./")||r.startsWith("../"))return r;try{let l=new URL(r);if(l.protocol==="http:"||l.protocol==="https:")return l.toString()}catch{}return n}var J=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function Se(){let{config:e}=y(),[n,r]=react.useState(false),[l,d]=react.useState(null);return {pay:react.useCallback(async f=>{if(!e.merchantWallet||!J.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{r(!0),d(null);let{Connection:c,PublicKey:s,Transaction:a,SystemProgram:t}=await import('@solana/web3.js'),o=typeof window<"u"?window.solana:void 0;if(!o||typeof o!="object"||!o.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let i=o,u=new s(e.merchantWallet),g=await i.connect(),k=new s(g.publicKey.toString()),R="https://api.mainnet-beta.solana.com",P=j(e.solanaRpcUrl,R),Y=P==="#"?R:P,Z=new c(Y),{blockhash:G}=await Z.getLatestBlockhash(),b=BigInt(Math.floor(f*1e9)),w=e.protocolTreasuryWallet,A=e.protocolFeeBps??500,E=new a({recentBlockhash:G,feePayer:k});if(w&&J.test(w)&&A>0){let v=b*BigInt(A)/10000n,ee=b-v,te=new s(w);E.add(t.transfer({fromPubkey:k,toPubkey:u,lamports:Number(ee)}),t.transfer({fromPubkey:k,toPubkey:te,lamports:Number(v)}));}else E.add(t.transfer({fromPubkey:k,toPubkey:u,lamports:Number(b)}));let{signature:Q}=await i.signAndSendTransaction(E);return Q}catch(c){let s=c instanceof Error?c:new Error("SOL payment failed");throw d(s.message),s}finally{r(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:n,error:l}}function Ie(){let{config:e,callbacks:n}=y(),[r,l]=react.useState(false),[d,p]=react.useState(null),[f,c]=react.useState(null),s=react.useRef(true);return {transferKey:react.useCallback(async(t,o)=>{try{l(!0),c(null);let i=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(t)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({recipientId:o})});if(!i.ok)throw new Error(await m(i,`Transfer failed (${i.status})`));let u=await i.json();return s.current&&(p(u),n.onTransferComplete?.(u)),u}catch(i){let u=i instanceof Error?i.message:"Transfer failed";return s.current&&c(u),null}finally{s.current&&l(false);}},[e.apiBaseUrl,n]),transferring:r,result:d,error:f}}function Be(){let{config:e,callbacks:n}=y(),[r,l]=react.useState(false),[d,p]=react.useState(null),[f,c]=react.useState(null),s=react.useRef(true);react.useEffect(()=>(s.current=true,()=>{s.current=false;}),[]);let a=react.useCallback(async(o,i)=>{try{l(!0),c(null);let u={stackId:e.stackId};i&&(u.payoutMethod=i);let g=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify(u)});if(!g.ok)throw new Error(await m(g,`Filing failed (${g.status})`));let k=await g.json();return s.current&&(p(k),n.onFilingComplete?.(k)),k}catch(u){let g=u instanceof Error?u:new Error("Filing failed");return s.current&&c(g.message),n.onFilingError?.(g),null}finally{s.current&&l(false);}},[e.apiBaseUrl,e.stackId,n]),t=react.useCallback(()=>{p(null),c(null);},[]);return {filePaperwork:a,filing:r,result:d,error:f,reset:t}}function Ae(){let{config:e}=y(),[n,r]=react.useState([]),[l,d]=react.useState(true),[p,f]=react.useState(null),c=react.useRef(true),s=e.apiBaseUrl,a=react.useCallback(async()=>{try{d(!0),f(null);let t=await fetch(`${s}/api/keys/filings`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Failed to fetch filings (${t.status})`));let o=await t.json(),i=Array.isArray(o)?o:o.filings??[];c.current&&r(i);}catch(t){c.current&&f(t instanceof Error?t.message:"Failed to fetch filings");}finally{c.current&&d(false);}},[s]);return react.useEffect(()=>(c.current=true,a(),()=>{c.current=false;}),[a]),{entries:n,loading:l,error:p,refresh:a}}function He(e){let{config:n}=y(),r=e??n.stackId,l=n.apiBaseUrl,[d,p]=react.useState(null),[f,c]=react.useState(!!r),[s,a]=react.useState(null),t=react.useRef(true),o=react.useCallback(async()=>{if(!r){p(null),c(false);return}try{c(!0),a(null);let i=await fetch(`${l}/api/stacks/${encodeURIComponent(r)}/payout-capabilities`,{credentials:"include"});if(!i.ok)throw new Error(await m(i,`Failed to load payout capabilities (${i.status})`));let u=await i.json();t.current&&p(u);}catch(i){t.current&&a(i instanceof Error?i.message:"Failed to load payout capabilities");}finally{t.current&&c(false);}},[l,r]);return react.useEffect(()=>(t.current=true,o(),()=>{t.current=false;}),[o]),{caps:d,loading:f,error:s,refresh:o}}var We=5e3;function Je(e){return e==="paid"||e==="failed"}function qe(e){let{config:n}=y(),r=n.apiBaseUrl,[l,d]=react.useState(null),[p,f]=react.useState(!!e),[c,s]=react.useState(null),a=react.useRef(true),t=react.useCallback(async()=>{if(!e){d(null),f(false);return}try{s(null);let o=await fetch(`${r}/api/keys/filings/${encodeURIComponent(e)}`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to load filing (${o.status})`));let i=await o.json();a.current&&d(i);}catch(o){a.current&&s(o instanceof Error?o.message:"Failed to load filing");}finally{a.current&&f(false);}},[r,e]);return react.useEffect(()=>{if(a.current=true,!e)return d(null),f(false),()=>{a.current=false;};f(true),t();let o=setInterval(()=>{a.current&&(l&&Je(l.status)||t());},We);return ()=>{a.current=false,clearInterval(o);}},[e,t,l]),{detail:l,loading:p,error:c,refresh:t}}function Xe(e){let{config:n}=y(),r=e??n.stackId??"",l=n.apiBaseUrl,[d,p]=react.useState(null),[f,c]=react.useState(true),[s,a]=react.useState(null),[t,o]=react.useState(false),i=react.useRef(true),u=react.useCallback(async()=>{try{c(!0),a(null);let k=r?`${l}/api/payout?stackId=${encodeURIComponent(r)}`:`${l}/api/payout`,R=await fetch(k,{credentials:"include"});if(!R.ok)throw new Error(await m(R,`Failed to load payout account (${R.status})`));let P=await R.json();i.current&&p(P);}catch(k){i.current&&a(k instanceof Error?k.message:"Failed to load payout account");}finally{i.current&&c(false);}},[l,r]);react.useEffect(()=>(i.current=true,u(),()=>{i.current=false;}),[u]);let g=react.useCallback(async k=>{try{o(!0),a(null);let R=k?`${l}/api/payout?stackId=${encodeURIComponent(k)}`:`${l}/api/payout`,P=await fetch(R,{method:"DELETE",headers:{...h()},credentials:"include"});if(!P.ok&&P.status!==204)throw new Error(await m(P,`Disconnect failed (${P.status})`));return await u(),!0}catch(R){return i.current&&a(R instanceof Error?R.message:"Disconnect failed"),false}finally{i.current&&o(false);}},[l,u]);return {account:d,loading:f,error:s,refresh:u,disconnect:g,disconnecting:t}}function Qe(){let{config:e}=y(),n=e.apiBaseUrl,[r,l]=react.useState([]),[d,p]=react.useState(true),[f,c]=react.useState(null),s=react.useRef(true),a=react.useCallback(async()=>{try{p(!0),c(null);let t=await fetch(`${n}/api/payout/stripe-stacks`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Failed to load stripe stacks (${t.status})`));let o=await t.json();s.current&&l(o.stacks??[]);}catch(t){s.current&&c(t instanceof Error?t.message:"Failed to load stripe stacks");}finally{s.current&&p(false);}},[n]);return react.useEffect(()=>(s.current=true,a(),()=>{s.current=false;}),[a]),{stacks:r,loading:d,error:f,refresh:a}}function tt(e){let{config:n}=y(),r=e??n.stackId,[l,d]=react.useState(false),[p,f]=react.useState(null);return {startStripeConnect:react.useCallback(async()=>{try{d(!0),f(null);let s=await fetch(`${n.apiBaseUrl}/api/payout/stripe/start`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({stackId:r})});if(!s.ok)throw new Error(await m(s,`Stripe Connect start failed (${s.status})`));let a=await s.json();if(typeof window<"u"&&a.onboardingUrl){let t;try{t=new URL(a.onboardingUrl);}catch{throw new Error("Invalid onboarding URL")}if(t.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(t.hostname))throw new Error("Refusing to redirect to non-Stripe URL");window.location.href=t.toString();return}}catch(s){f(s instanceof Error?s.message:"Stripe Connect start failed");}finally{d(false);}},[n.apiBaseUrl,r]),starting:l,error:p}}function nt(){if(typeof window>"u")return null;let e=window,n=e.solana,r=e.phantom?.solana;return ((n&&n.isPhantom?n:null)||(r&&r.isPhantom?r:null))??null}function st(e){let n="";for(let r=0;r<e.length;r+=1)n+=String.fromCharCode(e[r]);return typeof btoa=="function"?btoa(n):Buffer.from(e).toString("base64")}function ot(){let{config:e}=y(),[n,r]=react.useState(false),[l,d]=react.useState(null);return {connectAndVerify:react.useCallback(async()=>{try{r(!0),d(null);let f=nt();if(!f)throw new Error("Phantom wallet not found. Install Phantom to continue.");let s=(await f.connect()).publicKey.toString(),a=await fetch(`${e.apiBaseUrl}/api/payout/crypto/nonce`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({address:s})});if(!a.ok)throw new Error(await m(a,`Nonce request failed (${a.status})`));let{nonce:t,message:o}=await a.json(),i=new TextEncoder().encode(o),u=await f.signMessage(i,"utf8"),g=st(u.signature),k=await fetch(`${e.apiBaseUrl}/api/payout/crypto/verify`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({address:s,nonce:t,signature:g})});if(!k.ok)throw new Error(await m(k,`Verification failed (${k.status})`));return {address:s}}catch(f){let c=f instanceof Error?f:new Error("Wallet verification failed");return d(c.message),null}finally{r(false);}},[e.apiBaseUrl]),connecting:n,error:l}}
2
+ exports.useCryptoConnect=ot;exports.useFilePaperwork=Be;exports.useFilingDetail=qe;exports.useFilingHistory=Ae;exports.useKeyLedger=ke;exports.useKeys=de;exports.useListKey=Ue;exports.useMintKey=Re;exports.usePayoutAccount=Xe;exports.usePricing=ae;exports.useSolanaPayment=Se;exports.useStackPayoutCapabilities=He;exports.useStripeCheckout=Ee;exports.useStripeConnect=tt;exports.useTransferKey=Ie;exports.useUserStripeStacks=Qe;
@@ -1,4 +1,4 @@
1
- import { PricingInfo, NodeKeyInfo, LedgerEntry, PaymentMethod, MintResult, ListingResult, DirectTransferResult, PayoutMethod, FilingResult, FilingHistoryEntry, StackPayoutCapabilities, FilingDetail, PayoutAccount } from '../types/index.cjs';
1
+ import { PricingInfo, NodeKeyInfo, LedgerEntry, PaymentMethod, MintResult, ListingResult, DirectTransferResult, PayoutMethod, FilingResult, FilingHistoryEntry, StackPayoutCapabilities, FilingDetail, PayoutAccount, StripeStackPayout } from '../types/index.cjs';
2
2
 
3
3
  interface UsePricingReturn {
4
4
  pricing: PricingInfo | null;
@@ -149,21 +149,49 @@ interface UsePayoutAccountReturn {
149
149
  loading: boolean;
150
150
  error: string | null;
151
151
  refresh: () => Promise<void>;
152
- /** Disconnect the current method (deletes saved payout config). */
153
- disconnect: () => Promise<boolean>;
152
+ /**
153
+ * Disconnect the payout config. With no argument, disconnects everything
154
+ * (Solana wallet + every Stripe stack). Pass a stackId to remove only the
155
+ * Stripe Connect record for that stack while preserving the Solana wallet
156
+ * and any other stacks' Stripe connections.
157
+ */
158
+ disconnect: (stackId?: string) => Promise<boolean>;
154
159
  disconnecting: boolean;
155
160
  }
156
161
  /**
157
- * Read + manage the user's payout account.
162
+ * Read + manage the user's payout config in the context of one stack.
163
+ *
164
+ * Stripe Connect is per-(user, stack) — each stack runs its own Stripe
165
+ * platform, so the user has an independent connected account per stack
166
+ * they file for. The Solana wallet is global (one address services every
167
+ * stack). The returned `PayoutAccount` exposes both rails: `stripe` is the
168
+ * connected account for `stackId` (if any), `solana` is the user-level
169
+ * wallet (if verified).
158
170
  *
159
171
  * Backend contract:
160
- * GET {apiBaseUrl}/api/payout → PayoutAccount
161
- * DELETE {apiBaseUrl}/api/payout → 204
172
+ * GET {apiBaseUrl}/api/payout?stackId=stk_… → PayoutAccount
173
+ * DELETE {apiBaseUrl}/api/payout → 204 (everything)
174
+ * DELETE {apiBaseUrl}/api/payout?stackId=stk_… → 204 (this stripe only)
175
+ */
176
+ declare function usePayoutAccount(stackIdOverride?: string): UsePayoutAccountReturn;
177
+
178
+ interface UseUserStripeStacksReturn {
179
+ stacks: StripeStackPayout[];
180
+ loading: boolean;
181
+ error: string | null;
182
+ refresh: () => Promise<void>;
183
+ }
184
+ /**
185
+ * List every stack the user has a Stripe Connect account on.
186
+ *
187
+ * Stripe Connect is per-(user, stack) — each stack runs its own platform —
188
+ * so a multi-stack user has multiple connected accounts. This hook drives
189
+ * the settings-page list view ("Stack A: payouts ✓, Stack B: pending…").
162
190
  *
163
- * The account is per-user (not per-stack). Switching methods (e.g. crypto →
164
- * stripe) replaces the previous record server-side.
191
+ * Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
192
+ * response: { stacks: StripeStackPayout[] }
165
193
  */
166
- declare function usePayoutAccount(): UsePayoutAccountReturn;
194
+ declare function useUserStripeStacks(): UseUserStripeStacksReturn;
167
195
 
168
196
  interface UseStripeConnectReturn {
169
197
  /**
@@ -179,12 +207,16 @@ interface UseStripeConnectReturn {
179
207
  error: string | null;
180
208
  }
181
209
  /**
210
+ * Stripe Connect is per-(user, stack) — each stack runs its own platform
211
+ * under its own secret. Pass `stackIdOverride` to onboard against a stack
212
+ * other than the provider's default; this is what callers use when filing
213
+ * a key whose originating stack isn't the same as the host app's stack.
214
+ *
182
215
  * Backend contract: POST {apiBaseUrl}/api/payout/stripe/start
183
- * body: { stackId? } — optional override; server defaults to the stack
184
- * the user's session is currently scoped to.
216
+ * body: { stackId }
185
217
  * response: StripeConnectStartResponse
186
218
  */
187
- declare function useStripeConnect(): UseStripeConnectReturn;
219
+ declare function useStripeConnect(stackIdOverride?: string): UseStripeConnectReturn;
188
220
 
189
221
  interface UseCryptoConnectReturn {
190
222
  /**
@@ -200,4 +232,4 @@ interface UseCryptoConnectReturn {
200
232
  }
201
233
  declare function useCryptoConnect(): UseCryptoConnectReturn;
202
234
 
203
- export { useCryptoConnect, useFilePaperwork, useFilingDetail, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePayoutAccount, usePricing, useSolanaPayment, useStackPayoutCapabilities, useStripeCheckout, useStripeConnect, useTransferKey };
235
+ export { useCryptoConnect, useFilePaperwork, useFilingDetail, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePayoutAccount, usePricing, useSolanaPayment, useStackPayoutCapabilities, useStripeCheckout, useStripeConnect, useTransferKey, useUserStripeStacks };
@@ -1,4 +1,4 @@
1
- import { PricingInfo, NodeKeyInfo, LedgerEntry, PaymentMethod, MintResult, ListingResult, DirectTransferResult, PayoutMethod, FilingResult, FilingHistoryEntry, StackPayoutCapabilities, FilingDetail, PayoutAccount } from '../types/index.js';
1
+ import { PricingInfo, NodeKeyInfo, LedgerEntry, PaymentMethod, MintResult, ListingResult, DirectTransferResult, PayoutMethod, FilingResult, FilingHistoryEntry, StackPayoutCapabilities, FilingDetail, PayoutAccount, StripeStackPayout } from '../types/index.js';
2
2
 
3
3
  interface UsePricingReturn {
4
4
  pricing: PricingInfo | null;
@@ -149,21 +149,49 @@ interface UsePayoutAccountReturn {
149
149
  loading: boolean;
150
150
  error: string | null;
151
151
  refresh: () => Promise<void>;
152
- /** Disconnect the current method (deletes saved payout config). */
153
- disconnect: () => Promise<boolean>;
152
+ /**
153
+ * Disconnect the payout config. With no argument, disconnects everything
154
+ * (Solana wallet + every Stripe stack). Pass a stackId to remove only the
155
+ * Stripe Connect record for that stack while preserving the Solana wallet
156
+ * and any other stacks' Stripe connections.
157
+ */
158
+ disconnect: (stackId?: string) => Promise<boolean>;
154
159
  disconnecting: boolean;
155
160
  }
156
161
  /**
157
- * Read + manage the user's payout account.
162
+ * Read + manage the user's payout config in the context of one stack.
163
+ *
164
+ * Stripe Connect is per-(user, stack) — each stack runs its own Stripe
165
+ * platform, so the user has an independent connected account per stack
166
+ * they file for. The Solana wallet is global (one address services every
167
+ * stack). The returned `PayoutAccount` exposes both rails: `stripe` is the
168
+ * connected account for `stackId` (if any), `solana` is the user-level
169
+ * wallet (if verified).
158
170
  *
159
171
  * Backend contract:
160
- * GET {apiBaseUrl}/api/payout → PayoutAccount
161
- * DELETE {apiBaseUrl}/api/payout → 204
172
+ * GET {apiBaseUrl}/api/payout?stackId=stk_… → PayoutAccount
173
+ * DELETE {apiBaseUrl}/api/payout → 204 (everything)
174
+ * DELETE {apiBaseUrl}/api/payout?stackId=stk_… → 204 (this stripe only)
175
+ */
176
+ declare function usePayoutAccount(stackIdOverride?: string): UsePayoutAccountReturn;
177
+
178
+ interface UseUserStripeStacksReturn {
179
+ stacks: StripeStackPayout[];
180
+ loading: boolean;
181
+ error: string | null;
182
+ refresh: () => Promise<void>;
183
+ }
184
+ /**
185
+ * List every stack the user has a Stripe Connect account on.
186
+ *
187
+ * Stripe Connect is per-(user, stack) — each stack runs its own platform —
188
+ * so a multi-stack user has multiple connected accounts. This hook drives
189
+ * the settings-page list view ("Stack A: payouts ✓, Stack B: pending…").
162
190
  *
163
- * The account is per-user (not per-stack). Switching methods (e.g. crypto →
164
- * stripe) replaces the previous record server-side.
191
+ * Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
192
+ * response: { stacks: StripeStackPayout[] }
165
193
  */
166
- declare function usePayoutAccount(): UsePayoutAccountReturn;
194
+ declare function useUserStripeStacks(): UseUserStripeStacksReturn;
167
195
 
168
196
  interface UseStripeConnectReturn {
169
197
  /**
@@ -179,12 +207,16 @@ interface UseStripeConnectReturn {
179
207
  error: string | null;
180
208
  }
181
209
  /**
210
+ * Stripe Connect is per-(user, stack) — each stack runs its own platform
211
+ * under its own secret. Pass `stackIdOverride` to onboard against a stack
212
+ * other than the provider's default; this is what callers use when filing
213
+ * a key whose originating stack isn't the same as the host app's stack.
214
+ *
182
215
  * Backend contract: POST {apiBaseUrl}/api/payout/stripe/start
183
- * body: { stackId? } — optional override; server defaults to the stack
184
- * the user's session is currently scoped to.
216
+ * body: { stackId }
185
217
  * response: StripeConnectStartResponse
186
218
  */
187
- declare function useStripeConnect(): UseStripeConnectReturn;
219
+ declare function useStripeConnect(stackIdOverride?: string): UseStripeConnectReturn;
188
220
 
189
221
  interface UseCryptoConnectReturn {
190
222
  /**
@@ -200,4 +232,4 @@ interface UseCryptoConnectReturn {
200
232
  }
201
233
  declare function useCryptoConnect(): UseCryptoConnectReturn;
202
234
 
203
- export { useCryptoConnect, useFilePaperwork, useFilingDetail, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePayoutAccount, usePricing, useSolanaPayment, useStackPayoutCapabilities, useStripeCheckout, useStripeConnect, useTransferKey };
235
+ export { useCryptoConnect, useFilePaperwork, useFilingDetail, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePayoutAccount, usePricing, useSolanaPayment, useStackPayoutCapabilities, useStripeCheckout, useStripeConnect, useTransferKey, useUserStripeStacks };
@@ -1,2 +1,2 @@
1
- import {createContext,useState,useRef,useEffect,useCallback,useContext}from'react';import'react/jsx-runtime';var ne=createContext(null);function y(){let e=useContext(ne);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function se(e,n){if(typeof e!="string"||e.length===0)return n;let t=e.replace(/[\u0000-\u001F\u007F]/g," ");return t.length>500?t.slice(0,500)+"\u2026":t}async function p(e,n){try{let t=await e.json();if(t&&typeof t=="object"&&"error"in t)return se(t.error,n)}catch{}return n}function ie(){let{config:e}=y(),[n,t]=useState(null),[f,d]=useState(true),[m,u]=useState(null),i=useRef(true),o=useRef(e.apiBaseUrl);o.current=e.apiBaseUrl;let a=async()=>{try{i.current&&(d(!0),u(null));let s=await fetch(`${o.current}/api/keys/pricing`,{credentials:"include"});if(!s.ok)throw new Error(await p(s,`Pricing unavailable (${s.status})`));let r=await s.json();i.current&&t(r);}catch(s){i.current&&u(s instanceof Error?s.message:"Failed to fetch pricing");}finally{i.current&&d(false);}};return useEffect(()=>{i.current=true,a();let s=setInterval(a,6e4);return ()=>{i.current=false,clearInterval(s);}},[]),{pricing:n,loading:f,error:m,refresh:a}}function ue(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key:e.id||e.key||e.keyPrefix||"",userId:e.userId||e.user_id||"",status:e.status||"active",tokenBalance:e.tokenBalance??e.currentTokenBalance??e.current_token_balance??0,maxTokens:e.maxTokens??e.initialTokenBalance??e.initial_token_balance??0,createdAt:String(e.createdAt??e.created_at??""),expiresAt:e.expiresAt,label:e.label||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function fe(){let{config:e}=y(),[n,t]=useState([]),[f,d]=useState(true),[m,u]=useState(null),i=useRef(true),o=e.apiBaseUrl,a=useCallback(async()=>{try{d(!0),u(null);let r=await fetch(`${o}/api/keys`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to fetch keys (${r.status})`));let c=await r.json(),l=Array.isArray(c)?c:c.keys??[];i.current&&t(l.map(ue));}catch(r){i.current&&u(r instanceof Error?r.message:"Failed to fetch keys");}finally{i.current&&d(false);}},[o]);useEffect(()=>(i.current=true,a(),()=>{i.current=false;}),[a]);let s=n.reduce((r,c)=>r+c.tokenBalance,0);return {keys:n,totalBalance:s,loading:f,error:m,refresh:a}}var N=false;function k(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);if(!e)return N||(N=true,console.warn("[keyutils] __csrf cookie not found; mutations will be sent without a CSRF token")),{};let n=e[1];try{n=decodeURIComponent(n);}catch{}return {"x-csrf-token":n}}function _(e){let n=e.type||e.entry_type||"debit",t=e.amount??e.tokens??e.token_amount??0,f=e.description||e.memo||e.reason||de(n);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:n,amount:t,description:f,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function de(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function ge(e){let{config:n}=y(),[t,f]=useState([]),[d,m]=useState(false),[u,i]=useState(null),o=useRef(true),a=n.apiBaseUrl,s=useCallback(async()=>{if(e)try{m(!0),i(null);let r=await fetch(`${a}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to fetch ledger (${r.status})`));let c=await r.json(),l=Array.isArray(c)?c:c.entries??[];o.current&&f(l.map(_));}catch(r){o.current&&i(r instanceof Error?r.message:"Failed to fetch ledger");}finally{o.current&&m(false);}},[a,e]);return useEffect(()=>(o.current=true,s(),()=>{o.current=false;}),[s]),{entries:t,loading:d,error:u,refresh:s}}function he(){let{config:e,callbacks:n}=y(),[t,f]=useState(false),[d,m]=useState(null),[u,i]=useState(null);return {mint:useCallback(async(a,s,r=1)=>{try{f(!0),i(null),n.onPaymentComplete?.(a,s);let c=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({paymentMethod:a,paymentRef:s,quantity:r,stackId:e.stackId})});if(!c.ok)throw new Error(await p(c,`Key generation failed (${c.status})`));let l=await c.json(),g=l.keys?.[0]||l,h={success:!0,key:{id:g.keyId||g.id||"",key:g.key||"",userId:g.userId||"",status:"active",tokenBalance:g.tokenBalance??g.currentTokenBalance??0,maxTokens:g.initialTokenBalance??g.tokenBalance??0,createdAt:String(g.createdAt||Date.now())},transactionId:s};return m(h),n.onMintSuccess?.(h),h}catch(c){let l=c instanceof Error?c:new Error("Key generation failed");return i(l.message),n.onMintError?.(l),{success:false,error:l.message}}finally{f(false);}},[e.apiBaseUrl,n]),minting:t,result:d,error:u}}function Pe(){let{config:e,callbacks:n}=y(),[t,f]=useState(false),[d,m]=useState(null),[u,i]=useState(null),o=useRef(true),a=useCallback(async(r,c)=>{try{f(!0),i(null);let l=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({askPriceCents:c,stackId:e.stackId,stackName:e.stackName})});if(!l.ok)throw new Error(await p(l,`Listing failed (${l.status})`));let g=await l.json();return o.current&&(m(g),n.onListingCreated?.(g)),g}catch(l){let g=l instanceof Error?l.message:"Listing failed";return o.current&&i(g),null}finally{o.current&&f(false);}},[e.apiBaseUrl,e.stackId,e.stackName,n]),s=useCallback(async r=>{try{f(!0),i(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/list`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!c.ok)throw new Error(await p(c,`Delist failed (${c.status})`));return o.current&&m(null),!0}catch(c){let l=c instanceof Error?c.message:"Delist failed";return o.current&&i(l),false}finally{o.current&&f(false);}},[e.apiBaseUrl]);return {listKey:a,delistKey:s,listing:t,result:d,error:u}}function we(){let{config:e}=y(),[n,t]=useState(false),[f,d]=useState(null),m=useRef(true);return {createSession:useCallback(async(i,o)=>{try{t(!0),d(null);let a=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({priceCents:i,quantity:o,stackId:e.stackId,referrerUrl:window.location.href})});if(!a.ok)throw new Error(await p(a,`Checkout failed (${a.status})`));let{url:s}=await a.json();if(!s)throw new Error("No checkout URL returned");let r;try{r=new URL(s);}catch{throw new Error("Invalid checkout URL")}if(r.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(r.hostname))throw new Error("Refusing to redirect to non-Stripe URL");try{sessionStorage.setItem("keyutils_stripe_pending","1"),sessionStorage.setItem("keyutils_stripe_quantity",String(o));}catch{}window.location.href=r.toString();}catch(a){if(m.current){let s=a instanceof Error?a.message:"Checkout failed";d(s),t(false);}}},[e.apiBaseUrl,e.stackId]),loading:n,error:f}}function O(e,n="#"){if(!e||typeof e!="string")return n;let t=e.trim();if(t===""||t==="#")return n;if(t.startsWith("/")||t.startsWith("./")||t.startsWith("../"))return t;try{let f=new URL(t);if(f.protocol==="http:"||f.protocol==="https:")return f.toString()}catch{}return n}var W=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function Ce(){let{config:e}=y(),[n,t]=useState(false),[f,d]=useState(null);return {pay:useCallback(async u=>{if(!e.merchantWallet||!W.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{t(!0),d(null);let{Connection:i,PublicKey:o,Transaction:a,SystemProgram:s}=await import('@solana/web3.js'),r=typeof window<"u"?window.solana:void 0;if(!r||typeof r!="object"||!r.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let c=r,l=new o(e.merchantWallet),g=await c.connect(),h=new o(g.publicKey.toString()),M="https://api.mainnet-beta.solana.com",$=O(e.solanaRpcUrl,M),X=$==="#"?M:$,Y=new i(X),{blockhash:Z}=await Y.getLatestBlockhash(),P=BigInt(Math.floor(u*1e9)),b=e.protocolTreasuryWallet,F=e.protocolFeeBps??500,U=new a({recentBlockhash:Z,feePayer:h});if(b&&W.test(b)&&F>0){let A=P*BigInt(F)/10000n,Q=P-A,ee=new o(b);U.add(s.transfer({fromPubkey:h,toPubkey:l,lamports:Number(Q)}),s.transfer({fromPubkey:h,toPubkey:ee,lamports:Number(A)}));}else U.add(s.transfer({fromPubkey:h,toPubkey:l,lamports:Number(P)}));let{signature:G}=await c.signAndSendTransaction(U);return G}catch(i){let o=i instanceof Error?i:new Error("SOL payment failed");throw d(o.message),o}finally{t(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:n,error:f}}function xe(){let{config:e,callbacks:n}=y(),[t,f]=useState(false),[d,m]=useState(null),[u,i]=useState(null),o=useRef(true);return {transferKey:useCallback(async(s,r)=>{try{f(!0),i(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(s)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({recipientId:r})});if(!c.ok)throw new Error(await p(c,`Transfer failed (${c.status})`));let l=await c.json();return o.current&&(m(l),n.onTransferComplete?.(l)),l}catch(c){let l=c instanceof Error?c.message:"Transfer failed";return o.current&&i(l),null}finally{o.current&&f(false);}},[e.apiBaseUrl,n]),transferring:t,result:d,error:u}}function Le(){let{config:e,callbacks:n}=y(),[t,f]=useState(false),[d,m]=useState(null),[u,i]=useState(null),o=useRef(true);useEffect(()=>(o.current=true,()=>{o.current=false;}),[]);let a=useCallback(async(r,c)=>{try{f(!0),i(null);let l={stackId:e.stackId};c&&(l.payoutMethod=c);let g=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(r)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify(l)});if(!g.ok)throw new Error(await p(g,`Filing failed (${g.status})`));let h=await g.json();return o.current&&(m(h),n.onFilingComplete?.(h)),h}catch(l){let g=l instanceof Error?l:new Error("Filing failed");return o.current&&i(g.message),n.onFilingError?.(g),null}finally{o.current&&f(false);}},[e.apiBaseUrl,e.stackId,n]),s=useCallback(()=>{m(null),i(null);},[]);return {filePaperwork:a,filing:t,result:d,error:u,reset:s}}function Fe(){let{config:e}=y(),[n,t]=useState([]),[f,d]=useState(true),[m,u]=useState(null),i=useRef(true),o=e.apiBaseUrl,a=useCallback(async()=>{try{d(!0),u(null);let s=await fetch(`${o}/api/keys/filings`,{credentials:"include"});if(!s.ok)throw new Error(await p(s,`Failed to fetch filings (${s.status})`));let r=await s.json(),c=Array.isArray(r)?r:r.filings??[];i.current&&t(c);}catch(s){i.current&&u(s instanceof Error?s.message:"Failed to fetch filings");}finally{i.current&&d(false);}},[o]);return useEffect(()=>(i.current=true,a(),()=>{i.current=false;}),[a]),{entries:n,loading:f,error:m,refresh:a}}function _e(e){let{config:n}=y(),t=e??n.stackId,f=n.apiBaseUrl,[d,m]=useState(null),[u,i]=useState(!!t),[o,a]=useState(null),s=useRef(true),r=useCallback(async()=>{if(!t){m(null),i(false);return}try{i(!0),a(null);let c=await fetch(`${f}/api/stacks/${encodeURIComponent(t)}/payout-capabilities`,{credentials:"include"});if(!c.ok)throw new Error(await p(c,`Failed to load payout capabilities (${c.status})`));let l=await c.json();s.current&&m(l);}catch(c){s.current&&a(c instanceof Error?c.message:"Failed to load payout capabilities");}finally{s.current&&i(false);}},[f,t]);return useEffect(()=>(s.current=true,r(),()=>{s.current=false;}),[r]),{caps:d,loading:u,error:o,refresh:r}}var je=5e3;function We(e){return e==="paid"||e==="failed"}function Je(e){let{config:n}=y(),t=n.apiBaseUrl,[f,d]=useState(null),[m,u]=useState(!!e),[i,o]=useState(null),a=useRef(true),s=useCallback(async()=>{if(!e){d(null),u(false);return}try{o(null);let r=await fetch(`${t}/api/keys/filings/${encodeURIComponent(e)}`,{credentials:"include"});if(!r.ok)throw new Error(await p(r,`Failed to load filing (${r.status})`));let c=await r.json();a.current&&d(c);}catch(r){a.current&&o(r instanceof Error?r.message:"Failed to load filing");}finally{a.current&&u(false);}},[t,e]);return useEffect(()=>{if(a.current=true,!e)return d(null),u(false),()=>{a.current=false;};u(true),s();let r=setInterval(()=>{a.current&&(f&&We(f.status)||s());},je);return ()=>{a.current=false,clearInterval(r);}},[e,s,f]),{detail:f,loading:m,error:i,refresh:s}}function ze(){let{config:e}=y(),[n,t]=useState(null),[f,d]=useState(true),[m,u]=useState(null),[i,o]=useState(false),a=useRef(true),s=e.apiBaseUrl,r=useCallback(async()=>{try{d(!0),u(null);let l=await fetch(`${s}/api/payout`,{credentials:"include"});if(!l.ok)throw new Error(await p(l,`Failed to load payout account (${l.status})`));let g=await l.json();a.current&&t(g);}catch(l){a.current&&u(l instanceof Error?l.message:"Failed to load payout account");}finally{a.current&&d(false);}},[s]);useEffect(()=>(a.current=true,r(),()=>{a.current=false;}),[r]);let c=useCallback(async()=>{try{o(!0),u(null);let l=await fetch(`${s}/api/payout`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!l.ok&&l.status!==204)throw new Error(await p(l,`Disconnect failed (${l.status})`));return a.current&&t({method:null}),!0}catch(l){return a.current&&u(l instanceof Error?l.message:"Disconnect failed"),false}finally{a.current&&o(false);}},[s]);return {account:n,loading:f,error:m,refresh:r,disconnect:c,disconnecting:i}}function Ye(){let{config:e}=y(),[n,t]=useState(false),[f,d]=useState(null);return {startStripeConnect:useCallback(async()=>{try{t(!0),d(null);let u=await fetch(`${e.apiBaseUrl}/api/payout/stripe/start`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({stackId:e.stackId})});if(!u.ok)throw new Error(await p(u,`Stripe Connect start failed (${u.status})`));let i=await u.json();if(typeof window<"u"&&i.onboardingUrl){let o;try{o=new URL(i.onboardingUrl);}catch{throw new Error("Invalid onboarding URL")}if(o.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(o.hostname))throw new Error("Refusing to redirect to non-Stripe URL");window.location.href=o.toString();return}}catch(u){d(u instanceof Error?u.message:"Stripe Connect start failed");}finally{t(false);}},[e.apiBaseUrl,e.stackId]),starting:n,error:f}}function Ge(){if(typeof window>"u")return null;let e=window,n=e.solana,t=e.phantom?.solana;return ((n&&n.isPhantom?n:null)||(t&&t.isPhantom?t:null))??null}function Qe(e){let n="";for(let t=0;t<e.length;t+=1)n+=String.fromCharCode(e[t]);return typeof btoa=="function"?btoa(n):Buffer.from(e).toString("base64")}function et(){let{config:e}=y(),[n,t]=useState(false),[f,d]=useState(null);return {connectAndVerify:useCallback(async()=>{try{t(!0),d(null);let u=Ge();if(!u)throw new Error("Phantom wallet not found. Install Phantom to continue.");let o=(await u.connect()).publicKey.toString(),a=await fetch(`${e.apiBaseUrl}/api/payout/crypto/nonce`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({address:o})});if(!a.ok)throw new Error(await p(a,`Nonce request failed (${a.status})`));let{nonce:s,message:r}=await a.json(),c=new TextEncoder().encode(r),l=await u.signMessage(c,"utf8"),g=Qe(l.signature),h=await fetch(`${e.apiBaseUrl}/api/payout/crypto/verify`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({address:o,nonce:s,signature:g})});if(!h.ok)throw new Error(await p(h,`Verification failed (${h.status})`));return {address:o}}catch(u){let i=u instanceof Error?u:new Error("Wallet verification failed");return d(i.message),null}finally{t(false);}},[e.apiBaseUrl]),connecting:n,error:f}}
2
- export{et as useCryptoConnect,Le as useFilePaperwork,Je as useFilingDetail,Fe as useFilingHistory,ge as useKeyLedger,fe as useKeys,Pe as useListKey,he as useMintKey,ze as usePayoutAccount,ie as usePricing,Ce as useSolanaPayment,_e as useStackPayoutCapabilities,we as useStripeCheckout,Ye as useStripeConnect,xe as useTransferKey};
1
+ import {createContext,useState,useRef,useEffect,useCallback,useContext}from'react';import'react/jsx-runtime';var se=createContext(null);function y(){let e=useContext(se);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function oe(e,n){if(typeof e!="string"||e.length===0)return n;let r=e.replace(/[\u0000-\u001F\u007F]/g," ");return r.length>500?r.slice(0,500)+"\u2026":r}async function m(e,n){try{let r=await e.json();if(r&&typeof r=="object"&&"error"in r)return oe(r.error,n)}catch{}return n}function ae(){let{config:e}=y(),[n,r]=useState(null),[l,d]=useState(true),[p,f]=useState(null),c=useRef(true),s=useRef(e.apiBaseUrl);s.current=e.apiBaseUrl;let a=async()=>{try{c.current&&(d(!0),f(null));let t=await fetch(`${s.current}/api/keys/pricing`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Pricing unavailable (${t.status})`));let o=await t.json();c.current&&r(o);}catch(t){c.current&&f(t instanceof Error?t.message:"Failed to fetch pricing");}finally{c.current&&d(false);}};return useEffect(()=>{c.current=true,a();let t=setInterval(a,6e4);return ()=>{c.current=false,clearInterval(t);}},[]),{pricing:n,loading:l,error:p,refresh:a}}function fe(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key:e.id||e.key||e.keyPrefix||"",userId:e.userId||e.user_id||"",status:e.status||"active",tokenBalance:e.tokenBalance??e.currentTokenBalance??e.current_token_balance??0,maxTokens:e.maxTokens??e.initialTokenBalance??e.initial_token_balance??0,createdAt:String(e.createdAt??e.created_at??""),expiresAt:e.expiresAt,label:e.label||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function de(){let{config:e}=y(),[n,r]=useState([]),[l,d]=useState(true),[p,f]=useState(null),c=useRef(true),s=e.apiBaseUrl,a=useCallback(async()=>{try{d(!0),f(null);let o=await fetch(`${s}/api/keys`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to fetch keys (${o.status})`));let i=await o.json(),u=Array.isArray(i)?i:i.keys??[];c.current&&r(u.map(fe));}catch(o){c.current&&f(o instanceof Error?o.message:"Failed to fetch keys");}finally{c.current&&d(false);}},[s]);useEffect(()=>(c.current=true,a(),()=>{c.current=false;}),[a]);let t=n.reduce((o,i)=>o+i.tokenBalance,0);return {keys:n,totalBalance:t,loading:l,error:p,refresh:a}}var _=false;function h(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);if(!e)return _||(_=true,console.warn("[keyutils] __csrf cookie not found; mutations will be sent without a CSRF token")),{};let n=e[1];try{n=decodeURIComponent(n);}catch{}return {"x-csrf-token":n}}function H(e){let n=e.type||e.entry_type||"debit",r=e.amount??e.tokens??e.token_amount??0,l=e.description||e.memo||e.reason||pe(n);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:n,amount:r,description:l,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function pe(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function ke(e){let{config:n}=y(),[r,l]=useState([]),[d,p]=useState(false),[f,c]=useState(null),s=useRef(true),a=n.apiBaseUrl,t=useCallback(async()=>{if(e)try{p(!0),c(null);let o=await fetch(`${a}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to fetch ledger (${o.status})`));let i=await o.json(),u=Array.isArray(i)?i:i.entries??[];s.current&&l(u.map(H));}catch(o){s.current&&c(o instanceof Error?o.message:"Failed to fetch ledger");}finally{s.current&&p(false);}},[a,e]);return useEffect(()=>(s.current=true,t(),()=>{s.current=false;}),[t]),{entries:r,loading:d,error:f,refresh:t}}function Re(){let{config:e,callbacks:n}=y(),[r,l]=useState(false),[d,p]=useState(null),[f,c]=useState(null);return {mint:useCallback(async(a,t,o=1)=>{try{l(!0),c(null),n.onPaymentComplete?.(a,t);let i=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({paymentMethod:a,paymentRef:t,quantity:o,stackId:e.stackId})});if(!i.ok)throw new Error(await m(i,`Key generation failed (${i.status})`));let u=await i.json(),g=u.keys?.[0]||u,k={success:!0,key:{id:g.keyId||g.id||"",key:g.key||"",userId:g.userId||"",status:"active",tokenBalance:g.tokenBalance??g.currentTokenBalance??0,maxTokens:g.initialTokenBalance??g.tokenBalance??0,createdAt:String(g.createdAt||Date.now())},transactionId:t};return p(k),n.onMintSuccess?.(k),k}catch(i){let u=i instanceof Error?i:new Error("Key generation failed");return c(u.message),n.onMintError?.(u),{success:false,error:u.message}}finally{l(false);}},[e.apiBaseUrl,n]),minting:r,result:d,error:f}}function Ue(){let{config:e,callbacks:n}=y(),[r,l]=useState(false),[d,p]=useState(null),[f,c]=useState(null),s=useRef(true),a=useCallback(async(o,i)=>{try{l(!0),c(null);let u=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({askPriceCents:i,stackId:e.stackId,stackName:e.stackName})});if(!u.ok)throw new Error(await m(u,`Listing failed (${u.status})`));let g=await u.json();return s.current&&(p(g),n.onListingCreated?.(g)),g}catch(u){let g=u instanceof Error?u.message:"Listing failed";return s.current&&c(g),null}finally{s.current&&l(false);}},[e.apiBaseUrl,e.stackId,e.stackName,n]),t=useCallback(async o=>{try{l(!0),c(null);let i=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/list`,{method:"DELETE",headers:{...h()},credentials:"include"});if(!i.ok)throw new Error(await m(i,`Delist failed (${i.status})`));return s.current&&p(null),!0}catch(i){let u=i instanceof Error?i.message:"Delist failed";return s.current&&c(u),false}finally{s.current&&l(false);}},[e.apiBaseUrl]);return {listKey:a,delistKey:t,listing:r,result:d,error:f}}function Ee(){let{config:e}=y(),[n,r]=useState(false),[l,d]=useState(null),p=useRef(true);return {createSession:useCallback(async(c,s)=>{try{r(!0),d(null);let a=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({priceCents:c,quantity:s,stackId:e.stackId,referrerUrl:window.location.href})});if(!a.ok)throw new Error(await m(a,`Checkout failed (${a.status})`));let{url:t}=await a.json();if(!t)throw new Error("No checkout URL returned");let o;try{o=new URL(t);}catch{throw new Error("Invalid checkout URL")}if(o.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(o.hostname))throw new Error("Refusing to redirect to non-Stripe URL");try{sessionStorage.setItem("keyutils_stripe_pending","1"),sessionStorage.setItem("keyutils_stripe_quantity",String(s));}catch{}window.location.href=o.toString();}catch(a){if(p.current){let t=a instanceof Error?a.message:"Checkout failed";d(t),r(false);}}},[e.apiBaseUrl,e.stackId]),loading:n,error:l}}function j(e,n="#"){if(!e||typeof e!="string")return n;let r=e.trim();if(r===""||r==="#")return n;if(r.startsWith("/")||r.startsWith("./")||r.startsWith("../"))return r;try{let l=new URL(r);if(l.protocol==="http:"||l.protocol==="https:")return l.toString()}catch{}return n}var J=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function Se(){let{config:e}=y(),[n,r]=useState(false),[l,d]=useState(null);return {pay:useCallback(async f=>{if(!e.merchantWallet||!J.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{r(!0),d(null);let{Connection:c,PublicKey:s,Transaction:a,SystemProgram:t}=await import('@solana/web3.js'),o=typeof window<"u"?window.solana:void 0;if(!o||typeof o!="object"||!o.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let i=o,u=new s(e.merchantWallet),g=await i.connect(),k=new s(g.publicKey.toString()),R="https://api.mainnet-beta.solana.com",P=j(e.solanaRpcUrl,R),Y=P==="#"?R:P,Z=new c(Y),{blockhash:G}=await Z.getLatestBlockhash(),b=BigInt(Math.floor(f*1e9)),w=e.protocolTreasuryWallet,A=e.protocolFeeBps??500,E=new a({recentBlockhash:G,feePayer:k});if(w&&J.test(w)&&A>0){let v=b*BigInt(A)/10000n,ee=b-v,te=new s(w);E.add(t.transfer({fromPubkey:k,toPubkey:u,lamports:Number(ee)}),t.transfer({fromPubkey:k,toPubkey:te,lamports:Number(v)}));}else E.add(t.transfer({fromPubkey:k,toPubkey:u,lamports:Number(b)}));let{signature:Q}=await i.signAndSendTransaction(E);return Q}catch(c){let s=c instanceof Error?c:new Error("SOL payment failed");throw d(s.message),s}finally{r(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:n,error:l}}function Ie(){let{config:e,callbacks:n}=y(),[r,l]=useState(false),[d,p]=useState(null),[f,c]=useState(null),s=useRef(true);return {transferKey:useCallback(async(t,o)=>{try{l(!0),c(null);let i=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(t)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({recipientId:o})});if(!i.ok)throw new Error(await m(i,`Transfer failed (${i.status})`));let u=await i.json();return s.current&&(p(u),n.onTransferComplete?.(u)),u}catch(i){let u=i instanceof Error?i.message:"Transfer failed";return s.current&&c(u),null}finally{s.current&&l(false);}},[e.apiBaseUrl,n]),transferring:r,result:d,error:f}}function Be(){let{config:e,callbacks:n}=y(),[r,l]=useState(false),[d,p]=useState(null),[f,c]=useState(null),s=useRef(true);useEffect(()=>(s.current=true,()=>{s.current=false;}),[]);let a=useCallback(async(o,i)=>{try{l(!0),c(null);let u={stackId:e.stackId};i&&(u.payoutMethod=i);let g=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(o)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify(u)});if(!g.ok)throw new Error(await m(g,`Filing failed (${g.status})`));let k=await g.json();return s.current&&(p(k),n.onFilingComplete?.(k)),k}catch(u){let g=u instanceof Error?u:new Error("Filing failed");return s.current&&c(g.message),n.onFilingError?.(g),null}finally{s.current&&l(false);}},[e.apiBaseUrl,e.stackId,n]),t=useCallback(()=>{p(null),c(null);},[]);return {filePaperwork:a,filing:r,result:d,error:f,reset:t}}function Ae(){let{config:e}=y(),[n,r]=useState([]),[l,d]=useState(true),[p,f]=useState(null),c=useRef(true),s=e.apiBaseUrl,a=useCallback(async()=>{try{d(!0),f(null);let t=await fetch(`${s}/api/keys/filings`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Failed to fetch filings (${t.status})`));let o=await t.json(),i=Array.isArray(o)?o:o.filings??[];c.current&&r(i);}catch(t){c.current&&f(t instanceof Error?t.message:"Failed to fetch filings");}finally{c.current&&d(false);}},[s]);return useEffect(()=>(c.current=true,a(),()=>{c.current=false;}),[a]),{entries:n,loading:l,error:p,refresh:a}}function He(e){let{config:n}=y(),r=e??n.stackId,l=n.apiBaseUrl,[d,p]=useState(null),[f,c]=useState(!!r),[s,a]=useState(null),t=useRef(true),o=useCallback(async()=>{if(!r){p(null),c(false);return}try{c(!0),a(null);let i=await fetch(`${l}/api/stacks/${encodeURIComponent(r)}/payout-capabilities`,{credentials:"include"});if(!i.ok)throw new Error(await m(i,`Failed to load payout capabilities (${i.status})`));let u=await i.json();t.current&&p(u);}catch(i){t.current&&a(i instanceof Error?i.message:"Failed to load payout capabilities");}finally{t.current&&c(false);}},[l,r]);return useEffect(()=>(t.current=true,o(),()=>{t.current=false;}),[o]),{caps:d,loading:f,error:s,refresh:o}}var We=5e3;function Je(e){return e==="paid"||e==="failed"}function qe(e){let{config:n}=y(),r=n.apiBaseUrl,[l,d]=useState(null),[p,f]=useState(!!e),[c,s]=useState(null),a=useRef(true),t=useCallback(async()=>{if(!e){d(null),f(false);return}try{s(null);let o=await fetch(`${r}/api/keys/filings/${encodeURIComponent(e)}`,{credentials:"include"});if(!o.ok)throw new Error(await m(o,`Failed to load filing (${o.status})`));let i=await o.json();a.current&&d(i);}catch(o){a.current&&s(o instanceof Error?o.message:"Failed to load filing");}finally{a.current&&f(false);}},[r,e]);return useEffect(()=>{if(a.current=true,!e)return d(null),f(false),()=>{a.current=false;};f(true),t();let o=setInterval(()=>{a.current&&(l&&Je(l.status)||t());},We);return ()=>{a.current=false,clearInterval(o);}},[e,t,l]),{detail:l,loading:p,error:c,refresh:t}}function Xe(e){let{config:n}=y(),r=e??n.stackId??"",l=n.apiBaseUrl,[d,p]=useState(null),[f,c]=useState(true),[s,a]=useState(null),[t,o]=useState(false),i=useRef(true),u=useCallback(async()=>{try{c(!0),a(null);let k=r?`${l}/api/payout?stackId=${encodeURIComponent(r)}`:`${l}/api/payout`,R=await fetch(k,{credentials:"include"});if(!R.ok)throw new Error(await m(R,`Failed to load payout account (${R.status})`));let P=await R.json();i.current&&p(P);}catch(k){i.current&&a(k instanceof Error?k.message:"Failed to load payout account");}finally{i.current&&c(false);}},[l,r]);useEffect(()=>(i.current=true,u(),()=>{i.current=false;}),[u]);let g=useCallback(async k=>{try{o(!0),a(null);let R=k?`${l}/api/payout?stackId=${encodeURIComponent(k)}`:`${l}/api/payout`,P=await fetch(R,{method:"DELETE",headers:{...h()},credentials:"include"});if(!P.ok&&P.status!==204)throw new Error(await m(P,`Disconnect failed (${P.status})`));return await u(),!0}catch(R){return i.current&&a(R instanceof Error?R.message:"Disconnect failed"),false}finally{i.current&&o(false);}},[l,u]);return {account:d,loading:f,error:s,refresh:u,disconnect:g,disconnecting:t}}function Qe(){let{config:e}=y(),n=e.apiBaseUrl,[r,l]=useState([]),[d,p]=useState(true),[f,c]=useState(null),s=useRef(true),a=useCallback(async()=>{try{p(!0),c(null);let t=await fetch(`${n}/api/payout/stripe-stacks`,{credentials:"include"});if(!t.ok)throw new Error(await m(t,`Failed to load stripe stacks (${t.status})`));let o=await t.json();s.current&&l(o.stacks??[]);}catch(t){s.current&&c(t instanceof Error?t.message:"Failed to load stripe stacks");}finally{s.current&&p(false);}},[n]);return useEffect(()=>(s.current=true,a(),()=>{s.current=false;}),[a]),{stacks:r,loading:d,error:f,refresh:a}}function tt(e){let{config:n}=y(),r=e??n.stackId,[l,d]=useState(false),[p,f]=useState(null);return {startStripeConnect:useCallback(async()=>{try{d(!0),f(null);let s=await fetch(`${n.apiBaseUrl}/api/payout/stripe/start`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({stackId:r})});if(!s.ok)throw new Error(await m(s,`Stripe Connect start failed (${s.status})`));let a=await s.json();if(typeof window<"u"&&a.onboardingUrl){let t;try{t=new URL(a.onboardingUrl);}catch{throw new Error("Invalid onboarding URL")}if(t.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(t.hostname))throw new Error("Refusing to redirect to non-Stripe URL");window.location.href=t.toString();return}}catch(s){f(s instanceof Error?s.message:"Stripe Connect start failed");}finally{d(false);}},[n.apiBaseUrl,r]),starting:l,error:p}}function nt(){if(typeof window>"u")return null;let e=window,n=e.solana,r=e.phantom?.solana;return ((n&&n.isPhantom?n:null)||(r&&r.isPhantom?r:null))??null}function st(e){let n="";for(let r=0;r<e.length;r+=1)n+=String.fromCharCode(e[r]);return typeof btoa=="function"?btoa(n):Buffer.from(e).toString("base64")}function ot(){let{config:e}=y(),[n,r]=useState(false),[l,d]=useState(null);return {connectAndVerify:useCallback(async()=>{try{r(!0),d(null);let f=nt();if(!f)throw new Error("Phantom wallet not found. Install Phantom to continue.");let s=(await f.connect()).publicKey.toString(),a=await fetch(`${e.apiBaseUrl}/api/payout/crypto/nonce`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({address:s})});if(!a.ok)throw new Error(await m(a,`Nonce request failed (${a.status})`));let{nonce:t,message:o}=await a.json(),i=new TextEncoder().encode(o),u=await f.signMessage(i,"utf8"),g=st(u.signature),k=await fetch(`${e.apiBaseUrl}/api/payout/crypto/verify`,{method:"POST",headers:{"Content-Type":"application/json",...h()},credentials:"include",body:JSON.stringify({address:s,nonce:t,signature:g})});if(!k.ok)throw new Error(await m(k,`Verification failed (${k.status})`));return {address:s}}catch(f){let c=f instanceof Error?f:new Error("Wallet verification failed");return d(c.message),null}finally{r(false);}},[e.apiBaseUrl]),connecting:n,error:l}}
2
+ export{ot as useCryptoConnect,Be as useFilePaperwork,qe as useFilingDetail,Ae as useFilingHistory,ke as useKeyLedger,de as useKeys,Ue as useListKey,Re as useMintKey,Xe as usePayoutAccount,ae as usePricing,Se as useSolanaPayment,He as useStackPayoutCapabilities,Ee as useStripeCheckout,tt as useStripeConnect,Ie as useTransferKey,Qe as useUserStripeStacks};