@stacknet/keyutils 0.5.0 → 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.
- package/dist/components/index.cjs +2 -2
- package/dist/components/index.d.cts +10 -1
- package/dist/components/index.d.ts +10 -1
- package/dist/components/index.js +2 -2
- package/dist/hooks/index.cjs +2 -2
- package/dist/hooks/index.d.cts +45 -13
- package/dist/hooks/index.d.ts +45 -13
- package/dist/hooks/index.js +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/types/index.d.cts +27 -5
- package/dist/types/index.d.ts +27 -5
- package/package.json +1 -1
package/dist/hooks/index.cjs
CHANGED
|
@@ -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=
|
|
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;
|
package/dist/hooks/index.d.cts
CHANGED
|
@@ -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
|
-
/**
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
164
|
-
*
|
|
191
|
+
* Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
|
|
192
|
+
* response: { stacks: StripeStackPayout[] }
|
|
165
193
|
*/
|
|
166
|
-
declare function
|
|
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
|
|
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 };
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
153
|
-
|
|
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
|
|
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
|
|
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
|
-
*
|
|
164
|
-
*
|
|
191
|
+
* Backend contract: GET {apiBaseUrl}/api/payout/stripe-stacks
|
|
192
|
+
* response: { stacks: StripeStackPayout[] }
|
|
165
193
|
*/
|
|
166
|
-
declare function
|
|
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
|
|
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 };
|
package/dist/hooks/index.js
CHANGED
|
@@ -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{
|
|
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};
|