@stacknet/keyutils 0.4.8 → 0.6.0

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 Y=react.createContext(null);function m(){let e=react.useContext(Y);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function Z(e,a){if(typeof e!="string"||e.length===0)return a;let i=e.replace(/[\u0000-\u001F\u007F]/g," ");return i.length>500?i.slice(0,500)+"\u2026":i}async function y(e,a){try{let i=await e.json();if(i&&typeof i=="object"&&"error"in i)return Z(i.error,a)}catch{}return a}function Q(){let{config:e}=m(),[a,i]=react.useState(null),[u,f]=react.useState(true),[d,g]=react.useState(null),r=react.useRef(true),o=react.useRef(e.apiBaseUrl);o.current=e.apiBaseUrl;let l=async()=>{try{r.current&&(f(!0),g(null));let s=await fetch(`${o.current}/api/keys/pricing`,{credentials:"include"});if(!s.ok)throw new Error(await y(s,`Pricing unavailable (${s.status})`));let n=await s.json();r.current&&i(n);}catch(s){r.current&&g(s instanceof Error?s.message:"Failed to fetch pricing");}finally{r.current&&f(false);}};return react.useEffect(()=>{r.current=true,l();let s=setInterval(l,6e4);return ()=>{r.current=false,clearInterval(s);}},[]),{pricing:a,loading:u,error:d,refresh:l}}function ne(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key: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||e.keyPrefix||e.key_prefix||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function se(){let{config:e}=m(),[a,i]=react.useState([]),[u,f]=react.useState(true),[d,g]=react.useState(null),r=react.useRef(true),o=e.apiBaseUrl,l=react.useCallback(async()=>{try{f(!0),g(null);let n=await fetch(`${o}/api/keys`,{credentials:"include"});if(!n.ok)throw new Error(await y(n,`Failed to fetch keys (${n.status})`));let t=await n.json(),c=Array.isArray(t)?t:t.keys??[];r.current&&i(c.map(ne));}catch(n){r.current&&g(n instanceof Error?n.message:"Failed to fetch keys");}finally{r.current&&f(false);}},[o]);react.useEffect(()=>(r.current=true,l(),()=>{r.current=false;}),[l]);let s=a.reduce((n,t)=>n+t.tokenBalance,0);return {keys:a,totalBalance:s,loading:u,error:d,refresh:l}}function N(e){let a=e.type||e.entry_type||"debit",i=e.amount??e.tokens??e.token_amount??0,u=e.description||e.memo||e.reason||ie(a);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:a,amount:i,description:u,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function ie(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function le(e){let{config:a}=m(),[i,u]=react.useState([]),[f,d]=react.useState(false),[g,r]=react.useState(null),o=react.useRef(true),l=a.apiBaseUrl,s=react.useCallback(async()=>{if(e)try{d(!0),r(null);let n=await fetch(`${l}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!n.ok)throw new Error(await y(n,`Failed to fetch ledger (${n.status})`));let t=await n.json(),c=Array.isArray(t)?t:t.entries??[];o.current&&u(c.map(N));}catch(n){o.current&&r(n instanceof Error?n.message:"Failed to fetch ledger");}finally{o.current&&d(false);}},[l,e]);return react.useEffect(()=>(o.current=true,s(),()=>{o.current=false;}),[s]),{entries:i,loading:f,error:g,refresh:s}}function k(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);return e?{"x-csrf-token":e[1]}:{}}function fe(){let{config:e,callbacks:a}=m(),[i,u]=react.useState(false),[f,d]=react.useState(null),[g,r]=react.useState(null);return {mint:react.useCallback(async(l,s,n=1)=>{try{u(!0),r(null),a.onPaymentComplete?.(l,s);let t=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({paymentMethod:l,paymentRef:s,quantity:n,stackId:e.stackId})});if(!t.ok)throw new Error(await y(t,`Key generation failed (${t.status})`));let c=await t.json(),p=c.keys?.[0]||c,h={success:!0,key:{id:p.keyId||p.id||"",key:p.key||"",userId:p.userId||"",status:"active",tokenBalance:p.tokenBalance??p.currentTokenBalance??0,maxTokens:p.initialTokenBalance??p.tokenBalance??0,createdAt:String(p.createdAt||Date.now())},transactionId:s};return d(h),a.onMintSuccess?.(h),h}catch(t){let c=t instanceof Error?t:new Error("Key generation failed");return r(c.message),a.onMintError?.(c),{success:false,error:c.message}}finally{u(false);}},[e.apiBaseUrl,a]),minting:i,result:f,error:g}}function ge(){let{config:e,callbacks:a}=m(),[i,u]=react.useState(false),[f,d]=react.useState(null),[g,r]=react.useState(null),o=react.useRef(true),l=react.useCallback(async(n,t)=>{try{u(!0),r(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({askPriceCents:t,stackId:e.stackId,stackName:e.stackName})});if(!c.ok)throw new Error(await y(c,`Listing failed (${c.status})`));let p=await c.json();return o.current&&(d(p),a.onListingCreated?.(p)),p}catch(c){let p=c instanceof Error?c.message:"Listing failed";return o.current&&r(p),null}finally{o.current&&u(false);}},[e.apiBaseUrl,e.stackId,e.stackName,a]),s=react.useCallback(async n=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/list`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!t.ok)throw new Error(await y(t,`Delist failed (${t.status})`));return o.current&&d(null),!0}catch(t){let c=t instanceof Error?t.message:"Delist failed";return o.current&&r(c),false}finally{o.current&&u(false);}},[e.apiBaseUrl]);return {listKey:l,delistKey:s,listing:i,result:f,error:g}}function pe(){let{config:e}=m(),[a,i]=react.useState(false),[u,f]=react.useState(null),d=react.useRef(true);return {createSession:react.useCallback(async(r,o)=>{try{i(!0),f(null);let l=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({priceCents:r,quantity:o,stackId:e.stackId,referrerUrl:window.location.href})});if(!l.ok)throw new Error(await y(l,`Checkout failed (${l.status})`));let{url:s}=await l.json();if(!s)throw new Error("No checkout URL returned");let n;try{n=new URL(s);}catch{throw new Error("Invalid checkout URL")}if(n.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(n.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=n.toString();}catch(l){if(d.current){let s=l instanceof Error?l.message:"Checkout failed";f(s),i(false);}}},[e.apiBaseUrl,e.stackId]),loading:a,error:u}}function H(e,a="#"){if(!e||typeof e!="string")return a;let i=e.trim();if(i===""||i==="#")return a;if(i.startsWith("/")||i.startsWith("./")||i.startsWith("../"))return i;try{let u=new URL(i);if(u.protocol==="http:"||u.protocol==="https:")return u.toString()}catch{}return a}var v=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function he(){let{config:e}=m(),[a,i]=react.useState(false),[u,f]=react.useState(null);return {pay:react.useCallback(async g=>{if(!e.merchantWallet||!v.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{i(!0),f(null);let{Connection:r,PublicKey:o,Transaction:l,SystemProgram:s}=await import('@solana/web3.js'),n=typeof window<"u"?window.solana:void 0;if(!n||typeof n!="object"||!n.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let t=n,c=new o(e.merchantWallet),p=await t.connect(),h=new o(p.publicKey.toString()),L="https://api.mainnet-beta.solana.com",T=H(e.solanaRpcUrl,L),j=T==="#"?L:T,D=new r(j),{blockhash:W}=await D.getLatestBlockhash(),R=BigInt(Math.floor(g*1e9)),P=e.protocolTreasuryWallet,B=e.protocolFeeBps??500,b=new l({recentBlockhash:W,feePayer:h});if(P&&v.test(P)&&B>0){let M=R*BigInt(B)/10000n,q=R-M,z=new o(P);b.add(s.transfer({fromPubkey:h,toPubkey:c,lamports:Number(q)}),s.transfer({fromPubkey:h,toPubkey:z,lamports:Number(M)}));}else b.add(s.transfer({fromPubkey:h,toPubkey:c,lamports:Number(R)}));let{signature:J}=await t.signAndSendTransaction(b);return J}catch(r){let o=r instanceof Error?r:new Error("SOL payment failed");throw f(o.message),o}finally{i(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:a,error:u}}function be(){let{config:e,callbacks:a}=m(),[i,u]=react.useState(false),[f,d]=react.useState(null),[g,r]=react.useState(null),o=react.useRef(true);return {transferKey:react.useCallback(async(s,n)=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(s)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({recipientId:n})});if(!t.ok)throw new Error(await y(t,`Transfer failed (${t.status})`));let c=await t.json();return o.current&&(d(c),a.onTransferComplete?.(c)),c}catch(t){let c=t instanceof Error?t.message:"Transfer failed";return o.current&&r(c),null}finally{o.current&&u(false);}},[e.apiBaseUrl,a]),transferring:i,result:f,error:g}}function Ee(){let{config:e,callbacks:a}=m(),[i,u]=react.useState(false),[f,d]=react.useState(null),[g,r]=react.useState(null),o=react.useRef(true),l=react.useCallback(async n=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({stackId:e.stackId})});if(!t.ok)throw new Error(await y(t,`Filing failed (${t.status})`));let c=await t.json();return o.current&&(d(c),a.onFilingComplete?.(c)),c}catch(t){let c=t instanceof Error?t:new Error("Filing failed");return o.current&&r(c.message),a.onFilingError?.(c),null}finally{o.current&&u(false);}},[e.apiBaseUrl,e.stackId,a]),s=react.useCallback(()=>{d(null),r(null);},[]);return {filePaperwork:l,filing:i,result:f,error:g,reset:s}}function Ie(){let{config:e}=m(),[a,i]=react.useState([]),[u,f]=react.useState(true),[d,g]=react.useState(null),r=react.useRef(true),o=e.apiBaseUrl,l=react.useCallback(async()=>{try{f(!0),g(null);let s=await fetch(`${o}/api/keys/filings`,{credentials:"include"});if(!s.ok)throw new Error(await y(s,`Failed to fetch filings (${s.status})`));let n=await s.json(),t=Array.isArray(n)?n:n.filings??[];r.current&&i(t);}catch(s){r.current&&g(s instanceof Error?s.message:"Failed to fetch filings");}finally{r.current&&f(false);}},[o]);return react.useEffect(()=>(r.current=true,l(),()=>{r.current=false;}),[l]),{entries:a,loading:u,error:d,refresh:l}}
2
- exports.useFilePaperwork=Ee;exports.useFilingHistory=Ie;exports.useKeyLedger=le;exports.useKeys=se;exports.useListKey=ge;exports.useMintKey=fe;exports.usePricing=Q;exports.useSolanaPayment=he;exports.useStripeCheckout=pe;exports.useTransferKey=be;
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, FilingResult, FilingHistoryEntry } 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;
@@ -72,7 +72,7 @@ interface UseTransferKeyReturn {
72
72
  declare function useTransferKey(): UseTransferKeyReturn;
73
73
 
74
74
  interface UseFilePaperworkReturn {
75
- filePaperwork: (keyId: string) => Promise<FilingResult | null>;
75
+ filePaperwork: (keyId: string, payoutMethod?: PayoutMethod | null) => Promise<FilingResult | null>;
76
76
  filing: boolean;
77
77
  result: FilingResult | null;
78
78
  error: string | null;
@@ -82,11 +82,17 @@ interface UseFilePaperworkReturn {
82
82
  * File paperwork against an eligible NodeKey to redeem Paper.
83
83
  *
84
84
  * Backend contract: POST {apiBaseUrl}/api/keys/{keyId}/file
85
- * Response: FilingResult JSON
86
- *
87
- * The backend reads the prepared paperWork blob attached to the key,
88
- * submits the on-chain prove instruction, and triggers the multisig
89
- * payout to the user's stack-scoped payment_address.
85
+ * Request body: { stackId?, payoutMethod? }
86
+ * - On stacknet versions that read from `user_payout_accounts`, the body
87
+ * can omit everything user-controlled the server derives the method
88
+ * and destination from the user's saved earnings account.
89
+ * - For backward compatibility with stacknet versions that still REQUIRE
90
+ * `payoutMethod` in the body, callers can pass the method they read
91
+ * from `usePayoutAccount()`. The server (new path) verifies the hint
92
+ * matches the saved record and rejects mismatches with 400.
93
+ * - Memo, amount, beneficiary are always server-derived.
94
+ * Response: FilingResult JSON with `filingId` (used to look up the detail /
95
+ * tracker view at /files/{filingId}).
90
96
  */
91
97
  declare function useFilePaperwork(): UseFilePaperworkReturn;
92
98
 
@@ -104,4 +110,126 @@ interface UseFilingHistoryReturn {
104
110
  */
105
111
  declare function useFilingHistory(): UseFilingHistoryReturn;
106
112
 
107
- export { useFilePaperwork, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePricing, useSolanaPayment, useStripeCheckout, useTransferKey };
113
+ interface UseStackPayoutCapabilitiesReturn {
114
+ caps: StackPayoutCapabilities | null;
115
+ loading: boolean;
116
+ error: string | null;
117
+ refresh: () => Promise<void>;
118
+ }
119
+ /**
120
+ * Fetch per-stack payout capabilities (which methods are configured + the
121
+ * default destination address). Drives the payout-method picker — Stripe
122
+ * tile is rendered disabled with "disabled by {stackName} stack" UX when
123
+ * `caps.stripe.enabled === false`.
124
+ *
125
+ * Backend contract: GET {apiBaseUrl}/api/stacks/{stackId}/payout-capabilities
126
+ *
127
+ * Falls back gracefully when no stackId is configured — returns null caps.
128
+ */
129
+ declare function useStackPayoutCapabilities(stackIdOverride?: string): UseStackPayoutCapabilitiesReturn;
130
+
131
+ interface UseFilingDetailReturn {
132
+ detail: FilingDetail | null;
133
+ loading: boolean;
134
+ error: string | null;
135
+ refresh: () => Promise<void>;
136
+ }
137
+ /**
138
+ * Fetch a single filing's detail (status, tracker, tx sigs, etc.) and poll
139
+ * every 5 s while non-terminal. Stops polling once status is `paid` or
140
+ * `failed`. Used by both the inline post-submit tracker and the standalone
141
+ * /files/{id} route.
142
+ *
143
+ * Backend contract: GET {apiBaseUrl}/api/keys/filings/{filingId}
144
+ */
145
+ declare function useFilingDetail(filingId: string | null | undefined): UseFilingDetailReturn;
146
+
147
+ interface UsePayoutAccountReturn {
148
+ account: PayoutAccount | null;
149
+ loading: boolean;
150
+ error: string | null;
151
+ refresh: () => Promise<void>;
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>;
159
+ disconnecting: boolean;
160
+ }
161
+ /**
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).
170
+ *
171
+ * Backend contract:
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…").
190
+ *
191
+ * Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
192
+ * response: { stacks: StripeStackPayout[] }
193
+ */
194
+ declare function useUserStripeStacks(): UseUserStripeStacksReturn;
195
+
196
+ interface UseStripeConnectReturn {
197
+ /**
198
+ * Kick off Stripe Connect Express onboarding. Server creates an Express
199
+ * connected account under the stack's platform Stripe credentials,
200
+ * generates an AccountLink, and returns its URL. The browser is then
201
+ * redirected to that URL — Stripe hosts the rest of the onboarding flow
202
+ * (KYC, bank details, payouts opt-in) and bounces back to
203
+ * `/settings?tab=account&stripe_return=1` when complete.
204
+ */
205
+ startStripeConnect: () => Promise<void>;
206
+ starting: boolean;
207
+ error: string | null;
208
+ }
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
+ *
215
+ * Backend contract: POST {apiBaseUrl}/api/payout/stripe/start
216
+ * body: { stackId }
217
+ * response: StripeConnectStartResponse
218
+ */
219
+ declare function useStripeConnect(stackIdOverride?: string): UseStripeConnectReturn;
220
+
221
+ interface UseCryptoConnectReturn {
222
+ /**
223
+ * Connect Phantom, request a nonce from the server, sign it, and POST the
224
+ * signature back for verification. On success the server saves the address
225
+ * as the user's payout destination.
226
+ */
227
+ connectAndVerify: () => Promise<{
228
+ address: string;
229
+ } | null>;
230
+ connecting: boolean;
231
+ error: string | null;
232
+ }
233
+ declare function useCryptoConnect(): UseCryptoConnectReturn;
234
+
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, FilingResult, FilingHistoryEntry } 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;
@@ -72,7 +72,7 @@ interface UseTransferKeyReturn {
72
72
  declare function useTransferKey(): UseTransferKeyReturn;
73
73
 
74
74
  interface UseFilePaperworkReturn {
75
- filePaperwork: (keyId: string) => Promise<FilingResult | null>;
75
+ filePaperwork: (keyId: string, payoutMethod?: PayoutMethod | null) => Promise<FilingResult | null>;
76
76
  filing: boolean;
77
77
  result: FilingResult | null;
78
78
  error: string | null;
@@ -82,11 +82,17 @@ interface UseFilePaperworkReturn {
82
82
  * File paperwork against an eligible NodeKey to redeem Paper.
83
83
  *
84
84
  * Backend contract: POST {apiBaseUrl}/api/keys/{keyId}/file
85
- * Response: FilingResult JSON
86
- *
87
- * The backend reads the prepared paperWork blob attached to the key,
88
- * submits the on-chain prove instruction, and triggers the multisig
89
- * payout to the user's stack-scoped payment_address.
85
+ * Request body: { stackId?, payoutMethod? }
86
+ * - On stacknet versions that read from `user_payout_accounts`, the body
87
+ * can omit everything user-controlled the server derives the method
88
+ * and destination from the user's saved earnings account.
89
+ * - For backward compatibility with stacknet versions that still REQUIRE
90
+ * `payoutMethod` in the body, callers can pass the method they read
91
+ * from `usePayoutAccount()`. The server (new path) verifies the hint
92
+ * matches the saved record and rejects mismatches with 400.
93
+ * - Memo, amount, beneficiary are always server-derived.
94
+ * Response: FilingResult JSON with `filingId` (used to look up the detail /
95
+ * tracker view at /files/{filingId}).
90
96
  */
91
97
  declare function useFilePaperwork(): UseFilePaperworkReturn;
92
98
 
@@ -104,4 +110,126 @@ interface UseFilingHistoryReturn {
104
110
  */
105
111
  declare function useFilingHistory(): UseFilingHistoryReturn;
106
112
 
107
- export { useFilePaperwork, useFilingHistory, useKeyLedger, useKeys, useListKey, useMintKey, usePricing, useSolanaPayment, useStripeCheckout, useTransferKey };
113
+ interface UseStackPayoutCapabilitiesReturn {
114
+ caps: StackPayoutCapabilities | null;
115
+ loading: boolean;
116
+ error: string | null;
117
+ refresh: () => Promise<void>;
118
+ }
119
+ /**
120
+ * Fetch per-stack payout capabilities (which methods are configured + the
121
+ * default destination address). Drives the payout-method picker — Stripe
122
+ * tile is rendered disabled with "disabled by {stackName} stack" UX when
123
+ * `caps.stripe.enabled === false`.
124
+ *
125
+ * Backend contract: GET {apiBaseUrl}/api/stacks/{stackId}/payout-capabilities
126
+ *
127
+ * Falls back gracefully when no stackId is configured — returns null caps.
128
+ */
129
+ declare function useStackPayoutCapabilities(stackIdOverride?: string): UseStackPayoutCapabilitiesReturn;
130
+
131
+ interface UseFilingDetailReturn {
132
+ detail: FilingDetail | null;
133
+ loading: boolean;
134
+ error: string | null;
135
+ refresh: () => Promise<void>;
136
+ }
137
+ /**
138
+ * Fetch a single filing's detail (status, tracker, tx sigs, etc.) and poll
139
+ * every 5 s while non-terminal. Stops polling once status is `paid` or
140
+ * `failed`. Used by both the inline post-submit tracker and the standalone
141
+ * /files/{id} route.
142
+ *
143
+ * Backend contract: GET {apiBaseUrl}/api/keys/filings/{filingId}
144
+ */
145
+ declare function useFilingDetail(filingId: string | null | undefined): UseFilingDetailReturn;
146
+
147
+ interface UsePayoutAccountReturn {
148
+ account: PayoutAccount | null;
149
+ loading: boolean;
150
+ error: string | null;
151
+ refresh: () => Promise<void>;
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>;
159
+ disconnecting: boolean;
160
+ }
161
+ /**
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).
170
+ *
171
+ * Backend contract:
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…").
190
+ *
191
+ * Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
192
+ * response: { stacks: StripeStackPayout[] }
193
+ */
194
+ declare function useUserStripeStacks(): UseUserStripeStacksReturn;
195
+
196
+ interface UseStripeConnectReturn {
197
+ /**
198
+ * Kick off Stripe Connect Express onboarding. Server creates an Express
199
+ * connected account under the stack's platform Stripe credentials,
200
+ * generates an AccountLink, and returns its URL. The browser is then
201
+ * redirected to that URL — Stripe hosts the rest of the onboarding flow
202
+ * (KYC, bank details, payouts opt-in) and bounces back to
203
+ * `/settings?tab=account&stripe_return=1` when complete.
204
+ */
205
+ startStripeConnect: () => Promise<void>;
206
+ starting: boolean;
207
+ error: string | null;
208
+ }
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
+ *
215
+ * Backend contract: POST {apiBaseUrl}/api/payout/stripe/start
216
+ * body: { stackId }
217
+ * response: StripeConnectStartResponse
218
+ */
219
+ declare function useStripeConnect(stackIdOverride?: string): UseStripeConnectReturn;
220
+
221
+ interface UseCryptoConnectReturn {
222
+ /**
223
+ * Connect Phantom, request a nonce from the server, sign it, and POST the
224
+ * signature back for verification. On success the server saves the address
225
+ * as the user's payout destination.
226
+ */
227
+ connectAndVerify: () => Promise<{
228
+ address: string;
229
+ } | null>;
230
+ connecting: boolean;
231
+ error: string | null;
232
+ }
233
+ declare function useCryptoConnect(): UseCryptoConnectReturn;
234
+
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 Y=createContext(null);function m(){let e=useContext(Y);if(!e)throw new Error("useKeyUtilsContext must be used within a KeyUtilsProvider");return e}function Z(e,a){if(typeof e!="string"||e.length===0)return a;let i=e.replace(/[\u0000-\u001F\u007F]/g," ");return i.length>500?i.slice(0,500)+"\u2026":i}async function y(e,a){try{let i=await e.json();if(i&&typeof i=="object"&&"error"in i)return Z(i.error,a)}catch{}return a}function Q(){let{config:e}=m(),[a,i]=useState(null),[u,f]=useState(true),[d,g]=useState(null),r=useRef(true),o=useRef(e.apiBaseUrl);o.current=e.apiBaseUrl;let l=async()=>{try{r.current&&(f(!0),g(null));let s=await fetch(`${o.current}/api/keys/pricing`,{credentials:"include"});if(!s.ok)throw new Error(await y(s,`Pricing unavailable (${s.status})`));let n=await s.json();r.current&&i(n);}catch(s){r.current&&g(s instanceof Error?s.message:"Failed to fetch pricing");}finally{r.current&&f(false);}};return useEffect(()=>{r.current=true,l();let s=setInterval(l,6e4);return ()=>{r.current=false,clearInterval(s);}},[]),{pricing:a,loading:u,error:d,refresh:l}}function ne(e){return {id:e.id||"",keyIndex:e.keyIndex??e.key_index??null,key: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||e.keyPrefix||e.key_prefix||void 0,paperWork:e.paperWork||e.paper_work||void 0,stackId:e.stackId,stackName:e.stackName}}function se(){let{config:e}=m(),[a,i]=useState([]),[u,f]=useState(true),[d,g]=useState(null),r=useRef(true),o=e.apiBaseUrl,l=useCallback(async()=>{try{f(!0),g(null);let n=await fetch(`${o}/api/keys`,{credentials:"include"});if(!n.ok)throw new Error(await y(n,`Failed to fetch keys (${n.status})`));let t=await n.json(),c=Array.isArray(t)?t:t.keys??[];r.current&&i(c.map(ne));}catch(n){r.current&&g(n instanceof Error?n.message:"Failed to fetch keys");}finally{r.current&&f(false);}},[o]);useEffect(()=>(r.current=true,l(),()=>{r.current=false;}),[l]);let s=a.reduce((n,t)=>n+t.tokenBalance,0);return {keys:a,totalBalance:s,loading:u,error:d,refresh:l}}function N(e){let a=e.type||e.entry_type||"debit",i=e.amount??e.tokens??e.token_amount??0,u=e.description||e.memo||e.reason||ie(a);return {id:e.id||"",keyId:e.keyId||e.key_id||"",type:a,amount:i,description:u,createdAt:String(e.createdAt??e.created_at??e.timestamp??""),metadata:e.metadata||void 0}}function ie(e){switch(e){case "credit":return "Credit";case "debit":return "Usage";case "mint":return "Mint";case "reward":return "Reward";default:return ""}}function le(e){let{config:a}=m(),[i,u]=useState([]),[f,d]=useState(false),[g,r]=useState(null),o=useRef(true),l=a.apiBaseUrl,s=useCallback(async()=>{if(e)try{d(!0),r(null);let n=await fetch(`${l}/api/keys/${encodeURIComponent(e)}/ledger`,{credentials:"include"});if(!n.ok)throw new Error(await y(n,`Failed to fetch ledger (${n.status})`));let t=await n.json(),c=Array.isArray(t)?t:t.entries??[];o.current&&u(c.map(N));}catch(n){o.current&&r(n instanceof Error?n.message:"Failed to fetch ledger");}finally{o.current&&d(false);}},[l,e]);return useEffect(()=>(o.current=true,s(),()=>{o.current=false;}),[s]),{entries:i,loading:f,error:g,refresh:s}}function k(){if(typeof document>"u")return {};let e=document.cookie.match(/(?:^|;\s*)__csrf=([^;]*)/);return e?{"x-csrf-token":e[1]}:{}}function fe(){let{config:e,callbacks:a}=m(),[i,u]=useState(false),[f,d]=useState(null),[g,r]=useState(null);return {mint:useCallback(async(l,s,n=1)=>{try{u(!0),r(null),a.onPaymentComplete?.(l,s);let t=await fetch(`${e.apiBaseUrl}/api/keys/mint`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({paymentMethod:l,paymentRef:s,quantity:n,stackId:e.stackId})});if(!t.ok)throw new Error(await y(t,`Key generation failed (${t.status})`));let c=await t.json(),p=c.keys?.[0]||c,h={success:!0,key:{id:p.keyId||p.id||"",key:p.key||"",userId:p.userId||"",status:"active",tokenBalance:p.tokenBalance??p.currentTokenBalance??0,maxTokens:p.initialTokenBalance??p.tokenBalance??0,createdAt:String(p.createdAt||Date.now())},transactionId:s};return d(h),a.onMintSuccess?.(h),h}catch(t){let c=t instanceof Error?t:new Error("Key generation failed");return r(c.message),a.onMintError?.(c),{success:false,error:c.message}}finally{u(false);}},[e.apiBaseUrl,a]),minting:i,result:f,error:g}}function ge(){let{config:e,callbacks:a}=m(),[i,u]=useState(false),[f,d]=useState(null),[g,r]=useState(null),o=useRef(true),l=useCallback(async(n,t)=>{try{u(!0),r(null);let c=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/list`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({askPriceCents:t,stackId:e.stackId,stackName:e.stackName})});if(!c.ok)throw new Error(await y(c,`Listing failed (${c.status})`));let p=await c.json();return o.current&&(d(p),a.onListingCreated?.(p)),p}catch(c){let p=c instanceof Error?c.message:"Listing failed";return o.current&&r(p),null}finally{o.current&&u(false);}},[e.apiBaseUrl,e.stackId,e.stackName,a]),s=useCallback(async n=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/list`,{method:"DELETE",headers:{...k()},credentials:"include"});if(!t.ok)throw new Error(await y(t,`Delist failed (${t.status})`));return o.current&&d(null),!0}catch(t){let c=t instanceof Error?t.message:"Delist failed";return o.current&&r(c),false}finally{o.current&&u(false);}},[e.apiBaseUrl]);return {listKey:l,delistKey:s,listing:i,result:f,error:g}}function pe(){let{config:e}=m(),[a,i]=useState(false),[u,f]=useState(null),d=useRef(true);return {createSession:useCallback(async(r,o)=>{try{i(!0),f(null);let l=await fetch(`${e.apiBaseUrl}/api/keys/stripe-session`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({priceCents:r,quantity:o,stackId:e.stackId,referrerUrl:window.location.href})});if(!l.ok)throw new Error(await y(l,`Checkout failed (${l.status})`));let{url:s}=await l.json();if(!s)throw new Error("No checkout URL returned");let n;try{n=new URL(s);}catch{throw new Error("Invalid checkout URL")}if(n.protocol!=="https:"||!/(^|\.)stripe\.com$/.test(n.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=n.toString();}catch(l){if(d.current){let s=l instanceof Error?l.message:"Checkout failed";f(s),i(false);}}},[e.apiBaseUrl,e.stackId]),loading:a,error:u}}function H(e,a="#"){if(!e||typeof e!="string")return a;let i=e.trim();if(i===""||i==="#")return a;if(i.startsWith("/")||i.startsWith("./")||i.startsWith("../"))return i;try{let u=new URL(i);if(u.protocol==="http:"||u.protocol==="https:")return u.toString()}catch{}return a}var v=/^[1-9A-HJ-NP-Za-km-z]{32,44}$/;function he(){let{config:e}=m(),[a,i]=useState(false),[u,f]=useState(null);return {pay:useCallback(async g=>{if(!e.merchantWallet||!v.test(e.merchantWallet))throw new Error("Merchant wallet not configured");try{i(!0),f(null);let{Connection:r,PublicKey:o,Transaction:l,SystemProgram:s}=await import('@solana/web3.js'),n=typeof window<"u"?window.solana:void 0;if(!n||typeof n!="object"||!n.isPhantom)throw new Error("Phantom wallet not found. Please install Phantom.");let t=n,c=new o(e.merchantWallet),p=await t.connect(),h=new o(p.publicKey.toString()),L="https://api.mainnet-beta.solana.com",T=H(e.solanaRpcUrl,L),j=T==="#"?L:T,D=new r(j),{blockhash:W}=await D.getLatestBlockhash(),R=BigInt(Math.floor(g*1e9)),P=e.protocolTreasuryWallet,B=e.protocolFeeBps??500,b=new l({recentBlockhash:W,feePayer:h});if(P&&v.test(P)&&B>0){let M=R*BigInt(B)/10000n,q=R-M,z=new o(P);b.add(s.transfer({fromPubkey:h,toPubkey:c,lamports:Number(q)}),s.transfer({fromPubkey:h,toPubkey:z,lamports:Number(M)}));}else b.add(s.transfer({fromPubkey:h,toPubkey:c,lamports:Number(R)}));let{signature:J}=await t.signAndSendTransaction(b);return J}catch(r){let o=r instanceof Error?r:new Error("SOL payment failed");throw f(o.message),o}finally{i(false);}},[e.merchantWallet,e.protocolTreasuryWallet,e.protocolFeeBps,e.solanaRpcUrl]),processing:a,error:u}}function be(){let{config:e,callbacks:a}=m(),[i,u]=useState(false),[f,d]=useState(null),[g,r]=useState(null),o=useRef(true);return {transferKey:useCallback(async(s,n)=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(s)}/transfer`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({recipientId:n})});if(!t.ok)throw new Error(await y(t,`Transfer failed (${t.status})`));let c=await t.json();return o.current&&(d(c),a.onTransferComplete?.(c)),c}catch(t){let c=t instanceof Error?t.message:"Transfer failed";return o.current&&r(c),null}finally{o.current&&u(false);}},[e.apiBaseUrl,a]),transferring:i,result:f,error:g}}function Ee(){let{config:e,callbacks:a}=m(),[i,u]=useState(false),[f,d]=useState(null),[g,r]=useState(null),o=useRef(true),l=useCallback(async n=>{try{u(!0),r(null);let t=await fetch(`${e.apiBaseUrl}/api/keys/${encodeURIComponent(n)}/file`,{method:"POST",headers:{"Content-Type":"application/json",...k()},credentials:"include",body:JSON.stringify({stackId:e.stackId})});if(!t.ok)throw new Error(await y(t,`Filing failed (${t.status})`));let c=await t.json();return o.current&&(d(c),a.onFilingComplete?.(c)),c}catch(t){let c=t instanceof Error?t:new Error("Filing failed");return o.current&&r(c.message),a.onFilingError?.(c),null}finally{o.current&&u(false);}},[e.apiBaseUrl,e.stackId,a]),s=useCallback(()=>{d(null),r(null);},[]);return {filePaperwork:l,filing:i,result:f,error:g,reset:s}}function Ie(){let{config:e}=m(),[a,i]=useState([]),[u,f]=useState(true),[d,g]=useState(null),r=useRef(true),o=e.apiBaseUrl,l=useCallback(async()=>{try{f(!0),g(null);let s=await fetch(`${o}/api/keys/filings`,{credentials:"include"});if(!s.ok)throw new Error(await y(s,`Failed to fetch filings (${s.status})`));let n=await s.json(),t=Array.isArray(n)?n:n.filings??[];r.current&&i(t);}catch(s){r.current&&g(s instanceof Error?s.message:"Failed to fetch filings");}finally{r.current&&f(false);}},[o]);return useEffect(()=>(r.current=true,l(),()=>{r.current=false;}),[l]),{entries:a,loading:u,error:d,refresh:l}}
2
- export{Ee as useFilePaperwork,Ie as useFilingHistory,le as useKeyLedger,se as useKeys,ge as useListKey,fe as useMintKey,Q as usePricing,he as useSolanaPayment,pe as useStripeCheckout,be 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};