@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.
- package/dist/components/index.cjs +2 -2
- package/dist/components/index.d.cts +103 -15
- package/dist/components/index.d.ts +103 -15
- package/dist/components/index.js +2 -2
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.js +1 -1
- package/dist/hooks/index.cjs +2 -2
- package/dist/hooks/index.d.cts +136 -8
- package/dist/hooks/index.d.ts +136 -8
- package/dist/hooks/index.js +2 -2
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/types/index.d.cts +122 -1
- package/dist/types/index.d.ts +122 -1
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.d.cts +58 -3
- package/dist/utils/index.d.ts +58 -3
- package/dist/utils/index.js +1 -1
- 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 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=
|
|
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, 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
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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
|
-
|
|
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 };
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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
|
-
|
|
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 };
|
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 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{
|
|
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};
|